Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7088 lines
198 KiB

  1. /*
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. upperapi.c
  5. Abstract:
  6. This is the WDM streaming class driver. This module contains code related
  7. to the driver's upper edge api.
  8. Author:
  9. billpa
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "codcls.h"
  15. #include "ksguid.h"
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, FilterDispatchGlobalCreate)
  18. #pragma alloc_text(PAGE, FilterDispatchIoControl)
  19. #pragma alloc_text(PAGE, FilterDispatchClose)
  20. #pragma alloc_text(PAGE, StreamDispatchCreate)
  21. #pragma alloc_text(PAGE, StreamDispatchIoControl)
  22. #pragma alloc_text(PAGE, StreamDispatchClose)
  23. #pragma alloc_text(PAGE, ClockDispatchCreate)
  24. #pragma alloc_text(PAGE, ClockDispatchIoControl)
  25. #pragma alloc_text(PAGE, ClockDispatchClose)
  26. #pragma alloc_text(PAGE, StreamClassMinidriverDeviceGetProperty)
  27. #pragma alloc_text(PAGE, StreamClassMinidriverDeviceSetProperty)
  28. #pragma alloc_text(PAGE, StreamClassMinidriverStreamGetProperty)
  29. #pragma alloc_text(PAGE, StreamClassMinidriverStreamSetProperty)
  30. #pragma alloc_text(PAGE, StreamClassNull)
  31. #pragma alloc_text(PAGE, SCStreamDeviceState)
  32. #pragma alloc_text(PAGE, SCStreamDeviceRate)
  33. #pragma alloc_text(PAGE, SCFilterPinInstances)
  34. #pragma alloc_text(PAGE, SCFilterPinPropertyHandler)
  35. #pragma alloc_text(PAGE, SCOpenStreamCallback)
  36. #pragma alloc_text(PAGE, SCOpenMasterCallback)
  37. #if ENABLE_MULTIPLE_FILTER_TYPES
  38. #else
  39. #pragma alloc_text(PAGE, SCGlobalInstanceCallback)
  40. #endif
  41. #pragma alloc_text(PAGE, SCSetMasterClock)
  42. #pragma alloc_text(PAGE, SCClockGetTime)
  43. #pragma alloc_text(PAGE, SCGetStreamDeviceState)
  44. #pragma alloc_text(PAGE, SCStreamDeviceRateCapability)
  45. #pragma alloc_text(PAGE, SCStreamProposeNewFormat)
  46. #pragma alloc_text(PAGE, SCStreamSetFormat)
  47. #pragma alloc_text(PAGE, AllocatorDispatchCreate)
  48. #pragma alloc_text(PAGE, SCGetMasterClock)
  49. #pragma alloc_text(PAGE, SCClockGetPhysicalTime)
  50. #pragma alloc_text(PAGE, SCClockGetSynchronizedTime)
  51. #pragma alloc_text(PAGE, SCClockGetFunctionTable)
  52. #pragma alloc_text(PAGE, SCCloseClockCallback)
  53. #pragma alloc_text(PAGE, SCFilterTopologyHandler)
  54. #pragma alloc_text(PAGE, SCFilterPinIntersectionHandler)
  55. #pragma alloc_text(PAGE, SCIntersectHandler)
  56. #pragma alloc_text(PAGE, SCDataIntersectionCallback)
  57. #pragma alloc_text(PAGE, SCGetStreamHeaderSize)
  58. #pragma alloc_text(PAGE, DllUnload)
  59. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  60. #pragma alloc_text(PAGE, SCStreamAllocator)
  61. #pragma alloc_text(PAGE, AllocateFrame)
  62. #pragma alloc_text(PAGE, FreeFrame)
  63. #pragma alloc_text(PAGE, PrepareTransfer)
  64. #pragma alloc_text(PAGE, PinCreateHandler)
  65. #endif
  66. #endif
  67. #ifdef ALLOC_DATA_PRAGMA
  68. #pragma const_seg("PAGECONST")
  69. #endif
  70. static const WCHAR ClockTypeName[] = KSSTRING_Clock;
  71. static const WCHAR AllocatorTypeName[] = KSSTRING_Allocator;
  72. //
  73. // this structure is the dispatch table for a filter instance of the device
  74. //
  75. DEFINE_KSDISPATCH_TABLE(
  76. FilterDispatchTable,
  77. FilterDispatchIoControl,
  78. KsDispatchInvalidDeviceRequest,
  79. KsDispatchInvalidDeviceRequest,
  80. KsDispatchInvalidDeviceRequest,
  81. FilterDispatchClose,
  82. NULL,
  83. NULL,
  84. NULL,
  85. NULL,
  86. NULL);
  87. //
  88. // dispatch table for pin properties that we support in the class driver
  89. //
  90. static DEFINE_KSPROPERTY_TABLE(PinPropertyHandlers)
  91. {
  92. DEFINE_KSPROPERTY_ITEM_PIN_CINSTANCES(SCFilterPinInstances),
  93. DEFINE_KSPROPERTY_ITEM_PIN_CTYPES(SCFilterPinPropertyHandler),
  94. DEFINE_KSPROPERTY_ITEM_PIN_DATAFLOW(SCFilterPinPropertyHandler),
  95. DEFINE_KSPROPERTY_ITEM_PIN_DATARANGES(SCFilterPinPropertyHandler),
  96. DEFINE_KSPROPERTY_ITEM_PIN_DATAINTERSECTION(SCFilterPinIntersectionHandler),
  97. DEFINE_KSPROPERTY_ITEM_PIN_INTERFACES(SCFilterPinPropertyHandler),
  98. DEFINE_KSPROPERTY_ITEM_PIN_MEDIUMS(SCFilterPinPropertyHandler),
  99. DEFINE_KSPROPERTY_ITEM_PIN_COMMUNICATION(SCFilterPinPropertyHandler),
  100. // DEFINE_KSPROPERTY_ITEM_PIN_GLOBALCINSTANCES(),
  101. // DEFINE_KSPROPERTY_ITEM_PIN_NECESSARYINSTANCES(),
  102. // DEFINE_KSPROPERTY_ITEM_PIN_PHYSICALCONNECTION(),
  103. DEFINE_KSPROPERTY_ITEM_PIN_CATEGORY(SCFilterPinPropertyHandler),
  104. DEFINE_KSPROPERTY_ITEM_PIN_NAME(SCFilterPinPropertyHandler)
  105. };
  106. static DEFINE_KSPROPERTY_TOPOLOGYSET(
  107. TopologyPropertyHandlers,
  108. SCFilterTopologyHandler);
  109. //
  110. // filter property sets supported by the class driver
  111. //
  112. static DEFINE_KSPROPERTY_SET_TABLE(FilterPropertySets)
  113. {
  114. DEFINE_KSPROPERTY_SET(
  115. &KSPROPSETID_Pin,
  116. SIZEOF_ARRAY(PinPropertyHandlers),
  117. (PKSPROPERTY_ITEM) PinPropertyHandlers,
  118. 0, NULL),
  119. DEFINE_KSPROPERTY_SET(
  120. &KSPROPSETID_Topology,
  121. SIZEOF_ARRAY(TopologyPropertyHandlers),
  122. (PKSPROPERTY_ITEM) TopologyPropertyHandlers,
  123. 0, NULL),
  124. };
  125. //
  126. // handlers for the control properties
  127. //
  128. static DEFINE_KSPROPERTY_TABLE(StreamControlHandlers)
  129. {
  130. DEFINE_KSPROPERTY_ITEM_CONNECTION_STATE(SCGetStreamDeviceState, SCStreamDeviceState),
  131. // DEFINE_KSPROPERTY_ITEM_CONNECTION_PRIORITY(),
  132. // DEFINE_KSPROPERTY_ITEM_CONNECTION_DATAFORMAT(),
  133. // DEFINE_KSPROPERTY_ITEM_CONNECTION_ALLOCATORFRAMING(),
  134. DEFINE_KSPROPERTY_ITEM_CONNECTION_PROPOSEDATAFORMAT(SCStreamProposeNewFormat),
  135. DEFINE_KSPROPERTY_ITEM_CONNECTION_DATAFORMAT(NULL, SCStreamSetFormat),
  136. // DEFINE_KSPROPERTY_ITEM_CONNECTION_ACQUIREORDERING(),
  137. };
  138. DEFINE_KSPROPERTY_TABLE(StreamStreamHandlers)
  139. {
  140. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  141. DEFINE_KSPROPERTY_ITEM_STREAM_ALLOCATOR(SCStreamAllocator,SCStreamAllocator),
  142. #else
  143. // DEFINE_KSPROPERTY_ITEM_STREAM_ALLOCATOR(),
  144. #endif
  145. // DEFINE_KSPROPERTY_ITEM_STREAM_QUALITY(),
  146. // DEFINE_KSPROPERTY_ITEM_STREAM_DEGRADATION(),
  147. DEFINE_KSPROPERTY_ITEM_STREAM_MASTERCLOCK(NULL, SCSetMasterClock),
  148. // DEFINE_KSPROPERTY_ITEM_STREAM_TIMEFORMAT(),
  149. // DEFINE_KSPROPERTY_ITEM_STREAM_PRESENTATIONTIME(),
  150. // DEFINE_KSPROPERTY_ITEM_STREAM_PRESENTATIONEXTENT(),
  151. // DEFINE_KSPROPERTY_ITEM_STREAM_FRAMETIME(),
  152. DEFINE_KSPROPERTY_ITEM_STREAM_RATECAPABILITY(SCStreamDeviceRateCapability),
  153. DEFINE_KSPROPERTY_ITEM_STREAM_RATE(NULL, SCStreamDeviceRate),
  154. };
  155. DEFINE_KSPROPERTY_TABLE(StreamInterfaceHandlers)
  156. {
  157. {
  158. KSPROPERTY_STREAMINTERFACE_HEADERSIZE,
  159. SCGetStreamHeaderSize,
  160. 0,
  161. 0,
  162. NULL,
  163. 0,
  164. 0,
  165. NULL
  166. }
  167. };
  168. //
  169. // stream property sets supported by the class driver
  170. //
  171. static DEFINE_KSPROPERTY_SET_TABLE(StreamProperties)
  172. {
  173. DEFINE_KSPROPERTY_SET(
  174. &KSPROPSETID_Connection,
  175. SIZEOF_ARRAY(StreamControlHandlers),
  176. (PVOID) StreamControlHandlers,
  177. 0, NULL),
  178. DEFINE_KSPROPERTY_SET(
  179. &KSPROPSETID_Stream,
  180. SIZEOF_ARRAY(StreamStreamHandlers),
  181. (PVOID) StreamStreamHandlers,
  182. 0, NULL),
  183. DEFINE_KSPROPERTY_SET(
  184. &KSPROPSETID_StreamInterface,
  185. SIZEOF_ARRAY(StreamInterfaceHandlers),
  186. (PVOID) StreamInterfaceHandlers,
  187. 0, NULL),
  188. };
  189. //
  190. // template for on the fly constructed properties
  191. // DO NOT CHANGE without MODIFYING the code that references this set.
  192. //
  193. DEFINE_KSPROPERTY_TABLE(ConstructedStreamHandlers)
  194. {
  195. DEFINE_KSPROPERTY_ITEM_STREAM_MASTERCLOCK(SCGetMasterClock, SCSetMasterClock)
  196. };
  197. //
  198. // template for on-the-fly constructed property sets.
  199. // DO NOT CHANGE without MODIFYING the code that references this set.
  200. //
  201. static DEFINE_KSPROPERTY_SET_TABLE(ConstructedStreamProperties)
  202. {
  203. DEFINE_KSPROPERTY_SET(
  204. &KSPROPSETID_Stream,
  205. SIZEOF_ARRAY(ConstructedStreamHandlers),
  206. (PVOID) ConstructedStreamHandlers,
  207. 0, NULL),
  208. };
  209. static const DEFINE_KSCREATE_DISPATCH_TABLE(StreamDriverDispatch)
  210. {
  211. DEFINE_KSCREATE_ITEM(ClockDispatchCreate,
  212. ClockTypeName,
  213. 0),
  214. DEFINE_KSCREATE_ITEM(AllocatorDispatchCreate,
  215. AllocatorTypeName,
  216. 0),
  217. };
  218. //
  219. // dispatch table for stream functions
  220. //
  221. DEFINE_KSDISPATCH_TABLE(
  222. StreamDispatchTable,
  223. StreamDispatchIoControl,
  224. KsDispatchInvalidDeviceRequest,
  225. KsDispatchInvalidDeviceRequest,
  226. KsDispatchInvalidDeviceRequest,
  227. StreamDispatchClose,
  228. NULL,
  229. NULL,
  230. NULL,
  231. NULL,
  232. NULL);
  233. DEFINE_KSDISPATCH_TABLE(
  234. ClockDispatchTable,
  235. ClockDispatchIoControl,
  236. KsDispatchInvalidDeviceRequest,
  237. KsDispatchInvalidDeviceRequest,
  238. KsDispatchInvalidDeviceRequest,
  239. ClockDispatchClose,
  240. KsDispatchInvalidDeviceRequest,
  241. KsDispatchInvalidDeviceRequest,
  242. KsDispatchFastIoDeviceControlFailure,
  243. KsDispatchFastReadFailure,
  244. KsDispatchFastWriteFailure);
  245. DEFINE_KSPROPERTY_TABLE(ClockPropertyItems)
  246. {
  247. DEFINE_KSPROPERTY_ITEM_CLOCK_TIME(SCClockGetTime),
  248. DEFINE_KSPROPERTY_ITEM_CLOCK_PHYSICALTIME(SCClockGetPhysicalTime),
  249. DEFINE_KSPROPERTY_ITEM_CLOCK_CORRELATEDTIME(SCClockGetSynchronizedTime),
  250. // DEFINE_KSPROPERTY_ITEM_CLOCK_CORRELATEDPHYSICALTIME(),
  251. // DEFINE_KSPROPERTY_ITEM_CLOCK_RESOLUTION(SCClockGetResolution),
  252. // DEFINE_KSPROPERTY_ITEM_CLOCK_STATE(SCClockGetState),
  253. DEFINE_KSPROPERTY_ITEM_CLOCK_FUNCTIONTABLE(SCClockGetFunctionTable)
  254. };
  255. DEFINE_KSPROPERTY_SET_TABLE(ClockPropertySets)
  256. {
  257. DEFINE_KSPROPERTY_SET(
  258. &KSPROPSETID_Clock,
  259. SIZEOF_ARRAY(ClockPropertyItems),
  260. ClockPropertyItems,
  261. 0,
  262. NULL
  263. )
  264. };
  265. #ifdef ALLOC_DATA_PRAGMA
  266. #pragma const_seg()
  267. #endif
  268. #if ENABLE_MULTIPLE_FILTER_TYPES
  269. NTSTATUS
  270. FilterDispatchGlobalCreate(
  271. IN PDEVICE_OBJECT DeviceObject,
  272. IN PIRP Irp)
  273. /*++
  274. Routine Description:
  275. This routine receives global createfile IRP's for the device.
  276. After the Srb_Open_Device_Instance instance we immediate
  277. send Srb_Get_Stream_Info for this filter.
  278. Arguments:
  279. DeviceObject - device object for the device
  280. Irp - probably an IRP, silly
  281. Return Value:
  282. The IRP status is set as appropriate
  283. --*/
  284. {
  285. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  286. PIO_STACK_LOCATION IrpStack;
  287. PFILTER_INSTANCE FilterInstance;
  288. NTSTATUS Status; // = STATUS_TOO_MANY_OPENED_FILES;
  289. IFN_MF( PAGED_CODE());
  290. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  291. DebugPrint((DebugLevelTrace,
  292. "'Closing global filter with Irp %x\n", Irp));
  293. //
  294. // show one more I/O pending & verify that we can actually do I/O.
  295. //
  296. Status = SCShowIoPending(DeviceObject->DeviceExtension, Irp);
  297. if ( !NT_SUCCESS ( Status )) {
  298. //
  299. // the device is currently not accessible, so just return with error
  300. //
  301. return (Status);
  302. } // if !showiopending
  303. //
  304. // if the device is not started, bail out.
  305. // swenum enables device interfaces very early. It should not have
  306. // done that for the pdo. we, the fdo, should be the one to
  307. // enable this. for now, try to work around the problem that we
  308. // come here before device is started.
  309. //
  310. if ( DeviceExtension->RegistryFlags & DRIVER_USES_SWENUM_TO_LOAD ) {
  311. #define OPEN_TIMEOUT -1000*1000 // 100 mili second
  312. #define OPEN_WAIT 50
  313. LARGE_INTEGER liOpenTimeOut;
  314. int i;
  315. liOpenTimeOut.QuadPart = OPEN_TIMEOUT;
  316. for ( i=0; i < OPEN_WAIT; i++ ) {
  317. if ( DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED ) {
  318. break;
  319. }
  320. KeDelayExecutionThread( KernelMode, FALSE, &liOpenTimeOut );
  321. }
  322. if ( 0 == (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) ) {
  323. Status = STATUS_DEVICE_NOT_READY;
  324. Irp->IoStatus.Status = Status;
  325. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  326. DebugPrint((DebugLevelError,
  327. "SWEnum device %p not ready!\n", DeviceObject));
  328. return Status;
  329. }
  330. }
  331. //
  332. // show one more reference to driver.
  333. //
  334. SCReferenceDriver(DeviceExtension);
  335. //
  336. // set the context of createfiles for the filter
  337. //
  338. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  339. Executive,
  340. KernelMode,
  341. FALSE,// not alertable
  342. NULL);
  343. //
  344. // Make sure adapter is powered on
  345. //
  346. SCCheckPoweredUp(DeviceExtension);
  347. Status = SCOpenMinidriverInstance(DeviceExtension,
  348. &FilterInstance,
  349. NULL, //SCGlobalInstanceCallback,
  350. Irp);
  351. //
  352. // if status != success, we failed so dereference the
  353. // driver.
  354. //
  355. if (!NT_SUCCESS(Status)) {
  356. //
  357. // show one fewer reference to driver.
  358. //
  359. SCDereferenceDriver(DeviceExtension);
  360. }
  361. else {
  362. //
  363. // Open is successul. Fill in the filter dispatch table pointer
  364. //
  365. if ( 0 == DeviceExtension->NumberOfOpenInstances ||
  366. 0 != DeviceExtension->FilterExtensionSize ) {
  367. //
  368. // 1st open of 1x1 or non 1x1 ( i.e. instance opne )
  369. //
  370. // add FilterInstance to DeviceExtension except non-1st open of legacy 1x1
  371. //
  372. PHW_STREAM_DESCRIPTOR StreamDescriptor, StreamDescriptorI;
  373. ULONG nPins;
  374. //
  375. // remeber DO for later
  376. //
  377. FilterInstance->DeviceObject = DeviceObject;
  378. //
  379. // Process stream info for this filterinstance
  380. //
  381. StreamDescriptorI = DeviceExtension->FilterTypeInfos
  382. [FilterInstance->FilterTypeIndex].StreamDescriptor;
  383. nPins = StreamDescriptorI->StreamHeader.NumberOfStreams;
  384. StreamDescriptor =
  385. ExAllocatePool( NonPagedPool,
  386. sizeof(HW_STREAM_HEADER) +
  387. sizeof(HW_STREAM_INFORMATION) * nPins );
  388. if ( NULL != StreamDescriptor ) {
  389. RtlCopyMemory( StreamDescriptor,
  390. StreamDescriptorI,
  391. sizeof(HW_STREAM_HEADER) +
  392. sizeof(HW_STREAM_INFORMATION) * nPins );
  393. Status = SciOnFilterStreamDescriptor(
  394. FilterInstance,
  395. StreamDescriptor);
  396. if ( NT_SUCCESS( Status ) ) {
  397. FilterInstance->StreamDescriptor = StreamDescriptor;
  398. DebugPrint((DebugLevelInfo,
  399. "NumNameExtensions=%x NumopenInstances=%x "
  400. "FilterInstance %x StreamDescriptor %x\n",
  401. DeviceExtension->NumberOfNameExtensions,
  402. DeviceExtension->NumberOfOpenInstances,
  403. FilterInstance,
  404. StreamDescriptor));
  405. }
  406. }
  407. else {
  408. Status = STATUS_INSUFFICIENT_RESOURCES;
  409. }
  410. }
  411. DeviceExtension->NumberOfOpenInstances++;
  412. DebugPrint((DebugLevelVerbose,
  413. "DevExt:%x, Open OpenCount=%x\n",
  414. DeviceExtension,
  415. DeviceExtension->NumberOfOpenInstances));
  416. //
  417. // Make FilterInstance the File Handle Context
  418. //
  419. IrpStack->FileObject->FsContext = FilterInstance;
  420. DebugPrint((DebugLevelVerbose,
  421. "CreateFilterInstance=%x ExtSize=%x\n",
  422. FilterInstance,
  423. DeviceExtension->MinidriverData->HwInitData.FilterInstanceExtensionSize ));
  424. //
  425. // Reference the FDO so that itwon't go away before all handles are closed.
  426. //
  427. ObReferenceObject(DeviceObject);
  428. }
  429. //
  430. // we're done so release the event
  431. //
  432. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  433. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  434. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  435. }
  436. #else // ENABLE_MULTIPLE_FILTER_TYPES
  437. #endif // ENABLE_MULTIPLE_FILTER_TYPES
  438. NTSTATUS
  439. StreamDispatchCreate(
  440. IN PDEVICE_OBJECT DeviceObject,
  441. IN PIRP Irp
  442. )
  443. /*++
  444. Routine Description:
  445. This routine receives createfile IRP's for a stream.
  446. Arguments:
  447. DeviceObject - device object for the device
  448. Irp - probably an IRP, silly
  449. Return Value:
  450. The IRP status is set as appropriate
  451. --*/
  452. {
  453. NTSTATUS Status;
  454. PFILTER_INSTANCE FilterInstance;
  455. PIO_STACK_LOCATION IrpStack;
  456. PKSPIN_CONNECT Connect;
  457. PFILE_OBJECT FileObject;
  458. PSTREAM_OBJECT StreamObject;
  459. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)
  460. DeviceObject->DeviceExtension;
  461. PHW_STREAM_INFORMATION CurrentInfo;
  462. ULONG i;
  463. BOOLEAN RequestIssued;
  464. PADDITIONAL_PIN_INFO AdditionalInfo;
  465. DebugPrint((DebugLevelTrace,
  466. "'Creating stream with Irp %x\n", Irp));
  467. PAGED_CODE();
  468. DebugPrint((DebugLevelTrace,"entering StreamDispatchCreate()\n"));
  469. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  470. DeviceExtension = DeviceObject->DeviceExtension;
  471. //
  472. // show one more I/O pending & verify that we can actually do I/O.
  473. //
  474. Status = SCShowIoPending(DeviceExtension, Irp);
  475. if ( !NT_SUCCESS ( Status )) {
  476. //
  477. // the device is currently not accessible, so just return with error
  478. //
  479. DebugPrint((DebugLevelError,"exiting StreamDispatchCreate():error1\n"));
  480. return (Status);
  481. }
  482. //
  483. // get the parent file object from the child object.
  484. //
  485. FileObject = IrpStack->FileObject->RelatedFileObject;
  486. //
  487. // get the filter instance & additional info pointers
  488. //
  489. FilterInstance =
  490. (PFILTER_INSTANCE) FileObject->FsContext;
  491. AdditionalInfo = FilterInstance->PinInstanceInfo;
  492. DebugPrint((DebugLevelVerbose,
  493. "FilterInstance=%x NumberOfPins=%x PinInfo=%x\n",
  494. FilterInstance,
  495. FilterInstance->NumberOfPins,
  496. FilterInstance->PinInformation));
  497. Status = KsValidateConnectRequest(Irp,
  498. FilterInstance->NumberOfPins,
  499. FilterInstance->PinInformation,
  500. &Connect);
  501. if ( !NT_SUCCESS( Status )) {
  502. DebugPrint((DebugLevelError,
  503. "exiting StreamDispatchCreate():error2\n"));
  504. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  505. }
  506. //
  507. // take the control event to protect the instance counter
  508. //
  509. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  510. Executive,
  511. KernelMode,
  512. FALSE,// not alertable
  513. NULL);
  514. //
  515. // if the # of instances for this pin is already opened, error the
  516. // request.
  517. //
  518. DebugPrint((DebugLevelVerbose,
  519. "AdditionalInfo@%x PinId=%x CurrentInstances=%x Max=%x\n",
  520. AdditionalInfo, Connect->PinId,
  521. AdditionalInfo[Connect->PinId].CurrentInstances,
  522. AdditionalInfo[Connect->PinId].MaxInstances));
  523. if (AdditionalInfo[Connect->PinId].CurrentInstances ==
  524. AdditionalInfo[Connect->PinId].MaxInstances) {
  525. DebugPrint((DebugLevelWarning,
  526. "StreamDispatchCreate: too many opens "));
  527. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  528. DebugPrint((DebugLevelError,"exiting StreamDispatchCreate():error3\n"));
  529. return (SCCompleteIrp(Irp, STATUS_TOO_MANY_OPENED_FILES, DeviceExtension));
  530. }
  531. //
  532. // initialize the stream object for this instance
  533. //
  534. StreamObject = ExAllocatePool(NonPagedPool,
  535. sizeof(STREAM_OBJECT) +
  536. DeviceExtension->MinidriverData->
  537. HwInitData.PerStreamExtensionSize
  538. );
  539. if (!StreamObject) {
  540. DebugPrint((DebugLevelError,
  541. "StreamDispatchCreate: No pool for stream info"));
  542. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  543. DebugPrint((DebugLevelError,"exiting StreamDispatchCreate():error4\n"));
  544. return (SCCompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, DeviceExtension));
  545. }
  546. RtlZeroMemory(StreamObject,
  547. sizeof(STREAM_OBJECT) +
  548. DeviceExtension->MinidriverData->
  549. HwInitData.PerStreamExtensionSize
  550. );
  551. //
  552. // TODO: Remove this once KS can multiplex CLEANUP requests.
  553. //
  554. StreamObject->ComObj.Cookie = STREAM_OBJECT_COOKIE;
  555. //
  556. // default state to stopped
  557. //
  558. StreamObject->CurrentState = KSSTATE_STOP;
  559. KsAllocateObjectHeader(&StreamObject->ComObj.DeviceHeader,
  560. SIZEOF_ARRAY(StreamDriverDispatch),
  561. (PKSOBJECT_CREATE_ITEM) StreamDriverDispatch,
  562. Irp,
  563. (PKSDISPATCH_TABLE) & StreamDispatchTable);
  564. StreamObject->HwStreamObject.StreamNumber = Connect->PinId;
  565. StreamObject->FilterFileObject = FileObject;
  566. StreamObject->FileObject = IrpStack->FileObject;
  567. StreamObject->FilterInstance = FilterInstance;
  568. StreamObject->DeviceExtension = DeviceExtension;
  569. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  570. StreamObject->PinToHandle = Connect->PinToHandle;
  571. #endif
  572. KeInitializeEvent (&StreamObject -> StopEvent, SynchronizationEvent, FALSE);
  573. //
  574. // For potential "source" pins, don't start sourcing standard
  575. // medium/interface stream requests across non-standard medium/interfaces.
  576. //
  577. if (!IsEqualGUIDAligned (&Connect->Medium.Set, &KSMEDIUMSETID_Standard) ||
  578. !IsEqualGUIDAligned (&Connect->Interface.Set, &KSINTERFACESETID_Standard)) {
  579. StreamObject->StandardTransport = FALSE;
  580. } else {
  581. StreamObject -> StandardTransport = TRUE;
  582. }
  583. //
  584. // set the minidriver's parameters in the HwStreamObject struct.
  585. //
  586. StreamObject->HwStreamObject.SizeOfThisPacket = sizeof(HW_STREAM_OBJECT);
  587. StreamObject->HwStreamObject.HwDeviceExtension =
  588. DeviceExtension->HwDeviceExtension;
  589. StreamObject->HwStreamObject.HwStreamExtension =
  590. (PVOID) (StreamObject + 1);
  591. //
  592. // walk the minidriver's stream info structure to find the properties
  593. // for this stream.
  594. //
  595. if ( NULL == FilterInstance->StreamDescriptor ) {
  596. //
  597. // has not reenum, use the global one
  598. //
  599. CurrentInfo = &DeviceExtension->StreamDescriptor->StreamInfo;
  600. }
  601. else {
  602. CurrentInfo = &FilterInstance->StreamDescriptor->StreamInfo;
  603. }
  604. CurrentInfo = CurrentInfo + Connect->PinId;
  605. //
  606. // set the property info in the stream object.
  607. //
  608. StreamObject->PropertyInfo = FilterInstance->
  609. StreamPropEventArray[Connect->PinId].StreamPropertiesArray;
  610. StreamObject->PropInfoSize = CurrentInfo->
  611. NumStreamPropArrayEntries;
  612. //
  613. // set the event info in the stream object
  614. //
  615. StreamObject->EventInfo = FilterInstance->
  616. StreamPropEventArray[Connect->PinId].StreamEventsArray;
  617. StreamObject->EventInfoCount = CurrentInfo->
  618. NumStreamEventArrayEntries;
  619. // moved from callback
  620. InitializeListHead(&StreamObject->NotifyList);
  621. //
  622. // call the minidriver to open the stream. processing will continue
  623. // when the callback procedure is called.
  624. //
  625. Status = SCSubmitRequest(SRB_OPEN_STREAM,
  626. (PVOID) (Connect + 1),
  627. 0,
  628. SCOpenStreamCallback,
  629. DeviceExtension,
  630. FilterInstance->HwInstanceExtension,
  631. &StreamObject->HwStreamObject,
  632. Irp,
  633. &RequestIssued,
  634. &DeviceExtension->PendingQueue,
  635. (PVOID) DeviceExtension->
  636. MinidriverData->HwInitData.
  637. HwReceivePacket
  638. );
  639. if (!RequestIssued) {
  640. //
  641. // failure submitting the request
  642. //
  643. DEBUG_BREAKPOINT();
  644. ExFreePool(StreamObject);
  645. DebugPrint((DebugLevelWarning,
  646. "StreamClassOpen: stream open failed"));
  647. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  648. DebugPrint((DebugLevelError,"exiting StreamDispatchCreate():error6\n"));
  649. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  650. }
  651. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  652. DebugPrint((DebugLevelTrace,"exiting StreamDispatchCreate()\n"));
  653. return (Status);
  654. }
  655. NTSTATUS
  656. SCOpenStreamCallback(
  657. IN PSTREAM_REQUEST_BLOCK SRB
  658. )
  659. /*++
  660. Routine Description:
  661. Process the completion of a stream open
  662. Arguments:
  663. SRB - address of the completed SRB
  664. Return Value:
  665. None.
  666. --*/
  667. {
  668. PDEVICE_EXTENSION DeviceExtension =
  669. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  670. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  671. SRB->HwSRB.StreamObject,
  672. STREAM_OBJECT,
  673. HwStreamObject
  674. );
  675. PIRP Irp = SRB->HwSRB.Irp;
  676. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  677. NTSTATUS Status = SRB->HwSRB.Status;
  678. PADDITIONAL_PIN_INFO AdditionalInfo;
  679. PVOID PropertyInfo;
  680. PKSPROPERTY_ITEM PropertyItem;
  681. PHW_STREAM_INFORMATION CurrentInfo;
  682. ULONG i;
  683. PAGED_CODE();
  684. if (NT_SUCCESS(Status)) {
  685. //
  686. // if required parameters have not been filled in, fail the open.
  687. //
  688. if (!StreamObject->HwStreamObject.ReceiveControlPacket) {
  689. DEBUG_BREAKPOINT();
  690. ExFreePool(StreamObject);
  691. SRB->HwSRB.Status = STATUS_ADAPTER_HARDWARE_ERROR;
  692. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  693. return (SCProcessCompletedRequest(SRB));
  694. }
  695. //
  696. // if the minidriver does not accept data, use dummy routine.
  697. //
  698. if (!StreamObject->HwStreamObject.ReceiveDataPacket) {
  699. StreamObject->HwStreamObject.ReceiveDataPacket = SCErrorDataSRB;
  700. }
  701. //
  702. // Save the pointer to our per stream structure in the FsContext
  703. // field of FileObject. Null out the 2nd context param.
  704. //
  705. IrpStack->FileObject->FsContext = StreamObject;
  706. IrpStack->FileObject->FsContext2 = NULL;
  707. //
  708. // Initialize ControlSetMasterClock to serialize the concurrent
  709. // calls of the function on us, and lock the Read/write of the
  710. // MasterLockInfo
  711. //
  712. KeInitializeEvent(&StreamObject->ControlSetMasterClock, SynchronizationEvent, TRUE);
  713. KeInitializeSpinLock(&StreamObject->LockUseMasterClock );
  714. DebugPrint((DebugLevelTrace, "'StreamClassOpen: Stream opened.\n"));
  715. //
  716. // Initialize minidriver timer and timer DPC for this stream
  717. //
  718. KeInitializeTimer(&StreamObject->ComObj.MiniDriverTimer);
  719. KeInitializeDpc(&StreamObject->ComObj.MiniDriverTimerDpc,
  720. SCMinidriverStreamTimerDpc,
  721. StreamObject);
  722. //
  723. // initialize the lists for this stream
  724. //
  725. InitializeListHead(&StreamObject->DataPendingQueue);
  726. InitializeListHead(&StreamObject->ControlPendingQueue);
  727. InitializeListHead(&StreamObject->NextStream);
  728. // a mini driver might start to call GetNextEvent once
  729. // returns from SRB_OPNE_STREAM. Do it earlier than submit.
  730. //InitializeListHead(&StreamObject->NotifyList);
  731. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  732. InitializeListHead(&StreamObject->FreeQueue);
  733. KeInitializeSpinLock(&StreamObject->FreeQueueLock );
  734. InitializeListHead(&StreamObject->Queues[READ].ActiveQueue);
  735. KeInitializeSpinLock(&StreamObject->Queues[READ].QueueLock );
  736. InitializeListHead(&StreamObject->Queues[WRITE].ActiveQueue);
  737. KeInitializeSpinLock(&StreamObject->Queues[WRITE].QueueLock );
  738. StreamObject->PinId = StreamObject->HwStreamObject.StreamNumber;
  739. StreamObject->PinType = IrpSink; // assume irp sink
  740. if (StreamObject->PinToHandle) { // if irp source
  741. StreamObject->PinType = IrpSource;
  742. Status = PinCreateHandler( Irp, StreamObject );
  743. if (!NT_SUCCESS(Status)) {
  744. DebugPrint((DebugLevelError,
  745. "\nStreamDispatchCreate: PinCreateHandler() returned ERROR"));
  746. ExFreePool(StreamObject);
  747. SRB->HwSRB.Status = Status;
  748. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  749. return (SCProcessCompletedRequest(SRB));
  750. }
  751. }
  752. #endif
  753. //
  754. // show we're ready for a request. Don't show this for data if the
  755. // minidriver does not want data on this stream.
  756. //
  757. CurrentInfo = &DeviceExtension->StreamDescriptor->StreamInfo;
  758. for (i = 0; i < StreamObject->HwStreamObject.StreamNumber; i++) {
  759. //
  760. // index to next streaminfo structure
  761. //
  762. CurrentInfo++;
  763. }
  764. if (CurrentInfo->DataAccessible) {
  765. StreamObject->ReadyForNextDataReq = TRUE;
  766. }
  767. StreamObject->ReadyForNextControlReq = TRUE;
  768. //
  769. // call locked routine to insert this stream in the list
  770. //
  771. SCInsertStreamInFilter(StreamObject, DeviceExtension);
  772. //
  773. // reference the filter so we won't be called to close the instance
  774. // before all streams are closed.
  775. //
  776. ObReferenceObject(IrpStack->FileObject->RelatedFileObject);
  777. //
  778. // call routine to update the persisted properties for this pin, if
  779. // any.
  780. //
  781. SCUpdatePersistedProperties(StreamObject, DeviceExtension,
  782. IrpStack->FileObject);
  783. //
  784. // show one more instance of this pin opened.
  785. //
  786. AdditionalInfo = ((PFILTER_INSTANCE) IrpStack->FileObject->
  787. RelatedFileObject->FsContext)->PinInstanceInfo;
  788. AdditionalInfo[StreamObject->HwStreamObject.StreamNumber].
  789. CurrentInstances++;
  790. //
  791. // construct on-the-fly properties for the stream, if necessary
  792. //
  793. if (StreamObject->HwStreamObject.HwClockObject.HwClockFunction) {
  794. //
  795. // create a property set describing the characteristics of the
  796. // clock.
  797. //
  798. PropertyInfo = ExAllocatePool(PagedPool,
  799. sizeof(ConstructedStreamHandlers) +
  800. sizeof(ConstructedStreamProperties));
  801. if (PropertyInfo) {
  802. PropertyItem = (PKSPROPERTY_ITEM) ((ULONG_PTR) PropertyInfo +
  803. sizeof(ConstructedStreamProperties));
  804. RtlCopyMemory(PropertyInfo,
  805. &ConstructedStreamProperties,
  806. sizeof(ConstructedStreamProperties));
  807. RtlCopyMemory(PropertyItem,
  808. &ConstructedStreamHandlers,
  809. sizeof(ConstructedStreamHandlers));
  810. //
  811. // patch the address of the handler
  812. //
  813. ((PKSPROPERTY_SET) PropertyInfo)->PropertyItem = PropertyItem;
  814. //
  815. // modify the master clock property based on the support
  816. // level.
  817. //
  818. if (0 == (StreamObject->HwStreamObject.HwClockObject.ClockSupportFlags
  819. & CLOCK_SUPPORT_CAN_RETURN_STREAM_TIME)) {
  820. DEBUG_BREAKPOINT();
  821. PropertyItem->GetPropertyHandler
  822. = NULL;
  823. } // if cannot return stream time
  824. StreamObject->ConstructedPropInfoSize =
  825. SIZEOF_ARRAY(ConstructedStreamProperties);
  826. StreamObject->ConstructedPropertyInfo =
  827. (PKSPROPERTY_SET) PropertyInfo;
  828. } // if property info
  829. } // if clock function
  830. } else {
  831. ExFreePool(StreamObject);
  832. } // if good status
  833. //
  834. // signal the event and complete the IRP.
  835. //
  836. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  837. SCProcessCompletedRequest(SRB);
  838. return (Status);
  839. }
  840. NTSTATUS
  841. SCSetMasterClockWhenDeviceInaccessible(
  842. IN PDEVICE_OBJECT DeviceObject,
  843. IN PIRP Irp )
  844. /*++
  845. Description:
  846. This function look for special case in pin property request when the device
  847. is inaccessible, probably by surprise removal. Yet we need to process the
  848. SetMasterClock(NULL) so that the MC ref'ed by us can be released. The MC could
  849. be on our pin or external.
  850. This function should only be called in StreamDispatchIoControl. We look for the
  851. Stream property.SetMasterClock(NULL). We returned SUCCESS if it is. Otherwise
  852. we return STATUS_UNCESSFUL to indicate that we don't process it.
  853. Arguments:
  854. DeviceObject - Device Object for the device
  855. Irp - the request packet
  856. Return:
  857. SUCCESS : If it is streamproperty.setmasterclock(NULL).
  858. UNSUCCESSFUL : otherwise.
  859. --*/
  860. {
  861. NTSTATUS Status=STATUS_UNSUCCESSFUL;
  862. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  863. ULONG InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  864. ULONG OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  865. PKSPROPERTY Property;
  866. if ( IOCTL_KS_PROPERTY == IrpStack->Parameters.DeviceIoControl.IoControlCode &&
  867. InputBufferLength >= sizeof(KSPROPERTY) &&
  868. OutputBufferLength >= sizeof( HANDLE )) {
  869. //
  870. // only ksproperty is in our interest.
  871. //
  872. try {
  873. //
  874. // Validate the pointers if the client is not trusted.
  875. //
  876. if (Irp->RequestorMode != KernelMode) {
  877. ProbeForRead(IrpStack->Parameters.DeviceIoControl.Type3InputBuffer,
  878. InputBufferLength,
  879. sizeof(BYTE));
  880. ProbeForRead(Irp->UserBuffer,
  881. OutputBufferLength,
  882. sizeof(DWORD));
  883. }
  884. } except (EXCEPTION_EXECUTE_HANDLER) {
  885. return STATUS_UNSUCCESSFUL;
  886. }
  887. //
  888. // Capture the property request
  889. //
  890. Property = (PKSPROPERTY)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
  891. if ( KSPROPERTY_TYPE_SET == Property->Flags &&
  892. KSPROPERTY_STREAM_MASTERCLOCK == Property->Id &&
  893. IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_Stream) &&
  894. NULL == *(PHANDLE) Irp->UserBuffer ) {
  895. //
  896. // All match. Now process it. In theory we should call mini driver.
  897. // But we did not before. To avoid potential regression in mini drivers
  898. // we refrain from sending set_master_clock in this condition.
  899. //
  900. PSTREAM_OBJECT StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  901. DebugPrint((DebugLevelInfo, "SCSetMasterClockWhen:Devobj %x Irp %x\n",
  902. DeviceObject, Irp));
  903. if (StreamObject->MasterClockInfo) {
  904. ObDereferenceObject(StreamObject->MasterClockInfo->ClockFileObject);
  905. ExFreePool(StreamObject->MasterClockInfo);
  906. StreamObject->MasterClockInfo = NULL;
  907. }
  908. return STATUS_SUCCESS;
  909. }
  910. }
  911. return Status;
  912. }
  913. NTSTATUS
  914. StreamDispatchIoControl
  915. (
  916. IN PDEVICE_OBJECT DeviceObject,
  917. IN PIRP Irp
  918. )
  919. /*++
  920. Routine Description:
  921. Process an ioctl to the stream.
  922. Arguments:
  923. DeviceObject - device object for the device
  924. Irp - probably an IRP, silly
  925. Return Value:
  926. NTSTATUS returned as appropriate.
  927. --*/
  928. {
  929. NTSTATUS Status;
  930. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  931. PDEVICE_EXTENSION DeviceExtension;
  932. PSTREAM_OBJECT StreamObject = (PSTREAM_OBJECT)
  933. IrpStack->FileObject->FsContext;
  934. PAGED_CODE();
  935. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  936. DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  937. //
  938. // show one more I/O pending & verify that we can actually do I/O.
  939. //
  940. Status = STATUS_INVALID_DEVICE_REQUEST;
  941. ///Status = SCShowIoPending(DeviceExtension, Irp);
  942. if (DeviceExtension->Flags & DEVICE_FLAGS_DEVICE_INACCESSIBLE) {
  943. ///
  944. // Note. When our device is surprised removed && we have ref on the master clock
  945. // && we receive the stream property to set the master clock to null,
  946. // we need to process it to deref the MC so the MC can be released.
  947. // We will special case it here otherwise there will be big code churn. And
  948. // the perf impact of this special case should be minimum for we get
  949. // in here quite rarely.
  950. //
  951. // (the device is currently not accessible, so just return with error)
  952. //
  953. NTSTATUS StatusProcessed;
  954. StatusProcessed = SCSetMasterClockWhenDeviceInaccessible( DeviceObject, Irp );
  955. if ( NT_SUCCESS( StatusProcessed ) ) {
  956. Status = StatusProcessed;
  957. }
  958. Irp->IoStatus.Status = Status;
  959. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  960. return (Status);
  961. }
  962. //
  963. // show one more IO pending.
  964. //
  965. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  966. switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
  967. case IOCTL_KS_READ_STREAM:
  968. //
  969. // process read data request
  970. //
  971. DebugPrint((DebugLevelTrace, "'SCReadStream:Irp %x\n", Irp));
  972. Status = SCProcessDataTransfer(DeviceExtension,
  973. Irp,
  974. SRB_READ_DATA);
  975. break;
  976. case IOCTL_KS_WRITE_STREAM:
  977. //
  978. // process write data request
  979. //
  980. DebugPrint((DebugLevelTrace, "'SCWriteStream:Irp %x\n", Irp));
  981. Status = SCProcessDataTransfer(DeviceExtension,
  982. Irp,
  983. SRB_WRITE_DATA);
  984. break;
  985. case IOCTL_KS_RESET_STATE:
  986. {
  987. BOOLEAN RequestIssued;
  988. KSRESET *Reset,
  989. ResetType;
  990. Reset = (KSRESET *) IrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
  991. if (Irp->RequestorMode != KernelMode) {
  992. try {
  993. ProbeForRead(Reset, sizeof(KSRESET), sizeof(ULONG));
  994. ResetType = *Reset;
  995. } except(EXCEPTION_EXECUTE_HANDLER) {
  996. TRAP;
  997. Status = GetExceptionCode();
  998. break;
  999. } // except
  1000. } // if !kernelmode
  1001. else {
  1002. //
  1003. // trusted kernel mode, just use it. #131858 prefixbug 17400
  1004. //
  1005. ResetType = *Reset;
  1006. }
  1007. ASSERT(ResetType == *Reset);
  1008. if (ResetType == KSRESET_BEGIN) {
  1009. StreamObject->InFlush = TRUE;
  1010. Status = SCSubmitRequest(SRB_BEGIN_FLUSH,
  1011. NULL,
  1012. 0,
  1013. SCDequeueAndDeleteSrb,
  1014. DeviceExtension,
  1015. ((PFILTER_INSTANCE)
  1016. (StreamObject->FilterInstance))
  1017. ->HwInstanceExtension,
  1018. &StreamObject->HwStreamObject,
  1019. Irp,
  1020. &RequestIssued,
  1021. &StreamObject->ControlPendingQueue,
  1022. StreamObject->HwStreamObject.
  1023. ReceiveControlPacket
  1024. );
  1025. StreamFlushIo(DeviceExtension, StreamObject);
  1026. } else {
  1027. Status = SCSubmitRequest(SRB_END_FLUSH,
  1028. NULL,
  1029. 0,
  1030. SCDequeueAndDeleteSrb,
  1031. DeviceExtension,
  1032. ((PFILTER_INSTANCE)
  1033. (StreamObject->FilterInstance))
  1034. ->HwInstanceExtension,
  1035. &StreamObject->HwStreamObject,
  1036. Irp,
  1037. &RequestIssued,
  1038. &StreamObject->ControlPendingQueue,
  1039. StreamObject->HwStreamObject.
  1040. ReceiveControlPacket
  1041. );
  1042. StreamObject->InFlush = FALSE;
  1043. } // if begin
  1044. break;
  1045. } // case reset
  1046. case IOCTL_KS_PROPERTY:
  1047. DebugPrint((DebugLevelTrace,
  1048. "'StreamDispatchIO: Property with Irp %x\n", Irp));
  1049. //
  1050. // assume that there are no minidriver properties.
  1051. //
  1052. Status = STATUS_PROPSET_NOT_FOUND;
  1053. //
  1054. // first try the minidriver's properties, giving it a chance to
  1055. // override our built in sets.
  1056. //
  1057. if (StreamObject->PropInfoSize) {
  1058. ASSERT( StreamObject->PropertyInfo );
  1059. Status = KsPropertyHandler(Irp,
  1060. StreamObject->PropInfoSize,
  1061. StreamObject->PropertyInfo);
  1062. } // if minidriver props
  1063. //
  1064. // if the minidriver did not support it, try our on the fly set.
  1065. //
  1066. if ((Status == STATUS_PROPSET_NOT_FOUND) ||
  1067. (Status == STATUS_NOT_FOUND)) {
  1068. if (StreamObject->ConstructedPropertyInfo) {
  1069. Status = KsPropertyHandler(Irp,
  1070. StreamObject->ConstructedPropInfoSize,
  1071. StreamObject->ConstructedPropertyInfo);
  1072. } // if constructed exists
  1073. } // if not found
  1074. //
  1075. // if neither supported it, try our built-in set.
  1076. //
  1077. if ((Status == STATUS_PROPSET_NOT_FOUND) ||
  1078. (Status == STATUS_NOT_FOUND)) {
  1079. Status =
  1080. KsPropertyHandler(Irp,
  1081. SIZEOF_ARRAY(StreamProperties),
  1082. (PKSPROPERTY_SET) StreamProperties);
  1083. } // if property not found
  1084. break;
  1085. case IOCTL_KS_ENABLE_EVENT:
  1086. DebugPrint((DebugLevelTrace,
  1087. "'StreamDispatchIO: Enable event with Irp %x\n", Irp));
  1088. Status = KsEnableEvent(Irp,
  1089. StreamObject->EventInfoCount,
  1090. StreamObject->EventInfo,
  1091. NULL, 0, NULL);
  1092. break;
  1093. case IOCTL_KS_DISABLE_EVENT:
  1094. {
  1095. KSEVENTS_LOCKTYPE LockType;
  1096. PVOID LockObject;
  1097. DebugPrint((DebugLevelTrace,
  1098. "'StreamDispatchIO: Disable event with Irp %x\n", Irp));
  1099. //
  1100. // determine the type of lock necessary based on whether we are
  1101. // using interrupt or spinlock synchronization.
  1102. //
  1103. #if DBG
  1104. if (DeviceExtension->SynchronizeExecution == SCDebugKeSynchronizeExecution) {
  1105. #else
  1106. if (DeviceExtension->SynchronizeExecution == KeSynchronizeExecution) {
  1107. #endif
  1108. LockType = KSEVENTS_INTERRUPT;
  1109. LockObject = DeviceExtension->InterruptObject;
  1110. } else {
  1111. LockType = KSEVENTS_SPINLOCK;
  1112. LockObject = &DeviceExtension->SpinLock;
  1113. }
  1114. Status = KsDisableEvent(Irp,
  1115. &StreamObject->NotifyList,
  1116. LockType,
  1117. LockObject);
  1118. }
  1119. break;
  1120. case IOCTL_KS_METHOD:
  1121. #ifdef ENABLE_KS_METHODS
  1122. DebugPrint((DebugLevelTrace,
  1123. "'StreamDispatchIO: Method in Irp %x\n", Irp));
  1124. //
  1125. // assume that there are no minidriver properties.
  1126. //
  1127. Status = STATUS_PROPSET_NOT_FOUND;
  1128. if ((Status == STATUS_PROPSET_NOT_FOUND) ||
  1129. (Status == STATUS_NOT_FOUND)) {
  1130. if (StreamObject->MethodInfo) {
  1131. Status = KsMethodHandler(Irp,
  1132. StreamObject->MethodInfoSize,
  1133. StreamObject->MethodInfo);
  1134. } // if constructed exists
  1135. } // if not found
  1136. break;
  1137. #else
  1138. Status = STATUS_PROPSET_NOT_FOUND;
  1139. break;
  1140. #endif
  1141. }
  1142. if (Status != STATUS_PENDING) {
  1143. SCCompleteIrp(Irp, Status, DeviceExtension);
  1144. }
  1145. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1146. return Status;
  1147. }
  1148. NTSTATUS
  1149. SCStreamDeviceState
  1150. (
  1151. IN PIRP Irp,
  1152. IN PKSPROPERTY Property,
  1153. IN OUT PKSSTATE DeviceState
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Process get/set device state to the stream.
  1158. Arguments:
  1159. Irp - pointer to the irp
  1160. Property - pointer to the information for device state property
  1161. DeviceState - state to which the device is to be set
  1162. Return Value:
  1163. NTSTATUS returned as appropriate.
  1164. --*/
  1165. {
  1166. NTSTATUS Status;
  1167. PIO_STACK_LOCATION IrpStack;
  1168. PDEVICE_EXTENSION DeviceExtension;
  1169. PSTREAM_OBJECT StreamObject;
  1170. BOOLEAN RequestIssued;
  1171. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  1172. PFILTER_INSTANCE FilterInstance;
  1173. PADDITIONAL_PIN_INFO AdditionalInfo;
  1174. PAGED_CODE();
  1175. DebugPrint((DebugLevelTrace, "'SCStreamDeviceState:Irp %x, State = %x\n",
  1176. Irp, *DeviceState));
  1177. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1178. DeviceExtension = (PDEVICE_EXTENSION)
  1179. (IrpStack->DeviceObject)->DeviceExtension;
  1180. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  1181. FilterInstance = ((PFILTER_INSTANCE) (StreamObject->FilterInstance));
  1182. AdditionalInfo = FilterInstance->PinInstanceInfo;
  1183. Status = STATUS_SUCCESS;
  1184. //
  1185. // Synchronize pin state changes
  1186. //
  1187. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  1188. Executive,
  1189. KernelMode,
  1190. FALSE,// not alertable
  1191. NULL);
  1192. if (StreamObject->CurrentState == *DeviceState) {
  1193. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1194. return STATUS_SUCCESS;
  1195. }
  1196. switch (*DeviceState) {
  1197. case KSSTATE_RUN:
  1198. DebugPrint((DebugLevelTrace, "STREAM: KSSTATE_RUN on stream:%x\n",StreamObject));
  1199. break;
  1200. case KSSTATE_ACQUIRE:
  1201. DebugPrint((DebugLevelTrace, "STREAM: KSSTATE_ACQUIRE on stream:%x\n",StreamObject));
  1202. break;
  1203. case KSSTATE_PAUSE:
  1204. DebugPrint((DebugLevelTrace, "STREAM: KSSTATE_PAUSE on stream:%x\n",StreamObject));
  1205. break;
  1206. case KSSTATE_STOP:
  1207. DebugPrint((DebugLevelTrace, "STREAM: KSSTATE_STOP on stream:%x\n",StreamObject));
  1208. break;
  1209. default:
  1210. DebugPrint((DebugLevelTrace, "STREAM: Invalid Device State\n"));
  1211. break;
  1212. }
  1213. DebugPrint((DebugLevelTrace, "STREAM: Stream->AllocatorFileObject:%x\n",StreamObject->AllocatorFileObject));
  1214. DebugPrint((DebugLevelTrace, "STREAM: Stream->NextFileObject:%x\n",StreamObject->NextFileObject));
  1215. DebugPrint((DebugLevelTrace, "STREAM: Stream->FileObject:%x\n",StreamObject->FileObject));
  1216. DebugPrint((DebugLevelTrace, "STREAM: Stream->PinType:"));
  1217. if (StreamObject->PinType == IrpSource)
  1218. DebugPrint((DebugLevelTrace, "IrpSource\n"));
  1219. else if (StreamObject->PinType == IrpSink)
  1220. DebugPrint((DebugLevelTrace, "IrpSink\n"));
  1221. else {
  1222. DebugPrint((DebugLevelTrace, "neither\n")); // this is a bug.
  1223. }
  1224. //
  1225. // send a set state SRB to the stream.
  1226. //
  1227. //
  1228. // GUBGUB: "we may need to send this if Status == STATUS_SUCCESS only"
  1229. // is a bugus concern since Status is inited to Success.
  1230. //
  1231. Status = SCSubmitRequest(SRB_SET_STREAM_STATE,
  1232. (PVOID) * DeviceState,
  1233. 0,
  1234. SCDequeueAndDeleteSrb,
  1235. DeviceExtension,
  1236. ((PFILTER_INSTANCE)
  1237. (StreamObject->FilterInstance))
  1238. ->HwInstanceExtension,
  1239. &StreamObject->HwStreamObject,
  1240. Irp,
  1241. &RequestIssued,
  1242. &StreamObject->ControlPendingQueue,
  1243. StreamObject->HwStreamObject.
  1244. ReceiveControlPacket
  1245. );
  1246. //
  1247. // if good status, set the new state in the stream object.
  1248. //
  1249. if (NT_SUCCESS(Status)) {
  1250. StreamObject->CurrentState = *DeviceState;
  1251. }
  1252. else {
  1253. DebugPrint((DebugLevelTrace, "STREAM: error sending DeviceState Irp\n"));
  1254. }
  1255. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1256. switch (*DeviceState) {
  1257. //
  1258. // 1. should start sourcing irps at pause
  1259. // 2. worker thread shutdown if pins are connected in certain order.......
  1260. // 3. check MSTEE bugs assigned to dalesat.
  1261. //
  1262. case KSSTATE_RUN:
  1263. if(StreamObject->PinType == IrpSource &&
  1264. StreamObject->StandardTransport)
  1265. {
  1266. Status = BeginTransfer(
  1267. FilterInstance,
  1268. StreamObject);
  1269. }
  1270. break;
  1271. case KSSTATE_ACQUIRE:
  1272. Status = STATUS_SUCCESS;
  1273. break;
  1274. case KSSTATE_PAUSE:
  1275. if (NT_SUCCESS (Status)) {
  1276. if(StreamObject->PinType == IrpSource &&
  1277. StreamObject->StandardTransport)
  1278. {
  1279. Status = PrepareTransfer(
  1280. FilterInstance,
  1281. StreamObject);
  1282. }
  1283. }
  1284. break;
  1285. case KSSTATE_STOP:
  1286. if(StreamObject->PinType == IrpSource &&
  1287. StreamObject->StandardTransport)
  1288. Status = EndTransfer( FilterInstance, StreamObject );
  1289. else
  1290. //
  1291. // cancel any pending I/O on this stream if the state is STOP.
  1292. //
  1293. StreamFlushIo(DeviceExtension, StreamObject);
  1294. break;
  1295. default:
  1296. break;
  1297. }
  1298. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1299. return (Status);
  1300. }
  1301. #else
  1302. PAGED_CODE();
  1303. DebugPrint((DebugLevelTrace, "'SCStreamDeviceState:Irp %x, State = %x\n",
  1304. Irp, *DeviceState));
  1305. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1306. DeviceExtension = (PDEVICE_EXTENSION)
  1307. (IrpStack->DeviceObject)->DeviceExtension;
  1308. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  1309. //
  1310. // cancel any pending I/O on this stream if the state is STOP.
  1311. //
  1312. if (*DeviceState == KSSTATE_STOP) {
  1313. StreamFlushIo(DeviceExtension, StreamObject);
  1314. }
  1315. //
  1316. // send a set state SRB to the stream.
  1317. //
  1318. DebugPrint((DebugLevelTrace,
  1319. "'SetStreamState: State %x with Irp %x\n", *DeviceState, Irp));
  1320. Status = SCSubmitRequest(SRB_SET_STREAM_STATE,
  1321. (PVOID) * DeviceState,
  1322. 0,
  1323. SCDequeueAndDeleteSrb,
  1324. DeviceExtension,
  1325. ((PFILTER_INSTANCE)
  1326. (StreamObject->FilterInstance))
  1327. ->HwInstanceExtension,
  1328. &StreamObject->HwStreamObject,
  1329. Irp,
  1330. &RequestIssued,
  1331. &StreamObject->ControlPendingQueue,
  1332. StreamObject->HwStreamObject.
  1333. ReceiveControlPacket
  1334. );
  1335. //
  1336. // if good status, set the new state in the stream object.
  1337. //
  1338. if (NT_SUCCESS(Status)) {
  1339. StreamObject->CurrentState = *DeviceState;
  1340. }
  1341. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1342. return (Status);
  1343. }
  1344. #endif
  1345. NTSTATUS
  1346. SCGetStreamDeviceStateCallback
  1347. (
  1348. IN PSTREAM_REQUEST_BLOCK SRB
  1349. )
  1350. {
  1351. // yep, its a do nothing routine.
  1352. return (SRB->HwSRB.Status);
  1353. }
  1354. NTSTATUS
  1355. SCGetStreamDeviceState
  1356. (
  1357. IN PIRP Irp,
  1358. IN PKSPROPERTY Property,
  1359. IN OUT PKSSTATE DeviceState
  1360. )
  1361. /*++
  1362. Routine Description:
  1363. Process get device state to the stream.
  1364. Arguments:
  1365. Irp - pointer to the irp
  1366. Property - pointer to the information for device state property
  1367. DeviceState - state to which the device is to be set
  1368. Return Value:
  1369. NTSTATUS returned as appropriate.
  1370. --*/
  1371. {
  1372. NTSTATUS Status;
  1373. PIO_STACK_LOCATION IrpStack;
  1374. PDEVICE_EXTENSION DeviceExtension;
  1375. PSTREAM_OBJECT StreamObject;
  1376. BOOLEAN RequestIssued;
  1377. PSTREAM_REQUEST_BLOCK SRB;
  1378. PAGED_CODE();
  1379. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1380. DeviceExtension = (PDEVICE_EXTENSION)
  1381. (IrpStack->DeviceObject)->DeviceExtension;
  1382. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  1383. //
  1384. // send a get state SRB to the stream.
  1385. //
  1386. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  1387. DebugPrint((DebugLevelTrace,
  1388. "'GetStreamState: State with StreamObj:%x\n", StreamObject));
  1389. if (StreamObject->PinType == IrpSource)
  1390. DebugPrint((DebugLevelTrace, "'GetStreamState: Is IrpSource\n"));
  1391. else
  1392. DebugPrint((DebugLevelTrace,"'GetStreamState: Is IrpSink\n"));
  1393. #endif
  1394. //
  1395. // set the returned data size to the correct size regardless of status.
  1396. //
  1397. Irp->IoStatus.Information = sizeof(KSSTATE);
  1398. Status = SCSubmitRequest(SRB_GET_STREAM_STATE,
  1399. (PVOID) DeviceState,
  1400. 0,
  1401. SCGetStreamDeviceStateCallback,
  1402. DeviceExtension,
  1403. ((PFILTER_INSTANCE)
  1404. (StreamObject->FilterInstance))
  1405. ->HwInstanceExtension,
  1406. &StreamObject->HwStreamObject,
  1407. Irp,
  1408. &RequestIssued,
  1409. &StreamObject->ControlPendingQueue,
  1410. StreamObject->HwStreamObject.
  1411. ReceiveControlPacket
  1412. );
  1413. SRB = (PSTREAM_REQUEST_BLOCK) Irp->Tail.Overlay.DriverContext[0];
  1414. *DeviceState = SRB->HwSRB.CommandData.StreamState;
  1415. SCDequeueAndDeleteSrb(SRB);
  1416. //
  1417. // if not supported, return the last known state of the stream.
  1418. //
  1419. if ((Status == STATUS_NOT_SUPPORTED)
  1420. || (Status == STATUS_NOT_IMPLEMENTED)) {
  1421. Status = STATUS_SUCCESS;
  1422. *DeviceState = StreamObject->CurrentState;
  1423. }
  1424. DebugPrint((DebugLevelTrace,
  1425. "'GetStreamState: Returning:%x: DeviceState:", Status));
  1426. switch (*DeviceState) {
  1427. case KSSTATE_RUN:
  1428. DebugPrint((DebugLevelTrace, "KSSTATE_RUN\n"));
  1429. break;
  1430. case KSSTATE_ACQUIRE:
  1431. DebugPrint((DebugLevelTrace, "KSSTATE_AQUIRE\n"));
  1432. break;
  1433. case KSSTATE_PAUSE:
  1434. DebugPrint((DebugLevelTrace, "KSSTATE_PAUSE\n"));
  1435. break;
  1436. case KSSTATE_STOP:
  1437. DebugPrint((DebugLevelTrace, "KSSTATE_STOP\n"));
  1438. break;
  1439. default:
  1440. DebugPrint((DebugLevelTrace, "Invalid Device State\n"));
  1441. break;
  1442. }
  1443. return (Status);
  1444. }
  1445. NTSTATUS
  1446. SCStreamDeviceRate
  1447. (
  1448. IN PIRP Irp,
  1449. IN PKSPROPERTY Property,
  1450. IN OUT PKSRATE DeviceRate
  1451. )
  1452. /*++
  1453. Routine Description:
  1454. Process set device rate to the stream.
  1455. Arguments:
  1456. Irp - pointer to the irp
  1457. Property - pointer to the information for device state property
  1458. DeviceRate - rate at which the device is to be set
  1459. Return Value:
  1460. NTSTATUS returned as appropriate.
  1461. --*/
  1462. {
  1463. NTSTATUS Status;
  1464. PIO_STACK_LOCATION IrpStack;
  1465. PDEVICE_EXTENSION DeviceExtension;
  1466. PSTREAM_OBJECT StreamObject;
  1467. BOOLEAN RequestIssued;
  1468. PAGED_CODE();
  1469. DebugPrint((DebugLevelTrace, "'SCStreamDeviceRate:Irp %x, Rate = %x\n",
  1470. Irp, *DeviceRate));
  1471. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1472. DeviceExtension = (PDEVICE_EXTENSION)
  1473. (IrpStack->DeviceObject)->DeviceExtension;
  1474. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  1475. //
  1476. // send a set rate SRB to the stream.
  1477. //
  1478. Status = SCSubmitRequest(SRB_SET_STREAM_RATE,
  1479. (PVOID) DeviceRate,
  1480. 0,
  1481. SCDequeueAndDeleteSrb,
  1482. DeviceExtension,
  1483. ((PFILTER_INSTANCE)
  1484. (StreamObject->FilterInstance))
  1485. ->HwInstanceExtension,
  1486. &StreamObject->HwStreamObject,
  1487. Irp,
  1488. &RequestIssued,
  1489. &StreamObject->ControlPendingQueue,
  1490. StreamObject->HwStreamObject.
  1491. ReceiveControlPacket
  1492. );
  1493. //
  1494. // change STATUS_NOT_IMPLEMENTED to STATUS_NOT_FOUND so that the proxy
  1495. // does not get confused (GUBGUB). A necessary mapping between r0 and r3
  1496. // worlds.
  1497. //
  1498. if (Status == STATUS_NOT_IMPLEMENTED) {
  1499. Status = STATUS_NOT_FOUND;
  1500. }
  1501. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1502. return (Status);
  1503. }
  1504. NTSTATUS
  1505. SCStreamDeviceRateCapability
  1506. (
  1507. IN PIRP Irp,
  1508. IN PKSRATE_CAPABILITY RateCap,
  1509. IN OUT PKSRATE DeviceRate
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Process set device rate to the stream.
  1514. Arguments:
  1515. Irp - pointer to the irp
  1516. RateCap - pointer to the information for device state property
  1517. DeviceRate - rate to which the device was set
  1518. Return Value:
  1519. NTSTATUS returned as appropriate.
  1520. --*/
  1521. {
  1522. NTSTATUS Status;
  1523. PIO_STACK_LOCATION IrpStack;
  1524. PDEVICE_EXTENSION DeviceExtension;
  1525. PSTREAM_OBJECT StreamObject;
  1526. BOOLEAN RequestIssued;
  1527. PAGED_CODE();
  1528. DebugPrint((DebugLevelTrace, "'SCStreamDeviceRate:Irp %x, Rate = %x\n",
  1529. Irp, *DeviceRate));
  1530. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1531. DeviceExtension = (PDEVICE_EXTENSION)
  1532. (IrpStack->DeviceObject)->DeviceExtension;
  1533. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  1534. //
  1535. // presuppose a successful completion, which means that the minidriver
  1536. // can normalize rate to 1.
  1537. //
  1538. *DeviceRate = RateCap->Rate;
  1539. DeviceRate->Rate = 1000;
  1540. Irp->IoStatus.Information = sizeof(KSRATE);
  1541. //
  1542. // send a set rate SRB to the stream.
  1543. //
  1544. Status = SCSubmitRequest(
  1545. SRB_PROPOSE_STREAM_RATE,
  1546. (PVOID) RateCap,
  1547. 0,
  1548. SCDequeueAndDeleteSrb,
  1549. DeviceExtension,
  1550. ((PFILTER_INSTANCE)(StreamObject->FilterInstance))->HwInstanceExtension,
  1551. &StreamObject->HwStreamObject,
  1552. Irp,
  1553. &RequestIssued,
  1554. &StreamObject->ControlPendingQueue,
  1555. StreamObject->HwStreamObject.ReceiveControlPacket
  1556. );
  1557. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1558. //
  1559. // change STATUS_NOT_IMPLEMENTED to STATUS_NOT_FOUND so that the proxy
  1560. // does not get confused (GUBGUB). A necessary mapping between r0 and r3
  1561. // worlds.
  1562. //
  1563. if (Status == STATUS_NOT_IMPLEMENTED) {
  1564. Status = STATUS_NOT_FOUND;
  1565. }
  1566. return (Status);
  1567. }
  1568. NTSTATUS
  1569. SCStreamProposeNewFormat
  1570. (
  1571. IN PIRP Irp,
  1572. IN PKSPROPERTY Property,
  1573. IN OUT PKSDATAFORMAT Format
  1574. )
  1575. /*++
  1576. Routine Description:
  1577. Process propose data format to the stream.
  1578. Arguments:
  1579. Irp - pointer to the irp
  1580. Property - pointer to the information for propose format property
  1581. DeviceState - state to which the device is to be set
  1582. Return Value:
  1583. NTSTATUS returned as appropriate.
  1584. --*/
  1585. {
  1586. NTSTATUS Status;
  1587. PIO_STACK_LOCATION IrpStack;
  1588. PDEVICE_EXTENSION DeviceExtension;
  1589. PSTREAM_OBJECT StreamObject;
  1590. BOOLEAN RequestIssued;
  1591. PAGED_CODE();
  1592. DebugPrint((DebugLevelTrace, "'SCStreamProposeNewFormat:Irp %x, Format = %x\n",
  1593. Irp, *Format));
  1594. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1595. DeviceExtension = (PDEVICE_EXTENSION)
  1596. (IrpStack->DeviceObject)->DeviceExtension;
  1597. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  1598. //
  1599. // send a propose format SRB to the stream.
  1600. //
  1601. Status = SCSubmitRequest(SRB_PROPOSE_DATA_FORMAT,
  1602. (PVOID) Format,
  1603. IrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  1604. SCDequeueAndDeleteSrb,
  1605. DeviceExtension,
  1606. ((PFILTER_INSTANCE)
  1607. (StreamObject->FilterInstance))
  1608. ->HwInstanceExtension,
  1609. &StreamObject->HwStreamObject,
  1610. Irp,
  1611. &RequestIssued,
  1612. &StreamObject->ControlPendingQueue,
  1613. StreamObject->HwStreamObject.
  1614. ReceiveControlPacket
  1615. );
  1616. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1617. //
  1618. // change STATUS_NOT_IMPLEMENTED to STATUS_NOT_FOUND so that the proxy
  1619. // does not get confused (GUBGUB). A necessary mapping between r0 and r3
  1620. // worlds.
  1621. //
  1622. if (Status == STATUS_NOT_IMPLEMENTED) {
  1623. Status = STATUS_NOT_FOUND;
  1624. }
  1625. return (Status);
  1626. }
  1627. NTSTATUS
  1628. SCStreamSetFormat
  1629. (
  1630. IN PIRP Irp,
  1631. IN PKSPROPERTY Property,
  1632. IN OUT PKSDATAFORMAT Format
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. Sets the data format on the stream.
  1637. Arguments:
  1638. Irp - pointer to the irp
  1639. Property - pointer to the information for the set format property
  1640. DeviceState - state to which the device is to be set
  1641. Return Value:
  1642. NTSTATUS returned as appropriate.
  1643. --*/
  1644. {
  1645. NTSTATUS Status;
  1646. PIO_STACK_LOCATION IrpStack;
  1647. PDEVICE_EXTENSION DeviceExtension;
  1648. PSTREAM_OBJECT StreamObject;
  1649. BOOLEAN RequestIssued;
  1650. PAGED_CODE();
  1651. DebugPrint((DebugLevelTrace, "'SCStreamSetFormat:Irp %x, Format = %x\n",
  1652. Irp, *Format));
  1653. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1654. DeviceExtension = (PDEVICE_EXTENSION)
  1655. (IrpStack->DeviceObject)->DeviceExtension;
  1656. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  1657. //
  1658. // send a set format SRB to the stream.
  1659. //
  1660. Status = SCSubmitRequest(SRB_SET_DATA_FORMAT,
  1661. (PVOID) Format,
  1662. IrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  1663. SCDequeueAndDeleteSrb,
  1664. DeviceExtension,
  1665. ((PFILTER_INSTANCE)
  1666. (StreamObject->FilterInstance))
  1667. ->HwInstanceExtension,
  1668. &StreamObject->HwStreamObject,
  1669. Irp,
  1670. &RequestIssued,
  1671. &StreamObject->ControlPendingQueue,
  1672. StreamObject->HwStreamObject.
  1673. ReceiveControlPacket
  1674. );
  1675. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1676. //
  1677. // change STATUS_NOT_IMPLEMENTED to STATUS_NOT_FOUND so that the proxy
  1678. // does not get confused (GUBGUB). A necessary mapping between r0 and r3
  1679. // worlds.
  1680. //
  1681. if (Status == STATUS_NOT_IMPLEMENTED) {
  1682. Status = STATUS_NOT_FOUND;
  1683. }
  1684. return (Status);
  1685. }
  1686. NTSTATUS
  1687. StreamClassMinidriverDeviceGetProperty
  1688. (
  1689. IN PIRP Irp,
  1690. IN PKSPROPERTY Property,
  1691. IN OUT PVOID PropertyInfo
  1692. )
  1693. /*++
  1694. Routine Description:
  1695. Process get property to the device.
  1696. Arguments:
  1697. Irp - pointer to the irp
  1698. Property - pointer to the information for the property
  1699. PropertyInfo - buffer to return the property data to
  1700. Return Value:
  1701. NTSTATUS returned as appropriate.
  1702. --*/
  1703. {
  1704. NTSTATUS Status;
  1705. PAGED_CODE();
  1706. Status = SCMinidriverDevicePropertyHandler(SRB_GET_DEVICE_PROPERTY,
  1707. Irp,
  1708. Property,
  1709. PropertyInfo
  1710. );
  1711. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1712. return (Status);
  1713. }
  1714. NTSTATUS
  1715. StreamClassMinidriverDeviceSetProperty
  1716. (
  1717. IN PIRP Irp,
  1718. IN PKSPROPERTY Property,
  1719. IN OUT PVOID PropertyInfo
  1720. )
  1721. /*++
  1722. Routine Description:
  1723. Process set property to the device.
  1724. Arguments:
  1725. Irp - pointer to the irp
  1726. Property - pointer to the information for the property
  1727. PropertyInfo - buffer that contains the property info
  1728. Return Value:
  1729. NTSTATUS returned as appropriate.
  1730. --*/
  1731. {
  1732. NTSTATUS Status;
  1733. PAGED_CODE();
  1734. Status = SCMinidriverDevicePropertyHandler(SRB_SET_DEVICE_PROPERTY,
  1735. Irp,
  1736. Property,
  1737. PropertyInfo);
  1738. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1739. return (Status);
  1740. }
  1741. NTSTATUS
  1742. StreamClassMinidriverStreamGetProperty
  1743. (
  1744. IN PIRP Irp,
  1745. IN PKSPROPERTY Property,
  1746. IN OUT PVOID PropertyInfo
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. Process get property of a stream.
  1751. Arguments:
  1752. Irp - pointer to the irp
  1753. Property - pointer to the information for the property
  1754. PropertyInfo - buffer to return the property data to
  1755. Return Value:
  1756. NTSTATUS returned as appropriate.
  1757. --*/
  1758. {
  1759. NTSTATUS Status;
  1760. PAGED_CODE();
  1761. Status = SCMinidriverStreamPropertyHandler(SRB_GET_STREAM_PROPERTY,
  1762. Irp,
  1763. Property,
  1764. PropertyInfo
  1765. );
  1766. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1767. return (Status);
  1768. }
  1769. NTSTATUS
  1770. StreamClassMinidriverStreamSetProperty
  1771. (
  1772. IN PIRP Irp,
  1773. IN PKSPROPERTY Property,
  1774. IN OUT PVOID PropertyInfo
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. Process set property to a stream.
  1779. Arguments:
  1780. Irp - pointer to the irp
  1781. Property - pointer to the information for the property
  1782. PropertyInfo - buffer that contains the property info
  1783. Return Value:
  1784. NTSTATUS returned as appropriate.
  1785. --*/
  1786. {
  1787. NTSTATUS Status;
  1788. PAGED_CODE();
  1789. Status = SCMinidriverStreamPropertyHandler(SRB_SET_STREAM_PROPERTY,
  1790. Irp,
  1791. Property,
  1792. PropertyInfo);
  1793. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1794. return (Status);
  1795. }
  1796. #ifdef ENABLE_KS_METHODS
  1797. NTSTATUS
  1798. StreamClassMinidriverStreamMethod(
  1799. IN PIRP Irp,
  1800. IN PKSMETHOD Method,
  1801. IN OUT PVOID MethodInfo)
  1802. /*++
  1803. Routine Description:
  1804. Process get property of a stream.
  1805. Arguments:
  1806. Irp - pointer to the irp
  1807. Property - pointer to the information for the property
  1808. PropertyInfo - buffer to return the property data to
  1809. Return Value:
  1810. NTSTATUS returned as appropriate.
  1811. --*/
  1812. {
  1813. NTSTATUS Status;
  1814. PAGED_CODE();
  1815. Status = SCMinidriverStreamMethodHandler(SRB_STREAM_METHOD,
  1816. Irp,
  1817. Method,
  1818. MethodInfo
  1819. );
  1820. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1821. return (Status);
  1822. }
  1823. NTSTATUS
  1824. StreamClassMinidriverDeviceMethod(
  1825. IN PIRP Irp,
  1826. IN PKSMETHOD Method,
  1827. IN OUT PVOID MethodInfo)
  1828. /*++
  1829. Routine Description:
  1830. Process get property of a device.
  1831. Arguments:
  1832. Irp - pointer to the irp
  1833. Property - pointer to the information for the property
  1834. PropertyInfo - buffer to return the property data to
  1835. Return Value:
  1836. NTSTATUS returned as appropriate.
  1837. --*/
  1838. {
  1839. NTSTATUS Status;
  1840. PAGED_CODE();
  1841. Status = SCMinidriverDeviceMethodHandler(SRB_DEVICE_METHOD,
  1842. Irp,
  1843. Method,
  1844. MethodInfo
  1845. );
  1846. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1847. return (Status);
  1848. }
  1849. #endif
  1850. NTSTATUS
  1851. StreamClassEnableEventHandler(
  1852. IN PIRP Irp,
  1853. IN PKSEVENTDATA EventData,
  1854. IN PKSEVENT_ENTRY EventEntry
  1855. )
  1856. /*++
  1857. Routine Description:
  1858. Process an enable event for the stream.
  1859. Arguments:
  1860. Irp - pointer to the IRP
  1861. EventData - data describing the event
  1862. EventEntry - more info about the event :-)
  1863. Return Value:
  1864. None.
  1865. --*/
  1866. {
  1867. PIO_STACK_LOCATION IrpStack;
  1868. PDEVICE_EXTENSION DeviceExtension;
  1869. PSTREAM_OBJECT StreamObject;
  1870. NTSTATUS Status;
  1871. ULONG EventSetID;
  1872. KIRQL irql;
  1873. HW_EVENT_DESCRIPTOR Event;
  1874. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1875. DeviceExtension = (PDEVICE_EXTENSION)
  1876. (IrpStack->DeviceObject)->DeviceExtension;
  1877. //
  1878. // clock events are indicated on the pin by the minidriver, for
  1879. // simplicity.
  1880. // but, we will receive clock events on the clock's handle. We need to
  1881. // determine if this file object is the clock's or the pin's.
  1882. //
  1883. StreamObject = IrpStack->FileObject->FsContext;
  1884. if ((PVOID) StreamObject == IrpStack->FileObject->FsContext2) {
  1885. StreamObject = ((PCLOCK_INSTANCE) StreamObject)->StreamObject;
  1886. }
  1887. //
  1888. // compute the index of the event set.
  1889. //
  1890. // this value is calculated by subtracting the base event set
  1891. // pointer from the requested event set pointer.
  1892. //
  1893. //
  1894. EventSetID = (ULONG) ((ULONG_PTR) EventEntry->EventSet -
  1895. (ULONG_PTR) StreamObject->EventInfo)
  1896. / sizeof(KSEVENT_SET);
  1897. //
  1898. // build an event info structure to represent the event to the
  1899. // minidriver.
  1900. //
  1901. Event.EnableEventSetIndex = EventSetID;
  1902. Event.EventEntry = EventEntry;
  1903. Event.StreamObject = &StreamObject->HwStreamObject;
  1904. Event.Enable = TRUE;
  1905. Event.EventData = EventData;
  1906. //
  1907. // acquire the spinlock to protect the interrupt structures
  1908. //
  1909. KeAcquireSpinLock(&DeviceExtension->SpinLock, &irql);
  1910. //
  1911. // call the synchronized routine to add the event to the list
  1912. //
  1913. Status = DeviceExtension->SynchronizeExecution(
  1914. DeviceExtension->InterruptObject,
  1915. (PKSYNCHRONIZE_ROUTINE) SCEnableEventSynchronized,
  1916. &Event);
  1917. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  1918. return (Status);
  1919. }
  1920. VOID
  1921. StreamClassDisableEventHandler(
  1922. IN PFILE_OBJECT FileObject,
  1923. IN PKSEVENT_ENTRY EventEntry
  1924. )
  1925. /*++
  1926. Routine Description:
  1927. Process an event disable for the stream.
  1928. NOTE: we are either at interrupt IRQL or the spinlock is taken on this call!
  1929. Arguments:
  1930. FileObject - file object for the pin
  1931. EventEntry - info about the event
  1932. Return Value:
  1933. None.
  1934. --*/
  1935. {
  1936. PDEVICE_EXTENSION DeviceExtension;
  1937. PSTREAM_OBJECT StreamObject;
  1938. HW_EVENT_DESCRIPTOR Event;
  1939. //
  1940. // clock events are indicated on the pin by the minidriver, for
  1941. // simplicity.
  1942. // but, we will receive clock events on the clock's handle. We need to
  1943. // determine if this file object is the clock's or the pin's.
  1944. //
  1945. StreamObject = FileObject->FsContext;
  1946. if ((PVOID) StreamObject == FileObject->FsContext2) {
  1947. StreamObject = ((PCLOCK_INSTANCE) StreamObject)->StreamObject;
  1948. }
  1949. DeviceExtension = StreamObject->DeviceExtension;
  1950. //
  1951. // build an event info structure to represent the event to the
  1952. // minidriver.
  1953. //
  1954. Event.EventEntry = EventEntry;
  1955. Event.StreamObject = &StreamObject->HwStreamObject;
  1956. Event.Enable = FALSE;
  1957. if (StreamObject->HwStreamObject.HwEventRoutine) {
  1958. //
  1959. // call the minidriver. ignore the status. note that we are
  1960. // already at the correct synchronization level.
  1961. //
  1962. StreamObject->HwStreamObject.HwEventRoutine(&Event);
  1963. } // if eventroutine
  1964. //
  1965. // remove the event from the list.
  1966. //
  1967. RemoveEntryList(&EventEntry->ListEntry);
  1968. }
  1969. NTSTATUS
  1970. StreamClassEnableDeviceEventHandler(
  1971. IN PIRP Irp,
  1972. IN PKSEVENTDATA EventData,
  1973. IN PKSEVENT_ENTRY EventEntry
  1974. )
  1975. /*++
  1976. Routine Description:
  1977. Process an enable event for the device.
  1978. Arguments:
  1979. Irp - pointer to the IRP
  1980. EventData - data describing the event
  1981. EventEntry - more info about the event :-)
  1982. Return Value:
  1983. None.
  1984. --*/
  1985. {
  1986. PIO_STACK_LOCATION IrpStack;
  1987. PDEVICE_EXTENSION DeviceExtension;
  1988. NTSTATUS Status;
  1989. ULONG EventSetID;
  1990. KIRQL irql;
  1991. HW_EVENT_DESCRIPTOR Event;
  1992. PFILTER_INSTANCE FilterInstance;
  1993. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1994. DeviceExtension = (PDEVICE_EXTENSION)
  1995. (IrpStack->DeviceObject)->DeviceExtension;
  1996. FilterInstance = IrpStack->FileObject->FsContext;
  1997. //
  1998. // compute the index of the event set.
  1999. //
  2000. // this value is calculated by subtracting the base event set
  2001. // pointer from the requested event set pointer.
  2002. //
  2003. //
  2004. EventSetID = (ULONG) ((ULONG_PTR) EventEntry->EventSet -
  2005. (ULONG_PTR) FilterInstance->EventInfo)
  2006. / sizeof(KSEVENT_SET);
  2007. //
  2008. // build an event info structure to represent the event to the
  2009. // minidriver.
  2010. //
  2011. Event.EnableEventSetIndex = EventSetID;
  2012. Event.EventEntry = EventEntry;
  2013. Event.DeviceExtension = DeviceExtension->HwDeviceExtension;
  2014. IF_MF( Event.HwInstanceExtension = FilterInstance->HwInstanceExtension; )
  2015. Event.Enable = TRUE;
  2016. Event.EventData = EventData;
  2017. //
  2018. // acquire the spinlock to protect the interrupt structures
  2019. //
  2020. KeAcquireSpinLock(&DeviceExtension->SpinLock, &irql);
  2021. //
  2022. // call the synchronized routine to add the event to the list
  2023. //
  2024. Status = DeviceExtension->SynchronizeExecution(
  2025. DeviceExtension->InterruptObject,
  2026. (PKSYNCHRONIZE_ROUTINE) SCEnableDeviceEventSynchronized,
  2027. &Event);
  2028. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  2029. return (Status);
  2030. }
  2031. VOID
  2032. StreamClassDisableDeviceEventHandler(
  2033. IN PFILE_OBJECT FileObject,
  2034. IN PKSEVENT_ENTRY EventEntry
  2035. )
  2036. /*++
  2037. Routine Description:
  2038. Process an event disable for the stream.
  2039. NOTE: we are either at interrupt IRQL or the spinlock is taken on this call!
  2040. Arguments:
  2041. FileObject - file object for the pin
  2042. EventEntry - info about the event
  2043. Return Value:
  2044. None.
  2045. --*/
  2046. {
  2047. PDEVICE_EXTENSION DeviceExtension;
  2048. HW_EVENT_DESCRIPTOR Event;
  2049. PFILTER_INSTANCE FilterInstance;
  2050. FilterInstance = (PFILTER_INSTANCE) FileObject->FsContext;
  2051. ASSERT_FILTER_INSTANCE( FilterInstance );
  2052. DeviceExtension = FilterInstance->DeviceExtension;
  2053. //
  2054. // build an event info structure to represent the event to the
  2055. // minidriver.
  2056. //
  2057. Event.EventEntry = EventEntry;
  2058. Event.DeviceExtension = DeviceExtension->HwDeviceExtension;
  2059. Event.Enable = FALSE;
  2060. Event.HwInstanceExtension = FilterInstance->HwInstanceExtension;
  2061. if (FilterInstance->HwEventRoutine) {
  2062. //
  2063. // call the minidriver. ignore the status. note that we are
  2064. // already at the correct synchronization level.
  2065. //
  2066. FilterInstance->HwEventRoutine(&Event);
  2067. }
  2068. //
  2069. // remove the event from the list.
  2070. //
  2071. RemoveEntryList(&EventEntry->ListEntry);
  2072. }
  2073. NTSTATUS
  2074. FilterDispatchIoControl(
  2075. IN PDEVICE_OBJECT DeviceObject,
  2076. IN PIRP Irp)
  2077. /*++
  2078. Routine Description:
  2079. This routine receives control IRP's for the device.
  2080. Arguments:
  2081. DeviceObject - device object for the device
  2082. Irp - probably an IRP, silly
  2083. Return Value:
  2084. The IRP status is set as appropriate
  2085. --*/
  2086. {
  2087. PIO_STACK_LOCATION IrpStack;
  2088. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  2089. PFILTER_INSTANCE FilterInstance;
  2090. NTSTATUS Status;
  2091. PAGED_CODE();
  2092. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2093. Status = SCShowIoPending(DeviceExtension, Irp);
  2094. if ( !NT_SUCCESS ( Status )) {
  2095. //
  2096. // the device is currently not accessible, so just return.
  2097. //
  2098. return (Status);
  2099. }
  2100. switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
  2101. case IOCTL_KS_PROPERTY:
  2102. Status = STATUS_PROPSET_NOT_FOUND;
  2103. FilterInstance = (PFILTER_INSTANCE) IrpStack->FileObject->FsContext;
  2104. ASSERT( FilterInstance );
  2105. if (FilterInstance->StreamDescriptor->
  2106. StreamHeader.NumDevPropArrayEntries) {
  2107. ASSERT( FilterInstance->DevicePropertiesArray );
  2108. Status = KsPropertyHandler(Irp,
  2109. FilterInstance->StreamDescriptor->
  2110. StreamHeader.NumDevPropArrayEntries,
  2111. FilterInstance->DevicePropertiesArray);
  2112. }
  2113. if ((Status == STATUS_PROPSET_NOT_FOUND) ||
  2114. (Status == STATUS_NOT_FOUND)) {
  2115. Status = KsPropertyHandler(Irp,
  2116. SIZEOF_ARRAY(FilterPropertySets),
  2117. (PKSPROPERTY_SET) &FilterPropertySets);
  2118. }
  2119. break;
  2120. case IOCTL_KS_ENABLE_EVENT:
  2121. DebugPrint((DebugLevelTrace,
  2122. "'FilterDispatchIO: Enable event with Irp %x\n", Irp));
  2123. FilterInstance = (PFILTER_INSTANCE) IrpStack->FileObject->FsContext;
  2124. Status = KsEnableEvent(Irp,
  2125. FilterInstance->EventInfoCount,
  2126. FilterInstance->EventInfo,
  2127. NULL, 0, NULL);
  2128. break;
  2129. case IOCTL_KS_DISABLE_EVENT:
  2130. {
  2131. KSEVENTS_LOCKTYPE LockType;
  2132. PVOID LockObject;
  2133. DebugPrint((DebugLevelTrace,
  2134. "'FilterDispatchIO: Disable event with Irp %x\n", Irp));
  2135. //
  2136. // determine the type of lock necessary based on whether we are
  2137. // using interrupt or spinlock synchronization.
  2138. //
  2139. #if DBG
  2140. if (DeviceExtension->SynchronizeExecution == SCDebugKeSynchronizeExecution) {
  2141. #else
  2142. if (DeviceExtension->SynchronizeExecution == KeSynchronizeExecution) {
  2143. #endif
  2144. LockType = KSEVENTS_INTERRUPT;
  2145. LockObject = DeviceExtension->InterruptObject;
  2146. } else {
  2147. LockType = KSEVENTS_SPINLOCK;
  2148. LockObject = &DeviceExtension->SpinLock;
  2149. }
  2150. FilterInstance = (PFILTER_INSTANCE) IrpStack->
  2151. FileObject->FsContext;
  2152. Status = KsDisableEvent(Irp,
  2153. &FilterInstance->NotifyList,
  2154. LockType,
  2155. LockObject);
  2156. }
  2157. break;
  2158. case IOCTL_KS_METHOD:
  2159. Status = STATUS_PROPSET_NOT_FOUND;
  2160. break;
  2161. default:
  2162. Status = STATUS_NOT_SUPPORTED;
  2163. }
  2164. if (Status != STATUS_PENDING) {
  2165. SCCompleteIrp(Irp, Status, DeviceExtension);
  2166. }
  2167. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2168. return (Status);
  2169. }
  2170. NTSTATUS
  2171. ClockDispatchIoControl(
  2172. IN PDEVICE_OBJECT DeviceObject,
  2173. IN PIRP Irp
  2174. )
  2175. /*++
  2176. Routine Description:
  2177. This routine receives control IRP's for the clock.
  2178. Arguments:
  2179. DeviceObject - device object for the device
  2180. Irp - probably an IRP, silly
  2181. Return Value:
  2182. The IRP status is set as appropriate
  2183. --*/
  2184. {
  2185. NTSTATUS Status;
  2186. PIO_STACK_LOCATION IrpStack;
  2187. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  2188. PSTREAM_OBJECT StreamObject;
  2189. PAGED_CODE();
  2190. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2191. Status = SCShowIoPending(DeviceExtension, Irp);
  2192. if ( !NT_SUCCESS ( Status )) {
  2193. //
  2194. // the device is currently not accessible, so just return.
  2195. //
  2196. return (Status);
  2197. }
  2198. switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
  2199. case IOCTL_KS_PROPERTY:
  2200. Status = KsPropertyHandler(Irp,
  2201. SIZEOF_ARRAY(ClockPropertySets),
  2202. (PKSPROPERTY_SET) & ClockPropertySets);
  2203. break;
  2204. case IOCTL_KS_ENABLE_EVENT:
  2205. DebugPrint((DebugLevelTrace,
  2206. "'StreamDispatchIO: Enable event with Irp %x\n", Irp));
  2207. //
  2208. // locate the stream object of the pin for this clock from the IRP.
  2209. // note that we use the event set of the pin for the clock events.
  2210. //
  2211. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->RelatedFileObject->
  2212. FsContext;
  2213. ASSERT(StreamObject);
  2214. Status = KsEnableEvent(Irp,
  2215. StreamObject->EventInfoCount,
  2216. StreamObject->EventInfo,
  2217. NULL, 0, NULL);
  2218. break;
  2219. case IOCTL_KS_DISABLE_EVENT:
  2220. {
  2221. KSEVENTS_LOCKTYPE LockType;
  2222. PVOID LockObject;
  2223. //
  2224. // locate the stream object of the pin for this clock from the
  2225. // IRP.
  2226. // note that we use the event set of the pin for the clock
  2227. // events.
  2228. //
  2229. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->RelatedFileObject->
  2230. FsContext;
  2231. ASSERT(StreamObject);
  2232. DebugPrint((DebugLevelTrace,
  2233. "'StreamDispatchIO: Disable event with Irp %x\n", Irp));
  2234. //
  2235. // determine the type of lock necessary based on whether we are
  2236. // using interrupt or spinlock synchronization.
  2237. //
  2238. #if DBG
  2239. if (DeviceExtension->SynchronizeExecution == SCDebugKeSynchronizeExecution) {
  2240. #else
  2241. if (DeviceExtension->SynchronizeExecution == KeSynchronizeExecution) {
  2242. #endif
  2243. LockType = KSEVENTS_INTERRUPT;
  2244. LockObject = DeviceExtension->InterruptObject;
  2245. } else {
  2246. LockType = KSEVENTS_SPINLOCK;
  2247. LockObject = &DeviceExtension->SpinLock;
  2248. }
  2249. Status = KsDisableEvent(Irp,
  2250. &StreamObject->NotifyList,
  2251. LockType,
  2252. LockObject);
  2253. }
  2254. break;
  2255. case IOCTL_KS_METHOD:
  2256. #ifdef ENABLE_KS_METHODS
  2257. Status = STATUS_PROPSET_NOT_FOUND;
  2258. {
  2259. PFILTER_INSTANCE FilterInstance;
  2260. PHW_STREAM_DESCRIPTOR StreamDescriptor;
  2261. FilterInstance = (PFILTER_INSTANCE) IrpStack->FileObject->FsContext;
  2262. if ( NULL == FilterInstance->StreamDescriptor ) {
  2263. StreamDescriptor = DeviceExtension->FilterTypeInfos
  2264. [FilterInstance->FilterTypeIndex].StreamDescriptor;
  2265. }
  2266. else {
  2267. StreamDescriptor = FilterInstance->StreamDescriptor;
  2268. }
  2269. Status = KsMethodHandler(Irp,
  2270. StreamDescriptor->
  2271. StreamHeader.NumDevMethodArrayEntries,
  2272. FilterInstance->DeviceMethodsArray);
  2273. }
  2274. break;
  2275. #else
  2276. Status = STATUS_PROPSET_NOT_FOUND;
  2277. break;
  2278. #endif
  2279. default:
  2280. DEBUG_BREAKPOINT();
  2281. Status = STATUS_NOT_SUPPORTED;
  2282. }
  2283. if (Status != STATUS_PENDING) {
  2284. SCCompleteIrp(Irp, Status, DeviceExtension);
  2285. }
  2286. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2287. return (Status);
  2288. }
  2289. NTSTATUS
  2290. FilterDispatchClose(
  2291. IN PDEVICE_OBJECT DeviceObject,
  2292. IN PIRP Irp
  2293. )
  2294. /*++
  2295. Routine Description:
  2296. This routine receives CLOSE IRP's for the device/instance
  2297. Arguments:
  2298. DeviceObject - device object for the device
  2299. Irp - probably an IRP, silly
  2300. Return Value:
  2301. The IRP status is set as appropriate
  2302. --*/
  2303. {
  2304. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2305. PFILTER_INSTANCE FilterInstance =
  2306. (PFILTER_INSTANCE) IrpStack->FileObject->FsContext;
  2307. PDEVICE_EXTENSION DeviceExtension =
  2308. (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2309. NTSTATUS Status;
  2310. BOOLEAN IsGlobal;
  2311. BOOLEAN RequestIssued;
  2312. PAGED_CODE();
  2313. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  2314. //
  2315. // remove the filter instance structure from our list
  2316. //
  2317. #if DBG
  2318. IFN_MF(
  2319. if (DeviceExtension->NumberOfGlobalInstances == 1) {
  2320. ASSERT(IsListEmpty(&FilterInstance->FirstStream));
  2321. } // if global = 1
  2322. )
  2323. #endif
  2324. //
  2325. // check to see if this is a global instance
  2326. //
  2327. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  2328. Executive,
  2329. KernelMode,
  2330. FALSE,// not alertable
  2331. NULL);
  2332. DebugPrint(( DebugLevelInfo,
  2333. "Closing FilterInstance %x NeameExts=%x\n",
  2334. FilterInstance,
  2335. DeviceExtension->NumberOfNameExtensions));
  2336. if ( 0 == DeviceExtension->FilterExtensionSize &&
  2337. DeviceExtension->NumberOfOpenInstances > 1) {
  2338. PFILE_OBJECT pFileObject;
  2339. //
  2340. // this is not the last close of the global instance, so just
  2341. // deref this instance and return good status.
  2342. //
  2343. DeviceExtension->NumberOfOpenInstances--;
  2344. DebugPrint(( DebugLevelInfo,
  2345. "DevExt=%x Close OpenCount=%x\n",
  2346. DeviceExtension,
  2347. DeviceExtension->NumberOfOpenInstances));
  2348. IrpStack->FileObject->FsContext = NULL;
  2349. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2350. ObDereferenceObject(DeviceObject);
  2351. SCDereferenceDriver(DeviceExtension);
  2352. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2353. return (SCCompleteIrp(Irp, STATUS_SUCCESS, DeviceExtension));
  2354. }
  2355. //
  2356. // we now know that this is either a local instance, or the last open of
  2357. // the global instance. process the close.
  2358. //
  2359. if ( 0 != DeviceExtension->FilterExtensionSize ) {
  2360. Status = SCSubmitRequest(SRB_CLOSE_DEVICE_INSTANCE,
  2361. NULL,
  2362. 0,
  2363. SCCloseInstanceCallback,
  2364. DeviceExtension,
  2365. FilterInstance->HwInstanceExtension,
  2366. NULL,
  2367. Irp,
  2368. &RequestIssued,
  2369. &DeviceExtension->PendingQueue,
  2370. (PVOID) DeviceExtension->
  2371. MinidriverData->HwInitData.
  2372. HwReceivePacket);
  2373. if (!RequestIssued) {
  2374. DEBUG_BREAKPOINT();
  2375. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2376. SCCompleteIrp(Irp, Status, DeviceExtension);
  2377. }
  2378. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2379. return (Status);
  2380. } else { // if instanceextension
  2381. //
  2382. // the minidriver doesn't need to be called as it does not support
  2383. // instancing. dereference the instance now.
  2384. //
  2385. DeviceExtension->NumberOfOpenInstances--;
  2386. DebugPrint(( DebugLevelInfo,
  2387. "DevExt=%x Close OpenCount=%x\n",
  2388. DeviceExtension,
  2389. DeviceExtension->NumberOfOpenInstances));
  2390. //
  2391. // we are ready to free the instance. if it is global, just zero
  2392. // the pointer. if it is local, remove it from the list.
  2393. //
  2394. IrpStack->FileObject->FsContext = NULL;
  2395. DebugPrint((DebugLevelInfo, "FilterCloseInstance=%x\n", FilterInstance));
  2396. if ( !IsListEmpty( &DeviceExtension->FilterInstanceList)) {
  2397. //
  2398. // The list could be emptied at surprise removal
  2399. // where all instances are removed. so when come in here
  2400. // check it first. Event is taken, check is safe.
  2401. //
  2402. RemoveEntryList(&FilterInstance->NextFilterInstance);
  2403. SciFreeFilterInstance( FilterInstance );
  2404. FilterInstance = NULL;
  2405. }
  2406. else {
  2407. //
  2408. // it has been closed by surprise removal. mark it.
  2409. //
  2410. FilterInstance= NULL;
  2411. }
  2412. //
  2413. // if this is the last close of a removed device, detach from
  2414. // the PDO now, since we couldn't do it on the remove. note that
  2415. // we will NOT do this if the NT style surprise remove IRP has been
  2416. // received, since we'll still receive an IRP_REMOVE in that case
  2417. // after
  2418. // this close.
  2419. //
  2420. if ((DeviceExtension->NumberOfOpenInstances == 0) &&
  2421. (DeviceExtension->Flags & DEVICE_FLAGS_DEVICE_INACCESSIBLE) &&
  2422. !(DeviceExtension->Flags & DEVICE_FLAGS_SURPRISE_REMOVE_RECEIVED)) {
  2423. DebugPrint((DebugLevelInfo,
  2424. "SCPNP: detaching %x from %x\n",
  2425. DeviceObject,
  2426. DeviceExtension->AttachedPdo));
  2427. //
  2428. // detach could happen at remove, check before leap.
  2429. // event is taken, check is safe.
  2430. //
  2431. if ( NULL != DeviceExtension->AttachedPdo ) {
  2432. IoDetachDevice(DeviceExtension->AttachedPdo);
  2433. DeviceExtension->AttachedPdo = NULL;
  2434. }
  2435. }
  2436. else {
  2437. //
  2438. // check if we can power down the device.
  2439. //
  2440. SCCheckPowerDown(DeviceExtension);
  2441. } // if inaccessible
  2442. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2443. if ( NULL != FilterInstance ) {
  2444. DebugPrint(( DebugLevelVerbose,
  2445. "Unregistering ReadWorker %x WriteWorker %x\n",
  2446. FilterInstance->WorkerRead,
  2447. FilterInstance->WorkerWrite));
  2448. KsUnregisterWorker( FilterInstance->WorkerRead );
  2449. KsUnregisterWorker( FilterInstance->WorkerWrite );
  2450. KsFreeObjectHeader(FilterInstance->DeviceHeader);
  2451. ExFreePool(FilterInstance);
  2452. }
  2453. SCDereferenceDriver(DeviceExtension);
  2454. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2455. Status = SCCompleteIrp(Irp, STATUS_SUCCESS, DeviceExtension);
  2456. ObDereferenceObject(DeviceObject);
  2457. return (Status);
  2458. }
  2459. }
  2460. NTSTATUS
  2461. SCCloseInstanceCallback(
  2462. IN PSTREAM_REQUEST_BLOCK SRB
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. Process the completion of an instance close.
  2467. Arguments:
  2468. SRB - address of the completed SRB
  2469. Return Value:
  2470. None.
  2471. --*/
  2472. {
  2473. PDEVICE_EXTENSION DeviceExtension =
  2474. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  2475. PIRP Irp = SRB->HwSRB.Irp;
  2476. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2477. PFILTER_INSTANCE FilterInstance =
  2478. (PFILTER_INSTANCE) SRB->HwSRB.HwInstanceExtension - 1;
  2479. NTSTATUS Status = SRB->HwSRB.Status;
  2480. KIRQL irql;
  2481. //
  2482. // Close should not fail. If it does, should clean up anyway
  2483. ASSERT( NT_SUCCESS(Status) && "Close Instance failed" );
  2484. ///if (NT_SUCCESS(Status)) {
  2485. //
  2486. // we are ready to free the instance. if it is global, just zero
  2487. // the pointer. if it is local, remove it from the list.
  2488. //
  2489. DeviceExtension->NumberOfOpenInstances--;
  2490. KeAcquireSpinLock(&DeviceExtension->SpinLock, &irql);
  2491. RemoveEntryList(&FilterInstance->NextFilterInstance);
  2492. //
  2493. // free the instance and return success.
  2494. //
  2495. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  2496. //
  2497. // if this is the last close of a removed device, detach from
  2498. // the PDO now, since we couldn't do it on the remove.
  2499. //
  2500. if ((DeviceExtension->NumberOfOpenInstances == 0) &&
  2501. (DeviceExtension->Flags & DEVICE_FLAGS_DEVICE_INACCESSIBLE)) {
  2502. DebugPrint((DebugLevelTrace,
  2503. "'SCPNP: detaching from PDO\n"));
  2504. TRAP;
  2505. IoDetachDevice(DeviceExtension->AttachedPdo);
  2506. DeviceExtension->AttachedPdo = NULL;
  2507. }
  2508. //
  2509. // check if we can power down the device.
  2510. //
  2511. SCCheckPowerDown(DeviceExtension);
  2512. ObDereferenceObject(DeviceExtension->DeviceObject);
  2513. //
  2514. // free the instance and header and dereference the driver
  2515. //
  2516. SciFreeFilterInstance( FilterInstance );
  2517. ///#ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  2518. ///DebugPrint(( DebugLevelVerbose,
  2519. /// "Unregistering ReadWorker %x WriteWorker %x\n",
  2520. /// FilterInstance->WorkerRead,
  2521. /// FilterInstance->WorkerWrite));
  2522. ///
  2523. ///KsUnregisterWorker( FilterInstance->WorkerRead );
  2524. ///KsUnregisterWorker( FilterInstance->WorkerWrite );
  2525. ///#endif
  2526. ///KsFreeObjectHeader(FilterInstance->DeviceHeader);
  2527. ///ExFreePool(FilterInstance);
  2528. SCDereferenceDriver(DeviceExtension);
  2529. ///} // if good status
  2530. //
  2531. // signal the event and complete the IRP.
  2532. //
  2533. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2534. SCProcessCompletedRequest(SRB);
  2535. return (Status);
  2536. }
  2537. NTSTATUS
  2538. StreamDispatchCleanup
  2539. (
  2540. IN PDEVICE_OBJECT DeviceObject,
  2541. IN PIRP Irp
  2542. )
  2543. /*++
  2544. Routine Description:
  2545. This routine receives CLEANUP IRP's for a stream
  2546. Arguments:
  2547. DeviceObject - device object for the device
  2548. Irp - The CLEANUP Irp
  2549. Return Value:
  2550. The IRP status set as appropriate
  2551. --*/
  2552. {
  2553. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation (Irp);
  2554. PSTREAM_OBJECT StreamObject =
  2555. (PSTREAM_OBJECT) IrpStack -> FileObject -> FsContext;
  2556. PDEVICE_EXTENSION DeviceExtension =
  2557. (PDEVICE_EXTENSION) DeviceObject -> DeviceExtension;
  2558. BOOLEAN BreakClockCycle = FALSE;
  2559. KeWaitForSingleObject (
  2560. &DeviceExtension -> ControlEvent,
  2561. Executive,
  2562. KernelMode,
  2563. FALSE,
  2564. NULL
  2565. );
  2566. //
  2567. // If the stream in question is a source stream and it has not yet
  2568. // stopped the sourcing worker, it must be done at this point in time.
  2569. //
  2570. if (StreamObject -> CurrentState > KSSTATE_STOP &&
  2571. StreamObject -> PinType == IrpSource &&
  2572. StreamObject -> StandardTransport) {
  2573. EndTransfer (StreamObject -> FilterInstance, StreamObject);
  2574. }
  2575. //
  2576. // Check for the clock<->pin cycle and break it if present.
  2577. //
  2578. if (StreamObject -> MasterClockInfo) {
  2579. PFILE_OBJECT ClockFile = StreamObject -> MasterClockInfo ->
  2580. ClockFileObject;
  2581. if (ClockFile &&
  2582. ClockFile -> RelatedFileObject == StreamObject -> FileObject)
  2583. BreakClockCycle = TRUE;
  2584. }
  2585. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2586. //
  2587. // Synchronously submit an Irp down our own stack to get break the
  2588. // clock<->pin cycle. Otherwise, the stream can't close. The driver should
  2589. // guard against the clock disappearing while running. Stream class does
  2590. // on TOP of that if they do not.
  2591. //
  2592. if (BreakClockCycle) {
  2593. KSPROPERTY Property;
  2594. HANDLE NewClock = NULL;
  2595. ULONG BytesReturned;
  2596. NTSTATUS Status;
  2597. Property.Set = KSPROPSETID_Stream;
  2598. Property.Id = KSPROPERTY_STREAM_MASTERCLOCK;
  2599. Property.Flags = KSPROPERTY_TYPE_SET;
  2600. Status =
  2601. KsSynchronousIoControlDevice (
  2602. StreamObject -> FileObject,
  2603. KernelMode,
  2604. IOCTL_KS_PROPERTY,
  2605. &Property,
  2606. sizeof (KSPROPERTY),
  2607. &NewClock,
  2608. sizeof (HANDLE),
  2609. &BytesReturned
  2610. );
  2611. ASSERT (NT_SUCCESS (Status));
  2612. }
  2613. Irp -> IoStatus.Status = STATUS_SUCCESS;
  2614. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  2615. return STATUS_SUCCESS;
  2616. }
  2617. NTSTATUS
  2618. StreamDispatchClose
  2619. (
  2620. IN PDEVICE_OBJECT DeviceObject,
  2621. IN PIRP Irp
  2622. )
  2623. /*++
  2624. Routine Description:
  2625. This routine receives CLOSE IRP's for a stream
  2626. Arguments:
  2627. DeviceObject - device object for the device
  2628. Irp - probably an IRP, silly
  2629. Return Value:
  2630. The IRP status is set as appropriate
  2631. --*/
  2632. {
  2633. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2634. PSTREAM_OBJECT StreamObject =
  2635. (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  2636. PDEVICE_EXTENSION DeviceExtension =
  2637. (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2638. NTSTATUS Status;
  2639. BOOLEAN RequestIssued;
  2640. KSEVENTS_LOCKTYPE LockType;
  2641. PVOID LockObject;
  2642. PAGED_CODE();
  2643. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  2644. ASSERT(IsListEmpty(&StreamObject->ControlPendingQueue));
  2645. ASSERT(IsListEmpty(&StreamObject->DataPendingQueue));
  2646. //
  2647. // free events associated with this stream. this will cause our remove
  2648. // handler to be called for each, and will hence notify the minidriver.
  2649. //
  2650. //
  2651. // determine the type of lock necessary based on whether we are
  2652. // using interrupt or spinlock synchronization.
  2653. //
  2654. #if DBG
  2655. if (DeviceExtension->SynchronizeExecution == SCDebugKeSynchronizeExecution) {
  2656. #else
  2657. if (DeviceExtension->SynchronizeExecution == KeSynchronizeExecution) {
  2658. #endif
  2659. LockType = KSEVENTS_INTERRUPT;
  2660. LockObject = DeviceExtension->InterruptObject;
  2661. } else {
  2662. LockType = KSEVENTS_SPINLOCK;
  2663. LockObject = &DeviceExtension->SpinLock;
  2664. }
  2665. KsFreeEventList(IrpStack->FileObject,
  2666. &StreamObject->NotifyList,
  2667. LockType,
  2668. LockObject);
  2669. //
  2670. // call the minidriver to close the stream. processing will continue
  2671. // when the callback procedure is called.
  2672. //
  2673. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  2674. Executive,
  2675. KernelMode,
  2676. FALSE,// not alertable
  2677. NULL);
  2678. Status = SCSubmitRequest(SRB_CLOSE_STREAM,
  2679. NULL,
  2680. 0,
  2681. SCCloseStreamCallback,
  2682. DeviceExtension,
  2683. StreamObject->
  2684. FilterInstance->HwInstanceExtension,
  2685. &StreamObject->HwStreamObject,
  2686. Irp,
  2687. &RequestIssued,
  2688. &DeviceExtension->PendingQueue,
  2689. (PVOID) DeviceExtension->
  2690. MinidriverData->HwInitData.
  2691. HwReceivePacket);
  2692. if (!RequestIssued) {
  2693. DEBUG_BREAKPOINT();
  2694. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2695. SCCompleteIrp(Irp, Status, DeviceExtension);
  2696. }
  2697. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2698. return (Status);
  2699. }
  2700. NTSTATUS
  2701. SCCloseStreamCallback(
  2702. IN PSTREAM_REQUEST_BLOCK SRB
  2703. )
  2704. /*++
  2705. Routine Description:
  2706. Process the completion of a stream close.
  2707. Arguments:
  2708. SRB - address of the completed SRB
  2709. Return Value:
  2710. None.
  2711. --*/
  2712. {
  2713. PDEVICE_EXTENSION DeviceExtension =
  2714. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  2715. PADDITIONAL_PIN_INFO AdditionalInfo;
  2716. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  2717. SRB->HwSRB.StreamObject,
  2718. STREAM_OBJECT,
  2719. HwStreamObject
  2720. );
  2721. PIRP Irp = SRB->HwSRB.Irp;
  2722. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2723. KIRQL Irql;
  2724. NTSTATUS Status = SRB->HwSRB.Status;
  2725. ASSERT( NT_SUCCESS(Status) && "CloseStream Failed by Minidriver");
  2726. //
  2727. // Close should not fail. Even it does, we want to clean up.
  2728. //
  2729. // if (NT_SUCCESS(Status)) {
  2730. //
  2731. // show one fewer instance open
  2732. //
  2733. DebugPrint((DebugLevelInfo, "SC Closing StreamObject %x\n", StreamObject));
  2734. AdditionalInfo = ((PFILTER_INSTANCE) IrpStack->FileObject->
  2735. RelatedFileObject->FsContext)->PinInstanceInfo;
  2736. AdditionalInfo[StreamObject->HwStreamObject.StreamNumber].
  2737. CurrentInstances--;
  2738. //
  2739. // free the object header for the stream
  2740. //
  2741. KsFreeObjectHeader(StreamObject->ComObj.DeviceHeader);
  2742. //
  2743. // free the constructed props, if any.
  2744. //
  2745. if (StreamObject->ConstructedPropertyInfo) {
  2746. ExFreePool(StreamObject->ConstructedPropertyInfo);
  2747. }
  2748. //
  2749. // signal the event.
  2750. // signal now so that we won't
  2751. // deadlock when we dereference the object and the filter is closed.
  2752. //
  2753. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2754. //
  2755. // Zero the pointer to our per stream structure in the FsContext
  2756. // field of
  2757. // of FileObject.
  2758. //
  2759. IrpStack->FileObject->FsContext = 0;
  2760. //
  2761. // remove the stream object from the filter instance list
  2762. //
  2763. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  2764. RemoveEntryList(&StreamObject->NextStream);
  2765. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  2766. //
  2767. // kill the timer, which might have been left dangling by the
  2768. // minidriver.
  2769. //
  2770. KeCancelTimer(&StreamObject->ComObj.MiniDriverTimer);
  2771. //
  2772. // dereference the master clock if any
  2773. //
  2774. if (StreamObject->MasterClockInfo) {
  2775. ObDereferenceObject(StreamObject->MasterClockInfo->ClockFileObject);
  2776. ExFreePool(StreamObject->MasterClockInfo);
  2777. }
  2778. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  2779. //
  2780. // dereference the next file object
  2781. //
  2782. if (StreamObject->NextFileObject)
  2783. {
  2784. ObDereferenceObject(StreamObject->NextFileObject);
  2785. StreamObject->NextFileObject = NULL;
  2786. }
  2787. //
  2788. // Dereference the allocator object or stream obj won't be
  2789. // release while it should. Problems would follow particularly
  2790. // with SWEnum loaded driver.
  2791. //
  2792. if ( StreamObject->AllocatorFileObject ) {
  2793. ObDereferenceObject( StreamObject->AllocatorFileObject );
  2794. StreamObject->AllocatorFileObject = NULL;
  2795. }
  2796. #endif
  2797. //
  2798. // dereference the filter
  2799. //
  2800. ObDereferenceObject(StreamObject->FilterFileObject);
  2801. ExFreePool(StreamObject);
  2802. ///} else { // if good status
  2803. /// KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  2804. ///} // if good status
  2805. SCProcessCompletedRequest(SRB);
  2806. return (Status);
  2807. }
  2808. BOOLEAN
  2809. StreamClassInterrupt(
  2810. IN PKINTERRUPT Interrupt,
  2811. IN PDEVICE_OBJECT DeviceObject
  2812. )
  2813. /*++
  2814. Routine Description:
  2815. Process interrupt from the device
  2816. Arguments:
  2817. Interrupt - interrupt object
  2818. Device Object - device object which is interrupting
  2819. Return Value:
  2820. Returns TRUE if interrupt expected.
  2821. --*/
  2822. {
  2823. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  2824. BOOLEAN returnValue;
  2825. UNREFERENCED_PARAMETER(Interrupt);
  2826. //
  2827. // check if the interrupt cannot currently go down
  2828. //
  2829. if (deviceExtension->DriverInfo->Flags & DRIVER_FLAGS_PAGED_OUT) {
  2830. return (FALSE);
  2831. }
  2832. //
  2833. // call the minidriver's interrupt service routine.
  2834. //
  2835. returnValue = deviceExtension->MinidriverData->
  2836. HwInitData.HwInterrupt(deviceExtension->HwDeviceExtension);
  2837. //
  2838. // Queue up a DPC if needed.
  2839. //
  2840. if ((deviceExtension->NeedyStream) || (deviceExtension->ComObj.
  2841. InterruptData.Flags & INTERRUPT_FLAGS_NOTIFICATION_REQUIRED)) {
  2842. KeInsertQueueDpc(&deviceExtension->WorkDpc, NULL, NULL);
  2843. }
  2844. return (returnValue);
  2845. } // end StreamClassInterrupt()
  2846. NTSTATUS
  2847. StreamClassNull(
  2848. IN PDEVICE_OBJECT DeviceObject,
  2849. IN PIRP Irp
  2850. )
  2851. /*++
  2852. Routine Description:
  2853. This routine fails incoming irps.
  2854. Arguments:
  2855. DeviceObject - device object for the device
  2856. Irp - probably an IRP, silly
  2857. Return Value:
  2858. The IRP status is returned
  2859. --*/
  2860. {
  2861. //
  2862. // complete the IRP with error status
  2863. //
  2864. PAGED_CODE();
  2865. return (SCCompleteIrp(Irp, STATUS_NOT_SUPPORTED, DeviceObject->DeviceExtension));
  2866. }
  2867. NTSTATUS
  2868. SCFilterPinInstances(
  2869. IN PIRP Irp,
  2870. IN PKSPROPERTY Property,
  2871. IN OUT PVOID Data)
  2872. /*++
  2873. Routine Description:
  2874. Returns the # of instances supported by a pin
  2875. Arguments:
  2876. Irp - pointer to the irp
  2877. Property - pointer to the property info
  2878. Data - instance info
  2879. Return Value:
  2880. NTSTATUS returned as appropriate
  2881. --*/
  2882. {
  2883. ULONG Pin;
  2884. PKSPIN_CINSTANCES CInstances;
  2885. PIO_STACK_LOCATION IrpStack;
  2886. PDEVICE_EXTENSION DeviceExtension;
  2887. PFILTER_INSTANCE FilterInstance;
  2888. PADDITIONAL_PIN_INFO AdditionalPinInfo;
  2889. PAGED_CODE();
  2890. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2891. DeviceExtension = (PDEVICE_EXTENSION) IrpStack->
  2892. DeviceObject->DeviceExtension;
  2893. FilterInstance = IrpStack->FileObject->FsContext;
  2894. //
  2895. // get the pin #
  2896. //
  2897. Pin = ((PKSP_PIN) Property)->PinId;
  2898. //
  2899. // if max pin number exceeded, return error
  2900. //
  2901. IFN_MF(
  2902. if (Pin >= DeviceExtension->NumberOfPins) {
  2903. DEBUG_BREAKPOINT();
  2904. return (STATUS_INVALID_PARAMETER);
  2905. }
  2906. )
  2907. IF_MF(
  2908. if (Pin >= FilterInstance->NumberOfPins) {
  2909. DEBUG_BREAKPOINT();
  2910. return (STATUS_INVALID_PARAMETER);
  2911. }
  2912. )
  2913. CInstances = (PKSPIN_CINSTANCES) Data;
  2914. AdditionalPinInfo = FilterInstance->PinInstanceInfo;
  2915. CInstances->PossibleCount = AdditionalPinInfo[Pin].MaxInstances;
  2916. CInstances->CurrentCount = AdditionalPinInfo[Pin].CurrentInstances;
  2917. Irp->IoStatus.Information = sizeof(KSPIN_CINSTANCES);
  2918. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  2919. return (STATUS_SUCCESS);
  2920. }
  2921. NTSTATUS
  2922. SCFilterPinPropertyHandler(
  2923. IN PIRP Irp,
  2924. IN PKSPROPERTY Property,
  2925. IN OUT PVOID Data)
  2926. /*++
  2927. Routine Description:
  2928. Dispatches a pin property request
  2929. Arguments:
  2930. Irp - pointer to the irp
  2931. Property - pointer to the property info
  2932. Data - property specific buffer
  2933. Return Value:
  2934. NTSTATUS returned as appropriate
  2935. --*/
  2936. {
  2937. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2938. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) IrpStack->
  2939. DeviceObject->DeviceExtension;
  2940. PFILTER_INSTANCE FilterInstance= (PFILTER_INSTANCE) IrpStack->
  2941. FileObject->FsContext;
  2942. PAGED_CODE();
  2943. return KsPinPropertyHandler(Irp,
  2944. Property,
  2945. Data,
  2946. FilterInstance->NumberOfPins,
  2947. FilterInstance->PinInformation);
  2948. }
  2949. VOID
  2950. StreamClassTickHandler(
  2951. IN PDEVICE_OBJECT DeviceObject,
  2952. IN PVOID Context
  2953. )
  2954. /*++
  2955. Routine Description:
  2956. Tick handler for device.
  2957. Arguments:
  2958. DeviceObject - pointer to the device object
  2959. Context - unreferenced
  2960. Return Value:
  2961. None.
  2962. --*/
  2963. {
  2964. PDEVICE_EXTENSION DeviceExtension =
  2965. (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2966. PLIST_ENTRY ListEntry;
  2967. PLIST_ENTRY SrbListEntry = ListEntry = &DeviceExtension->OutstandingQueue;
  2968. PSTREAM_REQUEST_BLOCK Srb;
  2969. UNREFERENCED_PARAMETER(Context);
  2970. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  2971. //
  2972. // acquire the device spinlock to protect the queues.
  2973. //
  2974. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  2975. //
  2976. // process any timed out requests on the device
  2977. //
  2978. while (SrbListEntry->Flink != ListEntry) {
  2979. SrbListEntry = SrbListEntry->Flink;
  2980. Srb = CONTAINING_RECORD(SrbListEntry,
  2981. STREAM_REQUEST_BLOCK,
  2982. SRBListEntry);
  2983. //
  2984. // first make sure the request is active, since it could have been
  2985. // called back but not yet removed from the queue.
  2986. //
  2987. if (Srb->Flags & SRB_FLAGS_IS_ACTIVE) {
  2988. //
  2989. // check for a timeout if the counter is currently nonzero.
  2990. //
  2991. if (Srb->HwSRB.TimeoutCounter != 0) {
  2992. if (--Srb->HwSRB.TimeoutCounter == 0) {
  2993. //
  2994. // request timed out. Call the minidriver to process it.
  2995. // first reset the timer in case the minidriver is
  2996. // busted.
  2997. //
  2998. DebugPrint((DebugLevelError, "SCTickHandler: Irp %x timed out! SRB = %x, SRB func = %x, Stream Object = %x\n",
  2999. Srb->HwSRB.Irp, Srb, Srb->HwSRB.Command, Srb->HwSRB.StreamObject));
  3000. Srb->HwSRB.TimeoutCounter = Srb->HwSRB.TimeoutOriginal;
  3001. DeviceExtension = (PDEVICE_EXTENSION)
  3002. Srb->HwSRB.HwDeviceExtension - 1;
  3003. //
  3004. // if we are not synchronizing the minidriver, release
  3005. // and reacquire the spinlock around the call into it.
  3006. //
  3007. if (DeviceExtension->NoSync) {
  3008. //
  3009. // we need to ensure that the SRB memory is valid for
  3010. // the async
  3011. // minidriver, EVEN if it happens to call back the
  3012. // request just
  3013. // before we call it to cancel it! This is done for
  3014. // two reasons:
  3015. // it obviates the need for the minidriver to walk
  3016. // its request
  3017. // queues to find the request, and I failed to pass
  3018. // the dev ext
  3019. // pointer to the minidriver in the below call, which
  3020. // means that
  3021. // the SRB HAS to be valid, and it's too late to
  3022. // change the API.
  3023. //
  3024. // Oh, well. Spinlock is now taken (by caller).
  3025. //
  3026. Srb->DoNotCallBack = TRUE;
  3027. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3028. (DeviceExtension->MinidriverData->HwInitData.HwRequestTimeoutHandler)
  3029. (&Srb->HwSRB);
  3030. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3031. //
  3032. // if the ACTIVE flag is now clear, it indicates that
  3033. // the
  3034. // SRB was completed during the above call into the
  3035. // minidriver.
  3036. // since we blocked the internal completion of the
  3037. // request,
  3038. // we must call it back ourselves in this case.
  3039. //
  3040. Srb->DoNotCallBack = FALSE;
  3041. if (!(Srb->Flags & SRB_FLAGS_IS_ACTIVE)) {
  3042. TRAP;
  3043. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3044. (Srb->Callback) (Srb);
  3045. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3046. } // if ! active
  3047. break;
  3048. } else { // if nosync
  3049. DeviceExtension->SynchronizeExecution(
  3050. DeviceExtension->InterruptObject,
  3051. (PVOID) DeviceExtension->MinidriverData->HwInitData.HwRequestTimeoutHandler,
  3052. &Srb->HwSRB);
  3053. // return now in case the minidriver aborted any
  3054. // other
  3055. // requests that
  3056. // may be timing out now.
  3057. //
  3058. break;
  3059. } // if nosync
  3060. } // if timed out
  3061. } // if counter != 0
  3062. } // if active
  3063. } // while list entry
  3064. //
  3065. // let my people go...
  3066. //
  3067. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3068. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  3069. return;
  3070. } // end StreamClassTickHandler()
  3071. VOID
  3072. StreamClassCancelPendingIrp(
  3073. IN PDEVICE_OBJECT DeviceObject,
  3074. IN PIRP Irp
  3075. )
  3076. /*++
  3077. Routine Description:
  3078. Cancel routine for pending IRP's.
  3079. Arguments:
  3080. DeviceObject - pointer to the device object
  3081. Irp - pointer to IRP to be cancelled
  3082. Return Value:
  3083. None.
  3084. --*/
  3085. {
  3086. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  3087. PFILTER_INSTANCE FilterInstance;
  3088. PLIST_ENTRY ListHead, ListEntry;
  3089. KIRQL CancelIrql,
  3090. Irql;
  3091. PSTREAM_REQUEST_BLOCK SRB;
  3092. DebugPrint((DebugLevelWarning, "'SCCancelPending: trying to cancel Irp = %x\n",
  3093. Irp));
  3094. //
  3095. // acquire the device spinlock then release the cancel spinlock.
  3096. //
  3097. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3098. CancelIrql = Irp->CancelIrql;
  3099. IoReleaseCancelSpinLock(Irql);
  3100. //
  3101. // there are two possibilities here. 1) the IRP is on the pending queue
  3102. // for the particular stream. 2) the IRP was moved from pending to
  3103. // outstanding and has been submitted to the minidriver.
  3104. // If we are running above an external bus driver, don't
  3105. //
  3106. //
  3107. // now process all streams on the local filter instances.
  3108. //
  3109. ListHead = &DeviceExtension->FilterInstanceList;
  3110. ListEntry = ListHead->Flink;
  3111. while ( ListEntry != ListHead ) {
  3112. //
  3113. // follow the link to the instance
  3114. //
  3115. FilterInstance = CONTAINING_RECORD(ListEntry,
  3116. FILTER_INSTANCE,
  3117. NextFilterInstance);
  3118. //
  3119. // process the streams on this list
  3120. //
  3121. if (SCCheckFilterInstanceStreamsForIrp(FilterInstance, Irp)) {
  3122. goto found;
  3123. }
  3124. ListEntry = ListEntry->Flink;
  3125. }
  3126. //
  3127. // now process any requests on the device itself
  3128. //
  3129. if (SCCheckRequestsForIrp(
  3130. &DeviceExtension->OutstandingQueue, Irp, TRUE, DeviceExtension)) {
  3131. goto found;
  3132. }
  3133. //
  3134. // request is not on pending queue, so call to check the outstanding
  3135. // queue
  3136. //
  3137. SCCancelOutstandingIrp(DeviceExtension, Irp);
  3138. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3139. exit:
  3140. //
  3141. // now call the DPC in case the request was successfully aborted.
  3142. //
  3143. StreamClassDpc(NULL,
  3144. DeviceExtension->DeviceObject,
  3145. NULL,
  3146. NULL);
  3147. KeLowerIrql(CancelIrql);
  3148. return;
  3149. found:
  3150. //
  3151. // the irp is on one of our pending queues. remove it from the queue and
  3152. // complete it.
  3153. //
  3154. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  3155. //
  3156. // retrieve the SRB.
  3157. //
  3158. SRB = Irp->Tail.Overlay.DriverContext[0];
  3159. //
  3160. // hack - the completion handlers will try to remove the SRB from the
  3161. // outstanding queue. Point the SRB's queues to itself so this will not
  3162. // cause a problem.
  3163. //
  3164. SRB->SRBListEntry.Flink = &SRB->SRBListEntry;
  3165. SRB->SRBListEntry.Blink = &SRB->SRBListEntry;
  3166. SRB->HwSRB.Status = STATUS_CANCELLED;
  3167. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3168. (SRB->Callback) (SRB);
  3169. goto exit;
  3170. }
  3171. VOID
  3172. StreamClassCancelOutstandingIrp(
  3173. IN PDEVICE_OBJECT DeviceObject,
  3174. IN PIRP Irp
  3175. )
  3176. /*++
  3177. Routine Description:
  3178. Cancel routine for IRP's outstanding in the minidriver
  3179. Arguments:
  3180. DeviceObject - pointer to the device object
  3181. Irp - pointer to IRP to be cancelled
  3182. Return Value:
  3183. None.
  3184. --*/
  3185. {
  3186. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  3187. KIRQL Irql,
  3188. CancelIrql;
  3189. DebugPrint((DebugLevelWarning, "'SCCancelOutstanding: trying to cancel Irp = %x\n",
  3190. Irp));
  3191. //
  3192. // acquire the device spinlock.
  3193. //
  3194. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3195. CancelIrql = Irp->CancelIrql;
  3196. IoReleaseCancelSpinLock(Irql);
  3197. SCCancelOutstandingIrp(DeviceExtension, Irp);
  3198. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3199. //
  3200. // now call the DPC in case the request was successfully aborted.
  3201. //
  3202. StreamClassDpc(NULL,
  3203. DeviceExtension->DeviceObject,
  3204. NULL,
  3205. NULL);
  3206. KeLowerIrql(CancelIrql);
  3207. return;
  3208. }
  3209. VOID
  3210. StreamFlushIo(
  3211. IN PDEVICE_EXTENSION DeviceExtension,
  3212. IN PSTREAM_OBJECT StreamObject
  3213. )
  3214. /*++
  3215. Routine Description:
  3216. Cancel all IRP's on the specified stream.
  3217. Arguments:
  3218. Return Value:
  3219. STATUS_SUCCESS
  3220. --*/
  3221. {
  3222. PLIST_ENTRY IrpEntry;
  3223. KIRQL Irql;
  3224. PSTREAM_REQUEST_BLOCK SRB;
  3225. PIRP Irp;
  3226. //
  3227. // abort all I/O on the specified stream. first acquire the spinlock.
  3228. //
  3229. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3230. //
  3231. // if there is I/O on our pending data queue, abort it.
  3232. //
  3233. while (!IsListEmpty(&StreamObject->DataPendingQueue)) {
  3234. //
  3235. // grab the IRP at the head of the queue and abort it.
  3236. //
  3237. IrpEntry = StreamObject->DataPendingQueue.Flink;
  3238. Irp = CONTAINING_RECORD(IrpEntry,
  3239. IRP,
  3240. Tail.Overlay.ListEntry);
  3241. //
  3242. // remove the IRP from our pending queue and call it back with
  3243. // cancelled status
  3244. //
  3245. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  3246. //
  3247. // null out the cancel routine
  3248. //
  3249. IoSetCancelRoutine(Irp, NULL);
  3250. DebugPrint((DebugLevelTrace,
  3251. "'StreamFlush: Canceling Irp %x \n", Irp));
  3252. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  3253. SCCompleteIrp(Irp, STATUS_CANCELLED, DeviceExtension);
  3254. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3255. }
  3256. //
  3257. // if there is I/O on our pending control queue, abort it.
  3258. //
  3259. while (!IsListEmpty(&StreamObject->ControlPendingQueue)) {
  3260. //
  3261. // grab the IRP at the head of the queue and abort it.
  3262. //
  3263. DEBUG_BREAKPOINT();
  3264. IrpEntry = StreamObject->ControlPendingQueue.Flink;
  3265. Irp = CONTAINING_RECORD(IrpEntry,
  3266. IRP,
  3267. Tail.Overlay.ListEntry);
  3268. //
  3269. // remove the IRP from our pending queue and call it back with
  3270. // cancelled status
  3271. //
  3272. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  3273. //
  3274. // null out the cancel routine
  3275. //
  3276. IoSetCancelRoutine(Irp, NULL);
  3277. DebugPrint((DebugLevelTrace,
  3278. "'StreamFlush: Canceling Irp %x \n", Irp));
  3279. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  3280. SCCompleteIrp(Irp, STATUS_CANCELLED, DeviceExtension);
  3281. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  3282. }
  3283. //
  3284. // now cancel any irps for this stream on the outstanding queue.
  3285. // walk the outstanding queue trying to find an SRB for this stream.
  3286. //
  3287. IrpEntry = &DeviceExtension->OutstandingQueue;
  3288. while (IrpEntry->Flink != &DeviceExtension->OutstandingQueue) {
  3289. IrpEntry = IrpEntry->Flink;
  3290. //
  3291. // follow the link to the SRB
  3292. //
  3293. SRB = (PSTREAM_REQUEST_BLOCK) (CONTAINING_RECORD(IrpEntry,
  3294. STREAM_REQUEST_BLOCK,
  3295. SRBListEntry));
  3296. //
  3297. // if this SRB's stream object matches the one we're cancelling for,
  3298. // AND it has not been previously cancelled, AND the IRP itself has
  3299. // not been completed (non-null IRP field), abort this request.
  3300. //
  3301. if ((StreamObject == CONTAINING_RECORD(
  3302. SRB->HwSRB.StreamObject,
  3303. STREAM_OBJECT,
  3304. HwStreamObject)) &&
  3305. (SRB->HwSRB.Irp) &&
  3306. !(SRB->HwSRB.Irp->Cancel)) {
  3307. //
  3308. // The IRP has not been previously cancelled, so cancel it after
  3309. // releasing the spinlock to avoid deadlock with the cancel
  3310. // routine.
  3311. //
  3312. DebugPrint((DebugLevelTrace,
  3313. "'StreamFlush: Canceling Irp %x \n", SRB->HwSRB.Irp));
  3314. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3315. IoCancelIrp(SRB->HwSRB.Irp);
  3316. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3317. //
  3318. // restart at the top of the queue since we released the
  3319. // spinlock.
  3320. // we won't get in an endless loop since we set the cancel flag
  3321. // in the IRP.
  3322. //
  3323. IrpEntry = &DeviceExtension->OutstandingQueue;
  3324. } // if streamobjects match
  3325. } // while entries
  3326. //
  3327. // release the spinlock but remain at DPC level.
  3328. //
  3329. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3330. //
  3331. // now call the DPC in case the request was successfully aborted.
  3332. //
  3333. StreamClassDpc(NULL,
  3334. DeviceExtension->DeviceObject,
  3335. NULL,
  3336. NULL);
  3337. //
  3338. // lower IRQL
  3339. //
  3340. KeLowerIrql(Irql);
  3341. }
  3342. NTSTATUS
  3343. ClockDispatchCreate(
  3344. IN PDEVICE_OBJECT DeviceObject,
  3345. IN PIRP Irp
  3346. )
  3347. {
  3348. NTSTATUS Status;
  3349. PCLOCK_INSTANCE ClockInstance=NULL; //Prefixbug 17399
  3350. PIO_STACK_LOCATION IrpStack;
  3351. PKSCLOCK_CREATE ClockCreate;
  3352. PFILE_OBJECT ParentFileObject;
  3353. PSTREAM_OBJECT StreamObject=NULL; // prefixbug 17399
  3354. BOOLEAN RequestIssued=FALSE; // prefixbug 17398
  3355. PAGED_CODE();
  3356. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3357. //
  3358. // show one more I/O pending & verify that we can actually do I/O.
  3359. //
  3360. Status = SCShowIoPending(DeviceObject->DeviceExtension, Irp);
  3361. if ( !NT_SUCCESS ( Status )) {
  3362. //
  3363. // the device is currently not accessible, so just return with error
  3364. //
  3365. return (Status);
  3366. }
  3367. Status = KsValidateClockCreateRequest(Irp,
  3368. &ClockCreate);
  3369. ParentFileObject = IrpStack->FileObject->RelatedFileObject;
  3370. DebugPrint((DebugLevelTrace,
  3371. "'ClockCreate: Creating clock with Irp %x \n", Irp));
  3372. if (NT_SUCCESS(Status)) {
  3373. //
  3374. // allocate a clock instance for the clock
  3375. //
  3376. ClockInstance =
  3377. (PCLOCK_INSTANCE)
  3378. ExAllocatePool(NonPagedPool, sizeof(CLOCK_INSTANCE));
  3379. if (ClockInstance) {
  3380. //
  3381. // fill in the clock instance structure and reference it in the
  3382. // file
  3383. // object for the clock
  3384. //
  3385. ClockInstance->ParentFileObject = ParentFileObject;
  3386. #if 0
  3387. ClockInstance->ClockFileObject = IrpStack->FileObject;
  3388. DebugPrint((DebugLevelInfo,
  3389. "++++++++ClockInstance=%x, FileObject=%x\n",
  3390. ClockInstance,
  3391. ClockInstance->ClockFileObject));
  3392. #endif
  3393. KsAllocateObjectHeader(&ClockInstance->DeviceHeader,
  3394. SIZEOF_ARRAY(StreamDriverDispatch),
  3395. (PKSOBJECT_CREATE_ITEM) NULL,
  3396. Irp,
  3397. (PKSDISPATCH_TABLE) & ClockDispatchTable);
  3398. IrpStack->FileObject->FsContext = ClockInstance;
  3399. //
  3400. // set the 2nd context parameter so that we can identify this
  3401. // object as the clock object.
  3402. //
  3403. IrpStack->FileObject->FsContext2 = ClockInstance;
  3404. //
  3405. // call the minidriver to indicate that this stream is the master
  3406. // clock. pass the file object as a handle to the master clock.
  3407. //
  3408. StreamObject = (PSTREAM_OBJECT) ParentFileObject->FsContext;
  3409. StreamObject->ClockInstance = ClockInstance;
  3410. ClockInstance->StreamObject = StreamObject;
  3411. Status = SCSubmitRequest(SRB_OPEN_MASTER_CLOCK,
  3412. (HANDLE) IrpStack->FileObject,
  3413. 0,
  3414. SCOpenMasterCallback,
  3415. StreamObject->DeviceExtension,
  3416. StreamObject->FilterInstance->HwInstanceExtension,
  3417. &StreamObject->HwStreamObject,
  3418. Irp,
  3419. &RequestIssued,
  3420. &StreamObject->ControlPendingQueue,
  3421. (PVOID) StreamObject->HwStreamObject.
  3422. ReceiveControlPacket
  3423. );
  3424. } else { // if clockinstance
  3425. Status = STATUS_INSUFFICIENT_RESOURCES;
  3426. } // if clockinstance
  3427. } // if validate success
  3428. if (!RequestIssued) {
  3429. if ( NULL != StreamObject && NULL != StreamObject->ClockInstance ) {
  3430. ExFreePool(StreamObject->ClockInstance);
  3431. StreamObject->ClockInstance = NULL; // prefixbug 17399
  3432. }
  3433. SCCompleteIrp(Irp,
  3434. STATUS_INSUFFICIENT_RESOURCES,
  3435. DeviceObject->DeviceExtension);
  3436. }
  3437. return (Status);
  3438. }
  3439. NTSTATUS
  3440. AllocatorDispatchCreate(
  3441. IN PDEVICE_OBJECT DeviceObject,
  3442. IN PIRP Irp
  3443. )
  3444. /*++
  3445. Routine Description:
  3446. Processes the allocator create IRP. Currently just uses the default
  3447. allocator.
  3448. Arguments:
  3449. Return Value:
  3450. None.
  3451. --*/
  3452. {
  3453. PIO_STACK_LOCATION IrpStack;
  3454. PFILE_OBJECT ParentFileObject;
  3455. PSTREAM_OBJECT StreamObject;
  3456. NTSTATUS Status;
  3457. PAGED_CODE();
  3458. DebugPrint((DebugLevelTrace,"entering AllocatorDispatchCreate\n"));
  3459. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3460. ParentFileObject = IrpStack->FileObject->RelatedFileObject;
  3461. StreamObject = (PSTREAM_OBJECT) ParentFileObject->FsContext;
  3462. //
  3463. // show one more I/O pending & verify that we can actually do I/O.
  3464. //
  3465. Status = SCShowIoPending(DeviceObject->DeviceExtension, Irp);
  3466. if ( !NT_SUCCESS ( Status )) {
  3467. //
  3468. // the device is currently not accessible, so just return with error
  3469. //
  3470. DebugPrint((DebugLevelError,"exiting AllocatorDispatchCreate-REMOVED\n"));
  3471. return (Status);
  3472. }
  3473. //
  3474. // if allocator is not needed for this stream, just fail the call.
  3475. //
  3476. if (!StreamObject->HwStreamObject.Allocator) {
  3477. DebugPrint((DebugLevelTrace,"exiting AllocatorDispatchCreate-not implemented\n"));
  3478. return SCCompleteIrp(Irp,
  3479. STATUS_NOT_IMPLEMENTED,
  3480. DeviceObject->DeviceExtension);
  3481. }
  3482. DebugPrint((DebugLevelTrace,"exiting AllocatorDispatchCreate-complete\n"));
  3483. return SCCompleteIrp(Irp,
  3484. KsCreateDefaultAllocator(Irp),
  3485. DeviceObject->DeviceExtension);
  3486. }
  3487. NTSTATUS
  3488. SCOpenMasterCallback(
  3489. IN PSTREAM_REQUEST_BLOCK SRB
  3490. )
  3491. /*++
  3492. Routine Description:
  3493. Process the completion of a master clock open.
  3494. Arguments:
  3495. SRB - address of the completed SRB
  3496. Return Value:
  3497. None.
  3498. --*/
  3499. {
  3500. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  3501. SRB->HwSRB.StreamObject,
  3502. STREAM_OBJECT,
  3503. HwStreamObject
  3504. );
  3505. PIRP Irp = SRB->HwSRB.Irp;
  3506. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3507. PAGED_CODE();
  3508. // log 'oMC ', StreamObject, DevExt, Status
  3509. SCLOG( ' CMo', StreamObject, StreamObject->DeviceExtension, SRB->HwSRB.Status);
  3510. if (!NT_SUCCESS(SRB->HwSRB.Status)) {
  3511. //
  3512. // if we could not set the master, free the clock handle and zero
  3513. // the link to the clock.
  3514. //
  3515. ExFreePool(StreamObject->ClockInstance);
  3516. StreamObject->ClockInstance = NULL;
  3517. } else { // if status success
  3518. //
  3519. // reference the pin handle so we won't be called to close the pin
  3520. // before the clock is closed
  3521. //
  3522. ObReferenceObject(IrpStack->FileObject->RelatedFileObject);
  3523. } // if status success
  3524. //
  3525. // complete the SRB
  3526. //
  3527. return (SCProcessCompletedRequest(SRB));
  3528. }
  3529. NTSTATUS
  3530. SCGetMasterClock(
  3531. IN PIRP Irp,
  3532. IN PKSPROPERTY Property,
  3533. IN OUT PHANDLE ClockHandle
  3534. )
  3535. {
  3536. //
  3537. // WorkWork - for now do nothing.
  3538. //
  3539. PAGED_CODE();
  3540. return (STATUS_NOT_SUPPORTED);
  3541. }
  3542. VOID
  3543. SciSetMasterClockInfo(
  3544. IN PSTREAM_OBJECT pStreamObject,
  3545. IN PMASTER_CLOCK_INFO pMasterClockInfo )
  3546. /*++
  3547. Decription:
  3548. This function simply set the new masterclock info for the stream
  3549. with LockUseMasterClock hold. Because of taking a spinlock we need
  3550. this function in lock memory. This function is intended to be called
  3551. by SCSetMasterClockOnly. pStreamObject is assumed valid.
  3552. Parameters:
  3553. pStreamObject: the target stream object to set to the new MasterCLockInfo
  3554. pMasterClockInfo: the new master clock info.
  3555. Return: None.
  3556. --*/
  3557. {
  3558. KIRQL SavedIrql;
  3559. KeAcquireSpinLock( &pStreamObject->LockUseMasterClock, &SavedIrql );
  3560. pStreamObject->MasterClockInfo = pMasterClockInfo;
  3561. KeReleaseSpinLock( &pStreamObject->LockUseMasterClock, SavedIrql );
  3562. return;
  3563. }
  3564. NTSTATUS
  3565. SCSetMasterClock(
  3566. IN PIRP Irp,
  3567. IN PKSPROPERTY Property,
  3568. IN PHANDLE ClockHandle
  3569. )
  3570. /*++
  3571. Description:
  3572. This is a Set property on a the stream. The request may be setting to
  3573. NULL CLockHandle which indicates master clock is revoked. If ClockHandle
  3574. is non-NULL, it is a new Master clock chosen by the graph manager.
  3575. Parameters:
  3576. Irp: the IO request packet to Set the master clock.
  3577. Property: the Set Master clock property
  3578. ClockHanlde: the handle of the clock designated as the new master clcok.
  3579. Return:
  3580. NTSTAUS: depending on the result of processing the request.
  3581. Comments:
  3582. This function must be called at IRQL < DISPATCH_LEVEL
  3583. --*/
  3584. {
  3585. NTSTATUS Status;
  3586. PIO_STACK_LOCATION IrpStack;
  3587. PSTREAM_OBJECT StreamObject;
  3588. KSPROPERTY FuncProperty;
  3589. PMASTER_CLOCK_INFO NewMasterClockInfo=NULL; //prefixbug 17396
  3590. PMASTER_CLOCK_INFO OldMasterClockInfo;
  3591. ULONG BytesReturned;
  3592. PFILE_OBJECT ClockFileObject = NULL;
  3593. BOOLEAN RequestIssued=FALSE;
  3594. PAGED_CODE();
  3595. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3596. StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  3597. //
  3598. // This function can be called from multiple threads. We will serialize
  3599. // this function on the Stream to protect against concurrent accesses.
  3600. //
  3601. KeWaitForSingleObject(&StreamObject->ControlSetMasterClock,
  3602. Executive,
  3603. KernelMode,
  3604. FALSE,// not alertable
  3605. NULL);
  3606. //
  3607. // N.B.
  3608. //
  3609. // If our clock is open, we are potentially the master clock. But this
  3610. // is not guaranteed. Ksproxy opens our clock in attempt to use it as
  3611. // the master clock. But it can change its mind to choose another clock,
  3612. // while keeping our clock open.
  3613. //
  3614. //
  3615. // log 'sMC ', StreamObject, MasterClockInfo, *ClockHandle )
  3616. //
  3617. SCLOG( ' CMs', StreamObject, StreamObject->MasterClockInfo, *ClockHandle );
  3618. /*
  3619. Not so soon. We have not told mini drivers the new master clock yet.
  3620. Mini drivers might think they still have the retiring Master clock and
  3621. can query the clock in the mean time. We would crash on accessing NULL
  3622. MasterClockInfo. We should not nullify it before we notify the mini
  3623. driver first.
  3624. if (StreamObject->MasterClockInfo) {
  3625. ObDereferenceObject(StreamObject->MasterClockInfo->ClockFileObject);
  3626. ExFreePool(StreamObject->MasterClockInfo);
  3627. StreamObject->MasterClockInfo = NULL;
  3628. }
  3629. */
  3630. OldMasterClockInfo = StreamObject->MasterClockInfo;
  3631. //
  3632. // if there is a clock, reference it. If not, we'll send down a null handle.
  3633. //
  3634. if (*ClockHandle) {
  3635. //
  3636. // alloc a structure to represent the master clock
  3637. //
  3638. NewMasterClockInfo = ExAllocatePool(NonPagedPool, sizeof(MASTER_CLOCK_INFO));
  3639. if (!NewMasterClockInfo) {
  3640. Status = STATUS_INSUFFICIENT_RESOURCES;
  3641. goto exit;
  3642. }
  3643. //
  3644. // This is too early to assign. We have not setup MasterClockInfo yet.
  3645. //
  3646. // StreamObject->MasterClockInfo = MasterClockInfo;
  3647. //
  3648. // reference the clock handle, thereby getting the file object for it.
  3649. //
  3650. if (!NT_SUCCESS((Status = ObReferenceObjectByHandle(*ClockHandle,
  3651. FILE_READ_ACCESS | SYNCHRONIZE,
  3652. *IoFileObjectType,
  3653. Irp->RequestorMode,
  3654. &ClockFileObject,
  3655. NULL
  3656. )))) {
  3657. ExFreePool(NewMasterClockInfo);
  3658. NewMasterClockInfo = NULL;
  3659. goto exit;
  3660. } // if Ob succeeded
  3661. NewMasterClockInfo->ClockFileObject = ClockFileObject;
  3662. // check master clock
  3663. #if 0
  3664. {
  3665. if ( StreamObject->ClockInstance ) {
  3666. //
  3667. // we are chosen the master clock
  3668. //
  3669. DebugPrint((DebugLevelInfo,
  3670. "--------ClockInstance=%x, FileObject=%x "
  3671. "Indicated ClockFileObject=%x context=%x\n",
  3672. StreamObject->ClockInstance,
  3673. StreamObject->ClockInstance->ParentFileObject,
  3674. ClockFileObject,
  3675. ClockFileObject->FsContext));
  3676. }
  3677. else {
  3678. DebugPrint((DebugLevelInfo,
  3679. "--------Indicated ClockFileObject=%x context=%x\n",
  3680. ClockFileObject,
  3681. ClockFileObject->FsContext));
  3682. }
  3683. }
  3684. #endif
  3685. //
  3686. // issue the IOCtl to get the function table of the master clock.
  3687. //
  3688. FuncProperty.Id = KSPROPERTY_CLOCK_FUNCTIONTABLE;
  3689. FuncProperty.Flags = KSPROPERTY_TYPE_GET;
  3690. RtlMoveMemory(&FuncProperty.Set, &KSPROPSETID_Clock, sizeof(GUID));
  3691. if (!NT_SUCCESS((Status = KsSynchronousIoControlDevice(
  3692. ClockFileObject,
  3693. KernelMode,
  3694. IOCTL_KS_PROPERTY,
  3695. &FuncProperty,
  3696. sizeof(KSPROPERTY),
  3697. &NewMasterClockInfo->FunctionTable,
  3698. sizeof(KSCLOCK_FUNCTIONTABLE),
  3699. &BytesReturned)))) {
  3700. ObDereferenceObject(NewMasterClockInfo->ClockFileObject);
  3701. ExFreePool(NewMasterClockInfo);
  3702. NewMasterClockInfo = NULL;
  3703. goto exit;
  3704. }
  3705. } // if *ClockHandle
  3706. //
  3707. // call the minidriver to indicate the master clock.
  3708. //
  3709. if ( NULL != NewMasterClockInfo ) {
  3710. //
  3711. // but first, let's put in the MasterClockInfo. When mini driver
  3712. // gets notified with the masterclock, it could fire GetTime right away
  3713. // before the notification returns. Get ready to deal with it. This is
  3714. // critical if oldMasterClockInfo is NULL. Not much so otherwise.
  3715. //
  3716. //
  3717. // Make sure no one is querying master clock when setting the new clock info.
  3718. //
  3719. SciSetMasterClockInfo( StreamObject, NewMasterClockInfo );
  3720. }
  3721. Status = SCSubmitRequest(SRB_INDICATE_MASTER_CLOCK,
  3722. ClockFileObject,
  3723. 0,
  3724. SCDequeueAndDeleteSrb,
  3725. StreamObject->DeviceExtension,
  3726. StreamObject->FilterInstance->HwInstanceExtension,
  3727. &StreamObject->HwStreamObject,
  3728. Irp,
  3729. &RequestIssued,
  3730. &StreamObject->ControlPendingQueue,
  3731. (PVOID) StreamObject->HwStreamObject.
  3732. ReceiveControlPacket);
  3733. ASSERT( RequestIssued );
  3734. ASSERT( NT_SUCCESS( Status ) );
  3735. //
  3736. // SCSubmitRequest is a synch call. When we return here, We can finish our work
  3737. // based on the Status code.
  3738. //
  3739. if ( NT_SUCCESS( Status )) {
  3740. //
  3741. // Everything is cool. Finish up. The assignment is redundent if
  3742. // NewMasterClockInfo is not NULL. Better assign unconditionally than check.
  3743. //
  3744. //
  3745. // Make sure no one is querying master clock when updating MasterClockInfo
  3746. //
  3747. SciSetMasterClockInfo( StreamObject, NewMasterClockInfo );
  3748. if (NULL != OldMasterClockInfo) {
  3749. ObDereferenceObject(OldMasterClockInfo->ClockFileObject);
  3750. ExFreePool(OldMasterClockInfo);
  3751. }
  3752. } else {
  3753. //
  3754. // Failed to tell mini driver the new clock. Clean up shop. But don't update
  3755. // StreamObject->MasterClockInfo. Keep the status quo.
  3756. //
  3757. //
  3758. // Make sure no one is querying master clock when updateing MasterClockInfo.
  3759. //
  3760. SciSetMasterClockInfo( StreamObject, OldMasterClockInfo );
  3761. if (NewMasterClockInfo) {
  3762. ObDereferenceObject(ClockFileObject);
  3763. ExFreePool(NewMasterClockInfo);
  3764. }
  3765. }
  3766. exit:
  3767. KeSetEvent(&StreamObject->ControlSetMasterClock, IO_NO_INCREMENT, FALSE);
  3768. return (Status);
  3769. }
  3770. NTSTATUS
  3771. SCClockGetTime(
  3772. IN PIRP Irp,
  3773. IN PKSPROPERTY Property,
  3774. IN OUT PULONGLONG StreamTime
  3775. )
  3776. {
  3777. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3778. PCLOCK_INSTANCE ClockInstance =
  3779. (PCLOCK_INSTANCE) IrpStack->FileObject->FsContext;
  3780. PSTREAM_OBJECT StreamObject = ClockInstance->ParentFileObject->FsContext;
  3781. PAGED_CODE();
  3782. if (StreamObject->HwStreamObject.HwClockObject.ClockSupportFlags &
  3783. CLOCK_SUPPORT_CAN_RETURN_STREAM_TIME) {
  3784. *StreamTime = SCGetStreamTime(IrpStack->FileObject);
  3785. Irp->IoStatus.Information = sizeof(ULONGLONG);
  3786. return STATUS_SUCCESS;
  3787. } else {
  3788. return (STATUS_NOT_SUPPORTED);
  3789. }
  3790. }
  3791. NTSTATUS
  3792. SCClockGetPhysicalTime(
  3793. IN PIRP Irp,
  3794. IN PKSPROPERTY Property,
  3795. IN OUT PULONGLONG PhysicalTime
  3796. )
  3797. {
  3798. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3799. PCLOCK_INSTANCE ClockInstance =
  3800. (PCLOCK_INSTANCE) IrpStack->FileObject->FsContext;
  3801. PSTREAM_OBJECT StreamObject = ClockInstance->ParentFileObject->FsContext;
  3802. PAGED_CODE();
  3803. if (StreamObject->HwStreamObject.HwClockObject.ClockSupportFlags &
  3804. CLOCK_SUPPORT_CAN_READ_ONBOARD_CLOCK) {
  3805. *PhysicalTime = SCGetPhysicalTime(IrpStack->FileObject->FsContext);
  3806. Irp->IoStatus.Information = sizeof(ULONGLONG);
  3807. return (STATUS_SUCCESS);
  3808. } else {
  3809. return (STATUS_NOT_SUPPORTED);
  3810. }
  3811. }
  3812. NTSTATUS
  3813. SCClockGetSynchronizedTime(
  3814. IN PIRP Irp,
  3815. IN PKSPROPERTY Property,
  3816. IN OUT PKSCORRELATED_TIME SyncTime
  3817. )
  3818. {
  3819. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3820. PCLOCK_INSTANCE ClockInstance =
  3821. (PCLOCK_INSTANCE) IrpStack->FileObject->FsContext;
  3822. PSTREAM_OBJECT StreamObject = ClockInstance->ParentFileObject->FsContext;
  3823. PAGED_CODE();
  3824. if (StreamObject->HwStreamObject.HwClockObject.ClockSupportFlags &
  3825. CLOCK_SUPPORT_CAN_RETURN_STREAM_TIME) {
  3826. SyncTime->Time = SCGetSynchronizedTime(IrpStack->FileObject,
  3827. &SyncTime->SystemTime);
  3828. Irp->IoStatus.Information = sizeof(KSCORRELATED_TIME);
  3829. return (STATUS_SUCCESS);
  3830. } else {
  3831. return (STATUS_NOT_SUPPORTED);
  3832. }
  3833. }
  3834. NTSTATUS
  3835. SCClockGetFunctionTable(
  3836. IN PIRP Irp,
  3837. IN PKSPROPERTY Property,
  3838. IN OUT PKSCLOCK_FUNCTIONTABLE FunctionTable
  3839. )
  3840. {
  3841. PCLOCK_INSTANCE ClockInstance;
  3842. PIO_STACK_LOCATION IrpStack;
  3843. PSTREAM_OBJECT StreamObject;
  3844. PAGED_CODE();
  3845. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3846. ClockInstance = (PCLOCK_INSTANCE) IrpStack->FileObject->FsContext;
  3847. StreamObject = ClockInstance->ParentFileObject->FsContext;
  3848. RtlZeroMemory(FunctionTable, sizeof(KSCLOCK_FUNCTIONTABLE));
  3849. if (StreamObject->HwStreamObject.HwClockObject.ClockSupportFlags &
  3850. CLOCK_SUPPORT_CAN_RETURN_STREAM_TIME) {
  3851. FunctionTable->GetTime = (PFNKSCLOCK_GETTIME) SCGetStreamTime;
  3852. FunctionTable->GetCorrelatedTime = (PFNKSCLOCK_CORRELATEDTIME) SCGetSynchronizedTime;
  3853. }
  3854. if (StreamObject->HwStreamObject.HwClockObject.ClockSupportFlags &
  3855. CLOCK_SUPPORT_CAN_READ_ONBOARD_CLOCK) {
  3856. FunctionTable->GetPhysicalTime = (PFNKSCLOCK_GETTIME) SCGetPhysicalTime;
  3857. }
  3858. Irp->IoStatus.Information = sizeof(KSCLOCK_FUNCTIONTABLE);
  3859. return STATUS_SUCCESS;
  3860. }
  3861. NTSTATUS
  3862. ClockDispatchClose
  3863. (
  3864. IN PDEVICE_OBJECT DeviceObject,
  3865. IN PIRP Irp
  3866. )
  3867. /*++
  3868. Routine Description:
  3869. This routine receives CLOSE IRP's for a stream
  3870. Arguments:
  3871. DeviceObject - device object for the device
  3872. Irp - probably an IRP, silly
  3873. Return Value:
  3874. The IRP status is set as appropriate
  3875. --*/
  3876. {
  3877. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3878. PDEVICE_EXTENSION DeviceExtension =
  3879. (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  3880. NTSTATUS Status;
  3881. BOOLEAN RequestIssued;
  3882. PCLOCK_INSTANCE ClockInstance = (PCLOCK_INSTANCE)
  3883. IrpStack->FileObject->FsContext;
  3884. PSTREAM_OBJECT StreamObject = ClockInstance->StreamObject;
  3885. PAGED_CODE();
  3886. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  3887. //
  3888. // call the minidriver to indicate that there is no master clock.
  3889. // processing will continue when the callback procedure is called.
  3890. //
  3891. Status = SCSubmitRequest(SRB_CLOSE_MASTER_CLOCK,
  3892. NULL,
  3893. 0,
  3894. SCCloseClockCallback,
  3895. DeviceExtension,
  3896. StreamObject->FilterInstance->HwInstanceExtension,
  3897. &StreamObject->HwStreamObject,
  3898. Irp,
  3899. &RequestIssued,
  3900. &StreamObject->ControlPendingQueue,
  3901. (PVOID) StreamObject->HwStreamObject.
  3902. ReceiveControlPacket
  3903. );
  3904. if (!RequestIssued) {
  3905. DEBUG_BREAKPOINT();
  3906. SCCompleteIrp(Irp, Status, DeviceExtension);
  3907. }
  3908. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  3909. return (Status);
  3910. }
  3911. NTSTATUS
  3912. SCCloseClockCallback(
  3913. IN PSTREAM_REQUEST_BLOCK SRB
  3914. )
  3915. /*++
  3916. Routine Description:
  3917. Process the completion of a stream close.
  3918. Arguments:
  3919. SRB - address of the completed SRB
  3920. Return Value:
  3921. None.
  3922. --*/
  3923. {
  3924. PDEVICE_EXTENSION DeviceExtension =
  3925. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  3926. PSTREAM_OBJECT StreamObject = CONTAINING_RECORD(
  3927. SRB->HwSRB.StreamObject,
  3928. STREAM_OBJECT,
  3929. HwStreamObject
  3930. );
  3931. PIRP Irp = SRB->HwSRB.Irp;
  3932. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3933. NTSTATUS Status = SRB->HwSRB.Status;
  3934. PCLOCK_INSTANCE ClockInstance;
  3935. PAGED_CODE();
  3936. // log 'cMC ', StreamObject, ClockInstance, Status )
  3937. SCLOG( ' CMc', StreamObject, IrpStack->FileObject->FsContext, Status );
  3938. if (NT_SUCCESS(Status)) {
  3939. //
  3940. // free the clock instance structure and the object header
  3941. //
  3942. ClockInstance =
  3943. (PCLOCK_INSTANCE) IrpStack->FileObject->FsContext;
  3944. KsFreeObjectHeader(ClockInstance->DeviceHeader);
  3945. ExFreePool(ClockInstance);
  3946. StreamObject->ClockInstance = NULL;
  3947. //
  3948. // dereference the pin handle
  3949. //
  3950. ObDereferenceObject(IrpStack->FileObject->RelatedFileObject);
  3951. } // if good status
  3952. SCProcessCompletedRequest(SRB);
  3953. return (Status);
  3954. }
  3955. NTSTATUS
  3956. SCFilterTopologyHandler(
  3957. IN PIRP Irp,
  3958. IN PKSPROPERTY Property,
  3959. IN OUT PVOID Data)
  3960. /*++
  3961. Routine Description:
  3962. Dispatches a pin property request
  3963. Arguments:
  3964. Irp - pointer to the irp
  3965. Property - pointer to the property info
  3966. Data - property specific buffer
  3967. Return Value:
  3968. NTSTATUS returned as appropriate
  3969. --*/
  3970. {
  3971. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3972. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) IrpStack->
  3973. DeviceObject->DeviceExtension;
  3974. PAGED_CODE();
  3975. IFN_MF(
  3976. return KsTopologyPropertyHandler(Irp,
  3977. Property,
  3978. Data,
  3979. DeviceExtension->StreamDescriptor->StreamHeader.Topology
  3980. );
  3981. )
  3982. IF_MFS(
  3983. PFILTER_INSTANCE FilterInstance;
  3984. FilterInstance = (PFILTER_INSTANCE) IrpStack->FileObject->FsContext;
  3985. return KsTopologyPropertyHandler(
  3986. Irp,
  3987. Property,
  3988. Data,
  3989. FilterInstance->StreamDescriptor->StreamHeader.Topology);
  3990. )
  3991. }
  3992. NTSTATUS
  3993. SCFilterPinIntersectionHandler(
  3994. IN PIRP Irp,
  3995. IN PKSP_PIN Pin,
  3996. OUT PVOID Data
  3997. )
  3998. /*++
  3999. Routine Description:
  4000. Handles the KSPROPERTY_PIN_DATAINTERSECTION property in the Pin property set.
  4001. Returns the first acceptable data format given a list of data ranges for a specified
  4002. Pin factory. Actually just calls the Intersection Enumeration helper, which then
  4003. calls the IntersectHandler callback with each data range.
  4004. Arguments:
  4005. Irp -
  4006. Device control Irp.
  4007. Pin -
  4008. Specific property request followed by Pin factory identifier, followed by a
  4009. KSMULTIPLE_ITEM structure. This is followed by zero or more data range structures.
  4010. Data -
  4011. The place in which to return the data format selected as the first intersection
  4012. between the list of data ranges passed, and the acceptable formats.
  4013. Return Values:
  4014. returns STATUS_SUCCESS or STATUS_NO_MATCH, else STATUS_INVALID_PARAMETER,
  4015. STATUS_BUFFER_TOO_SMALL, or STATUS_INVALID_BUFFER_SIZE.
  4016. --*/
  4017. {
  4018. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  4019. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) IrpStack->
  4020. DeviceObject->DeviceExtension;
  4021. PAGED_CODE();
  4022. IFN_MF(
  4023. return KsPinDataIntersection(
  4024. Irp,
  4025. Pin,
  4026. Data,
  4027. DeviceExtension->NumberOfPins,
  4028. DeviceExtension->PinInformation,
  4029. SCIntersectHandler);
  4030. )
  4031. IF_MFS(
  4032. PSTREAM_OBJECT StreamObject;
  4033. PFILTER_INSTANCE FilterInstance;
  4034. FilterInstance = (PFILTER_INSTANCE) IrpStack->FileObject->FsContext;
  4035. DebugPrint((DebugLevelVerbose,
  4036. "PinIntersection FilterInstance=%p\n", FilterInstance ));
  4037. return KsPinDataIntersection(
  4038. Irp,
  4039. Pin,
  4040. Data,
  4041. FilterInstance->NumberOfPins,
  4042. FilterInstance->PinInformation,
  4043. SCIntersectHandler);
  4044. )
  4045. }
  4046. NTSTATUS
  4047. SCIntersectHandler(
  4048. IN PIRP Irp,
  4049. IN PKSP_PIN Pin,
  4050. IN PKSDATARANGE DataRange,
  4051. OUT PVOID Data
  4052. )
  4053. /*++
  4054. Routine Description:
  4055. This is the data range callback for KsPinDataIntersection, which is called by
  4056. FilterPinIntersection to enumerate the given list of data ranges, looking for
  4057. an acceptable match. If a data range is acceptable, a data format is copied
  4058. into the return buffer. If there is a wave format selected in a current pin
  4059. connection, and it is contained within the data range passed in, it is chosen
  4060. as the data format to return. A STATUS_NO_MATCH continues the enumeration.
  4061. Arguments:
  4062. Irp -
  4063. Device control Irp.
  4064. Pin -
  4065. Specific property request followed by Pin factory identifier, followed by a
  4066. KSMULTIPLE_ITEM structure. This is followed by zero or more data range structures.
  4067. This enumeration callback does not need to look at any of this though. It need
  4068. only look at the specific pin identifier.
  4069. DataRange -
  4070. Contains a specific data range to validate.
  4071. Data -
  4072. The place in which to return the data format selected as the first intersection
  4073. between the list of data ranges passed, and the acceptable formats.
  4074. Return Values:
  4075. returns STATUS_SUCCESS or STATUS_NO_MATCH, else STATUS_INVALID_PARAMETER,
  4076. STATUS_BUFFER_TOO_SMALL, or STATUS_INVALID_BUFFER_SIZE.
  4077. --*/
  4078. {
  4079. PIO_STACK_LOCATION IrpStack;
  4080. NTSTATUS Status;
  4081. PFILTER_INSTANCE FilterInstance;
  4082. STREAM_DATA_INTERSECT_INFO IntersectInfo;
  4083. PDEVICE_EXTENSION DeviceExtension;
  4084. BOOLEAN RequestIssued;
  4085. PAGED_CODE();
  4086. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  4087. FilterInstance = (PFILTER_INSTANCE) IrpStack->FileObject->FsContext;
  4088. DeviceExtension = (PDEVICE_EXTENSION)
  4089. IrpStack->DeviceObject->DeviceExtension;
  4090. ASSERT_FILTER_INSTANCE( FilterInstance );
  4091. ASSERT_DEVICE_EXTENSION( DeviceExtension );
  4092. //
  4093. // fill in the intersect info struct from the input params.
  4094. //
  4095. IntersectInfo.DataRange = DataRange;
  4096. IntersectInfo.DataFormatBuffer = Data;
  4097. IntersectInfo.SizeOfDataFormatBuffer =
  4098. IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  4099. IntersectInfo.StreamNumber = Pin->PinId;
  4100. //
  4101. // call the minidriver to process the intersection. processing will
  4102. // continue
  4103. // when the callback procedure is called. take the event to ensure that
  4104. // pins don't come and go as we process the intersection.
  4105. //
  4106. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  4107. Executive,
  4108. KernelMode,
  4109. FALSE,// not alertable
  4110. NULL);
  4111. Status = SCSubmitRequest(SRB_GET_DATA_INTERSECTION,
  4112. &IntersectInfo,
  4113. 0,
  4114. SCDataIntersectionCallback,
  4115. DeviceExtension,
  4116. FilterInstance->HwInstanceExtension,
  4117. NULL,
  4118. Irp,
  4119. &RequestIssued,
  4120. &DeviceExtension->PendingQueue,
  4121. (PVOID) DeviceExtension->
  4122. MinidriverData->HwInitData.
  4123. HwReceivePacket);
  4124. if (!RequestIssued) {
  4125. DEBUG_BREAKPOINT();
  4126. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  4127. }
  4128. return Status;
  4129. }
  4130. NTSTATUS
  4131. SCDataIntersectionCallback(
  4132. IN PSTREAM_REQUEST_BLOCK SRB
  4133. )
  4134. /*++
  4135. Routine Description:
  4136. Process the completion of a data intersection query.
  4137. Arguments:
  4138. SRB - address of the completed SRB
  4139. Return Value:
  4140. None.
  4141. --*/
  4142. {
  4143. PDEVICE_EXTENSION DeviceExtension =
  4144. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  4145. PIRP Irp = SRB->HwSRB.Irp;
  4146. NTSTATUS Status = SRB->HwSRB.Status;
  4147. PAGED_CODE();
  4148. Irp->IoStatus.Information = SRB->HwSRB.ActualBytesTransferred;
  4149. //
  4150. // signal the event
  4151. //
  4152. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  4153. SCDequeueAndDeleteSrb(SRB);
  4154. return (Status);
  4155. }
  4156. NTSTATUS
  4157. SCGetStreamHeaderSize(
  4158. IN PIRP Irp,
  4159. IN PKSPROPERTY Property,
  4160. IN OUT PULONG StreamHeaderSize
  4161. )
  4162. /*++
  4163. Routine Description:
  4164. Process the get stream header extension property
  4165. Arguments:
  4166. Return Value:
  4167. None.
  4168. --*/
  4169. {
  4170. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  4171. PSTREAM_OBJECT StreamObject = (PSTREAM_OBJECT) IrpStack->FileObject->FsContext;
  4172. PAGED_CODE();
  4173. ASSERT(StreamObject);
  4174. *StreamHeaderSize = StreamObject->HwStreamObject.StreamHeaderMediaSpecific;
  4175. Irp->IoStatus.Information = sizeof(ULONG);
  4176. return (STATUS_SUCCESS);
  4177. }
  4178. NTSTATUS
  4179. DllUnload(
  4180. VOID
  4181. )
  4182. {
  4183. NTSTATUS Status=STATUS_SUCCESS;
  4184. #if DBG
  4185. NTSTATUS DbgDllUnload();
  4186. DebugPrint((1, "Stream Class DllUnload: Unloading\n"));
  4187. Status = DbgDllUnload();
  4188. #endif
  4189. return Status;
  4190. }
  4191. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  4192. //---------------------------------------------------------------------------
  4193. //---------------------------------------------------------------------------
  4194. NTSTATUS
  4195. SCStreamAllocator(
  4196. IN PIRP Irp,
  4197. IN PKSPROPERTY Property,
  4198. IN OUT PHANDLE AllocatorHandle
  4199. )
  4200. /*++
  4201. Routine Description:
  4202. If KSPROPERTY_TYPE_SET, this function sets the stream allocator
  4203. for this connection by referencing the file handle to obtain
  4204. the file object pointer and stores this pointer in the filter(stream?)
  4205. instance structure.
  4206. Otherwise, a KSPROPERTY_TYPE_GET request returns a NULL handle
  4207. and STATUS_SUCCESS to show that we support allocator creation.
  4208. Arguments:
  4209. IN PIRP Irp -
  4210. pointer to the I/O request packet
  4211. IN PKSPROPERTY Property -
  4212. pointer to the property structure
  4213. IN OUT PHANDLE AllocatorHandle -
  4214. pointer to the handle representing the file object
  4215. Return:
  4216. STATUS_SUCCESS or an appropriate error code
  4217. --*/
  4218. {
  4219. NTSTATUS Status;
  4220. PIO_STACK_LOCATION IrpStack;
  4221. PSTREAM_OBJECT StreamObject;
  4222. PDEVICE_EXTENSION DeviceExtension;
  4223. IrpStack = IoGetCurrentIrpStackLocation( Irp );
  4224. StreamObject = IrpStack->FileObject->FsContext;
  4225. DebugPrint((DebugLevelTrace, "STREAM:entering SCStreamAllocator:Stream:%x\n",StreamObject));
  4226. if (Property->Flags & KSPROPERTY_TYPE_GET) {
  4227. //
  4228. // This is a query to see if we support the creation of
  4229. // allocators. The returned handle is always NULL, but we
  4230. // signal that we support the creation of allocators by
  4231. // returning STATUS_SUCCESS.
  4232. //
  4233. *AllocatorHandle = NULL;
  4234. Status = STATUS_SUCCESS;
  4235. DebugPrint((DebugLevelTrace,"SCStreamAllocator-GET"));
  4236. } else {
  4237. PFILTER_INSTANCE FilterInstance;
  4238. FilterInstance =
  4239. (PFILTER_INSTANCE) StreamObject->FilterFileObject->FsContext;
  4240. DeviceExtension = StreamObject->DeviceExtension;
  4241. DebugPrint((DebugLevelTrace,"SCStreamAllocator-SET"));
  4242. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  4243. Executive,
  4244. KernelMode,
  4245. FALSE,// not alertable
  4246. NULL);
  4247. //
  4248. // The allocator can only be specified when the device is
  4249. // in KSSTATE_STOP.
  4250. //
  4251. if (StreamObject->CurrentState != KSSTATE_STOP) {
  4252. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  4253. DebugPrint((DebugLevelTrace,"SCStreamAllocator-device not in STOP"));
  4254. return STATUS_INVALID_DEVICE_STATE;
  4255. }
  4256. // if we are in _STOP, the flush was already done.
  4257. // this call may have to be enabled.
  4258. //
  4259. // StreamFlushIo(DeviceExtension, StreamObject);
  4260. //
  4261. // Release the previous allocator, if any.
  4262. //
  4263. if (StreamObject->AllocatorFileObject) {
  4264. ObDereferenceObject( StreamObject->AllocatorFileObject );
  4265. StreamObject->AllocatorFileObject = NULL;
  4266. }
  4267. //
  4268. // Reference this handle and store the resultant pointer
  4269. // in the filter instance. Note that the default allocator
  4270. // does not ObReferenceObject() for its parent
  4271. // (which would be the pin handle). If it did reference
  4272. // the pin handle, we could never close this pin as there
  4273. // would always be a reference to the pin file object held
  4274. // by the allocator and the pin object has a reference to the
  4275. // allocator file object.
  4276. //
  4277. if (*AllocatorHandle != NULL) {
  4278. Status =
  4279. ObReferenceObjectByHandle(
  4280. *AllocatorHandle,
  4281. FILE_READ_DATA | SYNCHRONIZE,
  4282. *IoFileObjectType,
  4283. ExGetPreviousMode(),
  4284. &StreamObject->AllocatorFileObject,
  4285. NULL );
  4286. DebugPrint((DebugLevelTrace, "SCStreamAllocator: got %x as Allocator file object\n",StreamObject->AllocatorFileObject));
  4287. } else {
  4288. Status = STATUS_SUCCESS;
  4289. }
  4290. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  4291. }
  4292. DebugPrint((DebugLevelTrace,"exiting SCStreamAllocator-normal path\n"));
  4293. return Status;
  4294. }
  4295. //---------------------------------------------------------------------------
  4296. BOOLEAN
  4297. HeaderTransfer(
  4298. IN PFILTER_INSTANCE FilterInstance,
  4299. IN PSTREAM_OBJECT StreamObject,
  4300. IN PFILE_OBJECT DestinationFileObject,
  4301. IN OUT PSTREAM_HEADER_EX *StreamHeader
  4302. )
  4303. /*++
  4304. Routine Description:
  4305. Sets up the stream header for a no-copy transfer to the
  4306. opposite pin.
  4307. Arguments:
  4308. IN PFILTER_INSTANCE FilterInstance -
  4309. pointer to the filter instance
  4310. IN PSTREAM_OBJECT StreamObject -
  4311. pointer to the transform instance structure
  4312. IN PSTREAM_OBJECT DestinationInstance -
  4313. pointer to the opposite transform instance structure
  4314. IN OUT PSTREAM_HEADER_EX *StreamHeader -
  4315. pointer containing a pointer to the current stream header,
  4316. this member is updated with a pointer to the next stream
  4317. header to submit to the opposite pin or NULL if there is
  4318. no header to submit.
  4319. Return:
  4320. An indication of whether stop can proceed now or not
  4321. Comments:
  4322. Not pageable, uses SpinLocks.
  4323. --*/
  4324. {
  4325. KIRQL irqlQueue, irqlFree;
  4326. ULONG WhichQueue = (*StreamHeader)->WhichQueue;
  4327. ULONG OppositeQueue = WhichQueue ^ 0x00000001; // 1 to 0, 0 to 1
  4328. BOOLEAN SignalStop = FALSE;
  4329. ASSERT(DestinationFileObject);
  4330. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  4331. if (StreamObject->PinState > PinStopPending) { // if normal running case
  4332. //
  4333. // If we are here after submitting an ENDOFSTREAM Irp to the
  4334. // outflow pin, then we have already read the end of stream
  4335. // from the input and there is no need to continue I/O.
  4336. //
  4337. if (DestinationFileObject) {
  4338. ULONG HeaderFlags = (*StreamHeader)->Header.OptionsFlags;
  4339. //
  4340. // Clear the options flags so that we continue
  4341. // reading from where we left off.
  4342. //
  4343. // (*StreamHeader)->Header.OptionsFlags = 0;
  4344. //
  4345. // Reset the stream segment valid data length
  4346. //
  4347. // (*StreamHeader)->Header.DataUsed = 0;
  4348. // (*StreamHeader)->Header.Duration = 0;
  4349. //
  4350. // Check for the end of the stream.
  4351. //
  4352. if ((HeaderFlags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM) ||
  4353. StreamObject->EndOfStream) {
  4354. DebugPrint((DebugLevelTrace,
  4355. "end of stream") );
  4356. //
  4357. // Make sure that this is set for the next time through.
  4358. //
  4359. StreamObject->EndOfStream = TRUE;
  4360. if (!(*StreamHeader)->ReferenceCount) {
  4361. //
  4362. // Put the header back on the free list of the inflow pin.
  4363. //
  4364. KeAcquireSpinLock( &StreamObject->FreeQueueLock, &irqlFree );
  4365. #if (DBG)
  4366. if ((*StreamHeader)->OnFreeList) {
  4367. DebugPrint((DebugLevelTrace,
  4368. "stream header already on free list.") );
  4369. }
  4370. #endif
  4371. DebugPrint((DebugLevelTrace,
  4372. "EOS adding %x to free queue", *StreamHeader) );
  4373. InsertTailList(
  4374. &StreamObject->FreeQueue,
  4375. &(*StreamHeader)->ListEntry );
  4376. if (!InterlockedDecrement (
  4377. &StreamObject -> QueuedFramesPlusOne
  4378. ))
  4379. SignalStop = TRUE;
  4380. #if (DBG)
  4381. (*StreamHeader)->OnFreeList = TRUE;
  4382. if ((*StreamHeader)->OnActiveList) {
  4383. DebugPrint((DebugLevelTrace,
  4384. "stream header on both lists.") );
  4385. }
  4386. #endif
  4387. KeReleaseSpinLock( &StreamObject->FreeQueueLock, irqlFree );
  4388. }
  4389. //
  4390. // No more I/O to opposite pin.
  4391. //
  4392. *StreamHeader = NULL;
  4393. }
  4394. }
  4395. //
  4396. // Grab the spin lock for the other queue, insert this
  4397. // stream header on the queue.
  4398. //
  4399. if (*StreamHeader) {
  4400. KeAcquireSpinLock( &StreamObject->Queues[OppositeQueue].QueueLock, &irqlQueue );
  4401. #if (DBG)
  4402. if ((*StreamHeader)->OnActiveList) {
  4403. DebugPrint((DebugLevelTrace,
  4404. "stream header already on active list.") );
  4405. }
  4406. #endif
  4407. InsertTailList(
  4408. &StreamObject->Queues[OppositeQueue].ActiveQueue,
  4409. &(*StreamHeader)->ListEntry );
  4410. #if (DBG)
  4411. (*StreamHeader)->OnActiveList = TRUE;
  4412. if ((*StreamHeader)->OnFreeList) {
  4413. DebugPrint((DebugLevelTrace,
  4414. "stream header on both lists.") );
  4415. }
  4416. #endif
  4417. KeReleaseSpinLock( &StreamObject->Queues[OppositeQueue].QueueLock, irqlQueue );
  4418. }
  4419. }
  4420. else // pin stop IS pending
  4421. {
  4422. //
  4423. // Location of frames (for this type of transfer, all frames
  4424. // are held on the source pin).
  4425. //
  4426. if (!(*StreamHeader)->ReferenceCount) {
  4427. DebugPrint((DebugLevelTrace,
  4428. "stop: adding %x to free queue.", *StreamHeader) );
  4429. KeAcquireSpinLock( &StreamObject->FreeQueueLock, &irqlFree );
  4430. #if (DBG)
  4431. if ((*StreamHeader)->OnFreeList) {
  4432. DebugPrint((DebugLevelTrace,
  4433. "stream header already on free list.") );
  4434. }
  4435. #endif
  4436. InsertTailList(
  4437. &StreamObject->FreeQueue, &(*StreamHeader)->ListEntry );
  4438. if (!InterlockedDecrement (&StreamObject -> QueuedFramesPlusOne))
  4439. SignalStop = TRUE;
  4440. #if (DBG)
  4441. (*StreamHeader)->OnFreeList = TRUE;
  4442. if ((*StreamHeader)->OnActiveList) {
  4443. DebugPrint((DebugLevelTrace,
  4444. "stream header on both lists.") );
  4445. }
  4446. #endif
  4447. KeReleaseSpinLock( &StreamObject->FreeQueueLock, irqlFree );
  4448. }
  4449. //
  4450. // No I/O to opposite pin this round.
  4451. //
  4452. *StreamHeader = NULL;
  4453. }
  4454. return SignalStop;
  4455. }
  4456. //---------------------------------------------------------------------------
  4457. VOID
  4458. IoWorker(
  4459. PVOID Context,
  4460. ULONG WhichQueue
  4461. )
  4462. /*++
  4463. Routine Description:
  4464. This is the work item for the source pins. Walks the queue
  4465. associated with the stream header looking for sequentially
  4466. completed headers and submits those headers to the opposite
  4467. pin.
  4468. Arguments:
  4469. PVOID Context -
  4470. pointer to the stream header
  4471. Return:
  4472. Nothing.
  4473. Comments:
  4474. Not pageable, uses SpinLocks.
  4475. --*/
  4476. {
  4477. KIRQL irqlOld;
  4478. PFILTER_INSTANCE FilterInstance;
  4479. PADDITIONAL_PIN_INFO AdditionalInfo;
  4480. PLIST_ENTRY Node;
  4481. PSTREAM_OBJECT StreamObject;
  4482. PFILE_OBJECT DestinationFileObject;
  4483. PSTREAM_HEADER_EX StreamHeader;
  4484. NTSTATUS Status;
  4485. ULONG Operation;
  4486. PDEVICE_EXTENSION DeviceExtension;
  4487. BOOLEAN SignalStop = FALSE;
  4488. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  4489. StreamObject = (PSTREAM_OBJECT) Context;
  4490. DeviceExtension = StreamObject->DeviceExtension;
  4491. #if (DBG)
  4492. DebugPrint((DebugLevelTrace,
  4493. "entering IoWorker:Source StreamObject:%x\n",StreamObject));
  4494. #endif
  4495. FilterInstance =
  4496. (PFILTER_INSTANCE)
  4497. StreamObject->FilterFileObject->FsContext;
  4498. if (!FilterInstance) {
  4499. //
  4500. // For some reason, the filter instance has gone missing.
  4501. //
  4502. DebugPrint((DebugLevelTrace,
  4503. "error: FilterInstance has gone missing.\n") );
  4504. return;
  4505. }
  4506. AdditionalInfo = FilterInstance->PinInstanceInfo;
  4507. //
  4508. // Synchronize with control changes and protect from reentrancy.
  4509. //
  4510. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  4511. Executive,
  4512. KernelMode,
  4513. FALSE,// not alertable
  4514. NULL);
  4515. //
  4516. // Synchronize with queues.
  4517. //
  4518. KeAcquireSpinLock( &StreamObject->Queues[WhichQueue].QueueLock, &irqlOld );
  4519. //
  4520. // Loop while there are completed items on the queue.
  4521. //
  4522. while (!IsListEmpty( &StreamObject->Queues[WhichQueue].ActiveQueue )) {
  4523. Node = StreamObject->Queues[WhichQueue].ActiveQueue.Flink;
  4524. StreamHeader =
  4525. CONTAINING_RECORD(
  4526. Node,
  4527. STREAM_HEADER_EX,
  4528. ListEntry );
  4529. #if (DBG)
  4530. DebugPrint((DebugLevelTrace,
  4531. "got StreamHeader:%08x\n", StreamHeader ));
  4532. #endif
  4533. if (StreamHeader->ReferenceCount) {
  4534. DebugPrint((DebugLevelTrace,
  4535. "breaking StreamHeader:%08x\n", StreamHeader ));
  4536. break;
  4537. } else {
  4538. //
  4539. // Remove this header from the current queue.
  4540. //
  4541. RemoveHeadList( &StreamObject->Queues[WhichQueue].ActiveQueue );
  4542. #if (DBG)
  4543. StreamHeader->OnActiveList = FALSE;
  4544. #endif
  4545. KeReleaseSpinLock( &StreamObject->Queues[WhichQueue].QueueLock, irqlOld );
  4546. //
  4547. // Wait for the APC to complete. Note that if an error was
  4548. // returned, the I/O status block is not updated and the
  4549. // event is not signalled.
  4550. //
  4551. DebugPrint((DebugLevelTrace,
  4552. "waiting for StreamHeader (%08x) to complete\n", StreamHeader ));
  4553. KeWaitForSingleObject(
  4554. &StreamHeader->CompletionEvent,
  4555. Executive,
  4556. KernelMode,
  4557. FALSE,
  4558. NULL);
  4559. DebugPrint((DebugLevelTrace,
  4560. "StreamHeader (%08x) completed\n", StreamHeader));
  4561. DestinationFileObject =
  4562. StreamHeader->NextFileObject;
  4563. //
  4564. // At the time this returns TRUE, the loop will be finished.
  4565. //
  4566. SignalStop = HeaderTransfer(
  4567. FilterInstance,
  4568. StreamObject,
  4569. DestinationFileObject,
  4570. &StreamHeader );
  4571. if (StreamHeader)
  4572. {
  4573. DebugPrint((DebugLevelTrace, "IoWorker issuing: "));
  4574. if (DestinationFileObject == StreamObject->NextFileObject)
  4575. {
  4576. DebugPrint((DebugLevelTrace,"KSSTREAM_WRITE:dest=%x\n",DestinationFileObject));
  4577. Operation = KSSTREAM_WRITE;
  4578. StreamHeader->NextFileObject =
  4579. StreamObject->FileObject;
  4580. #if (DBG)
  4581. if (StreamHeader->Id == 7)
  4582. DebugPrint((DebugLevelVerbose,"iw%x\n",StreamHeader->Id));
  4583. else
  4584. DebugPrint((DebugLevelVerbose,"iw%x",StreamHeader->Id));
  4585. #endif
  4586. }
  4587. else
  4588. {
  4589. DebugPrint((DebugLevelTrace,"KSSTREAM_READ:dest=%x\n",DestinationFileObject));
  4590. Operation = KSSTREAM_READ;
  4591. StreamHeader->Header.OptionsFlags = 0;
  4592. //
  4593. // Reset the stream segment valid data length
  4594. //
  4595. StreamHeader->Header.DataUsed = 0;
  4596. StreamHeader->Header.Duration = 0;
  4597. StreamHeader->NextFileObject = StreamObject->NextFileObject;
  4598. #if (DBG)
  4599. if (StreamHeader->Id == 7)
  4600. DebugPrint((DebugLevelVerbose,"ir%x\n",StreamHeader->Id));
  4601. else
  4602. DebugPrint((DebugLevelVerbose,"ir%x",StreamHeader->Id));
  4603. #endif
  4604. }
  4605. InterlockedIncrement( &StreamHeader->ReferenceCount );
  4606. StreamHeader->WhichQueue = WhichQueue ^ 0x00000001;
  4607. Status =
  4608. KsStreamIo(
  4609. DestinationFileObject,
  4610. &StreamHeader->CompletionEvent, // Event
  4611. NULL, // PortContext
  4612. IoCompletionRoutine,
  4613. StreamHeader, // CompletionContext
  4614. KsInvokeOnSuccess |
  4615. KsInvokeOnCancel |
  4616. KsInvokeOnError,
  4617. &StreamHeader->IoStatus,
  4618. &StreamHeader->Header,
  4619. StreamHeader->Header.Size,
  4620. KSSTREAM_SYNCHRONOUS | Operation,
  4621. KernelMode );
  4622. if (Status != STATUS_PENDING) {
  4623. //
  4624. // If this I/O completes immediately (failure or not), the
  4625. // event is not signalled.
  4626. //
  4627. KeSetEvent( &StreamHeader->CompletionEvent, IO_NO_INCREMENT, FALSE );
  4628. }
  4629. }
  4630. KeAcquireSpinLock( &StreamObject->Queues[WhichQueue].QueueLock, &irqlOld );
  4631. }
  4632. //
  4633. // Ok to schedule another work item now.
  4634. //
  4635. } // end while
  4636. InterlockedExchange( &StreamObject->Queues[WhichQueue].WorkItemQueued, FALSE );
  4637. //
  4638. // If a stop needs to be signalled, signal it.
  4639. //
  4640. if (SignalStop) {
  4641. KeSetEvent( &StreamObject->StopEvent,
  4642. IO_NO_INCREMENT,
  4643. FALSE );
  4644. }
  4645. KeReleaseSpinLock( &StreamObject->Queues[WhichQueue].QueueLock, irqlOld );
  4646. //
  4647. // Release the control event
  4648. //
  4649. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  4650. DebugPrint((DebugLevelTrace,"exiting IoWorker\n"));
  4651. }
  4652. //---------------------------------------------------------------------------
  4653. /*++
  4654. Routine Description:
  4655. These are the work items for the source and destination pins.
  4656. Calls the IoWorker code above, passing in READ or WRITE header
  4657. queue information.
  4658. Arguments:
  4659. PVOID Context -
  4660. pointer to the stream header
  4661. Return:
  4662. Nothing.
  4663. Comments:
  4664. --*/
  4665. VOID
  4666. IoWorkerRead(
  4667. PVOID Context
  4668. )
  4669. {
  4670. IoWorker(Context,READ);
  4671. }
  4672. VOID
  4673. IoWorkerWrite(
  4674. PVOID Context
  4675. )
  4676. {
  4677. IoWorker(Context,WRITE);
  4678. }
  4679. //---------------------------------------------------------------------------
  4680. NTSTATUS
  4681. IoCompletionRoutine(
  4682. PDEVICE_OBJECT DeviceObject,
  4683. PIRP Irp,
  4684. PVOID Context
  4685. )
  4686. /*++
  4687. Routine Description:
  4688. Processes the completion of the given Irp by marking the
  4689. associated stream header as completed and scheduling a
  4690. worker item to complete processing if necessary.
  4691. Arguments:
  4692. PDEVICE_OBJECT DeviceObject -
  4693. pointer to the device object
  4694. PIRP Irp -
  4695. pointer to the I/O request packet
  4696. PVOID Context -
  4697. a context pointer (pointer to the associated stream header)
  4698. Return:
  4699. The IoStatus.Status member of the Irp.
  4700. Comments:
  4701. Not pageable, uses SpinLocks and may be called at DISPATCH_LEVEL.
  4702. --*/
  4703. {
  4704. KIRQL irqlOld;
  4705. PSTREAM_HEADER_EX StreamHeader = Context;
  4706. PFILTER_INSTANCE FilterInstance;
  4707. PSTREAM_OBJECT StreamObject;
  4708. ULONG WhichQueue;
  4709. #if (DBG)
  4710. ASSERT( StreamHeader->Data == StreamHeader->Header.Data );
  4711. #endif
  4712. StreamObject =
  4713. (PSTREAM_OBJECT) StreamHeader->OwnerFileObject->FsContext;
  4714. DebugPrint((DebugLevelTrace,
  4715. "IoCompletionRoutine:StreamHeader %08x, StreamObject %08x\n",StreamHeader,StreamObject));
  4716. FilterInstance =
  4717. (PFILTER_INSTANCE)
  4718. StreamHeader->OwnerFileObject->RelatedFileObject->FsContext;
  4719. WhichQueue = StreamHeader->WhichQueue;
  4720. KeAcquireSpinLock( &StreamObject->Queues[WhichQueue].QueueLock, &irqlOld );
  4721. //
  4722. // Remove this reference count on the IRP so that we can continue
  4723. // the loop if this work item is not the head item of the list.
  4724. //
  4725. InterlockedDecrement( &StreamHeader->ReferenceCount );
  4726. //
  4727. // Copy the status block so that we don't have to wait for the APC.
  4728. //
  4729. StreamHeader->IoStatus = Irp->IoStatus;
  4730. //
  4731. // Sweep the active queue in the worker to complete the transfer.
  4732. //
  4733. if (!StreamObject->Queues[WhichQueue].WorkItemQueued) {
  4734. //
  4735. // A work item is not pending, initialize the worker item
  4736. // for the new context and queue it.
  4737. //
  4738. ExInitializeWorkItem(
  4739. &StreamObject->Queues[WhichQueue].WorkItem,
  4740. (WhichQueue == READ) ? IoWorkerRead : IoWorkerWrite,
  4741. StreamObject );
  4742. InterlockedExchange( &StreamObject->Queues[WhichQueue].WorkItemQueued, TRUE );
  4743. KsQueueWorkItem(
  4744. (WhichQueue == READ) ? FilterInstance->WorkerRead :
  4745. FilterInstance->WorkerWrite,
  4746. &StreamObject->Queues[WhichQueue].WorkItem );
  4747. }
  4748. KeReleaseSpinLock( &StreamObject->Queues[WhichQueue].QueueLock, irqlOld );
  4749. DebugPrint((DebugLevelTrace,
  4750. "exiting IoCompletionRoutine:Irp->IoStatus.Status:%x\n",Irp->IoStatus.Status));
  4751. return Irp->IoStatus.Status;
  4752. }
  4753. //---------------------------------------------------------------------------
  4754. NTSTATUS
  4755. PrepareTransfer(
  4756. IN PFILTER_INSTANCE FilterInstance,
  4757. IN PSTREAM_OBJECT StreamObject
  4758. )
  4759. /*++
  4760. Routine Description:
  4761. Prepares for the data transfer by distributing the assigned allocators
  4762. for the source and destination pins.
  4763. Arguments:
  4764. IN PFILTER_INSTANCE FilterInstance,
  4765. pointer to the filter instance
  4766. IN PSTREAM_OBJECT StreamObject -
  4767. pointer to the transform instance
  4768. Return:
  4769. STATUS_SUCCESS or an appropriate error code.
  4770. --*/
  4771. {
  4772. KSPROPERTY Property;
  4773. KSSTREAMALLOCATOR_STATUS AllocatorStatus;
  4774. NTSTATUS Status;
  4775. PSTREAM_HEADER_EX StreamHeader;
  4776. ULONG i, Returned;
  4777. PADDITIONAL_PIN_INFO AdditionalInfo;
  4778. //
  4779. // If the PinState is not PinStopped, then return.
  4780. //
  4781. DebugPrint((DebugLevelTrace,"entering PrepareTransfer\n"));
  4782. if (!StreamObject->AllocatorFileObject) {
  4783. DebugPrint((DebugLevelTrace,"!! AllocatorFileObject is NULL"));
  4784. return STATUS_SUCCESS;
  4785. }
  4786. if (StreamObject->PinState != PinStopped) {
  4787. //
  4788. // We only need to do this work when the pin has been
  4789. // completely stopped. If we were running, just reflect the
  4790. // state.
  4791. //
  4792. DebugPrint((DebugLevelTrace,"PrepareTransfer exiting, PinState != PinStopped\n"));
  4793. StreamObject->PinState = PinPrepared;
  4794. return STATUS_SUCCESS;
  4795. }
  4796. AdditionalInfo = FilterInstance->PinInstanceInfo;
  4797. //
  4798. // Retrieve the allocator framing information for the pin.
  4799. //
  4800. Property.Set = KSPROPSETID_StreamAllocator;
  4801. Property.Id = KSPROPERTY_STREAMALLOCATOR_STATUS;
  4802. Property.Flags = KSPROPERTY_TYPE_GET;
  4803. Status =
  4804. KsSynchronousIoControlDevice(
  4805. StreamObject->AllocatorFileObject,
  4806. KernelMode,
  4807. IOCTL_KS_PROPERTY,
  4808. &Property,
  4809. sizeof( Property ),
  4810. &AllocatorStatus,
  4811. sizeof( AllocatorStatus ),
  4812. &Returned );
  4813. if (!NT_SUCCESS( Status ))
  4814. {
  4815. DebugPrint((DebugLevelTrace,
  4816. "PrepareTransfer exiting, unable to retrieve allocator status\n"));
  4817. return Status;
  4818. }
  4819. //
  4820. // Save the framing information
  4821. //
  4822. StreamObject->Framing = AllocatorStatus.Framing;
  4823. //
  4824. // Allocate the frames from the allocator
  4825. //
  4826. // 1. Always allocate frames when starting the IrpSource.
  4827. //
  4828. // 2. If the allocator is not shared, then allocate the frames when
  4829. // the (each) destination pin is started.
  4830. //
  4831. if (StreamObject->PinType == IrpSource) {
  4832. InterlockedExchange (&StreamObject -> QueuedFramesPlusOne, 1);
  4833. #if (DBG)
  4834. DebugPrint((DebugLevelTrace,"Framing.Frames:%x\n", StreamObject->Framing.Frames));
  4835. DebugPrint((DebugLevelTrace,"Framing.FrameSize:%x\n", StreamObject->Framing.FrameSize));
  4836. #endif
  4837. for (i = 0; i < StreamObject->Framing.Frames; i++) {
  4838. DebugPrint((DebugLevelTrace,"StreamObject->ExtendedHeaderSize:%x\n", StreamObject->HwStreamObject.StreamHeaderMediaSpecific));
  4839. StreamHeader =
  4840. ExAllocatePoolWithTag(
  4841. NonPagedPool,
  4842. sizeof( STREAM_HEADER_EX ) +
  4843. StreamObject->HwStreamObject.StreamHeaderMediaSpecific,
  4844. STREAMCLASS_TAG_STREAMHEADER );
  4845. if (NULL == StreamHeader) {
  4846. DebugPrint((DebugLevelTrace,
  4847. "out of pool while allocating frames\n") );
  4848. Status = STATUS_INSUFFICIENT_RESOURCES;
  4849. } else {
  4850. RtlZeroMemory(
  4851. StreamHeader,
  4852. sizeof( STREAM_HEADER_EX ) +
  4853. StreamObject->HwStreamObject.StreamHeaderMediaSpecific);
  4854. KeInitializeEvent(
  4855. &StreamHeader->CompletionEvent,
  4856. SynchronizationEvent,
  4857. FALSE );
  4858. StreamHeader->Header.Size =
  4859. sizeof( KSSTREAM_HEADER ) +
  4860. StreamObject->HwStreamObject.StreamHeaderMediaSpecific;
  4861. if (StreamObject->HwStreamObject.StreamHeaderMediaSpecific) {
  4862. *(PULONG)((&StreamHeader->Header) + 1) =
  4863. StreamObject->HwStreamObject.StreamHeaderMediaSpecific;
  4864. }
  4865. Status =
  4866. AllocateFrame(
  4867. StreamObject->AllocatorFileObject,
  4868. &StreamHeader->Header.Data );
  4869. #if (DBG)
  4870. //
  4871. // Track who is stomping on the headers...
  4872. //
  4873. StreamHeader->Data = StreamHeader->Header.Data;
  4874. #endif
  4875. StreamHeader->WhichQueue = READ;
  4876. StreamHeader->Id = i;
  4877. if (!NT_SUCCESS( Status )) {
  4878. DebugPrint((DebugLevelTrace,
  4879. "failed to allocate a frame\n") );
  4880. //
  4881. // Free this header here and the routine below will
  4882. // clean up whatever has been added to the queue.
  4883. //
  4884. ExFreePool( StreamHeader );
  4885. } else {
  4886. //
  4887. // Start with the owner file object as this connection,
  4888. // if a no-copy condition exists, this will be adjusted
  4889. // in the transfer function.
  4890. //
  4891. StreamHeader->OwnerFileObject =
  4892. StreamObject->FileObject;
  4893. StreamHeader->Header.DataUsed = 0;
  4894. StreamHeader->Header.FrameExtent =
  4895. StreamObject->Framing.FrameSize;
  4896. #if (DBG)
  4897. if (StreamHeader->OnFreeList) {
  4898. DebugPrint((DebugLevelTrace,"stream header already on free list.\n") );
  4899. }
  4900. #endif
  4901. InsertTailList(
  4902. &StreamObject->FreeQueue,
  4903. &StreamHeader->ListEntry );
  4904. #if (DBG)
  4905. StreamHeader->OnFreeList = TRUE;
  4906. #endif
  4907. }
  4908. }
  4909. }
  4910. //
  4911. // Clean up orphaned frames from the allocator and free headers
  4912. // to the pool if there was a failure.
  4913. //
  4914. if (!NT_SUCCESS( Status )) {
  4915. while (!IsListEmpty( &StreamObject->FreeQueue )) {
  4916. PLIST_ENTRY Node;
  4917. Node = RemoveHeadList( &StreamObject->FreeQueue );
  4918. StreamHeader =
  4919. CONTAINING_RECORD(
  4920. Node,
  4921. STREAM_HEADER_EX,
  4922. ListEntry );
  4923. #if (DBG)
  4924. StreamHeader->OnFreeList = FALSE;
  4925. ASSERT( StreamHeader->Data == StreamHeader->Header.Data );
  4926. #endif
  4927. FreeFrame(
  4928. StreamObject->AllocatorFileObject,
  4929. StreamHeader->Header.Data );
  4930. #if (DBG)
  4931. if (StreamHeader->OnFreeList || StreamHeader->OnActiveList) {
  4932. DebugPrint((DebugLevelTrace,
  4933. "freeing header %x still on list\n", StreamHeader) );
  4934. }
  4935. #endif
  4936. ExFreePool( StreamHeader );
  4937. }
  4938. DebugPrint((DebugLevelTrace,
  4939. "PrepareTransfer exiting, frame allocation failed: %08x\n", Status) );
  4940. return Status;
  4941. }
  4942. }
  4943. StreamObject->PinState = PinPrepared;
  4944. DebugPrint((DebugLevelTrace,"exiting PrepareTransfer\n"));
  4945. return STATUS_SUCCESS;
  4946. }
  4947. //---------------------------------------------------------------------------
  4948. NTSTATUS
  4949. BeginTransfer(
  4950. IN PFILTER_INSTANCE FilterInstance,
  4951. IN PSTREAM_OBJECT StreamObject
  4952. )
  4953. /*++
  4954. Routine Description:
  4955. Begins the data transfer from each pin by initiating stream reads
  4956. from the inflow pin. The completion routine for each read will
  4957. continue the stream processing.
  4958. Arguments:
  4959. IN PFILTER_INSTANCE FilterInstance,
  4960. pointer to the filter instance
  4961. IN PSTREAM_OBJECT StreamObject -
  4962. pointer to the transform instance
  4963. Return:
  4964. STATUS_SUCCESS or an appropriate error code.
  4965. Comments:
  4966. Not pageable, uses SpinLocks.
  4967. --*/
  4968. {
  4969. KIRQL irql0,irqlFree;
  4970. NTSTATUS Status;
  4971. PSTREAM_HEADER_EX StreamHeader;
  4972. PADDITIONAL_PIN_INFO AdditionalInfo;
  4973. DebugPrint((DebugLevelTrace,"entering BeginTransfer\n"));
  4974. //
  4975. // If the PinState is not PinPrepared, then return.
  4976. //
  4977. if (StreamObject->PinState != PinPrepared) {
  4978. DebugPrint((DebugLevelTrace,"BeginTransfer exiting, PinState != PinPrepared\n") );
  4979. return STATUS_INVALID_DEVICE_STATE;
  4980. }
  4981. AdditionalInfo = FilterInstance->PinInstanceInfo;
  4982. StreamObject->PinState = PinRunning;
  4983. //
  4984. // All preparation is complete. If this is the source pin, begin
  4985. // the actual data transfer.
  4986. //
  4987. Status = STATUS_SUCCESS;
  4988. if (StreamObject->PinType == IrpSource) {
  4989. #if (DBG)
  4990. //
  4991. // get the dataflow direction
  4992. //
  4993. DebugPrint((DebugLevelVerbose,
  4994. "BeginTransfer, DataFlow:"));
  4995. if (StreamObject->DeviceExtension->StreamDescriptor->StreamInfo.DataFlow == KSPIN_DATAFLOW_IN)
  4996. DebugPrint((DebugLevelVerbose,
  4997. "KSPIN_DATAFLOW_IN\n"));
  4998. else
  4999. DebugPrint((DebugLevelVerbose,
  5000. "KSPIN_DATAFLOW_OUT\n"));
  5001. #endif
  5002. //
  5003. // Begin the transfer by reading from the inflow pin.
  5004. //
  5005. KeAcquireSpinLock( &StreamObject->Queues[0].QueueLock, &irql0 );
  5006. KeAcquireSpinLock( &StreamObject->FreeQueueLock, &irqlFree );
  5007. while (!IsListEmpty( &StreamObject->FreeQueue )) {
  5008. PLIST_ENTRY Node;
  5009. Node = RemoveHeadList( &StreamObject->FreeQueue );
  5010. StreamHeader =
  5011. CONTAINING_RECORD(
  5012. Node,
  5013. STREAM_HEADER_EX,
  5014. ListEntry );
  5015. #if (DBG)
  5016. StreamHeader->OnFreeList = FALSE;
  5017. if (StreamHeader->OnActiveList) {
  5018. DebugPrint((DebugLevelTrace,"stream header %x already on active list.\n",StreamHeader) );
  5019. }
  5020. #endif
  5021. InterlockedIncrement (&StreamObject -> QueuedFramesPlusOne);
  5022. InsertTailList( &StreamObject->Queues[0].ActiveQueue, Node );
  5023. #if (DBG)
  5024. StreamHeader->OnActiveList = TRUE;
  5025. #endif
  5026. KeReleaseSpinLock( &StreamObject->FreeQueueLock, irqlFree );
  5027. KeReleaseSpinLock( &StreamObject->Queues[0].QueueLock, irql0 );
  5028. DebugPrint((DebugLevelTrace,
  5029. "BeginTransfer, KsStreamIo: %x\n", StreamHeader));
  5030. DebugPrint((DebugLevelTrace,
  5031. "BeginTransfer, KsStreamIo: FileObject:%x\n", StreamObject->FileObject));
  5032. DebugPrint((DebugLevelTrace,
  5033. "BeginTransfer:HeaderSize:=%x\n",StreamHeader->Header.Size));
  5034. InterlockedIncrement( &StreamHeader->ReferenceCount );
  5035. StreamHeader->NextFileObject = StreamObject->NextFileObject;
  5036. //
  5037. // send a data irp to myself, first.
  5038. //
  5039. DebugPrint((DebugLevelTrace,
  5040. "BeginTransfer:Reading:%x\n",StreamHeader->Id));
  5041. Status =
  5042. KsStreamIo(
  5043. StreamObject->FileObject,
  5044. &StreamHeader->CompletionEvent, // Event
  5045. NULL, // PortContext
  5046. IoCompletionRoutine,
  5047. StreamHeader, // CompletionContext
  5048. KsInvokeOnSuccess |
  5049. KsInvokeOnCancel |
  5050. KsInvokeOnError,
  5051. &StreamHeader->IoStatus,
  5052. &StreamHeader->Header,
  5053. StreamHeader->Header.Size,
  5054. KSSTREAM_SYNCHRONOUS | KSSTREAM_READ,
  5055. KernelMode );
  5056. if (Status != STATUS_PENDING) {
  5057. //
  5058. // If this I/O completes immediately (failure or not), the
  5059. // event is not signalled.
  5060. //
  5061. KeSetEvent( &StreamHeader->CompletionEvent, IO_NO_INCREMENT, FALSE );
  5062. }
  5063. if (!NT_SUCCESS( Status )) {
  5064. DebugPrint((DebugLevelTrace, "KsStreamIo returned %08x\n", Status ));
  5065. } else {
  5066. Status = STATUS_SUCCESS;
  5067. }
  5068. KeAcquireSpinLock( &StreamObject->Queues[0].QueueLock, &irql0 );
  5069. KeAcquireSpinLock( &StreamObject->FreeQueueLock, &irqlFree );
  5070. }
  5071. KeReleaseSpinLock( &StreamObject->FreeQueueLock, irqlFree );
  5072. KeReleaseSpinLock( &StreamObject->Queues[0].QueueLock, irql0 );
  5073. }
  5074. DebugPrint((DebugLevelTrace,"exiting BeginTransfer\n"));
  5075. return Status;
  5076. }
  5077. //---------------------------------------------------------------------------
  5078. NTSTATUS
  5079. EndTransfer(
  5080. IN PFILTER_INSTANCE FilterInstance,
  5081. IN PSTREAM_OBJECT StreamObject
  5082. )
  5083. /*++
  5084. Routine Description:
  5085. Ends the data transfer, waits for all Irps to complete
  5086. Arguments:
  5087. IN PFILTER_INSTANCE FilterInstance -
  5088. pointer to the filter instance
  5089. IN PSTREAM_OBJECT StreamObject
  5090. pointer to the Stream object
  5091. Return:
  5092. STATUS_SUCCESS or an appropriate error code.
  5093. Comments:
  5094. Not pageable, uses SpinLocks.
  5095. --*/
  5096. {
  5097. PDEVICE_EXTENSION DeviceExtension;
  5098. KIRQL irqlOld;
  5099. DeviceExtension = StreamObject->DeviceExtension;
  5100. DebugPrint((DebugLevelTrace,"entering EndTransfer!\n"));
  5101. //
  5102. // Set the marker indicating that we stop sourcing frames and then flush
  5103. // to ensure that anything blocked on the output pin at least gets
  5104. // cancelled before we block and deadlock on it.
  5105. //
  5106. StreamObject -> PinState = PinStopPending;
  5107. StreamFlushIo (DeviceExtension, StreamObject);
  5108. if (InterlockedDecrement (&StreamObject -> QueuedFramesPlusOne)) {
  5109. //
  5110. // Release the control mutex to allow the I/O thread to run.
  5111. //
  5112. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  5113. DebugPrint((DebugLevelTrace,
  5114. "waiting for pin %d queue to empty\n", StreamObject->PinId));
  5115. //
  5116. // Wait for the queue to empty
  5117. //
  5118. KeWaitForSingleObject(
  5119. &StreamObject -> StopEvent,
  5120. Executive,
  5121. KernelMode,
  5122. FALSE,
  5123. NULL);
  5124. DebugPrint((DebugLevelTrace,"queue emptied\n") );
  5125. //
  5126. // Re-acquire the control object.
  5127. //
  5128. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  5129. Executive,
  5130. KernelMode,
  5131. FALSE,// not alertable
  5132. NULL);
  5133. }
  5134. //
  5135. // Free the frames so that we can reprepare for new allocator
  5136. // framing, a new allocator or just general cleanup/shutdown.
  5137. //
  5138. KeAcquireSpinLock( &StreamObject->FreeQueueLock, &irqlOld );
  5139. while (!IsListEmpty( &StreamObject->FreeQueue )) {
  5140. PLIST_ENTRY Node;
  5141. PSTREAM_HEADER_EX StreamHeader;
  5142. Node = RemoveHeadList( &StreamObject->FreeQueue );
  5143. StreamHeader =
  5144. CONTAINING_RECORD(
  5145. Node,
  5146. STREAM_HEADER_EX,
  5147. ListEntry );
  5148. #if (DBG)
  5149. StreamHeader->OnFreeList = FALSE;
  5150. #endif
  5151. KeReleaseSpinLock( &StreamObject->FreeQueueLock, irqlOld );
  5152. #if (DBG)
  5153. ASSERT( StreamHeader->Data == StreamHeader->Header.Data );
  5154. #endif
  5155. FreeFrame(
  5156. StreamObject->AllocatorFileObject,
  5157. StreamHeader->Header.Data );
  5158. DebugPrint((DebugLevelTrace,
  5159. "freeing header: %08x, list: %08x\n", StreamHeader, &StreamObject->FreeQueue) );
  5160. #if (DBG)
  5161. if (StreamHeader->OnFreeList || StreamHeader->OnActiveList) {
  5162. DebugPrint((DebugLevelTrace,
  5163. "freeing header %x still on list\n", StreamHeader) );
  5164. }
  5165. #endif
  5166. ExFreePool( StreamHeader );
  5167. KeAcquireSpinLock( &StreamObject->FreeQueueLock, &irqlOld );
  5168. }
  5169. StreamObject->PinState = PinStopped;
  5170. KeReleaseSpinLock( &StreamObject->FreeQueueLock, irqlOld );
  5171. DebugPrint((DebugLevelTrace,"exiting CleanupTransfer\n"));
  5172. return STATUS_SUCCESS;
  5173. }
  5174. //---------------------------------------------------------------------------
  5175. NTSTATUS
  5176. AllocateFrame(
  5177. PFILE_OBJECT Allocator,
  5178. PVOID *Frame
  5179. )
  5180. /*++
  5181. Routine Description:
  5182. Allocates a frame from the given allocator
  5183. Arguments:
  5184. PFILE_OBJECT Allocator -
  5185. pointer to the allocator's file object
  5186. PVOID *Frame -
  5187. pointer to receive the allocated frame pointer
  5188. Return:
  5189. STATUS_SUCCESS and *Frame contains a pointer to the allocated
  5190. frame, otherwise an appropriate error code.
  5191. --*/
  5192. {
  5193. NTSTATUS Status;
  5194. KSMETHOD Method;
  5195. ULONG Returned;
  5196. DebugPrint((DebugLevelTrace,"entering AllocateFrame\n"));
  5197. Method.Set = KSMETHODSETID_StreamAllocator;
  5198. Method.Id = KSMETHOD_STREAMALLOCATOR_ALLOC;
  5199. Method.Flags = KSMETHOD_TYPE_WRITE;
  5200. Status =
  5201. KsSynchronousIoControlDevice(
  5202. Allocator,
  5203. KernelMode,
  5204. IOCTL_KS_METHOD,
  5205. &Method,
  5206. sizeof( Method ),
  5207. Frame,
  5208. sizeof( PVOID ),
  5209. &Returned );
  5210. DebugPrint((DebugLevelTrace,"exiting AllocateFrame\n"));
  5211. return Status;
  5212. }
  5213. //---------------------------------------------------------------------------
  5214. NTSTATUS
  5215. FreeFrame(
  5216. PFILE_OBJECT Allocator,
  5217. PVOID Frame
  5218. )
  5219. /*++
  5220. Routine Description:
  5221. Frees a frame to the given allocator
  5222. Arguments:
  5223. PFILE_OBJECT Allocator -
  5224. pointer to the allocator's file object
  5225. PVOID Frame -
  5226. pointer to the frame to be freed.
  5227. Return:
  5228. STATUS_SUCCESS or else an appropriate error code.
  5229. --*/
  5230. {
  5231. NTSTATUS Status;
  5232. KSMETHOD Method;
  5233. ULONG Returned;
  5234. DebugPrint((DebugLevelTrace,"entering FreeFrame\n"));
  5235. Method.Set = KSMETHODSETID_StreamAllocator;
  5236. Method.Id = KSMETHOD_STREAMALLOCATOR_FREE;
  5237. Method.Flags = KSMETHOD_TYPE_READ;
  5238. Status =
  5239. KsSynchronousIoControlDevice(
  5240. Allocator,
  5241. KernelMode,
  5242. IOCTL_KS_METHOD,
  5243. &Method,
  5244. sizeof( Method ),
  5245. &Frame,
  5246. sizeof( PVOID ),
  5247. &Returned );
  5248. DebugPrint((DebugLevelTrace,"exiting FreeFrame\n"));
  5249. return Status;
  5250. }
  5251. //---------------------------------------------------------------------------
  5252. NTSTATUS
  5253. PinCreateHandler(
  5254. IN PIRP Irp,
  5255. IN PSTREAM_OBJECT StreamObject
  5256. )
  5257. /*++
  5258. Routine Description:
  5259. This is the pin creation handler which is called by KS when a
  5260. pin create request is submitted to the filter.
  5261. Arguments:
  5262. IN PIRP Irp -
  5263. pointer to the I/O request packet
  5264. Return:
  5265. STATUS_SUCCESS or an appropriate error return code.
  5266. --*/
  5267. {
  5268. NTSTATUS Status;
  5269. PIO_STACK_LOCATION IrpStack;
  5270. PFILTER_INSTANCE FilterInstance;
  5271. PADDITIONAL_PIN_INFO AdditionalInfo;
  5272. PFILE_OBJECT NextFileObject;
  5273. IrpStack = IoGetCurrentIrpStackLocation( Irp );
  5274. DebugPrint((DebugLevelTrace,"entering PinCreateHandler\n"));
  5275. FilterInstance =
  5276. (PFILTER_INSTANCE) IrpStack->FileObject->RelatedFileObject->FsContext;
  5277. AdditionalInfo = FilterInstance->PinInstanceInfo;
  5278. Status = STATUS_SUCCESS;
  5279. StreamObject->NextFileObject = NULL;
  5280. DebugPrint((DebugLevelTrace,"PinCreateHandler:its an IrpSource\n"));
  5281. //
  5282. // Validate that we can handle this connection request
  5283. //
  5284. if (StreamObject->NextFileObject) {
  5285. DebugPrint((DebugLevelTrace,"invalid connection request\n") );
  5286. Status = STATUS_CONNECTION_REFUSED;
  5287. }
  5288. else
  5289. {
  5290. Status =
  5291. ObReferenceObjectByHandle(
  5292. StreamObject->PinToHandle,
  5293. FILE_READ_ACCESS | FILE_WRITE_ACCESS | SYNCHRONIZE,
  5294. *IoFileObjectType,
  5295. KernelMode,
  5296. &NextFileObject,
  5297. NULL );
  5298. if (!NT_SUCCESS(Status)) {
  5299. DebugPrint((DebugLevelTrace,"PinCreateHandler:error referencing PinToHandle\n"));
  5300. }
  5301. else
  5302. {
  5303. // NextFileObject must be per instance
  5304. //AdditionalInfo[ StreamObject->PinId ].NextFileObject = NextFileObject;
  5305. StreamObject->NextFileObject = NextFileObject;
  5306. //
  5307. // Add the pin's target to the list of targets for
  5308. // recalculating stack depth.
  5309. //
  5310. KsSetTargetDeviceObject(
  5311. StreamObject->ComObj.DeviceHeader,
  5312. IoGetRelatedDeviceObject(
  5313. NextFileObject ) );
  5314. }
  5315. }
  5316. DebugPrint((DebugLevelTrace,"PinCreateHandler returning %x\n", Status ));
  5317. return Status;
  5318. }
  5319. #endif