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.

3326 lines
99 KiB

  1. /*****************************************************************************
  2. * irpstrm.cpp - IRP stream object implementation
  3. *****************************************************************************
  4. * Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
  5. */
  6. #ifndef PC_KDEXT
  7. #include "private.h"
  8. VOID
  9. IrpStreamCancelRoutine
  10. (
  11. IN PDEVICE_OBJECT DeviceObject,
  12. IN PIRP Irp
  13. );
  14. #if DBG
  15. #define DbgAcquireMappingIrp(a,b) AcquireMappingIrp(a,b)
  16. #define DbgAcquireUnmappingIrp(a) AcquireUnmappingIrp(a)
  17. #else
  18. #define DbgAcquireMappingIrp(a,b) AcquireMappingIrp(b)
  19. #define DbgAcquireUnmappingIrp(a) AcquireUnmappingIrp()
  20. #endif
  21. #endif // PC_KDEXT
  22. #define WHOLE_MDL_THRESHOLD (PAGE_SIZE * 16)
  23. #define PRE_OFFSET_THRESHOLD ((PAGE_SIZE / 4) * 3)
  24. #define POST_OFFSET_THRESHOLD (PAGE_SIZE / 4)
  25. #define MAX_PAGES_PER_MDL 16
  26. #define POOL_TAG_IRPSTREAM_IRP_CONTEXT 'sIcP'
  27. #define MAPPING_QUEUE_SIZE 128 // maximum entries in the mapping queue
  28. #define MAX_MAPPINGS 15 // maximum mappings per IoMapTransfer call
  29. // (this results in at most 16 map registers)
  30. /*****************************************************************************
  31. * PACKET_HEADER
  32. *****************************************************************************
  33. * Extension of KSSTREAM_HEADER containing a pointer to the matching MDL and
  34. * progress indicators for locking, mapping and unmapping.
  35. *
  36. * Invariants: BytesTotal >= MapPosition >= UnmapPosition
  37. *
  38. * It is true of MapPosition and UnmapPosition that at most one packet in an
  39. * IrpStream may have a value for the field that is not zero or BytesTotal.
  40. * If there is such a packet, all packets preceding it have 0 in that field
  41. * and all packets following have BytesTotal in that field. The two fields
  42. * form two progress indicators showing the position in the IrpStream that is
  43. * currently being mapped or unmapped.
  44. *
  45. * When both the BytesX are equal, the packet is ready for completion. When
  46. * this is true of all packets in an IRP, the IRP is ready for completion.
  47. *
  48. * InputPosition and OutputPosition are used to locate the packet in the
  49. * stream. InputPosition refers to the byte position of the packet on the
  50. * input side. This means that looped packets are counted only once in this
  51. * context. OutputPosition refers to the byte position of the packet on the
  52. * output side. This means that looped packets are counted as many times as
  53. * they are 'played'.
  54. */
  55. typedef struct PACKET_HEADER_
  56. {
  57. PKSSTREAM_HEADER StreamHeader;
  58. PMDL MdlAddress;
  59. ULONG BytesTotal;
  60. ULONG MapPosition;
  61. ULONG UnmapPosition;
  62. ULONG MapCount;
  63. ULONGLONG InputPosition;
  64. ULONGLONG OutputPosition;
  65. BOOLEAN IncrementMapping;
  66. BOOLEAN IncrementUnmapping;
  67. struct PACKET_HEADER_ * Next;
  68. }
  69. PACKET_HEADER, *PPACKET_HEADER;
  70. typedef struct
  71. {
  72. #if (DBG)
  73. ULONG IrpLabel;
  74. ULONG Reserved;
  75. #endif
  76. PEPROCESS SubmissionProcess;
  77. PVOID IrpStream;
  78. PPACKET_HEADER LockingPacket;
  79. PPACKET_HEADER MappingPacket;
  80. PPACKET_HEADER UnmappingPacket;
  81. PACKET_HEADER Packets[1]; // variable
  82. }
  83. IRP_CONTEXT, *PIRP_CONTEXT;
  84. typedef struct
  85. {
  86. PHYSICAL_ADDRESS PhysicalAddress;
  87. PIRP Irp;
  88. PPACKET_HEADER PacketHeader;
  89. PVOID VirtualAddress;
  90. ULONG ByteCount;
  91. ULONG Flags;
  92. PVOID MapRegisterBase;
  93. PVOID Tag;
  94. ULONG MappingStatus;
  95. PVOID SubpacketVa;
  96. ULONG SubpacketBytes;
  97. }
  98. MAPPING_QUEUE_ENTRY, *PMAPPING_QUEUE_ENTRY;
  99. #define MAPPING_STATUS_EMPTY 0x0000
  100. #define MAPPING_STATUS_MAPPED 0x0001
  101. #define MAPPING_STATUS_DELIVERED 0x0002
  102. #define MAPPING_STATUS_REVOKED 0x0004
  103. #define MAPPING_FLAG_END_OF_SUBPACKET 0x0002
  104. #define PPACKET_HEADER_LOOP PPACKET_HEADER(1)
  105. #define CAST_LVALUE(type,lvalue) (*((type*)&(lvalue)))
  106. #define FLINK_IRP_STORAGE(Irp) \
  107. CAST_LVALUE(PLIST_ENTRY,(Irp)->Tail.Overlay.ListEntry.Flink)
  108. #define BLINK_IRP_STORAGE(Irp) \
  109. CAST_LVALUE(PLIST_ENTRY,(Irp)->Tail.Overlay.ListEntry.Blink)
  110. #define FIRST_STREAM_HEADER_IRP_STORAGE(Irp) \
  111. CAST_LVALUE(PKSSTREAM_HEADER,(Irp)->AssociatedIrp.SystemBuffer)
  112. #define IRP_CONTEXT_IRP_STORAGE(Irp) \
  113. CAST_LVALUE(PIRP_CONTEXT,IoGetCurrentIrpStackLocation(Irp)-> \
  114. Parameters.Others.Argument4)
  115. /*****************************************************************************
  116. * CIrpStream
  117. *****************************************************************************
  118. * Irp stream implementation.
  119. */
  120. class CIrpStream : public IIrpStreamVirtual,
  121. public IIrpStreamPhysical,
  122. public CUnknown
  123. {
  124. private:
  125. PIKSSHELLTRANSPORT m_TransportSink;
  126. PIKSSHELLTRANSPORT m_TransportSource;
  127. KSSTATE m_ksState;
  128. BOOLEAN m_Flushing;
  129. BOOLEAN JustInTime;
  130. BOOLEAN WriteOperation;
  131. BOOLEAN WasExhausted;
  132. ULONG ProbeFlags;
  133. PIRP LockedIrp;
  134. KSPIN_LOCK m_kSpinLock;
  135. KSPIN_LOCK m_RevokeLock;
  136. KSPIN_LOCK m_irpStreamPositionLock;
  137. IRPSTREAM_POSITION m_irpStreamPosition;
  138. ULONGLONG InputPosition;
  139. ULONGLONG OutputPosition;
  140. PADAPTER_OBJECT BusMasterAdapterObject;
  141. PDEVICE_OBJECT FunctionalDeviceObject;
  142. PIRPSTREAMNOTIFY Notify;
  143. PIRPSTREAMNOTIFYPHYSICAL NotifyPhysical;
  144. //
  145. // Master spin lock taken when acquiring an IRP.
  146. //
  147. KIRQL m_kIrqlOld;
  148. LIST_ENTRY PreLockQueue;
  149. KSPIN_LOCK PreLockQueueLock;
  150. LIST_ENTRY LockedQueue;
  151. KSPIN_LOCK LockedQueueLock;
  152. LIST_ENTRY MappedQueue;
  153. KSPIN_LOCK MappedQueueLock;
  154. struct
  155. {
  156. PMAPPING_QUEUE_ENTRY Array;
  157. ULONG Head;
  158. ULONG Tail;
  159. ULONG Get;
  160. } MappingQueue;
  161. #if (DBG)
  162. ULONG MappingsOutstanding;
  163. ULONG MappingsQueued;
  164. ULONG IrpLabel;
  165. ULONG IrpLabelToComplete;
  166. ULONGLONG timeStep;
  167. ULONG irpCompleteCount;
  168. PCHAR MappingIrpOwner;
  169. PCHAR UnmappingIrpOwner;
  170. #endif
  171. PIRP AcquireMappingIrp
  172. (
  173. #if DBG
  174. IN PCHAR Owner,
  175. #endif
  176. IN BOOLEAN NotifyExhausted
  177. );
  178. PIRP AcquireUnmappingIrp
  179. (
  180. #if DBG
  181. IN PCHAR Owner
  182. #endif
  183. );
  184. void ReleaseMappingIrp
  185. (
  186. IN PIRP Irp,
  187. IN PPACKET_HEADER PacketHeader OPTIONAL
  188. );
  189. void ReleaseUnmappingIrp
  190. (
  191. IN PIRP Irp,
  192. IN PPACKET_HEADER PacketHeader OPTIONAL
  193. );
  194. NTSTATUS EnqueueMapping
  195. (
  196. IN PHYSICAL_ADDRESS PhysicalAddress,
  197. IN PIRP Irp,
  198. IN PPACKET_HEADER PacketHeader,
  199. IN PVOID VirtualAddress,
  200. IN ULONG ByteCount,
  201. IN ULONG Flags,
  202. IN PVOID MapRegisterBase,
  203. IN ULONG MappingStatus,
  204. IN PVOID SubpacketVa,
  205. IN ULONG SubpacketBytes
  206. );
  207. PMAPPING_QUEUE_ENTRY GetQueuedMapping
  208. ( void
  209. );
  210. PMAPPING_QUEUE_ENTRY DequeueMapping
  211. ( void
  212. );
  213. void
  214. CancelMappings
  215. (
  216. IN PIRP pIrp
  217. );
  218. void DbgQueues
  219. ( void
  220. );
  221. void
  222. ForwardIrpsInQueue
  223. (
  224. IN PLIST_ENTRY Queue,
  225. IN PKSPIN_LOCK SpinLock
  226. );
  227. public:
  228. DECLARE_STD_UNKNOWN();
  229. DEFINE_STD_CONSTRUCTOR(CIrpStream);
  230. ~CIrpStream();
  231. IMP_IIrpStreamVirtual;
  232. IMP_IIrpStreamPhysical_;
  233. PRKTHREAD m_CancelAllIrpsThread;
  234. /*************************************************************************
  235. * Friends
  236. */
  237. friend
  238. IO_ALLOCATION_ACTION
  239. CallbackFromIoAllocateAdapterChannel
  240. (
  241. IN PDEVICE_OBJECT DeviceObject,
  242. IN PIRP Reserved,
  243. IN PVOID MapRegisterBase,
  244. IN PVOID VoidContext
  245. );
  246. friend
  247. VOID
  248. IrpStreamCancelRoutine
  249. (
  250. IN PDEVICE_OBJECT DeviceObject,
  251. IN PIRP Irp
  252. );
  253. #ifdef PC_KDEXT
  254. // Debugger extension routines
  255. friend
  256. VOID
  257. PCKD_AcquireDeviceData
  258. (
  259. PDEVICE_CONTEXT DeviceContext,
  260. PLIST_ENTRY SubdeviceList,
  261. ULONG Flags
  262. );
  263. friend
  264. VOID
  265. PCKD_AcquireIrpStreamData
  266. (
  267. PVOID CurrentPinEntry,
  268. CIrpStream *RemoteIrpStream,
  269. CIrpStream *LocalIrpStream
  270. );
  271. #endif
  272. };
  273. /*****************************************************************************
  274. * CALLBACK_CONTEXT
  275. *****************************************************************************
  276. * Context for IoAllocateAdapterChannel() callback.
  277. */
  278. typedef struct
  279. {
  280. CIrpStream * IrpStream;
  281. // Used for BusMasterAdapterObject, WriteOperation, ApplyMappingConstraints(), EnqueueMapping()
  282. PPACKET_HEADER PacketHeader;
  283. // Used for MdlAddress, MapRegisterBase (out)
  284. // Queue references this also
  285. PIRP Irp;
  286. // Used for mapping cancellation
  287. KEVENT Event;
  288. // Used for partial mappings
  289. ULONG BytesThisMapping;
  290. // Used for partial mappings
  291. BOOL LastSubPacket;
  292. }
  293. CALLBACK_CONTEXT, *PCALLBACK_CONTEXT;
  294. #ifndef PC_KDEXT
  295. /*****************************************************************************
  296. * Factory.
  297. */
  298. #pragma code_seg("PAGE")
  299. /*****************************************************************************
  300. * CreateIrpStream()
  301. *****************************************************************************
  302. * Creates an IrpStream object.
  303. */
  304. NTSTATUS
  305. CreateIrpStream
  306. (
  307. OUT PUNKNOWN * Unknown,
  308. IN REFCLSID,
  309. IN PUNKNOWN UnknownOuter OPTIONAL,
  310. IN POOL_TYPE PoolType
  311. )
  312. {
  313. PAGED_CODE();
  314. ASSERT(Unknown);
  315. _DbgPrintF(DEBUGLVL_LIFETIME,("Creating IRPSTREAM"));
  316. STD_CREATE_BODY_( CIrpStream,
  317. Unknown,
  318. UnknownOuter,
  319. PoolType,
  320. PIRPSTREAMVIRTUAL );
  321. }
  322. /*****************************************************************************
  323. * PcNewIrpStreamVirtual()
  324. *****************************************************************************
  325. * Creates and initializes an IrpStream object with a virtual access
  326. * interface.
  327. */
  328. PORTCLASSAPI
  329. NTSTATUS
  330. NTAPI
  331. PcNewIrpStreamVirtual
  332. (
  333. OUT PIRPSTREAMVIRTUAL * OutIrpStreamVirtual,
  334. IN PUNKNOWN OuterUnknown OPTIONAL,
  335. IN BOOLEAN WriteOperation,
  336. IN PKSPIN_CONNECT PinConnect,
  337. IN PDEVICE_OBJECT DeviceObject
  338. )
  339. {
  340. PAGED_CODE();
  341. ASSERT(OutIrpStreamVirtual);
  342. ASSERT(PinConnect);
  343. ASSERT(DeviceObject);
  344. PUNKNOWN unknown;
  345. NTSTATUS ntStatus = CreateIrpStream( &unknown,
  346. GUID_NULL,
  347. OuterUnknown,
  348. NonPagedPool );
  349. if(NT_SUCCESS(ntStatus))
  350. {
  351. PIRPSTREAMVIRTUAL irpStream;
  352. ntStatus = unknown->QueryInterface( IID_IIrpStreamVirtual,
  353. (PVOID *) &irpStream );
  354. if(NT_SUCCESS(ntStatus))
  355. {
  356. ntStatus = irpStream->Init( WriteOperation,
  357. PinConnect,
  358. DeviceObject,
  359. NULL );
  360. if(NT_SUCCESS(ntStatus))
  361. {
  362. *OutIrpStreamVirtual = irpStream;
  363. }
  364. else
  365. {
  366. irpStream->Release();
  367. }
  368. }
  369. unknown->Release();
  370. }
  371. return ntStatus;
  372. }
  373. /*****************************************************************************
  374. * PcNewIrpStreamPhysical()
  375. *****************************************************************************
  376. * Creates and initializes an IrpStream object with a physical access
  377. * interface.
  378. */
  379. PORTCLASSAPI
  380. NTSTATUS
  381. NTAPI
  382. PcNewIrpStreamPhysical
  383. (
  384. OUT PIRPSTREAMPHYSICAL * OutIrpStreamPhysical,
  385. IN PUNKNOWN OuterUnknown OPTIONAL,
  386. IN BOOLEAN WriteOperation,
  387. IN PKSPIN_CONNECT PinConnect,
  388. IN PDEVICE_OBJECT DeviceObject,
  389. IN PADAPTER_OBJECT AdapterObject
  390. )
  391. {
  392. PAGED_CODE();
  393. ASSERT(OutIrpStreamPhysical);
  394. ASSERT(DeviceObject);
  395. ASSERT(AdapterObject);
  396. PUNKNOWN unknown;
  397. NTSTATUS ntStatus = CreateIrpStream( &unknown,
  398. GUID_NULL,
  399. OuterUnknown,
  400. NonPagedPool );
  401. if(NT_SUCCESS(ntStatus))
  402. {
  403. PIRPSTREAMPHYSICAL irpStream;
  404. ntStatus = unknown->QueryInterface( IID_IIrpStreamPhysical,
  405. (PVOID *) &irpStream );
  406. if(NT_SUCCESS(ntStatus))
  407. {
  408. ntStatus = irpStream->Init( WriteOperation,
  409. PinConnect,
  410. DeviceObject,
  411. AdapterObject );
  412. if(NT_SUCCESS(ntStatus))
  413. {
  414. *OutIrpStreamPhysical = irpStream;
  415. }
  416. else
  417. {
  418. irpStream->Release();
  419. }
  420. }
  421. unknown->Release();
  422. }
  423. return ntStatus;
  424. }
  425. /*****************************************************************************
  426. * Member functions.
  427. */
  428. /*****************************************************************************
  429. * CIrpStream::~CIrpStream()
  430. *****************************************************************************
  431. * Destructor.
  432. */
  433. CIrpStream::
  434. ~CIrpStream
  435. ( void
  436. )
  437. {
  438. PAGED_CODE();
  439. _DbgPrintF(DEBUGLVL_LIFETIME,("Destroying IRPSTREAM (0x%08x)",this));
  440. CancelAllIrps( TRUE ); // reset position counters
  441. if(Notify)
  442. {
  443. Notify->Release();
  444. }
  445. if(NotifyPhysical)
  446. {
  447. NotifyPhysical->Release();
  448. }
  449. if(MappingQueue.Array)
  450. {
  451. ExFreePool(MappingQueue.Array);
  452. }
  453. }
  454. /*****************************************************************************
  455. * CIrpStream::NonDelegatingQueryInterface()
  456. *****************************************************************************
  457. * Obtains an interface.
  458. */
  459. STDMETHODIMP_(NTSTATUS)
  460. CIrpStream::
  461. NonDelegatingQueryInterface
  462. (
  463. REFIID Interface,
  464. PVOID * Object
  465. )
  466. {
  467. PAGED_CODE();
  468. ASSERT(Object);
  469. if(IsEqualGUIDAligned(Interface,IID_IUnknown))
  470. {
  471. *Object = PVOID(PUNKNOWN(PIRPSTREAMVIRTUAL(this)));
  472. }
  473. else
  474. if(IsEqualGUIDAligned(Interface,IID_IIrpStreamSubmit))
  475. {
  476. *Object = PVOID(PIRPSTREAMSUBMIT(PIRPSTREAMVIRTUAL(this)));
  477. }
  478. else
  479. if(IsEqualGUIDAligned(Interface,IID_IIrpStream))
  480. {
  481. *Object = PVOID(PIRPSTREAM(PIRPSTREAMVIRTUAL(this)));
  482. }
  483. else
  484. if(IsEqualGUIDAligned(Interface,IID_IKsShellTransport))
  485. {
  486. *Object = PVOID(PIKSSHELLTRANSPORT(PIRPSTREAMVIRTUAL(this)));
  487. }
  488. else
  489. if(IsEqualGUIDAligned(Interface,IID_IIrpStreamVirtual))
  490. {
  491. // Only valid if not configured for physical access.
  492. if(BusMasterAdapterObject)
  493. {
  494. *Object = NULL;
  495. }
  496. else
  497. {
  498. *Object = QICAST(PIRPSTREAMVIRTUAL);
  499. }
  500. }
  501. else
  502. if(IsEqualGUIDAligned(Interface,IID_IIrpStreamPhysical))
  503. {
  504. // Only valid if configured for physical access or uninitialized.
  505. if(BusMasterAdapterObject || (ProbeFlags == 0))
  506. {
  507. *Object = QICAST(PIRPSTREAMPHYSICAL);
  508. }
  509. else
  510. {
  511. *Object = NULL;
  512. }
  513. }
  514. else
  515. {
  516. *Object = NULL;
  517. }
  518. if(*Object)
  519. {
  520. PUNKNOWN(*Object)->AddRef();
  521. return STATUS_SUCCESS;
  522. }
  523. return STATUS_INVALID_PARAMETER;
  524. }
  525. /*****************************************************************************
  526. * GetPartialMdlCountForMdl()
  527. *****************************************************************************
  528. * Determine number of partial MDLs that are required for a source MDL.
  529. */
  530. ULONG
  531. GetPartialMdlCountForMdl
  532. (
  533. IN PVOID Va,
  534. IN ULONG Size
  535. )
  536. {
  537. ULONG result = 1;
  538. if(Size > WHOLE_MDL_THRESHOLD)
  539. {
  540. ULONG pageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Va,Size);
  541. if(BYTE_OFFSET(Va) > PRE_OFFSET_THRESHOLD)
  542. {
  543. pageCount--;
  544. }
  545. if(BYTE_OFFSET(PVOID(PBYTE(Va) + Size - 1)) < POST_OFFSET_THRESHOLD)
  546. {
  547. pageCount--;
  548. }
  549. result = (pageCount + MAX_PAGES_PER_MDL - 1) / MAX_PAGES_PER_MDL;
  550. }
  551. return result;
  552. }
  553. STDMETHODIMP_(NTSTATUS)
  554. CIrpStream::
  555. TransferKsIrp
  556. (
  557. IN PIRP Irp,
  558. OUT PIKSSHELLTRANSPORT* NextTransport
  559. )
  560. /*++
  561. Routine Description:
  562. This routine handles the arrival of a streaming IRP via the shell
  563. transport.
  564. Arguments:
  565. Irp -
  566. Contains a pointer to the streaming IRP submitted to the queue.
  567. NextTransport -
  568. Contains a pointer to a location at which to deposit a pointer
  569. to the next transport interface to receive the IRP. May be set
  570. to NULL indicating the IRP should not be forwarded further.
  571. Return Value:
  572. STATUS_SUCCESS, STATUS_PENDING or some error status.
  573. --*/
  574. {
  575. ASSERT(Irp);
  576. ASSERT(NextTransport);
  577. ASSERT(m_TransportSink);
  578. ASSERT(m_TransportSource);
  579. //
  580. // Shunt IRPs to the next object if we are not ready.
  581. //
  582. if(m_Flushing || (m_ksState == KSSTATE_STOP) || Irp->Cancel ||
  583. ! NT_SUCCESS(Irp->IoStatus.Status))
  584. {
  585. *NextTransport = m_TransportSink;
  586. return STATUS_SUCCESS;
  587. }
  588. //
  589. // Not smart enough to do this yet.
  590. //
  591. *NextTransport = NULL;
  592. //
  593. // Prepare the IRP using KS's handiest function.
  594. //
  595. NTSTATUS ntStatus;
  596. if(ProbeFlags)
  597. {
  598. ntStatus = KsProbeStreamIrp( Irp,
  599. ProbeFlags,
  600. sizeof(KSSTREAM_HEADER) );
  601. }
  602. else
  603. {
  604. ntStatus = STATUS_SUCCESS;
  605. }
  606. PIRP_CONTEXT irpContext;
  607. if(NT_SUCCESS(ntStatus))
  608. {
  609. ntStatus = STATUS_PENDING;
  610. ULONG packetCount = 0;
  611. //
  612. // Count the number of 'packet headers' we will be needing.
  613. //
  614. PKSSTREAM_HEADER streamHeader = FIRST_STREAM_HEADER_IRP_STORAGE(Irp);
  615. if( (!streamHeader->DataUsed && WriteOperation) ||
  616. (!streamHeader->FrameExtent && !WriteOperation) )
  617. {
  618. //
  619. // At least one for the Irp context.
  620. //
  621. packetCount = 1;
  622. }
  623. else
  624. {
  625. for(PMDL mdl = Irp->MdlAddress; mdl; mdl = mdl->Next, streamHeader++)
  626. {
  627. if(JustInTime)
  628. {
  629. packetCount += GetPartialMdlCountForMdl(
  630. #ifdef UNDER_NT
  631. MmGetSystemAddressForMdlSafe(mdl,HighPagePriority),
  632. #else
  633. MmGetSystemAddressForMdl(mdl),
  634. #endif
  635. ( WriteOperation ?
  636. streamHeader->DataUsed :
  637. streamHeader->FrameExtent ) );
  638. }
  639. else
  640. {
  641. packetCount++;
  642. }
  643. }
  644. }
  645. irpContext = PIRP_CONTEXT( ExAllocatePoolWithTag( NonPagedPool,
  646. ( sizeof(IRP_CONTEXT) +
  647. ( sizeof(PACKET_HEADER) *
  648. (packetCount - 1) ) ),
  649. POOL_TAG_IRPSTREAM_IRP_CONTEXT ) );
  650. if(irpContext)
  651. {
  652. IRP_CONTEXT_IRP_STORAGE(Irp) = irpContext;
  653. }
  654. else
  655. {
  656. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  657. }
  658. }
  659. if(NT_SUCCESS(ntStatus))
  660. {
  661. irpContext->SubmissionProcess = IoGetCurrentProcess();
  662. irpContext->LockingPacket =
  663. irpContext->MappingPacket =
  664. irpContext->UnmappingPacket = &irpContext->Packets[0];
  665. irpContext->IrpStream = PVOID(this);
  666. #if (DBG)
  667. irpContext->IrpLabel = IrpLabel++;
  668. #endif
  669. PKSSTREAM_HEADER streamHeader = FIRST_STREAM_HEADER_IRP_STORAGE(Irp);
  670. PPACKET_HEADER packetHeader = &irpContext->Packets[0];
  671. PPACKET_HEADER firstLooped = NULL;
  672. PPACKET_HEADER prevLooped = NULL;
  673. if( (!streamHeader->DataUsed && WriteOperation) ||
  674. (!streamHeader->FrameExtent && !WriteOperation) )
  675. {
  676. RtlZeroMemory( packetHeader, sizeof( PACKET_HEADER ) );
  677. packetHeader->MapCount = 1;
  678. packetHeader->StreamHeader = streamHeader;
  679. packetHeader->InputPosition = InputPosition;
  680. packetHeader->OutputPosition = OutputPosition;
  681. }
  682. else
  683. {
  684. for(PMDL mdl = Irp->MdlAddress;
  685. mdl && NT_SUCCESS(ntStatus);
  686. mdl = mdl->Next, streamHeader++)
  687. {
  688. ULONG bytesRemaining = ( WriteOperation ?
  689. streamHeader->DataUsed :
  690. streamHeader->FrameExtent );
  691. m_irpStreamPosition.ullCurrentExtent += bytesRemaining;
  692. BOOLEAN createPartials = ( JustInTime &&
  693. ( bytesRemaining > WHOLE_MDL_THRESHOLD ) );
  694. ULONG currentOffset = MmGetMdlByteOffset(mdl);
  695. #ifdef UNDER_NT
  696. PVOID currentVA = MmGetSystemAddressForMdlSafe(mdl,HighPagePriority);
  697. #else
  698. PVOID currentVA = MmGetSystemAddressForMdl(mdl);
  699. #endif
  700. while(bytesRemaining)
  701. {
  702. PMDL partialMdl;
  703. ULONG partialMdlSize;
  704. if(! createPartials)
  705. {
  706. partialMdl = mdl;
  707. partialMdlSize = bytesRemaining;
  708. }
  709. else
  710. {
  711. ASSERT(!"Trying to create partials");
  712. #if 0
  713. partialMdlSize = MAX_PAGES_PER_MDL * PAGE_SIZE;
  714. if(currentOffset)
  715. {
  716. //
  717. // Handle initial offset.
  718. //
  719. partialMdlSize -= currentOffset;
  720. if(currentOffset > PRE_OFFSET_THRESHOLD)
  721. {
  722. partialMdlSize += PAGE_SIZE;
  723. }
  724. currentOffset = 0;
  725. }
  726. else
  727. if(partialMdlSize > bytesRemaining)
  728. {
  729. partialMdlSize = bytesRemaining;
  730. }
  731. ASSERT(partialMdlSize <= bytesRemaining);
  732. partialMdl = IoAllocateMdl( currentVA,
  733. partialMdlSize,
  734. FALSE,
  735. FALSE,
  736. NULL );
  737. if(partialMdl)
  738. {
  739. IoBuildPartialMdl( mdl,
  740. partialMdl,
  741. currentVA,
  742. partialMdlSize );
  743. }
  744. else
  745. {
  746. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  747. break;
  748. }
  749. #endif
  750. }
  751. bytesRemaining -= partialMdlSize;
  752. currentVA = PVOID(PBYTE(currentVA) + partialMdlSize);
  753. if( streamHeader->OptionsFlags
  754. & KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA
  755. )
  756. {
  757. if(prevLooped)
  758. {
  759. // Point the previous looped packet to this one.
  760. prevLooped->Next = packetHeader;
  761. }
  762. else
  763. {
  764. // No previous looped packet.
  765. firstLooped = packetHeader;
  766. }
  767. prevLooped = packetHeader;
  768. }
  769. packetHeader->StreamHeader = streamHeader;
  770. packetHeader->MdlAddress = partialMdl;
  771. packetHeader->BytesTotal = partialMdlSize;
  772. packetHeader->MapPosition = 0;
  773. packetHeader->UnmapPosition = 0;
  774. packetHeader->MapCount =
  775. (packetHeader == &irpContext->Packets[0]) ? 1 : 0;
  776. packetHeader->IncrementMapping =
  777. packetHeader->IncrementUnmapping =
  778. (mdl->Next != NULL) || bytesRemaining;
  779. packetHeader->Next = firstLooped;
  780. packetHeader->InputPosition = InputPosition;
  781. packetHeader->OutputPosition = OutputPosition;
  782. InputPosition += packetHeader->BytesTotal;
  783. packetHeader++;
  784. }
  785. }
  786. }
  787. _DbgPrintF(DEBUGLVL_BLAB,("AddIrp() IRP %d 0x%8x",IrpLabel,Irp));
  788. IoMarkIrpPending(Irp);
  789. if(JustInTime)
  790. {
  791. // PreLockQueue feeds JustInTime thread.
  792. KsAddIrpToCancelableQueue( &PreLockQueue,
  793. &PreLockQueueLock,
  794. Irp,
  795. KsListEntryTail,
  796. KsCancelRoutine );
  797. }
  798. else
  799. {
  800. // IRP is locked down in advance and ready to map.
  801. KsAddIrpToCancelableQueue( &LockedQueue,
  802. &LockedQueueLock,
  803. Irp,
  804. KsListEntryTail,
  805. IrpStreamCancelRoutine );
  806. }
  807. }
  808. if(NT_SUCCESS(ntStatus))
  809. {
  810. // need to change WasExhausted BEFORE notifying the sink since
  811. // notifying the sink may result in starvation again.
  812. BOOLEAN TempWasExhausted = WasExhausted;
  813. WasExhausted = FALSE;
  814. if(Notify)
  815. {
  816. Notify->IrpSubmitted(Irp,TempWasExhausted);
  817. }
  818. else
  819. if(NotifyPhysical)
  820. {
  821. NotifyPhysical->IrpSubmitted(Irp,TempWasExhausted);
  822. }
  823. ntStatus = STATUS_PENDING;
  824. }
  825. return ntStatus;
  826. }
  827. #pragma code_seg()
  828. /*****************************************************************************
  829. * CIrpStream::GetPosition()
  830. *****************************************************************************
  831. * Gets the current position.
  832. */
  833. STDMETHODIMP_(NTSTATUS)
  834. CIrpStream::
  835. GetPosition
  836. (
  837. OUT PIRPSTREAM_POSITION pIrpStreamPosition
  838. )
  839. {
  840. NTSTATUS ntStatus = STATUS_SUCCESS;
  841. KIRQL oldIrql;
  842. KeAcquireSpinLock(&m_irpStreamPositionLock, &oldIrql );
  843. *pIrpStreamPosition = m_irpStreamPosition;
  844. //
  845. // Assume stream position and unmapping position are the same.
  846. //
  847. pIrpStreamPosition->ullStreamPosition = pIrpStreamPosition->ullUnmappingPosition;
  848. //
  849. // Assume no physical offset.
  850. //
  851. pIrpStreamPosition->ullPhysicalOffset = 0;
  852. //
  853. // Give the notification sink a chance to modify the position.
  854. //
  855. if(Notify)
  856. {
  857. ntStatus = Notify->GetPosition(pIrpStreamPosition);
  858. }
  859. else
  860. if(NotifyPhysical)
  861. {
  862. ntStatus = NotifyPhysical->GetPosition(pIrpStreamPosition);
  863. }
  864. KeReleaseSpinLock(&m_irpStreamPositionLock, oldIrql);
  865. return ntStatus;
  866. }
  867. #pragma code_seg("PAGE")
  868. STDMETHODIMP_(void)
  869. CIrpStream::
  870. Connect
  871. (
  872. IN PIKSSHELLTRANSPORT NewTransport OPTIONAL,
  873. OUT PIKSSHELLTRANSPORT *OldTransport OPTIONAL,
  874. IN KSPIN_DATAFLOW DataFlow
  875. )
  876. /*++
  877. Routine Description:
  878. This routine establishes a shell transport connect.
  879. Arguments:
  880. Return Value:
  881. --*/
  882. {
  883. _DbgPrintF(DEBUGLVL_BLAB,("CIrpStream::Connect"));
  884. PAGED_CODE();
  885. KsShellStandardConnect( NewTransport,
  886. OldTransport,
  887. DataFlow,
  888. PIKSSHELLTRANSPORT(PIRPSTREAMVIRTUAL(this)),
  889. &m_TransportSource,
  890. &m_TransportSink);
  891. }
  892. STDMETHODIMP_(NTSTATUS)
  893. CIrpStream::
  894. SetDeviceState
  895. (
  896. IN KSSTATE NewState,
  897. IN KSSTATE OldState,
  898. OUT PIKSSHELLTRANSPORT* NextTransport
  899. )
  900. /*++
  901. Routine Description:
  902. This routine handles notification that the device state has changed.
  903. Arguments:
  904. Return Value:
  905. --*/
  906. {
  907. _DbgPrintF(DEBUGLVL_BLAB,("CIrpStream::SetDeviceState"));
  908. PAGED_CODE();
  909. ASSERT(NextTransport);
  910. if(m_ksState != NewState)
  911. {
  912. m_ksState = NewState;
  913. _DbgPrintF(DEBUGLVL_VERBOSE,("#### IrpStream%p.SetDeviceState: from %d to %d (%d,%d)",this,OldState,NewState,IsListEmpty(&LockedQueue),IsListEmpty(&MappedQueue)));
  914. if(NewState > OldState)
  915. {
  916. *NextTransport = m_TransportSink;
  917. }
  918. else
  919. {
  920. *NextTransport = m_TransportSource;
  921. }
  922. if(NewState == KSSTATE_STOP)
  923. {
  924. if(! WriteOperation)
  925. {
  926. TerminatePacket();
  927. }
  928. CancelAllIrps(TRUE);
  929. }
  930. //
  931. // Adjust the active pin count
  932. //
  933. if( (NewState == KSSTATE_RUN) && (OldState != KSSTATE_RUN) )
  934. {
  935. UpdateActivePinCount( PDEVICE_CONTEXT(FunctionalDeviceObject->DeviceExtension),
  936. TRUE );
  937. // Adjust the stream base position
  938. if(NotifyPhysical)
  939. {
  940. NTSTATUS ntStatus = NotifyPhysical->GetPosition(&m_irpStreamPosition);
  941. if( NT_SUCCESS(ntStatus) )
  942. {
  943. m_irpStreamPosition.ullStreamOffset = m_irpStreamPosition.ullStreamPosition -
  944. m_irpStreamPosition.ullUnmappingPosition;
  945. }
  946. }
  947. }
  948. else
  949. {
  950. if( (NewState != KSSTATE_RUN) && (OldState == KSSTATE_RUN) )
  951. {
  952. UpdateActivePinCount( PDEVICE_CONTEXT(FunctionalDeviceObject->DeviceExtension),
  953. FALSE );
  954. }
  955. }
  956. }
  957. else
  958. {
  959. *NextTransport = NULL;
  960. }
  961. return STATUS_SUCCESS;
  962. }
  963. STDMETHODIMP_(void)
  964. CIrpStream::
  965. SetResetState
  966. (
  967. IN KSRESET ksReset,
  968. OUT PIKSSHELLTRANSPORT* NextTransport
  969. )
  970. /*++
  971. Routine Description:
  972. This routine handles notification that the reset state has changed.
  973. Arguments:
  974. Return Value:
  975. --*/
  976. {
  977. _DbgPrintF(DEBUGLVL_BLAB,("CIrpStream::SetResetState"));
  978. PAGED_CODE();
  979. ASSERT(NextTransport);
  980. //
  981. // Take no action if we were already in this state.
  982. //
  983. if(m_Flushing != (ksReset == KSRESET_BEGIN))
  984. {
  985. //
  986. // Tell the caller to forward the state change to our sink.
  987. //
  988. *NextTransport = m_TransportSink;
  989. //
  990. // Set our local copy of the state.
  991. //
  992. m_Flushing = (ksReset == KSRESET_BEGIN);
  993. //
  994. // Flush the queues if we are beginning a reset.
  995. //
  996. if(m_Flushing)
  997. {
  998. CancelAllIrps(TRUE);
  999. }
  1000. }
  1001. else
  1002. {
  1003. *NextTransport = NULL;
  1004. }
  1005. }
  1006. /*****************************************************************************
  1007. * CIrpStream::Init()
  1008. *****************************************************************************
  1009. * Initializes the object.
  1010. */
  1011. STDMETHODIMP_(NTSTATUS)
  1012. CIrpStream::
  1013. Init
  1014. (
  1015. IN BOOLEAN WriteOperation_,
  1016. IN PKSPIN_CONNECT PinConnect,
  1017. IN PDEVICE_OBJECT DeviceObject,
  1018. IN PADAPTER_OBJECT AdapterObject OPTIONAL
  1019. )
  1020. {
  1021. PAGED_CODE();
  1022. _DbgPrintF(DEBUGLVL_LIFETIME,("Initializing IRPSTREAM (0x%08x)",this));
  1023. ASSERT(DeviceObject);
  1024. NTSTATUS ntStatus = STATUS_SUCCESS;
  1025. #if (DBG)
  1026. timeStep = PcGetTimeInterval(0);
  1027. irpCompleteCount = 0;
  1028. #endif
  1029. m_ksState = KSSTATE_STOP;
  1030. m_irpStreamPosition.bLoopedInterface =
  1031. ( PinConnect->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING );
  1032. InputPosition = 0;
  1033. OutputPosition = 0;
  1034. WriteOperation = WriteOperation_;
  1035. JustInTime = FALSE;
  1036. FunctionalDeviceObject = DeviceObject;
  1037. BusMasterAdapterObject = AdapterObject;
  1038. ProbeFlags = (( WriteOperation ?
  1039. KSPROBE_STREAMWRITE :
  1040. KSPROBE_STREAMREAD ) |
  1041. KSPROBE_ALLOCATEMDL );
  1042. WasExhausted = TRUE;
  1043. #if (DBG)
  1044. MappingsOutstanding = 0;
  1045. MappingsQueued = 0;
  1046. #endif
  1047. KeInitializeSpinLock(&m_kSpinLock);
  1048. KeInitializeSpinLock(&m_RevokeLock);
  1049. KeInitializeSpinLock(&m_irpStreamPositionLock);
  1050. m_CancelAllIrpsThread = NULL;
  1051. if(JustInTime)
  1052. {
  1053. InitializeListHead(&PreLockQueue);
  1054. KeInitializeSpinLock(&PreLockQueueLock);
  1055. }
  1056. else
  1057. {
  1058. ProbeFlags |= KSPROBE_PROBEANDLOCK | KSPROBE_SYSTEMADDRESS;
  1059. }
  1060. InitializeListHead(&LockedQueue);
  1061. KeInitializeSpinLock(&LockedQueueLock);
  1062. InitializeListHead(&MappedQueue);
  1063. KeInitializeSpinLock(&MappedQueueLock);
  1064. //
  1065. // Source pins don't need to probe because the requestor does it for us.
  1066. //
  1067. if(PinConnect->PinToHandle)
  1068. {
  1069. ProbeFlags = 0;
  1070. }
  1071. // allocate the mapping array
  1072. if(BusMasterAdapterObject)
  1073. {
  1074. MappingQueue.Array = PMAPPING_QUEUE_ENTRY( ExAllocatePoolWithTag( NonPagedPool,
  1075. sizeof(MAPPING_QUEUE_ENTRY) * MAPPING_QUEUE_SIZE,
  1076. 'qMcP' ) );
  1077. if(! MappingQueue.Array)
  1078. {
  1079. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1080. }
  1081. }
  1082. return ntStatus;
  1083. }
  1084. #pragma code_seg()
  1085. void
  1086. CIrpStream::
  1087. ForwardIrpsInQueue
  1088. (
  1089. IN PLIST_ENTRY Queue,
  1090. IN PKSPIN_LOCK SpinLock
  1091. )
  1092. /*++
  1093. Routine Description:
  1094. This routine forwards all the IRPs in a queue via the shell transport.
  1095. Arguments:
  1096. Return Value:
  1097. --*/
  1098. {
  1099. _DbgPrintF(DEBUGLVL_BLAB,("CIrpStream::ForwardIrpsInQueue"));
  1100. ASSERT(Queue);
  1101. ASSERT(SpinLock);
  1102. while(1)
  1103. {
  1104. PIRP irp = KsRemoveIrpFromCancelableQueue( Queue,
  1105. SpinLock,
  1106. KsListEntryHead,
  1107. KsAcquireAndRemoveOnlySingleItem );
  1108. if(! irp)
  1109. {
  1110. break;
  1111. }
  1112. // TODO: what about revoking the mappings?
  1113. //
  1114. // Forward the IRP to the next object.
  1115. //
  1116. if( IRP_CONTEXT_IRP_STORAGE(irp) )
  1117. {
  1118. _DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpsInQueue Freeing non-null context (0x%08x) for IRP (0x%08x)",IRP_CONTEXT_IRP_STORAGE(irp),irp));
  1119. ExFreePool(IRP_CONTEXT_IRP_STORAGE(irp));
  1120. IRP_CONTEXT_IRP_STORAGE(irp) = NULL;
  1121. }
  1122. KsShellTransferKsIrp(m_TransportSink,irp);
  1123. }
  1124. }
  1125. /*****************************************************************************
  1126. * CIrpStream::CancelAllIrps()
  1127. *****************************************************************************
  1128. * Cancel all IRPs.
  1129. */
  1130. STDMETHODIMP_(void)
  1131. CIrpStream::CancelAllIrps
  1132. (
  1133. IN BOOL ClearPositionCounters
  1134. )
  1135. {
  1136. _DbgPrintF(DEBUGLVL_VERBOSE,("CIrpStream::CancelAllIrps ClearPositionCounters=%s",ClearPositionCounters ? "TRUE" : "FALSE"));
  1137. KIRQL kIrqlOldRevoke;
  1138. KIRQL kIrqlOldMaster;
  1139. // grab the revoke spinlock (must always grab this BEFORE the master spinlock)
  1140. KeAcquireSpinLock(&m_RevokeLock, &kIrqlOldRevoke);
  1141. // grab the master spinlock
  1142. KeAcquireSpinLock(&m_kSpinLock, &kIrqlOldMaster);
  1143. // remember this so we won't re-acquire the two locks at CancelMapping in this context
  1144. m_CancelAllIrpsThread = KeGetCurrentThread();
  1145. if(ProbeFlags)
  1146. {
  1147. if(JustInTime)
  1148. {
  1149. KsCancelIo( &PreLockQueue,
  1150. &PreLockQueueLock );
  1151. }
  1152. KsCancelIo( &LockedQueue,
  1153. &LockedQueueLock );
  1154. KsCancelIo( &MappedQueue,
  1155. &MappedQueueLock );
  1156. }
  1157. else
  1158. {
  1159. ForwardIrpsInQueue( &MappedQueue,
  1160. &MappedQueueLock );
  1161. ForwardIrpsInQueue( &LockedQueue,
  1162. &LockedQueueLock );
  1163. if(JustInTime)
  1164. {
  1165. ForwardIrpsInQueue( &PreLockQueue,
  1166. &PreLockQueueLock );
  1167. }
  1168. }
  1169. //
  1170. // clear the input and output position counts
  1171. //
  1172. BOOLEAN bLooped = m_irpStreamPosition.bLoopedInterface;
  1173. ULONGLONG ullStreamOffset = m_irpStreamPosition.ullStreamOffset;
  1174. RtlZeroMemory(&m_irpStreamPosition,sizeof(m_irpStreamPosition));
  1175. m_irpStreamPosition.bLoopedInterface = bLooped;
  1176. m_irpStreamPosition.ullStreamOffset = ullStreamOffset;
  1177. if(ClearPositionCounters)
  1178. {
  1179. InputPosition = 0;
  1180. OutputPosition = 0;
  1181. }
  1182. // release the spinlocks, master first
  1183. m_CancelAllIrpsThread = NULL;
  1184. KeReleaseSpinLock(&m_kSpinLock, kIrqlOldMaster);
  1185. KeReleaseSpinLock(&m_RevokeLock, kIrqlOldRevoke);
  1186. }
  1187. /*****************************************************************************
  1188. * CIrpStream::TerminatePacket()
  1189. *****************************************************************************
  1190. * Bypasses all reamining mappings for the current packet.
  1191. */
  1192. STDMETHODIMP_(void)
  1193. CIrpStream::
  1194. TerminatePacket
  1195. ( void
  1196. )
  1197. {
  1198. if(BusMasterAdapterObject)
  1199. {
  1200. // TODO: What do we do for PCI?
  1201. }
  1202. else
  1203. {
  1204. PIRP irp = DbgAcquireUnmappingIrp("TerminatePacket");
  1205. if(irp)
  1206. {
  1207. PPACKET_HEADER packetHeader = IRP_CONTEXT_IRP_STORAGE(irp)->UnmappingPacket;
  1208. //
  1209. // The mapping window should be closed.
  1210. //
  1211. if( (packetHeader->MapCount == 1) &&
  1212. (packetHeader->MapPosition == packetHeader->UnmapPosition) &&
  1213. (packetHeader->MapPosition != 0) )
  1214. {
  1215. //
  1216. // Adjust for unused extent.
  1217. //
  1218. if(m_irpStreamPosition.ullCurrentExtent != ULONGLONG(-1))
  1219. {
  1220. m_irpStreamPosition.ullCurrentExtent +=
  1221. packetHeader->UnmapPosition;
  1222. m_irpStreamPosition.ullCurrentExtent -=
  1223. packetHeader->BytesTotal;
  1224. }
  1225. //
  1226. // We are not at the start of the packet, and this packet
  1227. // should be terminated. The adjusted BytesTotal will get
  1228. // copied back into DataUsed in the stream header.
  1229. //
  1230. packetHeader->BytesTotal = packetHeader->UnmapPosition;
  1231. }
  1232. else
  1233. {
  1234. //
  1235. // We are at the start of the packet or the packet window is
  1236. // not closed.
  1237. //
  1238. packetHeader = NULL;
  1239. }
  1240. ReleaseUnmappingIrp(irp,packetHeader);
  1241. }
  1242. }
  1243. }
  1244. /*****************************************************************************
  1245. * CIrpStream::ChangeOptionsFlags()
  1246. *****************************************************************************
  1247. * Change the flags for the current mapping and unmapping IRPs.
  1248. *
  1249. * "Mapping" IRP is the packet currently submitted to the device
  1250. * "Unmapping" IRP is the packet currently completed by the device
  1251. */
  1252. STDMETHODIMP_(NTSTATUS)
  1253. CIrpStream::
  1254. ChangeOptionsFlags
  1255. (
  1256. IN ULONG MappingOrMask,
  1257. IN ULONG MappingAndMask,
  1258. IN ULONG UnmappingOrMask,
  1259. IN ULONG UnmappingAndMask
  1260. )
  1261. {
  1262. PIRP pIrp;
  1263. PPACKET_HEADER pPacketHeader;
  1264. ULONG oldOptionsFlags;
  1265. NTSTATUS ntStatus = STATUS_SUCCESS;
  1266. if((MappingOrMask) || (~MappingAndMask))
  1267. {
  1268. pIrp = DbgAcquireMappingIrp("ChangeOptionsFlags",FALSE);
  1269. if(pIrp)
  1270. {
  1271. pPacketHeader = IRP_CONTEXT_IRP_STORAGE(pIrp)->MappingPacket;
  1272. if((pPacketHeader) && (pPacketHeader->StreamHeader))
  1273. {
  1274. oldOptionsFlags = pPacketHeader->StreamHeader->OptionsFlags;
  1275. oldOptionsFlags |= MappingOrMask;
  1276. oldOptionsFlags &= MappingAndMask;
  1277. pPacketHeader->StreamHeader->OptionsFlags = oldOptionsFlags;
  1278. }
  1279. else
  1280. ntStatus = STATUS_UNSUCCESSFUL;
  1281. ReleaseMappingIrp(pIrp,NULL);
  1282. }
  1283. else
  1284. {
  1285. ntStatus = STATUS_UNSUCCESSFUL;
  1286. }
  1287. }
  1288. if((UnmappingOrMask) || (~UnmappingAndMask))
  1289. {
  1290. pIrp = DbgAcquireUnmappingIrp("ChangeOptionsFlags");
  1291. if(pIrp)
  1292. {
  1293. pPacketHeader = IRP_CONTEXT_IRP_STORAGE(pIrp)->UnmappingPacket;
  1294. if((pPacketHeader) && (pPacketHeader->StreamHeader))
  1295. {
  1296. oldOptionsFlags = pPacketHeader->StreamHeader->OptionsFlags;
  1297. oldOptionsFlags |= UnmappingOrMask;
  1298. oldOptionsFlags &= UnmappingAndMask;
  1299. pPacketHeader->StreamHeader->OptionsFlags = oldOptionsFlags;
  1300. }
  1301. else
  1302. ntStatus = STATUS_UNSUCCESSFUL;
  1303. ReleaseUnmappingIrp(pIrp,NULL);
  1304. }
  1305. else
  1306. {
  1307. ntStatus = STATUS_UNSUCCESSFUL;
  1308. }
  1309. }
  1310. return ntStatus;
  1311. }
  1312. /*****************************************************************************
  1313. * CIrpStream::GetPacketInfo()
  1314. *****************************************************************************
  1315. * Get information about the current packet.
  1316. *
  1317. * "Mapping" information is the packet information currently
  1318. * submitted to the device
  1319. * "Unmapping" information is the packet information currently
  1320. * completed by the device
  1321. *
  1322. * OutputPosition is the unrolled position of the stream, e.g. the total
  1323. * number of bytes to the device.
  1324. * InputPosition is the position within the data not include the unrolled
  1325. * loops.
  1326. */
  1327. STDMETHODIMP_(NTSTATUS)
  1328. CIrpStream::
  1329. GetPacketInfo
  1330. (
  1331. OUT PIRPSTREAMPACKETINFO Mapping OPTIONAL,
  1332. OUT PIRPSTREAMPACKETINFO Unmapping OPTIONAL
  1333. )
  1334. {
  1335. NTSTATUS ntStatus = STATUS_SUCCESS;
  1336. if(Mapping)
  1337. {
  1338. PIRP irp = DbgAcquireMappingIrp("GetPacketInfo",FALSE);
  1339. if(irp)
  1340. {
  1341. PPACKET_HEADER packetHeader =
  1342. IRP_CONTEXT_IRP_STORAGE(irp)->MappingPacket;
  1343. Mapping->Header = *packetHeader->StreamHeader;
  1344. Mapping->InputPosition = packetHeader->InputPosition;
  1345. Mapping->OutputPosition = packetHeader->OutputPosition;
  1346. Mapping->CurrentOffset = packetHeader->MapPosition;
  1347. ReleaseMappingIrp(irp,NULL);
  1348. }
  1349. else
  1350. {
  1351. RtlZeroMemory(&Mapping->Header,sizeof(KSSTREAM_HEADER));
  1352. Mapping->InputPosition = InputPosition;
  1353. Mapping->OutputPosition = OutputPosition;
  1354. Mapping->CurrentOffset = 0;
  1355. }
  1356. }
  1357. if(NT_SUCCESS(ntStatus) && Unmapping)
  1358. {
  1359. PIRP irp = DbgAcquireUnmappingIrp("GetPacketInfo");
  1360. if(irp)
  1361. {
  1362. PPACKET_HEADER packetHeader =
  1363. IRP_CONTEXT_IRP_STORAGE(irp)->MappingPacket;
  1364. Unmapping->Header = *packetHeader->StreamHeader;
  1365. Unmapping->InputPosition = packetHeader->InputPosition;
  1366. Unmapping->OutputPosition = packetHeader->OutputPosition;
  1367. Unmapping->CurrentOffset = packetHeader->UnmapPosition;
  1368. ReleaseUnmappingIrp(irp,NULL);
  1369. }
  1370. else
  1371. {
  1372. RtlZeroMemory(&Unmapping->Header,sizeof(KSSTREAM_HEADER));
  1373. Unmapping->InputPosition = InputPosition;
  1374. Unmapping->OutputPosition = OutputPosition;
  1375. Unmapping->CurrentOffset = 0;
  1376. }
  1377. }
  1378. return ntStatus;
  1379. }
  1380. /*****************************************************************************
  1381. * CIrpStream::SetPacketOffsets()
  1382. *****************************************************************************
  1383. * Set packet mapping and unmapping offsets to a specified value.
  1384. */
  1385. STDMETHODIMP_(NTSTATUS)
  1386. CIrpStream::
  1387. SetPacketOffsets
  1388. (
  1389. IN ULONG MappingOffset,
  1390. IN ULONG UnmappingOffset
  1391. )
  1392. {
  1393. NTSTATUS ntStatus;
  1394. KIRQL oldIrql;
  1395. // grab the revoke spinlock BEFORE getting the irp (which will grab the
  1396. // master spinlock) so that we don't deadlock
  1397. KeAcquireSpinLock(&m_RevokeLock, &oldIrql);
  1398. //
  1399. // For physical mapping, all mappings must be cancelled.
  1400. //
  1401. CancelMappings(NULL);
  1402. PIRP irp = DbgAcquireMappingIrp("SetPacketOffsets",FALSE);
  1403. if(irp)
  1404. {
  1405. PPACKET_HEADER packetHeader = IRP_CONTEXT_IRP_STORAGE(irp)->MappingPacket;
  1406. packetHeader->MapPosition = MappingOffset;
  1407. packetHeader->UnmapPosition = UnmappingOffset;
  1408. m_irpStreamPosition.ulMappingOffset = MappingOffset;
  1409. m_irpStreamPosition.ullMappingPosition = MappingOffset;
  1410. m_irpStreamPosition.ulUnmappingOffset = UnmappingOffset;
  1411. m_irpStreamPosition.ullUnmappingPosition= UnmappingOffset;
  1412. //
  1413. // Make sure we have good packet sizes. Normally, the packet sizes
  1414. // are recorded in m_irpStreamPosition when the packets are accessed
  1415. // (e.g. through GetLockedRegion or Complete). This is generally
  1416. // cool because the offsets are zero until this happens anyway. In
  1417. // this case, we have non-zero offsets and the possibility that the
  1418. // packet has not been accessed yet, hence no valid packet sizes.
  1419. // Here's some code to fix that.
  1420. //
  1421. if(m_irpStreamPosition.ulMappingPacketSize == 0)
  1422. {
  1423. m_irpStreamPosition.ulMappingPacketSize =
  1424. packetHeader->BytesTotal;
  1425. }
  1426. if(m_irpStreamPosition.ulUnmappingPacketSize == 0)
  1427. {
  1428. m_irpStreamPosition.ulUnmappingPacketSize =
  1429. packetHeader->BytesTotal;
  1430. }
  1431. // Adjust the stream base position
  1432. if(NotifyPhysical)
  1433. {
  1434. NTSTATUS ntStatus2 = NotifyPhysical->GetPosition(&m_irpStreamPosition);
  1435. if( NT_SUCCESS(ntStatus2) )
  1436. {
  1437. m_irpStreamPosition.ullStreamOffset = m_irpStreamPosition.ullStreamPosition -
  1438. m_irpStreamPosition.ullUnmappingPosition;
  1439. }
  1440. }
  1441. ReleaseMappingIrp(irp,NULL);
  1442. KeReleaseSpinLock(&m_RevokeLock, oldIrql);
  1443. // kick the notify sink
  1444. if(Notify)
  1445. {
  1446. Notify->IrpSubmitted(NULL,TRUE);
  1447. }
  1448. else
  1449. if(NotifyPhysical)
  1450. {
  1451. NotifyPhysical->IrpSubmitted(NULL,TRUE);
  1452. }
  1453. ntStatus = STATUS_SUCCESS;
  1454. }
  1455. else
  1456. {
  1457. KeReleaseSpinLock(&m_RevokeLock, oldIrql);
  1458. ntStatus = STATUS_UNSUCCESSFUL;
  1459. }
  1460. return ntStatus;
  1461. }
  1462. #pragma code_seg("PAGE")
  1463. /*****************************************************************************
  1464. * CIrpStream::RegisterNotifySink()
  1465. *****************************************************************************
  1466. * Registers a notification sink.
  1467. */
  1468. STDMETHODIMP_(void)
  1469. CIrpStream::
  1470. RegisterNotifySink
  1471. (
  1472. IN PIRPSTREAMNOTIFY NotificationSink OPTIONAL
  1473. )
  1474. {
  1475. PAGED_CODE();
  1476. if(Notify)
  1477. {
  1478. Notify->Release();
  1479. }
  1480. Notify = NotificationSink;
  1481. if(Notify)
  1482. {
  1483. Notify->AddRef();
  1484. }
  1485. }
  1486. #pragma code_seg()
  1487. /*****************************************************************************
  1488. * CIrpStream::GetLockedRegion()
  1489. *****************************************************************************
  1490. * Get a locked contiguous region of the IRP stream. This region must be
  1491. * released using ReleaseLockedRegion() within a few microseconds.
  1492. */
  1493. STDMETHODIMP_(void)
  1494. CIrpStream::
  1495. GetLockedRegion
  1496. (
  1497. OUT PULONG ByteCount,
  1498. OUT PVOID * SystemAddress
  1499. )
  1500. {
  1501. ASSERT(ByteCount);
  1502. ASSERT(SystemAddress);
  1503. BOOL Done;
  1504. PIRP irp;
  1505. PPACKET_HEADER packetHeader;
  1506. Done = FALSE;
  1507. //
  1508. // Find an IRP that has requires some work...
  1509. //
  1510. do
  1511. {
  1512. irp = DbgAcquireMappingIrp("GetLockedRegion",TRUE);
  1513. Done = TRUE;
  1514. if(irp)
  1515. {
  1516. packetHeader = IRP_CONTEXT_IRP_STORAGE(irp)->MappingPacket;
  1517. //
  1518. // If packetHeader->BytesTotal is 0, then this packet is completed.
  1519. //
  1520. if(! packetHeader->BytesTotal)
  1521. {
  1522. packetHeader->OutputPosition = OutputPosition;
  1523. ReleaseMappingIrp(irp,packetHeader);
  1524. irp = NULL;
  1525. Done = FALSE;
  1526. }
  1527. }
  1528. }
  1529. while(!Done);
  1530. if(irp)
  1531. {
  1532. ASSERT(! LockedIrp);
  1533. LockedIrp = irp;
  1534. //
  1535. // Record new mapping packet information in the position structure.
  1536. //
  1537. if(packetHeader->MapPosition == 0)
  1538. {
  1539. packetHeader->OutputPosition = OutputPosition;
  1540. m_irpStreamPosition.ulMappingOffset = 0;
  1541. m_irpStreamPosition.ulMappingPacketSize =
  1542. packetHeader->BytesTotal;
  1543. m_irpStreamPosition.bMappingPacketLooped =
  1544. ( ( packetHeader->StreamHeader->OptionsFlags
  1545. & KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA
  1546. )
  1547. != 0
  1548. );
  1549. }
  1550. *ByteCount = packetHeader->BytesTotal - packetHeader->MapPosition;
  1551. if(*ByteCount)
  1552. {
  1553. *SystemAddress = PVOID(
  1554. #ifdef UNDER_NT
  1555. PBYTE(MmGetSystemAddressForMdlSafe(packetHeader->MdlAddress,HighPagePriority))
  1556. #else
  1557. PBYTE(MmGetSystemAddressForMdl(packetHeader->MdlAddress))
  1558. #endif
  1559. + packetHeader->MapPosition );
  1560. }
  1561. else
  1562. {
  1563. *SystemAddress = NULL;
  1564. LockedIrp = NULL;
  1565. ReleaseMappingIrp(irp,NULL);
  1566. }
  1567. }
  1568. else
  1569. {
  1570. *ByteCount = 0;
  1571. *SystemAddress = NULL;
  1572. }
  1573. }
  1574. /*****************************************************************************
  1575. * CIrpStream::ReleaseLockedRegion()
  1576. *****************************************************************************
  1577. * Releases the region previously obtained with GetLockedRegion().
  1578. */
  1579. STDMETHODIMP_(void)
  1580. CIrpStream::
  1581. ReleaseLockedRegion
  1582. (
  1583. IN ULONG ByteCount
  1584. )
  1585. {
  1586. if(LockedIrp)
  1587. {
  1588. PIRP irp = LockedIrp;
  1589. LockedIrp = NULL;
  1590. PPACKET_HEADER packetHeader =
  1591. IRP_CONTEXT_IRP_STORAGE(irp)->MappingPacket;
  1592. ULONG bytes = packetHeader->BytesTotal - packetHeader->MapPosition;
  1593. if(bytes > ByteCount)
  1594. {
  1595. bytes = ByteCount;
  1596. }
  1597. packetHeader->MapPosition += bytes;
  1598. m_irpStreamPosition.ullMappingPosition += bytes;
  1599. m_irpStreamPosition.ulMappingOffset += bytes;
  1600. if(packetHeader->MapPosition == packetHeader->BytesTotal)
  1601. {
  1602. OutputPosition += packetHeader->BytesTotal;
  1603. }
  1604. else
  1605. {
  1606. // ReleaseMappingIrp() wants only completed headers.
  1607. packetHeader = NULL;
  1608. }
  1609. ReleaseMappingIrp(irp,packetHeader);
  1610. }
  1611. }
  1612. /*****************************************************************************
  1613. * CIrpStream::Copy()
  1614. *****************************************************************************
  1615. * Copy to or from locked-down memory.
  1616. */
  1617. STDMETHODIMP_(void)
  1618. CIrpStream::
  1619. Copy
  1620. (
  1621. IN BOOLEAN WriteOperation,
  1622. IN ULONG RequestedSize,
  1623. OUT PULONG ActualSize,
  1624. IN OUT PVOID Buffer
  1625. )
  1626. {
  1627. ASSERT(ActualSize);
  1628. ASSERT(Buffer);
  1629. PBYTE buffer = PBYTE(Buffer);
  1630. ULONG remaining = RequestedSize;
  1631. ULONG loopMax = 10000;
  1632. while(remaining)
  1633. {
  1634. ASSERT(loopMax--);
  1635. ULONG byteCount;
  1636. PVOID systemAddress;
  1637. GetLockedRegion( &byteCount,
  1638. &systemAddress );
  1639. if(! byteCount)
  1640. {
  1641. break;
  1642. }
  1643. if(byteCount > remaining)
  1644. {
  1645. byteCount = remaining;
  1646. }
  1647. if(WriteOperation)
  1648. {
  1649. RtlCopyMemory(PVOID(buffer),systemAddress,byteCount);
  1650. }
  1651. else
  1652. {
  1653. RtlCopyMemory(systemAddress,PVOID(buffer),byteCount);
  1654. }
  1655. ReleaseLockedRegion(byteCount);
  1656. buffer += byteCount;
  1657. remaining -= byteCount;
  1658. }
  1659. *ActualSize = RequestedSize - remaining;
  1660. }
  1661. /*****************************************************************************
  1662. * CIrpStream::GetIrpStreamPositionLock()
  1663. *****************************************************************************
  1664. * So we protect access to m_IrpStreamPosition
  1665. */
  1666. STDMETHODIMP_(PKSPIN_LOCK)
  1667. CIrpStream::GetIrpStreamPositionLock()
  1668. {
  1669. return &m_irpStreamPositionLock;
  1670. }
  1671. /*****************************************************************************
  1672. * CIrpStream::Complete()
  1673. *****************************************************************************
  1674. * Complete.
  1675. */
  1676. STDMETHODIMP_(void)
  1677. CIrpStream::
  1678. Complete
  1679. (
  1680. IN ULONG RequestedSize,
  1681. OUT PULONG ActualSize
  1682. )
  1683. {
  1684. ASSERT(ActualSize);
  1685. if(RequestedSize == 0)
  1686. {
  1687. *ActualSize = 0;
  1688. return;
  1689. }
  1690. ULONG remaining = RequestedSize;
  1691. PIRP irp;
  1692. ULONG loopMax = 10000;
  1693. while(irp = DbgAcquireUnmappingIrp("Complete"))
  1694. {
  1695. ASSERT(loopMax--);
  1696. PPACKET_HEADER packetHeader = IRP_CONTEXT_IRP_STORAGE(irp)->UnmappingPacket;
  1697. ULONG unmapped;
  1698. //
  1699. // Record new unmapping packet information in the position structure.
  1700. //
  1701. if(packetHeader->UnmapPosition == 0)
  1702. {
  1703. m_irpStreamPosition.ulUnmappingOffset = 0;
  1704. m_irpStreamPosition.ulUnmappingPacketSize = packetHeader->BytesTotal;
  1705. m_irpStreamPosition.bUnmappingPacketLooped = ((packetHeader->StreamHeader->OptionsFlags &
  1706. KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA) != 0 );
  1707. }
  1708. if(packetHeader->MapCount == 1)
  1709. {
  1710. unmapped = packetHeader->MapPosition - packetHeader->UnmapPosition;
  1711. }
  1712. else
  1713. {
  1714. unmapped = packetHeader->BytesTotal - packetHeader->UnmapPosition;
  1715. }
  1716. if(unmapped > remaining)
  1717. {
  1718. unmapped = remaining;
  1719. }
  1720. remaining -= unmapped;
  1721. if(unmapped == 0)
  1722. {
  1723. _DbgPrintF(DEBUGLVL_VERBOSE,("CIrpStream::Complete unmapping zero-length segment"));
  1724. _DbgPrintF(DEBUGLVL_VERBOSE,("CIrpStream::Complete packetHeader->MapCount = %d",packetHeader->MapCount));
  1725. _DbgPrintF(DEBUGLVL_VERBOSE,("CIrpStream::Complete packetHeader->UnmapPosition = %d",packetHeader->UnmapPosition));
  1726. _DbgPrintF(DEBUGLVL_VERBOSE,("CIrpStream::Complete packetHeader->MapPosition = %d",packetHeader->MapPosition));
  1727. _DbgPrintF(DEBUGLVL_VERBOSE,("CIrpStream::Complete packetHeader->BytesTotal = %d",packetHeader->BytesTotal));
  1728. _DbgPrintF(DEBUGLVL_VERBOSE,("CIrpStream::Complete remaining = %d",remaining));
  1729. }
  1730. if(JustInTime)
  1731. {
  1732. // TODO: Unlock the bytes.
  1733. }
  1734. packetHeader->UnmapPosition += unmapped;
  1735. m_irpStreamPosition.ullUnmappingPosition += unmapped;
  1736. m_irpStreamPosition.ulUnmappingOffset += unmapped;
  1737. if(packetHeader->UnmapPosition != packetHeader->BytesTotal)
  1738. {
  1739. // ReleaseUnmappingIrp() wants only completed headers.
  1740. packetHeader = NULL;
  1741. }
  1742. ReleaseUnmappingIrp(irp,packetHeader);
  1743. //
  1744. // If all IRP processing is completed (e.g., the packet header
  1745. // has data, but the processing loop has completed the requested
  1746. // length) then break from this loop.
  1747. //
  1748. if(!remaining && unmapped)
  1749. {
  1750. break;
  1751. }
  1752. //
  1753. // If we have unmapped everything that was mapped in the packet but
  1754. // not all of the packet bytes, kick out of the loop
  1755. //
  1756. if( !unmapped && !packetHeader )
  1757. {
  1758. break;
  1759. }
  1760. }
  1761. *ActualSize = RequestedSize - remaining;
  1762. }
  1763. #pragma code_seg("PAGE")
  1764. /*****************************************************************************
  1765. * CIrpStream::RegisterPhysicalNotifySink()
  1766. *****************************************************************************
  1767. * Registers a notification sink.
  1768. */
  1769. STDMETHODIMP_(void)
  1770. CIrpStream::
  1771. RegisterPhysicalNotifySink
  1772. (
  1773. IN PIRPSTREAMNOTIFYPHYSICAL NotificationSink OPTIONAL
  1774. )
  1775. {
  1776. PAGED_CODE();
  1777. if(NotifyPhysical)
  1778. {
  1779. NotifyPhysical->Release();
  1780. }
  1781. NotifyPhysical = NotificationSink;
  1782. if(NotifyPhysical)
  1783. {
  1784. NotifyPhysical->AddRef();
  1785. }
  1786. }
  1787. #pragma code_seg()
  1788. /*****************************************************************************
  1789. * CIrpStream::GetMapping()
  1790. *****************************************************************************
  1791. * Gets a mapping.
  1792. */
  1793. STDMETHODIMP_(void)
  1794. CIrpStream::
  1795. GetMapping
  1796. (
  1797. IN PVOID Tag,
  1798. OUT PPHYSICAL_ADDRESS PhysicalAddress,
  1799. OUT PVOID * VirtualAddress,
  1800. OUT PULONG ByteCount,
  1801. OUT PULONG Flags
  1802. )
  1803. {
  1804. ASSERT(PhysicalAddress);
  1805. ASSERT(VirtualAddress);
  1806. ASSERT(ByteCount);
  1807. ASSERT(Flags);
  1808. KIRQL OldIrql;
  1809. //Acquire the revoke spinlock
  1810. KeAcquireSpinLock(&m_RevokeLock, &OldIrql);
  1811. PMAPPING_QUEUE_ENTRY entry = GetQueuedMapping();
  1812. // skip over any revoked mappings
  1813. while( (NULL != entry) && (entry->MappingStatus == MAPPING_STATUS_REVOKED) )
  1814. {
  1815. entry = GetQueuedMapping();
  1816. }
  1817. if(! entry)
  1818. {
  1819. PIRP irp = DbgAcquireMappingIrp("GetMapping",TRUE);
  1820. if(irp)
  1821. {
  1822. PPACKET_HEADER packetHeader = IRP_CONTEXT_IRP_STORAGE(irp)->MappingPacket;
  1823. // update mapping packet info
  1824. m_irpStreamPosition.ulMappingPacketSize = packetHeader->BytesTotal;
  1825. m_irpStreamPosition.bMappingPacketLooped = ( ( packetHeader->StreamHeader->OptionsFlags &
  1826. KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA ) != 0 );
  1827. m_irpStreamPosition.ulMappingOffset = packetHeader->MapPosition;
  1828. //
  1829. // Deal with one-shot buffer.
  1830. //
  1831. if( packetHeader->MapPosition &&
  1832. ( packetHeader->MapPosition == packetHeader->BytesTotal ) )
  1833. {
  1834. ReleaseMappingIrp(irp,NULL);
  1835. }
  1836. else
  1837. {
  1838. // grab the global DMA lock that serializes IoAllocateAdapter calls (we're already at DISPATCH_LEVEL)
  1839. KeAcquireSpinLockAtDpcLevel( PDEVICE_CONTEXT(FunctionalDeviceObject->DeviceExtension)->DriverDmaLock );
  1840. ULONG BytesToMap = packetHeader->BytesTotal - packetHeader->MapPosition;
  1841. ULONG BytesThisMapping = BytesToMap > (PAGE_SIZE * MAX_MAPPINGS) ?
  1842. (PAGE_SIZE * MAX_MAPPINGS) :
  1843. BytesToMap;
  1844. _DbgPrintF(DEBUGLVL_VERBOSE,("GetMapping mapping a new packet (0x%08x)",BytesThisMapping));
  1845. packetHeader->OutputPosition = OutputPosition;
  1846. ULONG mapRegisterCount = ( BytesThisMapping ?
  1847. ADDRESS_AND_SIZE_TO_SPAN_PAGES( PUCHAR(MmGetMdlVirtualAddress( packetHeader->MdlAddress )) +
  1848. packetHeader->MapPosition,
  1849. BytesThisMapping ) :
  1850. 0 );
  1851. if(mapRegisterCount != 0)
  1852. {
  1853. CALLBACK_CONTEXT callbackContext;
  1854. callbackContext.IrpStream = this;
  1855. callbackContext.PacketHeader = packetHeader;
  1856. callbackContext.Irp = irp;
  1857. KeInitializeEvent(&callbackContext.Event,NotificationEvent,FALSE);
  1858. callbackContext.BytesThisMapping = BytesThisMapping;
  1859. callbackContext.LastSubPacket = (BytesThisMapping == BytesToMap);
  1860. // note - we're already at DISPATCH_LEVEL (we're holding spinlocks)
  1861. NTSTATUS ntStatus = IoAllocateAdapterChannel( BusMasterAdapterObject,
  1862. FunctionalDeviceObject,
  1863. mapRegisterCount,
  1864. CallbackFromIoAllocateAdapterChannel,
  1865. PVOID(&callbackContext) );
  1866. if(NT_SUCCESS(ntStatus))
  1867. {
  1868. NTSTATUS WaitStatus;
  1869. LARGE_INTEGER ZeroTimeout = RtlConvertLongToLargeInteger(0);
  1870. ULONG RetryCount = 0;
  1871. while( RetryCount++ < 10000 )
  1872. {
  1873. // Wait for the scatter/gather processing to be completed.
  1874. WaitStatus = KeWaitForSingleObject( &callbackContext.Event,
  1875. Suspended,
  1876. KernelMode,
  1877. FALSE,
  1878. &ZeroTimeout );
  1879. if( WaitStatus == STATUS_SUCCESS )
  1880. {
  1881. entry = GetQueuedMapping();
  1882. break;
  1883. }
  1884. }
  1885. } else
  1886. {
  1887. ReleaseMappingIrp( irp, NULL );
  1888. KeReleaseSpinLockFromDpcLevel( PDEVICE_CONTEXT(FunctionalDeviceObject->DeviceExtension)->DriverDmaLock );
  1889. _DbgPrintF(DEBUGLVL_TERSE,("IoAllocateAdapterChannel FAILED (0x%08x)",ntStatus));
  1890. }
  1891. } else
  1892. {
  1893. ReleaseMappingIrp( irp,NULL );
  1894. KeReleaseSpinLockFromDpcLevel( PDEVICE_CONTEXT(FunctionalDeviceObject->DeviceExtension)->DriverDmaLock );
  1895. }
  1896. }
  1897. } else
  1898. {
  1899. _DbgPrintF(DEBUGLVL_VERBOSE,("GetMapping() unable to get an IRP"));
  1900. }
  1901. }
  1902. if(entry)
  1903. {
  1904. // it had better be mapped...
  1905. ASSERT( entry->MappingStatus == MAPPING_STATUS_MAPPED );
  1906. entry->Tag = Tag;
  1907. entry->MappingStatus = MAPPING_STATUS_DELIVERED;
  1908. *PhysicalAddress = entry->PhysicalAddress;
  1909. *VirtualAddress = entry->VirtualAddress;
  1910. *ByteCount = entry->ByteCount;
  1911. *Flags = (entry->Flags & (MAPPING_FLAG_END_OF_PACKET | MAPPING_FLAG_END_OF_SUBPACKET)) ?
  1912. MAPPING_FLAG_END_OF_PACKET : 0;
  1913. m_irpStreamPosition.ullMappingPosition += entry->ByteCount;
  1914. m_irpStreamPosition.ulMappingOffset += entry->ByteCount;
  1915. #if (DBG)
  1916. MappingsOutstanding++;
  1917. #endif
  1918. }
  1919. else
  1920. {
  1921. WasExhausted = TRUE;
  1922. *ByteCount = 0;
  1923. }
  1924. KeReleaseSpinLock(&m_RevokeLock, OldIrql);
  1925. }
  1926. /*****************************************************************************
  1927. * CIrpStream::ReleaseMapping()
  1928. *****************************************************************************
  1929. * Releases a mapping obtained through GetMapping().
  1930. */
  1931. STDMETHODIMP_(void)
  1932. CIrpStream::
  1933. ReleaseMapping
  1934. (
  1935. IN PVOID Tag
  1936. )
  1937. {
  1938. KIRQL OldIrql;
  1939. //Acquire the revoke spinlock
  1940. KeAcquireSpinLock(&m_RevokeLock, &OldIrql);
  1941. PMAPPING_QUEUE_ENTRY entry = DequeueMapping();
  1942. while( (NULL != entry) && (entry->MappingStatus != MAPPING_STATUS_DELIVERED) )
  1943. {
  1944. entry->MappingStatus = MAPPING_STATUS_EMPTY;
  1945. entry->Tag = PVOID(-1);
  1946. entry = DequeueMapping();
  1947. }
  1948. // check if we found and entry
  1949. if( !entry )
  1950. {
  1951. KeReleaseSpinLock(&m_RevokeLock, OldIrql);
  1952. _DbgPrintF(DEBUGLVL_VERBOSE,("ReleaseMapping failed to find a mapping to release"));
  1953. return;
  1954. }
  1955. //
  1956. // Due to race conditions between portcls and the WDM driver, the driver
  1957. // might first release the second mapping and then the first mapping in
  1958. // the row.
  1959. // By design, it doesn't make sense for a audio driver to play "in the
  1960. // middle" of a stream and release mappings there. The only exception
  1961. // where mappings might not be released in order how the driver got them
  1962. // is mentioned above.
  1963. // Since we know that, we don't need to search for the right mapping!
  1964. //
  1965. // mark the entry as empty
  1966. entry->MappingStatus = MAPPING_STATUS_EMPTY;
  1967. entry->Tag = PVOID(-1);
  1968. #if (DBG)
  1969. MappingsOutstanding--;
  1970. #endif
  1971. // get the unmapping irp
  1972. PIRP irp = DbgAcquireUnmappingIrp("ReleaseMapping");
  1973. if( irp )
  1974. {
  1975. PPACKET_HEADER packetHeader = IRP_CONTEXT_IRP_STORAGE(irp)->UnmappingPacket;
  1976. // update position info
  1977. packetHeader->UnmapPosition += entry->ByteCount;
  1978. m_irpStreamPosition.ulUnmappingPacketSize = packetHeader->BytesTotal;
  1979. m_irpStreamPosition.ulUnmappingOffset = packetHeader->UnmapPosition;
  1980. m_irpStreamPosition.ullUnmappingPosition += entry->ByteCount;
  1981. m_irpStreamPosition.bUnmappingPacketLooped = ( ( packetHeader->StreamHeader->OptionsFlags &
  1982. KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA ) != 0 );
  1983. // check if this is the last mapping in the packet or subpacket
  1984. if( ( entry->Flags & MAPPING_FLAG_END_OF_PACKET ) ||
  1985. ( entry->Flags & MAPPING_FLAG_END_OF_SUBPACKET) )
  1986. {
  1987. // Flush the DMA adapter buffers.
  1988. IoFlushAdapterBuffers( BusMasterAdapterObject,
  1989. packetHeader->MdlAddress,
  1990. entry->MapRegisterBase,
  1991. entry->SubpacketVa,
  1992. entry->SubpacketBytes,
  1993. WriteOperation );
  1994. IoFreeMapRegisters( BusMasterAdapterObject,
  1995. entry->MapRegisterBase,
  1996. ADDRESS_AND_SIZE_TO_SPAN_PAGES(entry->SubpacketVa,entry->SubpacketBytes) );
  1997. }
  1998. // release the unmapping irp and only pass the packet header if the packet is completed
  1999. ReleaseUnmappingIrp(irp, (entry->Flags & MAPPING_FLAG_END_OF_PACKET) ? packetHeader : NULL);
  2000. }
  2001. KeReleaseSpinLock(&m_RevokeLock, OldIrql);
  2002. }
  2003. /*****************************************************************************
  2004. * CallbackFromIoAllocateAdapterChannel()
  2005. *****************************************************************************
  2006. * Callback from IoAllocateAdapterChannel to create scatter/gather entries.
  2007. */
  2008. static
  2009. IO_ALLOCATION_ACTION
  2010. CallbackFromIoAllocateAdapterChannel
  2011. (
  2012. IN PDEVICE_OBJECT DeviceObject,
  2013. IN PIRP Reserved,
  2014. IN PVOID MapRegisterBase,
  2015. IN PVOID VoidContext
  2016. )
  2017. {
  2018. ASSERT(DeviceObject);
  2019. ASSERT(VoidContext);
  2020. PCALLBACK_CONTEXT context = PCALLBACK_CONTEXT(VoidContext);
  2021. PIRP Irp = context->Irp;
  2022. PUCHAR virtualAddress = PUCHAR(MmGetMdlVirtualAddress(context->PacketHeader->MdlAddress));
  2023. #ifdef UNDER_NT
  2024. PUCHAR entryVA = PUCHAR(MmGetSystemAddressForMdlSafe(context->PacketHeader->MdlAddress,HighPagePriority));
  2025. #else
  2026. PUCHAR entryVA = PUCHAR(MmGetSystemAddressForMdl(context->PacketHeader->MdlAddress));
  2027. #endif
  2028. ULONG bytesRemaining = context->BytesThisMapping;
  2029. ULONG flags = context->LastSubPacket ? MAPPING_FLAG_END_OF_PACKET : MAPPING_FLAG_END_OF_SUBPACKET;
  2030. //
  2031. // Consider mapping offset in case we have set position.
  2032. //
  2033. virtualAddress += context->PacketHeader->MapPosition;
  2034. entryVA += context->PacketHeader->MapPosition;
  2035. PVOID subpacketVa = virtualAddress;
  2036. while(bytesRemaining)
  2037. {
  2038. ULONG segmentLength = bytesRemaining;
  2039. // Create one mapping.
  2040. PHYSICAL_ADDRESS physicalAddress = IoMapTransfer( context->IrpStream->BusMasterAdapterObject,
  2041. context->PacketHeader->MdlAddress,
  2042. MapRegisterBase,
  2043. virtualAddress,
  2044. &segmentLength,
  2045. context->IrpStream->WriteOperation );
  2046. bytesRemaining -= segmentLength;
  2047. virtualAddress += segmentLength;
  2048. // enqueue the mapping
  2049. while(segmentLength)
  2050. {
  2051. NTSTATUS ntStatus;
  2052. // TODO: break up large mappings based on hardware constraints
  2053. ntStatus = context->IrpStream->EnqueueMapping( physicalAddress,
  2054. Irp,
  2055. context->PacketHeader,
  2056. PVOID(entryVA),
  2057. segmentLength,
  2058. ((bytesRemaining == 0) ? flags : 0),
  2059. MapRegisterBase,
  2060. MAPPING_STATUS_MAPPED,
  2061. ((bytesRemaining == 0) ? subpacketVa : NULL),
  2062. ((bytesRemaining == 0) ? context->BytesThisMapping : 0 ) );
  2063. if( NT_SUCCESS(ntStatus) )
  2064. {
  2065. entryVA += segmentLength;
  2066. physicalAddress.LowPart += segmentLength;
  2067. segmentLength = 0;
  2068. }
  2069. else
  2070. {
  2071. // TODO: deal properly with a full mapping queue
  2072. ASSERT(!"MappingQueue FULL");
  2073. }
  2074. }
  2075. }
  2076. context->PacketHeader->MapPosition += context->BytesThisMapping;
  2077. context->IrpStream->OutputPosition += context->BytesThisMapping;
  2078. context->IrpStream->ReleaseMappingIrp(context->Irp,
  2079. ((context->PacketHeader->MapPosition == context->PacketHeader->BytesTotal) ? context->PacketHeader : NULL));
  2080. KeSetEvent(&context->Event,0,FALSE);
  2081. KeReleaseSpinLock( PDEVICE_CONTEXT(context->IrpStream->FunctionalDeviceObject->DeviceExtension)->DriverDmaLock, KeGetCurrentIrql() );
  2082. return DeallocateObjectKeepRegisters;
  2083. }
  2084. /*****************************************************************************
  2085. * CIrpStream::AcquireMappingIrp()
  2086. *****************************************************************************
  2087. * Acquire the IRP in which mapping is currently occuring.
  2088. */
  2089. PIRP
  2090. CIrpStream::
  2091. AcquireMappingIrp
  2092. (
  2093. #if DBG
  2094. IN PCHAR Owner,
  2095. #endif
  2096. IN BOOLEAN NotifyExhausted
  2097. )
  2098. {
  2099. KIRQL kIrqlOld;
  2100. KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
  2101. m_kIrqlOld = kIrqlOld;
  2102. PIRP irp = KsRemoveIrpFromCancelableQueue( &LockedQueue,
  2103. &LockedQueueLock,
  2104. KsListEntryHead,
  2105. KsAcquireOnlySingleItem );
  2106. if(! irp)
  2107. {
  2108. KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
  2109. }
  2110. #if DBG
  2111. if(irp)
  2112. {
  2113. _DbgPrintF(DEBUGLVL_BLAB,("AcquireMappingIrp() %d 0x%8x",IRP_CONTEXT_IRP_STORAGE(irp)->IrpLabel,irp));
  2114. MappingIrpOwner = Owner;
  2115. }
  2116. else
  2117. {
  2118. _DbgPrintF(DEBUGLVL_BLAB,("AcquireMappingIrp() NO MAPPING IRP AVAILABLE"));
  2119. }
  2120. DbgQueues();
  2121. #endif
  2122. return irp;
  2123. }
  2124. /*****************************************************************************
  2125. * CIrpStream::AcquireUnmappingIrp()
  2126. *****************************************************************************
  2127. * Acquire the IRP in which unmapping is currently occuring.
  2128. */
  2129. PIRP
  2130. CIrpStream::
  2131. AcquireUnmappingIrp
  2132. (
  2133. #if DBG
  2134. IN PCHAR Owner
  2135. #endif
  2136. )
  2137. {
  2138. KIRQL kIrqlOld;
  2139. KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
  2140. m_kIrqlOld = kIrqlOld;
  2141. // The IRP that we should be unmapping is at the head of the mapped queue
  2142. // if it is completely mapped. Otherwise it's at the head of the locked
  2143. // queue, and the mapped queue is empty.
  2144. // Acquire the head IRP in the locked queue just in case.
  2145. PIRP lockedIrp = KsRemoveIrpFromCancelableQueue( &LockedQueue,
  2146. &LockedQueueLock,
  2147. KsListEntryHead,
  2148. KsAcquireOnlySingleItem );
  2149. // Acquire the head IRP in the mapped queue.
  2150. PIRP irp = KsRemoveIrpFromCancelableQueue( &MappedQueue,
  2151. &MappedQueueLock,
  2152. KsListEntryHead,
  2153. KsAcquireOnlySingleItem );
  2154. if(irp)
  2155. {
  2156. // Don't need the IRP from the locked queue.
  2157. if(lockedIrp)
  2158. {
  2159. KsReleaseIrpOnCancelableQueue( lockedIrp,
  2160. IrpStreamCancelRoutine );
  2161. }
  2162. }
  2163. else
  2164. if(IsListEmpty(&MappedQueue))
  2165. {
  2166. // Mapped queue is empty, try locked queue.
  2167. if(lockedIrp)
  2168. {
  2169. irp = lockedIrp;
  2170. }
  2171. }
  2172. else
  2173. {
  2174. // There's a busy IRP in the mapped queue.
  2175. if(lockedIrp)
  2176. {
  2177. KsReleaseIrpOnCancelableQueue( lockedIrp,
  2178. IrpStreamCancelRoutine );
  2179. }
  2180. }
  2181. if(! irp)
  2182. {
  2183. KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
  2184. }
  2185. #if DBG
  2186. if(irp)
  2187. {
  2188. _DbgPrintF(DEBUGLVL_BLAB,("AcquireUnmappingIrp() %d 0x%8x",IRP_CONTEXT_IRP_STORAGE(irp)->IrpLabel,irp));
  2189. UnmappingIrpOwner = Owner;
  2190. }
  2191. else
  2192. {
  2193. _DbgPrintF(DEBUGLVL_BLAB,("AcquireUnmappingIrp() NO UNMAPPING IRP AVAILABLE"));
  2194. }
  2195. DbgQueues();
  2196. #endif
  2197. return irp;
  2198. }
  2199. /*****************************************************************************
  2200. * CIrpStream::ReleaseMappingIrp()
  2201. *****************************************************************************
  2202. * Releases the mapping IRP previously acquired through AcqureMappingIrp(),
  2203. * possibly handling the completion of a packet.
  2204. */
  2205. void
  2206. CIrpStream::
  2207. ReleaseMappingIrp
  2208. (
  2209. IN PIRP pIrp,
  2210. IN PPACKET_HEADER pPacketHeader OPTIONAL
  2211. )
  2212. {
  2213. ASSERT(pIrp);
  2214. if(pPacketHeader)
  2215. {
  2216. if(pPacketHeader->IncrementMapping)
  2217. {
  2218. pPacketHeader->IncrementMapping = FALSE;
  2219. pPacketHeader++;
  2220. }
  2221. else
  2222. {
  2223. PPACKET_HEADER prevPacketHeader = pPacketHeader;
  2224. pPacketHeader = pPacketHeader->Next;
  2225. //
  2226. // If looping back, stop if there is another IRP.
  2227. //
  2228. if( pPacketHeader &&
  2229. (pPacketHeader <= prevPacketHeader) &&
  2230. (FLINK_IRP_STORAGE(pIrp) != &LockedQueue) )
  2231. {
  2232. pPacketHeader = NULL;
  2233. }
  2234. }
  2235. if(pPacketHeader)
  2236. {
  2237. // Use next packet header next time.
  2238. IRP_CONTEXT_IRP_STORAGE(pIrp)->MappingPacket = pPacketHeader;
  2239. pPacketHeader->MapCount++;
  2240. pPacketHeader->MapPosition = 0;
  2241. m_irpStreamPosition.ulMappingOffset = 0;
  2242. m_irpStreamPosition.ulMappingPacketSize = pPacketHeader->BytesTotal;
  2243. m_irpStreamPosition.bMappingPacketLooped = ( ( pPacketHeader->StreamHeader->OptionsFlags &
  2244. KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA ) != 0 );
  2245. KsReleaseIrpOnCancelableQueue( pIrp,
  2246. IrpStreamCancelRoutine );
  2247. }
  2248. else if( m_irpStreamPosition.bLoopedInterface && (FLINK_IRP_STORAGE(pIrp) == &LockedQueue) )
  2249. {
  2250. //
  2251. // Completed one-shot with looped interface and there are no more
  2252. // packets. Just hang out here.
  2253. //
  2254. KsReleaseIrpOnCancelableQueue( pIrp,
  2255. IrpStreamCancelRoutine );
  2256. }
  2257. else
  2258. {
  2259. //
  2260. // IRP is completely mapped.
  2261. //
  2262. //
  2263. // See if we need to initiate unmapping.
  2264. //
  2265. BOOL bKickUnmapping = FALSE;
  2266. if(IsListEmpty(&MappedQueue))
  2267. {
  2268. pPacketHeader = IRP_CONTEXT_IRP_STORAGE(pIrp)->UnmappingPacket;
  2269. bKickUnmapping = ( pPacketHeader->UnmapPosition == pPacketHeader->BytesTotal );
  2270. }
  2271. //
  2272. // Add the IRP to the mapped queued.
  2273. //
  2274. KsRemoveSpecificIrpFromCancelableQueue(pIrp);
  2275. KsAddIrpToCancelableQueue( &MappedQueue,
  2276. &MappedQueueLock,
  2277. pIrp,
  2278. KsListEntryTail,
  2279. IrpStreamCancelRoutine );
  2280. if(bKickUnmapping)
  2281. {
  2282. //
  2283. // Unmap the completed header.
  2284. //
  2285. PIRP pIrpRemoved = KsRemoveIrpFromCancelableQueue( &MappedQueue,
  2286. &MappedQueueLock,
  2287. KsListEntryHead,
  2288. KsAcquireOnlySingleItem );
  2289. ASSERT(pIrpRemoved == pIrp);
  2290. ReleaseUnmappingIrp( pIrp, IRP_CONTEXT_IRP_STORAGE(pIrp)->UnmappingPacket );
  2291. return; // ReleaseUnmappingIrp() releases the spinlock.
  2292. }
  2293. }
  2294. }
  2295. else
  2296. {
  2297. KsReleaseIrpOnCancelableQueue( pIrp,
  2298. IrpStreamCancelRoutine );
  2299. }
  2300. KeReleaseSpinLock(&m_kSpinLock,m_kIrqlOld);
  2301. }
  2302. /*****************************************************************************
  2303. * CIrpStream::ReleaseUnmappingIrp()
  2304. *****************************************************************************
  2305. * Releases the unmapping IRP acquired through AcquireUnmappingIrp(),
  2306. * possibly handling the completion of a packet.
  2307. */
  2308. void
  2309. CIrpStream::
  2310. ReleaseUnmappingIrp
  2311. (
  2312. IN PIRP pIrp,
  2313. IN PPACKET_HEADER pPacketHeader OPTIONAL
  2314. )
  2315. {
  2316. ASSERT(pIrp);
  2317. //
  2318. // Loop until there are no more packets completely unmapped.
  2319. //
  2320. while(1)
  2321. {
  2322. //
  2323. // If we don't have a newly unmapped packet, just release.
  2324. //
  2325. if(! pPacketHeader)
  2326. {
  2327. KsReleaseIrpOnCancelableQueue( pIrp,
  2328. IrpStreamCancelRoutine );
  2329. break;
  2330. }
  2331. //
  2332. // Loop 'til we find the next packet in the IRP if there is one.
  2333. //
  2334. while(1)
  2335. {
  2336. //
  2337. // Copy back total byte count into data used for capture.
  2338. // It's a no-op for render.
  2339. //
  2340. pPacketHeader->StreamHeader->DataUsed = pPacketHeader->BytesTotal;
  2341. pPacketHeader->MapCount--;
  2342. if(pPacketHeader->IncrementUnmapping)
  2343. {
  2344. pPacketHeader->IncrementUnmapping = FALSE;
  2345. pPacketHeader++;
  2346. }
  2347. else
  2348. {
  2349. pPacketHeader = pPacketHeader->Next;
  2350. if(! pPacketHeader)
  2351. {
  2352. break;
  2353. }
  2354. else
  2355. if(pPacketHeader->MapCount == 0)
  2356. {
  2357. pPacketHeader = NULL;
  2358. break;
  2359. }
  2360. }
  2361. //
  2362. // Loop only if this is a zero-length packet.
  2363. //
  2364. if(pPacketHeader->BytesTotal)
  2365. {
  2366. break;
  2367. }
  2368. }
  2369. if(pPacketHeader)
  2370. {
  2371. //
  2372. // Use next packet header next time.
  2373. //
  2374. IRP_CONTEXT_IRP_STORAGE(pIrp)->UnmappingPacket = pPacketHeader;
  2375. pPacketHeader->UnmapPosition = 0;
  2376. pPacketHeader = NULL;
  2377. }
  2378. else
  2379. {
  2380. //
  2381. // Remove the IRP from the queue.
  2382. //
  2383. KsRemoveSpecificIrpFromCancelableQueue(pIrp);
  2384. //
  2385. // Done with IRP...free the context memory we allocated
  2386. //
  2387. if( IRP_CONTEXT_IRP_STORAGE(pIrp) )
  2388. {
  2389. ExFreePool( IRP_CONTEXT_IRP_STORAGE(pIrp) );
  2390. IRP_CONTEXT_IRP_STORAGE(pIrp) = NULL;
  2391. } else
  2392. {
  2393. ASSERT( !"Freeing IRP with no context");
  2394. }
  2395. //
  2396. // Indicate in the IRP how much data we have captured.
  2397. //
  2398. if(! WriteOperation)
  2399. {
  2400. pIrp->IoStatus.Information = IoGetCurrentIrpStackLocation(pIrp)->
  2401. Parameters.DeviceIoControl.OutputBufferLength;
  2402. }
  2403. //
  2404. // Mark it happy.
  2405. //
  2406. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2407. //
  2408. // Pass it to the next transport sink.
  2409. //
  2410. ASSERT(m_TransportSink);
  2411. KsShellTransferKsIrp(m_TransportSink,pIrp);
  2412. //
  2413. // Acquire the head IRP in the mapped queue.
  2414. //
  2415. pIrp = KsRemoveIrpFromCancelableQueue( &MappedQueue,
  2416. &MappedQueueLock,
  2417. KsListEntryHead,
  2418. KsAcquireOnlySingleItem );
  2419. //
  2420. // No IRP. Outta here.
  2421. //
  2422. if(! pIrp)
  2423. {
  2424. break;
  2425. }
  2426. //
  2427. // See if we need to complete this packet.
  2428. //
  2429. pPacketHeader = IRP_CONTEXT_IRP_STORAGE(pIrp)->UnmappingPacket;
  2430. if(pPacketHeader->UnmapPosition != pPacketHeader->BytesTotal)
  2431. {
  2432. pPacketHeader = NULL;
  2433. }
  2434. }
  2435. }
  2436. KeReleaseSpinLock(&m_kSpinLock,m_kIrqlOld);
  2437. }
  2438. /*****************************************************************************
  2439. * CIrpStream::EnqueueMapping()
  2440. *****************************************************************************
  2441. * Add a mapping to the mapping queue.
  2442. */
  2443. NTSTATUS
  2444. CIrpStream::
  2445. EnqueueMapping
  2446. (
  2447. IN PHYSICAL_ADDRESS PhysicalAddress,
  2448. IN PIRP Irp,
  2449. IN PPACKET_HEADER PacketHeader,
  2450. IN PVOID VirtualAddress,
  2451. IN ULONG ByteCount,
  2452. IN ULONG Flags,
  2453. IN PVOID MapRegisterBase,
  2454. IN ULONG MappingStatus,
  2455. IN PVOID SubpacketVa,
  2456. IN ULONG SubpacketBytes
  2457. )
  2458. {
  2459. NTSTATUS ntStatus = STATUS_SUCCESS;
  2460. if( (MappingQueue.Tail + 1 == MappingQueue.Head) ||
  2461. ( (MappingQueue.Tail + 1 == MAPPING_QUEUE_SIZE) &&
  2462. (MappingQueue.Head == 0) ) )
  2463. {
  2464. // mapping queue looks full. check to see if we can move the head to make
  2465. // room.
  2466. if( (MappingQueue.Array[MappingQueue.Head].MappingStatus != MAPPING_STATUS_MAPPED) &&
  2467. (MappingQueue.Array[MappingQueue.Head].MappingStatus != MAPPING_STATUS_DELIVERED) )
  2468. {
  2469. PMAPPING_QUEUE_ENTRY entry = DequeueMapping();
  2470. ASSERT(entry);
  2471. if (entry)
  2472. {
  2473. entry->MappingStatus = MAPPING_STATUS_EMPTY;
  2474. }
  2475. else
  2476. {
  2477. ntStatus = STATUS_UNSUCCESSFUL;
  2478. }
  2479. }
  2480. else
  2481. {
  2482. _DbgPrintF(DEBUGLVL_TERSE,("EnqueueMapping MappingQueue FULL! (0x%08x)",this));
  2483. ntStatus = STATUS_UNSUCCESSFUL;
  2484. }
  2485. }
  2486. if (NT_SUCCESS(ntStatus))
  2487. {
  2488. MappingQueue.Array[MappingQueue.Tail].PhysicalAddress = PhysicalAddress;
  2489. MappingQueue.Array[MappingQueue.Tail].Irp = Irp;
  2490. MappingQueue.Array[MappingQueue.Tail].PacketHeader = PacketHeader;
  2491. MappingQueue.Array[MappingQueue.Tail].VirtualAddress = VirtualAddress;
  2492. MappingQueue.Array[MappingQueue.Tail].ByteCount = ByteCount;
  2493. MappingQueue.Array[MappingQueue.Tail].Flags = Flags;
  2494. MappingQueue.Array[MappingQueue.Tail].MapRegisterBase = MapRegisterBase;
  2495. MappingQueue.Array[MappingQueue.Tail].MappingStatus = MappingStatus;
  2496. MappingQueue.Array[MappingQueue.Tail].SubpacketVa = SubpacketVa;
  2497. MappingQueue.Array[MappingQueue.Tail].SubpacketBytes = SubpacketBytes;
  2498. #if (DBG)
  2499. MappingsQueued++;
  2500. #endif
  2501. if(++MappingQueue.Tail == MAPPING_QUEUE_SIZE)
  2502. {
  2503. MappingQueue.Tail = 0;
  2504. }
  2505. }
  2506. return ntStatus;
  2507. }
  2508. /*****************************************************************************
  2509. * CIrpStream::GetQueuedMapping()
  2510. *****************************************************************************
  2511. * Get a queued mapping from the mapping queue.
  2512. */
  2513. PMAPPING_QUEUE_ENTRY
  2514. CIrpStream::
  2515. GetQueuedMapping
  2516. ( void
  2517. )
  2518. {
  2519. PMAPPING_QUEUE_ENTRY result;
  2520. if(MappingQueue.Get == MappingQueue.Tail)
  2521. {
  2522. result = NULL;
  2523. }
  2524. else
  2525. {
  2526. result = &MappingQueue.Array[MappingQueue.Get];
  2527. if(++MappingQueue.Get == MAPPING_QUEUE_SIZE)
  2528. {
  2529. MappingQueue.Get = 0;
  2530. }
  2531. }
  2532. return result;
  2533. }
  2534. /*****************************************************************************
  2535. * CIrpStream::DequeueMapping()
  2536. *****************************************************************************
  2537. * Remove a mapping from the mapping queue.
  2538. */
  2539. PMAPPING_QUEUE_ENTRY
  2540. CIrpStream::
  2541. DequeueMapping
  2542. ( void
  2543. )
  2544. {
  2545. PMAPPING_QUEUE_ENTRY result;
  2546. if(MappingQueue.Head == MappingQueue.Tail)
  2547. {
  2548. result = NULL;
  2549. }
  2550. else
  2551. {
  2552. result = &MappingQueue.Array[MappingQueue.Head];
  2553. #if (DBG)
  2554. MappingsQueued--;
  2555. #endif
  2556. if(++MappingQueue.Head == MAPPING_QUEUE_SIZE)
  2557. {
  2558. MappingQueue.Head = 0;
  2559. }
  2560. }
  2561. return result;
  2562. }
  2563. /*****************************************************************************
  2564. * IrpStreamCancelRoutine()
  2565. *****************************************************************************
  2566. * Do cancellation.
  2567. */
  2568. VOID
  2569. IrpStreamCancelRoutine
  2570. (
  2571. IN PDEVICE_OBJECT DeviceObject,
  2572. IN PIRP Irp
  2573. )
  2574. {
  2575. ASSERT(DeviceObject);
  2576. ASSERT(Irp);
  2577. _DbgPrintF(DEBUGLVL_VERBOSE,("CancelRoutine Cancelling IRP: 0x%08x",Irp));
  2578. //
  2579. // Mark the IRP cancelled and call the standard routine. Doing the
  2580. // marking first has the effect of not completing the IRP in the standard
  2581. // routine. The standard routine removes the IRP from the queue and
  2582. // releases the cancel spin lock.
  2583. //
  2584. Irp->IoStatus.Status = STATUS_CANCELLED;
  2585. KsCancelRoutine(DeviceObject,Irp);
  2586. // TODO: Search the mapping queue for mappings to revoke.
  2587. // TODO: Free associated map registers.
  2588. if (IRP_CONTEXT_IRP_STORAGE(Irp))
  2589. {
  2590. // get the IrpStream context
  2591. CIrpStream *that = (CIrpStream *)(PIRP_CONTEXT(IRP_CONTEXT_IRP_STORAGE(Irp))->IrpStream);
  2592. //
  2593. // if we get here from CancelAllIrps we are assured that the spinlocks
  2594. // are held properly. if we get here from an arbitrary irp cancellation we won't
  2595. // have either the revoke or the mapping spinlock held. In that case we need to
  2596. // grab both locks here and release them after the CancelMappings call.
  2597. //
  2598. if ( that->m_CancelAllIrpsThread == KeGetCurrentThread()) {
  2599. that->CancelMappings(Irp);
  2600. } else {
  2601. //
  2602. // If we get here from CancelAllIrps we are assured that the spinlocks
  2603. // are held properly. However, if we get here from an arbitrary irp
  2604. // cancellation, we won't hold either the revoke or the mapping spinlock.
  2605. // In that case, we need to grab both locks around CancelMappings().
  2606. //
  2607. KIRQL kIrqlOldRevoke;
  2608. // must always grab revoke lock BEFORE master lock
  2609. KeAcquireSpinLock(&that->m_RevokeLock, &kIrqlOldRevoke);
  2610. KeAcquireSpinLockAtDpcLevel(&that->m_kSpinLock);
  2611. that->CancelMappings(Irp);
  2612. // release the spinlocks, master first
  2613. KeReleaseSpinLockFromDpcLevel(&that->m_kSpinLock);
  2614. KeReleaseSpinLock(&that->m_RevokeLock, kIrqlOldRevoke);
  2615. }
  2616. // Free the context memory we allocated
  2617. ExFreePool(IRP_CONTEXT_IRP_STORAGE(Irp));
  2618. IRP_CONTEXT_IRP_STORAGE(Irp) = NULL;
  2619. }
  2620. else
  2621. {
  2622. ASSERT( !"Freeing IRP with no context");
  2623. }
  2624. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  2625. }
  2626. /*****************************************************************************
  2627. * CIrpStream::CancelMappings()
  2628. *****************************************************************************
  2629. * Cancel mappings for an IRP or all IRPs.
  2630. */
  2631. void
  2632. CIrpStream::
  2633. CancelMappings
  2634. (
  2635. IN PIRP pIrp
  2636. )
  2637. {
  2638. // NOTE: the revoke and master spinlocks must be held before calling this routine
  2639. // check only if we have a non-empty mapping queue
  2640. if( (MappingQueue.Array) &&
  2641. (MappingQueue.Head != MappingQueue.Tail) )
  2642. {
  2643. ULONG ulPosition = MappingQueue.Head;
  2644. ULONG ulFirst = ULONG(-1);
  2645. ULONG ulLast = ULONG(-1);
  2646. ULONG ulMappingCount = 0;
  2647. // walk mapping queue from head to tail
  2648. while( ulPosition != MappingQueue.Tail )
  2649. {
  2650. // get the mapping queue entry
  2651. PMAPPING_QUEUE_ENTRY entry = &MappingQueue.Array[ulPosition];
  2652. // check if this mapping belongs to the irp(s) being cancelled
  2653. if( (NULL == pIrp) || (entry->Irp == pIrp) )
  2654. {
  2655. // check if the mapping has been delivered
  2656. if( entry->MappingStatus == MAPPING_STATUS_DELIVERED )
  2657. {
  2658. _DbgPrintF(DEBUGLVL_VERBOSE,("CancelMappings %d needs revoking",ulPosition));
  2659. // keep track of this for the driver revoke call
  2660. if( ulFirst == ULONG(-1) )
  2661. {
  2662. ulFirst = ulPosition;
  2663. }
  2664. ulLast = ulPosition;
  2665. ulMappingCount++;
  2666. }
  2667. // is this the last mapping in a packet (and not previously revoked)?
  2668. if( ( ( entry->Flags & MAPPING_FLAG_END_OF_PACKET ) ||
  2669. ( entry->Flags & MAPPING_FLAG_END_OF_SUBPACKET) ) &&
  2670. ( entry->MappingStatus != MAPPING_STATUS_REVOKED ) )
  2671. {
  2672. // do we need to revoke anything in the driver?
  2673. if( ulMappingCount )
  2674. {
  2675. ULONG ulRevoked = ulMappingCount; // init to how many we are asking for
  2676. // revoke mappings in the driver
  2677. if( NotifyPhysical )
  2678. {
  2679. _DbgPrintF(DEBUGLVL_VERBOSE,("CancelMappings REVOKING (%d)",ulMappingCount));
  2680. NotifyPhysical->MappingsCancelled( MappingQueue.Array[ulFirst].Tag,
  2681. MappingQueue.Array[ulLast].Tag,
  2682. &ulRevoked );
  2683. #if (DBG)
  2684. MappingsOutstanding -= ulRevoked;
  2685. #endif
  2686. }
  2687. // check if all were revoked
  2688. if( ulRevoked != ulMappingCount )
  2689. {
  2690. _DbgPrintF(DEBUGLVL_TERSE,("Mappings not fully revoked (%d of %d)",
  2691. ulRevoked,
  2692. ulMappingCount));
  2693. }
  2694. // reset the revoke tracking
  2695. ulFirst = ULONG(-1);
  2696. ulLast = ULONG(-1);
  2697. ulMappingCount = 0;
  2698. }
  2699. // get the packet header
  2700. PPACKET_HEADER header = entry->PacketHeader;
  2701. // release the mappings in this subpacket
  2702. if( ( header ) &&
  2703. ( entry->SubpacketVa ) &&
  2704. ( entry->SubpacketBytes ) )
  2705. {
  2706. // flush and free the mappings and map registers
  2707. IoFlushAdapterBuffers( BusMasterAdapterObject,
  2708. header->MdlAddress,
  2709. entry->MapRegisterBase,
  2710. entry->SubpacketVa,
  2711. entry->SubpacketBytes,
  2712. WriteOperation );
  2713. IoFreeMapRegisters( BusMasterAdapterObject,
  2714. entry->MapRegisterBase,
  2715. ADDRESS_AND_SIZE_TO_SPAN_PAGES( entry->SubpacketVa,
  2716. entry->SubpacketBytes ) );
  2717. if( entry->Flags & MAPPING_FLAG_END_OF_PACKET )
  2718. {
  2719. // decrement the map count if this is the end of a packet
  2720. header->MapCount--;
  2721. }
  2722. }
  2723. else
  2724. {
  2725. _DbgPrintF(DEBUGLVL_TERSE,("Mapping entry with EOP flag set and NULL packet header"));
  2726. }
  2727. }
  2728. // mark the mapping as revoked
  2729. entry->MappingStatus = MAPPING_STATUS_REVOKED;
  2730. }
  2731. // move on to the next entry
  2732. if( ++ulPosition == MAPPING_QUEUE_SIZE )
  2733. {
  2734. ulPosition = 0;
  2735. }
  2736. }
  2737. }
  2738. }
  2739. #if (DBG)
  2740. /*****************************************************************************
  2741. * CIrpStream::DbgQueues()
  2742. *****************************************************************************
  2743. * Show the queues.
  2744. */
  2745. void
  2746. CIrpStream::
  2747. DbgQueues
  2748. ( void
  2749. )
  2750. {
  2751. PLIST_ENTRY entry = LockedQueue.Flink;
  2752. _DbgPrintF(DEBUGLVL_BLAB,("DbgQueues() LockedQueue"));
  2753. while(entry != &LockedQueue)
  2754. {
  2755. PIRP irp = PIRP(CONTAINING_RECORD(entry,IRP,Tail.Overlay.ListEntry));
  2756. _DbgPrintF(DEBUGLVL_BLAB,(" %d 0x%8x",IRP_CONTEXT_IRP_STORAGE(irp)->IrpLabel,irp));
  2757. entry = entry->Flink;
  2758. }
  2759. entry = MappedQueue.Flink;
  2760. _DbgPrintF(DEBUGLVL_BLAB,("DbgQueues() MappedQueue"));
  2761. while(entry != &MappedQueue)
  2762. {
  2763. PIRP irp = PIRP(CONTAINING_RECORD(entry,IRP,Tail.Overlay.ListEntry));
  2764. _DbgPrintF(DEBUGLVL_BLAB,(" %d 0x%8x",IRP_CONTEXT_IRP_STORAGE(irp)->IrpLabel,irp));
  2765. entry = entry->Flink;
  2766. }
  2767. }
  2768. #include "stdio.h"
  2769. STDMETHODIMP_(void)
  2770. CIrpStream::
  2771. DbgRollCall
  2772. (
  2773. IN ULONG MaxNameSize,
  2774. OUT PCHAR Name,
  2775. OUT PIKSSHELLTRANSPORT* NextTransport,
  2776. OUT PIKSSHELLTRANSPORT* PrevTransport
  2777. )
  2778. /*++
  2779. Routine Description:
  2780. This routine produces a component name and the transport pointers.
  2781. Arguments:
  2782. Return Value:
  2783. --*/
  2784. {
  2785. _DbgPrintF(DEBUGLVL_BLAB,("CIrpStream::DbgRollCall"));
  2786. PAGED_CODE();
  2787. ASSERT(Name);
  2788. ASSERT(NextTransport);
  2789. ASSERT(PrevTransport);
  2790. ULONG references = AddRef() - 1; Release();
  2791. _snprintf(Name,MaxNameSize,"IrpStream%p refs=%d\n",this,references);
  2792. *NextTransport = m_TransportSink;
  2793. *PrevTransport = m_TransportSource;
  2794. }
  2795. #endif // DBG
  2796. #endif // PC_KDEXT