Source code of Windows XP (NT5)
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.

7438 lines
194 KiB

  1. /* ++
  2. *
  3. * Copyright (c) 1996 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * codguts.c
  8. *
  9. * Abstract:
  10. *
  11. * This is the WDM streaming class driver. This module contains code related
  12. * to internal processing.
  13. *
  14. * Author:
  15. *
  16. * billpa
  17. *
  18. * Environment:
  19. *
  20. * Kernel mode only
  21. *
  22. *
  23. * Revision History:
  24. *
  25. * -- */
  26. #include "codcls.h"
  27. #include <stdlib.h>
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, SCBuildRequestPacket)
  30. #pragma alloc_text(PAGE, SCProcessDmaDataBuffers)
  31. #pragma alloc_text(PAGE, SCProcessPioDataBuffers)
  32. #pragma alloc_text(PAGE, SCOpenMinidriverInstance)
  33. #pragma alloc_text(PAGE, SCMinidriverDevicePropertyHandler)
  34. #pragma alloc_text(PAGE, SCMinidriverStreamPropertyHandler)
  35. #pragma alloc_text(PAGE, SCUpdateMinidriverProperties)
  36. #pragma alloc_text(PAGE, SCProcessCompletedPropertyRequest)
  37. #pragma alloc_text(PAGE, SCLogError)
  38. #pragma alloc_text(PAGE, SCLogErrorWithString)
  39. #pragma alloc_text(PAGE, SCReferenceDriver)
  40. #pragma alloc_text(PAGE, SCDereferenceDriver)
  41. #pragma alloc_text(PAGE, SCReadRegistryValues)
  42. #pragma alloc_text(PAGE, SCGetRegistryValue)
  43. #pragma alloc_text(PAGE, SCSubmitRequest)
  44. #pragma alloc_text(PAGE, SCProcessDataTransfer)
  45. #pragma alloc_text(PAGE, SCShowIoPending)
  46. #pragma alloc_text(PAGE, SCCheckPoweredUp)
  47. #pragma alloc_text(PAGE, SCCheckPowerDown)
  48. #pragma alloc_text(PAGE, SCCallNextDriver)
  49. #pragma alloc_text(PAGE, SCSendUnknownCommand)
  50. #pragma alloc_text(PAGE, SCMapMemoryAddress)
  51. #pragma alloc_text(PAGE, SCUpdatePersistedProperties)
  52. #pragma alloc_text(PAGE, SCProcessCompletedPropertyRequest)
  53. #pragma alloc_text(PAGE, SCUpdateMinidriverEvents)
  54. #pragma alloc_text(PAGE, SCQueryCapabilities)
  55. #pragma alloc_text(PAGE, SCRescanStreams)
  56. #pragma alloc_text(PAGE, SCCopyMinidriverProperties)
  57. #pragma alloc_text(PAGE, SCCopyMinidriverEvents)
  58. #endif
  59. #ifdef ENABLE_KS_METHODS
  60. #pragma alloc_text(PAGE, SCCopyMinidriverMethods)
  61. #endif
  62. #ifdef ALLOC_DATA_PRAGMA
  63. #pragma const_seg("PAGECONST")
  64. #endif
  65. extern KSDISPATCH_TABLE FilterDispatchTable;
  66. //
  67. // registry string indicating that the minidriver should be paged out when
  68. // unopened
  69. //
  70. static const WCHAR PageOutWhenUnopenedString[] = L"PageOutWhenUnopened";
  71. //
  72. // registry string indicating that the minidriver should be paged out when
  73. // idle
  74. //
  75. static const WCHAR PageOutWhenIdleString[] = L"PageOutWhenIdle";
  76. //
  77. // registry string indicating that the device should be powered down when
  78. // unopened
  79. //
  80. static const WCHAR PowerDownWhenUnopenedString[] = L"PowerDownWhenUnopened";
  81. //
  82. // registry string indicating that the device should not be suspended when
  83. // pins are in run state
  84. //
  85. static const WCHAR DontSuspendIfStreamsAreRunning[] = L"DontSuspendIfStreamsAreRunning";
  86. //
  87. // This driver uses SWEnum to load, which means it is a kernel mode
  88. // streaming driver that has no hardware associated with it. We need to
  89. // AddRef/DeRef this driver special.
  90. //
  91. static const WCHAR DriverUsesSWEnumToLoad[] = L"DriverUsesSWEnumToLoad";
  92. //
  93. //
  94. //
  95. static const WCHAR OkToHibernate[] = L"OkToHibernate";
  96. //
  97. // array of registry settings to be read when the device is initialized
  98. //
  99. static const STREAM_REGISTRY_ENTRY RegistrySettings[] = {
  100. {
  101. (PWCHAR) PageOutWhenUnopenedString,
  102. sizeof(PageOutWhenUnopenedString),
  103. DEVICE_REG_FL_PAGE_CLOSED
  104. },
  105. {
  106. (PWCHAR) PageOutWhenIdleString,
  107. sizeof(PageOutWhenIdleString),
  108. DEVICE_REG_FL_PAGE_IDLE
  109. },
  110. {
  111. (PWCHAR) PowerDownWhenUnopenedString,
  112. sizeof(PowerDownWhenUnopenedString),
  113. DEVICE_REG_FL_POWER_DOWN_CLOSED
  114. },
  115. {
  116. (PWCHAR) DontSuspendIfStreamsAreRunning,
  117. sizeof(DontSuspendIfStreamsAreRunning),
  118. DEVICE_REG_FL_NO_SUSPEND_IF_RUNNING
  119. },
  120. {
  121. (PWCHAR) DriverUsesSWEnumToLoad,
  122. sizeof(DriverUsesSWEnumToLoad),
  123. DRIVER_USES_SWENUM_TO_LOAD
  124. },
  125. {
  126. (PWCHAR) OkToHibernate,
  127. sizeof(OkToHibernate),
  128. DEVICE_REG_FL_OK_TO_HIBERNATE
  129. }
  130. };
  131. //
  132. // this structure indicates the handlers for CreateFile on Streams
  133. //
  134. static const WCHAR PinTypeName[] = KSSTRING_Pin;
  135. static const KSOBJECT_CREATE_ITEM CreateHandlers[] = {
  136. DEFINE_KSCREATE_ITEM(StreamDispatchCreate,
  137. PinTypeName,
  138. 0)
  139. };
  140. #ifdef ALLOC_DATA_PRAGMA
  141. #pragma const_seg()
  142. #endif
  143. //
  144. // Routines start
  145. //
  146. NTSTATUS
  147. SCDequeueAndStartStreamDataRequest(
  148. IN PSTREAM_OBJECT StreamObject
  149. )
  150. /*++
  151. Routine Description:
  152. Start the queued data IRP for the stream.
  153. THE SPINLOCK MUST BE TAKEN ON THIS CALL AND A DATA IRP MUST BE ON THE
  154. QUEUE!
  155. Arguments:
  156. StreamObject - address of stream info structure.
  157. Return Value:
  158. NTSTATUS returned
  159. --*/
  160. {
  161. PIRP Irp;
  162. PSTREAM_REQUEST_BLOCK Request;
  163. PLIST_ENTRY Entry;
  164. BOOLEAN Status;
  165. PDEVICE_EXTENSION DeviceExtension = StreamObject->DeviceExtension;
  166. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  167. Entry = RemoveTailList(&StreamObject->DataPendingQueue);
  168. Irp = CONTAINING_RECORD(Entry,
  169. IRP,
  170. Tail.Overlay.ListEntry);
  171. ASSERT(Irp);
  172. // ASSERT((IoGetCurrentIrpStackLocation(Irp)->MajorFunction ==
  173. // IOCTL_KS_READ_STREAM) ||
  174. // (IoGetCurrentIrpStackLocation(Irp)->MajorFunction ==
  175. // IOCTL_KS_WRITE_STREAM));
  176. ASSERT((ULONG_PTR) Irp->Tail.Overlay.DriverContext[0] > 0x40000000);
  177. DebugPrint((DebugLevelVerbose, "'SCStartStreamDataReq: Irp = %x, S# = %x\n",
  178. Irp, StreamObject->HwStreamObject.StreamNumber));
  179. //
  180. // clear the ready flag as we are going to send one down.
  181. //
  182. ASSERT(StreamObject->ReadyForNextDataReq);
  183. StreamObject->ReadyForNextDataReq = FALSE;
  184. //
  185. // set the cancel routine to outstanding
  186. //
  187. IoSetCancelRoutine(Irp, StreamClassCancelOutstandingIrp);
  188. //
  189. // release the spinlock.
  190. //
  191. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  192. //
  193. // get the request packet from the IRP
  194. //
  195. Request = Irp->Tail.Overlay.DriverContext[0];
  196. //
  197. // build scatter/gather list if necessary
  198. //
  199. if (StreamObject->HwStreamObject.Dma) {
  200. //
  201. // allocate the adapter channel. call cannot fail as the only
  202. // time it would is when there aren't enough map registers, and
  203. // we've already checked for that condition.
  204. //
  205. Status = SCSetUpForDMA(DeviceExtension->DeviceObject,
  206. Request);
  207. ASSERT(Status);
  208. //
  209. // DMA adapter allocation requires a
  210. // callback, so just exit
  211. //
  212. return (STATUS_PENDING);
  213. } // if DMA
  214. //
  215. // start the request for the PIO case.
  216. //
  217. SCStartMinidriverRequest(StreamObject,
  218. Request,
  219. (PVOID)
  220. StreamObject->HwStreamObject.ReceiveDataPacket);
  221. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  222. return (STATUS_PENDING);
  223. }
  224. NTSTATUS
  225. SCDequeueAndStartStreamControlRequest(
  226. IN PSTREAM_OBJECT StreamObject
  227. )
  228. /*++
  229. Routine Description:
  230. Start the queued control IRP for the stream.
  231. THE SPINLOCK MUST BE TAKEN ON THIS CALL AND A DATA IRP MUST BE ON THE
  232. QUEUE!
  233. Arguments:
  234. StreamObject - address of stream info structure.
  235. Return Value:
  236. NTSTATUS returned
  237. --*/
  238. {
  239. PIRP Irp;
  240. PSTREAM_REQUEST_BLOCK Request;
  241. PLIST_ENTRY Entry;
  242. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  243. Entry = RemoveTailList(&StreamObject->ControlPendingQueue);
  244. Irp = CONTAINING_RECORD(Entry,
  245. IRP,
  246. Tail.Overlay.ListEntry);
  247. ASSERT(Irp);
  248. DebugPrint((DebugLevelTrace, "'SCStartStreamControlReq: Irp = %x, S# = %x\n",
  249. Irp, StreamObject->HwStreamObject.StreamNumber));
  250. //
  251. // clear the ready flag as we are going
  252. // to send one down.
  253. //
  254. ASSERT(StreamObject->ReadyForNextControlReq);
  255. StreamObject->ReadyForNextControlReq = FALSE;
  256. //
  257. // release the spinlock.
  258. //
  259. KeReleaseSpinLockFromDpcLevel(&StreamObject->DeviceExtension->SpinLock);
  260. //
  261. // get the request packet from the IRP
  262. //
  263. Request = Irp->Tail.Overlay.DriverContext[0];
  264. //
  265. // start the request.
  266. //
  267. SCStartMinidriverRequest(StreamObject,
  268. Request,
  269. (PVOID)
  270. StreamObject->HwStreamObject.ReceiveControlPacket);
  271. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  272. return (STATUS_PENDING);
  273. }
  274. NTSTATUS
  275. SCDequeueAndStartDeviceRequest(
  276. IN PDEVICE_EXTENSION DeviceExtension
  277. )
  278. /*++
  279. Routine Description:
  280. Start the queued device IRP.
  281. THE DEV SPINLOCK MUST BE TAKEN ON THIS CALL AND AN IRP MUST BE ON THE QUEUE!
  282. Arguments:
  283. DeviceExtension - address of device extension.
  284. Return Value:
  285. NTSTATUS
  286. --*/
  287. {
  288. PIRP Irp;
  289. PLIST_ENTRY Entry;
  290. PSTREAM_REQUEST_BLOCK Request;
  291. Entry = RemoveTailList(&DeviceExtension->PendingQueue);
  292. Irp = CONTAINING_RECORD(Entry,
  293. IRP,
  294. Tail.Overlay.ListEntry);
  295. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  296. ASSERT(Irp);
  297. //
  298. // clear the ready flag as we are going
  299. // to send one down.
  300. //
  301. ASSERT(DeviceExtension->ReadyForNextReq);
  302. DeviceExtension->ReadyForNextReq = FALSE;
  303. //
  304. // get the request packet from the IRP
  305. //
  306. Request = Irp->Tail.Overlay.DriverContext[0];
  307. ASSERT(Request);
  308. //
  309. // show that the request is active.
  310. //
  311. Request->Flags |= SRB_FLAGS_IS_ACTIVE;
  312. //
  313. // place the request on the outstanding
  314. // queue
  315. //
  316. InsertHeadList(
  317. &DeviceExtension->OutstandingQueue,
  318. &Request->SRBListEntry);
  319. //
  320. // set the cancel routine to outstanding
  321. //
  322. IoSetCancelRoutine(Irp, StreamClassCancelOutstandingIrp);
  323. //
  324. // send down the request to the
  325. // minidriver.
  326. //
  327. DebugPrint((DebugLevelTrace, "'SCDequeueStartDevice: starting Irp %x, SRB = %x, Command = %x\n",
  328. Request->HwSRB.Irp, Request, Request->HwSRB.Command));
  329. DeviceExtension->SynchronizeExecution(
  330. DeviceExtension->InterruptObject,
  331. (PVOID) DeviceExtension->MinidriverData->HwInitData.HwReceivePacket,
  332. &Request->HwSRB);
  333. //
  334. // release the spinlock.
  335. //
  336. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  337. return (STATUS_PENDING);
  338. }
  339. PSTREAM_REQUEST_BLOCK
  340. SCBuildRequestPacket(
  341. IN PDEVICE_EXTENSION DeviceExtension,
  342. IN PIRP Irp,
  343. IN ULONG AdditionalSize1, // scatter gather size
  344. IN ULONG AdditionalSize2 // saved ptr array size
  345. )
  346. /*++
  347. Routine Description:
  348. Routine builds an SRB and fills in generic fields
  349. Arguments:
  350. DeviceExtension - address of device extension.
  351. Irp - Address of I/O request packet.
  352. AdditionalSize1 - additional size needed for scatter/gather, etc.
  353. AdditionalSize2 - additional size needed for the Saved pointer array.
  354. Return Value:
  355. Address of the streaming request packet.
  356. --*/
  357. {
  358. ULONG BlockSize;
  359. PSTREAM_REQUEST_BLOCK Request;
  360. PAGED_CODE();
  361. //
  362. // compute the size of the block needed.
  363. //
  364. BlockSize = sizeof(STREAM_REQUEST_BLOCK) +
  365. DeviceExtension->
  366. MinidriverData->HwInitData.PerRequestExtensionSize +
  367. AdditionalSize1+
  368. AdditionalSize2;
  369. Request = ExAllocatePool(NonPagedPool, BlockSize);
  370. if (Request == NULL) {
  371. DebugPrint((DebugLevelError,
  372. "SCBuildRequestPacket: No pool for packet"));
  373. ASSERT(0);
  374. return (NULL);
  375. }
  376. //
  377. // alloc MDL for the request.
  378. //
  379. // GUBGUB This a marginal performace enhancment chance.
  380. // - should find a way to avoid allocating both an MDL and
  381. // SRB per request. Maybe have a list of MDL's around and allocate only
  382. // if we run out. Forrest won't like this.
  383. //
  384. //
  385. Request->Mdl = IoAllocateMdl(Request,
  386. BlockSize,
  387. FALSE,
  388. FALSE,
  389. NULL
  390. );
  391. if (Request->Mdl == NULL) {
  392. ExFreePool(Request);
  393. DebugPrint((DebugLevelError,
  394. "SCBuildRequestPacket: can't get MDL"));
  395. return (NULL);
  396. }
  397. MmBuildMdlForNonPagedPool(Request->Mdl);
  398. //
  399. // fill in the various SRB fields
  400. // generically
  401. //
  402. Request->Length = BlockSize;
  403. Request->HwSRB.SizeOfThisPacket = sizeof(HW_STREAM_REQUEST_BLOCK);
  404. Request->HwSRB.Status = STATUS_PENDING;
  405. Request->HwSRB.StreamObject = NULL;
  406. Request->HwSRB.HwInstanceExtension = NULL;
  407. Request->HwSRB.NextSRB = (PHW_STREAM_REQUEST_BLOCK) NULL;
  408. Request->HwSRB.SRBExtension = Request + 1;
  409. Request->HwSRB.Irp = Irp;
  410. Request->Flags = 0;
  411. Request->MapRegisterBase = 0;
  412. Request->HwSRB.Flags = 0;
  413. Request->HwSRB.TimeoutCounter = 15;
  414. Request->HwSRB.TimeoutOriginal = 15;
  415. Request->HwSRB.ScatterGatherBuffer =
  416. (PKSSCATTER_GATHER) ((ULONG_PTR) Request->HwSRB.SRBExtension +
  417. (ULONG_PTR) DeviceExtension->
  418. MinidriverData->HwInitData.PerRequestExtensionSize);
  419. Request->pMemPtrArray = (PVOID) (((ULONG_PTR) Request->HwSRB.SRBExtension +
  420. (ULONG_PTR) DeviceExtension->
  421. MinidriverData->HwInitData.PerRequestExtensionSize) +
  422. AdditionalSize1);
  423. //
  424. // point the IRP workspace to the request
  425. // packet
  426. //
  427. Irp->Tail.Overlay.DriverContext[0] = Request;
  428. return (Request);
  429. } // end SCBuildRequestPacket()
  430. VOID
  431. SCProcessDmaDataBuffers(
  432. IN PKSSTREAM_HEADER FirstHeader,
  433. IN ULONG NumberOfHeaders,
  434. IN PSTREAM_OBJECT StreamObject,
  435. IN PMDL FirstMdl,
  436. OUT PULONG NumberOfPages,
  437. IN ULONG StreamHeaderSize,
  438. IN BOOLEAN Write
  439. )
  440. /*++
  441. Routine Description:
  442. Processes each data buffer for PIO &| DMA case
  443. Arguments:
  444. FirstHeader - Address of the 1st s/g packet
  445. StreamObject- pointer to stream object
  446. NumberOfPages - number of pages in the request
  447. Return Value:
  448. --*/
  449. {
  450. PKSSTREAM_HEADER CurrentHeader;
  451. PMDL CurrentMdl;
  452. ULONG i;
  453. ULONG DataBytes;
  454. PAGED_CODE();
  455. //
  456. // loop through each scatter/gather elements
  457. //
  458. CurrentHeader = FirstHeader;
  459. CurrentMdl = FirstMdl;
  460. for (i = 0; i < NumberOfHeaders; i++) {
  461. //
  462. // pick up the correct data buffer, based on the xfer direction
  463. //
  464. if (Write) {
  465. DataBytes = CurrentHeader->DataUsed;
  466. } else { // if write
  467. DataBytes = CurrentHeader->FrameExtent;
  468. } // if write
  469. //
  470. // if this header has data, process it.
  471. //
  472. if (DataBytes) {
  473. #if DBG
  474. if (CurrentHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID) {
  475. DebugPrint((DebugLevelVerbose, "'SCProcessData: time = %x\n",
  476. CurrentHeader->PresentationTime.Time));
  477. }
  478. #endif
  479. //
  480. // add # pages to total if DMA
  481. //
  482. *NumberOfPages += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  483. MmGetMdlVirtualAddress(CurrentMdl),
  484. DataBytes);
  485. CurrentMdl = CurrentMdl->Next;
  486. }
  487. //
  488. // offset to the next buffer
  489. //
  490. CurrentHeader = ((PKSSTREAM_HEADER) ((PBYTE) CurrentHeader +
  491. StreamHeaderSize));
  492. } // for # elements
  493. } // end SCProcessDmaDataBuffers()
  494. //
  495. // mmGetSystemAddressForMdl() is defined as a macro in wdm.h which
  496. // calls mmMapLockedPages() which is treated as an evil by verifier.
  497. // mmMapLockedPages is reimplemented by mm via
  498. // mmMapLockedPagesSpecifyCache(MDL,Mode,mmCaches,NULL,TRUE,HighPriority)
  499. // where TRUE is to indicate a bug check, should the call fails.
  500. // I don't need the bug check, therefore, I specify FALSE below.
  501. //
  502. #ifdef WIN9X_STREAM
  503. #define SCGetSystemAddressForMdl(MDL) MmGetSystemAddressForMdl(MDL)
  504. #else
  505. #define SCGetSystemAddressForMdl(MDL) \
  506. (((MDL)->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | \
  507. MDL_SOURCE_IS_NONPAGED_POOL)) ? \
  508. ((MDL)->MappedSystemVa) : \
  509. (MmMapLockedPagesSpecifyCache((MDL), \
  510. KernelMode, \
  511. MmCached, \
  512. NULL, \
  513. FALSE, \
  514. HighPagePriority)))
  515. #endif
  516. BOOLEAN
  517. SCProcessPioDataBuffers(
  518. IN PKSSTREAM_HEADER FirstHeader,
  519. IN ULONG NumberOfHeaders,
  520. IN PSTREAM_OBJECT StreamObject,
  521. IN PMDL FirstMdl,
  522. IN ULONG StreamHeaderSize,
  523. IN PVOID *pDataPtrArray,
  524. IN BOOLEAN Write
  525. )
  526. /*++
  527. Routine Description:
  528. Processes each data buffer for PIO &| DMA case
  529. Arguments:
  530. FirstHeader - Address of the 1st s/g packet
  531. StreamObject- pointer to stream object
  532. NumberOfPages - number of pages in the request
  533. Return Value:
  534. --*/
  535. {
  536. PKSSTREAM_HEADER CurrentHeader;
  537. PMDL CurrentMdl;
  538. ULONG i;
  539. ULONG DataBytes;
  540. BOOLEAN ret = FALSE;
  541. PAGED_CODE();
  542. //
  543. // loop through each scatter/gather elements
  544. //
  545. CurrentHeader = FirstHeader;
  546. CurrentMdl = FirstMdl;
  547. for (i = 0; i < NumberOfHeaders; i++) {
  548. //
  549. // pick up the correct data buffer, based on the xfer direction
  550. //
  551. if (Write) {
  552. DataBytes = CurrentHeader->DataUsed;
  553. } else { // if write
  554. DataBytes = CurrentHeader->FrameExtent;
  555. } // if write
  556. //
  557. // if this header has data, process it.
  558. //
  559. if (DataBytes) {
  560. //
  561. // fill in the system virtual pointer
  562. // to the buffer if mapping is
  563. // needed
  564. //
  565. #if (DBG)
  566. if ( 0 != ( CurrentMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA |
  567. MDL_SOURCE_IS_NONPAGED_POOL))) {
  568. ASSERT(CurrentHeader->Data == (PVOID) ((ULONG_PTR) CurrentMdl->StartVa +
  569. CurrentMdl->ByteOffset));
  570. }
  571. #endif
  572. DebugPrint((DebugLevelVerbose, "Saving: Index:%x, Ptr:%x\n",
  573. i, CurrentHeader->Data));
  574. ret = TRUE;
  575. pDataPtrArray[i] = CurrentHeader->Data;
  576. CurrentHeader->Data = SCGetSystemAddressForMdl(CurrentMdl);
  577. DebugPrint((DebugLevelVerbose, "'SCPio: buff = %x, length = %x\n",
  578. CurrentHeader->Data, DataBytes));
  579. CurrentMdl = CurrentMdl->Next;
  580. }
  581. //
  582. // offset to the next buffer
  583. //
  584. CurrentHeader = ((PKSSTREAM_HEADER) ((PBYTE) CurrentHeader +
  585. StreamHeaderSize));
  586. } // for # elements
  587. return(ret);
  588. } // end SCProcessPioDataBuffers()
  589. BOOLEAN
  590. SCSetUpForDMA(
  591. IN PDEVICE_OBJECT DeviceObject,
  592. IN PSTREAM_REQUEST_BLOCK Request
  593. )
  594. /*++
  595. Routine Description:
  596. process read/write DMA request. allocate adapter channel.
  597. Arguments:
  598. DeviceObject - device object for the device
  599. Request - address of Codec Request Block
  600. Return Value:
  601. returns TRUE if channel is allocated
  602. --*/
  603. {
  604. NTSTATUS status;
  605. //
  606. // Allocate the adapter channel with sufficient map registers
  607. // for the transfer.
  608. //
  609. status = IoAllocateAdapterChannel(
  610. ((PDEVICE_EXTENSION) (DeviceObject->DeviceExtension))->DmaAdapterObject,
  611. DeviceObject,
  612. Request->HwSRB.NumberOfPhysicalPages + 1, // one more for the SRB
  613. // extension
  614. StreamClassDmaCallback,
  615. Request);
  616. if (!NT_SUCCESS(status)) {
  617. return FALSE;
  618. }
  619. return TRUE;
  620. }
  621. IO_ALLOCATION_ACTION
  622. StreamClassDmaCallback(
  623. IN PDEVICE_OBJECT DeviceObject,
  624. IN PIRP InputIrp,
  625. IN PVOID MapRegisterBase,
  626. IN PVOID Context
  627. )
  628. /*++
  629. Routine Description:
  630. continues to process read/write request after DMA adapter is allocated
  631. builds scatter/gather list from logical buffer list.
  632. Arguments:
  633. DeviceObject - dev object for adapter
  634. InputIrp - bogus
  635. MapRegisterBase - base address of map registers
  636. Context - address of Codec Request Block
  637. Return Value:
  638. returns the appropriate I/O allocation action.
  639. --*/
  640. {
  641. PSTREAM_REQUEST_BLOCK Request = Context;
  642. PKSSCATTER_GATHER scatterList;
  643. BOOLEAN writeToDevice;
  644. PVOID dataVirtualAddress;
  645. ULONG totalLength,
  646. NumberOfBuffers;
  647. PIRP Irp = Request->HwSRB.Irp;
  648. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  649. Request->HwSRB.StreamObject,
  650. STREAM_OBJECT,
  651. HwStreamObject
  652. );
  653. PMDL CurrentMdl;
  654. ULONG NumberOfElements = 0;
  655. //
  656. // Save the MapRegisterBase for later use
  657. // to deallocate the map
  658. // registers.
  659. //
  660. Request->MapRegisterBase = MapRegisterBase;
  661. //
  662. // determine whether this is a write request
  663. //
  664. writeToDevice = Request->HwSRB.Command == SRB_WRITE_DATA ? TRUE : FALSE;
  665. scatterList = Request->HwSRB.ScatterGatherBuffer;
  666. NumberOfBuffers = Request->HwSRB.NumberOfBuffers;
  667. ASSERT(Irp);
  668. CurrentMdl = Irp->MdlAddress;
  669. while (CurrentMdl) {
  670. //
  671. // Determine the virtual address of the buffer
  672. //
  673. dataVirtualAddress = (PSCHAR) MmGetMdlVirtualAddress(CurrentMdl);
  674. //
  675. // flush the buffers since we are doing DMA.
  676. //
  677. KeFlushIoBuffers(CurrentMdl,
  678. (BOOLEAN) (Request->HwSRB.Command == SRB_WRITE_DATA ? TRUE : FALSE),
  679. TRUE);
  680. //
  681. // Build the scatter/gather list by looping through the buffers
  682. // calling I/O map transfer.
  683. //
  684. totalLength = 0;
  685. while (totalLength < CurrentMdl->ByteCount) {
  686. NumberOfElements++;
  687. //
  688. // Request that the rest of the transfer be mapped.
  689. //
  690. scatterList->Length = CurrentMdl->ByteCount - totalLength;
  691. //
  692. // Since we are a master call I/O map transfer with a NULL
  693. // adapter.
  694. //
  695. scatterList->PhysicalAddress = IoMapTransfer(((PDEVICE_EXTENSION) (DeviceObject->DeviceExtension))
  696. ->DmaAdapterObject,
  697. CurrentMdl,
  698. MapRegisterBase,
  699. (PSCHAR) dataVirtualAddress
  700. + totalLength,
  701. &scatterList->Length,
  702. writeToDevice);
  703. DebugPrint((DebugLevelVerbose, "'SCDma: seg = %x'%x, length = %x\n",
  704. scatterList->PhysicalAddress.HighPart,
  705. scatterList->PhysicalAddress.LowPart,
  706. scatterList->Length));
  707. totalLength += scatterList->Length;
  708. scatterList++;
  709. }
  710. CurrentMdl = CurrentMdl->Next;
  711. } // while CurrentMdl
  712. Request->HwSRB.NumberOfScatterGatherElements = NumberOfElements;
  713. //
  714. // now map the transfer for the SRB in case the minidriver needs the
  715. // physical address of the extension.
  716. //
  717. // NOTE: This function changes the length field in the SRB, which
  718. // makes it invalid. It is not used elsewhere, however.
  719. //
  720. // We must flush the buffers appropriately as the SRB extension
  721. // may be DMA'ed both from and to. According to JHavens, we want to
  722. // tell IOMapXfer and KeFlushIoBuffers that this is a write, and upon
  723. // completion tell IoFlushAdapterBuffers that this is a read.
  724. //
  725. // Need to investigate if doing these extra calls add more overhead than
  726. // maintaining a queue of SRB's & extensions. However, on x86
  727. // platforms the KeFlush call gets compiled out and
  728. // on PCI systems the IoFlush call doesn't get made, so there is no
  729. // overhead on these system except the map xfer call.
  730. //
  731. //
  732. // flush the SRB buffer since we are doing DMA.
  733. //
  734. KeFlushIoBuffers(Request->Mdl,
  735. FALSE,
  736. TRUE);
  737. //
  738. // get the physical address of the SRB
  739. //
  740. Request->PhysicalAddress = IoMapTransfer(((PDEVICE_EXTENSION) (DeviceObject->DeviceExtension))
  741. ->DmaAdapterObject,
  742. Request->Mdl,
  743. MapRegisterBase,
  744. (PSCHAR) MmGetMdlVirtualAddress(
  745. Request->Mdl),
  746. &Request->Length,
  747. TRUE);
  748. //
  749. // if we are async, signal the event which will cause the request to be
  750. // called down on the original thread; otherwise, send the request down
  751. // now at dispatch level.
  752. //
  753. if (((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->NoSync) {
  754. KeSetEvent(&Request->DmaEvent, IO_NO_INCREMENT, FALSE);
  755. } else {
  756. //
  757. // send the request to the minidriver
  758. //
  759. SCStartMinidriverRequest(StreamObject,
  760. Request,
  761. (PVOID)
  762. StreamObject->HwStreamObject.ReceiveDataPacket);
  763. } // if nosync
  764. //
  765. // keep the map registers but release the I/O adapter channel
  766. //
  767. return (DeallocateObjectKeepRegisters);
  768. }
  769. VOID
  770. SCStartMinidriverRequest(
  771. IN PSTREAM_OBJECT StreamObject,
  772. IN PSTREAM_REQUEST_BLOCK Request,
  773. IN PVOID EntryPoint
  774. )
  775. /*++
  776. Routine Description:
  777. adds request to outstanding queue and starts the minidriver.
  778. Arguments:
  779. StreamObject - Address stream info struct
  780. Request - Address of streaming data packet
  781. EntryPoint - Minidriver routine to be called
  782. Return Value:
  783. --*/
  784. {
  785. PIRP Irp = Request->HwSRB.Irp;
  786. PDEVICE_EXTENSION DeviceExtension =
  787. StreamObject->DeviceExtension;
  788. //
  789. // show that the request is active.
  790. //
  791. Request->Flags |= SRB_FLAGS_IS_ACTIVE;
  792. //
  793. // place the request on the outstanding queue
  794. //
  795. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  796. InsertHeadList(
  797. &DeviceExtension->OutstandingQueue,
  798. &Request->SRBListEntry);
  799. //
  800. // set the cancel routine to outstanding
  801. //
  802. IoSetCancelRoutine(Irp, StreamClassCancelOutstandingIrp);
  803. //
  804. // send down the request to the minidriver. Protect the call with the
  805. // device spinlock to synchronize timers, etc.
  806. //
  807. #if DBG
  808. if (DeviceExtension->NeedyStream) {
  809. ASSERT(DeviceExtension->NeedyStream->OnNeedyQueue);
  810. }
  811. #endif
  812. DebugPrint((DebugLevelTrace, "'SCStartMinidriverRequeest: starting Irp %x, S# = %x, SRB = %x, Command = %x\n",
  813. Request->HwSRB.Irp, StreamObject->HwStreamObject.StreamNumber, Request, Request->HwSRB.Command));
  814. DeviceExtension->SynchronizeExecution(
  815. DeviceExtension->InterruptObject,
  816. EntryPoint,
  817. &Request->HwSRB);
  818. #if DBG
  819. if (DeviceExtension->NeedyStream) {
  820. ASSERT(DeviceExtension->NeedyStream->OnNeedyQueue);
  821. }
  822. #endif
  823. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  824. return;
  825. } // SCStartMinidriverRequest
  826. VOID
  827. StreamClassDpc(
  828. IN PKDPC Dpc,
  829. IN PDEVICE_OBJECT DeviceObject,
  830. IN PIRP Irp,
  831. IN PVOID Context
  832. )
  833. /*++
  834. Routine Description:
  835. this routine processes requests and notifications from the minidriver
  836. Arguments:
  837. Dpc - pointer to Dpc structure
  838. DeviceObject - device object for the adapter
  839. Irp - not used
  840. Context - StreamObject structure
  841. Return Value:
  842. None.
  843. --*/
  844. {
  845. PSTREAM_OBJECT StreamObject = Context,
  846. NeedyStream;
  847. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  848. INTERRUPT_CONTEXT interruptContext;
  849. INTERRUPT_DATA SavedStreamInterruptData;
  850. INTERRUPT_DATA SavedDeviceInterruptData;
  851. PSTREAM_REQUEST_BLOCK SRB;
  852. PERROR_LOG_ENTRY LogEntry;
  853. HW_TIME_CONTEXT TimeContext;
  854. UNREFERENCED_PARAMETER(Irp);
  855. UNREFERENCED_PARAMETER(Dpc);
  856. interruptContext.SavedStreamInterruptData = &SavedStreamInterruptData;
  857. interruptContext.SavedDeviceInterruptData = &SavedDeviceInterruptData;
  858. interruptContext.DeviceExtension = DeviceExtension;
  859. DebugPrint((DebugLevelVerbose, "'StreamClassDpc: enter\n"));
  860. //
  861. // if a stream object is passed in, first
  862. // check if work is pending
  863. //
  864. if (StreamObject) {
  865. SCStartRequestOnStream(StreamObject, DeviceExtension);
  866. } // if streamobject
  867. RestartDpc:
  868. //
  869. // Check for a ready for next packet on
  870. // the device.
  871. //
  872. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  873. if ((DeviceExtension->ReadyForNextReq) &&
  874. (!IsListEmpty(&DeviceExtension->PendingQueue))) {
  875. //
  876. // start the device request, which
  877. // clears the ready flag and
  878. // releases the spinlock. Then
  879. // reacquire the spinloc.
  880. //
  881. SCDequeueAndStartDeviceRequest(DeviceExtension);
  882. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  883. }
  884. //
  885. // Get the interrupt state snapshot. This copies the interrupt state to
  886. // saved state where it can be processed. It also clears the interrupt
  887. // flags. We acquired the device spinlock to protect the structure as
  888. // the minidriver could have requested a DPC call from this routine,
  889. // which could be preempted in the middle of minidriver's changing the
  890. // below structure, and we'd then take a snapshot of the structure while
  891. // it was changing.
  892. //
  893. interruptContext.NeedyStream = NULL;
  894. SavedDeviceInterruptData.CompletedSRB = NULL;
  895. SavedStreamInterruptData.CompletedSRB = NULL;
  896. SavedDeviceInterruptData.Flags = 0;
  897. SavedStreamInterruptData.Flags = 0;
  898. if (!DeviceExtension->SynchronizeExecution(DeviceExtension->InterruptObject,
  899. SCGetInterruptState,
  900. &interruptContext)) {
  901. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  902. return;
  903. }
  904. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  905. NeedyStream = interruptContext.NeedyStream;
  906. if (NeedyStream) {
  907. //
  908. // try to start a request on this
  909. // stream
  910. //
  911. SCStartRequestOnStream(NeedyStream, DeviceExtension);
  912. //
  913. // Process any completed stream requests.
  914. //
  915. while (SavedStreamInterruptData.CompletedSRB != NULL) {
  916. //
  917. // Remove the request from the
  918. // linked-list.
  919. //
  920. SRB = CONTAINING_RECORD(SavedStreamInterruptData.CompletedSRB,
  921. STREAM_REQUEST_BLOCK,
  922. HwSRB);
  923. SavedStreamInterruptData.CompletedSRB = SRB->HwSRB.NextSRB;
  924. DebugPrint((DebugLevelTrace, "'SCDpc: Completing stream Irp %x, S# = %x, SRB = %x, Func = %x, Callback = %x, SRB->IRP = %x\n",
  925. SRB->HwSRB.Irp, NeedyStream->HwStreamObject.StreamNumber,
  926. SRB, SRB->HwSRB.Command, SRB->Callback, SRB->HwSRB.Irp));
  927. SCCallBackSrb(SRB, DeviceExtension);
  928. }
  929. //
  930. // Check for timer requests.
  931. //
  932. if (SavedStreamInterruptData.Flags & INTERRUPT_FLAGS_TIMER_CALL_REQUEST) {
  933. SCProcessTimerRequest(&NeedyStream->ComObj,
  934. &SavedStreamInterruptData);
  935. }
  936. //
  937. // check to see if a change priority call has been requested.
  938. //
  939. if (SavedStreamInterruptData.Flags &
  940. INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST) {
  941. SCProcessPriorityChangeRequest(&NeedyStream->ComObj,
  942. &SavedStreamInterruptData,
  943. DeviceExtension);
  944. }
  945. //
  946. // Check for master clock queries.
  947. //
  948. if (SavedStreamInterruptData.Flags & INTERRUPT_FLAGS_CLOCK_QUERY_REQUEST) {
  949. LARGE_INTEGER ticks;
  950. ULONGLONG rate;
  951. KIRQL SavedIrql;
  952. //
  953. // call the master clock's entry point then call the minidriver's
  954. // callback procedure to report the time.
  955. //
  956. TimeContext.HwDeviceExtension = DeviceExtension->HwDeviceExtension;
  957. TimeContext.HwStreamObject = &NeedyStream->HwStreamObject;
  958. TimeContext.Function = SavedStreamInterruptData.HwQueryClockFunction;
  959. //
  960. // take the lock so MasterCliockinfo won't disapear under us
  961. //
  962. KeAcquireSpinLock( &NeedyStream->LockUseMasterClock, &SavedIrql );
  963. if ( NULL == NeedyStream->MasterClockInfo ) {
  964. ASSERT( 0 && "Mini driver queries clock while we have no master clock");
  965. //
  966. // give a hint that something is wrong via Time, since we return void.
  967. //
  968. TimeContext.Time = (ULONGLONG)-1;
  969. goto callminidriver;
  970. }
  971. switch (SavedStreamInterruptData.HwQueryClockFunction) {
  972. case TIME_GET_STREAM_TIME:
  973. TimeContext.Time = NeedyStream->MasterClockInfo->
  974. FunctionTable.GetCorrelatedTime(
  975. NeedyStream->MasterClockInfo->ClockFileObject,
  976. &TimeContext.SystemTime);
  977. goto callminidriver;
  978. case TIME_READ_ONBOARD_CLOCK:
  979. TimeContext.Time = NeedyStream->MasterClockInfo->
  980. FunctionTable.GetTime(
  981. NeedyStream->MasterClockInfo->ClockFileObject);
  982. //
  983. // timestamp the value as close as possible
  984. //
  985. ticks = KeQueryPerformanceCounter((PLARGE_INTEGER) & rate);
  986. TimeContext.SystemTime = KSCONVERT_PERFORMANCE_TIME( rate, ticks );
  987. callminidriver:
  988. //
  989. // finish using MasterClockInfo.
  990. //
  991. KeReleaseSpinLock( &NeedyStream->LockUseMasterClock, SavedIrql );
  992. //
  993. // call the minidriver's callback procedure
  994. //
  995. if (!DeviceExtension->NoSync) {
  996. //
  997. // Acquire the device spinlock.
  998. //
  999. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  1000. }
  1001. DebugPrint((DebugLevelTrace, "'SCDPC: calling time func, S# = %x, Command = %x\n",
  1002. NeedyStream->HwStreamObject.StreamNumber, TimeContext.Function));
  1003. DeviceExtension->SynchronizeExecution(
  1004. DeviceExtension->InterruptObject,
  1005. (PKSYNCHRONIZE_ROUTINE) SavedStreamInterruptData.HwQueryClockRoutine,
  1006. &TimeContext
  1007. );
  1008. if (!DeviceExtension->NoSync) {
  1009. //
  1010. // Release the spinlock.
  1011. //
  1012. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  1013. }
  1014. break;
  1015. default:
  1016. KeReleaseSpinLock( &NeedyStream->LockUseMasterClock, SavedIrql );
  1017. ASSERT(0);
  1018. } // switch clock func
  1019. } // if queryclock
  1020. } // if needystream
  1021. //
  1022. // Check for an error log request.
  1023. //
  1024. if (SavedDeviceInterruptData.Flags & INTERRUPT_FLAGS_LOG_ERROR) {
  1025. //
  1026. // Process the error log request.
  1027. //
  1028. LogEntry = &SavedDeviceInterruptData.LogEntry;
  1029. SCLogError(DeviceObject,
  1030. LogEntry->SequenceNumber,
  1031. LogEntry->ErrorCode,
  1032. LogEntry->UniqueId
  1033. );
  1034. } // if log error
  1035. //
  1036. // Process any completed device requests.
  1037. //
  1038. while (SavedDeviceInterruptData.CompletedSRB != NULL) {
  1039. //
  1040. // Remove the request from the linked-list.
  1041. //
  1042. SRB = CONTAINING_RECORD(SavedDeviceInterruptData.CompletedSRB,
  1043. STREAM_REQUEST_BLOCK,
  1044. HwSRB);
  1045. SavedDeviceInterruptData.CompletedSRB = SRB->HwSRB.NextSRB;
  1046. DebugPrint((DebugLevelTrace, "'SCDpc: Completing device Irp %x\n", SRB->HwSRB.Irp));
  1047. SCCallBackSrb(SRB, DeviceExtension);
  1048. }
  1049. //
  1050. // Check for device timer requests.
  1051. //
  1052. if (SavedDeviceInterruptData.Flags & INTERRUPT_FLAGS_TIMER_CALL_REQUEST) {
  1053. SCProcessTimerRequest(&DeviceExtension->ComObj,
  1054. &SavedDeviceInterruptData);
  1055. }
  1056. //
  1057. // check if we have any dead events that need discarding. if so, we'll
  1058. // schedule a work item to get rid of them.
  1059. //
  1060. if ((!IsListEmpty(&DeviceExtension->DeadEventList)) &&
  1061. (!(DeviceExtension->DeadEventItemQueued))) {
  1062. DeviceExtension->DeadEventItemQueued = TRUE;
  1063. ExQueueWorkItem(&DeviceExtension->EventWorkItem,
  1064. DelayedWorkQueue);
  1065. }
  1066. //
  1067. // check to see if a change priority call
  1068. // has been requested for the device.
  1069. //
  1070. if (SavedDeviceInterruptData.Flags &
  1071. INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST) {
  1072. SCProcessPriorityChangeRequest(&DeviceExtension->ComObj,
  1073. &SavedDeviceInterruptData,
  1074. DeviceExtension);
  1075. } // if change priority
  1076. //
  1077. // Check for stream rescan request.
  1078. //
  1079. if (SavedDeviceInterruptData.Flags & INTERRUPT_FLAGS_NEED_STREAM_RESCAN) {
  1080. TRAP;
  1081. ExQueueWorkItem(&DeviceExtension->RescanWorkItem,
  1082. DelayedWorkQueue);
  1083. }
  1084. //
  1085. // Check for minidriver work requests. Note this is an unsynchronized
  1086. // test on bits that can be set by the interrupt routine; however,
  1087. // the worst that can happen is that the completion DPC checks for work
  1088. // twice.
  1089. //
  1090. if ((DeviceExtension->NeedyStream)
  1091. || (DeviceExtension->ComObj.InterruptData.Flags &
  1092. INTERRUPT_FLAGS_NOTIFICATION_REQUIRED)) {
  1093. //
  1094. // Start over from the top.
  1095. //
  1096. DebugPrint((DebugLevelVerbose, "'StreamClassDpc: restarting\n"));
  1097. goto RestartDpc;
  1098. }
  1099. return;
  1100. } // end StreamClassDpc()
  1101. VOID
  1102. SCStartRequestOnStream(
  1103. IN PSTREAM_OBJECT StreamObject,
  1104. IN PDEVICE_EXTENSION DeviceExtension
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. Routine tries to start either a control or data request on the specified
  1109. stream.
  1110. Arguments:
  1111. StreamObject - pointer to stream object
  1112. DeviceExtension - pointer to device extension.
  1113. Return Value:
  1114. None
  1115. Notes:
  1116. --*/
  1117. {
  1118. //
  1119. // Check for a ready for next packet. Acquire spinlock to protect
  1120. // READY bits. Note that we don't snapshot the ready flags as we do with
  1121. // the remaining notification flags, as we don't want to clear the flags
  1122. // unconditionally in the snapshot in case there is not currently a
  1123. // request pending. Also, starting a request before the snapshot will
  1124. // give a slight perf improvement. Note that the flags can be set via
  1125. // the minidriver while we are checking them, but since the minidriver
  1126. // cannot clear them and the minidriver cannot call for a next request
  1127. // more than once before it receives one, this is not a problem.
  1128. //
  1129. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  1130. if ((StreamObject->ReadyForNextDataReq) &&
  1131. (!IsListEmpty(&StreamObject->DataPendingQueue))) {
  1132. //
  1133. // start the request, which clears the ready flag and releases
  1134. // the spinlock, then reobtain the spinlock.
  1135. //
  1136. SCDequeueAndStartStreamDataRequest(StreamObject);
  1137. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  1138. } // if ready for data
  1139. if ((StreamObject->ReadyForNextControlReq) &&
  1140. (!IsListEmpty(&StreamObject->ControlPendingQueue))) {
  1141. //
  1142. // start the request, which clears the ready flag and releases
  1143. // the spinlock.
  1144. //
  1145. SCDequeueAndStartStreamControlRequest(StreamObject);
  1146. } else {
  1147. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  1148. } // if ready for control
  1149. return;
  1150. }
  1151. BOOLEAN
  1152. SCGetInterruptState(
  1153. IN PVOID ServiceContext
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. This routine saves the InterruptFlags, error log info, and
  1158. CompletedRequests fields and clears the InterruptFlags.
  1159. Arguments:
  1160. ServiceContext - Supplies a pointer to the interrupt context which contains
  1161. pointers to the interrupt data and where to save it.
  1162. Return Value:
  1163. Returns TRUE if there is new work and FALSE otherwise.
  1164. Notes:
  1165. Called via KeSynchronizeExecution with the port device extension spinlock
  1166. held.
  1167. --*/
  1168. {
  1169. PINTERRUPT_CONTEXT interruptContext = ServiceContext;
  1170. PDEVICE_EXTENSION DeviceExtension;
  1171. PSTREAM_OBJECT NeedyStream;
  1172. BOOLEAN Work = FALSE;
  1173. DeviceExtension = interruptContext->DeviceExtension;
  1174. //
  1175. // get the needy streams and zero the
  1176. // link.
  1177. //
  1178. interruptContext->NeedyStream = NeedyStream = DeviceExtension->NeedyStream;
  1179. //
  1180. // capture the state of needy stream
  1181. //
  1182. if (NeedyStream) {
  1183. //
  1184. // Move the interrupt state to save
  1185. // area.
  1186. //
  1187. ASSERT(NeedyStream->NextNeedyStream != NeedyStream);
  1188. ASSERT(NeedyStream->ComObj.InterruptData.Flags & INTERRUPT_FLAGS_NOTIFICATION_REQUIRED);
  1189. ASSERT(NeedyStream->OnNeedyQueue);
  1190. DebugPrint((DebugLevelVerbose, "'SCGetInterruptState: Snapshot for stream %p, S# = %x, NextNeedy = %p\n",
  1191. NeedyStream, NeedyStream->HwStreamObject.StreamNumber, NeedyStream->NextNeedyStream));
  1192. NeedyStream->OnNeedyQueue = FALSE;
  1193. *interruptContext->SavedStreamInterruptData =
  1194. NeedyStream->ComObj.InterruptData;
  1195. //
  1196. // Clear the interrupt state.
  1197. //
  1198. NeedyStream->ComObj.InterruptData.Flags &= STREAM_FLAGS_INTERRUPT_FLAG_MASK;
  1199. NeedyStream->ComObj.InterruptData.CompletedSRB = NULL;
  1200. Work = TRUE;
  1201. DeviceExtension->NeedyStream = (PSTREAM_OBJECT) NeedyStream->NextNeedyStream;
  1202. NeedyStream->NextNeedyStream = NULL;
  1203. #if DBG
  1204. if (DeviceExtension->NeedyStream) {
  1205. ASSERT(DeviceExtension->NeedyStream->OnNeedyQueue);
  1206. }
  1207. #endif
  1208. } // if NeedyStream
  1209. //
  1210. // now copy over the device interrupt
  1211. // data if necessary
  1212. //
  1213. if (DeviceExtension->ComObj.InterruptData.Flags &
  1214. INTERRUPT_FLAGS_NOTIFICATION_REQUIRED) {
  1215. *interruptContext->SavedDeviceInterruptData =
  1216. DeviceExtension->ComObj.InterruptData;
  1217. //
  1218. // Clear the device interrupt state.
  1219. //
  1220. DeviceExtension->ComObj.InterruptData.Flags &=
  1221. DEVICE_FLAGS_INTERRUPT_FLAG_MASK;
  1222. DeviceExtension->ComObj.InterruptData.CompletedSRB = NULL;
  1223. Work = TRUE;
  1224. }
  1225. return (Work);
  1226. }
  1227. NTSTATUS
  1228. SCProcessCompletedRequest(
  1229. IN PSTREAM_REQUEST_BLOCK SRB
  1230. )
  1231. /*++
  1232. Routine Description:
  1233. This routine processes a request which has completed.
  1234. Arguments:
  1235. SRB- address of completed STREAM request block
  1236. Return Value:
  1237. None.
  1238. --*/
  1239. {
  1240. PIRP Irp = SRB->HwSRB.Irp;
  1241. //
  1242. // complete the IRP
  1243. //
  1244. return (SCCompleteIrp(Irp,
  1245. SCDequeueAndDeleteSrb(SRB),
  1246. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1));
  1247. }
  1248. NTSTATUS
  1249. SCDequeueAndDeleteSrb(
  1250. IN PSTREAM_REQUEST_BLOCK SRB
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. This routine dequeues and deletes a completed SRB
  1255. Arguments:
  1256. SRB- address of completed STREAM request block
  1257. Return Value:
  1258. None.
  1259. --*/
  1260. {
  1261. PDEVICE_EXTENSION DeviceExtension =
  1262. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  1263. NTSTATUS Status = SRB->HwSRB.Status;
  1264. KIRQL irql;
  1265. //
  1266. // remove the SRB from our outstanding
  1267. // queue. protect list with
  1268. // spinlock.
  1269. //
  1270. KeAcquireSpinLock(&DeviceExtension->SpinLock, &irql);
  1271. RemoveEntryList(&SRB->SRBListEntry);
  1272. if (SRB->HwSRB.Irp) {
  1273. IoSetCancelRoutine(SRB->HwSRB.Irp, NULL);
  1274. }
  1275. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  1276. //
  1277. // free the SRB and MDL
  1278. //
  1279. if ( !NT_SUCCESS( Status )) {
  1280. DebugPrint((DebugLevelWarning,
  1281. "SCDequeueAndDeleteSrb Command:%x Status=%x\n",
  1282. SRB->HwSRB.Command,
  1283. Status ));
  1284. }
  1285. IoFreeMdl(SRB->Mdl);
  1286. ExFreePool(SRB);
  1287. return (Status);
  1288. }
  1289. VOID
  1290. SCProcessCompletedDataRequest(
  1291. IN PSTREAM_REQUEST_BLOCK SRB
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. This routine processes a data request which has completed. It completes any
  1296. pending transfers, releases the adapter objects and map registers.
  1297. Arguments:
  1298. SRB- address of completed STREAM request block
  1299. Return Value:
  1300. None.
  1301. --*/
  1302. {
  1303. PDEVICE_EXTENSION DeviceExtension =
  1304. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  1305. PIRP Irp = SRB->HwSRB.Irp;
  1306. PMDL CurrentMdl;
  1307. ULONG i = 0;
  1308. if (Irp) {
  1309. PIO_STACK_LOCATION IrpStack;
  1310. PKSSTREAM_HEADER CurrentHeader;
  1311. CurrentHeader = SRB->HwSRB.CommandData.DataBufferArray;
  1312. ASSERT(CurrentHeader);
  1313. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1314. ASSERT(IrpStack);
  1315. #if DBG
  1316. //
  1317. // assert the MDL list.
  1318. //
  1319. CurrentMdl = Irp->MdlAddress;
  1320. while (CurrentMdl) {
  1321. CurrentMdl = CurrentMdl->Next;
  1322. } // while
  1323. #endif
  1324. CurrentMdl = Irp->MdlAddress;
  1325. while (CurrentMdl) {
  1326. //
  1327. // flush the buffers if we did PIO data in
  1328. //
  1329. if (SRB->HwSRB.StreamObject->Pio) {
  1330. //
  1331. // find the first header with data...
  1332. //
  1333. while (!(CurrentHeader->DataUsed) && (!CurrentHeader->FrameExtent)) {
  1334. CurrentHeader = ((PKSSTREAM_HEADER) ((PBYTE) CurrentHeader +
  1335. SRB->StreamHeaderSize));
  1336. }
  1337. //
  1338. // restore the pointer we changed
  1339. //
  1340. // CurrentHeader->Data = (PVOID) ((ULONG_PTR) CurrentMdl->StartVa +
  1341. // CurrentMdl->ByteOffset);
  1342. //
  1343. if (SRB->bMemPtrValid) { // safety first!
  1344. DebugPrint((DebugLevelVerbose, "Restoring: Index:%x, Ptr:%x\n",
  1345. i, SRB->pMemPtrArray[i]));
  1346. CurrentHeader->Data = SRB->pMemPtrArray[i];
  1347. }
  1348. DebugPrint((DebugLevelVerbose, "'SCPioComplete: Irp = %x, header = %x, Data = %x\n",
  1349. Irp, CurrentHeader, CurrentHeader->Data));
  1350. //
  1351. // update to the next header
  1352. //
  1353. i++;
  1354. CurrentHeader = ((PKSSTREAM_HEADER) ((PBYTE) CurrentHeader +
  1355. SRB->StreamHeaderSize));
  1356. if (SRB->HwSRB.Command == SRB_READ_DATA) {
  1357. KeFlushIoBuffers(CurrentMdl,
  1358. TRUE,
  1359. FALSE);
  1360. } // if data in
  1361. } // if PIO
  1362. //
  1363. // Flush the adapter buffers if we had map registers => DMA.
  1364. //
  1365. if (SRB->MapRegisterBase) {
  1366. //
  1367. // Since we are a master call I/O flush adapter buffers
  1368. // with a NULL adapter.
  1369. //
  1370. IoFlushAdapterBuffers(DeviceExtension->DmaAdapterObject,
  1371. CurrentMdl,
  1372. SRB->MapRegisterBase,
  1373. MmGetMdlVirtualAddress(CurrentMdl),
  1374. CurrentMdl->ByteCount,
  1375. (BOOLEAN) (SRB->HwSRB.Command ==
  1376. SRB_READ_DATA ? FALSE : TRUE)
  1377. );
  1378. } // if DMA
  1379. CurrentMdl = CurrentMdl->Next;
  1380. } // while CurrentMdl
  1381. //
  1382. // flush the buffer for the SRB extension in case the adapter DMA'ed
  1383. // to it. JHavens says we must treat this as a READ.
  1384. //
  1385. //
  1386. // Flush the adapter buffer for the SRB if we had map registers =>
  1387. // DMA.
  1388. //
  1389. if (SRB->MapRegisterBase) {
  1390. IoFlushAdapterBuffers(DeviceExtension->DmaAdapterObject,
  1391. SRB->Mdl,
  1392. SRB->MapRegisterBase,
  1393. MmGetMdlVirtualAddress(
  1394. SRB->Mdl),
  1395. SRB->Length,
  1396. FALSE);
  1397. //
  1398. // Free the map registers if DMA.
  1399. //
  1400. IoFreeMapRegisters(DeviceExtension->DmaAdapterObject,
  1401. SRB->MapRegisterBase,
  1402. SRB->HwSRB.NumberOfPhysicalPages);
  1403. } // if MapRegisterBase
  1404. //
  1405. // free the extra data, if any.
  1406. //
  1407. if (IrpStack->Parameters.Others.Argument4 != NULL) {
  1408. TRAP;
  1409. ExFreePool(IrpStack->Parameters.Others.Argument4);
  1410. } // if extradata
  1411. } // if Irp
  1412. //
  1413. // call the generic completion handler
  1414. //
  1415. SCProcessCompletedRequest(SRB);
  1416. } // SCProcessCompletedDataRequest
  1417. VOID
  1418. SCMinidriverStreamTimerDpc(
  1419. IN struct _KDPC * Dpc,
  1420. IN PVOID Context,
  1421. IN PVOID SystemArgument1,
  1422. IN PVOID SystemArgument2
  1423. )
  1424. /*++
  1425. Routine Description:
  1426. This routine calls the minidriver when its requested timer fires.
  1427. It interlocks either with the port spinlock and the interrupt object.
  1428. Arguments:
  1429. Dpc - Unsed.
  1430. Context - Supplies a pointer to the stream object for this adapter.
  1431. SystemArgument1 - Unused.
  1432. SystemArgument2 - Unused.
  1433. Return Value:
  1434. None.
  1435. --*/
  1436. {
  1437. PSTREAM_OBJECT StreamObject = ((PSTREAM_OBJECT) Context);
  1438. PDEVICE_EXTENSION DeviceExtension = StreamObject->DeviceExtension;
  1439. //
  1440. // Acquire the device spinlock if synchronized.
  1441. //
  1442. if (!(DeviceExtension->NoSync)) {
  1443. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  1444. }
  1445. //
  1446. // Make sure the timer routine is still
  1447. // desired.
  1448. //
  1449. if (StreamObject->ComObj.HwTimerRoutine != NULL) {
  1450. DebugPrint((DebugLevelTrace, "'SCTimerDpc: Calling MD timer callback, S# = %x, Routine = %p\n",
  1451. StreamObject->HwStreamObject.StreamNumber, StreamObject->ComObj.HwTimerRoutine));
  1452. DeviceExtension->SynchronizeExecution(
  1453. DeviceExtension->InterruptObject,
  1454. (PKSYNCHRONIZE_ROUTINE) StreamObject->ComObj.HwTimerRoutine,
  1455. StreamObject->ComObj.HwTimerContext
  1456. );
  1457. }
  1458. //
  1459. // Release the spinlock if we're synchronized.
  1460. //
  1461. if (!(DeviceExtension->NoSync)) {
  1462. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  1463. }
  1464. //
  1465. // Call the DPC directly to check for work.
  1466. //
  1467. StreamClassDpc(NULL,
  1468. DeviceExtension->DeviceObject,
  1469. NULL,
  1470. StreamObject);
  1471. }
  1472. VOID
  1473. SCMinidriverDeviceTimerDpc(
  1474. IN struct _KDPC * Dpc,
  1475. IN PVOID Context,
  1476. IN PVOID SystemArgument1,
  1477. IN PVOID SystemArgument2
  1478. )
  1479. /*++
  1480. Routine Description:
  1481. This routine calls the minidriver when its requested timer fires.
  1482. It interlocks either with the port spinlock and the interrupt object.
  1483. Arguments:
  1484. Dpc - Unsed.
  1485. Context - Supplies a pointer to the stream object for this adapter.
  1486. SystemArgument1 - Unused.
  1487. SystemArgument2 - Unused.
  1488. Return Value:
  1489. None.
  1490. --*/
  1491. {
  1492. PDEVICE_EXTENSION DeviceExtension = Context;
  1493. //
  1494. // Acquire the device spinlock.
  1495. //
  1496. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  1497. //
  1498. // Make sure the timer routine is still
  1499. // desired.
  1500. //
  1501. if (DeviceExtension->ComObj.HwTimerRoutine != NULL) {
  1502. DeviceExtension->SynchronizeExecution(
  1503. DeviceExtension->InterruptObject,
  1504. (PKSYNCHRONIZE_ROUTINE) DeviceExtension->ComObj.HwTimerRoutine,
  1505. DeviceExtension->ComObj.HwTimerContext
  1506. );
  1507. }
  1508. //
  1509. // Release the spinlock.
  1510. //
  1511. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  1512. //
  1513. // Call the DPC directly to check for
  1514. // work.
  1515. //
  1516. StreamClassDpc(NULL,
  1517. DeviceExtension->DeviceObject,
  1518. NULL,
  1519. NULL);
  1520. }
  1521. VOID
  1522. SCLogError(
  1523. IN PDEVICE_OBJECT DeviceObject,
  1524. IN ULONG SequenceNumber,
  1525. IN NTSTATUS ErrorCode,
  1526. IN ULONG UniqueId
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. This function logs an error.
  1531. Arguments:
  1532. DeviceObject - device or driver object
  1533. SequenceNumber - supplies the sequence # of the error.
  1534. ErrorCode - Supplies the error code for this error.
  1535. UniqueId - Supplies the UniqueId for this error.
  1536. Return Value:
  1537. None.
  1538. --*/
  1539. {
  1540. PIO_ERROR_LOG_PACKET packet;
  1541. PAGED_CODE();
  1542. packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceObject,
  1543. sizeof(IO_ERROR_LOG_PACKET));
  1544. if (packet) {
  1545. packet->ErrorCode = ErrorCode;
  1546. packet->SequenceNumber = SequenceNumber;
  1547. packet->MajorFunctionCode = 0;
  1548. packet->RetryCount = (UCHAR) 0;
  1549. packet->UniqueErrorValue = UniqueId;
  1550. packet->FinalStatus = STATUS_SUCCESS;
  1551. packet->DumpDataSize = 0;
  1552. IoWriteErrorLogEntry(packet);
  1553. }
  1554. }
  1555. VOID
  1556. SCLogErrorWithString(
  1557. IN PDEVICE_OBJECT DeviceObject,
  1558. IN OPTIONAL PDEVICE_EXTENSION DeviceExtension,
  1559. IN NTSTATUS ErrorCode,
  1560. IN ULONG UniqueId,
  1561. IN PUNICODE_STRING String1
  1562. )
  1563. /*++
  1564. Routine Description
  1565. This function logs an error and includes the string provided.
  1566. Arguments:
  1567. DeviceObject - device or driver object
  1568. DeviceExtension - Supplies a pointer to the port device extension.
  1569. ErrorCode - Supplies the error code for this error.
  1570. UniqueId - Supplies the UniqueId for this error.
  1571. String1 - The string to be inserted.
  1572. Return Value:
  1573. None.
  1574. --*/
  1575. {
  1576. ULONG length;
  1577. PCHAR dumpData;
  1578. PIO_ERROR_LOG_PACKET packet;
  1579. PAGED_CODE();
  1580. length = String1->Length + sizeof(IO_ERROR_LOG_PACKET) + 2;
  1581. if (length > ERROR_LOG_MAXIMUM_SIZE) {
  1582. length = ERROR_LOG_MAXIMUM_SIZE;
  1583. }
  1584. packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceObject,
  1585. (UCHAR) length);
  1586. if (packet) {
  1587. packet->ErrorCode = ErrorCode;
  1588. packet->SequenceNumber = (DeviceExtension != NULL) ?
  1589. DeviceExtension->SequenceNumber++ : 0;
  1590. packet->MajorFunctionCode = 0;
  1591. packet->RetryCount = (UCHAR) 0;
  1592. packet->UniqueErrorValue = UniqueId;
  1593. packet->FinalStatus = STATUS_SUCCESS;
  1594. packet->NumberOfStrings = 1;
  1595. packet->StringOffset = (USHORT) ((PUCHAR) & packet->DumpData[0] - (PUCHAR) packet);
  1596. packet->DumpDataSize = (USHORT) (length - sizeof(IO_ERROR_LOG_PACKET));
  1597. packet->DumpDataSize /= sizeof(ULONG);
  1598. dumpData = (PUCHAR) & packet->DumpData[0];
  1599. RtlCopyMemory(dumpData, String1->Buffer, String1->Length);
  1600. dumpData += String1->Length;
  1601. *dumpData++ = '\0';
  1602. *dumpData++ = '\0';
  1603. IoWriteErrorLogEntry(packet);
  1604. }
  1605. return;
  1606. }
  1607. BOOLEAN
  1608. StreamClassSynchronizeExecution(
  1609. IN PKINTERRUPT Interrupt,
  1610. IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
  1611. IN PVOID SynchronizeContext
  1612. )
  1613. /*++
  1614. Routine Description:
  1615. This routine calls the minidriver entry point which was passed in as
  1616. a parameter. It acquires a spin lock so that all accesses to the
  1617. minidriver's routines are synchronized. This routine is used as a
  1618. subsitute for KeSynchronizedExecution for minidrivers which do not use
  1619. hardware interrupts.
  1620. Arguments:
  1621. Interrrupt - Supplies a pointer to the port device extension.
  1622. SynchronizeRoutine - Supplies a pointer to the routine to be called.
  1623. SynchronizeContext - Supplies the context to pass to the
  1624. SynchronizeRoutine.
  1625. Return Value:
  1626. Returns the returned by the SynchronizeRoutine.
  1627. --*/
  1628. {
  1629. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) Interrupt;
  1630. BOOLEAN returnValue;
  1631. #if DBG
  1632. ULONGLONG ticks;
  1633. ULONGLONG rate;
  1634. ULONGLONG StartTime,
  1635. EndTime;
  1636. ticks = (ULONGLONG) KeQueryPerformanceCounter((PLARGE_INTEGER) & rate).QuadPart;
  1637. StartTime = ticks * 10000 / rate;
  1638. #endif
  1639. returnValue = SynchronizeRoutine(SynchronizeContext);
  1640. #if DBG
  1641. ticks = (ULONGLONG) KeQueryPerformanceCounter((PLARGE_INTEGER) & rate).QuadPart;
  1642. EndTime = ticks * 10000 / rate;
  1643. DebugPrint((DebugLevelVerbose, "'SCDebugSync: minidriver took %d microseconds at dispatch level.\n",
  1644. (EndTime - StartTime) * 10));
  1645. if ((EndTime - StartTime) > 100) {
  1646. DebugPrint((DebugLevelFatal, "Stream Class: minidriver took %I64d millisecond(s) at "
  1647. "dispatch level. See dev owner. Type LN %p for the name of the minidriver\n",
  1648. (EndTime - StartTime) / 100, SynchronizeRoutine));
  1649. }
  1650. #endif
  1651. return (returnValue);
  1652. }
  1653. #if DBG
  1654. BOOLEAN
  1655. SCDebugKeSynchronizeExecution(
  1656. IN PKINTERRUPT Interrupt,
  1657. IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
  1658. IN PVOID SynchronizeContext
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. Arguments:
  1663. Interrrupt - Supplies a pointer to the port device extension.
  1664. SynchronizeRoutine - Supplies a pointer to the routine to be called.
  1665. SynchronizeContext - Supplies the context to pass to the
  1666. SynchronizeRoutine.
  1667. Return Value:
  1668. Returns the returned by the SynchronizeRoutine.
  1669. --*/
  1670. {
  1671. ULONGLONG ticks;
  1672. ULONGLONG rate;
  1673. ULONGLONG StartTime,
  1674. EndTime;
  1675. BOOLEAN returnValue;
  1676. ticks = (ULONGLONG) KeQueryPerformanceCounter((PLARGE_INTEGER) & rate).QuadPart;
  1677. StartTime = ticks * 10000 / rate;
  1678. returnValue = KeSynchronizeExecution(Interrupt,
  1679. SynchronizeRoutine,
  1680. SynchronizeContext);
  1681. ticks = (ULONGLONG) KeQueryPerformanceCounter((PLARGE_INTEGER) & rate).QuadPart;
  1682. EndTime = ticks * 10000 / rate;
  1683. DebugPrint((DebugLevelVerbose, "'SCDebugSync: minidriver took %d microseconds at raised IRQL.\n",
  1684. (EndTime - StartTime) * 10));
  1685. if ((EndTime - StartTime) > 50) {
  1686. DebugPrint((DebugLevelFatal, "Stream Class: minidriver took %d%d millisecond(s) at raised IRQL. See dev owner. Type LN %x for the name of the minidriver\n",
  1687. (EndTime - StartTime) / 100, SynchronizeRoutine));
  1688. }
  1689. return (returnValue);
  1690. }
  1691. #endif
  1692. NTSTATUS
  1693. SCCompleteIrp(
  1694. IN PIRP Irp,
  1695. IN NTSTATUS Status,
  1696. IN PDEVICE_EXTENSION DeviceExtension
  1697. )
  1698. /*++
  1699. Routine Description:
  1700. Routine generically calls back a completed IRP, and shows one less I/O
  1701. pending.
  1702. Arguments:
  1703. Irp - IRP to complete
  1704. Status - Status to complete it with
  1705. DeviceExtension - pointer to device extension
  1706. Return Value:
  1707. Returns the Status parameter
  1708. --*/
  1709. {
  1710. #if DBG
  1711. PMDL CurrentMdl;
  1712. #endif
  1713. if (Irp) {
  1714. Irp->IoStatus.Status = Status;
  1715. #if DBG
  1716. //
  1717. // random asserts follow...
  1718. // make sure we have not freed the system buffer.
  1719. //
  1720. if (Irp->AssociatedIrp.SystemBuffer) {
  1721. DebugPrint((DebugLevelVerbose, "'SCComplete: Irp = %p, sys buffer = %p\n",
  1722. Irp, Irp->AssociatedIrp.SystemBuffer));
  1723. }
  1724. //
  1725. // assert the MDL list.
  1726. //
  1727. CurrentMdl = Irp->MdlAddress;
  1728. while (CurrentMdl) {
  1729. CurrentMdl = CurrentMdl->Next;
  1730. } // while
  1731. #endif
  1732. if ( Irp->CurrentLocation < Irp->StackCount+1 ) {
  1733. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1734. } else {
  1735. //
  1736. // we got a dummy Irp we created. IoVerifier code will pews if
  1737. // we call IoCompleteRequest because the Current Stack location
  1738. // is at the end of last stack location. We can't use
  1739. // IoBuildIoControlRequest to create the Irp becuase it will
  1740. // be added to a thread and the only way to get it off is to
  1741. // call IoCompleteRequest.
  1742. //
  1743. IoFreeIrp( Irp );
  1744. }
  1745. }
  1746. if (!(InterlockedDecrement(&DeviceExtension->OneBasedIoCount))) {
  1747. //
  1748. // the device is being removed and all I/O is complete. Signal the
  1749. // removal thread to wake up.
  1750. //
  1751. KeSetEvent(&DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE);
  1752. }
  1753. ASSERT(DeviceExtension->OneBasedIoCount >= 0);
  1754. return (Status);
  1755. }
  1756. BOOLEAN
  1757. SCDummyMinidriverRoutine(
  1758. IN PVOID Context
  1759. )
  1760. /*++
  1761. Routine Description:
  1762. Routine used when the minidriver fills in a null for an optional routine
  1763. Arguments:
  1764. Context - unreferenced
  1765. Return Value:
  1766. TRUE
  1767. --*/
  1768. {
  1769. return (TRUE);
  1770. }
  1771. #if ENABLE_MULTIPLE_FILTER_TYPES
  1772. NTSTATUS
  1773. SCOpenMinidriverInstance(
  1774. IN PDEVICE_EXTENSION DeviceExtension,
  1775. OUT PFILTER_INSTANCE * ReturnedFilterInstance,
  1776. IN PSTREAM_CALLBACK_PROCEDURE SCGlobalInstanceCallback,
  1777. IN PIRP Irp)
  1778. /*++
  1779. Routine Description:
  1780. Worker routine to process opening of a filter instance.
  1781. Once open, we issue srb_get_stream_info.
  1782. Arguments:
  1783. DeviceExtension - pointer to device extension
  1784. ReturnedFilterInstance - pointer to the filter instance structure
  1785. SCGlobalInstanceCallback - callback procedure to be called if we call the minidriver
  1786. Irp - pointer to the irp
  1787. Return Value:
  1788. Returns NTSTATUS and a filter instance structure if successfull
  1789. --*/
  1790. {
  1791. ULONG FilterExtensionSize;
  1792. PFILTER_INSTANCE FilterInstance;
  1793. PHW_STREAM_INFORMATION CurrentInfo;
  1794. PADDITIONAL_PIN_INFO CurrentAdditionalInfo;
  1795. ULONG i;
  1796. BOOLEAN RequestIssued;
  1797. PKSOBJECT_CREATE_ITEM CreateItem;
  1798. ULONG FilterTypeIndex;
  1799. ULONG NumberOfPins;
  1800. NTSTATUS Status = STATUS_SUCCESS;
  1801. PAGED_CODE();
  1802. //
  1803. // The CreateItem is in Irp->Tail.Overlay.DriverContext[0] from KS
  1804. //
  1805. CreateItem = (PKSOBJECT_CREATE_ITEM)Irp->Tail.Overlay.DriverContext[0];
  1806. ASSERT( CreateItem != NULL );
  1807. FilterTypeIndex = (ULONG)(ULONG_PTR)CreateItem->Context;
  1808. ASSERT( FilterTypeIndex == 0 ||
  1809. FilterTypeIndex <
  1810. DeviceExtension->MinidriverData->HwInitData.NumNameExtensions);
  1811. FilterExtensionSize = DeviceExtension->FilterExtensionSize;
  1812. ASSERT( DeviceExtension->FilterExtensionSize ==
  1813. DeviceExtension->MinidriverData->
  1814. HwInitData.FilterInstanceExtensionSize);
  1815. FilterInstance = NULL;
  1816. NumberOfPins = DeviceExtension->FilterTypeInfos[FilterTypeIndex].
  1817. StreamDescriptor->StreamHeader.NumberOfStreams;
  1818. //
  1819. // don't call the minidriver to open the filter instance if 1x1 for backward
  1820. // compat. We do this so that minidrivers that don't support
  1821. // instancing (the vast majority) don't have to respond to this call.
  1822. //
  1823. if ( DeviceExtension->NumberOfOpenInstances > 0 &&
  1824. 0 == FilterExtensionSize ) {
  1825. //
  1826. // Legacy 1x1 and non-1st open. assign the same
  1827. // FilterInstance and succeed it.
  1828. //
  1829. PLIST_ENTRY node;
  1830. ASSERT( !IsListEmpty( &DeviceExtension->FilterInstanceList));
  1831. node = DeviceExtension->FilterInstanceList.Flink;
  1832. FilterInstance = CONTAINING_RECORD(node,
  1833. FILTER_INSTANCE,
  1834. NextFilterInstance);
  1835. ASSERT_FILTER_INSTANCE( FilterInstance );
  1836. *ReturnedFilterInstance = FilterInstance;
  1837. Status = STATUS_SUCCESS;
  1838. return Status; // can't goto Exit, it will insert FI again.
  1839. }
  1840. FilterInstance =
  1841. ExAllocatePool(NonPagedPool, sizeof(FILTER_INSTANCE) +
  1842. FilterExtensionSize +
  1843. sizeof(ADDITIONAL_PIN_INFO) *
  1844. NumberOfPins);
  1845. if (!FilterInstance) {
  1846. Status = STATUS_INSUFFICIENT_RESOURCES;
  1847. goto Exit;
  1848. }
  1849. RtlZeroMemory(FilterInstance, sizeof(FILTER_INSTANCE) +
  1850. FilterExtensionSize +
  1851. sizeof(ADDITIONAL_PIN_INFO) *
  1852. NumberOfPins);
  1853. FilterInstance->Signature = SIGN_FILTER_INSTANCE;
  1854. FilterInstance->DeviceExtension = DeviceExtension; // keep this handy
  1855. //
  1856. // To get FilterInstance from HwInstanceExtension we need
  1857. // to arrange the memory layout
  1858. // [FilterInstnace][HwInstanceExtension][AddionalPinInfo...]
  1859. // as opposed to
  1860. // [FilterInstance][AdditionalPinInfo...][HwInstanceExtension]
  1861. //
  1862. FilterInstance->HwInstanceExtension = FilterInstance + 1;
  1863. FilterInstance->PinInstanceInfo =
  1864. (PADDITIONAL_PIN_INFO) ((PBYTE)(FilterInstance+1) + FilterExtensionSize);
  1865. FilterInstance->FilterTypeIndex = FilterTypeIndex;
  1866. //
  1867. // initialize the filter instance list
  1868. //
  1869. InitializeListHead(&FilterInstance->FirstStream);
  1870. InitializeListHead(&FilterInstance->NextFilterInstance);
  1871. InitializeListHead(&FilterInstance->NotifyList);
  1872. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  1873. Status = KsRegisterWorker( CriticalWorkQueue, &FilterInstance->WorkerRead );
  1874. if (!NT_SUCCESS( Status )) {
  1875. ExFreePool(FilterInstance);
  1876. FilterInstance = NULL;
  1877. Status = STATUS_INSUFFICIENT_RESOURCES;
  1878. ASSERT( 0 );
  1879. goto Exit;
  1880. }
  1881. Status = KsRegisterWorker( CriticalWorkQueue, &FilterInstance->WorkerWrite );
  1882. if (!NT_SUCCESS( Status )) {
  1883. KsUnregisterWorker( FilterInstance->WorkerRead );
  1884. ExFreePool(FilterInstance);
  1885. FilterInstance = NULL;
  1886. Status = STATUS_INSUFFICIENT_RESOURCES;
  1887. ASSERT( 0 );
  1888. goto Exit;
  1889. }
  1890. DebugPrint((DebugLevelVerbose,
  1891. "RegisterReadWorker %x WriteWorker %x\n",
  1892. FilterInstance->WorkerRead,
  1893. FilterInstance->WorkerWrite));
  1894. #endif
  1895. //
  1896. // initialize the current and max instances
  1897. //
  1898. CurrentAdditionalInfo = FilterInstance->PinInstanceInfo;
  1899. CurrentInfo = &DeviceExtension->StreamDescriptor->StreamInfo;
  1900. for (i = 0; i < NumberOfPins; i++) {
  1901. CurrentAdditionalInfo[i].CurrentInstances = 0;
  1902. CurrentAdditionalInfo[i].MaxInstances =
  1903. CurrentInfo->NumberOfPossibleInstances;
  1904. //
  1905. // index to next streaminfo and additional info structures.
  1906. //
  1907. CurrentInfo++;
  1908. }
  1909. //
  1910. // fill in the filter dispatch table pointer
  1911. //
  1912. KsAllocateObjectHeader(&FilterInstance->DeviceHeader,
  1913. SIZEOF_ARRAY(CreateHandlers),
  1914. (PKSOBJECT_CREATE_ITEM) CreateHandlers,
  1915. Irp,
  1916. (PKSDISPATCH_TABLE) & FilterDispatchTable);
  1917. if (FilterExtensionSize) {
  1918. //
  1919. // call the minidriver to open the instance if the call is supported.
  1920. // final status will be processed in the callback procedure.
  1921. //
  1922. //
  1923. // C4312 fix: This union corresponds to the _CommandData union within
  1924. // HW_STREAM_REQUEST_BLOCK. This is done to correctly align
  1925. // FilterTypeIndex for assignment on 64-bit such that it doesn't
  1926. // break on big endian machines. I don't want to waste stack
  1927. // space with an entire HW_STREAM_REQUEST_BLOCK for a 64-bit safe
  1928. // cast.
  1929. //
  1930. union {
  1931. PVOID Buffer;
  1932. LONG FilterTypeIndex;
  1933. } u;
  1934. u.Buffer = NULL;
  1935. u.FilterTypeIndex = (LONG)FilterTypeIndex;
  1936. Status = SCSubmitRequest(
  1937. SRB_OPEN_DEVICE_INSTANCE,
  1938. u.Buffer,
  1939. 0,
  1940. SCDequeueAndDeleteSrb, //SCGlobalInstanceCallback,
  1941. DeviceExtension,
  1942. FilterInstance->HwInstanceExtension,
  1943. NULL,
  1944. Irp,
  1945. &RequestIssued,
  1946. &DeviceExtension->PendingQueue,
  1947. (PVOID) DeviceExtension->MinidriverData->HwInitData.HwReceivePacket
  1948. );
  1949. if (!RequestIssued) {
  1950. //
  1951. // if request not issued, fail the request as we could not send
  1952. // it down.
  1953. //
  1954. ASSERT(Status != STATUS_SUCCESS);
  1955. KsFreeObjectHeader(FilterInstance->DeviceHeader);
  1956. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  1957. KsUnregisterWorker( FilterInstance->WorkerRead );
  1958. KsUnregisterWorker( FilterInstance->WorkerWrite );
  1959. #endif
  1960. //ExFreePool(FilterInstance);
  1961. }
  1962. } // if minidriver supports multiple filter
  1963. Exit: {
  1964. if ( NT_SUCCESS( Status ) ) {
  1965. DebugPrint((DebugLevelInfo,
  1966. "Inserting FilterInstance %x\n",
  1967. FilterInstance));
  1968. SCInsertFiltersInDevice( FilterInstance, DeviceExtension );
  1969. }
  1970. else if ( NULL != FilterInstance) {
  1971. ExFreePool( FilterInstance );
  1972. FilterInstance = NULL;
  1973. }
  1974. *ReturnedFilterInstance = FilterInstance;
  1975. return (Status);
  1976. }
  1977. }
  1978. #else // ENABLE_MULTIPLE_FILTER_TYPES
  1979. #endif // ENABLE_MULTIPLE_FILTER_TYPES
  1980. NTSTATUS
  1981. SCSubmitRequest(
  1982. IN SRB_COMMAND Command,
  1983. IN PVOID Buffer,
  1984. IN ULONG DataSize,
  1985. IN PSTREAM_CALLBACK_PROCEDURE Callback,
  1986. IN PDEVICE_EXTENSION DeviceExtension,
  1987. IN PVOID InstanceExtension,
  1988. IN OPTIONAL PHW_STREAM_OBJECT HwStreamObject,
  1989. IN PIRP Irp,
  1990. OUT PBOOLEAN RequestIssued,
  1991. IN PLIST_ENTRY Queue,
  1992. IN PVOID MinidriverRoutine
  1993. )
  1994. /*++
  1995. Routine Description:
  1996. This routine generically submits a non-data SRB to the minidriver. The
  1997. callback procedure is called back at PASSIVE level.
  1998. Arguments:
  1999. Command - command to issue
  2000. Buffer - data buffer, if any
  2001. DataSize - length of transfer
  2002. Callback - procedure to call back at passive level
  2003. DeviceExtension - pointer to device extension
  2004. InstanceExtension - pointer to instance extension, if any
  2005. HwStreamObject - optional pointer to minidriver's stream object
  2006. Irp - pointer to IRP
  2007. RequestIssued - pointer to boolean which is set if request issued
  2008. Queue - queue upon which to enqueue the request
  2009. MinidriverRoutine - request routine to call with the request
  2010. Return Value:
  2011. Status
  2012. --*/
  2013. {
  2014. PSTREAM_OBJECT StreamObject = 0;
  2015. PSTREAM_REQUEST_BLOCK Request = SCBuildRequestPacket(DeviceExtension,
  2016. Irp,
  2017. 0,
  2018. 0);
  2019. NTSTATUS Status;
  2020. PAGED_CODE();
  2021. //
  2022. // assume request will be successfully issued.
  2023. //
  2024. *RequestIssued = TRUE;
  2025. //
  2026. // if the alloc failed, call the callback procedure with a null SRB
  2027. //
  2028. if (!Request) {
  2029. *RequestIssued = FALSE;
  2030. return (STATUS_INSUFFICIENT_RESOURCES);
  2031. }
  2032. if (HwStreamObject) {
  2033. StreamObject = CONTAINING_RECORD(
  2034. HwStreamObject,
  2035. STREAM_OBJECT,
  2036. HwStreamObject
  2037. );
  2038. //
  2039. // hack. we need to set the stream request flag if this is a stream
  2040. // request. the only case that we would NOT set this when a stream
  2041. // object is passed in is on an OPEN or CLOSE, where the stream
  2042. // object is
  2043. // passed in on a device request. special case this. if later
  2044. // this assumption changes, an assert will be hit in lowerapi.
  2045. //
  2046. if ((Command != SRB_OPEN_STREAM) && (Command != SRB_CLOSE_STREAM)) {
  2047. Request->HwSRB.Flags |= SRB_HW_FLAGS_STREAM_REQUEST;
  2048. }
  2049. }
  2050. //
  2051. // initialize event for blocking for completion
  2052. //
  2053. KeInitializeEvent(&Request->Event, SynchronizationEvent, FALSE);
  2054. Request->HwSRB.Command = Command;
  2055. Request->Callback = SCSignalSRBEvent;
  2056. Request->HwSRB.HwInstanceExtension = InstanceExtension;
  2057. Request->HwSRB.StreamObject = HwStreamObject;
  2058. Request->HwSRB.CommandData.StreamBuffer = Buffer;
  2059. Request->HwSRB.HwDeviceExtension = DeviceExtension->HwDeviceExtension;
  2060. Request->HwSRB.NumberOfBytesToTransfer = DataSize;
  2061. Request->DoNotCallBack = FALSE;
  2062. //
  2063. // call routine to actually submit request to the device
  2064. //
  2065. Status = SCIssueRequestToDevice(DeviceExtension,
  2066. StreamObject,
  2067. Request,
  2068. MinidriverRoutine,
  2069. Queue,
  2070. Irp);
  2071. //
  2072. // block waiting for completion if pending
  2073. //
  2074. if (Status == STATUS_PENDING) {
  2075. KeWaitForSingleObject(&Request->Event, Executive, KernelMode, FALSE, NULL);
  2076. }
  2077. return (Callback(Request));
  2078. }
  2079. VOID
  2080. SCSignalSRBEvent(
  2081. IN PSTREAM_REQUEST_BLOCK Srb
  2082. )
  2083. /*++
  2084. Routine Description:
  2085. Sets the event for a completed SRB
  2086. Arguments:
  2087. Srb - pointer to the request
  2088. Return Value:
  2089. none
  2090. --*/
  2091. {
  2092. KeSetEvent(&Srb->Event, IO_NO_INCREMENT, FALSE);
  2093. return;
  2094. }
  2095. NTSTATUS
  2096. SCProcessDataTransfer(
  2097. IN PDEVICE_EXTENSION DeviceExtension,
  2098. IN PIRP Irp,
  2099. IN SRB_COMMAND Command
  2100. )
  2101. /*++
  2102. Routine Description:
  2103. Process a data transfer request to a stream
  2104. Arguments:
  2105. DeviceExtension - address of device extension.
  2106. Irp - pointer to the IRP
  2107. Command - read or write command
  2108. Return Value:
  2109. NTSTATUS returned as appropriate
  2110. --*/
  2111. {
  2112. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2113. PSTREAM_REQUEST_BLOCK Request;
  2114. PSTREAM_OBJECT StreamObject = IrpStack->FileObject->FsContext;
  2115. NTSTATUS Status;
  2116. PKSSTREAM_HEADER OutputBuffer = NULL;
  2117. ULONG NumberOfPages = 0,
  2118. NumberOfBuffers = 0;
  2119. ULONG Flags =
  2120. KSPROBE_STREAMWRITE |
  2121. KSPROBE_ALLOCATEMDL |
  2122. KSPROBE_PROBEANDLOCK |
  2123. KSPROBE_ALLOWFORMATCHANGE;
  2124. ULONG HeaderSize=0; // prefixbug 17392
  2125. ULONG ExtraSize=0; // prefixbug 17391
  2126. #if DBG
  2127. PMDL CurrentMdl;
  2128. #endif
  2129. PVOID pMemPtrArray = NULL;
  2130. PAGED_CODE();
  2131. //
  2132. // if we are flushing, we must error any I/O during this period.
  2133. //
  2134. if (StreamObject->InFlush) {
  2135. DebugPrint((DebugLevelError,
  2136. "'StreamDispatchIOControl: Aborting IRP during flush!"));
  2137. TRAP;
  2138. return (STATUS_DEVICE_NOT_READY);
  2139. } // if flushing
  2140. Irp->IoStatus.Information = 0;
  2141. #if DBG
  2142. DeviceExtension->NumberOfRequests++;
  2143. #endif
  2144. if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength) {
  2145. //
  2146. // get the size of the header and the expansion from the minidriver.
  2147. //
  2148. HeaderSize = StreamObject->HwStreamObject.StreamHeaderMediaSpecific +
  2149. sizeof(KSSTREAM_HEADER);
  2150. ExtraSize = StreamObject->HwStreamObject.StreamHeaderWorkspace;
  2151. //
  2152. // we assumed this was a write. do additional processing if a read.
  2153. //
  2154. if (Command == SRB_READ_DATA) {
  2155. Flags =
  2156. KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK;
  2157. //
  2158. // this is a read, so set the information field in the irp to
  2159. // copy back the headers when the I/O is complete.
  2160. //
  2161. Irp->IoStatus.Information =
  2162. IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  2163. }
  2164. //
  2165. // lock and probe the buffer
  2166. //
  2167. DebugPrint((DebugLevelVerbose, "Stream: HeaderSize:%x\n",HeaderSize));
  2168. DebugPrint((DebugLevelVerbose, "Stream: sizeof(KSSSTREAM_HEADER):%x\n",sizeof(KSSTREAM_HEADER)));
  2169. DebugPrint((DebugLevelVerbose, "Stream: MediaSpecific:%x\n",StreamObject->HwStreamObject.StreamHeaderMediaSpecific));
  2170. DebugPrint((DebugLevelVerbose, "Stream: StreamHeader->Size:%x\n",((PKSSTREAM_HEADER)(Irp->UserBuffer))->Size));
  2171. if (!NT_SUCCESS(Status =
  2172. KsProbeStreamIrp(Irp,
  2173. Flags,
  2174. HeaderSize))) {
  2175. DebugPrint((DebugLevelError, "Stream: ProbeStreamIrp failed!"));
  2176. return (Status);
  2177. }
  2178. if (!ExtraSize) {
  2179. OutputBuffer = (PKSSTREAM_HEADER)
  2180. Irp->AssociatedIrp.SystemBuffer;
  2181. IrpStack->Parameters.Others.Argument4 = NULL;
  2182. } else {
  2183. TRAP;
  2184. if (!NT_SUCCESS(Status = KsAllocateExtraData(Irp,
  2185. ExtraSize,
  2186. &OutputBuffer))) {
  2187. DebugPrint((DebugLevelError, "Stream: AllocExtraData failed!"));
  2188. return (Status);
  2189. } // if not success
  2190. IrpStack->Parameters.Others.Argument4 = OutputBuffer;
  2191. }
  2192. #if DBG
  2193. //
  2194. // assert the MDL list.
  2195. //
  2196. CurrentMdl = Irp->MdlAddress;
  2197. while (CurrentMdl) {
  2198. CurrentMdl = CurrentMdl->Next;
  2199. } // while
  2200. #endif
  2201. //
  2202. // calculate the # of buffers.
  2203. //
  2204. NumberOfBuffers = IrpStack->Parameters.
  2205. DeviceIoControl.OutputBufferLength / HeaderSize;
  2206. //
  2207. // do addtional processing on the data buffers.
  2208. //
  2209. if (StreamObject->HwStreamObject.Dma) { // an optimization
  2210. SCProcessDmaDataBuffers(OutputBuffer,
  2211. NumberOfBuffers,
  2212. StreamObject,
  2213. Irp->MdlAddress,
  2214. &NumberOfPages,
  2215. HeaderSize + ExtraSize,
  2216. (BOOLEAN) (Command == SRB_WRITE_DATA));
  2217. }
  2218. //
  2219. // if number of pages is > than the max supported, return error.
  2220. // Allow
  2221. // for one extra map register for the SRB extension.
  2222. //
  2223. // GUBGUB - This is really a workitem to make it correct.
  2224. // need to break up requests that have too many elements.
  2225. //
  2226. if (NumberOfPages > (DeviceExtension->NumberOfMapRegisters - 1)) {
  2227. return (STATUS_INSUFFICIENT_RESOURCES);
  2228. }
  2229. } // if BufferSize
  2230. //
  2231. // build an SRB and alloc workspace for the request. Allocate
  2232. // scatter/gather space also if needed.
  2233. //
  2234. Request = SCBuildRequestPacket(DeviceExtension,
  2235. Irp,
  2236. NumberOfPages * sizeof(KSSCATTER_GATHER),
  2237. NumberOfBuffers * sizeof(PVOID));
  2238. if (Request == NULL) {
  2239. return (STATUS_INSUFFICIENT_RESOURCES);
  2240. }
  2241. //
  2242. // do more addtional processing on the data buffers.
  2243. //
  2244. if (StreamObject->HwStreamObject.Pio) { // a small optimization
  2245. Request->bMemPtrValid = SCProcessPioDataBuffers(OutputBuffer,
  2246. NumberOfBuffers,
  2247. StreamObject,
  2248. Irp->MdlAddress,
  2249. HeaderSize + ExtraSize,
  2250. Request->pMemPtrArray,
  2251. (BOOLEAN) (Command == SRB_WRITE_DATA));
  2252. }
  2253. //
  2254. // set # of physical pages
  2255. //
  2256. Request->HwSRB.NumberOfPhysicalPages = NumberOfPages;
  2257. //
  2258. // set # of data buffers
  2259. //
  2260. Request->HwSRB.NumberOfBuffers = NumberOfBuffers;
  2261. //
  2262. // set the command code in the packet.
  2263. //
  2264. Request->HwSRB.Command = Command;
  2265. //
  2266. // set the input and output buffers
  2267. //
  2268. Request->HwSRB.CommandData.DataBufferArray = OutputBuffer;
  2269. Request->HwSRB.HwDeviceExtension = DeviceExtension->HwDeviceExtension;
  2270. Request->Callback = SCProcessCompletedDataRequest;
  2271. Request->HwSRB.StreamObject = &StreamObject->HwStreamObject;
  2272. Request->StreamHeaderSize = HeaderSize + ExtraSize;
  2273. Request->DoNotCallBack = FALSE;
  2274. Request->HwSRB.Flags |= (SRB_HW_FLAGS_DATA_TRANSFER
  2275. | SRB_HW_FLAGS_STREAM_REQUEST);
  2276. ASSERT_FILTER_INSTANCE( StreamObject->FilterInstance );
  2277. Request->HwSRB.HwInstanceExtension =
  2278. StreamObject->FilterInstance->HwInstanceExtension;
  2279. //
  2280. // point the IRP workspace to the request
  2281. // packet
  2282. //
  2283. Irp->Tail.Overlay.DriverContext[0] = Request;
  2284. IoMarkIrpPending(Irp);
  2285. // ASSERT((IoGetCurrentIrpStackLocation(Irp)->MajorFunction ==
  2286. // IOCTL_KS_READ_STREAM) ||
  2287. // (IoGetCurrentIrpStackLocation(Irp)->MajorFunction ==
  2288. // IOCTL_KS_WRITE_STREAM));
  2289. ASSERT((ULONG_PTR) Irp->Tail.Overlay.DriverContext[0] > 0x40000000);
  2290. return (SCIssueRequestToDevice(DeviceExtension,
  2291. StreamObject,
  2292. Request,
  2293. StreamObject->HwStreamObject.ReceiveDataPacket,
  2294. &StreamObject->DataPendingQueue,
  2295. Irp));
  2296. }
  2297. VOID
  2298. SCErrorDataSRB(
  2299. IN PHW_STREAM_REQUEST_BLOCK SRB
  2300. )
  2301. /*++
  2302. Routine Description:
  2303. Dummy routine invoked when a data request is received for non-data
  2304. receiving stream.
  2305. Arguments:
  2306. SRB- address of STREAM request block
  2307. Return Value:
  2308. None.
  2309. --*/
  2310. {
  2311. //
  2312. // just call the SRB back with error
  2313. //
  2314. SRB->Status = STATUS_NOT_SUPPORTED;
  2315. StreamClassStreamNotification(StreamRequestComplete,
  2316. SRB->StreamObject);
  2317. StreamClassStreamNotification(ReadyForNextStreamDataRequest,
  2318. SRB->StreamObject);
  2319. } // SCErrorDataSRB
  2320. NTSTATUS
  2321. SCIssueRequestToDevice(
  2322. IN PDEVICE_EXTENSION DeviceExtension,
  2323. IN OPTIONAL PSTREAM_OBJECT StreamObject,
  2324. PSTREAM_REQUEST_BLOCK Request,
  2325. IN PVOID MinidriverRoutine,
  2326. IN PLIST_ENTRY Queue,
  2327. IN PIRP Irp
  2328. )
  2329. /*++
  2330. Routine Description:
  2331. This routine calls the minidriver's request vector with a request.
  2332. Both data and non-data requests are handled by this routine. The routine
  2333. either synchronizes the call or not, based on the NoSync boolean.
  2334. Arguments:
  2335. DeviceExtension - pointer to device extension
  2336. StreamObject - optional pointer to stream object
  2337. MinidriverRoutine - request routine to call with the request
  2338. Queue - queue upon which to enqueue the request
  2339. Irp - pointer to IRP
  2340. Return Value:
  2341. Status
  2342. --*/
  2343. {
  2344. KIRQL irql;
  2345. KeAcquireSpinLock(&DeviceExtension->SpinLock, &irql);
  2346. if (DeviceExtension->NoSync) {
  2347. //
  2348. // place the request on the
  2349. // outstanding queue and call it down
  2350. // immediately
  2351. //
  2352. ASSERT((DeviceExtension->BeginMinidriverCallin == SCBeginSynchronizedMinidriverCallin) ||
  2353. (DeviceExtension->BeginMinidriverCallin == SCBeginUnsynchronizedMinidriverCallin));
  2354. Request->Flags |= SRB_FLAGS_IS_ACTIVE;
  2355. InsertHeadList(
  2356. &DeviceExtension->OutstandingQueue,
  2357. &Request->SRBListEntry);
  2358. IoSetCancelRoutine(Irp, StreamClassCancelOutstandingIrp);
  2359. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  2360. if ((StreamObject) && (StreamObject->HwStreamObject.Dma) &&
  2361. (Request->HwSRB.Flags & SRB_HW_FLAGS_DATA_TRANSFER)) {
  2362. //
  2363. // allocate the adapter channel. call cannot fail as the only
  2364. // time it would is when there aren't enough map registers, and
  2365. // we've already checked for that condition. Block waiting til
  2366. // it's allocated.
  2367. //
  2368. KIRQL oldIrql;
  2369. KeInitializeEvent(&Request->DmaEvent, SynchronizationEvent, FALSE);
  2370. ASSERT( PASSIVE_LEVEL == KeGetCurrentIrql());
  2371. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  2372. SCSetUpForDMA(DeviceExtension->DeviceObject,
  2373. Request);
  2374. KeLowerIrql( oldIrql );
  2375. KeWaitForSingleObject(&Request->DmaEvent, Executive, KernelMode, FALSE, NULL);
  2376. }
  2377. // this could open a race window. It should be protected in spinlock.
  2378. //Request->Flags |= SRB_FLAGS_IS_ACTIVE;
  2379. ((PHW_RECEIVE_STREAM_CONTROL_SRB) (MinidriverRoutine))
  2380. (&Request->HwSRB);
  2381. } else {
  2382. //
  2383. // insert the item on the queue
  2384. //
  2385. InsertHeadList(
  2386. Queue,
  2387. &Irp->Tail.Overlay.ListEntry);
  2388. //
  2389. // set the cancel routine to pending
  2390. //
  2391. IoSetCancelRoutine(Irp, StreamClassCancelPendingIrp);
  2392. //
  2393. // check to see if the IRP is already cancelled.
  2394. //
  2395. if (Irp->Cancel) {
  2396. //
  2397. // the IRP is cancelled. Make sure that the cancel routine
  2398. // will be called.
  2399. //
  2400. if (IoSetCancelRoutine(Irp, NULL)) {
  2401. //
  2402. // wow, the cancel routine will not be invoked.
  2403. // dequeue the request ourselves and complete
  2404. // with cancelled status.
  2405. RemoveEntryList(&Request->SRBListEntry);
  2406. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  2407. //
  2408. // free the SRB and MDL
  2409. //
  2410. IoFreeMdl(Request->Mdl);
  2411. ExFreePool(Request);
  2412. return (STATUS_CANCELLED);
  2413. } else { // if we must cancel
  2414. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  2415. } // if we must cancel
  2416. return (STATUS_PENDING);
  2417. } // if cancelled
  2418. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2419. //
  2420. // call the DPC routine directly. GUBGUB questionable performance improvement chance
  2421. // BGP - is this really
  2422. // faster than scheduling it?
  2423. //
  2424. StreamClassDpc(NULL, DeviceExtension->DeviceObject, Irp, StreamObject);
  2425. KeLowerIrql(irql);
  2426. }
  2427. return (STATUS_PENDING);
  2428. }
  2429. BOOLEAN
  2430. SCCheckFilterInstanceStreamsForIrp(
  2431. IN PFILTER_INSTANCE FilterInstance,
  2432. IN PIRP Irp
  2433. )
  2434. /*++
  2435. Routine Description:
  2436. This routine checks all filter instance streams for the specified IRP.
  2437. Arguments:
  2438. FilterInstance - pointer to the filter instance
  2439. Irp - pointer to the IRP.
  2440. Return Value:
  2441. TRUE if the IRP is found.
  2442. --*/
  2443. {
  2444. PSTREAM_OBJECT StreamObject;
  2445. PLIST_ENTRY StreamListEntry,
  2446. StreamObjectEntry;
  2447. StreamListEntry = StreamObjectEntry = &FilterInstance->FirstStream;
  2448. while (StreamObjectEntry->Flink != StreamListEntry) {
  2449. StreamObjectEntry = StreamObjectEntry->Flink;
  2450. //
  2451. // follow the link to the stream
  2452. // object
  2453. //
  2454. StreamObject = CONTAINING_RECORD(StreamObjectEntry,
  2455. STREAM_OBJECT,
  2456. NextStream);
  2457. if (SCCheckRequestsForIrp(
  2458. &StreamObject->DataPendingQueue, Irp, TRUE, StreamObject->DeviceExtension)) {
  2459. return (TRUE);
  2460. }
  2461. if (SCCheckRequestsForIrp(
  2462. &StreamObject->ControlPendingQueue, Irp, TRUE, StreamObject->DeviceExtension)) {
  2463. return (TRUE);
  2464. }
  2465. }
  2466. return (FALSE);
  2467. } // SCCheckFilterInstanceStreamsForIrp
  2468. BOOLEAN
  2469. SCCheckRequestsForIrp(
  2470. IN PLIST_ENTRY ListEntry,
  2471. IN PIRP Irp,
  2472. IN BOOLEAN IsIrpQueue,
  2473. IN PDEVICE_EXTENSION DeviceExtension
  2474. )
  2475. /*++
  2476. Routine Description:
  2477. This routine checks all requests on a queue for the specified IRP.
  2478. If the IRP parameter is NULL, the first IRP on the queue is cancelled.
  2479. Arguments:
  2480. ListEntry - list to check for the IRP
  2481. Irp - pointer to the IRP or NULL to cancel the first IRP.
  2482. IsIrpQueue - TRUE indicates an IRP queue, FALSE indicates an SRB queue
  2483. DeviceExtension - pointer to the device extension
  2484. Return Value:
  2485. TRUE if the IRP is found or if we cancel it.
  2486. --*/
  2487. {
  2488. PLIST_ENTRY IrpEntry = ListEntry;
  2489. PIRP CurrentIrp;
  2490. while (IrpEntry->Flink != ListEntry) {
  2491. IrpEntry = IrpEntry->Flink;
  2492. ASSERT(IrpEntry);
  2493. ASSERT(IrpEntry->Flink);
  2494. ASSERT(IrpEntry->Blink);
  2495. //
  2496. // follow the link to the IRP
  2497. //
  2498. if (IsIrpQueue) {
  2499. CurrentIrp = CONTAINING_RECORD(IrpEntry,
  2500. IRP,
  2501. Tail.Overlay.ListEntry);
  2502. } else {
  2503. CurrentIrp = ((PSTREAM_REQUEST_BLOCK) (CONTAINING_RECORD(IrpEntry,
  2504. STREAM_REQUEST_BLOCK,
  2505. SRBListEntry)))->HwSRB.Irp;
  2506. }
  2507. //
  2508. // this routine is used to cancel irp's if IRP is null.
  2509. //
  2510. if ((!Irp) && (!CurrentIrp->Cancel)) {
  2511. //
  2512. // The IRP has not been previously cancelled, so cancel it after
  2513. // releasing the spinlock to avoid deadlock with the cancel
  2514. // routine.
  2515. //
  2516. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2517. //
  2518. // This code is suspicious that the CurrentIrp is not protected, i.e.
  2519. // it could be processed and freed from other thread. However, we
  2520. // are not never called with (!Irp). Therefore, we should never
  2521. // come in executing this piece of code. here is the analysis.
  2522. // 1. We are called from
  2523. // a. SCCheckFilterInstanceStreamIrp()
  2524. // b. SCCancelOutstandingIrp()
  2525. // c. StreamClassCancelPendingIrp()
  2526. // 2. Further inspection shows that a. SCCheckFilterInstanceStreamForIrp() is
  2527. // only called by StreamClassCancelPendingIrp() which always has non-null Irp.
  2528. // 3. SCCancelOutstandingIrp() is called by
  2529. // a. StreamClassCancelPendingIrp() which always has non-NULL irp.
  2530. // b. StreamClassCancelOutstandingIrp() which always has non-NULL irp.
  2531. // The concusion is that we are never called with null irp. Therefore, this
  2532. // piece code is never executed. But this driver has been thru win2k extenteded
  2533. // test cycle. I rather be conservative. Add an Assertion instead of removing
  2534. // the code for now.
  2535. //
  2536. ASSERT( 0 );
  2537. IoCancelIrp(CurrentIrp);
  2538. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  2539. return (TRUE);
  2540. }
  2541. if (Irp == CurrentIrp) {
  2542. return (TRUE);
  2543. }
  2544. } // while list entry
  2545. return (FALSE);
  2546. } // SCCheckRequestsForIrp
  2547. VOID
  2548. SCNotifyMinidriverCancel(
  2549. IN PSTREAM_REQUEST_BLOCK SRB
  2550. )
  2551. /*++
  2552. Routine Description:
  2553. Synchronized routine to notify minidriver that an IRP has been canceled
  2554. Arguments:
  2555. SRB - pointer to SRB that has been canceled.
  2556. Return Value:
  2557. none
  2558. --*/
  2559. {
  2560. PDEVICE_EXTENSION DeviceExtension =
  2561. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  2562. //
  2563. // if the active flag is still set in the SRB, the minidriver still
  2564. // has it so call him to abort it.
  2565. //
  2566. if (SRB->Flags & SRB_FLAGS_IS_ACTIVE) {
  2567. //
  2568. // call the minidriver with the SRB.
  2569. //
  2570. (DeviceExtension->MinidriverData->HwInitData.HwCancelPacket)
  2571. (&SRB->HwSRB);
  2572. }
  2573. return;
  2574. }
  2575. VOID
  2576. SCCancelOutstandingIrp(
  2577. IN PDEVICE_EXTENSION DeviceExtension,
  2578. IN PIRP Irp
  2579. )
  2580. /*++
  2581. Routine Description:
  2582. Routine to notify minidriver that an IRP has been canceled. Device
  2583. spinlock NUST be taken before this routine is called.
  2584. Arguments:
  2585. DeviceExtension - pointer to device extension
  2586. Irp - pointer to the IRP.
  2587. Return Value:
  2588. none
  2589. --*/
  2590. {
  2591. PSTREAM_REQUEST_BLOCK Srb;
  2592. //
  2593. // just return if the request is not on
  2594. // our queue.
  2595. //
  2596. if ((!IsListEmpty(&DeviceExtension->OutstandingQueue)) &&
  2597. (SCCheckRequestsForIrp(
  2598. &DeviceExtension->OutstandingQueue, Irp, FALSE, DeviceExtension))) {
  2599. //
  2600. // the request is sitting on our
  2601. // outstanding queue. call the
  2602. // minidriver
  2603. // via a synchronize routine to
  2604. // cancel it.
  2605. //
  2606. Srb = Irp->Tail.Overlay.DriverContext[0];
  2607. #if DBG
  2608. if (Srb->HwSRB.StreamObject) {
  2609. DebugPrint((DebugLevelWarning, "'SCCancelOutstanding: canceling, Irp = %x, Srb = %x, S# = %x\n",
  2610. Irp, Srb, Srb->HwSRB.StreamObject->StreamNumber));
  2611. } else {
  2612. DebugPrint((DebugLevelWarning, "'SCCancelOutstanding: canceling nonstream, Irp = %x\n",
  2613. Irp));
  2614. } // if SO
  2615. #endif
  2616. if (DeviceExtension->NoSync) {
  2617. //
  2618. // we need to ensure that the SRB memory is valid for the async
  2619. // minidriver, EVEN if it happens to call back the request just
  2620. // before we call it to cancel it! This is done for two
  2621. // reasons:
  2622. // it obviates the need for the minidriver to walk its request
  2623. // queues to find the request, and I failed to pass the dev ext
  2624. // pointer to the minidriver in the below call, which means that
  2625. // the SRB HAS to be valid, and it's too late to change the API.
  2626. //
  2627. // Oh, well. Spinlock is now taken (by caller).
  2628. //
  2629. if (!(Srb->Flags & SRB_FLAGS_IS_ACTIVE)) {
  2630. return;
  2631. }
  2632. Srb->DoNotCallBack = TRUE;
  2633. //
  2634. // release the spinlock temporarily since we need to call the
  2635. // minidriver. The caller won't be affected by this.
  2636. //
  2637. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2638. (DeviceExtension->MinidriverData->HwInitData.HwCancelPacket)
  2639. (&Srb->HwSRB);
  2640. //
  2641. // reacquire the spinlock since the caller will release it
  2642. //
  2643. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  2644. Srb->DoNotCallBack = FALSE;
  2645. //
  2646. // if the ACTIVE flag is now clear, it indicates that the
  2647. // SRB was completed during the above call into the minidriver.
  2648. // since we blocked the internal completion of the request,
  2649. // we must call it back ourselves in this case.
  2650. //
  2651. if (!(Srb->Flags & SRB_FLAGS_IS_ACTIVE)) {
  2652. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2653. (Srb->Callback) (Srb);
  2654. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  2655. } // if ! active
  2656. } else {
  2657. DeviceExtension->SynchronizeExecution(
  2658. DeviceExtension->InterruptObject,
  2659. (PVOID) SCNotifyMinidriverCancel,
  2660. Srb);
  2661. } // if nosync
  2662. } // if on our queue
  2663. return;
  2664. }
  2665. NTSTATUS
  2666. SCMinidriverDevicePropertyHandler(
  2667. IN SRB_COMMAND Command,
  2668. IN PIRP Irp,
  2669. IN PKSPROPERTY Property,
  2670. IN OUT PVOID PropertyInfo
  2671. )
  2672. /*++
  2673. Routine Description:
  2674. Process get/set property to the device.
  2675. Arguments:
  2676. Command - either GET or SET property
  2677. Irp - pointer to the IRP
  2678. Property - pointer to the property structure
  2679. PropertyInfo - buffer for property information
  2680. Return Value:
  2681. NTSTATUS returned as appropriate.
  2682. --*/
  2683. {
  2684. PIO_STACK_LOCATION IrpStack;
  2685. PDEVICE_EXTENSION DeviceExtension;
  2686. PFILTER_INSTANCE FilterInstance;
  2687. PSTREAM_PROPERTY_DESCRIPTOR PropDescriptor;
  2688. NTSTATUS Status;
  2689. BOOLEAN RequestIssued;
  2690. PAGED_CODE();
  2691. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2692. DeviceExtension = (PDEVICE_EXTENSION)
  2693. (IrpStack->DeviceObject)->DeviceExtension;
  2694. FilterInstance = IrpStack->FileObject->FsContext;
  2695. PropDescriptor = ExAllocatePool(NonPagedPool,
  2696. sizeof(STREAM_PROPERTY_DESCRIPTOR));
  2697. if (PropDescriptor == NULL) {
  2698. DebugPrint((DebugLevelError,
  2699. "SCDevicePropHandler: No pool for descriptor"));
  2700. return (STATUS_INSUFFICIENT_RESOURCES);
  2701. }
  2702. //
  2703. // compute the index of the property set.
  2704. //
  2705. // this value is calculated by subtracting the base property set
  2706. // pointer from the requested property set pointer.
  2707. //
  2708. // The requested property set is pointed to by Context[0] by
  2709. // KsPropertyHandler.
  2710. //
  2711. PropDescriptor->PropertySetID = (ULONG)
  2712. ((ULONG_PTR) Irp->Tail.Overlay.DriverContext[0] -
  2713. IFN_MF( (ULONG_PTR) DeviceExtension->DevicePropertiesArray)
  2714. IF_MF( (ULONG_PTR) FilterInstance->DevicePropertiesArray)
  2715. )/ sizeof(KSPROPERTY_SET);
  2716. PropDescriptor->Property = Property;
  2717. PropDescriptor->PropertyInfo = PropertyInfo;
  2718. PropDescriptor->PropertyInputSize =
  2719. IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  2720. PropDescriptor->PropertyOutputSize =
  2721. IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  2722. //
  2723. // send a get or set property SRB to the device.
  2724. //
  2725. Status = SCSubmitRequest(Command,
  2726. PropDescriptor,
  2727. 0,
  2728. SCProcessCompletedPropertyRequest,
  2729. DeviceExtension,
  2730. FilterInstance->HwInstanceExtension,
  2731. NULL,
  2732. Irp,
  2733. &RequestIssued,
  2734. &DeviceExtension->PendingQueue,
  2735. (PVOID) DeviceExtension->
  2736. MinidriverData->HwInitData.
  2737. HwReceivePacket
  2738. );
  2739. if (!RequestIssued) {
  2740. ExFreePool(PropDescriptor);
  2741. }
  2742. return (Status);
  2743. }
  2744. NTSTATUS
  2745. SCMinidriverStreamPropertyHandler(
  2746. IN SRB_COMMAND Command,
  2747. IN PIRP Irp,
  2748. IN PKSPROPERTY Property,
  2749. IN OUT PVOID PropertyInfo
  2750. )
  2751. /*++
  2752. Routine Description:
  2753. Process get or set property to the device.
  2754. Arguments:
  2755. Command - either GET or SET property
  2756. Irp - pointer to the IRP
  2757. Property - pointer to the property structure
  2758. PropertyInfo - buffer for property information
  2759. Return Value:
  2760. None.
  2761. --*/
  2762. {
  2763. PIO_STACK_LOCATION IrpStack;
  2764. PDEVICE_EXTENSION DeviceExtension;
  2765. PSTREAM_OBJECT StreamObject;
  2766. PSTREAM_PROPERTY_DESCRIPTOR PropDescriptor;
  2767. NTSTATUS Status;
  2768. BOOLEAN RequestIssued;
  2769. PAGED_CODE();
  2770. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2771. DeviceExtension = (PDEVICE_EXTENSION)
  2772. (IrpStack->DeviceObject)->DeviceExtension;
  2773. StreamObject = IrpStack->FileObject->FsContext;
  2774. PropDescriptor = ExAllocatePool(NonPagedPool,
  2775. sizeof(STREAM_PROPERTY_DESCRIPTOR));
  2776. if (PropDescriptor == NULL) {
  2777. DebugPrint((DebugLevelError,
  2778. "SCDevicePropHandler: No pool for descriptor"));
  2779. return (STATUS_INSUFFICIENT_RESOURCES);
  2780. }
  2781. //
  2782. // compute the index of the property set.
  2783. //
  2784. // this value is calculated by subtracting the base property set
  2785. // pointer from the requested property set pointer.
  2786. //
  2787. // The requested property set is pointed to by Context[0] by
  2788. // KsPropertyHandler.
  2789. //
  2790. PropDescriptor->PropertySetID = (ULONG)
  2791. ((ULONG_PTR) Irp->Tail.Overlay.DriverContext[0] -
  2792. (ULONG_PTR) StreamObject->PropertyInfo)
  2793. / sizeof(KSPROPERTY_SET);
  2794. PropDescriptor->Property = Property;
  2795. PropDescriptor->PropertyInfo = PropertyInfo;
  2796. PropDescriptor->PropertyInputSize =
  2797. IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  2798. PropDescriptor->PropertyOutputSize =
  2799. IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  2800. //
  2801. // send a get or set property SRB to the stream.
  2802. //
  2803. Status = SCSubmitRequest(Command,
  2804. PropDescriptor,
  2805. 0,
  2806. SCProcessCompletedPropertyRequest,
  2807. DeviceExtension,
  2808. StreamObject->FilterInstance->HwInstanceExtension,
  2809. &StreamObject->HwStreamObject,
  2810. Irp,
  2811. &RequestIssued,
  2812. &StreamObject->ControlPendingQueue,
  2813. (PVOID) StreamObject->HwStreamObject.
  2814. ReceiveControlPacket
  2815. );
  2816. if (!RequestIssued) {
  2817. ExFreePool(PropDescriptor);
  2818. }
  2819. return (Status);
  2820. }
  2821. NTSTATUS
  2822. SCProcessCompletedPropertyRequest(
  2823. IN PSTREAM_REQUEST_BLOCK SRB
  2824. )
  2825. /*++
  2826. Routine Description:
  2827. This routine processes a property request which has completed.
  2828. Arguments:
  2829. SRB- address of completed STREAM request block
  2830. Return Value:
  2831. None.
  2832. --*/
  2833. {
  2834. PAGED_CODE();
  2835. //
  2836. // free the prop info structure and
  2837. // complete the request
  2838. //
  2839. ExFreePool(SRB->HwSRB.CommandData.PropertyInfo);
  2840. //
  2841. // set the information field from the SRB
  2842. // transferlength field
  2843. //
  2844. SRB->HwSRB.Irp->IoStatus.Information = SRB->HwSRB.ActualBytesTransferred;
  2845. return (SCDequeueAndDeleteSrb(SRB));
  2846. }
  2847. VOID
  2848. SCUpdateMinidriverProperties(
  2849. IN ULONG NumProps,
  2850. IN PKSPROPERTY_SET MinidriverProps,
  2851. IN BOOLEAN Stream
  2852. )
  2853. /*++
  2854. Routine Description:
  2855. Process get property to the device.
  2856. Arguments:
  2857. NumProps - number of properties to process
  2858. MinidriverProps - pointer to the array of properties to process
  2859. Stream - TRUE indicates we are processing a set for the stream
  2860. Return Value:
  2861. None.
  2862. --*/
  2863. {
  2864. PKSPROPERTY_ITEM CurrentPropId;
  2865. PKSPROPERTY_SET CurrentProp;
  2866. ULONG i,
  2867. j;
  2868. PAGED_CODE();
  2869. //
  2870. // walk the minidriver's property info to fill in the dispatch
  2871. // vectors as appropriate.
  2872. //
  2873. CurrentProp = MinidriverProps;
  2874. for (i = 0; i < NumProps; i++) {
  2875. CurrentPropId = (PKSPROPERTY_ITEM) CurrentProp->PropertyItem;
  2876. for (j = 0; j < CurrentProp->PropertiesCount; j++) {
  2877. //
  2878. // if support handler is supported, send it to the "get" handler
  2879. //
  2880. if (CurrentPropId->SupportHandler) {
  2881. if (Stream) {
  2882. CurrentPropId->SupportHandler = StreamClassMinidriverStreamGetProperty;
  2883. } else {
  2884. CurrentPropId->SupportHandler = StreamClassMinidriverDeviceGetProperty;
  2885. } // if stream
  2886. }
  2887. //
  2888. // if get prop routine is
  2889. // supported, add our vector.
  2890. //
  2891. if (CurrentPropId->GetPropertyHandler) {
  2892. if (Stream) {
  2893. CurrentPropId->GetPropertyHandler = StreamClassMinidriverStreamGetProperty;
  2894. } else {
  2895. CurrentPropId->GetPropertyHandler = StreamClassMinidriverDeviceGetProperty;
  2896. } // if stream
  2897. } // if get supported
  2898. //
  2899. // if get prop routine is
  2900. // supported, add our vector.
  2901. //
  2902. if (CurrentPropId->SetPropertyHandler) {
  2903. if (Stream) {
  2904. CurrentPropId->SetPropertyHandler = StreamClassMinidriverStreamSetProperty;
  2905. } else {
  2906. CurrentPropId->SetPropertyHandler = StreamClassMinidriverDeviceSetProperty;
  2907. } // if stream
  2908. }
  2909. //
  2910. // index to next property item in
  2911. // array
  2912. //
  2913. CurrentPropId++;
  2914. } // for number of property items
  2915. //
  2916. // index to next property set in
  2917. // array
  2918. //
  2919. CurrentProp++;
  2920. } // for number of property sets
  2921. }
  2922. VOID
  2923. SCUpdateMinidriverEvents(
  2924. IN ULONG NumEvents,
  2925. IN PKSEVENT_SET MinidriverEvents,
  2926. IN BOOLEAN Stream
  2927. )
  2928. /*++
  2929. Routine Description:
  2930. Process get property to the device.
  2931. Arguments:
  2932. NumEvents - number of event sets to process
  2933. MinidriverEvents - pointer to the array of properties to process
  2934. Stream - TRUE indicates we are processing a set for the stream
  2935. Return Value:
  2936. None.
  2937. --*/
  2938. {
  2939. PKSEVENT_ITEM CurrentEventId;
  2940. PKSEVENT_SET CurrentEvent;
  2941. ULONG i,
  2942. j;
  2943. PAGED_CODE();
  2944. //
  2945. // walk the minidriver's event info to fill in the dispatch
  2946. // vectors as appropriate.
  2947. //
  2948. CurrentEvent = MinidriverEvents;
  2949. for (i = 0; i < NumEvents; i++) {
  2950. CurrentEventId = (PKSEVENT_ITEM) CurrentEvent->EventItem;
  2951. for (j = 0; j < CurrentEvent->EventsCount; j++) {
  2952. if (Stream) {
  2953. //
  2954. // set up the add and remove handlers for the stream.
  2955. // GUBGUB - Still not see justifications.
  2956. // don't support IsSupported currently, until
  2957. // a good justification of it is made.
  2958. //
  2959. CurrentEventId->AddHandler = StreamClassEnableEventHandler;
  2960. CurrentEventId->RemoveHandler = StreamClassDisableEventHandler;
  2961. } else {
  2962. //
  2963. // set up the add and remove handlers for the device.
  2964. // GUBGUB - still not see justifications
  2965. // - don't support IsSupported currently, until
  2966. // a good justification of it is made.
  2967. //
  2968. CurrentEventId->AddHandler = StreamClassEnableDeviceEventHandler;
  2969. CurrentEventId->RemoveHandler = StreamClassDisableDeviceEventHandler;
  2970. } // if stream
  2971. //
  2972. // index to next property item in
  2973. // array
  2974. //
  2975. CurrentEventId++;
  2976. } // for number of event items
  2977. //
  2978. // index to next event set in array
  2979. //
  2980. CurrentEvent++;
  2981. } // for number of event sets
  2982. }
  2983. VOID
  2984. SCReadRegistryValues(IN PDEVICE_EXTENSION DeviceExtension,
  2985. IN PDEVICE_OBJECT PhysicalDeviceObject
  2986. )
  2987. /*++
  2988. Routine Description:
  2989. Reads all registry values for the device
  2990. Arguments:
  2991. DeviceExtension - pointer to the device extension
  2992. PhysicalDeviceObject - pointer to the PDO
  2993. Return Value:
  2994. None.
  2995. --*/
  2996. {
  2997. ULONG i;
  2998. NTSTATUS Status;
  2999. HANDLE handle;
  3000. ULONG DataBuffer;
  3001. PAGED_CODE();
  3002. Status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  3003. PLUGPLAY_REGKEY_DRIVER,
  3004. STANDARD_RIGHTS_ALL,
  3005. &handle);
  3006. //
  3007. // loop through our table of strings,
  3008. // reading the registry for each.
  3009. //
  3010. if (NT_SUCCESS(Status)) {
  3011. for (i = 0; i < SIZEOF_ARRAY(RegistrySettings); i++) {
  3012. //
  3013. // read the registry value and set
  3014. // the flag if the setting is true.
  3015. //
  3016. //
  3017. // Need to init each time besides
  3018. // we only obtain one byte in the DataBuffer
  3019. //
  3020. DataBuffer = 0;
  3021. Status = SCGetRegistryValue(handle,
  3022. RegistrySettings[i].String,
  3023. RegistrySettings[i].StringLength,
  3024. &DataBuffer,
  3025. 1);
  3026. DebugPrint((DebugLevelInfo,
  3027. "Reg Key %S value %x\n",
  3028. RegistrySettings[i].String,
  3029. (BYTE)DataBuffer));
  3030. if ((NT_SUCCESS(Status)) && DataBuffer) {
  3031. //
  3032. // setting is true, so or in the
  3033. // appropriate flag
  3034. //
  3035. DeviceExtension->RegistryFlags |= RegistrySettings[i].Flags;
  3036. } // if true
  3037. } // while strings
  3038. DebugPrint((DebugLevelInfo,"====DeviceObject %x DeviceExtenion %x has RegFlags %x\n",
  3039. DeviceExtension->DeviceObject,
  3040. DeviceExtension,
  3041. DeviceExtension->RegistryFlags ));
  3042. //
  3043. // close the registry handle.
  3044. //
  3045. ZwClose(handle);
  3046. } // status = success
  3047. }
  3048. NTSTATUS
  3049. SCGetRegistryValue(
  3050. IN HANDLE Handle,
  3051. IN PWCHAR KeyNameString,
  3052. IN ULONG KeyNameStringLength,
  3053. IN PVOID Data,
  3054. IN ULONG DataLength
  3055. )
  3056. /*++
  3057. Routine Description:
  3058. Reads the specified registry value
  3059. Arguments:
  3060. Handle - handle to the registry key
  3061. KeyNameString - value to read
  3062. KeyNameStringLength - length of string
  3063. Data - buffer to read data into
  3064. DataLength - length of data buffer
  3065. Return Value:
  3066. NTSTATUS returned as appropriate
  3067. --*/
  3068. {
  3069. NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  3070. UNICODE_STRING KeyName;
  3071. ULONG Length;
  3072. PKEY_VALUE_FULL_INFORMATION FullInfo;
  3073. PAGED_CODE();
  3074. RtlInitUnicodeString(&KeyName, KeyNameString);
  3075. Length = sizeof(KEY_VALUE_FULL_INFORMATION) +
  3076. KeyNameStringLength + DataLength;
  3077. FullInfo = ExAllocatePool(PagedPool, Length);
  3078. if (FullInfo) {
  3079. Status = ZwQueryValueKey(Handle,
  3080. &KeyName,
  3081. KeyValueFullInformation,
  3082. FullInfo,
  3083. Length,
  3084. &Length);
  3085. if (NT_SUCCESS(Status)) {
  3086. if (DataLength >= FullInfo->DataLength) {
  3087. RtlCopyMemory(Data, ((PUCHAR) FullInfo) + FullInfo->DataOffset, FullInfo->DataLength);
  3088. } else {
  3089. Status = STATUS_BUFFER_TOO_SMALL;
  3090. } // buffer right length
  3091. } // if success
  3092. ExFreePool(FullInfo);
  3093. } // if fullinfo
  3094. return Status;
  3095. }
  3096. NTSTATUS
  3097. SCReferenceSwEnumDriver(
  3098. IN PDEVICE_EXTENSION DeviceExtension,
  3099. IN BOOLEAN Reference // AddRef or DeRef
  3100. )
  3101. /*++
  3102. Routine Description:
  3103. This routine shows one more reference to the minidriver, and pages
  3104. in the minidriver if the count was zero
  3105. Arguments:
  3106. DeviceExtension - pointer to device extension
  3107. Return Value:
  3108. none.
  3109. --*/
  3110. {
  3111. NTSTATUS Status;
  3112. KEVENT Event;
  3113. IO_STATUS_BLOCK IoStatusBlock;
  3114. PIRP Irp;
  3115. PIO_STACK_LOCATION IrpStackNext;
  3116. PBUS_INTERFACE_REFERENCE BusInterface;
  3117. PMINIDRIVER_INFORMATION MinidriverInfo = DeviceExtension->DriverInfo;
  3118. PAGED_CODE();
  3119. BusInterface = ExAllocatePool(NonPagedPool,
  3120. sizeof(BUS_INTERFACE_REFERENCE));
  3121. if (BusInterface == NULL)
  3122. {
  3123. return STATUS_INSUFFICIENT_RESOURCES;
  3124. }
  3125. //
  3126. // There is no file object associated with this Irp, so the event may be located
  3127. // on the stack as a non-object manager object.
  3128. //
  3129. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  3130. Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  3131. DeviceExtension->AttachedPdo,
  3132. NULL,
  3133. 0,
  3134. NULL,
  3135. &Event,
  3136. &IoStatusBlock);
  3137. if (Irp != NULL)
  3138. {
  3139. Irp->RequestorMode = KernelMode;
  3140. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  3141. IrpStackNext = IoGetNextIrpStackLocation(Irp);
  3142. //
  3143. // Create an interface query out of the Irp.
  3144. //
  3145. IrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE;
  3146. IrpStackNext->Parameters.QueryInterface.InterfaceType = (GUID*)&REFERENCE_BUS_INTERFACE;
  3147. IrpStackNext->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_REFERENCE);
  3148. IrpStackNext->Parameters.QueryInterface.Version = BUS_INTERFACE_REFERENCE_VERSION;
  3149. IrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
  3150. IrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  3151. Status = IoCallDriver(DeviceExtension->AttachedPdo, Irp);
  3152. if (Status == STATUS_PENDING)
  3153. {
  3154. //
  3155. // This waits using KernelMode, so that the stack, and therefore the
  3156. // event on that stack, is not paged out.
  3157. //
  3158. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  3159. Status = IoStatusBlock.Status;
  3160. }
  3161. }
  3162. else
  3163. {
  3164. Status = STATUS_INSUFFICIENT_RESOURCES;
  3165. }
  3166. if (Status == STATUS_SUCCESS)
  3167. {
  3168. if (Reference)
  3169. BusInterface->ReferenceDeviceObject(BusInterface->Interface.Context);
  3170. else
  3171. BusInterface->DereferenceDeviceObject(BusInterface->Interface.Context);
  3172. }
  3173. ExFreePool(BusInterface);
  3174. return Status;
  3175. }
  3176. VOID
  3177. SCDereferenceDriver(
  3178. IN PDEVICE_EXTENSION DeviceExtension
  3179. )
  3180. /*++
  3181. Routine Description:
  3182. This routine shows one fewer reference to the minidriver, and pages
  3183. out the minidriver if the count goes to zero
  3184. Arguments:
  3185. DeviceExtension - pointer to device extension
  3186. Return Value:
  3187. none.
  3188. --*/
  3189. {
  3190. PMINIDRIVER_INFORMATION MinidriverInfo;
  3191. PDEVICE_EXTENSION CurrentDeviceExtension;
  3192. BOOLEAN RequestIssued,
  3193. DontPage = FALSE;
  3194. KEVENT Event;
  3195. IO_STATUS_BLOCK IoStatusBlock;
  3196. PIRP Irp;
  3197. PDEVICE_OBJECT DeviceObject;
  3198. NTSTATUS Status;
  3199. PAGED_CODE();
  3200. //
  3201. // if the driver said it was a SWENUM driver, dereference it.
  3202. //
  3203. if (DeviceExtension->RegistryFlags & DRIVER_USES_SWENUM_TO_LOAD)
  3204. {
  3205. SCReferenceSwEnumDriver(DeviceExtension,FALSE);
  3206. }
  3207. MinidriverInfo = IoGetDriverObjectExtension(DeviceExtension->DeviceObject->DriverObject,
  3208. (PVOID) StreamClassPnP);
  3209. DebugPrint(( DebugLevelVerbose,
  3210. "DerefernceDriver %x Count %x DriverFlags=%x\n",
  3211. DeviceExtension->DeviceObject->DriverObject,
  3212. MinidriverInfo->UseCount, MinidriverInfo->Flags));
  3213. if (!(MinidriverInfo->Flags & DRIVER_FLAGS_NO_PAGEOUT)) {
  3214. KeWaitForSingleObject(&MinidriverInfo->ControlEvent,
  3215. Executive,
  3216. KernelMode,
  3217. FALSE, // not alertable
  3218. NULL);
  3219. //
  3220. // dec the refcount and see if we can page out.
  3221. //
  3222. DebugPrint(( DebugLevelVerbose,
  3223. "DerefernceDriver CountDown\n"));
  3224. ASSERT((LONG) MinidriverInfo->UseCount > 0);
  3225. if (!(--MinidriverInfo->UseCount)) {
  3226. //
  3227. // page out the minidriver after alerting it that we are going to.
  3228. // PNP is supposed to be serialized, so there should be
  3229. // no need to protect this list. I'm worried about this, tho.
  3230. // need to research.
  3231. // My unstderstanding is that PnP is serialized.
  3232. //
  3233. // This is by-design, not a bug.
  3234. // This code assumes that the minidriver will bind only
  3235. // with the stream class. this needs to be doc'ed in the spec
  3236. // that only single binders will be able to use autopage.
  3237. //
  3238. //
  3239. // find the first device object chained to the driver object.
  3240. //
  3241. DeviceObject = DeviceExtension->DeviceObject->DriverObject->DeviceObject;
  3242. while (DeviceObject) {
  3243. CurrentDeviceExtension = DeviceObject->DeviceExtension;
  3244. DebugPrint((DebugLevelVerbose,
  3245. "DerefernceDriver Checking Device=%x\n",
  3246. DeviceObject));
  3247. //
  3248. // if the device is not started, don't call the minidriver
  3249. // also don't process a child device
  3250. //
  3251. if ((CurrentDeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) &&
  3252. (!(CurrentDeviceExtension->Flags & DEVICE_FLAGS_CHILD))) {
  3253. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  3254. //
  3255. // allocate IRP for issuing the pageout. Since this IRP
  3256. // should not really be referenced, use dummy IOCTL code.
  3257. // I chose this one since it will always fail in the KS
  3258. // property handler if someone is silly enough to try to
  3259. // process it. Also make the irp internal i/o control.
  3260. //
  3261. // IoVerifier.c test code does not check IrpStack bound like
  3262. // the formal production code. And the owner does not want to
  3263. // fix it. It's more productive just work around here.
  3264. //Irp = IoBuildDeviceIoControlRequest(
  3265. // IOCTL_KS_PROPERTY,
  3266. // DeviceObject,
  3267. // NULL,
  3268. // 0,
  3269. // NULL,
  3270. // 0,
  3271. // TRUE,
  3272. // &Event,
  3273. // &IoStatusBlock);
  3274. Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  3275. if (!Irp) {
  3276. //
  3277. // could not allocate IRP. don't page out.
  3278. //
  3279. DontPage = TRUE;
  3280. break;
  3281. }
  3282. else {
  3283. PIO_STACK_LOCATION NextStack;
  3284. //
  3285. // This is a dummy Irp, the MJ/MN are arbitrary
  3286. //
  3287. NextStack = IoGetNextIrpStackLocation(Irp);
  3288. ASSERT(NextStack != NULL);
  3289. NextStack->MajorFunction = IRP_MJ_PNP;
  3290. NextStack->MinorFunction = IRP_MN_CANCEL_STOP_DEVICE;
  3291. Irp->UserIosb = &IoStatusBlock;
  3292. Irp->UserEvent = &Event;
  3293. }
  3294. //
  3295. // show one more I/O pending on the device.
  3296. //
  3297. DebugPrint((DebugLevelVerbose,
  3298. "Sending SRB_PAGING_OUT_DRIVER to Device=%x\n",
  3299. DeviceObject));
  3300. InterlockedIncrement(&CurrentDeviceExtension->OneBasedIoCount);
  3301. Status = SCSubmitRequest(SRB_PAGING_OUT_DRIVER,
  3302. (PVOID) NULL,
  3303. 0,
  3304. SCProcessCompletedRequest,
  3305. CurrentDeviceExtension,
  3306. NULL,
  3307. NULL,
  3308. Irp,
  3309. &RequestIssued,
  3310. &CurrentDeviceExtension->PendingQueue,
  3311. (PVOID) CurrentDeviceExtension->
  3312. MinidriverData->HwInitData.
  3313. HwReceivePacket
  3314. );
  3315. if (!RequestIssued) {
  3316. //
  3317. // could not issue SRB. complete IRP and don't page
  3318. // out.
  3319. //
  3320. DontPage = TRUE;
  3321. SCCompleteIrp(Irp, Status, CurrentDeviceExtension);
  3322. break;
  3323. } // if ! requestissued
  3324. //
  3325. // check status. note that we do not check for pending,
  3326. // since the above call is sync and won't return til the
  3327. // request is complete.
  3328. //
  3329. if (!NT_SUCCESS(Status)) {
  3330. //
  3331. // if the minidriver did not OK the pageout, don't
  3332. // page
  3333. // out.
  3334. //
  3335. DontPage = TRUE;
  3336. break;
  3337. } // if !success
  3338. } // if started
  3339. DeviceObject = DeviceObject->NextDevice;
  3340. } // while deviceobject
  3341. //
  3342. // if we were able to alert each device controlled by the driver
  3343. // that a pageout is emminent, page the driver out.
  3344. //
  3345. if (!DontPage) {
  3346. DebugPrint((DebugLevelVerbose,
  3347. "mmPageEntireDriver %x\n",
  3348. DeviceExtension->DeviceObject->DriverObject));
  3349. MinidriverInfo->Flags |= DRIVER_FLAGS_PAGED_OUT;
  3350. MmPageEntireDriver(MinidriverInfo->HwInitData.HwReceivePacket);
  3351. } // if ! dontpage
  3352. } // if !usecount
  3353. //
  3354. // release the control event.
  3355. //
  3356. KeSetEvent(&MinidriverInfo->ControlEvent, IO_NO_INCREMENT, FALSE);
  3357. } // if pageable
  3358. }
  3359. VOID
  3360. SCReferenceDriver(
  3361. IN PDEVICE_EXTENSION DeviceExtension
  3362. )
  3363. /*++
  3364. Routine Description:
  3365. This routine shows one more reference to the minidriver, and pages
  3366. in the minidriver if the count was zero
  3367. Arguments:
  3368. DeviceExtension - pointer to device extension
  3369. Return Value:
  3370. none.
  3371. --*/
  3372. {
  3373. PMINIDRIVER_INFORMATION MinidriverInfo = DeviceExtension->DriverInfo;
  3374. PAGED_CODE();
  3375. //
  3376. // if the driver said it was a SWENUM driver, reference it.
  3377. //
  3378. if (DeviceExtension->RegistryFlags & DRIVER_USES_SWENUM_TO_LOAD)
  3379. {
  3380. SCReferenceSwEnumDriver(DeviceExtension,TRUE);
  3381. }
  3382. DebugPrint(( DebugLevelVerbose,
  3383. "ReferenceDriver %x Count %x DriverFlags=%x\n",
  3384. DeviceExtension->DeviceObject->DriverObject,
  3385. MinidriverInfo->UseCount, MinidriverInfo->Flags));
  3386. if (!(MinidriverInfo->Flags & DRIVER_FLAGS_NO_PAGEOUT)) {
  3387. KeWaitForSingleObject(&MinidriverInfo->ControlEvent,
  3388. Executive,
  3389. KernelMode,
  3390. FALSE, // not alertable
  3391. NULL);
  3392. DebugPrint(( DebugLevelVerbose,
  3393. "RefernceDriver Countup\n"));
  3394. //
  3395. // inc the refcount and see if we
  3396. // need to page in.
  3397. //
  3398. ASSERT((LONG) MinidriverInfo->UseCount >= 0);
  3399. if (!(MinidriverInfo->UseCount++)) {
  3400. //
  3401. // page in the minidriver
  3402. //
  3403. MmResetDriverPaging(MinidriverInfo->HwInitData.HwReceivePacket);
  3404. MinidriverInfo->Flags &= ~(DRIVER_FLAGS_PAGED_OUT);
  3405. } // if !usecount
  3406. KeSetEvent(&MinidriverInfo->ControlEvent, IO_NO_INCREMENT, FALSE);
  3407. } // if pageable
  3408. }
  3409. VOID
  3410. SCInsertStreamInFilter(
  3411. IN PSTREAM_OBJECT StreamObject,
  3412. IN PDEVICE_EXTENSION DeviceExtension
  3413. )
  3414. /*++
  3415. Routine Description:
  3416. Inserts a new stream in the stream queue on the filter instance
  3417. Arguments:
  3418. StreamObject = pointer to stream object
  3419. Return Value:
  3420. none.
  3421. --*/
  3422. {
  3423. KIRQL Irql;
  3424. //
  3425. // insert the stream object in the filter
  3426. // instance list
  3427. //
  3428. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3429. InsertHeadList(&((PFILTER_INSTANCE) (StreamObject->FilterInstance))->
  3430. FirstStream,
  3431. &StreamObject->NextStream);
  3432. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  3433. return;
  3434. }
  3435. VOID
  3436. SCInsertFiltersInDevice(
  3437. IN PFILTER_INSTANCE FilterInstance,
  3438. IN PDEVICE_EXTENSION DeviceExtension
  3439. )
  3440. /*++
  3441. Routine Description:
  3442. Inserts a new filter in the device list at DPC level
  3443. Arguments:
  3444. Return Value:
  3445. none.
  3446. --*/
  3447. {
  3448. KIRQL Irql;
  3449. //
  3450. // insert the filter instance in the global list
  3451. //
  3452. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3453. InsertHeadList(
  3454. &DeviceExtension->FilterInstanceList,
  3455. &FilterInstance->NextFilterInstance);
  3456. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  3457. }
  3458. VOID
  3459. SCInterlockedRemoveEntryList(
  3460. PDEVICE_EXTENSION DeviceExtension,
  3461. PLIST_ENTRY List
  3462. )
  3463. /*++
  3464. Routine Description:
  3465. Removes the specified entry under spinlock
  3466. Arguments:
  3467. Return Value:
  3468. none.
  3469. --*/
  3470. {
  3471. KIRQL Irql;
  3472. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3473. RemoveEntryList(List);
  3474. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  3475. }
  3476. VOID
  3477. SCProcessTimerRequest(
  3478. IN PCOMMON_OBJECT CommonObject,
  3479. IN PINTERRUPT_DATA SavedInterruptData
  3480. )
  3481. /*++
  3482. Routine Description:
  3483. This routine handles a minidriver request to either set or clear a timer
  3484. Arguments:
  3485. CommonObject - pointer to common object
  3486. SavedInterruptData - captured interrupt data
  3487. Return Value:
  3488. none.
  3489. --*/
  3490. {
  3491. LARGE_INTEGER timeValue;
  3492. CommonObject->HwTimerRoutine =
  3493. SavedInterruptData->HwTimerRoutine;
  3494. CommonObject->HwTimerContext =
  3495. SavedInterruptData->HwTimerContext;
  3496. //
  3497. // The minidriver wants a timer request.
  3498. // If the requested timer value is zero,
  3499. // then cancel the timer.
  3500. //
  3501. if (SavedInterruptData->HwTimerValue == 0) {
  3502. KeCancelTimer(&CommonObject->MiniDriverTimer);
  3503. } else {
  3504. //
  3505. // Convert the timer value from
  3506. // microseconds to a negative
  3507. // 100
  3508. // nanoseconds.
  3509. //
  3510. // timeValue.QuadPart = Int32x32To64(
  3511. // SavedInterruptData->HwTimerValue,
  3512. // -10);
  3513. timeValue.LowPart = SavedInterruptData->HwTimerValue * -10;
  3514. timeValue.HighPart = -1;
  3515. //
  3516. // Set the timer.
  3517. //
  3518. KeSetTimer(&CommonObject->MiniDriverTimer,
  3519. timeValue,
  3520. &CommonObject->MiniDriverTimerDpc);
  3521. }
  3522. }
  3523. VOID
  3524. SCProcessPriorityChangeRequest(
  3525. IN PCOMMON_OBJECT CommonObject,
  3526. IN PINTERRUPT_DATA SavedInterruptData,
  3527. IN PDEVICE_EXTENSION DeviceExtension
  3528. )
  3529. /*++
  3530. Routine Description:
  3531. Routine handles priority change requests from the minidriver
  3532. Arguments:
  3533. CommonObject - pointer to common object
  3534. SavedInterruptData - captured interrupt data
  3535. DeviceExtension - pointer to device extension
  3536. Return Value:
  3537. none.
  3538. --*/
  3539. {
  3540. #if DBG
  3541. PDEBUG_WORK_ITEM DbgWorkItemStruct;
  3542. #endif
  3543. if (SavedInterruptData->HwPriorityLevel == Dispatch) {
  3544. DebugPrint((DebugLevelVerbose, "'SCDpc: Dispatch priority callout\n"));
  3545. //
  3546. // Acquire the device spinlock so
  3547. // nothing else starts.
  3548. //
  3549. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3550. //
  3551. // call the minidriver at dispatch
  3552. // level.
  3553. //
  3554. SavedInterruptData->HwPriorityRoutine(SavedInterruptData->HwPriorityContext);
  3555. if ((CommonObject->InterruptData.Flags &
  3556. INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST)
  3557. &&
  3558. (CommonObject->InterruptData.HwPriorityLevel == High)) {
  3559. DebugPrint((DebugLevelVerbose, "'SCDpc: High priority callout\n"));
  3560. //
  3561. // if the minidriver now wants a high priority callback,
  3562. // do so now. This is safe since we have the device
  3563. // spinlock and the minidriver cannot make
  3564. // another priority request for this stream while one is
  3565. // requested.
  3566. //
  3567. CommonObject->InterruptData.Flags &=
  3568. ~(INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST);
  3569. DeviceExtension->SynchronizeExecution(
  3570. DeviceExtension->InterruptObject,
  3571. (PVOID) CommonObject->InterruptData.HwPriorityRoutine,
  3572. CommonObject->InterruptData.HwPriorityContext);
  3573. } // if high requested
  3574. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3575. } else if (SavedInterruptData->HwPriorityLevel == Low) {
  3576. #if DBG
  3577. //
  3578. // make sure that the minidriver is not misusing this function.
  3579. //
  3580. if (DeviceExtension->NumberOfRequests > 0xFFFFFFF0) {
  3581. DeviceExtension->Flags |= DEVICE_FLAGS_PRI_WARN_GIVEN;
  3582. }
  3583. if ((++DeviceExtension->NumberOfLowPriCalls > 100) &&
  3584. ((DeviceExtension->NumberOfLowPriCalls) >
  3585. DeviceExtension->NumberOfRequests / 4) &&
  3586. (!(DeviceExtension->Flags & DEVICE_FLAGS_PRI_WARN_GIVEN))) {
  3587. DeviceExtension->Flags |= DEVICE_FLAGS_PRI_WARN_GIVEN;
  3588. DebugPrint((DebugLevelFatal, "Stream Class has determined that a minidriver is scheduling\n"));
  3589. DebugPrint((DebugLevelFatal, "a low priority callback for more than 25 percent of the requests\n"));
  3590. DebugPrint((DebugLevelFatal, "it has received. This driver should probably be setting the\n"));
  3591. DebugPrint((DebugLevelFatal, "TurnOffSynchronization boolean and doing its own synchronization.\n"));
  3592. DebugPrint((DebugLevelFatal, "Please open a bug against the dev owner of this minidriver.\n"));
  3593. DebugPrint((DebugLevelFatal, "Do an LN of %x to determine the name of the minidriver.\n", SavedInterruptData->HwPriorityRoutine));
  3594. TRAP;
  3595. } // if bad pri
  3596. if (CommonObject->InterruptData.Flags &
  3597. INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST) {
  3598. DebugPrint((DebugLevelFatal, "Stream Minidriver scheduled priority twice!\n"));
  3599. ASSERT(1 == 0);
  3600. } // if scheduled twice
  3601. DbgWorkItemStruct = ExAllocatePool(NonPagedPool, sizeof(DEBUG_WORK_ITEM));
  3602. // DebugPrint((DebugLevelFatal, "A %x\n", DbgWorkItemStruct));
  3603. if (DbgWorkItemStruct) {
  3604. DbgWorkItemStruct->HwPriorityRoutine = SavedInterruptData->HwPriorityRoutine;
  3605. DbgWorkItemStruct->HwPriorityContext = SavedInterruptData->HwPriorityContext;
  3606. DbgWorkItemStruct->Object = CommonObject;
  3607. ExInitializeWorkItem(&CommonObject->WorkItem,
  3608. SCDebugPriorityWorkItem,
  3609. DbgWorkItemStruct);
  3610. } else {
  3611. ExInitializeWorkItem(&CommonObject->WorkItem,
  3612. SavedInterruptData->HwPriorityRoutine,
  3613. SavedInterruptData->HwPriorityContext);
  3614. }
  3615. #else
  3616. ExInitializeWorkItem(&CommonObject->WorkItem,
  3617. SavedInterruptData->HwPriorityRoutine,
  3618. SavedInterruptData->HwPriorityContext);
  3619. #endif
  3620. ExQueueWorkItem(&CommonObject->WorkItem,
  3621. DelayedWorkQueue);
  3622. } // if priority
  3623. }
  3624. VOID
  3625. SCBeginSynchronizedMinidriverCallin(
  3626. IN PDEVICE_EXTENSION DeviceExtension,
  3627. IN PKIRQL Irql)
  3628. /*++
  3629. Routine Description:
  3630. This routine handles begin processing of a synchronized minidriver callin
  3631. Arguments:
  3632. DeviceExtension - pointer to the device extension
  3633. Irql - POINTER to a KIRQL structure
  3634. Return Value:
  3635. none.
  3636. --*/
  3637. {
  3638. return;
  3639. }
  3640. VOID
  3641. SCBeginUnsynchronizedMinidriverCallin(
  3642. IN PDEVICE_EXTENSION DeviceExtension,
  3643. IN PKIRQL Irql)
  3644. /*++
  3645. Routine Description:
  3646. This routine handles begin processing of an unsynchronized minidriver callin
  3647. Arguments:
  3648. DeviceExtension - pointer to the device extension
  3649. Irql - POINTER to a KIRQL structure
  3650. Return Value:
  3651. none.
  3652. --*/
  3653. {
  3654. KeAcquireSpinLock(&DeviceExtension->SpinLock, Irql);
  3655. \
  3656. return;
  3657. }
  3658. VOID
  3659. SCEndSynchronizedMinidriverStreamCallin(
  3660. IN PSTREAM_OBJECT StreamObject,
  3661. IN PKIRQL Irql)
  3662. /*++
  3663. Routine Description:
  3664. This routine handles end processing of a synchronized minidriver
  3665. stream callin
  3666. Arguments:
  3667. DeviceExtension - pointer to the device extension
  3668. Irql - POINTER to a KIRQL structure
  3669. Return Value:
  3670. none.
  3671. --*/
  3672. {
  3673. SCRequestDpcForStream(StreamObject);
  3674. return;
  3675. }
  3676. VOID
  3677. SCEndSynchronizedMinidriverDeviceCallin(
  3678. IN PDEVICE_EXTENSION DeviceExtension,
  3679. IN PKIRQL Irql)
  3680. /*++
  3681. Routine Description:
  3682. This routine handles end processing of a synchronized minidriver
  3683. device callin
  3684. Arguments:
  3685. DeviceExtension - pointer to the device extension
  3686. Irql - POINTER to a KIRQL structure
  3687. Return Value:
  3688. none.
  3689. --*/
  3690. {
  3691. DeviceExtension->ComObj.InterruptData.Flags |= INTERRUPT_FLAGS_NOTIFICATION_REQUIRED;
  3692. return;
  3693. }
  3694. VOID
  3695. SCEndUnsynchronizedMinidriverDeviceCallin(
  3696. IN PDEVICE_EXTENSION DeviceExtension,
  3697. IN PKIRQL Irql)
  3698. /*++
  3699. Routine Description:
  3700. This routine handles end processing of an unsynchronized minidriver
  3701. device callin
  3702. Arguments:
  3703. DeviceExtension - pointer to the device extension
  3704. Irql - POINTER to a KIRQL structure
  3705. Return Value:
  3706. none.
  3707. --*/
  3708. {
  3709. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3710. DeviceExtension->ComObj.InterruptData.Flags |= INTERRUPT_FLAGS_NOTIFICATION_REQUIRED;
  3711. StreamClassDpc(NULL,
  3712. DeviceExtension->DeviceObject,
  3713. NULL,
  3714. NULL);
  3715. KeLowerIrql(*Irql);
  3716. return;
  3717. }
  3718. VOID
  3719. SCEndUnsynchronizedMinidriverStreamCallin(
  3720. IN PSTREAM_OBJECT StreamObject,
  3721. IN PKIRQL Irql)
  3722. /*++
  3723. Routine Description:
  3724. This routine handles end processing of an unsynchronized minidriver
  3725. stream callin
  3726. Arguments:
  3727. DeviceExtension - pointer to the device extension
  3728. Irql - POINTER to a KIRQL structure
  3729. Return Value:
  3730. none.
  3731. --*/
  3732. {
  3733. KeReleaseSpinLockFromDpcLevel(&StreamObject->DeviceExtension->SpinLock);
  3734. SCRequestDpcForStream(StreamObject);
  3735. StreamClassDpc(NULL,
  3736. StreamObject->DeviceExtension->DeviceObject,
  3737. NULL,
  3738. StreamObject);
  3739. KeLowerIrql(*Irql);
  3740. return;
  3741. }
  3742. VOID
  3743. SCCheckPoweredUp(
  3744. IN PDEVICE_EXTENSION DeviceExtension
  3745. )
  3746. /*++
  3747. Routine Description:
  3748. This routine powers up the HW if necessary
  3749. Arguments:
  3750. DeviceExtension - pointer to the device extension
  3751. Return Value:
  3752. none.
  3753. --*/
  3754. {
  3755. NTSTATUS Status;
  3756. POWER_STATE PowerState;
  3757. POWER_CONTEXT PowerContext;
  3758. PAGED_CODE();
  3759. //
  3760. // check to see if we are powered down
  3761. //
  3762. if (DeviceExtension->RegistryFlags & DEVICE_REG_FL_POWER_DOWN_CLOSED) {
  3763. while (DeviceExtension->CurrentPowerState != PowerDeviceD0) {
  3764. //
  3765. // release the event to avoid deadlocks with the power up code.
  3766. //
  3767. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  3768. //
  3769. // tell the power manager to power up the device.
  3770. //
  3771. PowerState.DeviceState = PowerDeviceD0;
  3772. //
  3773. // now send down a set power based on this info.
  3774. //
  3775. KeInitializeEvent(&PowerContext.Event, NotificationEvent, FALSE);
  3776. Status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
  3777. IRP_MN_SET_POWER,
  3778. PowerState,
  3779. SCBustedSynchPowerCompletionRoutine,
  3780. &PowerContext,
  3781. NULL);
  3782. if (Status == STATUS_PENDING) {
  3783. //
  3784. // wait for the IRP to complete
  3785. //
  3786. KeWaitForSingleObject(
  3787. &PowerContext.Event,
  3788. Suspended,
  3789. KernelMode,
  3790. FALSE,
  3791. NULL);
  3792. }
  3793. //
  3794. // reacquire the event and loop if good status. The only reason
  3795. // we would get a good status here is if the HW powered up, but
  3796. // some
  3797. // policy maker instantly powered it down again. This should
  3798. // never
  3799. // happen more than once, but if it does this thread could be
  3800. // stuck.
  3801. //
  3802. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  3803. Executive,
  3804. KernelMode,
  3805. FALSE, // not alertable
  3806. NULL);
  3807. if (!NT_SUCCESS(PowerContext.Status)) {
  3808. //
  3809. // if we could not power up, go ahead and let the request go
  3810. // through. The worst that will happen is that the request
  3811. // will fail at the HW level.
  3812. //
  3813. break;
  3814. }
  3815. }
  3816. } // if power down when closed
  3817. return;
  3818. }
  3819. VOID
  3820. SCCheckPowerDown(
  3821. IN PDEVICE_EXTENSION DeviceExtension
  3822. )
  3823. /*++
  3824. Routine Description:
  3825. This routine powers down the hardware if possible
  3826. Arguments:
  3827. DeviceExtension - pointer to the device extension
  3828. Return Value:
  3829. none.
  3830. --*/
  3831. {
  3832. NTSTATUS Status;
  3833. POWER_STATE PowerState;
  3834. POWER_CONTEXT PowerContext;
  3835. PAGED_CODE();
  3836. //
  3837. // only power down if there are not open files
  3838. //
  3839. if (DeviceExtension->RegistryFlags & DEVICE_REG_FL_POWER_DOWN_CLOSED) {
  3840. if (!DeviceExtension->NumberOfOpenInstances) {
  3841. //
  3842. // release the event to avoid deadlocks with the power up code.
  3843. //
  3844. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  3845. //
  3846. // tell the power manager to power down the device.
  3847. //
  3848. PowerState.DeviceState = PowerDeviceD3;
  3849. //
  3850. // now send down a set power based on this info.
  3851. //
  3852. KeInitializeEvent(&PowerContext.Event, NotificationEvent, FALSE);
  3853. Status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
  3854. IRP_MN_SET_POWER,
  3855. PowerState,
  3856. SCBustedSynchPowerCompletionRoutine,
  3857. &PowerContext,
  3858. NULL);
  3859. if (Status == STATUS_PENDING) {
  3860. //
  3861. // wait for the IRP to complete
  3862. //
  3863. KeWaitForSingleObject(
  3864. &PowerContext.Event,
  3865. Suspended,
  3866. KernelMode,
  3867. FALSE,
  3868. NULL);
  3869. }
  3870. //
  3871. // reacquire the event.
  3872. //
  3873. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  3874. Executive,
  3875. KernelMode,
  3876. FALSE, // not alertable
  3877. NULL);
  3878. }
  3879. } // if power down closed
  3880. return;
  3881. }
  3882. VOID
  3883. SCWaitForOutstandingIo(
  3884. IN PDEVICE_EXTENSION DeviceExtension
  3885. )
  3886. /*++
  3887. Routine Description:
  3888. This routine decs the one based I/O counter and blocks until the counter
  3889. goes to zero.
  3890. Arguments:
  3891. DeviceExtension - pointer to the device extension
  3892. Return Value:
  3893. none.
  3894. --*/
  3895. {
  3896. KIRQL Irql;
  3897. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3898. DeviceExtension->Flags |= DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  3899. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  3900. if (InterlockedDecrement(&DeviceExtension->OneBasedIoCount)) {
  3901. #ifdef wecandothis
  3902. PFILTER_INSTANCE FilterInstance;
  3903. KIRQL Irql;
  3904. PLIST_ENTRY FilterEntry,
  3905. FilterListEntry;
  3906. //
  3907. // there is I/O outstanding. Cancel all outstanding IRP's.
  3908. //
  3909. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3910. checkfilters:
  3911. FilterInstance = DeviceExtension->GlobalFilterInstance;
  3912. if (FilterInstance) {
  3913. if (SCCheckFilterInstanceStreamsForIrp(FilterInstance, NULL)) {
  3914. DebugPrint((DebugLevelWarning, "'SCCancelPending: found Irp on global instance\n"));
  3915. //
  3916. // we found one. jump back to loop back through since the
  3917. // spinlock
  3918. // had to be released and reaquired to cancel the irp.
  3919. //
  3920. goto checkfilters;
  3921. }
  3922. }
  3923. FilterListEntry = FilterEntry = &DeviceExtension->FilterInstanceList;
  3924. while (FilterEntry->Flink != FilterListEntry->Blink) {
  3925. FilterEntry = FilterEntry->Flink;
  3926. //
  3927. // follow the link to the instance
  3928. //
  3929. FilterInstance = CONTAINING_RECORD(FilterListEntry,
  3930. FILTER_INSTANCE,
  3931. NextFilterInstance);
  3932. //
  3933. // process the streams on this list
  3934. //
  3935. if (SCCheckFilterInstanceStreamsForIrp(FilterInstance, NULL)) {
  3936. //
  3937. // we found one. jump back to loop back through since the
  3938. // spinlock
  3939. // had to be released and reaquired to cancel the irp.
  3940. //
  3941. goto checkfilters;
  3942. }
  3943. //
  3944. // get the list entry for this instance
  3945. //
  3946. FilterListEntry = &FilterInstance->NextFilterInstance;
  3947. }
  3948. //
  3949. // now process any requests on the device itself
  3950. //
  3951. while (SCCheckRequestsForIrp(
  3952. &DeviceExtension->OutstandingQueue, NULL, TRUE, DeviceExtension)) {
  3953. }
  3954. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  3955. #endif
  3956. //
  3957. // Block on the removal event which is signaled as the last I/O
  3958. // completes.
  3959. //
  3960. KeWaitForSingleObject(&DeviceExtension->RemoveEvent,
  3961. Executive,
  3962. KernelMode,
  3963. FALSE, // not alertable
  3964. NULL);
  3965. }
  3966. //
  3967. // restore the counter to 1-based, since we've now assured that all
  3968. // I/O to the device has completed.
  3969. //
  3970. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  3971. return;
  3972. }
  3973. NTSTATUS
  3974. SCShowIoPending(
  3975. IN PDEVICE_EXTENSION DeviceExtension,
  3976. IN PIRP Irp
  3977. )
  3978. /*++
  3979. Routine Description:
  3980. This routine shows that one more I/O is outstanding, or errors the I/O
  3981. if the device is inaccessible.
  3982. Arguments:
  3983. DeviceExtension - pointer to device extension
  3984. Irp - pointer to IRP
  3985. Return Value:
  3986. TRUE if I/O can be submitted.
  3987. --*/
  3988. {
  3989. PAGED_CODE();
  3990. //
  3991. // assume that the device is accessible and show one more request.
  3992. // if it's not accessible, we'll show one less. do it in this order
  3993. // to prevent a race where the inaccessible flag has been set, but the
  3994. // the i/o count has not been dec'd yet.
  3995. //
  3996. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  3997. if (DeviceExtension->Flags & DEVICE_FLAGS_DEVICE_INACCESSIBLE) {
  3998. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  3999. InterlockedDecrement(&DeviceExtension->OneBasedIoCount);
  4000. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  4001. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4002. return (Status);
  4003. }
  4004. return (STATUS_SUCCESS);
  4005. }
  4006. NTSTATUS
  4007. SCCallNextDriver(
  4008. IN PDEVICE_EXTENSION DeviceExtension,
  4009. IN PIRP Irp
  4010. )
  4011. /*++
  4012. Routine Description:
  4013. Arguments:
  4014. DeviceExtension - pointer to device extension
  4015. Irp - pointer to IRP
  4016. Return Value:
  4017. none.
  4018. --*/
  4019. {
  4020. KEVENT Event;
  4021. PIO_STACK_LOCATION IrpStack,
  4022. NextStack;
  4023. NTSTATUS Status;
  4024. PAGED_CODE();
  4025. if ( NULL == DeviceExtension->AttachedPdo ) {
  4026. //
  4027. // DO has been detached, return success directly.
  4028. //
  4029. return STATUS_SUCCESS;
  4030. }
  4031. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  4032. NextStack = IoGetNextIrpStackLocation(Irp);
  4033. ASSERT(NextStack != NULL);
  4034. RtlCopyMemory(NextStack, IrpStack, sizeof(IO_STACK_LOCATION));
  4035. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  4036. IoSetCompletionRoutine(Irp,
  4037. SCSynchCompletionRoutine,
  4038. &Event,
  4039. TRUE,
  4040. TRUE,
  4041. TRUE);
  4042. if ( IRP_MJ_POWER != IrpStack->MajorFunction ) {
  4043. Status = IoCallDriver(DeviceExtension->AttachedPdo, Irp);
  4044. } else {
  4045. //
  4046. // power Irp, use PoCallDriver()
  4047. //
  4048. Status = PoCallDriver( DeviceExtension->AttachedPdo, Irp );
  4049. }
  4050. if (Status == STATUS_PENDING) {
  4051. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  4052. Status = Irp->IoStatus.Status;
  4053. }
  4054. return (Status);
  4055. }
  4056. VOID
  4057. SCMinidriverTimeFunction(
  4058. IN PHW_TIME_CONTEXT TimeContext
  4059. )
  4060. /*++
  4061. Routine Description:
  4062. Arguments:
  4063. Return Value:
  4064. Notes:
  4065. --*/
  4066. {
  4067. PDEVICE_EXTENSION DeviceExtension =
  4068. (PDEVICE_EXTENSION) TimeContext->HwDeviceExtension - 1;
  4069. KIRQL Irql;
  4070. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  4071. TimeContext->HwStreamObject,
  4072. STREAM_OBJECT,
  4073. HwStreamObject);
  4074. //
  4075. // call the minidriver to process the time function
  4076. //
  4077. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  4078. DeviceExtension->SynchronizeExecution(
  4079. DeviceExtension->InterruptObject,
  4080. (PVOID) StreamObject->
  4081. HwStreamObject.HwClockObject.HwClockFunction,
  4082. TimeContext);
  4083. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  4084. }
  4085. ULONGLONG
  4086. SCGetStreamTime(
  4087. IN PFILE_OBJECT FileObject
  4088. )
  4089. /*++
  4090. Routine Description:
  4091. Arguments:
  4092. Return Value:
  4093. Notes:
  4094. --*/
  4095. {
  4096. HW_TIME_CONTEXT TimeContext;
  4097. PCLOCK_INSTANCE ClockInstance = (PCLOCK_INSTANCE) FileObject->FsContext;
  4098. TimeContext.HwStreamObject = &ClockInstance->StreamObject->HwStreamObject;
  4099. TimeContext.HwDeviceExtension = ClockInstance->StreamObject->
  4100. DeviceExtension->HwDeviceExtension;
  4101. TimeContext.Function = TIME_GET_STREAM_TIME;
  4102. SCMinidriverTimeFunction(&TimeContext);
  4103. return (TimeContext.Time);
  4104. }
  4105. ULONGLONG FASTCALL
  4106. SCGetPhysicalTime(
  4107. IN PFILE_OBJECT FileObject
  4108. )
  4109. /*++
  4110. Routine Description:
  4111. Arguments:
  4112. Return Value:
  4113. Notes:
  4114. --*/
  4115. {
  4116. HW_TIME_CONTEXT TimeContext;
  4117. PCLOCK_INSTANCE ClockInstance = (PCLOCK_INSTANCE) FileObject->FsContext;
  4118. TimeContext.HwStreamObject = &ClockInstance->StreamObject->HwStreamObject;
  4119. TimeContext.HwDeviceExtension = ClockInstance->StreamObject->
  4120. DeviceExtension->HwDeviceExtension;
  4121. TimeContext.Function = TIME_READ_ONBOARD_CLOCK;
  4122. SCMinidriverTimeFunction(&TimeContext);
  4123. return (TimeContext.Time);
  4124. }
  4125. ULONGLONG FASTCALL
  4126. SCGetSynchronizedTime(
  4127. IN PFILE_OBJECT FileObject,
  4128. IN PULONGLONG SystemTime
  4129. )
  4130. /*++
  4131. Routine Description:
  4132. Arguments:
  4133. Return Value:
  4134. Notes:
  4135. --*/
  4136. {
  4137. HW_TIME_CONTEXT TimeContext;
  4138. PCLOCK_INSTANCE ClockInstance = (PCLOCK_INSTANCE) FileObject->FsContext;
  4139. TimeContext.HwStreamObject = &ClockInstance->StreamObject->HwStreamObject;
  4140. TimeContext.HwDeviceExtension = ClockInstance->StreamObject->
  4141. DeviceExtension->HwDeviceExtension;
  4142. TimeContext.Function = TIME_GET_STREAM_TIME;
  4143. SCMinidriverTimeFunction(&TimeContext);
  4144. *SystemTime = TimeContext.SystemTime;
  4145. return (TimeContext.Time);
  4146. }
  4147. NTSTATUS
  4148. SCSendUnknownCommand(
  4149. IN PIRP Irp,
  4150. IN PDEVICE_EXTENSION DeviceExtension,
  4151. IN PVOID Callback,
  4152. OUT PBOOLEAN RequestIssued
  4153. )
  4154. /*++
  4155. Routine Description:
  4156. Arguments:
  4157. Irp - pointer to the IRP
  4158. Return Value:
  4159. NTSTATUS returned as appropriate.
  4160. --*/
  4161. {
  4162. PAGED_CODE();
  4163. //
  4164. // send an UNKNOWN_COMMAND SRB to the minidriver.
  4165. //
  4166. return (SCSubmitRequest(SRB_UNKNOWN_DEVICE_COMMAND,
  4167. NULL,
  4168. 0,
  4169. Callback,
  4170. DeviceExtension,
  4171. NULL,
  4172. NULL,
  4173. Irp,
  4174. RequestIssued,
  4175. &DeviceExtension->PendingQueue,
  4176. (PVOID) DeviceExtension->
  4177. MinidriverData->HwInitData.
  4178. HwReceivePacket
  4179. ));
  4180. }
  4181. BOOLEAN
  4182. SCMapMemoryAddress(PACCESS_RANGE AccessRanges,
  4183. PHYSICAL_ADDRESS TranslatedAddress,
  4184. PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  4185. PDEVICE_EXTENSION DeviceExtension,
  4186. PCM_RESOURCE_LIST ResourceList,
  4187. PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor)
  4188. /*++
  4189. Routine Description:
  4190. Arguments:
  4191. Return Value:
  4192. None.
  4193. --*/
  4194. {
  4195. PMAPPED_ADDRESS newMappedAddress;
  4196. PAGED_CODE();
  4197. //
  4198. // Now we need to map a linear address to the physical
  4199. // address that HalTranslateBusAddress provided us.
  4200. //
  4201. //
  4202. // set the access range in the structure.
  4203. //
  4204. AccessRanges->RangeLength = PartialResourceDescriptor->u.Memory.Length;
  4205. AccessRanges->RangeInMemory = TRUE;
  4206. AccessRanges->RangeStart.QuadPart = (ULONG_PTR) MmMapIoSpace(
  4207. TranslatedAddress,
  4208. AccessRanges->RangeLength,
  4209. FALSE // No caching
  4210. );
  4211. if (AccessRanges->RangeStart.QuadPart == 0) {
  4212. //
  4213. // Couldn't translate the resources, return an error
  4214. // status
  4215. //
  4216. DebugPrint((DebugLevelFatal, "StreamClassPnP: Couldn't translate Memory Slot Resources\n"));
  4217. return FALSE;
  4218. }
  4219. //
  4220. // Allocate memory to store mapped address for unmap.
  4221. //
  4222. newMappedAddress = ExAllocatePool(NonPagedPool,
  4223. sizeof(MAPPED_ADDRESS));
  4224. //
  4225. // save a link to the resources if the alloc succeeded.
  4226. // if it failed, don't worry about it.
  4227. //
  4228. if (newMappedAddress != NULL) {
  4229. //
  4230. // Store mapped address, bytes count, etc.
  4231. //
  4232. newMappedAddress->MappedAddress = (PVOID)
  4233. AccessRanges->RangeStart.QuadPart;
  4234. newMappedAddress->NumberOfBytes =
  4235. AccessRanges->RangeLength;
  4236. newMappedAddress->IoAddress =
  4237. PartialResourceDescriptor->u.Memory.Start;
  4238. newMappedAddress->BusNumber =
  4239. ConfigInfo->SystemIoBusNumber;
  4240. //
  4241. // Link current list to new entry.
  4242. //
  4243. newMappedAddress->NextMappedAddress =
  4244. DeviceExtension->MappedAddressList;
  4245. //
  4246. // Point anchor at new list.
  4247. //
  4248. DeviceExtension->MappedAddressList = newMappedAddress;
  4249. } // if newmappedaddress
  4250. return TRUE;
  4251. }
  4252. VOID
  4253. SCUpdatePersistedProperties(IN PSTREAM_OBJECT StreamObject,
  4254. IN PDEVICE_EXTENSION DeviceExtension,
  4255. IN PFILE_OBJECT FileObject
  4256. )
  4257. /*++
  4258. Routine Description:
  4259. Arguments:
  4260. Return Value:
  4261. None.
  4262. --*/
  4263. {
  4264. NTSTATUS Status;
  4265. HANDLE handle;
  4266. CHAR AsciiKeyName[32];
  4267. ANSI_STRING AnsiKeyName;
  4268. UNICODE_STRING UnicodeKeyName;
  4269. PAGED_CODE();
  4270. Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
  4271. PLUGPLAY_REGKEY_DRIVER,
  4272. STANDARD_RIGHTS_ALL,
  4273. &handle);
  4274. //
  4275. // loop through our table of strings,
  4276. // reading the registry for each.
  4277. //
  4278. if (NT_SUCCESS(Status)) {
  4279. //
  4280. // create the subkey for the pin, in the form of "Pin0\Properties",
  4281. // etc.
  4282. //
  4283. sprintf(AsciiKeyName, "Pin%d\\Properties", StreamObject->HwStreamObject.StreamNumber);
  4284. RtlInitAnsiString(&AnsiKeyName, AsciiKeyName);
  4285. if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeKeyName,
  4286. &AnsiKeyName, TRUE))) {
  4287. //
  4288. // call KS to unserialize the properties.
  4289. //
  4290. KsUnserializeObjectPropertiesFromRegistry(FileObject,
  4291. handle,
  4292. &UnicodeKeyName);
  4293. //
  4294. // free the unicode string
  4295. //
  4296. RtlFreeUnicodeString(&UnicodeKeyName);
  4297. } // if rtl..
  4298. //
  4299. // close the registry handle.
  4300. //
  4301. ZwClose(handle);
  4302. } // status = success
  4303. }
  4304. NTSTATUS
  4305. SCQueryCapabilities(
  4306. IN PDEVICE_OBJECT PdoDeviceObject,
  4307. IN PDEVICE_CAPABILITIES DeviceCapabilities
  4308. )
  4309. /*++
  4310. Routine Description:
  4311. This routine reads the capabilities of our parent.
  4312. Arguments:
  4313. DeviceObject - "Real" physical device object
  4314. Return Value:
  4315. None.
  4316. --*/
  4317. {
  4318. PIO_STACK_LOCATION NextStack;
  4319. PIRP Irp;
  4320. NTSTATUS Status;
  4321. KEVENT Event;
  4322. PAGED_CODE();
  4323. //
  4324. // allocate an IRP for the call.
  4325. //
  4326. Irp = IoAllocateIrp(PdoDeviceObject->StackSize, FALSE);
  4327. if (!Irp) {
  4328. return STATUS_INSUFFICIENT_RESOURCES;
  4329. }
  4330. NextStack = IoGetNextIrpStackLocation(Irp);
  4331. ASSERT(NextStack != NULL);
  4332. NextStack->MajorFunction = IRP_MJ_PNP;
  4333. NextStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  4334. //
  4335. // Initialize the capabilities that we will send down
  4336. //
  4337. RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
  4338. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  4339. DeviceCapabilities->Version = 1;
  4340. DeviceCapabilities->Address = -1;
  4341. DeviceCapabilities->UINumber = -1;
  4342. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  4343. IoSetCompletionRoutine(Irp,
  4344. SCSynchCompletionRoutine,
  4345. &Event,
  4346. TRUE,
  4347. TRUE,
  4348. TRUE);
  4349. NextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  4350. DebugPrint((DebugLevelInfo,
  4351. "Capabilities Version %x Flags %x\n",
  4352. (ULONG)DeviceCapabilities->Version,
  4353. *(UNALIGNED ULONG*)(&DeviceCapabilities->Version+1)));
  4354. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; // bug #282910
  4355. Status = IoCallDriver(PdoDeviceObject,
  4356. Irp);
  4357. if (Status == STATUS_PENDING) {
  4358. //
  4359. // block waiting for completion
  4360. //
  4361. KeWaitForSingleObject(
  4362. &Event,
  4363. Suspended,
  4364. KernelMode,
  4365. FALSE,
  4366. NULL);
  4367. }
  4368. //
  4369. // obtain final status and free IRP.
  4370. //
  4371. Status = Irp->IoStatus.Status;
  4372. IoFreeIrp(Irp);
  4373. return (Status);
  4374. }
  4375. NTSTATUS
  4376. SCEnableEventSynchronized(
  4377. IN PVOID ServiceContext
  4378. )
  4379. /*++
  4380. Routine Description:
  4381. This routine inserts the new event on the queue, and calls the minidriver
  4382. with the event.
  4383. Arguments:
  4384. ServiceContext - Supplies a pointer to the interrupt context which contains
  4385. pointers to the interrupt data and where to save it.
  4386. Return Value:
  4387. Returns TRUE if there is new work and FALSE otherwise.
  4388. Notes:
  4389. Called via KeSynchronizeExecution with the port device extension spinlock
  4390. held.
  4391. --*/
  4392. {
  4393. PHW_EVENT_DESCRIPTOR Event = ServiceContext;
  4394. NTSTATUS Status = STATUS_SUCCESS;
  4395. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  4396. Event->StreamObject,
  4397. STREAM_OBJECT,
  4398. HwStreamObject);
  4399. PDEVICE_EXTENSION DeviceExtension = StreamObject->DeviceExtension;
  4400. //
  4401. // insert the event on our list, in case the minidriver decides to signal
  4402. // from within this call.
  4403. //
  4404. InsertHeadList(&StreamObject->NotifyList,
  4405. &Event->EventEntry->ListEntry);
  4406. //
  4407. // call the minidriver's event routine, if present.
  4408. //
  4409. if (StreamObject->HwStreamObject.HwEventRoutine) {
  4410. Status = StreamObject->HwStreamObject.HwEventRoutine(Event);
  4411. } // if eventroutine
  4412. if (!NT_SUCCESS(Status)) {
  4413. //
  4414. // minidriver did not like it. remove the entry from the list.
  4415. //
  4416. DebugPrint((DebugLevelError, "StreamEnableEvent: minidriver failed enable!\n"));
  4417. RemoveEntryList(&Event->EventEntry->ListEntry);
  4418. }
  4419. return (Status);
  4420. }
  4421. NTSTATUS
  4422. SCEnableDeviceEventSynchronized(
  4423. IN PVOID ServiceContext
  4424. )
  4425. /*++
  4426. Routine Description:
  4427. This routine inserts the new event on the queue, and calls the minidriver
  4428. with the event.
  4429. Arguments:
  4430. ServiceContext - Supplies a pointer to the interrupt context which contains
  4431. pointers to the interrupt data and where to save it.
  4432. Return Value:
  4433. Returns TRUE if there is new work and FALSE otherwise.
  4434. Notes:
  4435. --*/
  4436. {
  4437. PHW_EVENT_DESCRIPTOR Event = ServiceContext;
  4438. NTSTATUS Status = STATUS_SUCCESS;
  4439. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)Event->DeviceExtension - 1;
  4440. IF_MF( PFILTER_INSTANCE FilterInstance = (PFILTER_INSTANCE)Event->HwInstanceExtension -1;)
  4441. //
  4442. // insert the event on our list, in case the minidriver decides to signal
  4443. // from within this call.
  4444. //
  4445. IFN_MF(InsertHeadList(&DeviceExtension->NotifyList,&Event->EventEntry->ListEntry);)
  4446. IF_MF(InsertHeadList(&FilterInstance->NotifyList,&Event->EventEntry->ListEntry);)
  4447. //
  4448. // call the minidriver's event routine, if present.
  4449. //
  4450. IFN_MF(
  4451. if (DeviceExtension->HwEventRoutine) {
  4452. Status = DeviceExtension->HwEventRoutine(Event);
  4453. } // if eventroutine
  4454. )
  4455. IF_MF(
  4456. if (FilterInstance->HwEventRoutine) {
  4457. Status = FilterInstance->HwEventRoutine(Event);
  4458. } // if eventroutine
  4459. )
  4460. if (!NT_SUCCESS(Status)) {
  4461. //
  4462. // minidriver did not like it. remove the entry from the list.
  4463. //
  4464. DebugPrint((DebugLevelError, "DeviceEnableEvent: minidriver failed enable!\n"));
  4465. RemoveEntryList(&Event->EventEntry->ListEntry);
  4466. }
  4467. return (Status);
  4468. }
  4469. VOID
  4470. SCFreeDeadEvents(
  4471. IN PDEVICE_EXTENSION DeviceExtension
  4472. )
  4473. /*++
  4474. Routine Description:
  4475. Free dead events at passive level
  4476. Arguments:
  4477. DeviceExtension - address of device extension.
  4478. Return Value:
  4479. None
  4480. --*/
  4481. {
  4482. LIST_ENTRY EventList;
  4483. PLIST_ENTRY EventListEntry;
  4484. PKSEVENT_ENTRY EventEntry;
  4485. KIRQL Irql;
  4486. //
  4487. // capture the dead list at the appropriate synchronization level.
  4488. //
  4489. // hack to save code. store the DeviceExtension* in the list entry.
  4490. EventList.Flink = (PLIST_ENTRY) DeviceExtension;
  4491. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  4492. DeviceExtension->SynchronizeExecution(
  4493. DeviceExtension->InterruptObject,
  4494. (PVOID) SCGetDeadListSynchronized,
  4495. &EventList);
  4496. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  4497. //
  4498. // discard each event on the captured list
  4499. //
  4500. while (!IsListEmpty(&EventList)) {
  4501. EventListEntry = RemoveHeadList(&EventList);
  4502. EventEntry = CONTAINING_RECORD(EventListEntry,
  4503. KSEVENT_ENTRY,
  4504. ListEntry);
  4505. KsDiscardEvent(EventEntry);
  4506. } // while not empty
  4507. //
  4508. // show event has been run
  4509. //
  4510. DeviceExtension->DeadEventItemQueued = FALSE;
  4511. return;
  4512. }
  4513. VOID
  4514. SCGetDeadListSynchronized(
  4515. IN PLIST_ENTRY NewEventList
  4516. )
  4517. /*++
  4518. Routine Description:
  4519. Get the list of dead events at the appropriate sync level
  4520. Arguments:
  4521. NewListEntry - list head to add the event list.
  4522. Return Value:
  4523. None
  4524. --*/
  4525. {
  4526. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) NewEventList->Flink;
  4527. PLIST_ENTRY ListEntry;
  4528. InitializeListHead(NewEventList);
  4529. //
  4530. // capture the dead list to our temp list head
  4531. //
  4532. while (!IsListEmpty(&DeviceExtension->DeadEventList)) {
  4533. ListEntry = RemoveTailList(&DeviceExtension->DeadEventList);
  4534. InsertHeadList(NewEventList,
  4535. ListEntry);
  4536. } // while dead list not empty
  4537. InitializeListHead(&DeviceExtension->DeadEventList);
  4538. return;
  4539. }
  4540. #if SUPPORT_MULTIPLE_FILTER_TYPES
  4541. VOID
  4542. SCRescanStreams(
  4543. IN PDEVICE_EXTENSION DeviceExtension
  4544. )
  4545. /*++
  4546. Routine Description:
  4547. Rescan minidriver streams of all filters with the request
  4548. Arguments:
  4549. DeviceExtension - address of device extension.
  4550. Return Value:
  4551. None
  4552. --*/
  4553. {
  4554. PHW_STREAM_DESCRIPTOR StreamBuffer;
  4555. PDEVICE_OBJECT DeviceObject = DeviceExtension->DeviceObject;
  4556. PFILTER_INSTANCE FilterInstance;
  4557. BOOLEAN RequestIssued;
  4558. KEVENT Event;
  4559. NTSTATUS Status;
  4560. IO_STATUS_BLOCK IoStatusBlock;
  4561. PIRP Irp;
  4562. ULONG ul;
  4563. PLIST_ENTRY Node;
  4564. PAGED_CODE();
  4565. TRAP;
  4566. DebugPrint((DebugLevelVerbose, "'RescanStreams: enter\n"));
  4567. //
  4568. // take the control event to avoid race
  4569. //
  4570. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  4571. Executive,
  4572. KernelMode,
  4573. FALSE,// not alertable
  4574. NULL);
  4575. ASSERT( !IsListEmpty( DeviceExtension->FilterInstanceList ));
  4576. Node = &DeviceExtension->FilterInstanceList;
  4577. while ( Node != Node->Flink ) {
  4578. FilterInstance = CONTAINING_RECORD(Node,
  4579. FILTER_INSTANCE,
  4580. NextFilterInstance);
  4581. if ( InterlockedExchange( &FilterInstance->NeedReenumeration, 0)) {
  4582. //
  4583. // send an SRB to retrieve the stream information
  4584. //
  4585. ASSERT( FilterInstance->StreamDescriptorSize );
  4586. StreamBuffer =
  4587. ExAllocatePool(NonPagedPool,
  4588. FilterInstance->StreamDescriptorSize);
  4589. if (!StreamBuffer) {
  4590. DebugPrint((DebugLevelError,
  4591. "RescanStreams: couldn't allocate!\n"));
  4592. TRAP;
  4593. KeSetEvent( &DeviceExtension->ControlEvent,IO_NO_INCREMENT, FALSE);
  4594. return;
  4595. }
  4596. //
  4597. // zero-init the buffer
  4598. //
  4599. RtlZeroMemory(StreamBuffer, ConfigInfo->StreamDescriptorSize);
  4600. //
  4601. // allocate IRP for issuing the get stream info.
  4602. // Since this IRP
  4603. // should not really be referenced, use dummy IOCTL code.
  4604. // I chose this one since it will always fail in the KS
  4605. // property handler if someone is silly enough to try to
  4606. // process it. Also make the irp internal i/o control.
  4607. //
  4608. // IoVerifier.c test code does not check IrpStack bound like
  4609. // the formal production code. And the owner does not want to
  4610. // fix it. It's more productive just work around here.
  4611. //Irp = IoBuildDeviceIoControlRequest(
  4612. // IOCTL_KS_PROPERTY,
  4613. // DeviceObject,
  4614. // NULL,
  4615. // 0,
  4616. // NULL,
  4617. // 0,
  4618. // TRUE,
  4619. // &Event,
  4620. // &IoStatusBlock);
  4621. Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  4622. if (!Irp) {
  4623. //
  4624. // could not allocate IRP. fail.
  4625. //
  4626. ExFreePool( StreamBuffer );
  4627. DebugPrint((DebugLevelError, "RescanStreams: couldn't allocate!\n"));
  4628. TRAP;
  4629. return;
  4630. } else {
  4631. PIO_STACK_LOCATION NextStack;
  4632. //
  4633. // This is a dummy Ir, the MJ is arbitrary
  4634. //
  4635. NextStack = IoGetNextIrpStackLocation(Irp);
  4636. ASSERT(NextStack != NULL);
  4637. NextStack->MajorFunction = IRP_MJ_PNP;
  4638. NextStack->MinorFunction = IRP_MN_CANCEL_STOP_DEVICE;
  4639. Irp->UserIosb = &IoStatusBlock;
  4640. Irp->UserEvent = &Event;
  4641. }
  4642. //
  4643. // show one more I/O pending on the device.
  4644. //
  4645. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  4646. //
  4647. // submit the command to retrieve the stream info.
  4648. // additional processing will be done by the callback
  4649. // procedure.
  4650. //
  4651. Status = SCSubmitRequest(SRB_GET_STREAM_INFO,
  4652. StreamBuffer,
  4653. ConfigInfo->StreamDescriptorSize,
  4654. SCStreamInfoCallback,
  4655. DeviceExtension,
  4656. FilterInstance->HwInstanceExtension,
  4657. NULL,
  4658. Irp,
  4659. &RequestIssued,
  4660. &DeviceExtension->PendingQueue,
  4661. (PVOID) DeviceExtension->
  4662. MinidriverData->HwInitData.
  4663. HwReceivePacket
  4664. );
  4665. if (!RequestIssued) {
  4666. KeSetEvent( &DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  4667. ExFreePool(StreamBuffer);
  4668. DebugPrint((DebugLevelError, "RescanStreams: couldn't issue request!\n"));
  4669. TRAP;
  4670. SCCompleteIrp(Irp, Status, DeviceExtension);
  4671. return;
  4672. }
  4673. } // check all filterinstances
  4674. //
  4675. // processing will continue in callback procedure.
  4676. //
  4677. return;
  4678. }
  4679. #else // SUPPORT_MULTIPLE_FILTER_TYPES
  4680. VOID
  4681. SCRescanStreams(
  4682. IN PDEVICE_EXTENSION DeviceExtension
  4683. )
  4684. /*++
  4685. Routine Description:
  4686. Rescan minidriver streams
  4687. Arguments:
  4688. DeviceExtension - address of device extension.
  4689. Return Value:
  4690. None
  4691. --*/
  4692. {
  4693. PHW_STREAM_DESCRIPTOR StreamBuffer;
  4694. PDEVICE_OBJECT DeviceObject = DeviceExtension->DeviceObject;
  4695. PPORT_CONFIGURATION_INFORMATION ConfigInfo =
  4696. DeviceExtension->ConfigurationInformation;
  4697. BOOLEAN RequestIssued;
  4698. KEVENT Event;
  4699. NTSTATUS Status;
  4700. IO_STATUS_BLOCK IoStatusBlock;
  4701. PIRP Irp;
  4702. PAGED_CODE();
  4703. TRAP;
  4704. DebugPrint((DebugLevelVerbose, "'RescanStreams: enter\n"));
  4705. //
  4706. // send an SRB to retrieve the stream information
  4707. //
  4708. ASSERT(ConfigInfo->StreamDescriptorSize);
  4709. StreamBuffer =
  4710. ExAllocatePool(NonPagedPool,
  4711. ConfigInfo->StreamDescriptorSize
  4712. );
  4713. if (!StreamBuffer) {
  4714. DebugPrint((DebugLevelError, "RescanStreams: couldn't allocate!\n"));
  4715. TRAP;
  4716. return;
  4717. }
  4718. //
  4719. // take the control event to avoid race
  4720. //
  4721. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  4722. Executive,
  4723. KernelMode,
  4724. FALSE,// not alertable
  4725. NULL);
  4726. //
  4727. // zero-init the buffer
  4728. //
  4729. RtlZeroMemory(StreamBuffer, ConfigInfo->StreamDescriptorSize);
  4730. //
  4731. // allocate IRP for issuing the get stream info.
  4732. // Since this IRP
  4733. // should not really be referenced, use dummy IOCTL code.
  4734. // I chose this one since it will always fail in the KS
  4735. // property handler if someone is silly enough to try to
  4736. // process it. Also make the irp internal i/o control.
  4737. //
  4738. Irp = IoBuildDeviceIoControlRequest(
  4739. IOCTL_KS_PROPERTY,
  4740. DeviceObject,
  4741. NULL,
  4742. 0,
  4743. NULL,
  4744. 0,
  4745. TRUE,
  4746. &Event,
  4747. &IoStatusBlock);
  4748. if (!Irp) {
  4749. //
  4750. // could not allocate IRP. fail.
  4751. //
  4752. ExFreePool( StreamBuffer );
  4753. DebugPrint((DebugLevelError, "RescanStreams: couldn't allocate!\n"));
  4754. TRAP;
  4755. return;
  4756. } // if ! irp
  4757. //
  4758. // show one more I/O pending on the device.
  4759. //
  4760. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  4761. //
  4762. // submit the command to retrieve the stream info.
  4763. // additional processing will be done by the callback
  4764. // procedure.
  4765. //
  4766. Status = SCSubmitRequest(SRB_GET_STREAM_INFO,
  4767. StreamBuffer,
  4768. ConfigInfo->StreamDescriptorSize,
  4769. SCStreamInfoCallback,
  4770. DeviceExtension,
  4771. NULL,
  4772. NULL,
  4773. Irp,
  4774. &RequestIssued,
  4775. &DeviceExtension->PendingQueue,
  4776. (PVOID) DeviceExtension->
  4777. MinidriverData->HwInitData.
  4778. HwReceivePacket
  4779. );
  4780. if (!RequestIssued) {
  4781. ExFreePool(StreamBuffer);
  4782. DebugPrint((DebugLevelError, "RescanStreams: couldn't issue request!\n"));
  4783. TRAP;
  4784. SCCompleteIrp(Irp, Status, DeviceExtension);
  4785. return;
  4786. }
  4787. //
  4788. // processing will continue in callback procedure.
  4789. //
  4790. return;
  4791. }
  4792. #endif // SUPPORT_MULTIPLE_FILTER_TYPES
  4793. BOOLEAN
  4794. SCCheckIfStreamsRunning(
  4795. IN PFILTER_INSTANCE FilterInstance
  4796. )
  4797. /*++
  4798. Routine Description:
  4799. Arguments:
  4800. Return Value:
  4801. --*/
  4802. {
  4803. PSTREAM_OBJECT StreamObject;
  4804. PLIST_ENTRY StreamListEntry,
  4805. StreamObjectEntry;
  4806. //
  4807. // process the streams on this list
  4808. //
  4809. StreamListEntry = StreamObjectEntry = &FilterInstance->FirstStream;
  4810. while (StreamObjectEntry->Flink != StreamListEntry) {
  4811. StreamObjectEntry = StreamObjectEntry->Flink;
  4812. //
  4813. // follow the link to the stream
  4814. // object
  4815. //
  4816. StreamObject = CONTAINING_RECORD(StreamObjectEntry,
  4817. STREAM_OBJECT,
  4818. NextStream);
  4819. if (StreamObject->CurrentState == KSSTATE_RUN) {
  4820. return (TRUE);
  4821. } // if running
  4822. } // while streams
  4823. return (FALSE);
  4824. }
  4825. VOID
  4826. SCCallBackSrb(
  4827. IN PSTREAM_REQUEST_BLOCK Srb,
  4828. IN PDEVICE_EXTENSION DeviceExtension
  4829. )
  4830. /*++
  4831. Routine Description:
  4832. Arguments:
  4833. Return Value:
  4834. --*/
  4835. {
  4836. KIRQL Irql;
  4837. if (DeviceExtension->NoSync) {
  4838. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  4839. if (Srb->DoNotCallBack) {
  4840. TRAP;
  4841. DebugPrint((DebugLevelError, "'ScCallback: NOT calling back request - Irp = %x",
  4842. Srb->HwSRB.Irp));
  4843. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  4844. return;
  4845. } // if NoCallback
  4846. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  4847. } // if NoSync
  4848. (Srb->Callback) (Srb);
  4849. }
  4850. #if DBG
  4851. VOID
  4852. SCDebugPriorityWorkItem(
  4853. IN PDEBUG_WORK_ITEM WorkItemStruct
  4854. )
  4855. /*++
  4856. Routine Description:
  4857. Arguments:
  4858. Return Value:
  4859. None
  4860. --*/
  4861. {
  4862. PCOMMON_OBJECT Object = WorkItemStruct->Object;
  4863. PHW_PRIORITY_ROUTINE Routine = WorkItemStruct->HwPriorityRoutine;
  4864. PVOID Context = WorkItemStruct->HwPriorityContext;
  4865. // DebugPrint((DebugLevelFatal, "F %x\n", WorkItemStruct));
  4866. ExFreePool(WorkItemStruct);
  4867. Object->PriorityWorkItemScheduled = FALSE;
  4868. if (Object->InterruptData.Flags &
  4869. INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST) {
  4870. DebugPrint((DebugLevelFatal, "Stream Minidriver scheduled priority twice!\n"));
  4871. ASSERT(1 == 0);
  4872. } // if scheduled twice
  4873. Routine(Context);
  4874. if (Object->InterruptData.Flags &
  4875. INTERRUPT_FLAGS_PRIORITY_CHANGE_REQUEST) {
  4876. DebugPrint((DebugLevelFatal, "Stream Minidriver scheduled priority twice!\n"));
  4877. ASSERT(1 == 0);
  4878. } // if scheduled twice
  4879. }
  4880. #endif
  4881. PKSPROPERTY_SET
  4882. SCCopyMinidriverProperties(
  4883. IN ULONG NumProps,
  4884. IN PKSPROPERTY_SET MinidriverProps
  4885. )
  4886. /*++
  4887. Routine Description:
  4888. Makes a private copy of the minidriver's properties
  4889. Arguments:
  4890. NumProps - number of properties to process
  4891. MinidriverProps - pointer to the array of properties to process
  4892. Return Value:
  4893. None.
  4894. --*/
  4895. {
  4896. PKSPROPERTY_ITEM CurrentPropItem;
  4897. PKSPROPERTY_SET CurrentProp;
  4898. ULONG i,
  4899. BufferSize;
  4900. PVOID NewPropertyBuffer;
  4901. #if DBG
  4902. ULONG TotalBufferUsed;
  4903. #endif
  4904. PAGED_CODE();
  4905. CurrentProp = MinidriverProps;
  4906. BufferSize = NumProps * sizeof(KSPROPERTY_SET);
  4907. //
  4908. // walk the minidriver's property sets to determine the size of the
  4909. // buffer
  4910. // needed. Size computed from # of sets from above, + # of items.
  4911. //
  4912. for (i = 0; i < NumProps; i++) {
  4913. BufferSize += CurrentProp->PropertiesCount * sizeof(KSPROPERTY_ITEM);
  4914. //
  4915. // index to next property set in
  4916. // array
  4917. //
  4918. CurrentProp++;
  4919. } // for number of property sets
  4920. if (!(NewPropertyBuffer = ExAllocatePool(NonPagedPool, BufferSize))) {
  4921. TRAP;
  4922. return (NULL);
  4923. }
  4924. //
  4925. // copy the array of sets over to the 1st part of the buffer.
  4926. //
  4927. RtlCopyMemory(NewPropertyBuffer,
  4928. MinidriverProps,
  4929. sizeof(KSPROPERTY_SET) * NumProps);
  4930. //
  4931. // walk thru the sets, copying the items for each set, and updating the
  4932. // pointer to each item array in each set as we go.
  4933. //
  4934. CurrentProp = (PKSPROPERTY_SET) NewPropertyBuffer;
  4935. CurrentPropItem = (PKSPROPERTY_ITEM) ((ULONG_PTR) NewPropertyBuffer + sizeof(KSPROPERTY_SET) * NumProps);
  4936. #if DBG
  4937. TotalBufferUsed = sizeof(KSPROPERTY_SET) * NumProps;
  4938. #endif
  4939. for (i = 0; i < NumProps; i++) {
  4940. RtlCopyMemory(CurrentPropItem,
  4941. CurrentProp->PropertyItem,
  4942. CurrentProp->PropertiesCount * sizeof(KSPROPERTY_ITEM));
  4943. #if DBG
  4944. TotalBufferUsed += CurrentProp->PropertiesCount * sizeof(KSPROPERTY_ITEM);
  4945. ASSERT(TotalBufferUsed <= BufferSize);
  4946. #endif
  4947. CurrentProp->PropertyItem = CurrentPropItem;
  4948. CurrentPropItem += CurrentProp->PropertiesCount;
  4949. CurrentProp++;
  4950. }
  4951. return ((PKSPROPERTY_SET) NewPropertyBuffer);
  4952. }
  4953. PKSEVENT_SET
  4954. SCCopyMinidriverEvents(
  4955. IN ULONG NumEvents,
  4956. IN PKSEVENT_SET MinidriverEvents
  4957. )
  4958. /*++
  4959. Routine Description:
  4960. Makes a private copy of the minidriver's properties
  4961. Arguments:
  4962. NumEvents - number of event sets to process
  4963. MinidriverEvents - pointer to the array of properties to process
  4964. Return Value:
  4965. None.
  4966. --*/
  4967. {
  4968. PKSEVENT_ITEM CurrentEventItem;
  4969. PKSEVENT_SET CurrentEvent;
  4970. ULONG i,
  4971. BufferSize;
  4972. PVOID NewEventBuffer;
  4973. #if DBG
  4974. ULONG TotalBufferUsed;
  4975. #endif
  4976. PAGED_CODE();
  4977. CurrentEvent = MinidriverEvents;
  4978. BufferSize = NumEvents * sizeof(KSEVENT_SET);
  4979. //
  4980. // walk the minidriver's property sets to determine the size of the
  4981. // buffer
  4982. // needed. Size computed from # of sets from above, + # of items.
  4983. //
  4984. for (i = 0; i < NumEvents; i++) {
  4985. BufferSize += CurrentEvent->EventsCount * sizeof(KSEVENT_ITEM);
  4986. //
  4987. // index to next property set in
  4988. // array
  4989. //
  4990. CurrentEvent++;
  4991. } // for number of property sets
  4992. if (!(NewEventBuffer = ExAllocatePool(NonPagedPool, BufferSize))) {
  4993. TRAP;
  4994. return (NULL);
  4995. }
  4996. //
  4997. // copy the array of sets over to the 1st part of the buffer.
  4998. //
  4999. RtlCopyMemory(NewEventBuffer,
  5000. MinidriverEvents,
  5001. sizeof(KSEVENT_SET) * NumEvents);
  5002. //
  5003. // walk thru the sets, copying the items for each set, and updating the
  5004. // pointer to each item array in each set as we go.
  5005. //
  5006. CurrentEvent = (PKSEVENT_SET) NewEventBuffer;
  5007. CurrentEventItem = (PKSEVENT_ITEM) ((ULONG_PTR) NewEventBuffer + sizeof(KSEVENT_SET) * NumEvents);
  5008. #if DBG
  5009. TotalBufferUsed = sizeof(KSEVENT_SET) * NumEvents;
  5010. #endif
  5011. for (i = 0; i < NumEvents; i++) {
  5012. RtlCopyMemory(CurrentEventItem,
  5013. CurrentEvent->EventItem,
  5014. CurrentEvent->EventsCount * sizeof(KSEVENT_ITEM));
  5015. #if DBG
  5016. TotalBufferUsed += CurrentEvent->EventsCount * sizeof(KSEVENT_ITEM);
  5017. ASSERT(TotalBufferUsed <= BufferSize);
  5018. #endif
  5019. CurrentEvent->EventItem = CurrentEventItem;
  5020. CurrentEventItem += CurrentEvent->EventsCount;
  5021. CurrentEvent++;
  5022. }
  5023. return ((PKSEVENT_SET) NewEventBuffer);
  5024. }
  5025. #ifdef ENABLE_KS_METHODS
  5026. PKSMETHOD_SET
  5027. SCCopyMinidriverMethods(
  5028. IN ULONG NumMethods,
  5029. IN PKSMETHOD_SET MinidriverMethods
  5030. )
  5031. /*++
  5032. Routine Description:
  5033. Makes a private copy of the minidriver's properties
  5034. Arguments:
  5035. NumMethods - number of properties to process
  5036. MinidriverMethods - pointer to the array of properties to process
  5037. Return Value:
  5038. None.
  5039. --*/
  5040. {
  5041. PKSMETHOD_ITEM CurrentMethodItem;
  5042. PKSMETHOD_SET CurrentMethod;
  5043. ULONG i,
  5044. BufferSize;
  5045. PVOID NewMethodBuffer;
  5046. #if DBG
  5047. ULONG TotalBufferUsed;
  5048. #endif
  5049. PAGED_CODE();
  5050. CurrentMethod = MinidriverMethods;
  5051. BufferSize = NumMethods * sizeof(KSMETHOD_SET);
  5052. //
  5053. // walk the minidriver's property sets to determine the size of the
  5054. // buffer
  5055. // needed. Size computed from # of sets from above, + # of items.
  5056. //
  5057. for (i = 0; i < NumMethods; i++) {
  5058. BufferSize += CurrentMethod->MethodsCount * sizeof(KSMETHOD_ITEM);
  5059. //
  5060. // index to next property set in
  5061. // array
  5062. //
  5063. CurrentMethod++;
  5064. } // for number of property sets
  5065. if (!(NewMethodBuffer = ExAllocatePool(NonPagedPool, BufferSize))) {
  5066. TRAP;
  5067. return (NULL);
  5068. }
  5069. //
  5070. // copy the array of sets over to the 1st part of the buffer.
  5071. //
  5072. RtlCopyMemory(NewMethodBuffer,
  5073. MinidriverMethods,
  5074. sizeof(KSMETHOD_SET) * NumMethods);
  5075. //
  5076. // walk thru the sets, copying the items for each set, and updating the
  5077. // pointer to each item array in each set as we go.
  5078. //
  5079. CurrentMethod = (PKSMETHOD_SET) NewMethodBuffer;
  5080. CurrentMethodItem = (PKSMETHOD_ITEM) ((ULONG_PTR) NewMethodBuffer + sizeof(KSMETHOD_SET) * NumMethods);
  5081. #if DBG
  5082. TotalBufferUsed = sizeof(KSMETHOD_SET) * NumMethods;
  5083. #endif
  5084. for (i = 0; i < NumMethods; i++) {
  5085. RtlCopyMemory(CurrentMethodItem,
  5086. CurrentMethod->MethodItem,
  5087. CurrentMethod->MethodsCount * sizeof(KSMETHOD_ITEM));
  5088. #if DBG
  5089. TotalBufferUsed += CurrentMethod->MethodsCount * sizeof(KSMETHOD_ITEM);
  5090. ASSERT(TotalBufferUsed <= BufferSize);
  5091. #endif
  5092. CurrentMethod->MethodItem = CurrentMethodItem;
  5093. CurrentMethodItem += CurrentMethod->MethodsCount;
  5094. CurrentMethod++;
  5095. }
  5096. return ((PKSMETHOD_SET) NewMethodBuffer);
  5097. }
  5098. VOID
  5099. SCUpdateMinidriverMethods(
  5100. IN ULONG NumMethods,
  5101. IN PKSMETHOD_SET MinidriverMethods,
  5102. IN BOOLEAN Stream
  5103. )
  5104. /*++
  5105. Routine Description:
  5106. Process method to the device.
  5107. Arguments:
  5108. NumMethods - number of methods to process
  5109. MinidriverMethods - pointer to the array of methods to process
  5110. Stream - TRUE indicates we are processing a set for the stream
  5111. Return Value:
  5112. None.
  5113. --*/
  5114. {
  5115. PKSMETHOD_ITEM CurrentMethodId;
  5116. PKSMETHOD_SET CurrentMethod;
  5117. ULONG i,
  5118. j;
  5119. PAGED_CODE();
  5120. //
  5121. // walk the minidriver's property info to fill in the dispatch
  5122. // vectors as appropriate.
  5123. //
  5124. CurrentMethod = MinidriverMethods;
  5125. for (i = 0; i < NumMethods; i++) {
  5126. CurrentMethodId = (PKSMETHOD_ITEM) CurrentMethod->MethodItem;
  5127. for (j = 0; j < CurrentMethod->MethodsCount; j++) {
  5128. //
  5129. // if support handler is supported, send it to the handler
  5130. //
  5131. if (CurrentMethodId->SupportHandler) {
  5132. if (Stream) {
  5133. CurrentMethodId->SupportHandler = StreamClassMinidriverStreamMethod;
  5134. } else {
  5135. CurrentMethodId->SupportHandler = StreamClassMinidriverDeviceMethod;
  5136. } // if stream
  5137. }
  5138. //
  5139. // if method routine is
  5140. // supported, add our vector.
  5141. //
  5142. if (CurrentMethodId->MethodHandler) {
  5143. if (Stream) {
  5144. CurrentMethodId->MethodHandler = StreamClassMinidriverStreamMethod;
  5145. } else {
  5146. CurrentMethodId->MethodHandler = StreamClassMinidriverDeviceMethod;
  5147. } // if stream
  5148. } // if supported
  5149. //
  5150. // index to next method item in
  5151. // array
  5152. //
  5153. CurrentMethodId++;
  5154. } // for number of property items
  5155. //
  5156. // index to next method set in
  5157. // array
  5158. //
  5159. CurrentMethod++;
  5160. } // for number of method sets
  5161. }
  5162. NTSTATUS
  5163. SCMinidriverDeviceMethodHandler(
  5164. IN SRB_COMMAND Command,
  5165. IN PIRP Irp,
  5166. IN PKSMETHOD Method,
  5167. IN OUT PVOID MethodInfo
  5168. )
  5169. /*++
  5170. Routine Description:
  5171. Process get/set method to the device.
  5172. Arguments:
  5173. Command - either GET or SET method
  5174. Irp - pointer to the IRP
  5175. Method - pointer to the method structure
  5176. MethodInfo - buffer for method information
  5177. Return Value:
  5178. NTSTATUS returned as appropriate.
  5179. --*/
  5180. {
  5181. PIO_STACK_LOCATION IrpStack;
  5182. PDEVICE_EXTENSION DeviceExtension;
  5183. PFILTER_INSTANCE FilterInstance;
  5184. PSTREAM_METHOD_DESCRIPTOR MethodDescriptor;
  5185. NTSTATUS Status;
  5186. BOOLEAN RequestIssued;
  5187. PAGED_CODE();
  5188. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  5189. DeviceExtension = (PDEVICE_EXTENSION)
  5190. (IrpStack->DeviceObject)->DeviceExtension;
  5191. FilterInstance = IrpStack->FileObject->FsContext;
  5192. MethodDescriptor = ExAllocatePool(NonPagedPool,
  5193. sizeof(STREAM_METHOD_DESCRIPTOR));
  5194. if (MethodDescriptor == NULL) {
  5195. DEBUG_BREAKPOINT();
  5196. DebugPrint((DebugLevelError,
  5197. "SCDeviceMethodHandler: No pool for descriptor"));
  5198. return (STATUS_INSUFFICIENT_RESOURCES);
  5199. }
  5200. //
  5201. // compute the index of the method set.
  5202. //
  5203. // this value is calculated by subtracting the base method set
  5204. // pointer from the requested method set pointer.
  5205. //
  5206. // The requested method set is pointed to by Context[0] by
  5207. // KsMethodHandler.
  5208. //
  5209. MethodDescriptor->MethodSetID = (ULONG)
  5210. ((ULONG_PTR) Irp->Tail.Overlay.DriverContext[0] -
  5211. IFN_MF((ULONG_PTR) DeviceExtension->DeviceMethodsArray)
  5212. IF_MF((ULONG_PTR) FilterInstance->DeviceMethodsArray)
  5213. ) / sizeof(KSMETHOD_SET);
  5214. MethodDescriptor->Method = Method;
  5215. MethodDescriptor->MethodInfo = MethodInfo;
  5216. MethodDescriptor->MethodInputSize =
  5217. IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  5218. MethodDescriptor->MethodOutputSize =
  5219. IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  5220. //
  5221. // send a get or set method SRB to the device.
  5222. //
  5223. Status = SCSubmitRequest(Command,
  5224. MethodDescriptor,
  5225. 0,
  5226. SCProcessCompletedMethodRequest,
  5227. DeviceExtension,
  5228. FilterInstance->HwInstanceExtension,
  5229. NULL,
  5230. Irp,
  5231. &RequestIssued,
  5232. &DeviceExtension->PendingQueue,
  5233. (PVOID) DeviceExtension->
  5234. MinidriverData->HwInitData.
  5235. HwReceivePacket
  5236. );
  5237. if (!RequestIssued) {
  5238. DEBUG_BREAKPOINT();
  5239. ExFreePool(MethodDescriptor);
  5240. }
  5241. return (Status);
  5242. }
  5243. NTSTATUS
  5244. SCMinidriverStreamMethodHandler(
  5245. IN SRB_COMMAND Command,
  5246. IN PIRP Irp,
  5247. IN PKSMETHOD Method,
  5248. IN OUT PVOID MethodInfo
  5249. )
  5250. /*++
  5251. Routine Description:
  5252. Process get or set method to the device.
  5253. Arguments:
  5254. Command - either GET or SET method
  5255. Irp - pointer to the IRP
  5256. Method - pointer to the method structure
  5257. MethodInfo - buffer for method information
  5258. Return Value:
  5259. None.
  5260. --*/
  5261. {
  5262. PIO_STACK_LOCATION IrpStack;
  5263. PDEVICE_EXTENSION DeviceExtension;
  5264. PSTREAM_OBJECT StreamObject;
  5265. PSTREAM_METHOD_DESCRIPTOR MethodDescriptor;
  5266. NTSTATUS Status;
  5267. BOOLEAN RequestIssued;
  5268. PAGED_CODE();
  5269. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  5270. DeviceExtension = (PDEVICE_EXTENSION)
  5271. (IrpStack->DeviceObject)->DeviceExtension;
  5272. StreamObject = IrpStack->FileObject->FsContext;
  5273. MethodDescriptor = ExAllocatePool(NonPagedPool,
  5274. sizeof(STREAM_METHOD_DESCRIPTOR));
  5275. if (MethodDescriptor == NULL) {
  5276. DEBUG_BREAKPOINT();
  5277. DebugPrint((DebugLevelError,
  5278. "SCDeviceMethodHandler: No pool for descriptor"));
  5279. return (STATUS_INSUFFICIENT_RESOURCES);
  5280. }
  5281. //
  5282. // compute the index of the method set.
  5283. //
  5284. // this value is calculated by subtracting the base method set
  5285. // pointer from the requested method set pointer.
  5286. //
  5287. // The requested method set is pointed to by Context[0] by
  5288. // KsMethodHandler.
  5289. //
  5290. MethodDescriptor->MethodSetID = (ULONG)
  5291. ((ULONG_PTR) Irp->Tail.Overlay.DriverContext[0] -
  5292. (ULONG_PTR) StreamObject->MethodInfo)
  5293. / sizeof(KSMETHOD_SET);
  5294. MethodDescriptor->Method = Method;
  5295. MethodDescriptor->MethodInfo = MethodInfo;
  5296. MethodDescriptor->MethodInputSize =
  5297. IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  5298. MethodDescriptor->MethodOutputSize =
  5299. IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  5300. //
  5301. // send a get or set method SRB to the stream.
  5302. //
  5303. Status = SCSubmitRequest(Command,
  5304. MethodDescriptor,
  5305. 0,
  5306. SCProcessCompletedMethodRequest,
  5307. DeviceExtension,
  5308. StreamObject->FilterInstance->HwInstanceExtension,
  5309. &StreamObject->HwStreamObject,
  5310. Irp,
  5311. &RequestIssued,
  5312. &StreamObject->ControlPendingQueue,
  5313. (PVOID) StreamObject->HwStreamObject.
  5314. ReceiveControlPacket
  5315. );
  5316. if (!RequestIssued) {
  5317. DEBUG_BREAKPOINT();
  5318. ExFreePool(MethodDescriptor);
  5319. }
  5320. return (Status);
  5321. }
  5322. NTSTATUS
  5323. SCProcessCompletedMethodRequest(
  5324. IN PSTREAM_REQUEST_BLOCK SRB
  5325. )
  5326. /*++
  5327. Routine Description:
  5328. This routine processes a method request which has completed.
  5329. Arguments:
  5330. SRB- address of completed STREAM request block
  5331. Return Value:
  5332. None.
  5333. --*/
  5334. {
  5335. PAGED_CODE();
  5336. //
  5337. // free the method info structure and
  5338. // complete the request
  5339. //
  5340. ExFreePool(SRB->HwSRB.CommandData.MethodInfo);
  5341. //
  5342. // set the information field from the SRB
  5343. // transferlength field
  5344. //
  5345. SRB->HwSRB.Irp->IoStatus.Information = SRB->HwSRB.ActualBytesTransferred;
  5346. return (SCDequeueAndDeleteSrb(SRB));
  5347. }
  5348. #endif // ENABLE_KS_METHODS