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

993 lines
24 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. shreq.cpp
  5. Abstract:
  6. This module contains the implementation of the kernel streaming shell
  7. requestor object.
  8. Author:
  9. Dale Sather (DaleSat) 31-Jul-1998
  10. --*/
  11. #include "private.h"
  12. #include <kcom.h>
  13. #include "stdio.h"
  14. #define POOLTAG_REQUESTOR 'gbcP'
  15. #define POOLTAG_STREAMHEADER 'hscP'
  16. //
  17. // CKsShellQueue is the implementation of the kernel shell requestor object.
  18. //
  19. class CKsShellRequestor:
  20. public IKsShellTransport,
  21. public IKsWorkSink,
  22. public CBaseUnknown
  23. {
  24. private:
  25. PIKSSHELLTRANSPORT m_TransportSource;
  26. PIKSSHELLTRANSPORT m_TransportSink;
  27. PDEVICE_OBJECT m_NextDeviceObject;
  28. PFILE_OBJECT m_AllocatorFileObject;
  29. KSSTREAMALLOCATOR_FUNCTIONTABLE m_AllocatorFunctionTable;
  30. KSSTREAMALLOCATOR_STATUS m_AllocatorStatus;
  31. ULONG m_StackSize;
  32. ULONG m_ProbeFlags;
  33. ULONG m_StreamHeaderSize;
  34. ULONG m_FrameSize;
  35. ULONG m_FrameCount;
  36. ULONG m_ActiveIrpCountPlusOne;
  37. BOOLEAN m_Flushing;
  38. BOOLEAN m_EndOfStream;
  39. KSSTATE m_State;
  40. INTERLOCKEDLIST_HEAD m_IrpsToFree;
  41. WORK_QUEUE_ITEM m_WorkItem;
  42. PKSWORKER m_Worker;
  43. KEVENT m_StopEvent;
  44. public:
  45. DEFINE_STD_UNKNOWN();
  46. CKsShellRequestor(PUNKNOWN OuterUnknown):
  47. CBaseUnknown(OuterUnknown) {
  48. }
  49. ~CKsShellRequestor();
  50. IMP_IKsShellTransport;
  51. IMP_IKsWorkSink;
  52. NTSTATUS
  53. Init(
  54. IN ULONG ProbeFlags,
  55. IN ULONG StreamHeaderSize OPTIONAL,
  56. IN ULONG FrameSize,
  57. IN ULONG FrameCount,
  58. IN PDEVICE_OBJECT NextDeviceObject,
  59. IN PFILE_OBJECT AllocatorFileObject OPTIONAL
  60. );
  61. private:
  62. NTSTATUS
  63. Prime(
  64. void
  65. );
  66. NTSTATUS
  67. Unprime(
  68. void
  69. );
  70. PVOID
  71. AllocateFrame(
  72. void
  73. );
  74. void
  75. FreeFrame(
  76. IN PVOID Frame
  77. );
  78. };
  79. IMPLEMENT_STD_UNKNOWN(CKsShellRequestor)
  80. #pragma code_seg("PAGE")
  81. NTSTATUS
  82. KspShellCreateRequestor(
  83. OUT PIKSSHELLTRANSPORT* RequestorTransport,
  84. IN ULONG ProbeFlags,
  85. IN ULONG StreamHeaderSize OPTIONAL,
  86. IN ULONG FrameSize,
  87. IN ULONG FrameCount,
  88. IN PDEVICE_OBJECT NextDeviceObject,
  89. IN PFILE_OBJECT AllocatorFileObject OPTIONAL
  90. )
  91. /*++
  92. Routine Description:
  93. This routine creates a new requestor.
  94. Arguments:
  95. Return Value:
  96. --*/
  97. {
  98. _DbgPrintF(DEBUGLVL_BLAB,("KspShellCreateRequestor"));
  99. PAGED_CODE();
  100. ASSERT(RequestorTransport);
  101. NTSTATUS status;
  102. CKsShellRequestor *requestor =
  103. new(NonPagedPool,POOLTAG_REQUESTOR) CKsShellRequestor(NULL);
  104. if (requestor) {
  105. requestor->AddRef();
  106. status =
  107. requestor->Init(
  108. ProbeFlags,
  109. StreamHeaderSize,
  110. FrameSize,
  111. FrameCount,
  112. NextDeviceObject,
  113. AllocatorFileObject);
  114. if (NT_SUCCESS(status)) {
  115. *RequestorTransport = PIKSSHELLTRANSPORT(requestor);
  116. } else {
  117. requestor->Release();
  118. }
  119. } else {
  120. status = STATUS_INSUFFICIENT_RESOURCES;
  121. }
  122. return status;
  123. }
  124. NTSTATUS
  125. CKsShellRequestor::
  126. Init(
  127. IN ULONG ProbeFlags,
  128. IN ULONG StreamHeaderSize OPTIONAL,
  129. IN ULONG FrameSize,
  130. IN ULONG FrameCount,
  131. IN PDEVICE_OBJECT NextDeviceObject,
  132. IN PFILE_OBJECT AllocatorFileObject OPTIONAL
  133. )
  134. /*++
  135. Routine Description:
  136. This routine initializes a requestor object.
  137. Arguments:
  138. Return Value:
  139. --*/
  140. {
  141. _DbgPrintF(DEBUGLVL_VERBOSE,("CKsShellRequestor::Init"));
  142. PAGED_CODE();
  143. ASSERT(((StreamHeaderSize == 0) ||
  144. (StreamHeaderSize >= sizeof(KSSTREAM_HEADER))) &&
  145. ((StreamHeaderSize & FILE_QUAD_ALIGNMENT) == 0));
  146. if (StreamHeaderSize == 0)
  147. {
  148. StreamHeaderSize = sizeof(KSSTREAM_HEADER);
  149. }
  150. m_NextDeviceObject = NextDeviceObject;
  151. m_AllocatorFileObject = AllocatorFileObject;
  152. m_ProbeFlags = ProbeFlags;
  153. m_StreamHeaderSize = StreamHeaderSize;
  154. m_FrameSize = FrameSize;
  155. m_FrameCount = FrameCount;
  156. m_State = KSSTATE_STOP;
  157. m_Flushing = FALSE;
  158. m_EndOfStream = FALSE;
  159. //
  160. // This is a one-based count of IRPs in circulation. We decrement it when
  161. // we go to stop state and block until it hits zero.
  162. //
  163. m_ActiveIrpCountPlusOne = 1;
  164. KeInitializeEvent(&m_StopEvent,SynchronizationEvent,FALSE);
  165. //
  166. // Initialize IRP-freeing work item stuff.
  167. //
  168. InitializeInterlockedListHead(&m_IrpsToFree);
  169. KsInitializeWorkSinkItem(&m_WorkItem,this);
  170. NTSTATUS status = KsRegisterCountedWorker(DelayedWorkQueue,&m_WorkItem,&m_Worker);
  171. if (!NT_SUCCESS(status))
  172. {
  173. return status;
  174. }
  175. //
  176. // Get the function table and status from the allocator if there is an
  177. // allocator.
  178. //
  179. if (m_AllocatorFileObject)
  180. {
  181. KSPROPERTY property;
  182. property.Set = KSPROPSETID_StreamAllocator;
  183. property.Id = KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE;
  184. property.Flags = KSPROPERTY_TYPE_GET;
  185. ULONG bytesReturned;
  186. status =
  187. KsSynchronousIoControlDevice(
  188. m_AllocatorFileObject,
  189. KernelMode,
  190. IOCTL_KS_PROPERTY,
  191. PVOID(&property),
  192. sizeof(property),
  193. PVOID(&m_AllocatorFunctionTable),
  194. sizeof(m_AllocatorFunctionTable),
  195. &bytesReturned);
  196. if (NT_SUCCESS(status) &&
  197. (bytesReturned != sizeof(m_AllocatorFunctionTable)))
  198. {
  199. status = STATUS_INVALID_BUFFER_SIZE;
  200. }
  201. if (NT_SUCCESS(status))
  202. {
  203. property.Id = KSPROPERTY_STREAMALLOCATOR_STATUS;
  204. status =
  205. KsSynchronousIoControlDevice(
  206. m_AllocatorFileObject,
  207. KernelMode,
  208. IOCTL_KS_PROPERTY,
  209. PVOID(&property),
  210. sizeof(property),
  211. PVOID(&m_AllocatorStatus),
  212. sizeof(m_AllocatorStatus),
  213. &bytesReturned);
  214. if (NT_SUCCESS(status) &&
  215. (bytesReturned != sizeof(m_AllocatorStatus)))
  216. {
  217. status = STATUS_INVALID_BUFFER_SIZE;
  218. }
  219. if (NT_SUCCESS(status))
  220. {
  221. m_FrameSize = m_AllocatorStatus.Framing.FrameSize;
  222. m_FrameCount = m_AllocatorStatus.Framing.Frames;
  223. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.Init: using allocator 0x%08x, size %d, count %d",this,m_AllocatorFileObject,m_FrameSize,m_FrameCount));
  224. }
  225. else
  226. {
  227. _DbgPrintF(DEBUGLVL_TERSE,("#### Req%p.Init: allocator failed status query: 0x%08x",this,status));
  228. }
  229. }
  230. else
  231. {
  232. _DbgPrintF(DEBUGLVL_TERSE,("#### Req%p.Init: allocator failed function table query: 0x%08x",this,status));
  233. }
  234. }
  235. else
  236. {
  237. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.Init: not using an allocator, size %d, count %d",this,m_FrameSize,m_FrameCount));
  238. }
  239. return status;
  240. }
  241. CKsShellRequestor::
  242. ~CKsShellRequestor(
  243. void
  244. )
  245. /*++
  246. Routine Description:
  247. This routine destructs a requestor object.
  248. Arguments:
  249. Return Value:
  250. --*/
  251. {
  252. _DbgPrintF(DEBUGLVL_BLAB,("CKsShellRequestor::~CKsShellRequestor"));
  253. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.~",this));
  254. PAGED_CODE();
  255. ASSERT(! m_TransportSink);
  256. ASSERT(! m_TransportSource);
  257. if (m_Worker) {
  258. KsUnregisterWorker(m_Worker);
  259. m_Worker = NULL;
  260. }
  261. }
  262. STDMETHODIMP_(NTSTATUS)
  263. CKsShellRequestor::
  264. NonDelegatedQueryInterface(
  265. IN REFIID InterfaceId,
  266. OUT PVOID* InterfacePointer
  267. )
  268. /*++
  269. Routine Description:
  270. This routine obtains an interface to a requestor object.
  271. Arguments:
  272. Return Value:
  273. --*/
  274. {
  275. _DbgPrintF(DEBUGLVL_BLAB,("CKsShellRequestor::NonDelegatedQueryInterface"));
  276. PAGED_CODE();
  277. ASSERT(InterfacePointer);
  278. NTSTATUS status = STATUS_SUCCESS;
  279. if (IsEqualGUIDAligned(InterfaceId,__uuidof(IKsShellTransport))) {
  280. *InterfacePointer = PVOID(PIKSSHELLTRANSPORT(this));
  281. AddRef();
  282. } else {
  283. status = CBaseUnknown::NonDelegatedQueryInterface(
  284. InterfaceId,InterfacePointer);
  285. }
  286. return status;
  287. }
  288. STDMETHODIMP_(void)
  289. CKsShellRequestor::
  290. Work(
  291. void
  292. )
  293. /*++
  294. Routine Description:
  295. This routine performs work in a worker thread. In particular, it frees
  296. IRPs.
  297. Arguments:
  298. Return Value:
  299. --*/
  300. {
  301. _DbgPrintF(DEBUGLVL_BLAB,("CKsShellRequestor::Work"));
  302. PAGED_CODE();
  303. //
  304. // Send all IRPs in the queue.
  305. //
  306. do
  307. {
  308. if (! IsListEmpty(&m_IrpsToFree.ListEntry))
  309. {
  310. PIRP irp;
  311. PLIST_ENTRY pListHead = ExInterlockedRemoveHeadList(&m_IrpsToFree.ListEntry,&m_IrpsToFree.SpinLock);
  312. if (pListHead)
  313. {
  314. irp = CONTAINING_RECORD(pListHead,IRP,Tail.Overlay.ListEntry);
  315. }
  316. else
  317. {
  318. return;
  319. }
  320. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.Work: freeing IRP 0x%08x",this,irp));
  321. //
  322. // Free MDL(s).
  323. //
  324. PMDL nextMdl;
  325. for (PMDL mdl = irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
  326. nextMdl = mdl->Next;
  327. if (mdl->MdlFlags & MDL_PAGES_LOCKED) {
  328. MmUnlockPages(mdl);
  329. }
  330. IoFreeMdl(mdl);
  331. }
  332. //
  333. // Free header and frame.
  334. //
  335. PKSSTREAM_HEADER streamHeader = PKSSTREAM_HEADER(irp->UserBuffer);
  336. if (streamHeader) {
  337. if (streamHeader->Data) {
  338. FreeFrame(streamHeader->Data);
  339. }
  340. ExFreePool(streamHeader);
  341. }
  342. IoFreeIrp(irp);
  343. //
  344. // Count the active IRPs. If we have hit zero, this means that
  345. // another thread is waiting to finish a transition to stop state.
  346. //
  347. if (! InterlockedDecrement(PLONG(&m_ActiveIrpCountPlusOne))) {
  348. KeSetEvent(&m_StopEvent,IO_NO_INCREMENT,FALSE);
  349. }
  350. }
  351. } while (KsDecrementCountedWorker(m_Worker));
  352. }
  353. #pragma code_seg()
  354. STDMETHODIMP_(NTSTATUS)
  355. CKsShellRequestor::
  356. TransferKsIrp(
  357. IN PIRP Irp,
  358. IN PIKSSHELLTRANSPORT* NextTransport
  359. )
  360. /*++
  361. Routine Description:
  362. This routine handles the arrival of a streaming IRP.
  363. Arguments:
  364. Return Value:
  365. --*/
  366. {
  367. _DbgPrintF(DEBUGLVL_BLAB,("CKsShellRequestor::TransferKsIrp"));
  368. ASSERT(Irp);
  369. ASSERT(NextTransport);
  370. ASSERT(m_TransportSink);
  371. if (m_State != KSSTATE_RUN) {
  372. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.TransferKsIrp: got IRP %p in state %d",this,Irp,m_State));
  373. }
  374. NTSTATUS status;
  375. PKSSTREAM_HEADER streamHeader = PKSSTREAM_HEADER(Irp->UserBuffer);
  376. //
  377. // Check for end of stream.
  378. //
  379. if (streamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM) {
  380. m_EndOfStream = TRUE;
  381. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.TransferKsIrp: IRP %p is marked end-of-stream",this,Irp));
  382. }
  383. if (m_Flushing || m_EndOfStream || (m_State == KSSTATE_STOP)) {
  384. //
  385. // Stopping...destroy the IRP.
  386. //
  387. ExInterlockedInsertTailList(
  388. &m_IrpsToFree.ListEntry,
  389. &Irp->Tail.Overlay.ListEntry,
  390. &m_IrpsToFree.SpinLock);
  391. *NextTransport = NULL;
  392. KsIncrementCountedWorker(m_Worker);
  393. status = STATUS_PENDING;
  394. } else {
  395. //
  396. // Recondition and forward it.
  397. //
  398. PVOID frame = streamHeader->Data;
  399. RtlZeroMemory(streamHeader,m_StreamHeaderSize);
  400. streamHeader->Size = m_StreamHeaderSize;
  401. streamHeader->Data = frame;
  402. streamHeader->FrameExtent = m_FrameSize;
  403. Irp->IoStatus.Status = STATUS_SUCCESS;
  404. Irp->IoStatus.Information = 0;
  405. Irp->PendingReturned = 0;
  406. Irp->Cancel = 0;
  407. *NextTransport = m_TransportSink;
  408. status = STATUS_SUCCESS;
  409. }
  410. return status;
  411. }
  412. #pragma code_seg("PAGE")
  413. STDMETHODIMP_(void)
  414. CKsShellRequestor::
  415. Connect(
  416. IN PIKSSHELLTRANSPORT NewTransport OPTIONAL,
  417. OUT PIKSSHELLTRANSPORT *OldTransport OPTIONAL,
  418. IN KSPIN_DATAFLOW DataFlow
  419. )
  420. /*++
  421. Routine Description:
  422. This routine establishes a transport connection.
  423. Arguments:
  424. Return Value:
  425. --*/
  426. {
  427. _DbgPrintF(DEBUGLVL_BLAB,("CKsShellRequestor::Connect"));
  428. PAGED_CODE();
  429. KsShellStandardConnect(
  430. NewTransport,
  431. OldTransport,
  432. DataFlow,
  433. PIKSSHELLTRANSPORT(this),
  434. &m_TransportSource,
  435. &m_TransportSink);
  436. }
  437. STDMETHODIMP_(NTSTATUS)
  438. CKsShellRequestor::
  439. SetDeviceState(
  440. IN KSSTATE ksStateTo,
  441. IN KSSTATE ksStateFrom,
  442. IN PIKSSHELLTRANSPORT* NextTransport
  443. )
  444. /*++
  445. Routine Description:
  446. This routine handles notification that the device state has changed.
  447. Arguments:
  448. Return Value:
  449. --*/
  450. {
  451. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.SetDeviceState: set from %d to %d",this,ksStateFrom,ksStateTo));
  452. PAGED_CODE();
  453. ASSERT(NextTransport);
  454. NTSTATUS status;
  455. //
  456. // If this is a change of state, note the new state and indicate the next
  457. // recipient.
  458. //
  459. if (m_State != ksStateTo) {
  460. //
  461. // The state has changed. Just note the new state, indicate the next
  462. // recipient, and get out. We will get the same state change again
  463. // when it has gone all the way around the circuit.
  464. //
  465. m_State = ksStateTo;
  466. if (ksStateTo > ksStateFrom){
  467. *NextTransport = m_TransportSink;
  468. } else {
  469. *NextTransport = m_TransportSource;
  470. }
  471. status = STATUS_SUCCESS;
  472. } else {
  473. //
  474. // The state change has gone all the way around the circuit and come
  475. // back. All the other components are in the new state now. For
  476. // transitions out of acquire state, there is work to be done.
  477. //
  478. *NextTransport = NULL;
  479. if (ksStateFrom == KSSTATE_ACQUIRE) {
  480. if (ksStateTo == KSSTATE_PAUSE) {
  481. //
  482. // Acquire-to-pause requires us to prime.
  483. //
  484. status = Prime();
  485. } else {
  486. //
  487. // Acquire-to-stop requires us to wait until all IRPs are home to
  488. // roost.
  489. //
  490. if (InterlockedDecrement(PLONG(&m_ActiveIrpCountPlusOne))) {
  491. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.SetDeviceState: waiting for %d active IRPs to return",this,m_ActiveIrpCountPlusOne));
  492. KeWaitForSingleObject(
  493. &m_StopEvent,
  494. Suspended,
  495. KernelMode,
  496. FALSE,
  497. NULL
  498. );
  499. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.SetDeviceState: done waiting",this));
  500. }
  501. status = STATUS_SUCCESS;
  502. }
  503. }
  504. else
  505. {
  506. #if 1
  507. //
  508. // Nothing to do.
  509. //
  510. #else
  511. // Take a configuration pass through the circuit.
  512. // The transport interface for each element in the circuit exposes GetTransportConfig
  513. // and SetTransportConfig.
  514. // The requestor's stack depth starts at 1
  515. // Each element that reports in GetTransportConfig returns it's stack depth
  516. // Queues, Intra-Pins report 1
  517. // Extra-Pins report the depth of the connected device object plus one
  518. // Splitters are handled somewhat differently (irrelevant to portcls?)
  519. // After each GetTransportConfig, the requestor's stack depth is adjusted to be the
  520. // highest depth seen thus far in configuration
  521. // At the end, SetTransportConfig is used to set the requestors stack depth
  522. //
  523. // This mechanism is also used to decide probe flags.
  524. // If you're interested in looking at the source, ksfilter\ks\shpipe.cpp
  525. // ConfigureCompleteCircuit and sh*.cpp GetTransportConfig / SetTransportConfig
  526. // are the ones to look at.
  527. //
  528. #endif
  529. status = STATUS_SUCCESS;
  530. }
  531. }
  532. return status;
  533. }
  534. NTSTATUS
  535. CKsShellRequestor::
  536. Prime(
  537. void
  538. )
  539. /*++
  540. Routine Description:
  541. This routine primes the requestor.
  542. Arguments:
  543. None.
  544. Return Value:
  545. Status.
  546. --*/
  547. {
  548. PAGED_CODE();
  549. //
  550. // Cache the stack size.
  551. //
  552. m_StackSize = m_NextDeviceObject->StackSize;
  553. // HACK
  554. //
  555. // ADRIAO ISSUE 06/29/1999
  556. // Arghhhh!!!!!!!!
  557. //
  558. // ISSUE MARTINP 2000/12/18 This is fixed with AVStream, so it isn't worth
  559. // making large changes to address this issue for Windows XP. This code is
  560. // no longer present in PortCls2. We should make sure this is fixed in for
  561. // sure in Blackcomb.
  562. //
  563. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.Prime: stack size is %d",this,m_StackSize));
  564. m_StackSize = 6;
  565. //
  566. // Reset the end of stream indicator.
  567. //
  568. m_EndOfStream = FALSE;
  569. NTSTATUS status = STATUS_SUCCESS;
  570. //
  571. // Call the allocator or create some synthetic frames. Then wrap the
  572. // frames in IRPs.
  573. //
  574. for (ULONG count = m_FrameCount; count--;) {
  575. //
  576. // Allocate the frame.
  577. //
  578. PVOID frame = AllocateFrame();
  579. if (! frame) {
  580. status = STATUS_INSUFFICIENT_RESOURCES;
  581. _DbgPrintF(DEBUGLVL_TERSE,("#### Req%p.Prime: failed to allocate frame",this));
  582. break;
  583. }
  584. //
  585. // Allocate and initialize the stream header.
  586. //
  587. PKSSTREAM_HEADER streamHeader = (PKSSTREAM_HEADER)
  588. ExAllocatePoolWithTag(
  589. NonPagedPool,m_StreamHeaderSize,POOLTAG_STREAMHEADER);
  590. if (! streamHeader) {
  591. status = STATUS_INSUFFICIENT_RESOURCES;
  592. _DbgPrintF(DEBUGLVL_TERSE,("#### Req%p.Prime: failed to allocate stream header",this));
  593. FreeFrame(frame);
  594. break;
  595. }
  596. RtlZeroMemory(streamHeader,m_StreamHeaderSize);
  597. streamHeader->Size = m_StreamHeaderSize;
  598. streamHeader->Data = frame;
  599. streamHeader->FrameExtent = m_FrameSize;
  600. //
  601. // Count the active IRPs.
  602. //
  603. InterlockedIncrement(PLONG(&m_ActiveIrpCountPlusOne));
  604. //
  605. // Allocate an IRP.
  606. //
  607. ASSERT(m_StackSize);
  608. PIRP irp = IoAllocateIrp(CCHAR(m_StackSize),FALSE);
  609. if (! irp) {
  610. status = STATUS_INSUFFICIENT_RESOURCES;
  611. _DbgPrintF(DEBUGLVL_TERSE,("#### Req%p.Prime: failed to allocate IRP",this));
  612. ExFreePool(streamHeader);
  613. FreeFrame(frame);
  614. break;
  615. }
  616. irp->UserBuffer = streamHeader;
  617. irp->RequestorMode = KernelMode;
  618. irp->Flags = IRP_NOCACHE;
  619. //
  620. // Set the stack pointer to the first location and fill it in.
  621. //
  622. IoSetNextIrpStackLocation(irp);
  623. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  624. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  625. irpSp->Parameters.DeviceIoControl.IoControlCode =
  626. IOCTL_KS_READ_STREAM;
  627. irpSp->Parameters.DeviceIoControl.OutputBufferLength =
  628. m_StreamHeaderSize;
  629. //
  630. // Let KsProbeStreamIrp() prepare the IRP as specified by the caller.
  631. //
  632. status = KsProbeStreamIrp(irp,m_ProbeFlags,sizeof(KSSTREAM_HEADER));
  633. if (! NT_SUCCESS(status)) {
  634. _DbgPrintF(DEBUGLVL_TERSE,("#### Req%p.Prime: KsProbeStreamIrp failed: 0x%08x",this,status));
  635. IoFreeIrp(irp);
  636. ExFreePool(streamHeader);
  637. FreeFrame(frame);
  638. break;
  639. }
  640. //
  641. // Send the IRP to the next component.
  642. //
  643. //mgp
  644. _DbgPrintF(DEBUGLVL_VERBOSE,("#### Req%p.SetDeviceState: transferring new IRP 0x%08x",this,irp));
  645. status = KsShellTransferKsIrp(m_TransportSink,irp);
  646. if (NT_SUCCESS(status) || (status == STATUS_MORE_PROCESSING_REQUIRED)) {
  647. status = STATUS_SUCCESS;
  648. } else {
  649. _DbgPrintF(DEBUGLVL_TERSE,("#### Req%p.Prime: receiver failed transfer call: 0x%08x",this,status));
  650. IoFreeIrp(irp);
  651. ExFreePool(streamHeader);
  652. FreeFrame(frame);
  653. break;
  654. }
  655. }
  656. return status;
  657. }
  658. STDMETHODIMP_(void)
  659. CKsShellRequestor::
  660. SetResetState(
  661. IN KSRESET ksReset,
  662. IN PIKSSHELLTRANSPORT* NextTransport
  663. )
  664. /*++
  665. Routine Description:
  666. This routine handles notification that the reset state has changed.
  667. Arguments:
  668. Return Value:
  669. --*/
  670. {
  671. _DbgPrintF(DEBUGLVL_VERBOSE,("CKsShellRequestor::SetResetState] to %d",ksReset));
  672. PAGED_CODE();
  673. ASSERT(NextTransport);
  674. if (m_Flushing != (ksReset == KSRESET_BEGIN)) {
  675. *NextTransport = m_TransportSink;
  676. m_Flushing = (ksReset == KSRESET_BEGIN);
  677. } else {
  678. *NextTransport = NULL;
  679. }
  680. }
  681. PVOID
  682. CKsShellRequestor::
  683. AllocateFrame(
  684. void
  685. )
  686. /*++
  687. Routine Description:
  688. This routine allocates a frame.
  689. Arguments:
  690. None.
  691. Return Value:
  692. The allocated frame or NULL if no frame could be allocated.
  693. --*/
  694. {
  695. _DbgPrintF(DEBUGLVL_BLAB,("CKsShellRequestor::AllocateFrame"));
  696. PAGED_CODE();
  697. PVOID frame;
  698. if (m_AllocatorFileObject) {
  699. m_AllocatorFunctionTable.AllocateFrame(m_AllocatorFileObject,&frame);
  700. } else {
  701. frame = ExAllocatePoolWithTag(NonPagedPool,m_FrameSize,'kHcP');
  702. }
  703. return frame;
  704. }
  705. void
  706. CKsShellRequestor::
  707. FreeFrame(
  708. IN PVOID Frame
  709. )
  710. /*++
  711. Routine Description:
  712. This routine frees a frame.
  713. Arguments:
  714. Frame -
  715. The frame to free.
  716. Return Value:
  717. None.
  718. --*/
  719. {
  720. _DbgPrintF(DEBUGLVL_VERBOSE,("CKsShellRequestor::FreeFrame"));
  721. PAGED_CODE();
  722. if (m_AllocatorFileObject) {
  723. m_AllocatorFunctionTable.FreeFrame(m_AllocatorFileObject,Frame);
  724. } else {
  725. ExFreePool(Frame);
  726. }
  727. }
  728. #if DBG
  729. STDMETHODIMP_(void)
  730. CKsShellRequestor::
  731. DbgRollCall(
  732. IN ULONG MaxNameSize,
  733. OUT PCHAR Name,
  734. OUT PIKSSHELLTRANSPORT* NextTransport,
  735. OUT PIKSSHELLTRANSPORT* PrevTransport
  736. )
  737. /*++
  738. Routine Description:
  739. This routine produces a component name and the transport pointers.
  740. Arguments:
  741. Return Value:
  742. --*/
  743. {
  744. _DbgPrintF(DEBUGLVL_BLAB,("CKsShellRequestor::DbgRollCall"));
  745. PAGED_CODE();
  746. ASSERT(Name);
  747. ASSERT(NextTransport);
  748. ASSERT(PrevTransport);
  749. ULONG references = AddRef() - 1; Release();
  750. _snprintf(Name,MaxNameSize,"Req%p refs=%d\n",this,references);
  751. *NextTransport = m_TransportSink;
  752. *PrevTransport = m_TransportSource;
  753. }
  754. #endif