Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2350 lines
66 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. decinit.c
  5. Abstract:
  6. This is the WDM decoder class driver. This module contains code related
  7. to request processing.
  8. Author:
  9. billpa
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "codcls.h"
  15. #if DBG
  16. #if WIN95_BUILD
  17. ULONG StreamDebug = DebugLevelInfo;
  18. #else
  19. ULONG StreamDebug = DebugLevelError;
  20. #endif
  21. #define STREAM_BUFFER_SIZE 256
  22. UCHAR StreamBuffer[STREAM_BUFFER_SIZE];
  23. #endif
  24. #ifdef POOL_TAGGING
  25. #ifdef ExAllocatePool
  26. #undef ExAllocatePool
  27. #endif
  28. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'PscS')
  29. #endif
  30. VOID
  31. StreamClassStreamNotification(
  32. IN STREAM_MINIDRIVER_STREAM_NOTIFICATION_TYPE NotificationType,
  33. IN PHW_STREAM_OBJECT HwStreamObject,
  34. ...
  35. )
  36. /*++
  37. Routine Description:
  38. stream notification routine for minidriver
  39. Arguments:
  40. NotificationType - indicates what has happened
  41. HwStreamObject - address of minidriver's stream struct
  42. Return Value:
  43. none
  44. --*/
  45. {
  46. va_list Arguments;
  47. PSTREAM_REQUEST_BLOCK SRB;
  48. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  49. HwStreamObject,
  50. STREAM_OBJECT,
  51. HwStreamObject
  52. );
  53. PDEVICE_EXTENSION DeviceExtension;
  54. KIRQL Irql;
  55. #if DBG
  56. PMDL CurrentMdl;
  57. #endif
  58. va_start(Arguments, HwStreamObject);
  59. ASSERT(HwStreamObject != NULL);
  60. DeviceExtension = StreamObject->DeviceExtension;
  61. ASSERT((DeviceExtension->BeginMinidriverCallin == SCBeginSynchronizedMinidriverCallin) ||
  62. (DeviceExtension->BeginMinidriverCallin == SCBeginUnsynchronizedMinidriverCallin));
  63. #if DBG
  64. if (DeviceExtension->NoSync) {
  65. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  66. } // if nosync
  67. #endif
  68. //
  69. // optimization for async drivers - just directly call back the request
  70. // rather than queuing it on the DPC processed completed list.
  71. //
  72. if ((DeviceExtension->NoSync) && (NotificationType == StreamRequestComplete)) {
  73. SRB = CONTAINING_RECORD(va_arg(Arguments,
  74. PHW_STREAM_REQUEST_BLOCK),
  75. STREAM_REQUEST_BLOCK,
  76. HwSRB);
  77. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  78. //
  79. // Clear the active flag.
  80. //
  81. ASSERT(SRB->Flags & SRB_FLAGS_IS_ACTIVE);
  82. SRB->Flags &= ~SRB_FLAGS_IS_ACTIVE;
  83. #if DBG
  84. //
  85. // assert the MDL list.
  86. //
  87. if (SRB->HwSRB.Irp) {
  88. CurrentMdl = SRB->HwSRB.Irp->MdlAddress;
  89. while (CurrentMdl) {
  90. CurrentMdl = CurrentMdl->Next;
  91. } // while
  92. } // if IRP
  93. ASSERT(SRB->HwSRB.Flags & SRB_HW_FLAGS_STREAM_REQUEST);
  94. if ((SRB->HwSRB.Command == SRB_READ_DATA) ||
  95. (SRB->HwSRB.Command == SRB_WRITE_DATA)) {
  96. ASSERT(SRB->HwSRB.Flags & SRB_HW_FLAGS_DATA_TRANSFER);
  97. } else {
  98. ASSERT(!(SRB->HwSRB.Flags & SRB_HW_FLAGS_DATA_TRANSFER));
  99. } // if read/write
  100. #endif
  101. if (SRB->DoNotCallBack) {
  102. DebugPrint((DebugLevelError, "'ScNotify: NOT calling back request - Irp = %x, S# = %x\n",
  103. SRB->HwSRB.Irp, StreamObject->HwStreamObject.StreamNumber));
  104. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  105. return;
  106. } // if NoCallback
  107. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  108. DebugPrint((DebugLevelTrace, "'SCNotification: Completing async stream Irp %x, S# = %x, SRB = %x, Func = %x, Callback = %x, SRB->IRP = %x\n",
  109. SRB->HwSRB.Irp, StreamObject->HwStreamObject.StreamNumber,
  110. SRB, SRB->HwSRB.Command, SRB->Callback, SRB->HwSRB.Irp));
  111. (SRB->Callback) (SRB);
  112. return;
  113. } // if nosync & complete
  114. BEGIN_MINIDRIVER_STREAM_CALLIN(DeviceExtension, &Irql);
  115. switch (NotificationType) {
  116. case ReadyForNextStreamDataRequest:
  117. //
  118. // Start next data packet on adapter's stream queue.
  119. //
  120. DebugPrint((DebugLevelTrace, "'StreamClassStreamNotify: ready for next stream data request, S# = %x\n",
  121. StreamObject->HwStreamObject.StreamNumber));
  122. ASSERT(!(StreamObject->ReadyForNextDataReq));
  123. ASSERT(!(DeviceExtension->NoSync));
  124. StreamObject->ReadyForNextDataReq = TRUE;
  125. break;
  126. case ReadyForNextStreamControlRequest:
  127. //
  128. // Start next data packet on adapter's stream queue.
  129. //
  130. DebugPrint((DebugLevelTrace, "'StreamClassStreamNotify: ready for next stream control request, S# = %x\n",
  131. StreamObject->HwStreamObject.StreamNumber));
  132. ASSERT(!(StreamObject->ReadyForNextControlReq));
  133. ASSERT(!(DeviceExtension->NoSync));
  134. StreamObject->ReadyForNextControlReq = TRUE;
  135. break;
  136. case StreamRequestComplete:
  137. SRB = CONTAINING_RECORD(va_arg(Arguments,
  138. PHW_STREAM_REQUEST_BLOCK),
  139. STREAM_REQUEST_BLOCK,
  140. HwSRB);
  141. DebugPrint((DebugLevelTrace, "'SCStreamNot: completing Irp %x, S# = %x, SRB = %x, Command = %x\n",
  142. SRB->HwSRB.Irp, StreamObject->HwStreamObject.StreamNumber, SRB, SRB->HwSRB.Command));
  143. ASSERT(SRB->HwSRB.Status != STATUS_PENDING);
  144. ASSERT(SRB->Flags & SRB_FLAGS_IS_ACTIVE);
  145. //
  146. // Clear the active flag.
  147. //
  148. SRB->Flags &= ~SRB_FLAGS_IS_ACTIVE;
  149. //
  150. // add the SRB to the list of completed SRB's.
  151. //
  152. SRB->HwSRB.NextSRB = StreamObject->ComObj.InterruptData.CompletedSRB;
  153. StreamObject->ComObj.InterruptData.CompletedSRB = &SRB->HwSRB;
  154. #if DBG
  155. //
  156. // assert the MDL list.
  157. //
  158. if (SRB->HwSRB.Irp) {
  159. CurrentMdl = SRB->HwSRB.Irp->MdlAddress;
  160. while (CurrentMdl) {
  161. CurrentMdl = CurrentMdl->Next;
  162. } // while
  163. } // if IRP
  164. ASSERT(SRB->HwSRB.Flags & SRB_HW_FLAGS_STREAM_REQUEST);
  165. if ((SRB->HwSRB.Command == SRB_READ_DATA) ||
  166. (SRB->HwSRB.Command == SRB_WRITE_DATA)) {
  167. ASSERT(SRB->HwSRB.Flags & SRB_HW_FLAGS_DATA_TRANSFER);
  168. } else {
  169. ASSERT(!(SRB->HwSRB.Flags & SRB_HW_FLAGS_DATA_TRANSFER));
  170. } // if read/write
  171. #endif
  172. break;
  173. case SignalMultipleStreamEvents:
  174. {
  175. GUID *EventGuid = va_arg(Arguments, GUID *);
  176. ULONG EventItem = va_arg(Arguments, ULONG);
  177. //
  178. // signal all events that match the criteria. note that we are
  179. // already
  180. // at the level required for synchronizing the list, so no lock
  181. // type is specified.
  182. //
  183. KsGenerateEventList(EventGuid,
  184. EventItem,
  185. &StreamObject->NotifyList,
  186. KSEVENTS_NONE,
  187. NULL);
  188. } // case event
  189. break;
  190. case SignalStreamEvent:
  191. KsGenerateEvent(va_arg(Arguments, PKSEVENT_ENTRY));
  192. break;
  193. case DeleteStreamEvent:
  194. {
  195. PKSEVENT_ENTRY EventEntry;
  196. //
  197. // remove the entry from the list, and add it to the dead list.
  198. // note
  199. // that we are already at the correct sync level to do this.
  200. //
  201. EventEntry = va_arg(Arguments, PKSEVENT_ENTRY);
  202. RemoveEntryList(&EventEntry->ListEntry);
  203. InsertTailList(&DeviceExtension->DeadEventList,
  204. &EventEntry->ListEntry);
  205. }
  206. break;
  207. default:
  208. ASSERT(0);
  209. }
  210. va_end(Arguments);
  211. END_MINIDRIVER_STREAM_CALLIN(StreamObject, &Irql);
  212. } // end StreamClassStreamNotification()
  213. VOID
  214. StreamClassDeviceNotification(
  215. IN STREAM_MINIDRIVER_DEVICE_NOTIFICATION_TYPE NotificationType,
  216. IN PVOID HwDeviceExtension,
  217. ...
  218. )
  219. /*++
  220. Routine Description:
  221. device notification routine for minidriver
  222. Arguments:
  223. NotificationType - indicates what has happened
  224. HwDeviceExtension - address of minidriver's device extension
  225. Return Value:
  226. none
  227. --*/
  228. {
  229. va_list Arguments;
  230. PSTREAM_REQUEST_BLOCK SRB;
  231. PDEVICE_EXTENSION DeviceExtension =
  232. (PDEVICE_EXTENSION) HwDeviceExtension - 1;
  233. KIRQL Irql;
  234. va_start(Arguments, HwDeviceExtension);
  235. ASSERT(HwDeviceExtension != NULL);
  236. #if DBG
  237. if (DeviceExtension->NoSync) {
  238. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  239. } // if nosync
  240. #endif
  241. BEGIN_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  242. switch (NotificationType) {
  243. case ReadyForNextDeviceRequest:
  244. //
  245. // Start next control packet on adapter's device queue.
  246. //
  247. DebugPrint((DebugLevelTrace, "'StreamClassDeviceNotify: ready for next stream.\n"));
  248. ASSERT(!(DeviceExtension->ReadyForNextReq));
  249. ASSERT(!(DeviceExtension->NoSync));
  250. DeviceExtension->ReadyForNextReq = TRUE;
  251. break;
  252. case DeviceRequestComplete:
  253. SRB = CONTAINING_RECORD(va_arg(Arguments, PHW_STREAM_REQUEST_BLOCK),
  254. STREAM_REQUEST_BLOCK,
  255. HwSRB);
  256. DebugPrint((DebugLevelTrace, "'StreamClassDeviceNotify: stream request complete.\n"));
  257. ASSERT(SRB->HwSRB.Status != STATUS_PENDING);
  258. ASSERT(SRB->Flags & SRB_FLAGS_IS_ACTIVE);
  259. ASSERT(!(SRB->HwSRB.Flags & SRB_HW_FLAGS_STREAM_REQUEST));
  260. ASSERT(!(SRB->HwSRB.Flags & SRB_HW_FLAGS_DATA_TRANSFER));
  261. //
  262. // Clear the active flag.
  263. //
  264. SRB->Flags &= ~SRB_FLAGS_IS_ACTIVE;
  265. //
  266. // add the SRB to the list of completed SRB's.
  267. //
  268. SRB->HwSRB.NextSRB = DeviceExtension->ComObj.InterruptData.CompletedSRB;
  269. DeviceExtension->ComObj.InterruptData.CompletedSRB = &SRB->HwSRB;
  270. break;
  271. case SignalMultipleDeviceEvents:
  272. {
  273. GUID *EventGuid = va_arg(Arguments, GUID *);
  274. ULONG EventItem = va_arg(Arguments, ULONG);
  275. //
  276. // signal all events that match the criteria. note that we are
  277. // already
  278. // at the level required for synchronizing the list, so no lock
  279. // type is specified.
  280. //
  281. PFILTER_INSTANCE FilterInstance;
  282. ASSERT( 0 == DeviceExtension->MinidriverData->
  283. HwInitData.FilterInstanceExtensionSize);
  284. //
  285. // this is synced should not need to avoid race
  286. //
  287. FilterInstance = (PFILTER_INSTANCE)
  288. DeviceExtension->FilterInstanceList.Flink;
  289. if ( (PLIST_ENTRY)FilterInstance ==
  290. &DeviceExtension->FilterInstanceList ) {
  291. DebugPrint((DebugLevelWarning, "Filter Closed\n"));
  292. break;
  293. }
  294. FilterInstance = CONTAINING_RECORD(FilterInstance,
  295. FILTER_INSTANCE,
  296. NextFilterInstance);
  297. KsGenerateEventList(EventGuid,
  298. EventItem,
  299. &FilterInstance->NotifyList,
  300. KSEVENTS_NONE,
  301. NULL);
  302. }
  303. break;
  304. #if ENABLE_MULTIPLE_FILTER_TYPES
  305. case SignalMultipleDeviceInstanceEvents:
  306. {
  307. PFILTER_INSTANCE FilterInstance =
  308. (PFILTER_INSTANCE)va_arg( Arguments, PVOID) -1;
  309. GUID *EventGuid = va_arg(Arguments, GUID *);
  310. ULONG EventItem = va_arg(Arguments, ULONG);
  311. //
  312. // signal all events that match the criteria. note that we are
  313. // already
  314. // at the level required for synchronizing the list, so no lock
  315. // type is specified.
  316. //
  317. KsGenerateEventList(EventGuid,
  318. EventItem,
  319. &FilterInstance->NotifyList,
  320. KSEVENTS_NONE,
  321. NULL);
  322. }
  323. break;
  324. #endif // ENABLE_MULTIPLE_FILTER_TYPES
  325. case SignalDeviceEvent:
  326. KsGenerateEvent(va_arg(Arguments, PKSEVENT_ENTRY));
  327. break;
  328. case DeleteDeviceEvent:
  329. {
  330. PKSEVENT_ENTRY EventEntry;
  331. //
  332. // remove the entry from the list, and add it to the dead list.
  333. // note
  334. // that we are already at the correct sync level to do this.
  335. //
  336. EventEntry = va_arg(Arguments, PKSEVENT_ENTRY);
  337. RemoveEntryList(&EventEntry->ListEntry);
  338. InsertTailList(&DeviceExtension->DeadEventList,
  339. &EventEntry->ListEntry);
  340. }
  341. break;
  342. default:
  343. ASSERT(0);
  344. }
  345. va_end(Arguments);
  346. //
  347. // Request a DPC be queued after the interrupt completes.
  348. //
  349. END_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  350. } // end StreamClassDeviceNotification()
  351. VOID
  352. StreamClassScheduleTimer(
  353. IN OPTIONAL PHW_STREAM_OBJECT HwStreamObject,
  354. IN PVOID HwDeviceExtension,
  355. IN ULONG NumberOfMicroseconds,
  356. IN PHW_TIMER_ROUTINE TimerRoutine,
  357. IN PVOID Context
  358. )
  359. /*++
  360. Routine Description:
  361. schedules a timer callback for the minidriver
  362. Arguments:
  363. HwStreamObject - address of minidriver's stream struct
  364. HwDeviceExtension - address of minidriver's device extension
  365. NumberOfMicroseconds - # of microseconds that should elapse before calling
  366. TimerRoutine - routine to call when the time expires
  367. Context - value to pass into the timer routine
  368. Return Value:
  369. none
  370. --*/
  371. {
  372. PSTREAM_OBJECT StreamObject;
  373. KIRQL Irql;
  374. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)
  375. (HwDeviceExtension) - 1;
  376. PCOMMON_OBJECT ComObj;
  377. ASSERT(HwDeviceExtension != NULL);
  378. StreamObject = CONTAINING_RECORD(
  379. HwStreamObject,
  380. STREAM_OBJECT,
  381. HwStreamObject
  382. );
  383. #if DBG
  384. if (DeviceExtension->NoSync) {
  385. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  386. } // if nosync
  387. #endif
  388. //
  389. // The driver wants to set the timer.
  390. // Save the timer parameters.
  391. //
  392. BEGIN_MINIDRIVER_STREAM_CALLIN(DeviceExtension, &Irql);
  393. if (HwStreamObject) {
  394. ComObj = &StreamObject->ComObj;
  395. //DebugPrint((DebugLevelVerbose, "'StreamClassScheduleTimer for stream.\n"));
  396. } else {
  397. StreamObject = NULL;
  398. ComObj = &DeviceExtension->ComObj;
  399. ComObj->InterruptData.Flags |= INTERRUPT_FLAGS_NOTIFICATION_REQUIRED;
  400. DebugPrint((DebugLevelVerbose, "'StreamClassScheduleTimer for device.\n"));
  401. }
  402. //
  403. // assert that a timer is not scheduled multiple times.
  404. //
  405. #if DBG
  406. if ((ComObj->InterruptData.Flags & INTERRUPT_FLAGS_TIMER_CALL_REQUEST) &&
  407. ((NumberOfMicroseconds != 0) && (ComObj->InterruptData.HwTimerValue
  408. != 0))) {
  409. DebugPrint((DebugLevelFatal, "Stream Minidriver scheduled same timer twice!\n"));
  410. DEBUG_BREAKPOINT();
  411. ASSERT(1 == 0);
  412. } // if scheduled twice
  413. #endif
  414. ComObj->InterruptData.Flags |= INTERRUPT_FLAGS_TIMER_CALL_REQUEST;
  415. ComObj->InterruptData.HwTimerRoutine = TimerRoutine;
  416. ComObj->InterruptData.HwTimerValue = NumberOfMicroseconds;
  417. ComObj->InterruptData.HwTimerContext = Context;
  418. if (StreamObject) {
  419. END_MINIDRIVER_STREAM_CALLIN(StreamObject, &Irql);
  420. } else {
  421. END_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  422. } // if streamobject
  423. }
  424. VOID
  425. StreamClassCallAtNewPriority(
  426. IN OPTIONAL PHW_STREAM_OBJECT HwStreamObject,
  427. IN PVOID HwDeviceExtension,
  428. IN STREAM_PRIORITY Priority,
  429. IN PHW_PRIORITY_ROUTINE PriorityRoutine,
  430. IN PVOID Context
  431. )
  432. /*++
  433. Routine Description:
  434. schedules a callback at the specified priority
  435. Arguments:
  436. HwStreamObject - address of minidriver's stream struct
  437. HwDeviceExtension - address of minidriver's device extension
  438. Priority - priority at which to call minidriver
  439. PriorityRoutine - routine to call at specified priority
  440. Context - value to pass into the priority routine
  441. Return Value:
  442. none
  443. --*/
  444. {
  445. PSTREAM_OBJECT StreamObject;
  446. KIRQL Irql;
  447. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)
  448. (HwDeviceExtension) - 1;
  449. PCOMMON_OBJECT ComObj;
  450. ASSERT(HwDeviceExtension != NULL);
  451. StreamObject = CONTAINING_RECORD(
  452. HwStreamObject,
  453. STREAM_OBJECT,
  454. HwStreamObject
  455. );
  456. //
  457. // The driver wants to get called back at a different priority.
  458. // Save the priority parameters.
  459. //
  460. if (Priority == LowToHigh) {
  461. //
  462. // the minidriver wishes to be called from low priority to high
  463. // we must call it directly from this routine as we cannot use
  464. // the interruptcontext structure due to the possibility of
  465. // reentrancy.
  466. //
  467. DebugPrint((DebugLevelVerbose, "'StreamClassChangePriority LowToHigh.\n"));
  468. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  469. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  470. DeviceExtension->SynchronizeExecution(
  471. DeviceExtension->InterruptObject,
  472. (PVOID) PriorityRoutine,
  473. Context);
  474. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  475. //
  476. // Call the DPC directly to check for work.
  477. //
  478. StreamClassDpc(NULL,
  479. DeviceExtension->DeviceObject,
  480. NULL,
  481. NULL);
  482. KeLowerIrql(Irql);
  483. } else {
  484. if (HwStreamObject) {
  485. DebugPrint((DebugLevelVerbose, "'StreamClassChangePriority to %x for stream %x\n",
  486. StreamObject->ComObj.InterruptData.HwPriorityLevel, StreamObject->HwStreamObject.StreamNumber));
  487. ComObj = &StreamObject->ComObj;
  488. SCRequestDpcForStream(StreamObject);
  489. } else {
  490. DebugPrint((DebugLevelVerbose, "'StreamClassChangePriority for device.\n"));
  491. ComObj = &DeviceExtension->ComObj;
  492. ComObj->InterruptData.Flags |= INTERRUPT_FLAGS_NOTIFICATION_REQUIRED;
  493. } // if streamobject
  494. #if DBG
  495. if ((ComObj->InterruptData.Flags &
  496. INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST) ||
  497. ((ComObj->PriorityWorkItemScheduled) && (Priority == Low))) {
  498. DebugPrint((DebugLevelFatal, "Stream Minidriver scheduled priority twice!\n"));
  499. DEBUG_BREAKPOINT();
  500. ASSERT(1 == 0);
  501. } // if scheduled twice
  502. ComObj->PriorityWorkItemScheduled = TRUE;
  503. #endif
  504. ComObj->InterruptData.Flags |= INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST;
  505. ComObj->InterruptData.HwPriorityLevel = Priority;
  506. ComObj->InterruptData.HwPriorityRoutine = PriorityRoutine;
  507. ComObj->InterruptData.HwPriorityContext = Context;
  508. } // if lowtohigh
  509. }
  510. VOID
  511. StreamClassLogError(
  512. IN PVOID HwDeviceExtension,
  513. IN PHW_STREAM_REQUEST_BLOCK hwSRB OPTIONAL,
  514. IN ULONG ErrorCode,
  515. IN ULONG UniqueId
  516. )
  517. /*++
  518. Routine Description:
  519. This routine saves the error log information, and queues a DPC if necessary.
  520. Arguments:
  521. HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.
  522. SRB - Supplies an optional pointer to SRB if there is one.
  523. ErrorCode - Supplies an error code indicating the type of error.
  524. UniqueId - Supplies a unique identifier for the error.
  525. Return Value:
  526. None.
  527. --*/
  528. {
  529. PDEVICE_EXTENSION deviceExtension =
  530. ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  531. PDEVICE_OBJECT DeviceObject = deviceExtension->DeviceObject;
  532. PERROR_LOG_ENTRY errorLogEntry;
  533. PSTREAM_REQUEST_BLOCK SRB;
  534. KIRQL Irql;
  535. //
  536. // If the error log entry is already full, then dump the error.
  537. //
  538. DEBUG_BREAKPOINT();
  539. ASSERT(HwDeviceExtension != NULL);
  540. BEGIN_MINIDRIVER_DEVICE_CALLIN(deviceExtension, &Irql);
  541. DebugPrint((DebugLevelError, "StreamClassLogError.\n"));
  542. if (deviceExtension->ComObj.InterruptData.Flags & INTERRUPT_FLAGS_LOG_ERROR) {
  543. DEBUG_BREAKPOINT();
  544. DebugPrint((1, "'StreamClassLogError: Ignoring error log packet.\n"));
  545. return;
  546. }
  547. //
  548. // Save the error log data in the log entry.
  549. //
  550. errorLogEntry = &deviceExtension->ComObj.InterruptData.LogEntry;
  551. errorLogEntry->ErrorCode = ErrorCode;
  552. errorLogEntry->UniqueId = UniqueId;
  553. //
  554. // Get the sequence number from the SRB.
  555. //
  556. if (hwSRB != NULL) {
  557. DEBUG_BREAKPOINT();
  558. SRB = CONTAINING_RECORD(hwSRB,
  559. STREAM_REQUEST_BLOCK,
  560. HwSRB);
  561. errorLogEntry->SequenceNumber = SRB->SequenceNumber;
  562. } else {
  563. DEBUG_BREAKPOINT();
  564. errorLogEntry->SequenceNumber = 0;
  565. }
  566. //
  567. // Indicate that the error log entry is in use and that a
  568. // notification
  569. // is required.
  570. //
  571. deviceExtension->ComObj.InterruptData.Flags |= INTERRUPT_FLAGS_LOG_ERROR;
  572. END_MINIDRIVER_DEVICE_CALLIN(deviceExtension, &Irql);
  573. return;
  574. } // end StreamClassLogError()
  575. #if DBG
  576. VOID
  577. StreamClassDebugPrint(
  578. STREAM_DEBUG_LEVEL DebugPrintLevel,
  579. PSCHAR DebugMessage,
  580. ...
  581. )
  582. /*++
  583. Routine Description:
  584. Debug print routine
  585. Arguments:
  586. DebugPrintLevel - Debug print level
  587. DebugMessage - message to print
  588. Return Value:
  589. None
  590. --*/
  591. {
  592. va_list ap;
  593. va_start(ap, DebugMessage);
  594. if (DebugPrintLevel <= (INT) StreamDebug) {
  595. _vsnprintf(StreamBuffer, STREAM_BUFFER_SIZE-1, DebugMessage, ap);
  596. DbgPrint(StreamBuffer);
  597. }
  598. va_end(ap);
  599. } // end StreamClassDebugPrint()
  600. #else
  601. //
  602. // StreamClassDebugPrint stub
  603. //
  604. VOID
  605. StreamClassDebugPrint(
  606. STREAM_DEBUG_LEVEL DebugPrintLevel,
  607. PSCHAR DebugMessage,
  608. ...
  609. )
  610. {
  611. }
  612. #endif
  613. STREAM_PHYSICAL_ADDRESS
  614. StreamClassGetPhysicalAddress(
  615. IN PVOID HwDeviceExtension,
  616. IN PHW_STREAM_REQUEST_BLOCK HwSRB OPTIONAL,
  617. IN PVOID VirtualAddress,
  618. IN STREAM_BUFFER_TYPE Type,
  619. OUT ULONG * Length
  620. )
  621. /*++
  622. Routine Description:
  623. Convert virtual address to physical address for DMA.
  624. Arguments:
  625. HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.
  626. HwSRB - Supplies an optional pointer to SRB if there is one.
  627. VirtualAddress - pointer to address for which to retrieve physical address
  628. Type - type of buffer in VirtualAddress
  629. Return Value:
  630. Returns phys address and length or NULL if invalid address
  631. --*/
  632. {
  633. PDEVICE_EXTENSION deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  634. PKSSTREAM_HEADER CurrentHeader;
  635. PKSSCATTER_GATHER ScatterList;
  636. PSTREAM_REQUEST_BLOCK SRB;
  637. ULONG VirtualOffset;
  638. PHYSICAL_ADDRESS address;
  639. ULONG NumberOfBuffers,
  640. i,
  641. SizeSoFar = 0,
  642. ListSize = 0;
  643. ULONG DataBytes;
  644. PHW_STREAM_OBJECT HwStreamObject;
  645. ASSERT(HwDeviceExtension != NULL);
  646. switch (Type) {
  647. case PerRequestExtension:
  648. ASSERT(HwSRB);
  649. SRB = CONTAINING_RECORD((PHW_STREAM_REQUEST_BLOCK) HwSRB,
  650. STREAM_REQUEST_BLOCK,
  651. HwSRB);
  652. VirtualOffset = (ULONG) ((ULONG_PTR) VirtualAddress - (ULONG_PTR) (SRB + 1));
  653. *Length = SRB->ExtensionLength - VirtualOffset;
  654. address.QuadPart = SRB->PhysicalAddress.QuadPart +
  655. sizeof(STREAM_REQUEST_BLOCK) +
  656. VirtualOffset;
  657. return (address);
  658. case DmaBuffer:
  659. VirtualOffset = (ULONG) ((ULONG_PTR) VirtualAddress - (ULONG_PTR) deviceExtension->DmaBuffer);
  660. *Length = deviceExtension->DmaBufferLength - VirtualOffset;
  661. address.QuadPart = deviceExtension->DmaBufferPhysical.QuadPart
  662. + VirtualOffset;
  663. return (address);
  664. case SRBDataBuffer:
  665. ASSERT(HwSRB);
  666. SRB = CONTAINING_RECORD((PHW_STREAM_REQUEST_BLOCK) HwSRB,
  667. STREAM_REQUEST_BLOCK,
  668. HwSRB);
  669. HwStreamObject = SRB->HwSRB.StreamObject;
  670. ASSERT(HwStreamObject);
  671. CurrentHeader = SRB->HwSRB.CommandData.DataBufferArray;
  672. NumberOfBuffers = SRB->HwSRB.NumberOfBuffers;
  673. for (i = 0; i < NumberOfBuffers; i++) {
  674. if (SRB->HwSRB.Command == SRB_WRITE_DATA) {
  675. DataBytes = CurrentHeader->DataUsed;
  676. } else { // if write
  677. DataBytes = CurrentHeader->FrameExtent;
  678. } // if write
  679. //
  680. // see if the buffer is within the range of this element
  681. //
  682. VirtualOffset = (ULONG) ((ULONG_PTR) VirtualAddress - (ULONG_PTR) CurrentHeader->Data + 1);
  683. if (VirtualOffset > DataBytes) {
  684. //
  685. // buffer not within this element. add the size of this one
  686. // to our total.
  687. //
  688. SizeSoFar += DataBytes;
  689. } else {
  690. //
  691. // we've found the element. Now calculate the phys
  692. // address from the phys list.
  693. //
  694. // GUBGUB - This function is seldom called. n is most ofen small
  695. // <=3. The O(n^2) performance concern is insignificant.
  696. // - this algorithm gets n^2 expensive for long lists
  697. // an alternative is to build a separate array which holds
  698. // the mapping between the stream headers and the s/g
  699. // elements
  700. // for each header. We currently don't get that many
  701. // elements
  702. // so the below is more efficient now.
  703. //
  704. ScatterList = SRB->HwSRB.ScatterGatherBuffer;
  705. while (SizeSoFar > ListSize) {
  706. ListSize += ScatterList++->Length;
  707. }
  708. //
  709. // Now ScatterList points to the correct scatter/gather
  710. // element.
  711. //
  712. while (VirtualOffset > ScatterList->Length) {
  713. VirtualOffset -= ScatterList->Length;
  714. ScatterList++;
  715. }
  716. *Length = ScatterList->Length - VirtualOffset + 1;
  717. address.QuadPart = ScatterList->PhysicalAddress.QuadPart
  718. + VirtualOffset - 1;
  719. return (address);
  720. } // if buffer
  721. CurrentHeader = ((PKSSTREAM_HEADER) ((PBYTE) CurrentHeader +
  722. HwStreamObject->StreamHeaderMediaSpecific +
  723. HwStreamObject->StreamHeaderWorkspace));
  724. } // for # buffers
  725. DebugPrint((DebugLevelFatal, "StreamClassGetPhysicalAddress: address not in SRB!\n"));
  726. default:
  727. DEBUG_BREAKPOINT();
  728. *Length = 0;
  729. address.QuadPart = (LONGLONG) 0;
  730. return (address);
  731. } // switch
  732. } // end StreamClassGetPhysicalAddress()
  733. VOID
  734. StreamClassDebugAssert(
  735. IN PCHAR File,
  736. IN ULONG Line,
  737. IN PCHAR AssertText,
  738. IN ULONG AssertValue
  739. )
  740. /*++
  741. Routine Description:
  742. This is the minidriver debug assert call. When running a checked version
  743. of the class driver, asserts are recognized resulting in a debug
  744. message and breakpoint. When running a free version of the port driver,
  745. asserts are ignored.
  746. Arguments:
  747. File - file name where assert occurred
  748. Line - line number of assert
  749. AssertText - Text to be printed
  750. AssertValue - value to be printed
  751. Return Value:
  752. none
  753. --*/
  754. {
  755. DebugPrint((DebugLevelError, "(%s:%d) Assert failed (%s)=0x%x\n", File, Line, AssertText, AssertValue));
  756. DbgBreakPoint();
  757. }
  758. VOID
  759. SCRequestDpcForStream(
  760. IN PSTREAM_OBJECT StreamObject
  761. )
  762. /*++
  763. Routine Description:
  764. This routine places a stream object on the NeedyStream queue if it is
  765. not already there
  766. Arguments:
  767. StreamObject - pointer to stream object
  768. Return Value:
  769. none
  770. --*/
  771. {
  772. PDEVICE_EXTENSION DeviceExtension = StreamObject->DeviceExtension;
  773. //
  774. // add the stream to the queue of needy streams unless it is already
  775. // there.
  776. //
  777. #if DBG
  778. if (DeviceExtension->NeedyStream) {
  779. ASSERT(DeviceExtension->NeedyStream->OnNeedyQueue);
  780. }
  781. #endif
  782. ASSERT(StreamObject->NextNeedyStream != StreamObject);
  783. if (!(StreamObject->OnNeedyQueue)) {
  784. ASSERT(!StreamObject->NextNeedyStream);
  785. DebugPrint((DebugLevelVerbose, "'SCRequestDpc: Stream %x added to needy queue, Next = %x\n",
  786. StreamObject, StreamObject->NextNeedyStream));
  787. StreamObject->OnNeedyQueue = TRUE;
  788. StreamObject->NextNeedyStream = DeviceExtension->NeedyStream;
  789. DeviceExtension->NeedyStream = StreamObject;
  790. ASSERT(StreamObject->NextNeedyStream != StreamObject);
  791. } else {
  792. DebugPrint((DebugLevelVerbose, "'SCRequestDpc: Stream %x already on needy queue\n",
  793. StreamObject));
  794. } // if on needy queue
  795. StreamObject->ComObj.InterruptData.Flags |= INTERRUPT_FLAGS_NOTIFICATION_REQUIRED;
  796. }
  797. VOID
  798. StreamClassAbortOutstandingRequests(
  799. IN PVOID HwDeviceExtension,
  800. IN PHW_STREAM_OBJECT HwStreamObject,
  801. IN NTSTATUS Status
  802. )
  803. /*++
  804. Routine Description:
  805. aborts outstanding requests on the specified device or stream
  806. Arguments:
  807. HwStreamObject - address of minidriver's stream struct
  808. HwDeviceExtension - device extension
  809. Status - NT Status to use for aborting
  810. Return Value:
  811. none
  812. --*/
  813. {
  814. PSTREAM_OBJECT StreamObject = NULL;
  815. PDEVICE_EXTENSION DeviceExtension =
  816. (PDEVICE_EXTENSION) HwDeviceExtension - 1;
  817. KIRQL Irql;
  818. PLIST_ENTRY SrbEntry,
  819. ListEntry;
  820. PSTREAM_REQUEST_BLOCK CurrentSrb;
  821. PHW_STREAM_OBJECT CurrentHwStreamObject;
  822. PSTREAM_OBJECT CurrentStreamObject;
  823. ASSERT(HwDeviceExtension != NULL);
  824. #if DBG
  825. if (DeviceExtension->NoSync) {
  826. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  827. } // if nosync
  828. #endif
  829. if (HwStreamObject) {
  830. DEBUG_BREAKPOINT();
  831. StreamObject = CONTAINING_RECORD(HwStreamObject,
  832. STREAM_OBJECT,
  833. HwStreamObject);
  834. }
  835. BEGIN_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  836. DebugPrint((DebugLevelError, "StreamClassAbortOutstandingRequests.\n"));
  837. //
  838. // walk the outstanding queue and abort all requests on it.
  839. //
  840. SrbEntry = ListEntry = &DeviceExtension->OutstandingQueue;
  841. while (SrbEntry->Flink != ListEntry) {
  842. SrbEntry = SrbEntry->Flink;
  843. //
  844. // follow the link to the Srb
  845. //
  846. CurrentSrb = CONTAINING_RECORD(SrbEntry,
  847. STREAM_REQUEST_BLOCK,
  848. SRBListEntry);
  849. CurrentHwStreamObject = CurrentSrb->HwSRB.StreamObject;
  850. if ((!HwStreamObject) || (CurrentHwStreamObject ==
  851. HwStreamObject)) {
  852. //
  853. // abort this one and show that it's ready for a next request,
  854. // assuming it's active. it might not be active if the
  855. // minidriver
  856. // just called it back.
  857. //
  858. if (CurrentSrb->Flags & SRB_FLAGS_IS_ACTIVE) {
  859. //
  860. // Clear the active flag.
  861. //
  862. CurrentSrb->Flags &= ~SRB_FLAGS_IS_ACTIVE;
  863. CurrentSrb->HwSRB.Status = Status;
  864. if (CurrentSrb->HwSRB.Flags & SRB_HW_FLAGS_STREAM_REQUEST) {
  865. CurrentStreamObject = CONTAINING_RECORD(
  866. CurrentHwStreamObject,
  867. STREAM_OBJECT,
  868. HwStreamObject
  869. );
  870. //
  871. // indicate that the appropriate queue is ready for a
  872. // next
  873. // request.
  874. //
  875. if (CurrentSrb->HwSRB.Flags & SRB_HW_FLAGS_DATA_TRANSFER) {
  876. CurrentStreamObject->ReadyForNextDataReq = TRUE;
  877. } else { // if data
  878. CurrentStreamObject->ReadyForNextControlReq = TRUE;
  879. } // if data
  880. DebugPrint((DebugLevelTrace, "'SCAbort: aborting stream IRP %x\n",
  881. CurrentSrb->HwSRB.Irp));
  882. //
  883. // add the SRB to the list of completed stream SRB's.
  884. //
  885. CurrentSrb->HwSRB.NextSRB = CurrentStreamObject->ComObj.InterruptData.CompletedSRB;
  886. CurrentStreamObject->ComObj.InterruptData.CompletedSRB = &CurrentSrb->HwSRB;
  887. //
  888. // add this stream to the queue of needy streams
  889. //
  890. SCRequestDpcForStream(CurrentStreamObject);
  891. } else { // if stream
  892. DebugPrint((DebugLevelTrace, "'SCAbort: aborting device IRP %x\n",
  893. CurrentSrb->HwSRB.Irp));
  894. //
  895. // add the SRB to the list of completed device SRB's.
  896. //
  897. DEBUG_BREAKPOINT();
  898. CurrentSrb->HwSRB.NextSRB = DeviceExtension->ComObj.InterruptData.CompletedSRB;
  899. DeviceExtension->ComObj.InterruptData.CompletedSRB = &CurrentSrb->HwSRB;
  900. DeviceExtension->ReadyForNextReq = TRUE;
  901. } // if stream
  902. } // if active
  903. } // if aborting this one
  904. } // while list entry
  905. //
  906. // all necessary requests have been aborted. exit.
  907. //
  908. END_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  909. }
  910. PKSEVENT_ENTRY
  911. StreamClassGetNextEvent(
  912. IN PVOID HwInstanceExtension_OR_HwDeviceExtension,
  913. IN OPTIONAL PHW_STREAM_OBJECT HwStreamObject,
  914. IN OPTIONAL GUID * EventGuid,
  915. IN OPTIONAL ULONG EventItem,
  916. IN OPTIONAL PKSEVENT_ENTRY CurrentEvent
  917. )
  918. /*++
  919. Routine Description:
  920. Arguments:
  921. HwInstanceExtenion: was HwDeviceExtension. But we now support multiinstances.
  922. Therefore, we need the HwInstanceExtension instead for MF.
  923. CurrentEvent - event (if any) to get the next from
  924. Return Value:
  925. next event, if any
  926. --*/
  927. {
  928. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(HwStreamObject,
  929. STREAM_OBJECT,
  930. HwStreamObject);
  931. PFILTER_INSTANCE FilterInstance;
  932. PDEVICE_EXTENSION DeviceExtension;
  933. //(PDEVICE_EXTENSION) HwDeviceExtension - 1;
  934. PLIST_ENTRY EventListEntry,
  935. EventEntry;
  936. PKSEVENT_ENTRY NextEvent,
  937. ReturnEvent = NULL;
  938. KIRQL Irql;
  939. //
  940. // see which is HwInstanceExtension_OR_HwDeviceExtension
  941. // need to try HwInstanceExtension first because is has a smaller
  942. // offset backward so we don't touch invalid memory.
  943. //
  944. // try
  945. FilterInstance = (PFILTER_INSTANCE)
  946. HwInstanceExtension_OR_HwDeviceExtension-1;
  947. if ( SIGN_FILTER_INSTANCE != FilterInstance->Signature ) {
  948. //
  949. // single instance legacy driver
  950. //
  951. DeviceExtension = (PDEVICE_EXTENSION)
  952. HwInstanceExtension_OR_HwDeviceExtension -1;
  953. ASSERT( 0 == DeviceExtension->MinidriverData->
  954. HwInitData.FilterInstanceExtensionSize);
  955. if (DeviceExtension->NoSync) {
  956. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  957. }
  958. if ( IsListEmpty( &DeviceExtension->FilterInstanceList ) ) {
  959. //
  960. // filter has been closed. but we are called.
  961. // Single instance drivers do not receive open/close
  962. // they don't know when to sotp calling this.
  963. // We need to check.
  964. //
  965. DebugPrint((DebugLevelWarning, "GetNextEvent no open filters\n"));
  966. if (DeviceExtension->NoSync) {
  967. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  968. }
  969. return NULL;
  970. }
  971. FilterInstance = (PFILTER_INSTANCE)
  972. DeviceExtension->FilterInstanceList.Flink;
  973. if (DeviceExtension->NoSync) {
  974. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  975. }
  976. FilterInstance = CONTAINING_RECORD(FilterInstance,
  977. FILTER_INSTANCE,
  978. NextFilterInstance);
  979. }
  980. else {
  981. DeviceExtension = FilterInstance ->DeviceExtension;
  982. }
  983. #if DBG
  984. if (DeviceExtension->NoSync) {
  985. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  986. }
  987. #endif
  988. //
  989. // take the spinlock if we are unsynchronized.
  990. //
  991. BEGIN_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  992. //
  993. // loop thru the events, trying to find the requested one.
  994. //
  995. if (HwStreamObject) {
  996. EventListEntry = EventEntry = &StreamObject->NotifyList;
  997. } else {
  998. EventListEntry = EventEntry = &FilterInstance->NotifyList;
  999. }
  1000. while (EventEntry->Flink != EventListEntry) {
  1001. EventEntry = EventEntry->Flink;
  1002. NextEvent = CONTAINING_RECORD(EventEntry,
  1003. KSEVENT_ENTRY,
  1004. ListEntry);
  1005. if ((EventItem == NextEvent->EventItem->EventId) &&
  1006. (!EventGuid || IsEqualGUIDAligned(EventGuid, NextEvent->EventSet->Set))) {
  1007. //
  1008. // if we are to return the 1st event which matches, break.
  1009. //
  1010. if (!CurrentEvent) {
  1011. ReturnEvent = NextEvent;
  1012. break;
  1013. } // if !current
  1014. //
  1015. // if we are to return the next event after the specified one,
  1016. // check
  1017. // to see if these match. If they do, zero the specified event
  1018. // so
  1019. // that we will return the next event of the specified type.
  1020. //
  1021. if (CurrentEvent == NextEvent) {
  1022. CurrentEvent = NULL;
  1023. } // if cur=next
  1024. } // if guid & id match
  1025. } // while events
  1026. //
  1027. // if we are unsynchronized, release the spinlock acquired in the macro
  1028. // above.
  1029. //
  1030. ASSERT(--DeviceExtension->LowerApiThreads == 0); // typo barfs. but this is truely ok
  1031. if (DeviceExtension->NoSync) {
  1032. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  1033. }
  1034. //
  1035. // return the next event, if any.
  1036. //
  1037. return (ReturnEvent);
  1038. }
  1039. VOID
  1040. StreamClassQueryMasterClock(
  1041. IN PHW_STREAM_OBJECT HwStreamObject,
  1042. IN HANDLE MasterClockHandle,
  1043. IN TIME_FUNCTION TimeFunction,
  1044. IN PHW_QUERY_CLOCK_ROUTINE ClockCallbackRoutine
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Arguments:
  1049. HwStreamObject - address of minidriver's stream struct
  1050. Context - value to pass into the time callback routine
  1051. Return Value:
  1052. none
  1053. --*/
  1054. {
  1055. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(HwStreamObject,
  1056. STREAM_OBJECT,
  1057. HwStreamObject);
  1058. PDEVICE_EXTENSION DeviceExtension =
  1059. (PDEVICE_EXTENSION) StreamObject->DeviceExtension;
  1060. KIRQL Irql;
  1061. #if DBG
  1062. if (DeviceExtension->NoSync) {
  1063. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1064. } // if nosync
  1065. #endif
  1066. BEGIN_MINIDRIVER_STREAM_CALLIN(DeviceExtension, &Irql);
  1067. //
  1068. // save away the parameters for the clock query. The DPC will do the
  1069. // actual processing.
  1070. //
  1071. StreamObject->ComObj.InterruptData.HwQueryClockRoutine = ClockCallbackRoutine;
  1072. StreamObject->ComObj.InterruptData.HwQueryClockFunction = TimeFunction;
  1073. StreamObject->ComObj.InterruptData.Flags |= INTERRUPT_FLAGS_CLOCK_QUERY_REQUEST;
  1074. END_MINIDRIVER_STREAM_CALLIN(StreamObject, &Irql);
  1075. }
  1076. #if ENABLE_MULTIPLE_FILTER_TYPES
  1077. VOID
  1078. StreamClassFilterReenumerateStreams(
  1079. IN PVOID HwInstanceExtension,
  1080. IN ULONG StreamDescriptorSize )
  1081. /*++
  1082. Description:
  1083. Reenumerates all streams on the filter instance.
  1084. This is used to increase the number of pins exposed to
  1085. the world so that application can make connections on
  1086. new streams exposed. It's caller's responsibility
  1087. not to change the order of the streams that have been
  1088. open ( connected ). If there is no reduction of the streams
  1089. This won't be an issue.
  1090. Arguments;
  1091. HwInstanceExtension:
  1092. The instanc extension pointer we gave to the mini driver
  1093. StreamDecriptorSize:
  1094. # of bytes to contain the new stream descriptor for the filter
  1095. Return Valuse:
  1096. None
  1097. --*/
  1098. {
  1099. PFILTER_INSTANCE FilterInstance;
  1100. PDEVICE_EXTENSION DeviceExtension;
  1101. KIRQL Irql;
  1102. FilterInstance = ( PFILTER_INSTANCE ) HwInstanceExtension -1;
  1103. DeviceExtension = FilterInstance->DeviceExtension;
  1104. //
  1105. // take the spinlock if we are unsynchronized.
  1106. //
  1107. #if DBG
  1108. if (DeviceExtension->NoSync) {
  1109. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1110. }
  1111. # endif
  1112. BEGIN_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  1113. //
  1114. // show that we need to rescan the stream info, and set the new size in
  1115. // the config info structure.
  1116. //
  1117. DeviceExtension->ComObj.InterruptData.Flags |=
  1118. INTERRUPT_FLAGS_NEED_STREAM_RESCAN;
  1119. InterlockedExchange( &FilterInstance->NeedReenumeration, 1 );
  1120. FilterInstance->StreamDescriptorSize = StreamDescriptorSize;
  1121. //
  1122. // queue a DPC to service the request.
  1123. //
  1124. END_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  1125. return;
  1126. }
  1127. #endif // ENABLE_MULTIPLE_FILTER_TYPES
  1128. VOID
  1129. StreamClassReenumerateStreams(
  1130. IN PVOID HwDeviceExtension,
  1131. IN ULONG StreamDescriptorSize
  1132. )
  1133. /*++
  1134. Routine Description:
  1135. Reenumerates all streams on the device
  1136. Arguments:
  1137. HwDeviceExtension - pointer to minidriver's device extension
  1138. StreamDescriptorSize - size of the buffer needed by the minidriver to
  1139. hold the stream info.
  1140. Return Value:
  1141. none
  1142. --*/
  1143. {
  1144. PDEVICE_EXTENSION DeviceExtension =
  1145. (PDEVICE_EXTENSION) HwDeviceExtension - 1;
  1146. KIRQL Irql;
  1147. //
  1148. // take the spinlock if we are unsynchronized.
  1149. //
  1150. TRAP;
  1151. #if DBG
  1152. if (DeviceExtension->NoSync) {
  1153. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1154. } // if nosync
  1155. #endif
  1156. BEGIN_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  1157. //
  1158. // show that we need to rescan the stream info, and set the new size in
  1159. // the config info structure.
  1160. //
  1161. ASSERT(!DeviceExtension->ComObj.InterruptData.Flags &
  1162. INTERRUPT_FLAGS_NEED_STREAM_RESCAN);
  1163. DeviceExtension->ComObj.InterruptData.Flags |=
  1164. INTERRUPT_FLAGS_NEED_STREAM_RESCAN;
  1165. DeviceExtension->ConfigurationInformation->StreamDescriptorSize =
  1166. StreamDescriptorSize;
  1167. //
  1168. // queue a DPC to service the request.
  1169. //
  1170. END_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  1171. return;
  1172. }
  1173. #define FCC(ch4) ((((DWORD)(ch4) & 0xFF) << 24) | \
  1174. (((DWORD)(ch4) & 0xFF00) << 8) | \
  1175. (((DWORD)(ch4) & 0xFF0000) >> 8) | \
  1176. (((DWORD)(ch4) & 0xFF000000) >> 24))
  1177. // OK to have zero instances of pin In this case you will have to
  1178. // Create a pin to have even one instance
  1179. #define REG_PIN_B_ZERO 0x1
  1180. // The filter renders this input
  1181. #define REG_PIN_B_RENDERER 0x2
  1182. // OK to create many instance of pin
  1183. #define REG_PIN_B_MANY 0x4
  1184. // This is an Output pin
  1185. #define REG_PIN_B_OUTPUT 0x8
  1186. typedef struct {
  1187. ULONG Version;
  1188. ULONG Merit;
  1189. ULONG Pins;
  1190. ULONG Reserved;
  1191. } REGFILTER_REG;
  1192. typedef struct {
  1193. ULONG Signature;
  1194. ULONG Flags;
  1195. ULONG PossibleInstances;
  1196. ULONG MediaTypes;
  1197. ULONG MediumTypes;
  1198. ULONG CategoryOffset;
  1199. ULONG MediumOffset; // By definition, we always have a Medium
  1200. //#ifdef _WIN64
  1201. //This method create filterdata that upset ring3 code.
  1202. //ULONG ulPad; // align to quadword to make ia64 happy
  1203. //#endif
  1204. } REGFILTERPINS_REG2;
  1205. NTSTATUS
  1206. StreamClassRegisterFilterWithNoKSPins(
  1207. IN PDEVICE_OBJECT DeviceObject,
  1208. IN const GUID * InterfaceClassGUID,
  1209. IN ULONG PinCount,
  1210. IN BOOL * PinDirection,
  1211. IN KSPIN_MEDIUM * MediumList,
  1212. IN OPTIONAL GUID * CategoryList
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. This routine is used to register filters with DShow which have no
  1217. KS pins and therefore do not stream in kernel mode. This is typically
  1218. used for TvTuners, Crossbars, and the like. On exit, a new binary
  1219. registry key, "FilterData" is created which contains the Mediums and
  1220. optionally the Categories for each pin on the filter.
  1221. Arguments:
  1222. DeviceObject -
  1223. Device object
  1224. InterfaceClassGUID
  1225. GUID representing the class to register
  1226. PinCount -
  1227. Count of the number of pins on this filter
  1228. PinDirection -
  1229. Array of BOOLS indicating pin direction for each pin (length PinCount)
  1230. If TRUE, this pin is an output pin
  1231. MediumList -
  1232. Array of PKSMEDIUM_DATA (length PinCount)
  1233. CategoryList -
  1234. Array of GUIDs indicating pin categories (length PinCount) OPTIONAL
  1235. Return Value:
  1236. NTSTATUS SUCCESS if the Blob was created
  1237. --*/
  1238. {
  1239. NTSTATUS Status;
  1240. ULONG CurrentPin;
  1241. ULONG TotalCategories;
  1242. REGFILTER_REG *RegFilter;
  1243. REGFILTERPINS_REG2 UNALIGNED * RegPin;
  1244. GUID UNALIGNED * CategoryCache;
  1245. KSPIN_MEDIUM UNALIGNED * MediumCache;
  1246. ULONG FilterDataLength;
  1247. PUCHAR FilterData;
  1248. PWSTR SymbolicLinkList;
  1249. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1250. if ((PinCount == 0) || (!InterfaceClassGUID) || (!PinDirection) || (!MediumList)) {
  1251. return STATUS_INVALID_DEVICE_REQUEST;
  1252. }
  1253. //
  1254. // Calculate the maximum amount of space which could be taken up by
  1255. // this cache data.
  1256. //
  1257. TotalCategories = (CategoryList ? PinCount : 0);
  1258. FilterDataLength = sizeof(REGFILTER_REG) +
  1259. PinCount * sizeof(REGFILTERPINS_REG2) +
  1260. PinCount * sizeof(KSPIN_MEDIUM) +
  1261. TotalCategories * sizeof(GUID);
  1262. //
  1263. // Allocate space to create the BLOB
  1264. //
  1265. FilterData = ExAllocatePool(PagedPool, FilterDataLength);
  1266. if (!FilterData) {
  1267. return STATUS_INSUFFICIENT_RESOURCES;
  1268. }
  1269. //
  1270. // Place the header in the data, defaulting the Merit to "unused".
  1271. //
  1272. DebugPrint((DebugLevelTrace,
  1273. "FilterData:%p\n",
  1274. FilterData ));
  1275. RegFilter = (REGFILTER_REG *) FilterData;
  1276. RegFilter->Version = 2;
  1277. RegFilter->Merit = 0x200000;
  1278. RegFilter->Pins = PinCount;
  1279. RegFilter->Reserved = 0;
  1280. //
  1281. // Calculate the offset to the list of pins, and to the
  1282. // MediumList and CategoryList
  1283. //
  1284. RegPin = (REGFILTERPINS_REG2 *) (RegFilter + 1);
  1285. MediumCache = (PKSPIN_MEDIUM) ((PUCHAR) (RegPin + PinCount));
  1286. CategoryCache = (GUID *) (MediumCache + PinCount);
  1287. //
  1288. // Create each pin header, followed by the list of Mediums
  1289. // followed by the list of optional categories.
  1290. //
  1291. for (CurrentPin = 0; CurrentPin < PinCount; CurrentPin++, RegPin++) {
  1292. //
  1293. // Initialize the pin header.
  1294. //
  1295. DebugPrint((DebugLevelTrace,
  1296. "CurrentPin:%d RegPin:%p MediumCache:%p CategoryCache:%p\n",
  1297. CurrentPin, RegPin, MediumCache, CategoryCache ));
  1298. RegPin->Signature = FCC('0pi3');
  1299. (*(PUCHAR) & RegPin->Signature) += (BYTE) CurrentPin;
  1300. RegPin->Flags = (PinDirection[CurrentPin] ? REG_PIN_B_OUTPUT : 0);
  1301. RegPin->PossibleInstances = 1;
  1302. RegPin->MediaTypes = 0;
  1303. RegPin->MediumTypes = 1;
  1304. RegPin->MediumOffset = (ULONG) ((PUCHAR) MediumCache - (PUCHAR) FilterData);
  1305. *MediumCache++ = MediumList[CurrentPin];
  1306. if (CategoryList) {
  1307. RegPin->CategoryOffset = (ULONG) ((PUCHAR) CategoryCache - (PUCHAR) FilterData);
  1308. *CategoryCache++ = CategoryList[CurrentPin];
  1309. } else {
  1310. RegPin->CategoryOffset = 0;
  1311. }
  1312. }
  1313. //
  1314. // Now create the BLOB in the registry
  1315. //
  1316. //
  1317. // Note for using the flag DEVICE_INTERFACE_INCLUDE_NONACTIVE following:
  1318. // PnP change circa 3/30/99 made the funtion IoSetDeviceInterfaceState() become
  1319. // asynchronous. It returns SUCCESS even when the enabling is deferred. Now when
  1320. // we arrive here, the DeviceInterface is still not enabled, we receive empty
  1321. // Symbolic link if the flag is not set. Here we only try to write relevent
  1322. // FilterData to the registry. I argue this should be fine for
  1323. // 1. Currently, if a device is removed, the registry key for the DeviceClass
  1324. // remains and with FilterData.Whatever components use the FilterData should
  1325. // be able to handle if the device is removed by either check Control\Linked
  1326. // or handling the failure in attempt to make connection to the non-exiting device.
  1327. // 2. I have found that if a device is moved between slots ( PCI, USB ports ) the
  1328. // DeviceInterface at DeviceClass is reused or at lease become the first entry in
  1329. // the registry. Therefore, we will be updating the right entry with the proposed flag.
  1330. //
  1331. if (NT_SUCCESS(Status = IoGetDeviceInterfaces(
  1332. InterfaceClassGUID, // ie.&KSCATEGORY_TVTUNER,etc.
  1333. DeviceObject, // IN PDEVICE_OBJECT PhysicalDeviceObject,OPTIONAL,
  1334. DEVICE_INTERFACE_INCLUDE_NONACTIVE, // IN ULONG Flags,
  1335. &SymbolicLinkList // OUT PWSTR *SymbolicLinkList
  1336. ))) {
  1337. UNICODE_STRING SymbolicLinkListU;
  1338. HANDLE DeviceInterfaceKey;
  1339. RtlInitUnicodeString(&SymbolicLinkListU, SymbolicLinkList);
  1340. DebugPrint((DebugLevelVerbose,
  1341. "NoKSPin for SymbolicLink %S\n",
  1342. SymbolicLinkList ));
  1343. if (NT_SUCCESS(Status = IoOpenDeviceInterfaceRegistryKey(
  1344. &SymbolicLinkListU, // IN PUNICODE_STRING SymbolicLinkName,
  1345. STANDARD_RIGHTS_ALL, // IN ACCESS_MASK DesiredAccess,
  1346. &DeviceInterfaceKey // OUT PHANDLE DeviceInterfaceKey
  1347. ))) {
  1348. UNICODE_STRING FilterDataString;
  1349. RtlInitUnicodeString(&FilterDataString, L"FilterData");
  1350. Status = ZwSetValueKey(DeviceInterfaceKey,
  1351. &FilterDataString,
  1352. 0,
  1353. REG_BINARY,
  1354. FilterData,
  1355. FilterDataLength);
  1356. ZwClose(DeviceInterfaceKey);
  1357. }
  1358. // START NEW MEDIUM CACHING CODE
  1359. for (CurrentPin = 0; CurrentPin < PinCount; CurrentPin++) {
  1360. NTSTATUS LocalStatus;
  1361. LocalStatus = KsCacheMedium(&SymbolicLinkListU,
  1362. &MediumList[CurrentPin],
  1363. (DWORD) ((PinDirection[CurrentPin] ? 1 : 0)) // 1 == output
  1364. );
  1365. #if DBG
  1366. if (LocalStatus != STATUS_SUCCESS) {
  1367. DebugPrint((DebugLevelError,
  1368. "KsCacheMedium: SymbolicLink = %S, Status = %x\n",
  1369. SymbolicLinkListU.Buffer, LocalStatus));
  1370. }
  1371. #endif
  1372. }
  1373. // END NEW MEDIUM CACHING CODE
  1374. ExFreePool(SymbolicLinkList);
  1375. }
  1376. ExFreePool(RegFilter);
  1377. return Status;
  1378. }
  1379. BOOLEAN
  1380. StreamClassReadWriteConfig(
  1381. IN PVOID HwDeviceExtension,
  1382. IN BOOLEAN Read,
  1383. IN PVOID Buffer,
  1384. IN ULONG Offset,
  1385. IN ULONG Length
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. Sends down a config space read/write. MUST BE CALLED AT PASSIVE LEVEL!
  1390. Arguments:
  1391. HwDeviceExtension - device extension
  1392. Read - TRUE if read, FALSE if write.
  1393. Buffer - The info to read or write.
  1394. Offset - The offset in config space to read or write.
  1395. Length - The length to transfer.
  1396. Return Value:
  1397. None.
  1398. --*/
  1399. {
  1400. PIO_STACK_LOCATION nextStack;
  1401. PIRP irp;
  1402. NTSTATUS ntStatus;
  1403. KEVENT event;
  1404. PDEVICE_EXTENSION DeviceExtension =
  1405. (PDEVICE_EXTENSION) HwDeviceExtension - 1;
  1406. PDEVICE_OBJECT DeviceObject = DeviceExtension->DeviceObject;
  1407. PAGED_CODE();
  1408. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1409. if (Read) {
  1410. memset(Buffer, '\0', Length);
  1411. }
  1412. irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  1413. if (!irp) {
  1414. DebugPrint((DebugLevelError, "StreamClassRWConfig: no IRP.\n"));
  1415. TRAP;
  1416. return (FALSE);
  1417. }
  1418. //
  1419. // new rule says all PnP Irp must be initialized to this
  1420. //
  1421. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1422. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1423. IoSetCompletionRoutine(irp,
  1424. SCSynchCompletionRoutine,
  1425. &event,
  1426. TRUE,
  1427. TRUE,
  1428. TRUE);
  1429. nextStack = IoGetNextIrpStackLocation(irp);
  1430. ASSERT(nextStack != NULL);
  1431. nextStack->MajorFunction = IRP_MJ_PNP;
  1432. nextStack->MinorFunction = Read ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG;
  1433. nextStack->Parameters.ReadWriteConfig.WhichSpace = 0;
  1434. nextStack->Parameters.ReadWriteConfig.Buffer = Buffer;
  1435. nextStack->Parameters.ReadWriteConfig.Offset = Offset;
  1436. nextStack->Parameters.ReadWriteConfig.Length = Length;
  1437. ASSERT( DeviceExtension->HwDeviceExtension == HwDeviceExtension );
  1438. ntStatus = IoCallDriver(DeviceExtension->PhysicalDeviceObject,
  1439. irp);
  1440. if (ntStatus == STATUS_PENDING) {
  1441. // wait for irp to complete
  1442. TRAP;
  1443. KeWaitForSingleObject(
  1444. &event,
  1445. Suspended,
  1446. KernelMode,
  1447. FALSE,
  1448. NULL);
  1449. }
  1450. if (!NT_SUCCESS(ntStatus)) {
  1451. DebugPrint((DebugLevelError, "StreamClassRWConfig: bad status!.\n"));
  1452. TRAP;
  1453. }
  1454. IoFreeIrp(irp);
  1455. return (TRUE);
  1456. }
  1457. VOID
  1458. StreamClassQueryMasterClockSync(
  1459. IN HANDLE MasterClockHandle,
  1460. IN OUT PHW_TIME_CONTEXT TimeContext
  1461. )
  1462. /*++
  1463. Routine Description:
  1464. synchronously returns the current time requested, based on the TimeContext
  1465. parameter.
  1466. Arguments:
  1467. Return Value:
  1468. none
  1469. --*/
  1470. {
  1471. PHW_STREAM_OBJECT HwStreamObject = TimeContext->HwStreamObject;
  1472. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(HwStreamObject,
  1473. STREAM_OBJECT,
  1474. HwStreamObject);
  1475. LARGE_INTEGER ticks;
  1476. ULONGLONG rate;
  1477. KIRQL SavedIrql;
  1478. ASSERT(MasterClockHandle);
  1479. ASSERT(TimeContext->HwDeviceExtension);
  1480. ASSERT(HwStreamObject);
  1481. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1482. //
  1483. // Lock the use of MasterClock, so it won't dispear under us
  1484. //
  1485. KeAcquireSpinLock( &StreamObject->LockUseMasterClock, &SavedIrql );
  1486. if ( NULL == StreamObject->MasterClockInfo ) {
  1487. //
  1488. // If we are called when MasterClockInfo is NULL,
  1489. // the mini driver has screwed up. We don't want to fault.
  1490. //
  1491. ASSERT(0 && "Mini driver queries clock while there is no master clock" );
  1492. //
  1493. // give a hint that something is wrong via Time, since we return void.
  1494. //
  1495. TimeContext->Time = (ULONGLONG)-1;
  1496. goto Exit;
  1497. }
  1498. //
  1499. // process the requested time function
  1500. //
  1501. switch (TimeContext->Function) {
  1502. case TIME_GET_STREAM_TIME:
  1503. TimeContext->Time = StreamObject->MasterClockInfo->
  1504. FunctionTable.GetCorrelatedTime(
  1505. StreamObject->MasterClockInfo->ClockFileObject,
  1506. &TimeContext->SystemTime);
  1507. break;
  1508. case TIME_READ_ONBOARD_CLOCK:
  1509. TRAP;
  1510. TimeContext->Time = StreamObject->MasterClockInfo->
  1511. FunctionTable.GetTime(
  1512. StreamObject->MasterClockInfo->ClockFileObject);
  1513. //
  1514. // timestamp the value as close as possible
  1515. //
  1516. ticks = KeQueryPerformanceCounter((PLARGE_INTEGER) & rate);
  1517. TimeContext->SystemTime = KSCONVERT_PERFORMANCE_TIME( rate, ticks );
  1518. break;
  1519. default:
  1520. DebugPrint((DebugLevelFatal, "SCQueryClockSync: unknown type!"));
  1521. TRAP;
  1522. }
  1523. Exit:
  1524. KeReleaseSpinLock( &StreamObject->LockUseMasterClock, SavedIrql );
  1525. return;
  1526. }
  1527. VOID
  1528. StreamClassCompleteRequestAndMarkQueueReady(
  1529. IN PHW_STREAM_REQUEST_BLOCK Srb
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. completes a stream request and marks the appropriate queue as ready for next
  1534. Arguments:
  1535. Return Value:
  1536. none
  1537. --*/
  1538. {
  1539. PDEVICE_EXTENSION DeviceExtension =
  1540. (PDEVICE_EXTENSION) Srb->HwDeviceExtension - 1;
  1541. ASSERT(!(DeviceExtension->NoSync));
  1542. ASSERT(Srb->Status != STATUS_PENDING);
  1543. DebugPrint((DebugLevelTrace, "'StreamClassComplete&Mark:SRB = %p\n",
  1544. Srb));
  1545. switch (Srb->Flags & (SRB_HW_FLAGS_DATA_TRANSFER |
  1546. SRB_HW_FLAGS_STREAM_REQUEST)) {
  1547. case SRB_HW_FLAGS_STREAM_REQUEST | SRB_HW_FLAGS_DATA_TRANSFER:
  1548. StreamClassStreamNotification(StreamRequestComplete,
  1549. Srb->StreamObject,
  1550. Srb);
  1551. StreamClassStreamNotification(ReadyForNextStreamDataRequest,
  1552. Srb->StreamObject);
  1553. break;
  1554. case SRB_HW_FLAGS_STREAM_REQUEST:
  1555. StreamClassStreamNotification(StreamRequestComplete,
  1556. Srb->StreamObject,
  1557. Srb);
  1558. StreamClassStreamNotification(ReadyForNextStreamControlRequest,
  1559. Srb->StreamObject);
  1560. break;
  1561. default:
  1562. StreamClassDeviceNotification(DeviceRequestComplete,
  1563. Srb->HwDeviceExtension,
  1564. Srb);
  1565. StreamClassDeviceNotification(ReadyForNextDeviceRequest,
  1566. Srb->HwDeviceExtension);
  1567. break;
  1568. } // switch
  1569. }
  1570. #if ENABLE_MULTIPLE_FILTER_TYPES
  1571. VOID STREAMAPI
  1572. StreamClassFilterNotification(
  1573. IN STREAM_MINIDRIVER_DEVICE_NOTIFICATION_TYPE NotificationType,
  1574. IN PVOID HwInstanceExtension,
  1575. ...
  1576. );
  1577. VOID STREAMAPI
  1578. StreamClassFilterScheduleTimer(
  1579. IN PVOID HwInstanceExtension,
  1580. IN ULONG NumberOfMicroseconds,
  1581. IN PHW_TIMER_ROUTINE TimerRoutine,
  1582. IN PVOID Context
  1583. );
  1584. PKSEVENT_ENTRY
  1585. StreamClassDeviceInstanceGetNextEvent(
  1586. IN PVOID HwInstanceExtension,
  1587. IN OPTIONAL GUID * EventGuid,
  1588. IN OPTIONAL ULONG EventItem,
  1589. IN OPTIONAL PKSEVENT_ENTRY CurrentEvent
  1590. )
  1591. /*++
  1592. Routine Description:
  1593. Arguments:
  1594. CurrentEvent - event (if any) to get the next from
  1595. Return Value:
  1596. next event, if any
  1597. --*/
  1598. {
  1599. PFILTER_INSTANCE FilterInstance= (PFILTER_INSTANCE)
  1600. HwInstanceExtension - 1;
  1601. PDEVICE_EXTENSION DeviceExtension =
  1602. FilterInstance->DeviceObject->DeviceExtension;
  1603. PLIST_ENTRY EventListEntry, EventEntry;
  1604. PKSEVENT_ENTRY NextEvent, ReturnEvent = NULL;
  1605. KIRQL Irql;
  1606. #if DBG
  1607. if (DeviceExtension->NoSync) {
  1608. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1609. } // if nosync
  1610. #endif
  1611. //
  1612. // take the spinlock if we are unsynchronized.
  1613. //
  1614. BEGIN_MINIDRIVER_DEVICE_CALLIN(DeviceExtension, &Irql);
  1615. //
  1616. // loop thru the events, trying to find the requested one.
  1617. //
  1618. EventListEntry = EventEntry = &FilterInstance->NotifyList;
  1619. while (EventEntry->Flink != EventListEntry) {
  1620. EventEntry = EventEntry->Flink;
  1621. NextEvent = CONTAINING_RECORD(EventEntry,
  1622. KSEVENT_ENTRY,
  1623. ListEntry);
  1624. if ((EventItem == NextEvent->EventItem->EventId) &&
  1625. (!EventGuid || IsEqualGUIDAligned(EventGuid, NextEvent->EventSet->Set))) {
  1626. //
  1627. // if we are to return the 1st event which matches, break.
  1628. //
  1629. if (!CurrentEvent) {
  1630. ReturnEvent = NextEvent;
  1631. break;
  1632. } // if !current
  1633. //
  1634. // if we are to return the next event after the specified one,
  1635. // check
  1636. // to see if these match. If they do, zero the specified event
  1637. // so
  1638. // that we will return the next event of the specified type.
  1639. //
  1640. if (CurrentEvent == NextEvent) {
  1641. CurrentEvent = NULL;
  1642. } // if cur=next
  1643. } // if guid & id match
  1644. } // while events
  1645. //
  1646. // if we are unsynchronized, release the spinlock acquired in the macro
  1647. // above.
  1648. //
  1649. ASSERT(--DeviceExtension->LowerApiThreads == 0); // typo barfs. but this is truely ok.
  1650. if (DeviceExtension->NoSync) {
  1651. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  1652. }
  1653. //
  1654. // return the next event, if any.
  1655. //
  1656. return (ReturnEvent);
  1657. }
  1658. #endif // ENABLE_MULTIPLE_FILTER_TYPES