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.

7385 lines
204 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. codinit.c
  5. Abstract:
  6. This is the WDM streaming class driver. This module contains code related
  7. to driver initialization.
  8. Author:
  9. billpa
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "codcls.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, StreamClassRegisterAdapter)
  17. #if ENABLE_MULTIPLE_FILTER_TYPES
  18. //#pragma alloc_text(PAGE, StreamClassRegisterNameExtensions)
  19. #endif
  20. #pragma alloc_text(PAGE, StreamClassPnPAddDevice)
  21. #pragma alloc_text(PAGE, StreamClassPnPAddDeviceWorker)
  22. #pragma alloc_text(PAGE, StreamClassPnP)
  23. #pragma alloc_text(PAGE, SCStartWorker)
  24. #pragma alloc_text(PAGE, SCUninitializeMinidriver)
  25. #pragma alloc_text(INIT, DriverEntry)
  26. #pragma alloc_text(PAGE, SCFreeAllResources)
  27. #pragma alloc_text(PAGE, SCInitializeCallback)
  28. #pragma alloc_text(PAGE, SCStreamInfoCallback)
  29. #pragma alloc_text(PAGE, SCUninitializeCallback)
  30. #pragma alloc_text(PAGE, SCUnknownPNPCallback)
  31. #pragma alloc_text(PAGE, SCUnknownPowerCallback)
  32. #pragma alloc_text(PAGE, SciQuerySystemPowerHiberCallback)
  33. #pragma alloc_text(PAGE, SCInsertStreamInfo)
  34. #pragma alloc_text(PAGE, SCPowerCallback)
  35. #pragma alloc_text(PAGE, SCCreateSymbolicLinks)
  36. #pragma alloc_text(PAGE, SCDestroySymbolicLinks)
  37. #pragma alloc_text(PAGE, SCCreateChildPdo)
  38. #pragma alloc_text(PAGE, SCEnumerateChildren)
  39. #pragma alloc_text(PAGE, SCEnumGetCaps)
  40. #pragma alloc_text(PAGE, SCQueryEnumId)
  41. #pragma alloc_text(PAGE, StreamClassForwardUnsupported)
  42. #pragma alloc_text(PAGE, SCPowerCompletionWorker)
  43. #pragma alloc_text(PAGE, SCSendSurpriseNotification)
  44. #endif
  45. #ifdef ALLOC_DATA_PRAGMA
  46. #pragma const_seg("PAGECONST")
  47. #endif
  48. static const WCHAR EnumString[] = L"Enum";
  49. static const WCHAR PnpIdString[] = L"PnpId";
  50. // CleanUp - the following three strings should go away
  51. static const WCHAR ClsIdString[] = L"CLSID";
  52. static const WCHAR DriverDescString[] = L"DriverDesc";
  53. static const WCHAR FriendlyNameString[] = L"FriendlyName";
  54. static const WCHAR DeviceTypeName[] = L"GLOBAL";
  55. static const DEFINE_KSCREATE_DISPATCH_TABLE(CreateItems)
  56. {
  57. DEFINE_KSCREATE_ITEM(
  58. FilterDispatchGlobalCreate,
  59. DeviceTypeName,
  60. NULL),
  61. };
  62. //
  63. // list anchor for global minidriver info.
  64. //
  65. DEFINE_KSPIN_INTERFACE_TABLE(PinInterfaces)
  66. {
  67. DEFINE_KSPIN_INTERFACE_ITEM(
  68. KSINTERFACESETID_Standard,
  69. KSINTERFACE_STANDARD_STREAMING),
  70. };
  71. DEFINE_KSPIN_MEDIUM_TABLE(PinMediums)
  72. {
  73. DEFINE_KSPIN_MEDIUM_ITEM(
  74. KSMEDIUMSETID_Standard,
  75. KSMEDIUM_TYPE_ANYINSTANCE),
  76. };
  77. #ifdef ALLOC_DATA_PRAGMA
  78. #pragma const_seg()
  79. #endif
  80. NTSTATUS
  81. StreamClassRegisterAdapter(
  82. IN PVOID Argument1,
  83. IN PVOID Argument2,
  84. IN PHW_INITIALIZATION_DATA HwInitializationData
  85. )
  86. /*++
  87. Routine Description:
  88. This routine registers a new streaming minidriver.
  89. Arguments:
  90. Argument1 - Pointer to driver object created by system.
  91. Argument2 - Pointer to a UNICODE string of the registry path created
  92. by system.
  93. HwInitializationData - Minidriver initialization structure.
  94. Return Value:
  95. Returns STATUS_SUCCESS if successful
  96. --*/
  97. {
  98. NTSTATUS Status;
  99. PDRIVER_OBJECT driverObject = Argument1;
  100. PDEVICE_EXTENSION deviceExtension = NULL;
  101. PMINIDRIVER_INFORMATION pMinidriverInfo;
  102. PAGED_CODE();
  103. DebugPrint((DebugLevelVerbose, "'StreamClassInitialize: enter\n"));
  104. //
  105. // Check that the length of this structure is what the
  106. // port driver expects it to be. This is effectively a
  107. // version check.
  108. //
  109. #if ENABLE_MULTIPLE_FILTER_TYPES
  110. //
  111. // we split the ULONG HwInitializationDataSize into two ushorts, one for
  112. // SizeOfThisPacket, another for StreamClassVersion which must be 0x0200 to
  113. // indicate the two reserved fields now NumNameExtesnions and NameExtensionArray,
  114. // contain valid information.
  115. //
  116. if (HwInitializationData->SizeOfThisPacket != sizeof(HW_INITIALIZATION_DATA) ||
  117. ( HwInitializationData->StreamClassVersion != 0 &&
  118. HwInitializationData->StreamClassVersion != STREAM_CLASS_VERSION_20)) {
  119. DebugPrint((DebugLevelFatal, "StreamClassInitialize: Minidriver wrong version\n"));
  120. SCLogError((PDEVICE_OBJECT) driverObject, 0, CODCLASS_CLASS_MINIDRIVER_MISMATCH, 0x1002);
  121. ASSERT( 0 );
  122. return (STATUS_REVISION_MISMATCH);
  123. }
  124. #else // ENABLE_MULTIPLE_FILTER_TYPES
  125. if (HwInitializationData->HwInitializationDataSize < sizeof(HW_INITIALIZATION_DATA)) {
  126. DebugPrint((DebugLevelFatal, "StreamClassInitialize: Minidriver wrong version\n"));
  127. SCLogError((PDEVICE_OBJECT) driverObject, 0, CODCLASS_CLASS_MINIDRIVER_MISMATCH, 0x1002);
  128. ASSERT( 0 );
  129. return (STATUS_REVISION_MISMATCH);
  130. }
  131. #endif // ENABLE_MULTIPLE_FILTER_TYPES
  132. //
  133. // Check that each required entry is not NULL.
  134. //
  135. if ((!HwInitializationData->HwReceivePacket) ||
  136. (!HwInitializationData->HwRequestTimeoutHandler)) {
  137. DebugPrint((DebugLevelFatal,
  138. "StreamClassInitialize: Minidriver driver missing required entry\n"));
  139. SCLogError((PDEVICE_OBJECT) driverObject, 0, CODCLASS_MINIDRIVER_MISSING_ENTRIES, 0x1003);
  140. return (STATUS_REVISION_MISMATCH);
  141. }
  142. //
  143. // set up dummy routines for each unsupported function
  144. //
  145. if (!HwInitializationData->HwCancelPacket) {
  146. HwInitializationData->HwCancelPacket = SCDummyMinidriverRoutine;
  147. }
  148. //
  149. // Set up the device driver entry points.
  150. //
  151. driverObject->MajorFunction[IRP_MJ_PNP] = StreamClassPnP;
  152. driverObject->MajorFunction[IRP_MJ_POWER] = StreamClassPower;
  153. driverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = StreamClassForwardUnsupported;
  154. // TODO: remove this once KS can multiplex cleanup Irps
  155. driverObject->MajorFunction[IRP_MJ_CLEANUP] = StreamClassCleanup;
  156. driverObject->DriverUnload = KsNullDriverUnload;
  157. driverObject->DriverExtension->AddDevice = StreamClassPnPAddDevice;
  158. //
  159. // set ioctl interface
  160. //
  161. driverObject->MajorFunction[IRP_MJ_CREATE] = StreamClassPassThroughIrp;
  162. driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
  163. StreamClassPassThroughIrp;
  164. driverObject->MajorFunction[IRP_MJ_CLOSE] = StreamClassPassThroughIrp;
  165. driverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] =
  166. StreamClassPassThroughIrp;
  167. //
  168. // Allocate a driver object extension to contain the minidriver's
  169. // vectors.
  170. //
  171. Status = IoAllocateDriverObjectExtension(driverObject,
  172. (PVOID) StreamClassPnP,
  173. sizeof(MINIDRIVER_INFORMATION),
  174. &pMinidriverInfo);
  175. if (!NT_SUCCESS(Status)) {
  176. DebugPrint((DebugLevelError,
  177. "StreamClassInitialize: No pool for global info"));
  178. SCLogError((PDEVICE_OBJECT) driverObject, 0, CODCLASS_NO_GLOBAL_INFO_POOL, 0x1004);
  179. return (STATUS_INSUFFICIENT_RESOURCES);
  180. }
  181. RtlZeroMemory(pMinidriverInfo, sizeof(MINIDRIVER_INFORMATION));
  182. RtlCopyMemory(pMinidriverInfo, HwInitializationData,
  183. sizeof(HW_INITIALIZATION_DATA));
  184. #if ENABLE_MULTIPLE_FILTER_TYPES
  185. if ( HwInitializationData->StreamClassVersion != STREAM_CLASS_VERSION_20 ) {
  186. //
  187. // name extension not supplied.
  188. //
  189. pMinidriverInfo->HwInitData.NumNameExtensions = 0;
  190. pMinidriverInfo->HwInitData.NameExtensionArray = NULL;
  191. }
  192. else {
  193. //
  194. // ver20, should have filter extension size
  195. //
  196. if ( 0 == pMinidriverInfo->HwInitData.FilterInstanceExtensionSize ) {
  197. DebugPrint((DebugLevelWarning, "Version 20 driver should not "
  198. " have FilterInstanceExtensionSize 0" ));
  199. pMinidriverInfo->HwInitData.FilterInstanceExtensionSize = 4;
  200. }
  201. }
  202. #endif
  203. //
  204. // initialize the control event for this driver
  205. //
  206. KeInitializeEvent(&pMinidriverInfo->ControlEvent,
  207. SynchronizationEvent,
  208. TRUE);
  209. return STATUS_SUCCESS;
  210. }
  211. NTSTATUS
  212. StreamClassPassThroughIrp (
  213. IN PDEVICE_OBJECT DeviceObject,
  214. IN PIRP Irp
  215. )
  216. /*++
  217. Routine Description:
  218. Pass through all Irps before being multiplexed through KS. If the device
  219. cannot handle the request right now (the device is in a low power state
  220. like D3), queue the Irp and complete it later.
  221. Arguments:
  222. DeviceObject -
  223. The device object
  224. Irp -
  225. The Irp in question
  226. Return Value:
  227. Either STATUS_PENDING or per the KS multiplex
  228. --*/
  229. {
  230. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)
  231. DeviceObject -> DeviceExtension;
  232. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
  233. //
  234. // Block user mode requests here in D3. Queue kernel mode ones.
  235. //
  236. if (Irp -> RequestorMode == UserMode) {
  237. //
  238. // Only do this rigmarole if we look to be outside D0.
  239. //
  240. if (DeviceExtension -> CurrentPowerState != PowerDeviceD0) {
  241. //
  242. // Handle PowerDownUnopened cases specially since they don't
  243. // actually go into D0 until an instance is opened. We cannot
  244. // block an open request in that case.
  245. //
  246. if (DeviceExtension -> RegistryFlags &
  247. DEVICE_REG_FL_POWER_DOWN_CLOSED) {
  248. KIRQL OldIrql;
  249. KeAcquireSpinLock (&DeviceExtension -> PowerLock, &OldIrql);
  250. if (DeviceExtension -> CurrentSystemState ==
  251. PowerSystemWorking &&
  252. DeviceExtension -> CurrentPowerState !=
  253. PowerDeviceD0) {
  254. KeReleaseSpinLock (&DeviceExtension -> PowerLock, OldIrql);
  255. //
  256. // If we got here, the Irp must pass through as transition
  257. // to D0 is keyed off it.
  258. //
  259. return KsDispatchIrp (DeviceObject, Irp);
  260. }
  261. KeReleaseSpinLock (&DeviceExtension -> PowerLock, OldIrql);
  262. //
  263. // At this point, we're not sleeping and not in SystemWorking.
  264. // We're safe to block. Yes -- this might be an open -- and
  265. // yes -- we might transition to SystemWorking before the
  266. // KeWaitForSingleObject; however -- if that's the case,
  267. // this **Notification** event will be signalled by that
  268. // transition and we don't block the D0 key Irp.
  269. //
  270. }
  271. ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
  272. //
  273. // At this point, it appeared that we weren't in D0. Block this
  274. // thread until the device actually wakes. It doesn't matter if
  275. // a state transition happened between the time we check and now
  276. // since this is a notification event.
  277. //
  278. KeWaitForSingleObject (
  279. &DeviceExtension -> BlockPoweredDownEvent,
  280. Executive,
  281. KernelMode,
  282. FALSE,
  283. NULL
  284. );
  285. }
  286. return KsDispatchIrp (DeviceObject, Irp);
  287. }
  288. //
  289. // If we're in a low power state, queue the Irp and redispatch it later.
  290. //
  291. if (DeviceExtension -> CurrentPowerState != PowerDeviceD0) {
  292. //
  293. // Guard against PM changes while we're queueing the Irp. I don't
  294. // want to get pre-empted before adding it to the queue, redispatch
  295. // a bunch of Irps, and THEN have this one queued only to be lost
  296. // until the next power transition.
  297. //
  298. // As an optimization, only grab the spinlock when it looks like we
  299. // care. I don't want to spinlock on every Irp.
  300. //
  301. KIRQL OldIrql;
  302. KeAcquireSpinLock (&DeviceExtension -> PowerLock, &OldIrql);
  303. //
  304. // DEVICE_REG_FL_POWER_DOWN_CLOSED devices will not power up until
  305. // an open happens and they power down when not opened. We cannot
  306. // queue creates on them unless they are not in D0 due to an actual
  307. // S-state transition. This is guarded against racing with an
  308. // S-state transition by the PowerLock spinlock.
  309. //
  310. // NOTE: this will implicitly only allow creates to pass in non-D0
  311. // for these power down closed devices because the only way we are
  312. // in D3 / SystemWorking for these devices is when there are no opens
  313. // currently on the device. Any Irp that comes through here at that
  314. // time will be a create.
  315. //
  316. if (DeviceExtension -> CurrentPowerState != PowerDeviceD0 &&
  317. !((DeviceExtension -> RegistryFlags &
  318. DEVICE_REG_FL_POWER_DOWN_CLOSED) &&
  319. DeviceExtension -> CurrentSystemState == PowerSystemWorking)) {
  320. IoMarkIrpPending (Irp);
  321. KsAddIrpToCancelableQueue (
  322. &DeviceExtension -> PendedIrps,
  323. &DeviceExtension -> PendedIrpsLock,
  324. Irp,
  325. KsListEntryTail,
  326. NULL
  327. );
  328. KeReleaseSpinLock (&DeviceExtension -> PowerLock, OldIrql);
  329. return STATUS_PENDING;
  330. }
  331. KeReleaseSpinLock (&DeviceExtension -> PowerLock, OldIrql);
  332. }
  333. return KsDispatchIrp (DeviceObject, Irp);
  334. }
  335. void
  336. SCRedispatchPendedIrps (
  337. IN PDEVICE_EXTENSION DeviceExtension,
  338. IN BOOLEAN FailRequests
  339. )
  340. /*++
  341. Routine Description:
  342. Redispatch any Irps that were queued as a result of the device being
  343. unavailable.
  344. Arguments:
  345. DeviceExtension -
  346. The device extension
  347. FailRequests -
  348. Indication of whether to fail the requests or redispatch them
  349. to the device.
  350. Return Value:
  351. None
  352. --*/
  353. {
  354. PIRP Irp;
  355. //
  356. // If we redispatch for any reason, allow Irps through.
  357. //
  358. KeSetEvent (
  359. &DeviceExtension -> BlockPoweredDownEvent,
  360. IO_NO_INCREMENT,
  361. FALSE
  362. );
  363. Irp = KsRemoveIrpFromCancelableQueue (
  364. &DeviceExtension -> PendedIrps,
  365. &DeviceExtension -> PendedIrpsLock,
  366. KsListEntryHead,
  367. KsAcquireAndRemove
  368. );
  369. while (Irp) {
  370. //
  371. // If we were to fail the requests instead of redispatching, do
  372. // this for everything but close Irps.
  373. //
  374. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
  375. if (FailRequests &&
  376. IrpSp -> MajorFunction != IRP_MJ_CLOSE) {
  377. Irp -> IoStatus.Status = STATUS_DEVICE_BUSY;
  378. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  379. }
  380. else {
  381. KsDispatchIrp (DeviceExtension -> DeviceObject, Irp);
  382. }
  383. Irp = KsRemoveIrpFromCancelableQueue (
  384. &DeviceExtension -> PendedIrps,
  385. &DeviceExtension -> PendedIrpsLock,
  386. KsListEntryHead,
  387. KsAcquireAndRemove
  388. );
  389. }
  390. }
  391. void
  392. SCSetCurrentDPowerState (
  393. IN PDEVICE_EXTENSION DeviceExtension,
  394. IN DEVICE_POWER_STATE PowerState
  395. )
  396. {
  397. KIRQL OldIrql;
  398. KeAcquireSpinLock (&DeviceExtension->PowerLock, &OldIrql);
  399. //
  400. // On any transition out of D0, block user mode requests until we're back
  401. // in D0.
  402. //
  403. if (PowerState != PowerDeviceD0) {
  404. KeResetEvent (&DeviceExtension->BlockPoweredDownEvent);
  405. }
  406. DeviceExtension->CurrentPowerState = PowerState;
  407. KeReleaseSpinLock (&DeviceExtension->PowerLock, OldIrql);
  408. }
  409. void
  410. SCSetCurrentSPowerState (
  411. IN PDEVICE_EXTENSION DeviceExtension,
  412. IN SYSTEM_POWER_STATE PowerState
  413. )
  414. {
  415. KIRQL OldIrql;
  416. KeAcquireSpinLock (&DeviceExtension->PowerLock, &OldIrql);
  417. DeviceExtension->CurrentSystemState = PowerState;
  418. KeReleaseSpinLock (&DeviceExtension->PowerLock, OldIrql);
  419. }
  420. NTSTATUS
  421. StreamClassPnPAddDevice(
  422. IN PDRIVER_OBJECT DriverObject,
  423. IN PDEVICE_OBJECT PhysicalDeviceObject
  424. )
  425. /*++
  426. Routine Description:
  427. This routine is called to create a new instance of the streaming minidriver
  428. Arguments:
  429. DriverObject - Pointer to our driver object
  430. PhysicalDeviceObject - Pointer to Device Object created by parent
  431. Return Value:
  432. Returns status of the worker routine.
  433. --*/
  434. {
  435. PDEVICE_EXTENSION DeviceExtension;
  436. PAGED_CODE();
  437. //
  438. // call the worker routine and return its status
  439. //
  440. return (StreamClassPnPAddDeviceWorker(DriverObject,
  441. PhysicalDeviceObject,
  442. &DeviceExtension));
  443. }
  444. NTSTATUS
  445. StreamClassPnPAddDeviceWorker(
  446. IN PDRIVER_OBJECT DriverObject,
  447. IN PDEVICE_OBJECT PhysicalDeviceObject,
  448. IN OUT PDEVICE_EXTENSION * ReturnedDeviceExtension
  449. )
  450. /*++
  451. Routine Description:
  452. This routine is the worker for processing the PNP add device call.
  453. Arguments:
  454. DriverObject - Pointer to our driver object
  455. PhysicalDeviceObject - Pointer to Device Object created by parent
  456. ReturnedDeviceExtension - pointer to the minidriver's extension
  457. Return Value:
  458. Status is returned.
  459. --*/
  460. {
  461. PMINIDRIVER_INFORMATION pMinidriverInfo;
  462. PDEVICE_EXTENSION DeviceExtension;
  463. NTSTATUS Status;
  464. PDEVICE_OBJECT DeviceObject,
  465. AttachedPdo;
  466. PAGED_CODE();
  467. DebugPrint((DebugLevelVerbose, "StreamClassAddDevice: enter\n"));
  468. pMinidriverInfo = IoGetDriverObjectExtension(DriverObject,
  469. (PVOID) StreamClassPnP);
  470. if (pMinidriverInfo == NULL) {
  471. DebugPrint((DebugLevelError,
  472. "StreamClassAddDevice: No minidriver info"));
  473. SCLogError((PDEVICE_OBJECT) DriverObject, 0, CODCLASS_NO_MINIDRIVER_INFO, 0x1004);
  474. return (STATUS_DEVICE_DOES_NOT_EXIST);
  475. }
  476. //
  477. // bump the add count in the minidriver object
  478. //
  479. pMinidriverInfo->OpenCount++;
  480. //
  481. // Create our device object with a our STREAM specific device extension
  482. // No need to name it thanks to Plug N Play.
  483. //
  484. Status = IoCreateDevice(
  485. DriverObject,
  486. sizeof(DEVICE_EXTENSION) +
  487. pMinidriverInfo->HwInitData.DeviceExtensionSize,
  488. NULL,
  489. FILE_DEVICE_KS,
  490. FILE_AUTOGENERATED_DEVICE_NAME,
  491. FALSE,
  492. &DeviceObject
  493. );
  494. if (!NT_SUCCESS(Status)) {
  495. return (Status);
  496. }
  497. //
  498. // Attach ourself into the driver stack on top of our parent.
  499. //
  500. AttachedPdo = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
  501. if (!(AttachedPdo)) {
  502. DEBUG_BREAKPOINT();
  503. DebugPrint((DebugLevelFatal, "StreamClassAddDevice: could not attach"));
  504. IoDeleteDevice(DeviceObject);
  505. return (Status);
  506. }
  507. *ReturnedDeviceExtension = DeviceExtension = DeviceObject->DeviceExtension;
  508. (*ReturnedDeviceExtension)->Signature = SIGN_DEVICE_EXTENSION;
  509. (*ReturnedDeviceExtension)->Signature2 = SIGN_DEVICE_EXTENSION;
  510. //
  511. // set the minidriver info in the device extension
  512. //
  513. DeviceExtension->AttachedPdo = AttachedPdo;
  514. //
  515. // set the I/O counter
  516. //
  517. DeviceExtension->OneBasedIoCount = 1;
  518. DeviceExtension->DriverInfo = pMinidriverInfo;
  519. //
  520. // Initialize timer.
  521. //
  522. IoInitializeTimer(DeviceObject, StreamClassTickHandler, NULL);
  523. ///
  524. /// move from start device, we could have child PDO if we start and stop
  525. ///
  526. InitializeListHead(&DeviceExtension->Children);
  527. //
  528. // Moved from StartDevice. We use the control event at Remove_device
  529. // which can come in before the device starts.
  530. //
  531. KeInitializeEvent(&DeviceExtension->ControlEvent,
  532. SynchronizationEvent,
  533. TRUE);
  534. //
  535. // set the current power state to D0
  536. //
  537. DeviceExtension->CurrentPowerState = PowerDeviceD0;
  538. DeviceExtension->CurrentSystemState = PowerSystemWorking;
  539. //
  540. // fill in the minidriver info pointer to the dev extension
  541. //
  542. DeviceExtension->MinidriverData = pMinidriverInfo;
  543. //
  544. // keep this handy
  545. //
  546. DeviceExtension->FilterExtensionSize =
  547. pMinidriverInfo->HwInitData.FilterInstanceExtensionSize;
  548. DeviceExtension->DeviceObject = DeviceObject;
  549. DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
  550. DeviceExtension->HwDeviceExtension = (PVOID) (DeviceExtension + 1);
  551. //
  552. // Initialize the pended Irp list.
  553. //
  554. InitializeListHead (&DeviceExtension -> PendedIrps);
  555. KeInitializeSpinLock (&DeviceExtension -> PendedIrpsLock);
  556. KeInitializeSpinLock (&DeviceExtension -> PowerLock);
  557. KeInitializeEvent (&DeviceExtension -> BlockPoweredDownEvent, NotificationEvent, TRUE);
  558. //
  559. // Mark this object as supporting direct I/O so that I/O system
  560. // will supply mdls in read/write irps.
  561. //
  562. DeviceObject->Flags |= DO_DIRECT_IO;
  563. {
  564. PKSOBJECT_CREATE_ITEM pCreateItems;
  565. PWCHAR *NameInfo;
  566. ULONG i;
  567. ULONG NumberOfFilterTypes;
  568. PFILTER_TYPE_INFO FilterTypeInfo;
  569. //
  570. // build an on-the-fly table of name extensions (including "GLOBAL"),
  571. // from the minidriver's table.
  572. //
  573. InitializeListHead( &DeviceExtension->FilterInstanceList );
  574. NumberOfFilterTypes = pMinidriverInfo->HwInitData.NumNameExtensions;
  575. DeviceExtension->NumberOfNameExtensions = NumberOfFilterTypes;
  576. if ( 0 == NumberOfFilterTypes ) {
  577. NumberOfFilterTypes = 1;
  578. }
  579. DebugPrint((DebugLevelVerbose,
  580. "Sizeof(FILTER_TYPE_INFO)=%x\n",
  581. sizeof(FILTER_TYPE_INFO)));
  582. FilterTypeInfo = ExAllocatePool(NonPagedPool,
  583. (sizeof(FILTER_TYPE_INFO) +
  584. sizeof(KSOBJECT_CREATE_ITEM))*
  585. NumberOfFilterTypes);
  586. if (!(FilterTypeInfo)) {
  587. DebugPrint((DebugLevelFatal,
  588. "StreamClassAddDevice: could not alloc createitems"));
  589. TRAP;
  590. IoDetachDevice(DeviceExtension->AttachedPdo);
  591. IoDeleteDevice(DeviceObject);
  592. return (Status);
  593. }
  594. pCreateItems = (PKSOBJECT_CREATE_ITEM)(FilterTypeInfo+NumberOfFilterTypes);
  595. DebugPrint((DebugLevelVerbose,
  596. "FilterTypeInfo@%x,pCreateItems@%x\n",
  597. FilterTypeInfo,pCreateItems ));
  598. DeviceExtension->NumberOfFilterTypes = NumberOfFilterTypes;
  599. DeviceExtension->FilterTypeInfos = FilterTypeInfo;
  600. //
  601. // first copy the single default create item.
  602. //
  603. ASSERT( sizeof(CreateItems) == sizeof(KSOBJECT_CREATE_ITEM));
  604. RtlCopyMemory(pCreateItems, CreateItems, sizeof (KSOBJECT_CREATE_ITEM));
  605. //
  606. // now construct the rest of the table based on the minidriver's values.
  607. //
  608. NameInfo = pMinidriverInfo->HwInitData.NameExtensionArray;
  609. for (i = 0;
  610. i < DeviceExtension->NumberOfNameExtensions;
  611. i++, NameInfo++) {
  612. LONG StringLength;
  613. StringLength = wcslen(*NameInfo)*sizeof(WCHAR);
  614. pCreateItems[i].ObjectClass.Length = (USHORT)StringLength;
  615. pCreateItems[i].ObjectClass.MaximumLength = (USHORT)(StringLength + sizeof(UNICODE_NULL));
  616. pCreateItems[i].ObjectClass.Buffer = *NameInfo;
  617. pCreateItems[i].Create = FilterDispatchGlobalCreate;
  618. pCreateItems[i].Context = ULongToPtr(i);
  619. pCreateItems[i].SecurityDescriptor = NULL;
  620. pCreateItems[i].Flags = 0;
  621. } // for # createitems
  622. DeviceExtension->CreateItems = pCreateItems;
  623. KsAllocateDeviceHeader(&DeviceExtension->ComObj.DeviceHeader,
  624. i+1,
  625. (PKSOBJECT_CREATE_ITEM) pCreateItems);
  626. }
  627. //
  628. // set the flag indicating whether we need to do synchronization.
  629. //
  630. DeviceExtension->NoSync =
  631. pMinidriverInfo->HwInitData.TurnOffSynchronization;
  632. //
  633. // presuppose we will need synchronization.
  634. //
  635. #if DBG
  636. DeviceExtension->SynchronizeExecution = SCDebugKeSynchronizeExecution;
  637. #else
  638. DeviceExtension->SynchronizeExecution = KeSynchronizeExecution;
  639. #endif
  640. //
  641. // set the synchronized minidriver callin routine vectors
  642. //
  643. DeviceExtension->BeginMinidriverCallin = (PVOID) SCBeginSynchronizedMinidriverCallin;
  644. DeviceExtension->EndMinidriverDeviceCallin = (PVOID) SCEndSynchronizedMinidriverDeviceCallin;
  645. DeviceExtension->EndMinidriverStreamCallin = (PVOID) SCEndSynchronizedMinidriverStreamCallin;
  646. if (DeviceExtension->NoSync) {
  647. //
  648. // we won't do synchronization, so use the dummy sync routine.
  649. //
  650. DeviceExtension->SynchronizeExecution = StreamClassSynchronizeExecution;
  651. DeviceExtension->InterruptObject = (PVOID) DeviceExtension;
  652. //
  653. // set the unsynchronized minidriver callin routine vectors
  654. //
  655. DeviceExtension->BeginMinidriverCallin = (PVOID) SCBeginUnsynchronizedMinidriverCallin;
  656. DeviceExtension->EndMinidriverDeviceCallin = (PVOID) SCEndUnsynchronizedMinidriverDeviceCallin;
  657. DeviceExtension->EndMinidriverStreamCallin = (PVOID) SCEndUnsynchronizedMinidriverStreamCallin;
  658. }
  659. //
  660. // read registry settings for this adapter
  661. //
  662. SCReadRegistryValues(DeviceExtension, PhysicalDeviceObject);
  663. //
  664. // if the device cannot be paged out when closed, turn off this feature
  665. // for the whole driver
  666. //
  667. if (!(DeviceExtension->RegistryFlags & DEVICE_REG_FL_PAGE_CLOSED)) {
  668. pMinidriverInfo->Flags |= DRIVER_FLAGS_NO_PAGEOUT;
  669. }
  670. DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  671. DeviceObject->Flags |= DO_POWER_PAGABLE;
  672. DebugPrint((DebugLevelVerbose, "StreamClassAddDevice: leave\n"));
  673. return (STATUS_SUCCESS);
  674. }
  675. NTSTATUS
  676. StreamClassPnP(
  677. IN PDEVICE_OBJECT DeviceObject,
  678. IN PIRP Irp
  679. )
  680. /*++
  681. Routine Description:
  682. This routine processes the various Plug N Play messages
  683. Arguments:
  684. DeviceObject - Pointer to class device object.
  685. Irp - Pointer to the request packet.
  686. Return Value:
  687. Status is returned.
  688. --*/
  689. {
  690. NTSTATUS Status;
  691. PHW_INITIALIZATION_DATA HwInitData;
  692. PDEVICE_EXTENSION DeviceExtension;
  693. PIO_STACK_LOCATION IrpStack,
  694. NextStack;
  695. BOOLEAN RequestIssued;
  696. DEVICE_CAPABILITIES DeviceCapabilities;
  697. PAGED_CODE();
  698. DeviceExtension = DeviceObject->DeviceExtension;
  699. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  700. //
  701. // check to see if the device is a child
  702. //
  703. DebugPrint((DebugLevelVerbose, "'SCPNP:DevObj=%x,Irp=%x\n",DeviceObject, Irp ));
  704. if (DeviceExtension->Flags & DEVICE_FLAGS_CHILD) {
  705. PCHILD_DEVICE_EXTENSION ChildExtension = (PCHILD_DEVICE_EXTENSION) DeviceExtension;
  706. switch (IrpStack->MinorFunction) {
  707. case IRP_MN_QUERY_INTERFACE:
  708. IoCopyCurrentIrpStackLocationToNext( Irp );
  709. DebugPrint((DebugLevelInfo,
  710. "Child PDO=%x forwards Query_Interface to Parent FDO=%x\n",
  711. DeviceObject,
  712. ChildExtension->ParentDeviceObject));
  713. return (IoCallDriver(ChildExtension->ParentDeviceObject,
  714. Irp));
  715. case IRP_MN_START_DEVICE:
  716. DebugPrint((DebugLevelInfo,
  717. "StartChild DevObj=%x Flags=%x\n"
  718. ,DeviceObject,
  719. ChildExtension->Flags ));
  720. ChildExtension->Flags &= ~DEVICE_FLAGS_CHILD_MARK_DELETE;
  721. Status = STATUS_SUCCESS;
  722. goto done;
  723. case IRP_MN_QUERY_STOP_DEVICE:
  724. case IRP_MN_QUERY_REMOVE_DEVICE:
  725. case IRP_MN_STOP_DEVICE:
  726. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  727. Status = STATUS_SUCCESS;
  728. goto done;
  729. case IRP_MN_QUERY_DEVICE_RELATIONS:
  730. if (IrpStack->Parameters.QueryDeviceRelations.Type ==
  731. TargetDeviceRelation) {
  732. PDEVICE_RELATIONS DeviceRelations = NULL;
  733. DeviceRelations = ExAllocatePool(PagedPool, sizeof(*DeviceRelations));
  734. if (DeviceRelations == NULL) {
  735. Status = STATUS_INSUFFICIENT_RESOURCES;
  736. } else {
  737. //
  738. // TargetDeviceRelation reported PDOs need to be ref'ed.
  739. // PNP will deref this later.
  740. //
  741. ObReferenceObject(DeviceObject);
  742. DeviceRelations->Count = 1;
  743. DeviceRelations->Objects[0] = DeviceObject;
  744. Status = STATUS_SUCCESS;
  745. }
  746. Irp->IoStatus.Information = (ULONG_PTR) DeviceRelations;
  747. } else {
  748. Status = Irp->IoStatus.Status;
  749. }
  750. goto done;
  751. case IRP_MN_REMOVE_DEVICE:
  752. DEBUG_BREAKPOINT();
  753. DebugPrint((DebugLevelInfo,
  754. "Child PDO %x receives REMOVE\n",
  755. DeviceObject ));
  756. //
  757. // remove this extension from the list.
  758. // This is true - pierre tells me that PNP won't reenter me. Verify
  759. // that this is true on NT also.
  760. //
  761. //
  762. // When a PDO first receives this msg, it is usually forwarded
  763. // from FDO. We can't just delete this PDO, but mark it delete
  764. // pending.
  765. //
  766. if ( !(ChildExtension->Flags & DEVICE_FLAGS_CHILD_MARK_DELETE )) {
  767. Status = STATUS_SUCCESS;
  768. goto done;
  769. }
  770. RemoveEntryList(&ChildExtension->ChildExtensionList);
  771. //
  772. // free the device name string if it exists.
  773. //
  774. if (ChildExtension->DeviceName) {
  775. ExFreePool(ChildExtension->DeviceName);
  776. }
  777. //
  778. // delete the PDO
  779. //
  780. IoDeleteDevice(DeviceObject);
  781. Status = STATUS_SUCCESS;
  782. goto done;
  783. case IRP_MN_QUERY_CAPABILITIES:
  784. Status = SCEnumGetCaps(ChildExtension,
  785. IrpStack->Parameters.DeviceCapabilities.Capabilities);
  786. goto done;
  787. case IRP_MN_QUERY_ID:
  788. //
  789. // process the ID query for the child devnode.
  790. //
  791. Status = SCQueryEnumId(DeviceObject,
  792. IrpStack->Parameters.QueryId.IdType,
  793. (PWSTR *) & (Irp->IoStatus.Information));
  794. goto done;
  795. default:
  796. Status = STATUS_NOT_IMPLEMENTED;
  797. done:
  798. Irp->IoStatus.Status = Status;
  799. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  800. return (Status);
  801. } // switch
  802. } // if child
  803. //
  804. // this is not a child device. do adult processing
  805. //
  806. HwInitData = &(DeviceExtension->MinidriverData->HwInitData);
  807. //
  808. // show one more reference to driver.
  809. //
  810. SCReferenceDriver(DeviceExtension);
  811. //
  812. // show one more I/O pending
  813. //
  814. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  815. switch (IrpStack->MinorFunction) {
  816. case IRP_MN_START_DEVICE:
  817. DebugPrint((DebugLevelInfo,
  818. "StreamClassPNP: Start Device %x\n",
  819. DeviceObject));
  820. //
  821. // reinitialize the minidriver's device extension. This is
  822. // necessary as we may receive a start before a remove, such as in
  823. // the case of a PNP rebalance.
  824. //
  825. RtlZeroMemory(DeviceExtension->HwDeviceExtension,
  826. DeviceExtension->DriverInfo->HwInitData.DeviceExtensionSize);
  827. //
  828. // clear the inaccessible flag since we may have stopped the
  829. // device previously.
  830. //
  831. DeviceExtension->Flags &= ~DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  832. //
  833. // The START message gets passed to the PhysicalDeviceObject
  834. // we were give in PnPAddDevice, so call 'er down first.
  835. //
  836. SCCallNextDriver(DeviceExtension, Irp);
  837. //
  838. // get the capabilities of our parent. This info is used for
  839. // controlling the system power state.
  840. //
  841. Status = SCQueryCapabilities(DeviceExtension->AttachedPdo,
  842. &DeviceCapabilities);
  843. ASSERT(NT_SUCCESS(Status));
  844. //
  845. // copy the device state info into the device extension.
  846. //
  847. if (NT_SUCCESS(Status)) {
  848. RtlCopyMemory(&DeviceExtension->DeviceState[0],
  849. &DeviceCapabilities.DeviceState[0],
  850. sizeof(DeviceExtension->DeviceState));
  851. } // if query succeeded
  852. //
  853. // call the worker routine to complete the start processing.
  854. // this routine completes the IRP.
  855. //
  856. Status = SCStartWorker(Irp);
  857. //
  858. // dereference the minidriver which will page it out if possible.
  859. //
  860. SCDereferenceDriver(DeviceExtension);
  861. return (Status);
  862. case IRP_MN_QUERY_DEVICE_RELATIONS:
  863. DebugPrint((DebugLevelInfo,
  864. "StreamClassPNP: Query Relations %x\n",
  865. DeviceObject));
  866. switch (IrpStack->Parameters.QueryDeviceRelations.Type) {
  867. case TargetDeviceRelation:
  868. //
  869. // just call the next driver and fall thru, since we're being
  870. // called for the FDO of a PDO for which we are not the parent.
  871. //
  872. Status = SCCallNextDriver(DeviceExtension, Irp);
  873. break;
  874. case BusRelations:
  875. //
  876. // invoke routine to enumerate any child devices
  877. //
  878. Status = SCEnumerateChildren(DeviceObject,
  879. Irp);
  880. break;
  881. default:
  882. //
  883. // pass down unmodified irp. see bug 282915.
  884. //
  885. Status = SCCallNextDriver(DeviceExtension, Irp);
  886. } // switch
  887. SCDereferenceDriver(DeviceExtension);
  888. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  889. case IRP_MN_QUERY_STOP_DEVICE:
  890. //
  891. // According to DDK, QUERY_STOP and QUERY_REMOVE
  892. // requeire very different repsonses. It's not best to
  893. // handle by the same code, if not erroneous.
  894. //
  895. DebugPrint((DebugLevelInfo,
  896. "StreamClassPNP: Query Stop %x\n",
  897. DeviceObject));
  898. //
  899. // presuppose good status.
  900. //
  901. Irp->IoStatus.Status = STATUS_SUCCESS;
  902. //
  903. // Performace improvement chance: The ControlEvent should be init in AddDevice, so
  904. // that we don't need a check here. This check is not an optimal
  905. // fix for 283057. Refix it and the same in Query_Remove.
  906. //
  907. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) // bug 283057
  908. {
  909. //
  910. // take the event to avoid race
  911. //
  912. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  913. Executive,
  914. KernelMode,
  915. FALSE, // not alertable
  916. NULL);
  917. }
  918. //
  919. // Refer to DDK.
  920. // We must fail a query_stop if any of the following is true.
  921. // a. we are notified with IRP_MN_DEVICE_USAGE_NOTIFICATION
  922. // that the device is in the path of a paging, hiberation
  923. // or crash dump file.
  924. // b. The device's hardware resources cannot be released.
  925. //
  926. // Assuming we are not in the paging path for a. For b, we will
  927. // pass this Irp down to the mini driver to let it have a say.
  928. // We will not reject the Query just because of outstanding opens.
  929. //
  930. //DeviceExtension->Flags |= DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  931. //
  932. // calldown to next driver will be done in the callback.
  933. //
  934. //Status = SCSendUnknownCommand(Irp,
  935. // DeviceExtension,
  936. // SCPNPQueryCallback,
  937. // &RequestIssued);
  938. //
  939. // However, to achieve the noble goal, as everything stands now, is opening
  940. // a whole can of worms. I will keep this old behavior that existed
  941. // since win98. The bug OSR4.1 #98132 said to be a regression is completely
  942. // false. This code is in win98 and win2k. And I have set up win98 to repro
  943. // this behavior to disapprove the regression claim.
  944. //
  945. if (DeviceExtension->NumberOfOpenInstances == 0) {
  946. //
  947. // if there are no open instances, there can be no outstanding
  948. // I/O, so mark the device as going away.
  949. //
  950. DeviceExtension->Flags |= DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  951. SCCallNextDriver(DeviceExtension, Irp);
  952. //
  953. // call the worker routine to complete the query processing.
  954. // this routine calls back the IRP.
  955. //
  956. Status = SCQueryWorker(DeviceObject, Irp);
  957. } else {
  958. //
  959. // the device is open. fail the query.
  960. //
  961. Status = SCCompleteIrp(Irp, STATUS_DEVICE_BUSY, DeviceExtension);
  962. }
  963. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) // bug 283057
  964. {
  965. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  966. }
  967. //
  968. // show one fewer reference to driver.
  969. //
  970. SCDereferenceDriver(DeviceExtension);
  971. return (Status);
  972. case IRP_MN_QUERY_REMOVE_DEVICE:
  973. DebugPrint((DebugLevelInfo,
  974. "StreamClassPNP: Query Remove %x\n",
  975. DeviceObject));
  976. //
  977. // presuppose good status.
  978. //
  979. Irp->IoStatus.Status = STATUS_SUCCESS;
  980. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) // bug 283057
  981. {
  982. //
  983. // take the event to avoid race
  984. //
  985. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  986. Executive,
  987. KernelMode,
  988. FALSE, // not alertable
  989. NULL);
  990. }
  991. //
  992. // According DDK, if there are opens that can't be closed
  993. // we must fail the query.
  994. // So, if there are opened files, just fail the query.
  995. //
  996. if (DeviceExtension->NumberOfOpenInstances == 0) {
  997. //
  998. // if there are no open instances, there can be no outstanding
  999. // I/O, so mark the device as going away.
  1000. //
  1001. DeviceExtension->Flags |= DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  1002. SCCallNextDriver(DeviceExtension, Irp);
  1003. //
  1004. // call the worker routine to complete the query processing.
  1005. // this routine calls back the IRP.
  1006. //
  1007. Status = SCQueryWorker(DeviceObject, Irp);
  1008. } else {
  1009. //
  1010. // the device is open. fail the query.
  1011. //
  1012. Status = SCCompleteIrp(Irp, STATUS_DEVICE_BUSY, DeviceExtension);
  1013. }
  1014. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) // bug 283057
  1015. {
  1016. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1017. }
  1018. //
  1019. // show one fewer reference to driver.
  1020. //
  1021. SCDereferenceDriver(DeviceExtension);
  1022. return (Status);
  1023. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1024. //
  1025. // clear the inaccessible flag and call'er down
  1026. //
  1027. DebugPrint((DebugLevelInfo,
  1028. "StreamClassPnP: MN_CANCEL_REMOVE %x\n",
  1029. DeviceObject));
  1030. DeviceExtension->Flags &= ~DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  1031. //
  1032. // call next driver
  1033. //
  1034. SCCallNextDriver(DeviceExtension, Irp);
  1035. //
  1036. // dereference the driver which will page out if possible.
  1037. //
  1038. SCDereferenceDriver(DeviceExtension);
  1039. return (SCCompleteIrp(Irp, STATUS_SUCCESS, DeviceExtension));
  1040. case IRP_MN_CANCEL_STOP_DEVICE:
  1041. //
  1042. // clear the inaccessible flag and call'er down
  1043. //
  1044. DebugPrint((DebugLevelInfo,
  1045. "StreamClassPnP: MN_CANCEL_STOP %x\n",
  1046. DeviceObject));
  1047. DeviceExtension->Flags &= ~DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  1048. //
  1049. // call next driver
  1050. //
  1051. SCCallNextDriver(DeviceExtension, Irp);
  1052. //
  1053. // dereference the driver which will page out if possible.
  1054. //
  1055. SCDereferenceDriver(DeviceExtension);
  1056. return (SCCompleteIrp(Irp, STATUS_SUCCESS, DeviceExtension));
  1057. break;
  1058. case IRP_MN_STOP_DEVICE:
  1059. DebugPrint((DebugLevelInfo,
  1060. "StreamClassPnP: MN_STOP_DEVICE %x\n",
  1061. DeviceObject));
  1062. //
  1063. // presuppose good status. if we have actually started the device,
  1064. // stop it now.
  1065. //
  1066. Status = STATUS_SUCCESS;
  1067. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) {
  1068. //
  1069. // call routine to uninitialize minidriver
  1070. //
  1071. Status = SCUninitializeMinidriver(DeviceObject, Irp);
  1072. //
  1073. // now call the next driver in the stack with the IRP, which will
  1074. // determine the final status.
  1075. //
  1076. } // if started
  1077. if (NT_SUCCESS(Status)) {
  1078. Status = SCCallNextDriver(DeviceExtension, Irp);
  1079. }
  1080. //
  1081. // Fail everything that's been queued.
  1082. //
  1083. SCRedispatchPendedIrps (DeviceExtension, TRUE);
  1084. //
  1085. // call routine to complete the IRP
  1086. //
  1087. SCCompleteIrp(Irp, Status, DeviceExtension);
  1088. //
  1089. // show one less reference to driver.
  1090. //
  1091. SCDereferenceDriver(DeviceExtension);
  1092. return (Status);
  1093. case IRP_MN_REMOVE_DEVICE:
  1094. DebugPrint((DebugLevelInfo,
  1095. "StreamClassPnP: MN_REMOVE_DEVICE %x\n",
  1096. DeviceObject));
  1097. //
  1098. // handle a "suprise" style removal if we have not been stopped.
  1099. // set success status in case we have already stopped.
  1100. //
  1101. Status = STATUS_SUCCESS;
  1102. if ( DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED ) {
  1103. SCSendSurpriseNotification(DeviceExtension, Irp);
  1104. Status = SCUninitializeMinidriver(DeviceObject, Irp);
  1105. }
  1106. if (NT_SUCCESS(Status)) {
  1107. Status = SCCallNextDriver(DeviceExtension, Irp);
  1108. }
  1109. //
  1110. // Fail any pended Irps.
  1111. //
  1112. SCRedispatchPendedIrps (DeviceExtension, TRUE);
  1113. //
  1114. // call routine to complete the IRP
  1115. //
  1116. Status = SCCompleteIrp(Irp, Status, DeviceExtension);
  1117. //
  1118. // dereference the driver
  1119. //
  1120. SCDereferenceDriver(DeviceExtension);
  1121. if (NT_SUCCESS(Status)) {
  1122. //
  1123. // free the device header.
  1124. //
  1125. if ( NULL != DeviceExtension->ComObj.DeviceHeader ) {
  1126. KsFreeDeviceHeader(DeviceExtension->ComObj.DeviceHeader);
  1127. }
  1128. //
  1129. // take the event to avoid race
  1130. //
  1131. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  1132. Executive,
  1133. KernelMode,
  1134. FALSE, // not alertable
  1135. NULL);
  1136. //
  1137. // detach from the PDO now if the opened file count is zero.
  1138. //
  1139. if (DeviceExtension->NumberOfOpenInstances == 0) {
  1140. DebugPrint((DebugLevelInfo,
  1141. "SCPNP: detaching %x from %x\n",
  1142. DeviceObject,
  1143. DeviceExtension->AttachedPdo));
  1144. if ( NULL != DeviceExtension->AttachedPdo ) {
  1145. //
  1146. // detach could happen at close, check before leap.
  1147. // event is taken, check is safe.
  1148. //
  1149. IoDetachDevice(DeviceExtension->AttachedPdo);
  1150. DeviceExtension->AttachedPdo = NULL;
  1151. }
  1152. ///
  1153. /// mark child pdos if any
  1154. ///
  1155. {
  1156. PLIST_ENTRY Node;
  1157. PCHILD_DEVICE_EXTENSION ChildExtension;
  1158. while (!IsListEmpty( &DeviceExtension->Children )) {
  1159. Node = RemoveHeadList( &DeviceExtension->Children );
  1160. ChildExtension = CONTAINING_RECORD(Node,
  1161. CHILD_DEVICE_EXTENSION,
  1162. ChildExtensionList);
  1163. DebugPrint((DebugLevelInfo,
  1164. "Marking and delete childpdo Extension %p\n",
  1165. ChildExtension));
  1166. ChildExtension->Flags |= DEVICE_FLAGS_CHILD_MARK_DELETE;
  1167. IoDeleteDevice(ChildExtension->ChildDeviceObject);
  1168. }
  1169. }
  1170. }
  1171. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1172. //
  1173. // delete the device
  1174. //
  1175. // A dev could be stop and start. Free stuff allocated
  1176. // at AddDevice.
  1177. // FilterTypeInfos includes FilterTypeInfos CreateItems.
  1178. // Free these here at remove_device
  1179. if ( DeviceExtension->FilterTypeInfos ) {
  1180. ExFreePool( DeviceExtension->FilterTypeInfos );
  1181. DeviceExtension->FilterTypeInfos = NULL;
  1182. DeviceExtension->CreateItems = NULL;
  1183. }
  1184. IoDeleteDevice(DeviceExtension->DeviceObject);
  1185. }
  1186. return (Status);
  1187. case IRP_MN_SURPRISE_REMOVAL:
  1188. DebugPrint((DebugLevelInfo,
  1189. "StreamClassPnP: MN_SURPRISE_REMOVAL %x\n",
  1190. DeviceObject));
  1191. //
  1192. // handle a "suprise" style removal if we have not been stopped.
  1193. // set success status in case we have already stopped.
  1194. //
  1195. Status = STATUS_SUCCESS;
  1196. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) {
  1197. SCSendSurpriseNotification(DeviceExtension, Irp);
  1198. Status = SCUninitializeMinidriver(DeviceObject, Irp);
  1199. }
  1200. //
  1201. // forward the surprise removal IRP to the next layer, regardless of
  1202. // our status.
  1203. //
  1204. Status = SCCallNextDriver(DeviceExtension, Irp);
  1205. //
  1206. // call routine to complete the IRP
  1207. //
  1208. Status = SCCompleteIrp(Irp, Status, DeviceExtension);
  1209. //
  1210. // dereference the driver
  1211. //
  1212. SCDereferenceDriver(DeviceExtension);
  1213. //
  1214. // indicate that we received an "NT style" surprise removal
  1215. // notification
  1216. // so that we won't do the "memphis style" behavior on filter close.
  1217. //
  1218. DeviceExtension->Flags |= DEVICE_FLAGS_SURPRISE_REMOVE_RECEIVED;
  1219. return (Status);
  1220. case IRP_MN_QUERY_CAPABILITIES:
  1221. DebugPrint((DebugLevelInfo,
  1222. "StreamClassPNP: Query Caps\n",
  1223. DeviceObject));
  1224. //
  1225. // indicate that suprise removal is OK after calling request down
  1226. // to next level.
  1227. //
  1228. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1229. Status = SCCallNextDriver(DeviceExtension, Irp);
  1230. IrpStack->Parameters.DeviceCapabilities.
  1231. Capabilities->SurpriseRemovalOK = TRUE;
  1232. Status = SCCompleteIrp(Irp, Status, DeviceExtension);
  1233. //
  1234. // show one less reference to driver.
  1235. //
  1236. SCDereferenceDriver(DeviceExtension);
  1237. return (Status);
  1238. default:
  1239. DebugPrint((DebugLevelInfo,
  1240. "StreamPnP: unknown function\n",
  1241. DeviceObject));
  1242. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) {
  1243. //
  1244. // unknown function, so call it down to the minidriver as such.
  1245. // this routine completes the IRP if we are able to issue the
  1246. // request.
  1247. //
  1248. Status = SCSendUnknownCommand(Irp,
  1249. DeviceExtension,
  1250. SCUnknownPNPCallback,
  1251. &RequestIssued);
  1252. if (!RequestIssued) {
  1253. //
  1254. // could not send the unknown command down. show one fewer
  1255. // I/O
  1256. // pending and fall thru to generic handler.
  1257. //
  1258. DEBUG_BREAKPOINT();
  1259. Status = SCCompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, DeviceExtension);
  1260. }
  1261. }
  1262. else {
  1263. //
  1264. // call next driver
  1265. //
  1266. Status = SCCallNextDriver(DeviceExtension, Irp);
  1267. SCCompleteIrp(Irp, Status, DeviceExtension);
  1268. } // if started
  1269. //
  1270. // dereference the driver
  1271. //
  1272. SCDereferenceDriver(DeviceExtension);
  1273. return (Status);
  1274. }
  1275. }
  1276. NTSTATUS
  1277. StreamClassCleanup (
  1278. IN PDEVICE_OBJECT DeviceObject,
  1279. IN PIRP Irp
  1280. )
  1281. /*++
  1282. Routine Description:
  1283. TODO: Remove this once KS can multiplex CLEANUP Irps.
  1284. Manual multiplex of cleanup Irps. Note that FsContext is NOT NECESSARILY
  1285. OURS. The cookie check is done to check for streams until KS handles
  1286. this correctly.
  1287. Arguments:
  1288. DeviceObject -
  1289. The device object
  1290. Irp -
  1291. The CLEANUP irp
  1292. Return Value:
  1293. The Irp return code set appropriately.
  1294. --*/
  1295. {
  1296. PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation (Irp);
  1297. PCOOKIE_CHECK CookieCheck =
  1298. (PCOOKIE_CHECK) IoStack -> FileObject -> FsContext;
  1299. //
  1300. // Check for the cookie. If it's not there or the context is not there,
  1301. // bail.
  1302. //
  1303. if (CookieCheck &&
  1304. CookieCheck -> PossibleCookie == STREAM_OBJECT_COOKIE) {
  1305. return StreamDispatchCleanup (DeviceObject, Irp);
  1306. }
  1307. Irp -> IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1308. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1309. return STATUS_INVALID_DEVICE_REQUEST;
  1310. }
  1311. NTSTATUS
  1312. SciQuerySystemPowerHiberCallback(
  1313. IN PSTREAM_REQUEST_BLOCK SRB
  1314. )
  1315. /*++
  1316. Routine Description:
  1317. Process the completion of an unknown Power command for query system hiber
  1318. Arguments:
  1319. SRB - address of the completed SRB
  1320. Return Value:
  1321. None.
  1322. --*/
  1323. {
  1324. PDEVICE_EXTENSION DeviceExtension =
  1325. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  1326. PIRP Irp = SRB->HwSRB.Irp;
  1327. NTSTATUS Status, MiniStatus;
  1328. PAGED_CODE();
  1329. //
  1330. // delete the SRB since we are done with it
  1331. //
  1332. MiniStatus = SCDequeueAndDeleteSrb(SRB);
  1333. if ( STATUS_NOT_IMPLEMENTED == MiniStatus ) {
  1334. MiniStatus = STATUS_NOT_SUPPORTED;
  1335. }
  1336. if ( STATUS_NOT_SUPPORTED == MiniStatus ) {
  1337. //
  1338. // not surprising, old driver doesn't handle this.
  1339. //
  1340. if ( 0 != (DeviceExtension->RegistryFlags &
  1341. DRIVER_USES_SWENUM_TO_LOAD ) ||
  1342. 0 != (DeviceExtension->RegistryFlags &
  1343. DEVICE_REG_FL_OK_TO_HIBERNATE ) ) {
  1344. //
  1345. // default for swenum driver is OK to hiber
  1346. // No hiber for other drivers unless explicitly
  1347. // say so in the registry
  1348. //
  1349. DebugPrint((DebugLevelInfo,
  1350. "%ws Allow hibernation!\n",
  1351. DeviceExtension->DeviceObject->
  1352. DriverObject->DriverName.Buffer));
  1353. MiniStatus = STATUS_SUCCESS;
  1354. }
  1355. else {
  1356. //
  1357. // for others, disallow
  1358. //
  1359. DebugPrint((DebugLevelInfo,
  1360. "%ws Disallow hibernation!\n",
  1361. DeviceExtension->DeviceObject->
  1362. DriverObject->DriverName.Buffer));
  1363. MiniStatus = STATUS_DEVICE_BUSY;
  1364. }
  1365. }
  1366. if ( NT_SUCCESS( MiniStatus )) {
  1367. //
  1368. // it is not explicitly failed by the mini driver pass down the Irp
  1369. //
  1370. Status = SCCallNextDriver(DeviceExtension, Irp);
  1371. if ( Status == STATUS_NOT_SUPPORTED ) {
  1372. //
  1373. // no one below knows/cares. Use our mini status
  1374. //
  1375. Status = MiniStatus;
  1376. }
  1377. }
  1378. else {
  1379. //
  1380. // mini driver explicitly failed this
  1381. //
  1382. Status = MiniStatus;
  1383. }
  1384. //
  1385. // complete the IRP with the final status
  1386. //
  1387. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  1388. }
  1389. NTSTATUS
  1390. SCSysWakeCallNextDriver(
  1391. IN PDEVICE_EXTENSION DeviceExtension,
  1392. IN PIRP Irp
  1393. )
  1394. /*++
  1395. Routine Description:
  1396. This is called when we receive a wake up system Irp which we can't not block.
  1397. If we block, the lower driver might queue this Irp ( such as acpi ) and the
  1398. po system could be dead locked. In theory, we should complete the requested
  1399. D Irp and use the status as the status for the SWake Irp. In practise, we can
  1400. just send down this Irp assuming all is well. In the unlikely condition, the SWake
  1401. Irp was unsuccessful, the D Irp will fail. But there is really nothing we can
  1402. improve or nothing will get worse.
  1403. Arguments:
  1404. DeviceExtension - pointer to device extension
  1405. Irp - pointer to IRP
  1406. Return Value:
  1407. none.
  1408. --*/
  1409. {
  1410. NTSTATUS Status;
  1411. //
  1412. // call down and be done with this SWake Irp; the D Irp completion routine
  1413. // should not complete this SWake Irp.
  1414. //
  1415. PoStartNextPowerIrp( Irp );
  1416. IoSkipCurrentIrpStackLocation( Irp );
  1417. Status = PoCallDriver(DeviceExtension->AttachedPdo, Irp);
  1418. //
  1419. // If we get an error, we complete this S irp in the caller with the error.
  1420. //
  1421. return (Status);
  1422. }
  1423. VOID
  1424. SCDevIrpCompletionWorker(
  1425. PIRP pIrp
  1426. )
  1427. /*++
  1428. Description:
  1429. This is the worker routine for Device Power Wakeup Irp which schedule
  1430. a workitem to continue the work at the Irp on its way up. We
  1431. need to schedule this work because the completion routine could be called at
  1432. DISPATCH_LEVEL. We schedule the workitem so we can safely take
  1433. control event and call to our mini driver.
  1434. IRQL < DISPATCH_LEVEL
  1435. Parameter:
  1436. pIrp: the original Irp which we have marked MORE_PROCEESING_REQUIRED.
  1437. We will complete it after we call our mini driver.
  1438. Return:
  1439. None.
  1440. --*/
  1441. {
  1442. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(pIrp);
  1443. PDEVICE_EXTENSION DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
  1444. BOOLEAN RequestIssued;
  1445. NTSTATUS Status;
  1446. PAGED_CODE();
  1447. //
  1448. // take the event to avoid race
  1449. //
  1450. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  1451. Executive,
  1452. KernelMode,
  1453. FALSE, // not alertable
  1454. NULL);
  1455. //
  1456. // send a set power SRB to the device.
  1457. // additional processing will be done by the callback
  1458. // procedure. This routine completes the IRP if it is able
  1459. // to issue the request.
  1460. //
  1461. Status = SCSubmitRequest(SRB_CHANGE_POWER_STATE,
  1462. (PVOID) PowerDeviceD0,
  1463. 0,
  1464. SCPowerCallback,
  1465. DeviceExtension,
  1466. NULL,
  1467. NULL,
  1468. pIrp,
  1469. &RequestIssued,
  1470. &DeviceExtension->PendingQueue,
  1471. (PVOID) DeviceExtension->
  1472. MinidriverData->HwInitData.
  1473. HwReceivePacket );
  1474. if (!RequestIssued) {
  1475. //
  1476. // If we fail to issue SRB, the SCPowerCallback won't happen which is
  1477. // supposed to call PoStartNextPowerIrp().
  1478. // We need to call PoStartNextPowerIrp() here;
  1479. //
  1480. PoStartNextPowerIrp( pIrp );
  1481. Status = SCCompleteIrp(pIrp, STATUS_INSUFFICIENT_RESOURCES, DeviceExtension);
  1482. }
  1483. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1484. //
  1485. // Redispatch any Irps pended because of lower power states.
  1486. //
  1487. SCRedispatchPendedIrps (DeviceExtension, FALSE);
  1488. //
  1489. // show one fewer reference to driver.
  1490. //
  1491. SCDereferenceDriver(DeviceExtension);
  1492. return;
  1493. }
  1494. NTSTATUS
  1495. SCDevWakeCompletionRoutine(
  1496. IN PDEVICE_OBJECT DeviceObject,
  1497. IN PIRP Irp,
  1498. IN PVOID pContext
  1499. )
  1500. /*++
  1501. Routine Description:
  1502. This routine is for Device wakeup Irp completion.
  1503. We sent it to NextDeviceObject first. Now this is back.
  1504. We process out work for the mini driver. We might be called
  1505. at Dispatch_LEVEL.
  1506. IRQL <= DISPATCH_LEVEL
  1507. Arguments:
  1508. DriverObject - Pointer to driver object created by system.
  1509. Irp - Irp that just completed
  1510. pContext - the context
  1511. Return Value:
  1512. None.
  1513. --*/
  1514. {
  1515. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  1516. //
  1517. // Schedule a work item in case we are called at DISPATCH_LEVEL
  1518. // note that we can use a global Devcice Power item since we have
  1519. // not yet issued the PoNextPowerIrp call which is called at the callback
  1520. // of the power Srb
  1521. //
  1522. ExInitializeWorkItem(&DeviceExtension->DevIrpCompletionWorkItem,
  1523. SCDevIrpCompletionWorker,
  1524. Irp);
  1525. ExQueueWorkItem(&DeviceExtension->DevIrpCompletionWorkItem,
  1526. DelayedWorkQueue);
  1527. return STATUS_MORE_PROCESSING_REQUIRED;
  1528. }
  1529. NTSTATUS
  1530. SCDevWakeCallNextDriver(
  1531. IN PDEVICE_EXTENSION DeviceExtension,
  1532. IN PIRP Irp
  1533. )
  1534. /*++
  1535. Routine Description:
  1536. Receive device wake up Irp. Need to send down the Irp 1st.
  1537. Also this can't be synchronous. We could dead lock, if we do this
  1538. synchronously. Send it down without waiting. Process it when it compltes
  1539. back to us.
  1540. Arguments:
  1541. DeviceExtension - pointer to device extension
  1542. Irp - pointer to IRP
  1543. Return Value:
  1544. none.
  1545. --*/
  1546. {
  1547. NTSTATUS Status;
  1548. IoCopyCurrentIrpStackLocationToNext( Irp );
  1549. IoSetCompletionRoutine(Irp,
  1550. SCDevWakeCompletionRoutine,
  1551. NULL,
  1552. TRUE,
  1553. TRUE,
  1554. TRUE);
  1555. //
  1556. // We are to schedule a workitem to complete the work
  1557. // in the completion routin. Mark the Irp pending
  1558. //
  1559. IoMarkIrpPending( Irp );
  1560. Status = PoCallDriver(DeviceExtension->AttachedPdo, Irp);
  1561. ASSERT( NT_SUCCESS( Status ));
  1562. return STATUS_PENDING;
  1563. }
  1564. NTSTATUS
  1565. StreamClassPower(
  1566. IN PDEVICE_OBJECT DeviceObject,
  1567. IN PIRP Irp
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. This routine processes the various Plug N Play messages
  1572. Arguments:
  1573. DeviceObject - Pointer to class device object.
  1574. Irp - Pointer to the request packet.
  1575. Return Value:
  1576. Status is returned.
  1577. --*/
  1578. {
  1579. NTSTATUS Status;
  1580. PHW_INITIALIZATION_DATA HwInitData;
  1581. PDEVICE_EXTENSION DeviceExtension;
  1582. PIO_STACK_LOCATION IrpStack;
  1583. BOOLEAN RequestIssued;
  1584. PAGED_CODE();
  1585. DeviceExtension = DeviceObject->DeviceExtension;
  1586. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1587. if (DeviceExtension->Flags & DEVICE_FLAGS_CHILD) {
  1588. switch (IrpStack->MinorFunction) {
  1589. default:
  1590. PoStartNextPowerIrp( Irp ); // shut down would bugcheck w/o this
  1591. Status = Irp->IoStatus.Status;
  1592. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1593. return (Status);
  1594. }
  1595. } // if child
  1596. //
  1597. // if the device is stopped, just call the power message down to the next
  1598. // level.
  1599. //
  1600. if (DeviceExtension->Flags & DEVICE_FLAGS_DEVICE_INACCESSIBLE) {
  1601. Status = SCCallNextDriver(DeviceExtension, Irp);
  1602. PoStartNextPowerIrp( Irp );
  1603. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1604. return (Status);
  1605. } // if inaccessible
  1606. HwInitData = &(DeviceExtension->MinidriverData->HwInitData);
  1607. //
  1608. // show one more reference to driver.
  1609. //
  1610. SCReferenceDriver(DeviceExtension);
  1611. //
  1612. // show one more I/O pending
  1613. //
  1614. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  1615. switch (IrpStack->MinorFunction) {
  1616. case IRP_MN_QUERY_POWER:
  1617. //
  1618. // presuppose good status.
  1619. //
  1620. Irp->IoStatus.Status = STATUS_SUCCESS;
  1621. switch (IrpStack->Parameters.Power.Type) {
  1622. case SystemPowerState:
  1623. DebugPrint((DebugLevelInfo,
  1624. "Query_power S[%d]\n",
  1625. IrpStack->Parameters.Power.State.SystemState));
  1626. //
  1627. // some minidrivers want to not suspend if their pins are in
  1628. // the RUN state. check for this case.
  1629. //
  1630. DebugPrint((DebugLevelInfo,
  1631. "POWER Query_Power DevObj %x RegFlags=%x SysState=%x\n",
  1632. DeviceObject,
  1633. DeviceExtension->RegistryFlags,
  1634. IrpStack->Parameters.Power.State.SystemState));
  1635. #ifdef WIN9X_STREAM
  1636. if ( PowerSystemHibernate ==
  1637. IrpStack->Parameters.Power.State.SystemState ) {
  1638. //
  1639. // Power query to hibernation state. Many existing drivers
  1640. // are hibernation unaware. We will reject this query. Or
  1641. // drivers' devices woken up from hiber will be in un-init
  1642. // state. Some drivers would fault. Lucky others do not but
  1643. // would not work. For less of the evil, we try to protect
  1644. // the system by rejecting the hibernation. Note though, this
  1645. // chance to reject is not available with forced ( low battery
  1646. // or user force ) hibernation.
  1647. //
  1648. //
  1649. // unknown function, so call it down to the minidriver as such.
  1650. // this routine completes the IRP if it is able to issue the request.
  1651. //
  1652. Status = SCSendUnknownCommand(Irp,
  1653. DeviceExtension,
  1654. SciQuerySystemPowerHiberCallback,
  1655. &RequestIssued);
  1656. if (!RequestIssued) {
  1657. //
  1658. // could not send the unknown command down. show one fewer I/O
  1659. // pending and fall thru to generic handler.
  1660. //
  1661. PoStartNextPowerIrp(Irp);
  1662. Status = SCCompleteIrp(Irp,
  1663. STATUS_INSUFFICIENT_RESOURCES,
  1664. DeviceExtension);
  1665. }
  1666. //
  1667. // dereference the driver
  1668. //
  1669. SCDereferenceDriver(DeviceExtension);
  1670. return Status;
  1671. } else
  1672. #endif //WIN9X_STREAM
  1673. if (DeviceExtension->RegistryFlags &
  1674. DEVICE_REG_FL_NO_SUSPEND_IF_RUNNING) {
  1675. PFILTER_INSTANCE FilterInstance;
  1676. KIRQL Irql;
  1677. PLIST_ENTRY FilterEntry,
  1678. FilterListHead;
  1679. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  1680. FilterListHead = FilterEntry = &DeviceExtension->FilterInstanceList;
  1681. while (FilterEntry->Flink != FilterListHead) {
  1682. FilterEntry = FilterEntry->Flink;
  1683. //
  1684. // follow the link to the instance
  1685. //
  1686. FilterInstance = CONTAINING_RECORD(FilterEntry,
  1687. FILTER_INSTANCE,
  1688. NextFilterInstance);
  1689. if (SCCheckIfStreamsRunning(FilterInstance)) {
  1690. DebugPrint((DebugLevelInfo,
  1691. "POWER Query_Power FilterInstance %x busy\n",
  1692. FilterInstance ));
  1693. Status = STATUS_DEVICE_BUSY;
  1694. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  1695. goto QuerySystemSuspendDone;
  1696. } // if streams running
  1697. //
  1698. // get the list entry for the next instance
  1699. //
  1700. FilterEntry = &FilterInstance->NextFilterInstance;
  1701. } // while local filter instances
  1702. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  1703. } // if no suspend if running
  1704. Status = SCCallNextDriver(DeviceExtension, Irp);
  1705. QuerySystemSuspendDone:
  1706. //
  1707. // indicate we're ready for next power irp
  1708. //
  1709. PoStartNextPowerIrp(Irp);
  1710. //
  1711. // show one fewer reference to driver.
  1712. //
  1713. SCDereferenceDriver(DeviceExtension);
  1714. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  1715. case DevicePowerState:
  1716. switch (IrpStack->Parameters.Power.State.DeviceState) {
  1717. default:
  1718. case PowerDeviceD2:
  1719. case PowerDeviceD3:
  1720. //
  1721. // check to see if the device is opened.
  1722. //
  1723. if (!DeviceExtension->NumberOfOpenInstances) {
  1724. //
  1725. // show pending status and call next driver without a
  1726. // completion
  1727. // handler
  1728. //
  1729. Status = SCCallNextDriver(DeviceExtension, Irp);
  1730. } else {
  1731. //
  1732. // the device is opened. Don't do the power down.
  1733. //
  1734. Status = STATUS_DEVICE_BUSY;
  1735. }
  1736. PoStartNextPowerIrp(Irp);
  1737. //
  1738. // show one fewer reference to driver.
  1739. //
  1740. SCDereferenceDriver(DeviceExtension);
  1741. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  1742. }
  1743. default:
  1744. //
  1745. // unknown power type: indicate we're ready for next power irp
  1746. //
  1747. PoStartNextPowerIrp(Irp);
  1748. //
  1749. // show one fewer reference to driver.
  1750. //
  1751. SCDereferenceDriver(DeviceExtension);
  1752. return (SCCompleteIrp(Irp, STATUS_NOT_SUPPORTED, DeviceExtension));
  1753. } // switch minorfunc
  1754. break;
  1755. case IRP_MN_SET_POWER:
  1756. //
  1757. // presuppose good status.
  1758. //
  1759. Irp->IoStatus.Status = STATUS_SUCCESS;
  1760. switch (IrpStack->Parameters.Power.Type) {
  1761. case SystemPowerState:
  1762. if (DeviceExtension->Flags & DEVICE_FLAGS_PNP_STARTED) {
  1763. //
  1764. // Only care if the device is started.
  1765. // We depend on DE->ControlEvent being inited at SCStartWorker.
  1766. //
  1767. POWER_STATE PowerState;
  1768. SYSTEM_POWER_STATE RequestedSysState =
  1769. IrpStack->Parameters.Power.State.SystemState;
  1770. //
  1771. // look up the correct device power state in the table
  1772. //
  1773. PowerState.DeviceState =
  1774. DeviceExtension->DeviceState[RequestedSysState];
  1775. DebugPrint((DebugLevelInfo,
  1776. "SCPower: DevObj %x S[%d]->D[%d]\n",
  1777. DeviceExtension->PhysicalDeviceObject,
  1778. RequestedSysState,
  1779. PowerState.DeviceState));
  1780. //
  1781. // if this is a wakeup, we must first pass the request down
  1782. // to the PDO for preprocessing.
  1783. //
  1784. if (RequestedSysState == PowerSystemWorking) {
  1785. //
  1786. // Send down this S power IRP to the next layer and be
  1787. // done with it, except requesting D Irp in the following
  1788. // condition that related to the S Irp but does not reference
  1789. // it any further.
  1790. //
  1791. Status = SCSysWakeCallNextDriver(DeviceExtension, Irp);
  1792. ASSERT( NT_SUCCESS( Status ) );
  1793. //
  1794. // Nullify Irp, so at the D Irp completion, we dont complete this Irp.
  1795. // Be careful not to touch the Irp afterwards.
  1796. //
  1797. InterlockedDecrement(&DeviceExtension->OneBasedIoCount);
  1798. Irp = NULL;
  1799. }
  1800. //
  1801. // Mark the S State.
  1802. //
  1803. SCSetCurrentSPowerState (DeviceExtension, RequestedSysState);
  1804. //
  1805. // take the event to avoid race.
  1806. //
  1807. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  1808. Executive,
  1809. KernelMode,
  1810. FALSE, // not alertable
  1811. NULL);
  1812. if ((RequestedSysState == PowerSystemWorking) &&
  1813. (!DeviceExtension->NumberOfOpenInstances) &&
  1814. (DeviceExtension->RegistryFlags & DEVICE_REG_FL_POWER_DOWN_CLOSED)) {
  1815. // We are awakening from a suspend.
  1816. // we don't want to wake up the device at this
  1817. // point. We'll just wait til the first open
  1818. // occurs to wake it up.
  1819. //
  1820. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1821. //
  1822. // Since there are no open instances, there can only be
  1823. // pended creates. Since we key device powerup off the
  1824. // creates, redispatch them now if there are any.
  1825. //
  1826. SCRedispatchPendedIrps (DeviceExtension, FALSE);
  1827. return Status;
  1828. } else { // if state = working
  1829. //
  1830. // now send down a set power based on this info.
  1831. //
  1832. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1833. //
  1834. // per Pierre and Lonny, we should use D3 instead of the
  1835. // mapped array value, as the array value is always D0!
  1836. // of course, they'll change this next week...
  1837. //
  1838. if (RequestedSysState != PowerSystemWorking) {
  1839. PowerState.DeviceState = PowerDeviceD3;
  1840. }
  1841. DebugPrint((DebugLevelInfo,
  1842. "SCPower: PoRequestPowerIrp %x to state=%d\n",
  1843. DeviceExtension->PhysicalDeviceObject,
  1844. PowerState));
  1845. //
  1846. // when (RequestedSysState == PowerSystemWorking) but
  1847. // (DeviceExtension->NumberOfOpenInstances) ||
  1848. // !(DeviceExtension->RegistryFlags & DEVICE_REG_FL_POWER_DOWN_CLOSED)
  1849. // we come here with Irp==NULL. Don't touch NULL Irp.
  1850. //
  1851. if ( NULL != Irp ) {
  1852. IoMarkIrpPending (Irp);
  1853. }
  1854. Status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
  1855. IRP_MN_SET_POWER,
  1856. PowerState,
  1857. SCSynchPowerCompletionRoutine,
  1858. Irp, // when NULL, it tells callback don't bother.
  1859. NULL);
  1860. if (!NT_SUCCESS (Status) && NULL != Irp ) {
  1861. PoStartNextPowerIrp (Irp);
  1862. SCCompleteIrp (Irp, Status, DeviceExtension);
  1863. }
  1864. //
  1865. // The Irp has been marked pending. We MUST return
  1866. // pending. Error case will complete the Irp with the
  1867. // appropriate status.
  1868. //
  1869. return STATUS_PENDING;
  1870. } // if system state working
  1871. //
  1872. // if this is a NOT wakeup, we must first pass the request
  1873. // down to the PDO for postprocessing.
  1874. //
  1875. if (RequestedSysState != PowerSystemWorking) {
  1876. //
  1877. // send down the power IRP to the next layer. this
  1878. // routine
  1879. // has a completion routine which does not complete the
  1880. // IRP.
  1881. //
  1882. Status = SCCallNextDriver(DeviceExtension, Irp);
  1883. #if DBG
  1884. if (!NT_SUCCESS(Status)) {
  1885. DebugPrint((DebugLevelError, "'SCPower: PDO failed power request!\n"));
  1886. }
  1887. #endif
  1888. }
  1889. }
  1890. else {
  1891. //
  1892. // We have not started the device, don't bother.
  1893. // Besides, we can't use the DE->ControlEvent which is not
  1894. // inited yet in this case.
  1895. //
  1896. Status = STATUS_SUCCESS;
  1897. }
  1898. //
  1899. // indicate that we're ready for the next power IRP.
  1900. //
  1901. PoStartNextPowerIrp(Irp);
  1902. //
  1903. // show one fewer reference to driver.
  1904. //
  1905. SCDereferenceDriver(DeviceExtension);
  1906. //
  1907. // now complete the original request
  1908. //
  1909. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  1910. // end of set system power state
  1911. case DevicePowerState:
  1912. {
  1913. DEVICE_POWER_STATE DeviceState;
  1914. DeviceState = IrpStack->Parameters.Power.State.DeviceState;
  1915. //
  1916. // if this is a power up, send the IRP down first to allow
  1917. // the PDO to preprocess it.
  1918. //
  1919. if (DeviceState == PowerDeviceD0) {
  1920. //
  1921. // Call down async or the Wakeup might dead lock.
  1922. // The subsequent work continues in the completion routine.
  1923. //
  1924. return SCDevWakeCallNextDriver(DeviceExtension, Irp);
  1925. }
  1926. //
  1927. // take the event to avoid race
  1928. //
  1929. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  1930. Executive,
  1931. KernelMode,
  1932. FALSE, // not alertable
  1933. NULL);
  1934. //
  1935. // send down a set power SRB to the device.
  1936. // additional processing will be done by the callback
  1937. // procedure. This routine completes the IRP if it is able
  1938. // to issue the request.
  1939. //
  1940. Status = SCSubmitRequest(SRB_CHANGE_POWER_STATE,
  1941. (PVOID) DeviceState,
  1942. 0,
  1943. SCPowerCallback,
  1944. DeviceExtension,
  1945. NULL,
  1946. NULL,
  1947. Irp,
  1948. &RequestIssued,
  1949. &DeviceExtension->PendingQueue,
  1950. (PVOID) DeviceExtension->
  1951. MinidriverData->HwInitData.
  1952. HwReceivePacket
  1953. );
  1954. if (!RequestIssued) {
  1955. //
  1956. // if we could not issue a request, release event.
  1957. //
  1958. PoStartNextPowerIrp( Irp );
  1959. Status = SCCompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, DeviceExtension);
  1960. }
  1961. }
  1962. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  1963. //
  1964. // show one fewer reference to driver.
  1965. //
  1966. SCDereferenceDriver(DeviceExtension);
  1967. return (Status);
  1968. } // case devicepowerstate
  1969. default:
  1970. DebugPrint((DebugLevelInfo,
  1971. "StreamPower: unknown function %x\n",
  1972. DeviceObject));
  1973. //
  1974. // unknown function, so call it down to the minidriver as such.
  1975. // this routine completes the IRP if it is able to issue the request.
  1976. //
  1977. Status = SCSendUnknownCommand(Irp,
  1978. DeviceExtension,
  1979. SCUnknownPowerCallback,
  1980. &RequestIssued);
  1981. if (!RequestIssued) {
  1982. //
  1983. // could not send the unknown command down. show one fewer I/O
  1984. // pending and fall thru to generic handler.
  1985. //
  1986. PoStartNextPowerIrp(Irp);
  1987. Status = SCCompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, DeviceExtension);
  1988. }
  1989. //
  1990. // dereference the driver
  1991. //
  1992. SCDereferenceDriver(DeviceExtension);
  1993. return (Status);
  1994. }
  1995. }
  1996. NTSTATUS
  1997. SCPNPQueryCallback(
  1998. IN PSTREAM_REQUEST_BLOCK SRB
  1999. )
  2000. /*++
  2001. Routine Description:
  2002. Process the completion of an PNP Query Stop/Remove command.
  2003. Arguments:
  2004. SRB - address of the completed SRB
  2005. Return Value:
  2006. None.
  2007. --*/
  2008. {
  2009. PDEVICE_EXTENSION DeviceExtension =
  2010. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  2011. PIRP Irp = SRB->HwSRB.Irp;
  2012. NTSTATUS Status, MiniStatus;
  2013. //
  2014. // delete the SRB
  2015. //
  2016. MiniStatus = SCDequeueAndDeleteSrb(SRB);
  2017. //
  2018. // IRP_MJ_PnP, IRP_MJ_POWER and IRP_MJ_SYSTEM_CONTROL
  2019. // are supposed to traverse the whole device stack unless
  2020. // it is to be failed right here.
  2021. // It should have been STATUS_NOT_SUUPORTED ||
  2022. // NT_SUCCESS( Status ), add STATUS_NOT_IMPLEMENTED as
  2023. // there are some mini drivers return it which should
  2024. // have been STATUS_NOT_SUPPORTED
  2025. //
  2026. if ( STATUS_NOT_IMPLEMENTED == MiniStatus ) {
  2027. MiniStatus = STATUS_NOT_SUPPORTED;
  2028. }
  2029. if ( STATUS_NOT_SUPPORTED == MiniStatus ||
  2030. NT_SUCCESS( MiniStatus ) ) {
  2031. //
  2032. // Mini driver did not explicitly failed this, passs down the Irp
  2033. //
  2034. Status = SCCallNextDriver(DeviceExtension, Irp);
  2035. if ( Status == STATUS_NOT_SUPPORTED ) {
  2036. //
  2037. // noone below knows/cares. Use our mini status
  2038. //
  2039. Status = MiniStatus;
  2040. }
  2041. }
  2042. else {
  2043. //
  2044. // mini driver explcitly failed this Irp, use MiniStatus
  2045. //
  2046. Status = MiniStatus;
  2047. }
  2048. if ( !NT_SUCCESS( Status ) ) {
  2049. //
  2050. // query is vetoed, reset the INACCESSIBLE flag
  2051. //
  2052. KIRQL Irql;
  2053. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  2054. DeviceExtension->Flags &= ~DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  2055. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  2056. }
  2057. //
  2058. // complete the IRP with the final status
  2059. //
  2060. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  2061. }
  2062. NTSTATUS
  2063. SCUnknownPNPCallback(
  2064. IN PSTREAM_REQUEST_BLOCK SRB
  2065. )
  2066. /*++
  2067. Routine Description:
  2068. Process the completion of an unknown PNP command.
  2069. Arguments:
  2070. SRB - address of the completed SRB
  2071. Return Value:
  2072. None.
  2073. --*/
  2074. {
  2075. PDEVICE_EXTENSION DeviceExtension =
  2076. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  2077. PIRP Irp = SRB->HwSRB.Irp;
  2078. NTSTATUS Status, MiniStatus;
  2079. PAGED_CODE();
  2080. //
  2081. // delete the SRB
  2082. //
  2083. MiniStatus = SCDequeueAndDeleteSrb(SRB);
  2084. //
  2085. // IRP_MJ_PnP, IRP_MJ_POWER and IRP_MJ_SYSTEM_CONTROL
  2086. // are supposed to traverse the whole device stack unless
  2087. // it is to be failed right here.
  2088. // It should have been STATUS_NOT_SUUPORTED ||
  2089. // NT_SUCCESS( Status ), add STATUS_NOT_IMPLEMENTED as
  2090. // there are some mini drivers return it which should
  2091. // have been STATUS_NOT_SUPPORTED
  2092. //
  2093. if ( STATUS_NOT_IMPLEMENTED == MiniStatus ) {
  2094. MiniStatus = STATUS_NOT_SUPPORTED;
  2095. }
  2096. if ( STATUS_NOT_SUPPORTED == MiniStatus ||
  2097. NT_SUCCESS( MiniStatus ) ) {
  2098. //
  2099. // Mini driver did not explicitly failed this, passs down the Irp
  2100. //
  2101. Status = SCCallNextDriver(DeviceExtension, Irp);
  2102. if ( Status == STATUS_NOT_SUPPORTED ) {
  2103. //
  2104. // noone below knows/cares. Use our mini status
  2105. //
  2106. Status = MiniStatus;
  2107. }
  2108. }
  2109. else {
  2110. //
  2111. // mini driver explcitly failed this Irp, use MiniStatus
  2112. //
  2113. Status = MiniStatus;
  2114. }
  2115. //
  2116. // complete the IRP with the final status
  2117. //
  2118. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  2119. }
  2120. NTSTATUS
  2121. SCUnknownPowerCallback(
  2122. IN PSTREAM_REQUEST_BLOCK SRB
  2123. )
  2124. /*++
  2125. Routine Description:
  2126. Process the completion of an unknown PNP command.
  2127. Arguments:
  2128. SRB - address of the completed SRB
  2129. Return Value:
  2130. None.
  2131. --*/
  2132. {
  2133. PDEVICE_EXTENSION DeviceExtension =
  2134. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  2135. PIRP Irp = SRB->HwSRB.Irp;
  2136. NTSTATUS Status, MiniStatus;
  2137. PAGED_CODE();
  2138. //
  2139. // delete the SRB
  2140. //
  2141. MiniStatus = SCDequeueAndDeleteSrb(SRB);
  2142. if ( STATUS_NOT_IMPLEMENTED == MiniStatus ) {
  2143. MiniStatus = STATUS_NOT_SUPPORTED;
  2144. }
  2145. if ( STATUS_NOT_SUPPORTED == MiniStatus ||
  2146. NT_SUCCESS( MiniStatus )) {
  2147. //
  2148. // it is not explicitly failed by the mini driver pass down the Irp
  2149. //
  2150. Status = SCCallNextDriver(DeviceExtension, Irp);
  2151. if ( Status == STATUS_NOT_SUPPORTED ) {
  2152. //
  2153. // noone below knows/cares. Use our mini status
  2154. //
  2155. Status = MiniStatus;
  2156. }
  2157. }
  2158. else {
  2159. //
  2160. // mini driver explicitly failed this
  2161. //
  2162. Status = MiniStatus;
  2163. }
  2164. //
  2165. // complete the IRP with the final status
  2166. //
  2167. PoStartNextPowerIrp( Irp );
  2168. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  2169. }
  2170. NTSTATUS
  2171. SCQueryWorker(
  2172. IN PDEVICE_OBJECT DeviceObject,
  2173. IN PIRP Irp
  2174. )
  2175. /*++
  2176. Routine Description:
  2177. IRP completion handler for querying removal of the hardware
  2178. Arguments:
  2179. DeviceObject - pointer to device object
  2180. Irp - pointer to Irp
  2181. Return Value:
  2182. NTSTATUS returned.
  2183. --*/
  2184. {
  2185. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  2186. KIRQL Irql;
  2187. //
  2188. // if the query did not succeed, reenable the device.
  2189. //
  2190. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  2191. //
  2192. // clear the inaccessible bit.
  2193. //
  2194. KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
  2195. DeviceExtension->Flags &= ~DEVICE_FLAGS_DEVICE_INACCESSIBLE;
  2196. KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
  2197. }
  2198. return (SCCompleteIrp(Irp, Irp->IoStatus.Status, DeviceExtension));
  2199. }
  2200. NTSTATUS
  2201. SCStartWorker(
  2202. IN PIRP Irp
  2203. )
  2204. /*++
  2205. Routine Description:
  2206. Passive level routine to process starting the hardware.
  2207. Arguments:
  2208. Irp - pointer to Irp
  2209. Return Value:
  2210. None.
  2211. --*/
  2212. {
  2213. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  2214. PDEVICE_OBJECT DeviceObject = IrpStack->DeviceObject;
  2215. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  2216. PPORT_CONFIGURATION_INFORMATION ConfigInfo;
  2217. PHW_INITIALIZATION_DATA HwInitData;
  2218. PCM_RESOURCE_LIST ResourceList;
  2219. PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
  2220. PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
  2221. KAFFINITY affinity;
  2222. PVOID Buffer;
  2223. PACCESS_RANGE pAccessRanges = NULL;
  2224. ULONG CurrentRange = 0;
  2225. BOOLEAN interruptSharable = TRUE;
  2226. DEVICE_DESCRIPTION deviceDescription;
  2227. ULONG numberOfMapRegisters;
  2228. ULONG DmaBufferSize;
  2229. ULONG i;
  2230. PHYSICAL_ADDRESS TranslatedAddress;
  2231. NTSTATUS Status = Irp->IoStatus.Status;
  2232. BOOLEAN RequestIssued;
  2233. INTERFACE_TYPE InterfaceBuffer;
  2234. ULONG InterfaceLength;
  2235. PAGED_CODE();
  2236. //
  2237. // continue processing if we got good status from our parent.
  2238. //
  2239. if (NT_SUCCESS(Status)) {
  2240. HwInitData = &(DeviceExtension->MinidriverData->HwInitData);
  2241. DebugPrint((DebugLevelInfo,
  2242. "SCPNPStartWorker %x\n",
  2243. DeviceObject));
  2244. //
  2245. // Initialize spin lock for critical sections.
  2246. //
  2247. KeInitializeSpinLock(&DeviceExtension->SpinLock);
  2248. //
  2249. // initialize a worker DPC for this device
  2250. //
  2251. KeInitializeDpc(&DeviceExtension->WorkDpc,
  2252. StreamClassDpc,
  2253. DeviceObject);
  2254. //
  2255. // initialize the control and remove events for this device
  2256. //
  2257. // move this to AddDevice, we use the control event at Remove_device
  2258. // which can come in before the device starts.
  2259. // KeInitializeEvent(&DeviceExtension->ControlEvent,
  2260. // SynchronizationEvent,
  2261. // TRUE);
  2262. KeInitializeEvent(&DeviceExtension->RemoveEvent,
  2263. SynchronizationEvent,
  2264. FALSE);
  2265. //
  2266. // Initialize minidriver timer and timer DPC for this stream
  2267. //
  2268. KeInitializeTimer(&DeviceExtension->ComObj.MiniDriverTimer);
  2269. KeInitializeDpc(&DeviceExtension->ComObj.MiniDriverTimerDpc,
  2270. SCMinidriverDeviceTimerDpc,
  2271. DeviceExtension);
  2272. //
  2273. // retrieve the resources for the device
  2274. //
  2275. ResourceList = IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
  2276. //
  2277. // allocate space for the config info structure.
  2278. //
  2279. ConfigInfo = ExAllocatePool(NonPagedPool,
  2280. sizeof(PORT_CONFIGURATION_INFORMATION)
  2281. );
  2282. if (ConfigInfo == NULL) {
  2283. DebugPrint((DebugLevelFatal, "StreamClassPNP: ConfigInfo alloc failed."));
  2284. Status = STATUS_INSUFFICIENT_RESOURCES;
  2285. goto exit;
  2286. }
  2287. DebugPrint((DebugLevelVerbose, "StreamClassPNP: ConfigInfo = %x\n", ConfigInfo));
  2288. RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
  2289. DeviceExtension->ConfigurationInformation = ConfigInfo;
  2290. //
  2291. // fill in the ConfigInfo fields we know about.
  2292. //
  2293. ConfigInfo->SizeOfThisPacket = sizeof(PORT_CONFIGURATION_INFORMATION);
  2294. #if DBG
  2295. //
  2296. // make sure that the minidriver handles receiving a bigger structure
  2297. // so we can expand it later
  2298. //
  2299. ConfigInfo->SizeOfThisPacket *= ConfigInfo->SizeOfThisPacket;
  2300. #endif
  2301. //
  2302. // set the callable PDO in the configinfo structure
  2303. //
  2304. ConfigInfo->PhysicalDeviceObject = DeviceExtension->AttachedPdo;
  2305. ConfigInfo->RealPhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject;
  2306. ConfigInfo->BusInterruptVector = MP_UNINITIALIZED_VALUE;
  2307. ConfigInfo->InterruptMode = Latched;
  2308. ConfigInfo->DmaChannel = MP_UNINITIALIZED_VALUE;
  2309. ConfigInfo->Irp = Irp;
  2310. //
  2311. // Now we get to chew thru the resources the OS found for us, if any.
  2312. //
  2313. if (ResourceList) {
  2314. FullResourceDescriptor = &ResourceList->List[0];
  2315. PartialResourceList = &FullResourceDescriptor->PartialResourceList;
  2316. //
  2317. // fill in the bus # and interface type based on the device
  2318. // properties
  2319. // for the PDO. default to InterfaceTypeUndefined if
  2320. // failure to retrieve interface type (if the miniport tries to
  2321. // use
  2322. // this value when filling in DEVICE_DESCRIPTION.InterfaceType
  2323. // for
  2324. // calling IoGetDmaAdapter, the right thing will happen, since
  2325. // PnP
  2326. // will automatically pick the correct legacy bus in the system
  2327. // (ISA or MCA).
  2328. //
  2329. if (!NT_SUCCESS(
  2330. IoGetDeviceProperty(
  2331. DeviceExtension->PhysicalDeviceObject,
  2332. DevicePropertyBusNumber,
  2333. sizeof(ULONG),
  2334. (PVOID) & (ConfigInfo->SystemIoBusNumber),
  2335. &InterfaceLength))) {
  2336. //
  2337. // Couldn't retrieve bus number property--assume bus zero.
  2338. //
  2339. ConfigInfo->SystemIoBusNumber = 0;
  2340. }
  2341. if (NT_SUCCESS(
  2342. IoGetDeviceProperty(
  2343. DeviceExtension->PhysicalDeviceObject,
  2344. DevicePropertyLegacyBusType,
  2345. sizeof(INTERFACE_TYPE),
  2346. &InterfaceBuffer,
  2347. &InterfaceLength))) {
  2348. ASSERT(InterfaceLength == sizeof(INTERFACE_TYPE));
  2349. ConfigInfo->AdapterInterfaceType = InterfaceBuffer;
  2350. } else { // if success
  2351. //
  2352. // Couldn't retrieve bus interface type--initialize to
  2353. // InterfaceTypeUndefined.
  2354. //
  2355. ConfigInfo->AdapterInterfaceType = InterfaceTypeUndefined;
  2356. } // if success
  2357. //
  2358. // allocate space for access ranges. We use the Count field
  2359. // in the resource list for determining this size, as the count
  2360. // will be >= the max # of ranges we will need.
  2361. //
  2362. if (PartialResourceList->Count) {
  2363. pAccessRanges = ExAllocatePool(NonPagedPool,
  2364. sizeof(ACCESS_RANGE) *
  2365. PartialResourceList->Count
  2366. );
  2367. if (pAccessRanges == NULL) {
  2368. DebugPrint((DebugLevelFatal,
  2369. "StreamClassPNP: No pool for global info"));
  2370. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2371. SCFreeAllResources(DeviceExtension);
  2372. Status = STATUS_INSUFFICIENT_RESOURCES;
  2373. goto exit;
  2374. }
  2375. } // if count
  2376. //
  2377. // Stash the AccessRanges structure at this time so that
  2378. // SCFreeAllResources will free it on resource failures below.
  2379. //
  2380. ConfigInfo->AccessRanges = pAccessRanges;
  2381. //
  2382. // Now update the port configuration info structure by looping
  2383. // thru the config
  2384. //
  2385. for (i = 0; i < PartialResourceList->Count; i++) {
  2386. switch (PartialResourceList->PartialDescriptors[i].Type) {
  2387. case CmResourceTypePort:
  2388. DebugPrint((DebugLevelVerbose, "'StreamClassPnP: Port Resources Found at %x, Length %x\n",
  2389. PartialResourceList->PartialDescriptors[i].u.Port.Start,
  2390. PartialResourceList->PartialDescriptors[i].u.Port.Length));
  2391. //
  2392. // translate the bus address for the minidriver
  2393. //
  2394. TranslatedAddress = PartialResourceList->PartialDescriptors[i].u.Port.Start;
  2395. //
  2396. // set the access range in the structure.
  2397. //
  2398. pAccessRanges[CurrentRange].RangeStart = TranslatedAddress;
  2399. pAccessRanges[CurrentRange].RangeLength =
  2400. PartialResourceList->
  2401. PartialDescriptors[i].u.Port.Length;
  2402. pAccessRanges[CurrentRange++].RangeInMemory =
  2403. FALSE;
  2404. break;
  2405. case CmResourceTypeInterrupt:
  2406. DebugPrint((DebugLevelVerbose, "'StreamClassPnP: Interrupt Resources Found! Level = %x Vector = %x\n",
  2407. PartialResourceList->PartialDescriptors[i].u.Interrupt.Level,
  2408. PartialResourceList->PartialDescriptors[i].u.Interrupt.Vector));
  2409. //
  2410. // Set the interrupt vector in the config info
  2411. //
  2412. ConfigInfo->BusInterruptVector = PartialResourceList->PartialDescriptors[i].u.Interrupt.Vector;
  2413. ;
  2414. affinity = PartialResourceList->PartialDescriptors[i].u.Interrupt.Affinity;
  2415. ConfigInfo->BusInterruptLevel = (ULONG) PartialResourceList->PartialDescriptors[i].u.Interrupt.Level;
  2416. ConfigInfo->InterruptMode = PartialResourceList->PartialDescriptors[i].Flags;
  2417. //
  2418. // Go to next resource for this Adapter
  2419. //
  2420. break;
  2421. case CmResourceTypeMemory:
  2422. //
  2423. // translate the bus address for the minidriver
  2424. //
  2425. DebugPrint((DebugLevelVerbose, "'StreamClassPnP: Memory Resources Found @ %x'%x, Length = %x\n",
  2426. PartialResourceList->PartialDescriptors[i].u.Memory.Start.HighPart,
  2427. PartialResourceList->PartialDescriptors[i].u.Memory.Start.LowPart,
  2428. PartialResourceList->PartialDescriptors[i].u.Memory.Length));
  2429. TranslatedAddress = PartialResourceList->PartialDescriptors[i].u.Memory.Start;
  2430. if (!SCMapMemoryAddress(&pAccessRanges[CurrentRange++],
  2431. TranslatedAddress,
  2432. ConfigInfo,
  2433. DeviceExtension,
  2434. ResourceList,
  2435. &PartialResourceList->
  2436. PartialDescriptors[i])) {
  2437. SCFreeAllResources(DeviceExtension);
  2438. Status = STATUS_CONFLICTING_ADDRESSES;
  2439. goto exit;
  2440. } // if !scmapmemoryaddress
  2441. default:
  2442. break;
  2443. }
  2444. }
  2445. } // if resources
  2446. //
  2447. // reference the access range structure to the
  2448. // config info structure & the ConfigInfo structure to the
  2449. // device extension & indicate # of ranges.
  2450. //
  2451. ConfigInfo->NumberOfAccessRanges = CurrentRange;
  2452. //
  2453. // Determine if a Dma Adapter must be allocated.
  2454. //
  2455. DmaBufferSize = HwInitData->DmaBufferSize;
  2456. if ((HwInitData->BusMasterDMA) || (DmaBufferSize)) {
  2457. //
  2458. // Get the adapter object for this card.
  2459. //
  2460. DebugPrint((DebugLevelVerbose, "'StreamClassPnP: Allocating DMA adapter\n"));
  2461. RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
  2462. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  2463. deviceDescription.DmaChannel = ConfigInfo->DmaChannel;
  2464. deviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
  2465. deviceDescription.DmaWidth = Width32Bits;
  2466. deviceDescription.DmaSpeed = Compatible;
  2467. deviceDescription.ScatterGather = TRUE;
  2468. deviceDescription.Master = TRUE;
  2469. deviceDescription.Dma32BitAddresses = !(HwInitData->Dma24BitAddresses);
  2470. deviceDescription.AutoInitialize = FALSE;
  2471. deviceDescription.MaximumLength = (ULONG) - 1;
  2472. DeviceExtension->DmaAdapterObject = IoGetDmaAdapter(
  2473. DeviceExtension->PhysicalDeviceObject,
  2474. &deviceDescription,
  2475. &numberOfMapRegisters
  2476. );
  2477. ASSERT(DeviceExtension->DmaAdapterObject);
  2478. //
  2479. // Set maximum number of pages
  2480. //
  2481. DeviceExtension->NumberOfMapRegisters = numberOfMapRegisters;
  2482. //
  2483. // expose the object to the minidriver
  2484. //
  2485. ConfigInfo->DmaAdapterObject = DeviceExtension->DmaAdapterObject;
  2486. } else {
  2487. //
  2488. // no DMA adapter object. show unlimited map registers so
  2489. // we won't have to do a real time check later for DMA.
  2490. //
  2491. DeviceExtension->NumberOfMapRegisters = -1;
  2492. }
  2493. if (DmaBufferSize) {
  2494. Buffer = HalAllocateCommonBuffer(DeviceExtension->DmaAdapterObject,
  2495. DmaBufferSize,
  2496. &DeviceExtension->DmaBufferPhysical,
  2497. FALSE);
  2498. if (Buffer == NULL) {
  2499. DEBUG_BREAKPOINT();
  2500. DebugPrint((DebugLevelFatal, "StreamClassPnPStart: Could not alloc buffer, size: %d\n", DmaBufferSize));
  2501. SCFreeAllResources(DeviceExtension);
  2502. Status = STATUS_INSUFFICIENT_RESOURCES;
  2503. goto exit;
  2504. }
  2505. //
  2506. // zero init the common buffer.
  2507. //
  2508. RtlZeroMemory(Buffer, DmaBufferSize);
  2509. //
  2510. // save virtual address of buffer
  2511. //
  2512. DeviceExtension->DmaBuffer = Buffer;
  2513. DeviceExtension->DmaBufferLength = DmaBufferSize; // osr#99489
  2514. } // if DMA buffer
  2515. //
  2516. // Performance Improvement chance
  2517. // - on rebalance, the uninitialize handler clears the sync
  2518. // vector when the interrupt is disconnected, but since we
  2519. // initialized this vector ONLY at AddDevice time, it wasn't getting
  2520. // reset correctly since only a new start (and not an adddevice) is
  2521. // sent on a rebalance. the correct fix is to move all of the
  2522. // initial vector setting to here, but I'm worried that there could
  2523. // be a case where if they aren't set up on the adddevice we could
  2524. // reference a null. So, I've duplicated the following few lines to
  2525. // reset the vector here. For code savings, this should be done
  2526. // only in one place.
  2527. //
  2528. //
  2529. // presuppose full synch
  2530. //
  2531. #if DBG
  2532. DeviceExtension->SynchronizeExecution = SCDebugKeSynchronizeExecution;
  2533. #else
  2534. DeviceExtension->SynchronizeExecution = KeSynchronizeExecution;
  2535. #endif
  2536. if (DeviceExtension->NoSync) {
  2537. //
  2538. // we won't do synchronization, so use the dummy sync routine.
  2539. //
  2540. DeviceExtension->SynchronizeExecution = StreamClassSynchronizeExecution;
  2541. DeviceExtension->InterruptObject = (PVOID) DeviceExtension;
  2542. }
  2543. //
  2544. // see if the driver has an interrupt, and process if so.
  2545. //
  2546. if (HwInitData->HwInterrupt == NULL ||
  2547. (ConfigInfo->BusInterruptLevel == 0 &&
  2548. ConfigInfo->BusInterruptVector == 0)) {
  2549. //
  2550. // There is no interrupt so use the dummy sync routine.
  2551. //
  2552. DeviceExtension->SynchronizeExecution = StreamClassSynchronizeExecution;
  2553. DeviceExtension->InterruptObject = (PVOID) DeviceExtension;
  2554. DebugPrint((1, "'StreamClassInitialize: Adapter has no interrupt.\n"));
  2555. } else {
  2556. DebugPrint((1,
  2557. "'StreamClassInitialize: STREAM adapter IRQ is %d\n",
  2558. ConfigInfo->BusInterruptLevel));
  2559. //
  2560. // Set up for a real interrupt.
  2561. //
  2562. Status = IoConnectInterrupt(
  2563. &DeviceExtension->InterruptObject,
  2564. StreamClassInterrupt,
  2565. DeviceObject,
  2566. (PKSPIN_LOCK) NULL,
  2567. ConfigInfo->BusInterruptVector,
  2568. (UCHAR) ConfigInfo->BusInterruptLevel,
  2569. (UCHAR) ConfigInfo->BusInterruptLevel,
  2570. ConfigInfo->InterruptMode,
  2571. interruptSharable,
  2572. affinity,
  2573. FALSE);
  2574. if (!NT_SUCCESS(Status)) {
  2575. DebugPrint((1, "'SCStartWorker: Can't connect interrupt %d\n",
  2576. ConfigInfo->BusInterruptLevel));
  2577. DeviceExtension->InterruptObject = NULL;
  2578. SCFreeAllResources(DeviceExtension);
  2579. goto exit;
  2580. }
  2581. //
  2582. // set the interrupt object for the minidriver
  2583. //
  2584. ConfigInfo->InterruptObject = DeviceExtension->InterruptObject;
  2585. }
  2586. //
  2587. // point the config info structure to the device extension &
  2588. // device object as
  2589. // we can only pass in one context value to KeSync....
  2590. //
  2591. ConfigInfo->HwDeviceExtension =
  2592. DeviceExtension->HwDeviceExtension;
  2593. ConfigInfo->ClassDeviceObject = DeviceObject;
  2594. //
  2595. // Start timer.
  2596. //
  2597. IoStartTimer(DeviceObject);
  2598. //
  2599. // the ConfigInfo structure is filled in and the IRQ hooked.
  2600. // call the minidriver to find the specified adapter.
  2601. //
  2602. //
  2603. // initialize the device extension queues
  2604. //
  2605. InitializeListHead(&DeviceExtension->PendingQueue);
  2606. InitializeListHead(&DeviceExtension->OutstandingQueue);
  2607. /// move to add device, we could have child PDO if we start and stop
  2608. ///InitializeListHead(&DeviceExtension->Children);
  2609. InitializeListHead(&DeviceExtension->DeadEventList);
  2610. IFN_MF(InitializeListHead(&DeviceExtension->NotifyList);)
  2611. ExInitializeWorkItem(&DeviceExtension->EventWorkItem,
  2612. SCFreeDeadEvents,
  2613. DeviceExtension);
  2614. ExInitializeWorkItem(&DeviceExtension->RescanWorkItem,
  2615. SCRescanStreams,
  2616. DeviceExtension);
  2617. ExInitializeWorkItem(&DeviceExtension->PowerCompletionWorkItem,
  2618. SCPowerCompletionWorker,
  2619. DeviceExtension);
  2620. ExInitializeWorkItem(&DeviceExtension->DevIrpCompletionWorkItem,
  2621. SCDevIrpCompletionWorker,
  2622. DeviceExtension);
  2623. //
  2624. // show that the device is ready for its first request.
  2625. //
  2626. DeviceExtension->ReadyForNextReq = TRUE;
  2627. //
  2628. // submit the initialize command.
  2629. // additional processing will be done by the callback procedure.
  2630. //
  2631. Status = SCSubmitRequest(
  2632. SRB_INITIALIZE_DEVICE,
  2633. ConfigInfo,
  2634. sizeof(PORT_CONFIGURATION_INFORMATION),
  2635. SCInitializeCallback,
  2636. DeviceExtension,
  2637. NULL,
  2638. NULL,
  2639. Irp,
  2640. &RequestIssued,
  2641. &DeviceExtension->PendingQueue,
  2642. (PVOID) DeviceExtension->MinidriverData->HwInitData.HwReceivePacket
  2643. );
  2644. //
  2645. // If the device failed to start then set the error and return.
  2646. //
  2647. if (!RequestIssued) {
  2648. DebugPrint((DebugLevelFatal, "StreamClassPnP: Adapter not found\n"));
  2649. SCFreeAllResources(DeviceExtension);
  2650. goto exit;
  2651. }
  2652. }
  2653. return (Status);
  2654. exit:
  2655. return (SCCompleteIrp(Irp, Status, DeviceExtension));
  2656. }
  2657. NTSTATUS
  2658. SCInitializeCallback(
  2659. IN PSTREAM_REQUEST_BLOCK SRB
  2660. )
  2661. /*++
  2662. Routine Description:
  2663. Process the minidriver's stream info structure.
  2664. Arguments:
  2665. SRB - address of the completed SRB
  2666. Return Value:
  2667. None.
  2668. --*/
  2669. {
  2670. PHW_STREAM_DESCRIPTOR StreamBuffer;
  2671. PDEVICE_EXTENSION DeviceExtension =
  2672. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  2673. PDEVICE_OBJECT DeviceObject = DeviceExtension->DeviceObject;
  2674. PIRP Irp = SRB->HwSRB.Irp;
  2675. PPORT_CONFIGURATION_INFORMATION ConfigInfo =
  2676. SRB->HwSRB.CommandData.ConfigInfo;
  2677. BOOLEAN RequestIssued;
  2678. NTSTATUS Status;
  2679. PAGED_CODE();
  2680. if (NT_SUCCESS(SRB->HwSRB.Status)) {
  2681. DebugPrint((DebugLevelVerbose, "'Stream: returned from HwInitialize\n"));
  2682. //
  2683. // send an SRB to retrieve the stream information
  2684. //
  2685. ASSERT(ConfigInfo->StreamDescriptorSize);
  2686. StreamBuffer =
  2687. ExAllocatePool(NonPagedPool,
  2688. ConfigInfo->StreamDescriptorSize
  2689. );
  2690. if (!StreamBuffer) {
  2691. SCUninitializeMinidriver(DeviceObject, Irp);
  2692. Status = STATUS_INSUFFICIENT_RESOURCES;
  2693. return (SCProcessCompletedRequest(SRB));
  2694. }
  2695. //
  2696. // zero-init the buffer
  2697. //
  2698. RtlZeroMemory(StreamBuffer, ConfigInfo->StreamDescriptorSize);
  2699. //
  2700. // submit the command.
  2701. // additional processing will be done by the callback
  2702. // procedure.
  2703. //
  2704. Status = SCSubmitRequest(SRB_GET_STREAM_INFO,
  2705. StreamBuffer,
  2706. ConfigInfo->StreamDescriptorSize,
  2707. SCStreamInfoCallback,
  2708. DeviceExtension,
  2709. NULL,
  2710. NULL,
  2711. Irp,
  2712. &RequestIssued,
  2713. &DeviceExtension->PendingQueue,
  2714. (PVOID) DeviceExtension->MinidriverData->HwInitData.HwReceivePacket
  2715. );
  2716. if (!RequestIssued) {
  2717. ExFreePool(StreamBuffer);
  2718. SCUninitializeMinidriver(DeviceObject, Irp);
  2719. return (SCProcessCompletedRequest(SRB));
  2720. }
  2721. } else {
  2722. //
  2723. // If the device failed to start then set the error and
  2724. // return.
  2725. //
  2726. DebugPrint((DebugLevelFatal, "StreamClassPnP: Adapter not found\n"));
  2727. SCFreeAllResources(DeviceExtension);
  2728. return (SCProcessCompletedRequest(SRB));
  2729. }
  2730. //
  2731. // dequeue and delete the SRB for initialize. Null out the IRP field
  2732. // so the dequeue routine won't try to access it, as it has been freed.
  2733. //
  2734. SRB->HwSRB.Irp = NULL;
  2735. SCDequeueAndDeleteSrb(SRB);
  2736. return (Status);
  2737. }
  2738. #if ENABLE_MULTIPLE_FILTER_TYPES
  2739. PUNICODE_STRING
  2740. SciCreateSymbolicLinks(
  2741. IN PDEVICE_EXTENSION DeviceExtension,
  2742. IN ULONG FilterTypeIndex,
  2743. IN PHW_STREAM_HEADER StreamHeader)
  2744. /*++
  2745. Routine Description:
  2746. Create symbolic links for all categories in the Topology of
  2747. one filter type so that clients can find them.
  2748. The Symbolic link array is kept in the FilterType so that
  2749. they can be released later.
  2750. Arguments:
  2751. DeviceExtenion: The device instance.
  2752. FiltertypeIndex: The filter type to create symbolic links.
  2753. StreamHeader: Go thru the categories in the Topology.
  2754. Return Value:
  2755. NTSTATUS
  2756. --*/
  2757. {
  2758. LPGUID GuidIndex = (LPGUID)StreamHeader->Topology->Categories;
  2759. ULONG ArrayCount = StreamHeader->Topology->CategoriesCount;
  2760. PUNICODE_STRING NamesArray;
  2761. ULONG i,j;
  2762. HANDLE ClassHandle, PdoHandle=NULL; // prefixbug 17135
  2763. UNICODE_STRING TempUnicodeString;
  2764. PVOID DataBuffer[MAX_STRING_LENGTH];
  2765. //ULONG NumberOfFilterTypes;
  2766. NTSTATUS Status=STATUS_SUCCESS;
  2767. PAGED_CODE();
  2768. ASSERT_DEVICE_EXTENSION( DeviceExtension );
  2769. //
  2770. // allocate space for the array of catagory names
  2771. //
  2772. NamesArray = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING) * ArrayCount);
  2773. if ( NULL == NamesArray ) {
  2774. DEBUG_BREAKPOINT();
  2775. Status = STATUS_INSUFFICIENT_RESOURCES;
  2776. goto Exit;
  2777. }
  2778. //
  2779. // zero the array in case we're unable to fill it in below. the Destroy
  2780. // routine below will then correctly handle this case.
  2781. //
  2782. RtlZeroMemory(NamesArray, sizeof(UNICODE_STRING) * ArrayCount);
  2783. //
  2784. // open the PDO
  2785. //
  2786. Status = IoOpenDeviceRegistryKey(
  2787. DeviceExtension->PhysicalDeviceObject,
  2788. PLUGPLAY_REGKEY_DRIVER,
  2789. STANDARD_RIGHTS_ALL,
  2790. &PdoHandle);
  2791. if ( !NT_SUCCESS(Status) ) {
  2792. DebugPrint((DebugLevelError, "StreamCreateSymLinks: couldn't open Pdo\n"));
  2793. PdoHandle = NULL;
  2794. goto Exit;
  2795. }
  2796. //
  2797. // loop through each of the catagory GUID's for each of the pins,
  2798. // creating a symbolic link for each one.
  2799. //
  2800. for (i = 0; i < ArrayCount; i++) {
  2801. //
  2802. // Create the symbolic link for each category
  2803. //
  2804. PKSOBJECT_CREATE_ITEM CreateItem;
  2805. CreateItem = &DeviceExtension->CreateItems[FilterTypeIndex];
  2806. DebugPrint((DebugLevelVerbose,
  2807. "RegisterDeviceInterface FType %d,"
  2808. "CreateItemName=%S\n",
  2809. FilterTypeIndex,
  2810. CreateItem->ObjectClass.Buffer));
  2811. Status = IoRegisterDeviceInterface(
  2812. DeviceExtension->PhysicalDeviceObject,
  2813. &GuidIndex[i],
  2814. (PUNICODE_STRING) &CreateItem->ObjectClass,
  2815. &NamesArray[i]);
  2816. if ( !NT_SUCCESS(Status)) {
  2817. //
  2818. // Can't register device interface
  2819. //
  2820. DebugPrint((DebugLevelError,
  2821. "StreamCreateSymLinks: couldn't register\n"));
  2822. DEBUG_BREAKPOINT();
  2823. goto Exit;
  2824. }
  2825. DebugPrint((DebugLevelVerbose,
  2826. "SymbolicLink:%S\n",
  2827. NamesArray[i].Buffer));
  2828. //
  2829. // Now set the symbolic link for the association
  2830. //
  2831. Status = IoSetDeviceInterfaceState(&NamesArray[i], TRUE);
  2832. if (!NT_SUCCESS(Status)) {
  2833. //
  2834. // unsuccessful
  2835. //
  2836. DebugPrint((DebugLevelError, "StreamCreateSymLinks: couldn't set\n"));
  2837. DEBUG_BREAKPOINT();
  2838. goto Exit;
  2839. }
  2840. //
  2841. // add the strings from the PDO's key to the association key.
  2842. // Performance Improvement Chance
  2843. // - the INF should be able to directly propogate these;
  2844. // forrest & lonny are fixing.
  2845. //
  2846. Status = IoOpenDeviceInterfaceRegistryKey(&NamesArray[i],
  2847. STANDARD_RIGHTS_ALL,
  2848. &ClassHandle);
  2849. if ( !NT_SUCCESS( Status )) {
  2850. //
  2851. // unsuccessful open Class interface
  2852. //
  2853. DebugPrint((DebugLevelError, "StreamCreateSymLinks: couldn't set\n"));
  2854. DEBUG_BREAKPOINT();
  2855. goto Exit;
  2856. }
  2857. //
  2858. // write the class ID for the proxy, if any.
  2859. //
  2860. Status = SCGetRegistryValue(PdoHandle,
  2861. (PWCHAR) ClsIdString,
  2862. sizeof(ClsIdString),
  2863. DataBuffer,
  2864. MAX_STRING_LENGTH);
  2865. if ( NT_SUCCESS(Status) ){
  2866. //
  2867. // write the class ID for the proxy
  2868. //
  2869. RtlInitUnicodeString(&TempUnicodeString, ClsIdString);
  2870. ZwSetValueKey(ClassHandle,
  2871. &TempUnicodeString,
  2872. 0,
  2873. REG_SZ,
  2874. DataBuffer,
  2875. MAX_STRING_LENGTH);
  2876. } // if cls guid read
  2877. //
  2878. // first check if a friendly name has already been propogated
  2879. // to the class via the INF. If not, we'll just use the device
  2880. // description string for this.
  2881. //
  2882. Status = SCGetRegistryValue(ClassHandle,
  2883. (PWCHAR) FriendlyNameString,
  2884. sizeof(FriendlyNameString),
  2885. DataBuffer,
  2886. MAX_STRING_LENGTH);
  2887. if ( !NT_SUCCESS(Status) ) {
  2888. //
  2889. // friendly name non-exists yet.
  2890. // write the friendly name for the device, if any.
  2891. //
  2892. Status = SCGetRegistryValue(PdoHandle,
  2893. (PWCHAR) DriverDescString,
  2894. sizeof(DriverDescString),
  2895. DataBuffer,
  2896. MAX_STRING_LENGTH);
  2897. if ( NT_SUCCESS(Status) ) {
  2898. //
  2899. // driver descrption string available, use it.
  2900. //
  2901. RtlInitUnicodeString(&TempUnicodeString, FriendlyNameString);
  2902. ZwSetValueKey(ClassHandle,
  2903. &TempUnicodeString,
  2904. 0,
  2905. REG_SZ,
  2906. DataBuffer,
  2907. MAX_STRING_LENGTH);
  2908. }
  2909. }
  2910. ZwClose(ClassHandle);
  2911. } // for # Categories
  2912. //
  2913. // If we reach here, consider as successful.
  2914. //
  2915. Status = STATUS_SUCCESS;
  2916. Exit: {
  2917. if ( NULL != PdoHandle ) {
  2918. ZwClose(PdoHandle);
  2919. }
  2920. if ( !NT_SUCCESS( Status ) ) {
  2921. if ( NULL != NamesArray ) {
  2922. ExFreePool( NamesArray );
  2923. NamesArray = NULL;
  2924. }
  2925. }
  2926. return NamesArray;
  2927. }
  2928. }
  2929. NTSTATUS
  2930. SciOnFilterStreamDescriptor(
  2931. PFILTER_INSTANCE FilterInstance,
  2932. PHW_STREAM_DESCRIPTOR StreamDescriptor)
  2933. /*++
  2934. Routine Description:
  2935. Process the minidriver's stream descriptor structure.
  2936. This is used for one FilterType specific streams.
  2937. Arguments:
  2938. FilterInstance: The one that we are to process for.
  2939. StreamDescriptor: Point to the descriptor to process for the filter.
  2940. Return Value:
  2941. None.
  2942. --*/
  2943. {
  2944. ULONG NumberOfPins, i;
  2945. PKSPIN_DESCRIPTOR PinDescs = NULL;
  2946. PHW_STREAM_INFORMATION CurrentInfo;
  2947. ULONG PinSize;
  2948. PSTREAM_ADDITIONAL_INFO NewStreamArray;
  2949. NTSTATUS Status=STATUS_SUCCESS;
  2950. PAGED_CODE();
  2951. NumberOfPins = StreamDescriptor->StreamHeader.NumberOfStreams;
  2952. DebugPrint((DebugLevelVerbose,
  2953. "Parsing StreamInfo Pins=%x\n", NumberOfPins ));
  2954. if (StreamDescriptor->StreamHeader.SizeOfHwStreamInformation <
  2955. sizeof(HW_STREAM_INFORMATION)) {
  2956. DebugPrint((DebugLevelError, "minidriver stream info too small!"));
  2957. DEBUG_BREAKPOINT();
  2958. Status = STATUS_INVALID_PARAMETER;
  2959. goto Exit;
  2960. }
  2961. if (NumberOfPins) {
  2962. //
  2963. // parse the minidriver's info into CSA format to build the
  2964. // mother of all structures.
  2965. //
  2966. PinSize = (sizeof(KSPIN_DESCRIPTOR) + sizeof(STREAM_ADDITIONAL_INFO))*
  2967. NumberOfPins;
  2968. PinDescs = ExAllocatePool(NonPagedPool, PinSize);
  2969. if (PinDescs == NULL) {
  2970. DebugPrint((DebugLevelError, "Stream: No pool for stream info"));
  2971. Status = STATUS_INSUFFICIENT_RESOURCES;
  2972. goto Exit;
  2973. }
  2974. RtlZeroMemory(PinDescs, PinSize);
  2975. //
  2976. // we need a new array to hold the new copies of the
  2977. // stream properties and events which are allocated below.
  2978. //
  2979. NewStreamArray = (PSTREAM_ADDITIONAL_INFO)
  2980. ((PBYTE) PinDescs + sizeof(KSPIN_DESCRIPTOR) * NumberOfPins);
  2981. FilterInstance->StreamPropEventArray = NewStreamArray;
  2982. CurrentInfo = &StreamDescriptor->StreamInfo;
  2983. for (i = 0; i < StreamDescriptor->StreamHeader.NumberOfStreams; i++) {
  2984. //
  2985. // process each pin info
  2986. //
  2987. PinDescs[i].InterfacesCount = SIZEOF_ARRAY(PinInterfaces);
  2988. PinDescs[i].Interfaces = PinInterfaces;
  2989. //
  2990. // use default medium if minidriver does not specify
  2991. //
  2992. if (CurrentInfo->MediumsCount) {
  2993. PinDescs[i].MediumsCount = CurrentInfo->MediumsCount;
  2994. PinDescs[i].Mediums = CurrentInfo->Mediums;
  2995. }
  2996. else {
  2997. PinDescs[i].MediumsCount = SIZEOF_ARRAY(PinMediums);
  2998. PinDescs[i].Mediums = PinMediums;
  2999. }
  3000. //
  3001. // set the # of data format blocks
  3002. //
  3003. PinDescs[i].DataRangesCount =
  3004. CurrentInfo->NumberOfFormatArrayEntries;
  3005. //
  3006. // point to the data format blocks for the pin
  3007. //
  3008. PinDescs[i].DataRanges = CurrentInfo->StreamFormatsArray;
  3009. //
  3010. // set the data flow direction
  3011. //
  3012. PinDescs[i].DataFlow = (KSPIN_DATAFLOW) CurrentInfo->DataFlow;
  3013. //
  3014. // set the communication field
  3015. //
  3016. if (CurrentInfo->BridgeStream) {
  3017. PinDescs[i].Communication = KSPIN_COMMUNICATION_BRIDGE;
  3018. }
  3019. else {
  3020. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  3021. PinDescs[i].Communication = KSPIN_COMMUNICATION_BOTH;
  3022. #else
  3023. PinDescs[i].Communication = KSPIN_COMMUNICATION_SINK;
  3024. #endif
  3025. }
  3026. //
  3027. // copy the pointers for the pin name and category
  3028. //
  3029. PinDescs[i].Category = CurrentInfo->Category;
  3030. PinDescs[i].Name = CurrentInfo->Name;
  3031. if ( CurrentInfo->NumStreamPropArrayEntries) {
  3032. ASSERT(CurrentInfo->StreamPropertiesArray);
  3033. //
  3034. // make a copy of the properties since we modify the struct
  3035. // though parts of it may be marked as a const.
  3036. // Performance Imporovement Chance
  3037. // - check for const in future if possible
  3038. //
  3039. if (!(NewStreamArray[i].StreamPropertiesArray =
  3040. SCCopyMinidriverProperties(
  3041. CurrentInfo->NumStreamPropArrayEntries,
  3042. CurrentInfo->StreamPropertiesArray))) {
  3043. //
  3044. // Fail to copy
  3045. //
  3046. Status = STATUS_INSUFFICIENT_RESOURCES;
  3047. goto Exit;
  3048. }
  3049. }
  3050. if (CurrentInfo->NumStreamEventArrayEntries) {
  3051. ASSERT(CurrentInfo->StreamEventsArray);
  3052. //
  3053. // make a copy of the events since we modify the
  3054. // struct
  3055. // though parts of it may be marked as a const.
  3056. // Performance Improvement Chance
  3057. // - check for const in future if possible
  3058. //
  3059. if (!(NewStreamArray[i].StreamEventsArray =
  3060. SCCopyMinidriverEvents(
  3061. CurrentInfo->NumStreamEventArrayEntries,
  3062. CurrentInfo->StreamEventsArray))) {
  3063. //
  3064. // Fail to copy
  3065. //
  3066. Status = STATUS_INSUFFICIENT_RESOURCES;
  3067. goto Exit;
  3068. }
  3069. }
  3070. //
  3071. // update the minidriver's properties for this stream.
  3072. //
  3073. SCUpdateMinidriverProperties(
  3074. CurrentInfo->NumStreamPropArrayEntries,
  3075. NewStreamArray[i].StreamPropertiesArray,
  3076. TRUE);
  3077. //
  3078. // update the minidriver's events for this stream.
  3079. //
  3080. SCUpdateMinidriverEvents(
  3081. CurrentInfo->NumStreamEventArrayEntries,
  3082. NewStreamArray[i].StreamEventsArray,
  3083. TRUE);
  3084. //
  3085. // index to next streaminfo structure.
  3086. //
  3087. CurrentInfo++;
  3088. } // for # pins
  3089. } // if there are pins
  3090. if (StreamDescriptor->StreamHeader.NumDevPropArrayEntries) {
  3091. ASSERT(StreamDescriptor->StreamHeader.DevicePropertiesArray);
  3092. //
  3093. // make a copy of the properties since we modify the struct
  3094. // though parts of it may be marked as a const.
  3095. // Performance Improvement Chance
  3096. // - check for const in future if possible
  3097. //
  3098. if (!(FilterInstance->DevicePropertiesArray =
  3099. SCCopyMinidriverProperties(
  3100. StreamDescriptor->StreamHeader.NumDevPropArrayEntries,
  3101. StreamDescriptor->StreamHeader.DevicePropertiesArray))) {
  3102. //
  3103. // Fail to copy
  3104. //
  3105. ASSERT( 0 );
  3106. Status = STATUS_INSUFFICIENT_RESOURCES;
  3107. goto Exit;
  3108. }
  3109. }
  3110. if (StreamDescriptor->StreamHeader.NumDevEventArrayEntries) {
  3111. ASSERT(StreamDescriptor->StreamHeader.DeviceEventsArray);
  3112. //
  3113. // make a copy of the events since we modify the struct
  3114. // though parts of it may be marked as a const.
  3115. // Performance Improvement Chance
  3116. // - check for const in future if possible
  3117. //
  3118. if (!(FilterInstance->EventInfo =
  3119. SCCopyMinidriverEvents(
  3120. StreamDescriptor->StreamHeader.NumDevEventArrayEntries,
  3121. StreamDescriptor->StreamHeader.DeviceEventsArray))) {
  3122. //
  3123. // Fail to copy
  3124. //
  3125. ASSERT( 0 );
  3126. Status = STATUS_INSUFFICIENT_RESOURCES;
  3127. goto Exit;
  3128. }
  3129. }
  3130. #ifdef ENABLE_KS_METHODS
  3131. //
  3132. // process the device methods
  3133. //
  3134. if (StreamDescriptor->StreamHeader.NumDevMethodArrayEntries) {
  3135. ASSERT(StreamDescriptor->StreamHeader.DeviceMethodsArray);
  3136. //
  3137. // make a copy of the properties since we modify the struct
  3138. // though parts of it may be marked as a const.
  3139. // Performance Improvement Chance
  3140. // - check for const in future if possible
  3141. //
  3142. if (!(FilterInstance->DeviceMethodsArray =
  3143. SCCopyMinidriverMethods(
  3144. StreamDescriptor->StreamHeader.NumDevMethodArrayEntries,
  3145. StreamDescriptor->StreamHeader.DeviceMethodsArray))) {
  3146. //
  3147. // Fail to copy
  3148. //
  3149. ASSERT( 0 );
  3150. Status = STATUS_INSUFFICIENT_RESOURCES;
  3151. goto Exit;
  3152. }
  3153. }
  3154. #endif
  3155. //
  3156. // process the minidriver's device properties.
  3157. //
  3158. SCUpdateMinidriverProperties(
  3159. StreamDescriptor->StreamHeader.NumDevPropArrayEntries,
  3160. FilterInstance->DevicePropertiesArray,
  3161. FALSE);
  3162. //
  3163. // process the minidriver's device events.
  3164. //
  3165. SCUpdateMinidriverEvents(
  3166. StreamDescriptor->StreamHeader.NumDevEventArrayEntries,
  3167. FilterInstance->EventInfo,
  3168. FALSE);
  3169. #ifdef ENABLE_KS_METHODS
  3170. //
  3171. // process the minidriver's device methods.
  3172. //
  3173. SCUpdateMinidriverMethods(
  3174. StreamDescriptor->StreamHeader.NumDevMethodArrayEntries,
  3175. FilterInstance->DeviceMethodsArray,
  3176. FALSE);
  3177. #endif
  3178. //
  3179. // set the event info count in the device extension
  3180. //
  3181. FilterInstance->EventInfoCount =
  3182. StreamDescriptor->StreamHeader.NumDevEventArrayEntries;
  3183. FilterInstance->HwEventRoutine =
  3184. StreamDescriptor->StreamHeader.DeviceEventRoutine;
  3185. //
  3186. // call routine to save new stream info
  3187. //
  3188. SciInsertFilterStreamInfo(FilterInstance,
  3189. PinDescs,
  3190. NumberOfPins);
  3191. Exit:{
  3192. // ToDo: need to cleanup in error conditions.
  3193. return Status;
  3194. }
  3195. }
  3196. VOID
  3197. SciInsertFilterStreamInfo(
  3198. IN PFILTER_INSTANCE FilterInstance,
  3199. IN PKSPIN_DESCRIPTOR PinDescs,
  3200. IN ULONG NumberOfPins)
  3201. /*++
  3202. Routine Description:
  3203. Arguments:
  3204. Return Value:
  3205. None.
  3206. --*/
  3207. {
  3208. PAGED_CODE();
  3209. //
  3210. // save the pin info in the dev extension
  3211. //
  3212. if (FilterInstance->PinInformation) {
  3213. ExFreePool(FilterInstance->PinInformation);
  3214. }
  3215. FilterInstance->PinInformation = PinDescs;
  3216. FilterInstance->NumberOfPins = NumberOfPins;
  3217. return;
  3218. }
  3219. NTSTATUS
  3220. SCStreamInfoCallback(
  3221. IN PSTREAM_REQUEST_BLOCK SRB
  3222. )
  3223. /*++
  3224. Routine Description:
  3225. Process the minidriver's stream info structure(s). This is used to
  3226. process an StreamDescriptor list as well as for one StreamInfo when
  3227. called by StreamClassReenumerateFilterStreams() to rescan.
  3228. Arguments:
  3229. SRB - address of the completed SRB
  3230. Return Value:
  3231. None.
  3232. --*/
  3233. {
  3234. PHW_STREAM_DESCRIPTOR StreamDescriptor;
  3235. PDEVICE_EXTENSION DeviceExtension;
  3236. NTSTATUS Status;
  3237. DeviceExtension= (PDEVICE_EXTENSION)SRB->HwSRB.HwDeviceExtension -1;
  3238. ASSERT_DEVICE_EXTENSION( DeviceExtension );
  3239. if ( NULL == SRB->HwSRB.HwInstanceExtension ) {
  3240. //
  3241. // This is a complete list of StreamInfos for the mini driver
  3242. //
  3243. //
  3244. // some validations and Just hang it off the DeviceExtension
  3245. //
  3246. ULONG TotalLength;
  3247. ULONG ul;
  3248. PFILTER_TYPE_INFO FilterTypeInfo;
  3249. PHW_STREAM_DESCRIPTOR NextStreamDescriptor;
  3250. BOOLEAN RequestIssued;
  3251. FilterTypeInfo = DeviceExtension->FilterTypeInfos;
  3252. StreamDescriptor =
  3253. (PHW_STREAM_DESCRIPTOR) SRB->HwSRB.CommandData.StreamBuffer;
  3254. DeviceExtension->StreamDescriptor = StreamDescriptor;
  3255. NextStreamDescriptor = StreamDescriptor;
  3256. Status = STATUS_SUCCESS;
  3257. //
  3258. // take the event early here. an open could come in the middle of
  3259. // enabling device interface.
  3260. //
  3261. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  3262. Executive,
  3263. KernelMode,
  3264. FALSE, // not alertable
  3265. NULL);
  3266. for ( ul=0, TotalLength=0;
  3267. ul < DeviceExtension->NumberOfFilterTypes;
  3268. ul++) {
  3269. //
  3270. // need a StreamDescriptor for each filter type
  3271. //
  3272. if ((TotalLength+sizeof(HW_STREAM_HEADER) >
  3273. SRB->HwSRB.ActualBytesTransferred ) ||
  3274. (sizeof(HW_STREAM_INFORMATION) !=
  3275. NextStreamDescriptor->StreamHeader.SizeOfHwStreamInformation)){
  3276. //
  3277. // Invalid data, bail out
  3278. //
  3279. DEBUG_BREAKPOINT();
  3280. Status = STATUS_INVALID_PARAMETER;
  3281. break;
  3282. }
  3283. if ( !(DeviceExtension->RegistryFlags & DRIVER_USES_SWENUM_TO_LOAD )) {
  3284. //
  3285. // Don't create symbolic link if loaded by SWEnum which
  3286. // will create a duplicate one.
  3287. //
  3288. // create the symbolic link to the device.
  3289. //
  3290. FilterTypeInfo[ul].SymbolicLinks =
  3291. SciCreateSymbolicLinks(
  3292. DeviceExtension,
  3293. ul,
  3294. &NextStreamDescriptor->StreamHeader );
  3295. FilterTypeInfo[ul].LinkNameCount =
  3296. NextStreamDescriptor->StreamHeader.Topology->CategoriesCount;
  3297. }
  3298. else {
  3299. //
  3300. // no creation, 0 count and null pointer.
  3301. //
  3302. FilterTypeInfo[ul].LinkNameCount = 0;
  3303. FilterTypeInfo[ul].SymbolicLinks = NULL;
  3304. }
  3305. FilterTypeInfo[ul].StreamDescriptor = NextStreamDescriptor;
  3306. TotalLength = TotalLength +
  3307. sizeof(HW_STREAM_HEADER) +
  3308. (sizeof(HW_STREAM_INFORMATION) *
  3309. NextStreamDescriptor->StreamHeader.NumberOfStreams);
  3310. DebugPrint((DebugLevelVerbose, "TotalLength=%d\n", TotalLength ));
  3311. NextStreamDescriptor = (PHW_STREAM_DESCRIPTOR)
  3312. ((PBYTE) StreamDescriptor + TotalLength);
  3313. }
  3314. if ( TotalLength != SRB->HwSRB.ActualBytesTransferred ) {
  3315. DebugPrint((DebugLevelWarning,
  3316. "TotalLength %x of StreamInfo not equal to "
  3317. "ActualBytesTransferred %x\n",
  3318. TotalLength,
  3319. SRB->HwSRB.ActualBytesTransferred ));
  3320. }
  3321. DeviceExtension->Flags |= DEVICE_FLAGS_PNP_STARTED;
  3322. //
  3323. // call the minidriver to indicate that initialization is
  3324. // complete.
  3325. //
  3326. SCSubmitRequest(SRB_INITIALIZATION_COMPLETE,
  3327. NULL,
  3328. 0,
  3329. SCDequeueAndDeleteSrb,
  3330. DeviceExtension,
  3331. NULL,
  3332. NULL,
  3333. SRB->HwSRB.Irp,
  3334. &RequestIssued,
  3335. &DeviceExtension->PendingQueue,
  3336. (PVOID) DeviceExtension->MinidriverData->HwInitData.HwReceivePacket
  3337. );
  3338. //
  3339. // tell the device to power down now, since it is not yet opened.
  3340. // acquire the control event since this routine needs it.
  3341. //
  3342. //KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  3343. // Executive,
  3344. // KernelMode,
  3345. // FALSE, // not alertable
  3346. // NULL);
  3347. SCCheckPowerDown(DeviceExtension);
  3348. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  3349. }
  3350. else {
  3351. //
  3352. // This is a rescan for the specific FilterInstance
  3353. //
  3354. PFILTER_INSTANCE FilterInstance;
  3355. FilterInstance = (PFILTER_INSTANCE) SRB->HwSRB.HwInstanceExtension-1;
  3356. StreamDescriptor = (PHW_STREAM_DESCRIPTOR)
  3357. SRB->HwSRB.CommandData.StreamBuffer;
  3358. Status = SciOnFilterStreamDescriptor(
  3359. FilterInstance,
  3360. StreamDescriptor);
  3361. if ( NT_SUCCESS( Status ) ) {
  3362. ASSERT( NULL != FilterInstance->StreamDescriptor );
  3363. ExFreePool( FilterInstance->StreamDescriptor );
  3364. ///if ( InterlockedExchange( &FilterInstance->Reenumerated, 1)) {
  3365. /// ASSERT( FilterInstance->StreamDescriptor );
  3366. /// ExFreePool( FilterInstance->StreamDescriptor );
  3367. ///}
  3368. FilterInstance->StreamDescriptor = StreamDescriptor;
  3369. }
  3370. }
  3371. return (SCProcessCompletedRequest(SRB));
  3372. }
  3373. #else // ENABLE_MULTIPLE_FILTER_TYPES
  3374. NTSTATUS
  3375. SCStreamInfoCallback(
  3376. IN PSTREAM_REQUEST_BLOCK SRB
  3377. )
  3378. /*++
  3379. Routine Description:
  3380. Process the minidriver's stream info structure.
  3381. Arguments:
  3382. SRB - address of the completed SRB
  3383. Return Value:
  3384. None.
  3385. --*/
  3386. {
  3387. PHW_STREAM_DESCRIPTOR StreamDescriptor = SRB->HwSRB.CommandData.StreamBuffer;
  3388. ULONG NumberOfPins,
  3389. i;
  3390. PKSPIN_DESCRIPTOR PinDescs = NULL;
  3391. PHW_STREAM_INFORMATION CurrentInfo;
  3392. PDEVICE_EXTENSION DeviceExtension =
  3393. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  3394. ULONG PinSize;
  3395. BOOLEAN Rescan = FALSE;
  3396. BOOLEAN RequestIssued;
  3397. PSTREAM_ADDITIONAL_INFO NewStreamArray;
  3398. PAGED_CODE();
  3399. //
  3400. // if this is a stream rescan, set the boolean
  3401. //
  3402. if (DeviceExtension->StreamDescriptor) {
  3403. Rescan = TRUE;
  3404. }
  3405. if (NT_SUCCESS(SRB->HwSRB.Status)) {
  3406. NumberOfPins = StreamDescriptor->StreamHeader.NumberOfStreams;
  3407. if (StreamDescriptor->StreamHeader.SizeOfHwStreamInformation < sizeof(HW_STREAM_INFORMATION)) {
  3408. DebugPrint((DebugLevelError,
  3409. "DecoderClassInit: minidriver stream info too small!"));
  3410. DEBUG_BREAKPOINT();
  3411. SRB->HwSRB.Status = STATUS_REVISION_MISMATCH;
  3412. //
  3413. // if this is not a rescan, uninitialize
  3414. //
  3415. if (!Rescan) {
  3416. SCUninitializeMinidriver(DeviceExtension->DeviceObject,
  3417. SRB->HwSRB.Irp);
  3418. }
  3419. return (SCProcessCompletedRequest(SRB));
  3420. }
  3421. if (NumberOfPins) {
  3422. //
  3423. // parse the minidriver's info into CSA format to build the
  3424. // mother of all structures.
  3425. //
  3426. PinSize = (sizeof(KSPIN_DESCRIPTOR) + sizeof(STREAM_ADDITIONAL_INFO)) * NumberOfPins;
  3427. PinDescs = ExAllocatePool(NonPagedPool,
  3428. PinSize);
  3429. if (PinDescs == NULL) {
  3430. DebugPrint((DebugLevelError,
  3431. "DecoderClassInit: No pool for stream info"));
  3432. SRB->HwSRB.Status = STATUS_INSUFFICIENT_RESOURCES;
  3433. //
  3434. // if this is not a rescan, uninitialize
  3435. //
  3436. if (!Rescan) {
  3437. SCUninitializeMinidriver(DeviceExtension->DeviceObject,
  3438. SRB->HwSRB.Irp);
  3439. }
  3440. return (SCProcessCompletedRequest(SRB));
  3441. }
  3442. RtlZeroMemory(PinDescs, PinSize);
  3443. //
  3444. // we need a new array to hold the new copies of the
  3445. // stream properties and events which are allocated below.
  3446. //
  3447. NewStreamArray = (PSTREAM_ADDITIONAL_INFO) ((ULONG_PTR) PinDescs + sizeof(KSPIN_DESCRIPTOR) * NumberOfPins);
  3448. DeviceExtension->StreamPropEventArray = NewStreamArray;
  3449. CurrentInfo = &StreamDescriptor->StreamInfo;
  3450. for (i = 0; i < StreamDescriptor->StreamHeader.NumberOfStreams; i++) {
  3451. PinDescs[i].InterfacesCount = SIZEOF_ARRAY(PinInterfaces);
  3452. PinDescs[i].Interfaces = PinInterfaces;
  3453. //
  3454. // use default medium if minidriver does not specify
  3455. //
  3456. if (CurrentInfo->MediumsCount) {
  3457. PinDescs[i].MediumsCount = CurrentInfo->MediumsCount;
  3458. PinDescs[i].Mediums = CurrentInfo->Mediums;
  3459. } else {
  3460. PinDescs[i].MediumsCount = SIZEOF_ARRAY(PinMediums);
  3461. PinDescs[i].Mediums = PinMediums;
  3462. } // if minidriver mediums
  3463. //
  3464. // set the # of data format blocks
  3465. //
  3466. PinDescs[i].DataRangesCount =
  3467. CurrentInfo->NumberOfFormatArrayEntries;
  3468. //
  3469. // point to the data format blocks for the pin
  3470. //
  3471. PinDescs[i].DataRanges = CurrentInfo->StreamFormatsArray;
  3472. //
  3473. // set the data flow direction
  3474. //
  3475. PinDescs[i].DataFlow = (KSPIN_DATAFLOW) CurrentInfo->DataFlow;
  3476. //
  3477. // set the communication field
  3478. //
  3479. if (CurrentInfo->BridgeStream) {
  3480. PinDescs[i].Communication = KSPIN_COMMUNICATION_BRIDGE;
  3481. } else {
  3482. #ifdef ENABLE_STREAM_CLASS_AS_ALLOCATOR
  3483. PinDescs[i].Communication = KSPIN_COMMUNICATION_BOTH;
  3484. #else
  3485. PinDescs[i].Communication = KSPIN_COMMUNICATION_SINK;
  3486. #endif
  3487. }
  3488. //
  3489. // copy the pointers for the pin name and category
  3490. //
  3491. PinDescs[i].Category = CurrentInfo->Category;
  3492. PinDescs[i].Name = CurrentInfo->Name;
  3493. if ((!Rescan) && (CurrentInfo->NumStreamPropArrayEntries)) {
  3494. ASSERT(CurrentInfo->StreamPropertiesArray);
  3495. //
  3496. // make a copy of the properties since we modify the struct
  3497. // though parts of it may be marked as a const.
  3498. // Performance Improvement Chance
  3499. // - check for const in future if possible
  3500. //
  3501. if (!(NewStreamArray[i].StreamPropertiesArray = SCCopyMinidriverProperties(CurrentInfo->NumStreamPropArrayEntries,
  3502. CurrentInfo->StreamPropertiesArray))) {
  3503. SCUninitializeMinidriver(DeviceExtension->DeviceObject,
  3504. SRB->HwSRB.Irp);
  3505. return (SCProcessCompletedRequest(SRB));
  3506. }
  3507. }
  3508. if ((!Rescan) && (CurrentInfo->NumStreamEventArrayEntries)) {
  3509. ASSERT(CurrentInfo->StreamEventsArray);
  3510. //
  3511. // make a copy of the events since we modify the struct
  3512. // though parts of it may be marked as a const.
  3513. // Performance Improvement Chance:
  3514. // - check for const in future if possible
  3515. //
  3516. if (!(NewStreamArray[i].StreamEventsArray = SCCopyMinidriverEvents(CurrentInfo->NumStreamEventArrayEntries,
  3517. CurrentInfo->StreamEventsArray))) {
  3518. SCUninitializeMinidriver(DeviceExtension->DeviceObject,
  3519. SRB->HwSRB.Irp);
  3520. return (SCProcessCompletedRequest(SRB));
  3521. }
  3522. }
  3523. //
  3524. // update the minidriver's properties for this stream.
  3525. //
  3526. SCUpdateMinidriverProperties(
  3527. CurrentInfo->NumStreamPropArrayEntries,
  3528. NewStreamArray[i].StreamPropertiesArray,
  3529. TRUE);
  3530. //
  3531. // update the minidriver's events for this stream.
  3532. //
  3533. SCUpdateMinidriverEvents(
  3534. CurrentInfo->NumStreamEventArrayEntries,
  3535. NewStreamArray[i].StreamEventsArray,
  3536. TRUE);
  3537. //
  3538. // index to next streaminfo structure.
  3539. //
  3540. CurrentInfo++;
  3541. } // for # pins
  3542. } // if pins
  3543. if ((!Rescan) && (StreamDescriptor->StreamHeader.NumDevPropArrayEntries)) {
  3544. ASSERT(StreamDescriptor->StreamHeader.DevicePropertiesArray);
  3545. //
  3546. // make a copy of the properties since we modify the struct
  3547. // though parts of it may be marked as a const.
  3548. // Performance Improvement Chance:
  3549. // - check for const in future if possible
  3550. //
  3551. if (!(DeviceExtension->DevicePropertiesArray =
  3552. SCCopyMinidriverProperties(StreamDescriptor->StreamHeader.NumDevPropArrayEntries,
  3553. StreamDescriptor->StreamHeader.DevicePropertiesArray))) {
  3554. SCUninitializeMinidriver(DeviceExtension->DeviceObject,
  3555. SRB->HwSRB.Irp);
  3556. return (SCProcessCompletedRequest(SRB));
  3557. }
  3558. }
  3559. if ((!Rescan) && (StreamDescriptor->StreamHeader.NumDevEventArrayEntries)) {
  3560. ASSERT(StreamDescriptor->StreamHeader.DeviceEventsArray);
  3561. //
  3562. // make a copy of the events since we modify the struct
  3563. // though parts of it may be marked as a const.
  3564. // Performance Improvement Chance
  3565. // - check for const in future if possible
  3566. //
  3567. if (!(DeviceExtension->EventInfo =
  3568. SCCopyMinidriverEvents(StreamDescriptor->StreamHeader.NumDevEventArrayEntries,
  3569. StreamDescriptor->StreamHeader.DeviceEventsArray))) {
  3570. SCUninitializeMinidriver(DeviceExtension->DeviceObject,
  3571. SRB->HwSRB.Irp);
  3572. return (SCProcessCompletedRequest(SRB));
  3573. }
  3574. }
  3575. #ifdef ENABLE_KS_METHODS
  3576. //
  3577. // process the device methods
  3578. //
  3579. if ((!Rescan) && (StreamDescriptor->StreamHeader.NumDevMethodArrayEntries)) {
  3580. ASSERT(StreamDescriptor->StreamHeader.DeviceMethodsArray);
  3581. //
  3582. // make a copy of the properties since we modify the struct
  3583. // though parts of it may be marked as a const.
  3584. // Performance Improvement Chance
  3585. // - check for const in future if possible
  3586. //
  3587. if (!(DeviceExtension->DeviceMethodsArray =
  3588. SCCopyMinidriverMethods(StreamDescriptor->StreamHeader.NumDevMethodArrayEntries,
  3589. StreamDescriptor->StreamHeader.DeviceMethodsArray))) {
  3590. SCUninitializeMinidriver(DeviceExtension->DeviceObject,
  3591. SRB->HwSRB.Irp);
  3592. return (SCProcessCompletedRequest(SRB));
  3593. }
  3594. }
  3595. #endif
  3596. //
  3597. // process the minidriver's device properties.
  3598. //
  3599. SCUpdateMinidriverProperties(
  3600. StreamDescriptor->StreamHeader.NumDevPropArrayEntries,
  3601. DeviceExtension->DevicePropertiesArray,
  3602. FALSE);
  3603. //
  3604. // process the minidriver's device events.
  3605. //
  3606. SCUpdateMinidriverEvents(
  3607. StreamDescriptor->StreamHeader.NumDevEventArrayEntries,
  3608. DeviceExtension->EventInfo,
  3609. FALSE);
  3610. #ifdef ENABLE_KS_METHODS
  3611. //
  3612. // process the minidriver's device methods.
  3613. //
  3614. SCUpdateMinidriverMethods(
  3615. StreamDescriptor->StreamHeader.NumDevMethodArrayEntries,
  3616. DeviceExtension->DeviceMethodsArray,
  3617. FALSE);
  3618. #endif
  3619. //
  3620. // set the event info count in the device extension
  3621. //
  3622. DeviceExtension->EventInfoCount = StreamDescriptor->StreamHeader.NumDevEventArrayEntries;
  3623. DeviceExtension->HwEventRoutine = StreamDescriptor->StreamHeader.DeviceEventRoutine;
  3624. //
  3625. // call routine to save new stream info
  3626. //
  3627. SCInsertStreamInfo(DeviceExtension,
  3628. PinDescs,
  3629. StreamDescriptor,
  3630. NumberOfPins);
  3631. if (!Rescan) {
  3632. //
  3633. // show device is started from PNP's perspective
  3634. //
  3635. DeviceExtension->Flags |= DEVICE_FLAGS_PNP_STARTED;
  3636. //
  3637. // create the symbolic link to the device.
  3638. //
  3639. if ( !(DeviceExtension->RegistryFlags & DRIVER_USES_SWENUM_TO_LOAD )) {
  3640. //
  3641. // Don't create symbolic link if loaded by SWEnum which
  3642. // will create a duplicate one.
  3643. //
  3644. // create the symbolic link to the device.
  3645. //
  3646. SCCreateSymbolicLinks(DeviceExtension);
  3647. }
  3648. //
  3649. // call the minidriver to indicate that initialization is
  3650. // complete.
  3651. //
  3652. SCSubmitRequest(SRB_INITIALIZATION_COMPLETE,
  3653. NULL,
  3654. 0,
  3655. SCDequeueAndDeleteSrb,
  3656. DeviceExtension,
  3657. NULL,
  3658. NULL,
  3659. SRB->HwSRB.Irp,
  3660. &RequestIssued,
  3661. &DeviceExtension->PendingQueue,
  3662. (PVOID) DeviceExtension->
  3663. MinidriverData->HwInitData.
  3664. HwReceivePacket
  3665. );
  3666. //
  3667. // tell the device to power down now, since it is not yet opened.
  3668. // acquire the control event since this routine needs it.
  3669. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  3670. Executive,
  3671. KernelMode,
  3672. FALSE, // not alertable
  3673. NULL);
  3674. SCCheckPowerDown(DeviceExtension);
  3675. } // if !rescan
  3676. //
  3677. // release the event. if we are doing a rescan, this is taken
  3678. // by the caller. If not, we took it a few lines above.
  3679. //
  3680. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  3681. } // if good status
  3682. //
  3683. // complete this SRB and the original IRP with the final
  3684. // status.
  3685. //
  3686. return (SCProcessCompletedRequest(SRB));
  3687. }
  3688. VOID
  3689. SCInsertStreamInfo(
  3690. IN PDEVICE_EXTENSION DeviceExtension,
  3691. IN PKSPIN_DESCRIPTOR PinDescs,
  3692. IN PHW_STREAM_DESCRIPTOR StreamDescriptor,
  3693. IN ULONG NumberOfPins
  3694. )
  3695. /*++
  3696. Routine Description:
  3697. Arguments:
  3698. Return Value:
  3699. None.
  3700. --*/
  3701. {
  3702. PAGED_CODE();
  3703. //
  3704. // save the pin info in the dev extension
  3705. //
  3706. if (DeviceExtension->PinInformation) {
  3707. ExFreePool(DeviceExtension->PinInformation);
  3708. }
  3709. DeviceExtension->PinInformation = PinDescs;
  3710. DeviceExtension->NumberOfPins = NumberOfPins;
  3711. //
  3712. // save the minidriver's descriptor also.
  3713. //
  3714. if (DeviceExtension->StreamDescriptor) {
  3715. ExFreePool(DeviceExtension->StreamDescriptor);
  3716. }
  3717. DeviceExtension->StreamDescriptor = StreamDescriptor;
  3718. return;
  3719. }
  3720. #endif //ENABLE_MULTIPLE_FILTER_TYPES
  3721. NTSTATUS
  3722. SCPowerCallback(
  3723. IN PSTREAM_REQUEST_BLOCK SRB
  3724. )
  3725. /*++
  3726. Routine Description:
  3727. SRB callback procedure for powering down the hardware
  3728. Arguments:
  3729. SRB - address of the completed SRB
  3730. Return Value:
  3731. None.
  3732. --*/
  3733. {
  3734. PDEVICE_EXTENSION DeviceExtension =
  3735. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  3736. NTSTATUS Status = SRB->HwSRB.Status;
  3737. PIRP Irp = SRB->HwSRB.Irp;
  3738. PAGED_CODE();
  3739. if ( (NT_SUCCESS(Status)) ||
  3740. (Status == STATUS_NOT_IMPLEMENTED) ||
  3741. (Status == STATUS_NOT_SUPPORTED)) {
  3742. //
  3743. // set the new power state in the device extension.
  3744. //
  3745. SCSetCurrentDPowerState (DeviceExtension, SRB->HwSRB.CommandData.DeviceState);
  3746. //
  3747. // free our SRB structure
  3748. //
  3749. SCDequeueAndDeleteSrb(SRB);
  3750. //
  3751. // set status to SUCCESS in case the minidriver didn't.
  3752. //
  3753. Status = STATUS_SUCCESS;
  3754. //
  3755. // if the state is NOT a power up, we must now send it to the PDO
  3756. // for postprocessing.
  3757. //
  3758. if (DeviceExtension->CurrentPowerState != PowerDeviceD0) {
  3759. //
  3760. // send the Irp down to the next layer, and return that status
  3761. // as the final one.
  3762. //
  3763. Status = SCCallNextDriver(DeviceExtension, Irp);
  3764. #if DBG
  3765. if (!NT_SUCCESS(Status)) {
  3766. DebugPrint((DebugLevelError, "'SCPowerCB: PDO failed power request!\n"));
  3767. }
  3768. #endif
  3769. }
  3770. PoStartNextPowerIrp(Irp);
  3771. SCCompleteIrp(Irp, Status, DeviceExtension);
  3772. } else {
  3773. DEBUG_BREAKPOINT();
  3774. //
  3775. // complete the request with error
  3776. //
  3777. PoStartNextPowerIrp(Irp);
  3778. SCProcessCompletedRequest(SRB);
  3779. }
  3780. return (Status);
  3781. }
  3782. NTSTATUS
  3783. SCUninitializeMinidriver(
  3784. IN PDEVICE_OBJECT DeviceObject,
  3785. IN PIRP Irp)
  3786. /*++
  3787. Routine Description:
  3788. This function calls the minidriver's HWUninitialize routine. If
  3789. successful, all adapter resources are freed, and the adapter is marked
  3790. as stopped.
  3791. Arguments:
  3792. DeviceObject - pointer to device object for adapter
  3793. Irp - pointer to the PNP Irp.
  3794. Return Value:
  3795. NT status code is returned.
  3796. --*/
  3797. {
  3798. PHW_INITIALIZATION_DATA HwInitData;
  3799. PDEVICE_EXTENSION DeviceExtension;
  3800. NTSTATUS Status;
  3801. BOOLEAN RequestIssued;
  3802. PAGED_CODE();
  3803. //
  3804. // call minidriver to indicate we are uninitializing.
  3805. //
  3806. DeviceExtension = DeviceObject->DeviceExtension;
  3807. //
  3808. // remove the symbolic links for the device
  3809. //
  3810. SCDestroySymbolicLinks(DeviceExtension);
  3811. //
  3812. // show one less I/O on this call since our wait logic won't
  3813. // finish until the I/O count goes to zero.
  3814. //
  3815. InterlockedDecrement(&DeviceExtension->OneBasedIoCount);
  3816. //
  3817. // wait for any outstanding I/O to complete
  3818. //
  3819. SCWaitForOutstandingIo(DeviceExtension);
  3820. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  3821. Executive,
  3822. KernelMode,
  3823. FALSE,// not alertable
  3824. NULL);
  3825. // release event at the callback. or next if !RequestIssued.
  3826. //
  3827. // restore I/O count to one as we have the PNP I/O outstanding.
  3828. //
  3829. InterlockedIncrement(&DeviceExtension->OneBasedIoCount);
  3830. HwInitData = &DeviceExtension->MinidriverData->HwInitData;
  3831. Status = SCSubmitRequest(SRB_UNINITIALIZE_DEVICE,
  3832. NULL,
  3833. 0,
  3834. SCUninitializeCallback,
  3835. DeviceExtension,
  3836. NULL,
  3837. NULL,
  3838. Irp,
  3839. &RequestIssued,
  3840. &DeviceExtension->PendingQueue,
  3841. (PVOID) DeviceExtension->
  3842. MinidriverData->HwInitData.
  3843. HwReceivePacket);
  3844. if (!RequestIssued) {
  3845. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  3846. }
  3847. return (Status);
  3848. }
  3849. NTSTATUS
  3850. SCUninitializeCallback(
  3851. IN PSTREAM_REQUEST_BLOCK SRB
  3852. )
  3853. /*++
  3854. Routine Description:
  3855. SRB callback procedure for uninitialize
  3856. Arguments:
  3857. SRB - pointer to the uninitialize SRB
  3858. Return Value:
  3859. NT status code is returned.
  3860. --*/
  3861. {
  3862. PDEVICE_EXTENSION DeviceExtension =
  3863. (PDEVICE_EXTENSION) SRB->HwSRB.HwDeviceExtension - 1;
  3864. PDEVICE_OBJECT DeviceObject = DeviceExtension->DeviceObject;
  3865. PIRP Irp = SRB->HwSRB.Irp;
  3866. NTSTATUS Status = SRB->HwSRB.Status;
  3867. PAGED_CODE();
  3868. //
  3869. // free all adapter resources we allocated on the START
  3870. // function if the minidriver did not fail
  3871. //
  3872. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  3873. if (Status != STATUS_ADAPTER_HARDWARE_ERROR) {
  3874. //
  3875. // show not started
  3876. //
  3877. DeviceExtension->Flags &= ~DEVICE_FLAGS_PNP_STARTED;
  3878. //
  3879. // free all resources on our device.
  3880. //
  3881. SCFreeAllResources(DeviceExtension);
  3882. } // if hwuninitialize
  3883. //
  3884. // free the SRB but don't call back the IRP.
  3885. //
  3886. SCDequeueAndDeleteSrb(SRB);
  3887. return (Status);
  3888. }
  3889. PVOID
  3890. StreamClassGetDmaBuffer(
  3891. IN PVOID HwDeviceExtension)
  3892. /*++
  3893. Routine Description:
  3894. This function returns the DMA buffer previously allocated.
  3895. Arguments:
  3896. HwDeviceExtension - Supplies a pointer to the minidriver's device extension.
  3897. Return Value:
  3898. A pointer to the uncached device extension or NULL if the extension could
  3899. not be allocated.
  3900. --*/
  3901. {
  3902. PDEVICE_EXTENSION DeviceExtension =
  3903. (PDEVICE_EXTENSION) HwDeviceExtension - 1;
  3904. return (DeviceExtension->DmaBuffer);
  3905. }
  3906. NTSTATUS
  3907. DriverEntry(
  3908. IN PDRIVER_OBJECT DriverObject,
  3909. IN PUNICODE_STRING RegistryPath
  3910. )
  3911. /*++
  3912. Routine Description:
  3913. Entry point for explicitely loaded stream class.
  3914. Arguments:
  3915. DriverObject - Pointer to the driver object created by the system.
  3916. RegistryPath - unused.
  3917. Return Value:
  3918. STATUS_SUCCESS
  3919. --*/
  3920. {
  3921. UNREFERENCED_PARAMETER(DriverObject);
  3922. PAGED_CODE();
  3923. DEBUG_BREAKPOINT();
  3924. return STATUS_SUCCESS;
  3925. }
  3926. #if DBG
  3927. #define DEFAULT_STREAMDEBUG 1
  3928. #define DEFAULT_MAX_LOG_ENTRIES 1024
  3929. #define SCLOG_LEVEL 0
  3930. #define SCLOG_MASK 0
  3931. #define SCLOG_FL_PNP 0x0001
  3932. #define STR_REG_DBG_STREAM L"\\Registry\\Machine\\system\\currentcontrolset\\services\\stream"
  3933. typedef struct _SCLOG_ENTRY {
  3934. ULONG ulTag;
  3935. ULONG ulArg1;
  3936. ULONG ulArg2;
  3937. ULONG ulArg3;
  3938. } SCLOG_ENTRY, *PSCLOG_ENTRY;
  3939. PSCLOG_ENTRY psclogBuffer;
  3940. ULONG scLogNextEntry;
  3941. ULONG scMaxLogEntries;
  3942. ULONG sclogMask;
  3943. ULONG ulTimeIncrement;
  3944. NTSTATUS
  3945. SCLog(
  3946. ULONG ulTag,
  3947. ULONG ulArg1,
  3948. ULONG ulArg2,
  3949. ULONG ulArg3 )
  3950. /*++
  3951. Description:
  3952. Log the information to the psclogBuffer in a circular mannar. Start from entry 0.
  3953. Wrap around when we hit the end.
  3954. Parameters:
  3955. ulTag: Tag for the log entry
  3956. ulArg1: argument 1
  3957. ulArg2: argument 2
  3958. ulArg3: argument 3
  3959. Return:
  3960. SUCCESS: if logged
  3961. UNSUCCESSFUL: otherwise
  3962. --*/
  3963. {
  3964. NTSTATUS Status=STATUS_UNSUCCESSFUL;
  3965. ULONG ulMyLogEntry;
  3966. if ( NULL == psclogBuffer ) return Status;
  3967. //
  3968. // grab the line ticket
  3969. //
  3970. ulMyLogEntry = (ULONG)InterlockedIncrement( &scLogNextEntry );
  3971. //
  3972. // land in the range
  3973. //
  3974. ulMyLogEntry = ulMyLogEntry % scMaxLogEntries;
  3975. //
  3976. // fill the entry
  3977. //
  3978. psclogBuffer[ulMyLogEntry].ulTag = ulTag;
  3979. psclogBuffer[ulMyLogEntry].ulArg1 = ulArg1;
  3980. psclogBuffer[ulMyLogEntry].ulArg2 = ulArg2;
  3981. psclogBuffer[ulMyLogEntry].ulArg3 = ulArg3;
  3982. if ( sclogMask & SCLOG_FLAGS_PRINT) {
  3983. char *pCh=(char*) &ulTag;
  3984. DbgPrint( "++scLOG %c%c%c%c %08x %08x %08x\n",
  3985. pCh[0], pCh[1], pCh[2], pCh[3],
  3986. ulArg1,
  3987. ulArg2,
  3988. ulArg3);
  3989. }
  3990. return STATUS_SUCCESS;
  3991. }
  3992. NTSTATUS SCLogWithTime(
  3993. ULONG ulTag,
  3994. ULONG ulArg1,
  3995. ULONG ulArg2 )
  3996. /*++
  3997. Description:
  3998. A wrapper to SCLog to also log time in ms in the record. We can have one less
  3999. Argument because time use 1.
  4000. Parameters:
  4001. ulTag: Tag for the log entry
  4002. ulArg1: argument 1
  4003. ulArg2: argument 2
  4004. Return:
  4005. SUCCESS: if logged
  4006. UNSUCCESSFUL: otherwise
  4007. --*/
  4008. {
  4009. LARGE_INTEGER liTime;
  4010. ULONG ulTime;
  4011. KeQueryTickCount(&liTime);
  4012. ulTime = (ULONG)(liTime.QuadPart*ulTimeIncrement/10000); // convert to ms
  4013. if ( NULL == psclogBuffer ) return STATUS_UNSUCCESSFUL;
  4014. return SCLog( ulTag, ulArg1, ulArg2, ulTime );
  4015. }
  4016. NTSTATUS
  4017. DbgDllUnload()
  4018. /*++
  4019. called by DllUnload to undo the work at DllInitialize
  4020. --*/
  4021. {
  4022. if ( NULL != psclogBuffer ) {
  4023. ExFreePool( psclogBuffer );
  4024. }
  4025. return STATUS_SUCCESS;
  4026. }
  4027. NTSTATUS
  4028. SCGetRegValue(
  4029. IN HANDLE KeyHandle,
  4030. IN PWSTR ValueName,
  4031. OUT PKEY_VALUE_FULL_INFORMATION *Information
  4032. )
  4033. /*++
  4034. Routine Description:
  4035. Copied from IopGetRegistryValue().
  4036. This routine is invoked to retrieve the data for a registry key's value.
  4037. This is done by querying the value of the key with a zero-length buffer
  4038. to determine the size of the value, and then allocating a buffer and
  4039. actually querying the value into the buffer.
  4040. It is the responsibility of the caller to free the buffer.
  4041. Arguments:
  4042. KeyHandle - Supplies the key handle whose value is to be queried
  4043. ValueName - Supplies the null-terminated Unicode name of the value.
  4044. Information - Returns a pointer to the allocated data buffer.
  4045. Return Value:
  4046. The function value is the final status of the query operation.
  4047. --*/
  4048. {
  4049. UNICODE_STRING unicodeString;
  4050. NTSTATUS status;
  4051. PKEY_VALUE_FULL_INFORMATION infoBuffer;
  4052. ULONG keyValueLength;
  4053. PAGED_CODE();
  4054. RtlInitUnicodeString( &unicodeString, ValueName );
  4055. //
  4056. // Figure out how big the data value is so that a buffer of the
  4057. // appropriate size can be allocated.
  4058. //
  4059. status = ZwQueryValueKey( KeyHandle,
  4060. &unicodeString,
  4061. KeyValueFullInformation,
  4062. (PVOID) NULL,
  4063. 0,
  4064. &keyValueLength );
  4065. if (status != STATUS_BUFFER_OVERFLOW &&
  4066. status != STATUS_BUFFER_TOO_SMALL) {
  4067. return status;
  4068. }
  4069. //
  4070. // Allocate a buffer large enough to contain the entire key data value.
  4071. //
  4072. infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength );
  4073. if (!infoBuffer) {
  4074. return STATUS_INSUFFICIENT_RESOURCES;
  4075. }
  4076. //
  4077. // Query the data for the key value.
  4078. //
  4079. status = ZwQueryValueKey( KeyHandle,
  4080. &unicodeString,
  4081. KeyValueFullInformation,
  4082. infoBuffer,
  4083. keyValueLength,
  4084. &keyValueLength );
  4085. if (!NT_SUCCESS( status )) {
  4086. ExFreePool( infoBuffer );
  4087. return status;
  4088. }
  4089. //
  4090. // Everything worked, so simply return the address of the allocated
  4091. // buffer to the caller, who is now responsible for freeing it.
  4092. //
  4093. *Information = infoBuffer;
  4094. return STATUS_SUCCESS;
  4095. }
  4096. NTSTATUS
  4097. SCGetRegDword(
  4098. HANDLE h,
  4099. PWCHAR ValueName,
  4100. PULONG pDword)
  4101. {
  4102. NTSTATUS Status;
  4103. PKEY_VALUE_FULL_INFORMATION pFullInfo;
  4104. Status = SCGetRegValue( h, ValueName, &pFullInfo );
  4105. if ( NT_SUCCESS( Status ) ) {
  4106. *pDword = *(PULONG)((PUCHAR)pFullInfo+pFullInfo->DataOffset);
  4107. ExFreePool( pFullInfo );
  4108. }
  4109. return Status;
  4110. }
  4111. NTSTATUS
  4112. SCSetRegDword(
  4113. IN HANDLE KeyHandle,
  4114. IN PWCHAR ValueName,
  4115. IN ULONG ValueData
  4116. )
  4117. /*++
  4118. Routine Description:
  4119. Sets a value key in the registry to a specific value of string (REG_SZ)
  4120. type.
  4121. Parameters:
  4122. KeyHandle - A handle to the key under which the value is stored.
  4123. ValueName - Supplies a pointer to the name of the value key
  4124. ValueData - Supplies a pointer to the value to be stored in the key.
  4125. Return Value:
  4126. Status code that indicates whether or not the function was successful.
  4127. --*/
  4128. {
  4129. NTSTATUS Status;
  4130. UNICODE_STRING unicodeString;
  4131. PAGED_CODE();
  4132. ASSERT(ValueName);
  4133. RtlInitUnicodeString( &unicodeString, ValueName );
  4134. //
  4135. // Set the registry value
  4136. //
  4137. Status = ZwSetValueKey(KeyHandle,
  4138. &unicodeString,
  4139. 0,
  4140. REG_DWORD,
  4141. &ValueData,
  4142. sizeof(ValueData));
  4143. return Status;
  4144. }
  4145. NTSTATUS
  4146. SCCreateDbgReg(void)
  4147. {
  4148. NTSTATUS Status;
  4149. HANDLE hStreamDebug;
  4150. OBJECT_ATTRIBUTES objectAttributes;
  4151. UNICODE_STRING PathName;
  4152. UNICODE_STRING uiStreamDebug;
  4153. ULONG ulDisposition;
  4154. ULONG dword;
  4155. static WCHAR strStreamDebug[]=L"StreamDebug";
  4156. static WCHAR strMaxLogEntries[]=L"MaxLogEntries";
  4157. static WCHAR strLogMask[]=L"MaxMask";
  4158. RtlInitUnicodeString( &PathName, STR_REG_DBG_STREAM );
  4159. InitializeObjectAttributes(&objectAttributes,
  4160. &PathName,
  4161. OBJ_CASE_INSENSITIVE,
  4162. NULL,
  4163. NULL);
  4164. Status = ZwCreateKey( &hStreamDebug,
  4165. KEY_ALL_ACCESS,
  4166. &objectAttributes,
  4167. 0, // title index
  4168. NULL, // class
  4169. 0,// create options
  4170. &ulDisposition);
  4171. if ( NT_SUCCESS( Status )) {
  4172. //
  4173. // getset StreamDebug
  4174. //
  4175. Status = SCGetRegDword( hStreamDebug, strStreamDebug, &dword);
  4176. if ( NT_SUCCESS( Status )) {
  4177. extern ULONG StreamDebug;
  4178. StreamDebug = dword;
  4179. }
  4180. else if ( STATUS_OBJECT_NAME_NOT_FOUND == Status ) {
  4181. //
  4182. // create one with the default value
  4183. //
  4184. Status = SCSetRegDword(hStreamDebug, strStreamDebug, DEFAULT_STREAMDEBUG);
  4185. ASSERT( NT_SUCCESS( Status ));
  4186. }
  4187. //
  4188. // getset LogMask
  4189. //
  4190. Status = SCGetRegDword( hStreamDebug, strLogMask, &dword);
  4191. if ( NT_SUCCESS( Status )) {
  4192. sclogMask=dword;
  4193. }
  4194. else if ( STATUS_OBJECT_NAME_NOT_FOUND == Status ) {
  4195. //
  4196. // create one with the default to all ( 0x7fffffff )
  4197. //
  4198. Status = SCSetRegDword(hStreamDebug, strLogMask, 0x7fffffff);
  4199. ASSERT( NT_SUCCESS( Status ));
  4200. }
  4201. //
  4202. // getset MaxLogEntries
  4203. //
  4204. Status = SCGetRegDword( hStreamDebug, strMaxLogEntries, &dword);
  4205. if ( NT_SUCCESS( Status )) {
  4206. scMaxLogEntries=dword;
  4207. }
  4208. else if ( STATUS_OBJECT_NAME_NOT_FOUND == Status ) {
  4209. //
  4210. // create one with the default value
  4211. //
  4212. Status = SCSetRegDword(hStreamDebug, strMaxLogEntries, DEFAULT_MAX_LOG_ENTRIES);
  4213. ASSERT( NT_SUCCESS( Status ));
  4214. }
  4215. ZwClose( hStreamDebug );
  4216. }
  4217. return Status;
  4218. }
  4219. NTSTATUS
  4220. SCInitDbg(
  4221. void )
  4222. {
  4223. NTSTATUS Status;
  4224. Status = SCCreateDbgReg(); // read or create
  4225. if ( NT_SUCCESS( Status ) ) {
  4226. if ( scMaxLogEntries ) {
  4227. psclogBuffer = ExAllocatePool( NonPagedPool, scMaxLogEntries*sizeof(SCLOG_ENTRY));
  4228. if ( NULL == psclogBuffer ) {
  4229. DbgPrint( "SC: Cant allocate log buffer for %d entries\n", scMaxLogEntries );
  4230. sclogMask = 0; // disable logging
  4231. }
  4232. else {
  4233. DbgPrint( "SC: Allocate log buffer for %d entries\n", scMaxLogEntries );
  4234. ulTimeIncrement = KeQueryTimeIncrement();
  4235. }
  4236. }
  4237. }
  4238. return Status;
  4239. }
  4240. #endif // DBG
  4241. NTSTATUS
  4242. DllInitialize(
  4243. IN PUNICODE_STRING RegistryPath
  4244. )
  4245. /*++
  4246. Description:
  4247. System invokes this entry point when it load the image in memory.
  4248. Arguments:
  4249. RegistryPath - unreferenced parameter.
  4250. Return:
  4251. STATUS_SUCCESS or appropriate error code.
  4252. --*/
  4253. {
  4254. //UNICODE_STRING DriverName;
  4255. NTSTATUS Status=STATUS_SUCCESS;
  4256. PAGED_CODE();
  4257. #if DBG
  4258. Status = SCInitDbg();
  4259. #endif
  4260. //RtlInitUnicodeString(&DriverName, STREAM_DRIVER_NAME);
  4261. //Status = IoCreateDriver(&DriverName, StreamDriverEntry);
  4262. if(!NT_SUCCESS(Status)){
  4263. DbgPrint("Stream DLL Initialization failed = %x\n",Status);
  4264. ASSERT(FALSE);
  4265. }
  4266. return Status;
  4267. }
  4268. VOID
  4269. SCFreeAllResources(
  4270. IN PDEVICE_EXTENSION DeviceExtension
  4271. )
  4272. /*++
  4273. Routine Description:
  4274. This functions deletes all of the storage associated with a device
  4275. extension, disconnects from the timers and interrupts.
  4276. This function can be called any time during the initialization.
  4277. Arguments:
  4278. DeviceExtension - Supplies a pointer to the device extension to be processed.
  4279. Return Value:
  4280. None.
  4281. --*/
  4282. {
  4283. PMAPPED_ADDRESS tempPointer;
  4284. PPORT_CONFIGURATION_INFORMATION ConfigInfo;
  4285. PADAPTER_OBJECT DmaAdapterObject;
  4286. ULONG DmaBufferSize;
  4287. ULONG i;
  4288. PSTREAM_ADDITIONAL_INFO NewStreamArray;
  4289. PAGED_CODE();
  4290. DebugPrint((DebugLevelTrace, "'SCFreeAllResources: enter\n"));
  4291. //
  4292. // take the event to avoid race with the CLOSE handler, which is
  4293. // the only code that will be executed at this point since the
  4294. // INACCESSIBLE bit has been set.
  4295. //
  4296. KeWaitForSingleObject(&DeviceExtension->ControlEvent,
  4297. Executive,
  4298. KernelMode,
  4299. FALSE,// not alertable
  4300. NULL);
  4301. //
  4302. // if an interrupt is in use, disconnect from it.
  4303. //
  4304. if ((DeviceExtension->InterruptObject != (PKINTERRUPT) DeviceExtension) &&
  4305. (DeviceExtension->InterruptObject != NULL)) {
  4306. DebugPrint((DebugLevelVerbose, "'SCFreeAllResources: Interrupt Disconnect\n"));
  4307. IoDisconnectInterrupt(DeviceExtension->InterruptObject);
  4308. //
  4309. // change the synchronization mechanism to internal, since
  4310. // the IRQ is gone away, hence IRQL level sync.
  4311. //
  4312. DeviceExtension->SynchronizeExecution = StreamClassSynchronizeExecution;
  4313. DeviceExtension->InterruptObject = (PVOID) DeviceExtension;
  4314. }
  4315. //
  4316. // Free the configuration information structure if it exists.
  4317. //
  4318. ConfigInfo = DeviceExtension->ConfigurationInformation;
  4319. if (ConfigInfo) {
  4320. //
  4321. // free the access range structure if it exists
  4322. //
  4323. if (ConfigInfo->AccessRanges) {
  4324. ExFreePool(ConfigInfo->AccessRanges);
  4325. }
  4326. DebugPrint((DebugLevelVerbose, "'SCFreeAllResources: freeing ConfigurationInfo\n"));
  4327. ExFreePool(ConfigInfo);
  4328. DeviceExtension->ConfigurationInformation = NULL;
  4329. }
  4330. //
  4331. // free the DMA adapter object and DMA buffer if present
  4332. //
  4333. DmaAdapterObject = DeviceExtension->DmaAdapterObject;
  4334. if (DmaAdapterObject) {
  4335. DmaBufferSize = DeviceExtension->DriverInfo->HwInitData.DmaBufferSize;
  4336. if (DeviceExtension->DmaBufferPhysical.QuadPart) {
  4337. //
  4338. // free the DMA buffer
  4339. //
  4340. DebugPrint((DebugLevelVerbose, "'StreamClass SCFreeAllResources- Freeing DMA stuff\n"));
  4341. HalFreeCommonBuffer(DmaAdapterObject,
  4342. DmaBufferSize,
  4343. DeviceExtension->DmaBufferPhysical,
  4344. DeviceExtension->DmaBuffer,
  4345. FALSE);
  4346. }
  4347. DeviceExtension->DmaAdapterObject = NULL;
  4348. }
  4349. //
  4350. // Unmap any mapped areas.
  4351. //
  4352. while (DeviceExtension->MappedAddressList != NULL) {
  4353. DebugPrint((DebugLevelVerbose, "'SCFreeAllResources: unmapping addresses\n"));
  4354. MmUnmapIoSpace(
  4355. DeviceExtension->MappedAddressList->MappedAddress,
  4356. DeviceExtension->MappedAddressList->NumberOfBytes
  4357. );
  4358. tempPointer = DeviceExtension->MappedAddressList;
  4359. DeviceExtension->MappedAddressList =
  4360. DeviceExtension->MappedAddressList->NextMappedAddress;
  4361. ExFreePool(tempPointer);
  4362. }
  4363. DeviceExtension->MappedAddressList = NULL;
  4364. //
  4365. // We can't free FilterInstances or PinInstances. They
  4366. // must be freed at close calls. However, release StreamDescriptor
  4367. // which is allocated at Start device
  4368. //
  4369. if ( DeviceExtension->StreamDescriptor ) {
  4370. ExFreePool( DeviceExtension->StreamDescriptor );
  4371. DeviceExtension->StreamDescriptor = NULL;
  4372. }
  4373. //
  4374. // Stop our timers and release event.
  4375. //
  4376. IoStopTimer(DeviceExtension->DeviceObject);
  4377. KeCancelTimer(&DeviceExtension->ComObj.MiniDriverTimer);
  4378. KeSetEvent(&DeviceExtension->ControlEvent, IO_NO_INCREMENT, FALSE);
  4379. }
  4380. #if ENABLE_MULTIPLE_FILTER_TYPES
  4381. NTSTATUS
  4382. SciFreeFilterInstance(
  4383. PFILTER_INSTANCE pFilterInstance
  4384. )
  4385. /*++
  4386. Free all resources associated with a FilterInstance and the filter
  4387. instance itself. This function assume Device control event is taken
  4388. by the caller.
  4389. Argument:
  4390. pFilterInstance : pointer to the filter instance to free
  4391. Return:
  4392. NTSTATUS: STATUS_SUCCESS of successful, error otherwise
  4393. --*/
  4394. {
  4395. PDEVICE_EXTENSION pDeviceExtension;
  4396. PSTREAM_ADDITIONAL_INFO NewStreamArray;
  4397. ULONG i;
  4398. ASSERT_FILTER_INSTANCE( pFilterInstance );
  4399. pDeviceExtension = pFilterInstance->DeviceExtension;
  4400. ASSERT_DEVICE_EXTENSION( pDeviceExtension );
  4401. NewStreamArray = pFilterInstance->StreamPropEventArray;
  4402. pFilterInstance->StreamPropEventArray = NULL;
  4403. DebugPrint((DebugLevelInfo,
  4404. "Freeing filterinstance %x\n", pFilterInstance));
  4405. while (!IsListEmpty( &pFilterInstance->FirstStream )) {
  4406. //
  4407. // free all stream instances
  4408. //
  4409. PLIST_ENTRY Node;
  4410. PSTREAM_OBJECT StreamObject;
  4411. DebugPrint((DebugLevelWarning,
  4412. "Freeing filterinstance %x still open streams\n", pFilterInstance));
  4413. Node = RemoveHeadList( &pFilterInstance->FirstStream );
  4414. StreamObject = CONTAINING_RECORD(Node,
  4415. STREAM_OBJECT,
  4416. NextStream);
  4417. if ( NULL != StreamObject->ComObj.DeviceHeader ) {
  4418. KsFreeObjectHeader( StreamObject->ComObj.DeviceHeader );
  4419. }
  4420. //
  4421. // null out FsContext for "surprise" stop cases
  4422. //
  4423. ASSERT( StreamObject->FileObject );
  4424. ASSERT( StreamObject->FileObject->FsContext );
  4425. StreamObject->FileObject->FsContext = NULL;
  4426. ExFreePool( StreamObject );
  4427. }
  4428. if (pFilterInstance->StreamDescriptor) {
  4429. //
  4430. // free each of the property buffers for the pins
  4431. //
  4432. DebugPrint((DebugLevelInfo,
  4433. "FI StreamDescriptor %x has %x pins\n",
  4434. pFilterInstance->StreamDescriptor,
  4435. pFilterInstance->StreamDescriptor->StreamHeader.NumberOfStreams));
  4436. for (i = 0;
  4437. i < pFilterInstance->StreamDescriptor->StreamHeader.NumberOfStreams;
  4438. i++) {
  4439. if (NewStreamArray[i].StreamPropertiesArray) {
  4440. DebugPrint((DebugLevelInfo,"\tFree pin %x Prop %x\n",
  4441. i, NewStreamArray[i].StreamPropertiesArray));
  4442. ExFreePool(NewStreamArray[i].StreamPropertiesArray);
  4443. }
  4444. if (NewStreamArray[i].StreamEventsArray) {
  4445. DebugPrint((DebugLevelInfo,"\tFree pin %x event %x\n",
  4446. i, NewStreamArray[i].StreamEventsArray));
  4447. ExFreePool(NewStreamArray[i].StreamEventsArray);
  4448. }
  4449. }
  4450. if (pFilterInstance->DevicePropertiesArray) {
  4451. DebugPrint((DebugLevelInfo,"Free dev prop %x\n",
  4452. pFilterInstance->DevicePropertiesArray));
  4453. ExFreePool(pFilterInstance->DevicePropertiesArray);
  4454. pFilterInstance->DevicePropertiesArray = NULL;
  4455. }
  4456. if (pFilterInstance->EventInfo) {
  4457. DebugPrint((DebugLevelInfo,"Free dev Event %x\n",
  4458. pFilterInstance->EventInfo));
  4459. ExFreePool(pFilterInstance->EventInfo);
  4460. pFilterInstance->EventInfo = NULL;
  4461. }
  4462. //
  4463. // always allocate, always free
  4464. //
  4465. DebugPrint((DebugLevelInfo,"Free StreamDescriptor %x\n",
  4466. pFilterInstance->StreamDescriptor));
  4467. ExFreePool(pFilterInstance->StreamDescriptor);
  4468. pFilterInstance->StreamDescriptor = NULL;
  4469. }
  4470. if (pFilterInstance->PinInformation) {
  4471. DebugPrint((DebugLevelInfo,"Free pininformationn %x\n",
  4472. pFilterInstance->PinInformation));
  4473. ExFreePool(pFilterInstance->PinInformation);
  4474. pFilterInstance->PinInformation = NULL;
  4475. }
  4476. if ( NULL != pFilterInstance->DeviceHeader ) {
  4477. KsFreeObjectHeader( pFilterInstance->DeviceHeader );
  4478. pFilterInstance->DeviceHeader = NULL;
  4479. }
  4480. if ( pFilterInstance->WorkerRead ) {
  4481. KsUnregisterWorker( pFilterInstance->WorkerRead );
  4482. pFilterInstance->WorkerRead = NULL;
  4483. }
  4484. if ( pFilterInstance->WorkerWrite ) {
  4485. KsUnregisterWorker( pFilterInstance->WorkerWrite );
  4486. pFilterInstance->WorkerWrite = NULL;
  4487. }
  4488. //
  4489. // finally the pFilterInstance itself.
  4490. //
  4491. ExFreePool( pFilterInstance );
  4492. return STATUS_SUCCESS;
  4493. }
  4494. VOID
  4495. SCDestroySymbolicLinks(
  4496. IN PDEVICE_EXTENSION DeviceExtension)
  4497. /*++
  4498. Routine Description:
  4499. For all device interfaces of all filter types of a device, disable
  4500. it and free the name list ofeach filter type
  4501. Arguments:
  4502. DeviceExtension - pointer to the device extension to be processed.
  4503. Return Value:
  4504. None.
  4505. --*/
  4506. {
  4507. PFILTER_TYPE_INFO FilterTypeInfo;
  4508. ULONG i, j;
  4509. UNICODE_STRING *LinkNames;
  4510. ULONG LinkNameCount;
  4511. PAGED_CODE();
  4512. for ( i =0; i < DeviceExtension->NumberOfFilterTypes; i++ ) {
  4513. LinkNames = DeviceExtension->FilterTypeInfos[i].SymbolicLinks;
  4514. LinkNameCount = DeviceExtension->FilterTypeInfos[i].LinkNameCount;
  4515. //
  4516. // if no names array, we're done.
  4517. //
  4518. if ( NULL == LinkNames ) {
  4519. continue;
  4520. }
  4521. //
  4522. // loop through each of the catagory GUID's for each of the pins,
  4523. // deleting the symbolic link for each one.
  4524. //
  4525. for (j = 0; j < LinkNameCount; j++) {
  4526. if (LinkNames[j].Buffer) {
  4527. //
  4528. // Delete the symbolic link, ignoring the status.
  4529. //
  4530. DebugPrint((DebugLevelVerbose,
  4531. " Deleteing symbolic link %S\n",
  4532. LinkNames[j].Buffer));
  4533. IoSetDeviceInterfaceState(&LinkNames[j], FALSE);
  4534. //
  4535. // free the buffer allocated by
  4536. // IoRegisterDeviceClassAssociation.
  4537. //
  4538. ExFreePool(LinkNames[j].Buffer);
  4539. }
  4540. }
  4541. //
  4542. // free the links structure and null the pointer
  4543. //
  4544. ExFreePool(LinkNames);
  4545. DeviceExtension->FilterTypeInfos[i].SymbolicLinks = NULL;
  4546. } // for # of FilterTypes
  4547. return;
  4548. }
  4549. #else // ENABLE_MULTIPLE_FILTER_TYPES
  4550. VOID
  4551. SCCreateSymbolicLinks(
  4552. IN PDEVICE_EXTENSION DeviceExtension
  4553. )
  4554. /*++
  4555. Routine Description:
  4556. Arguments:
  4557. DeviceExtension - Supplies a pointer to the device extension to be processed.
  4558. Return Value:
  4559. None.
  4560. --*/
  4561. {
  4562. PHW_STREAM_DESCRIPTOR StreamDescriptor = DeviceExtension->StreamDescriptor;
  4563. LPGUID GuidIndex = (LPGUID) StreamDescriptor->StreamHeader.Topology->Categories;
  4564. ULONG ArrayCount = StreamDescriptor->StreamHeader.Topology->CategoriesCount;
  4565. UNICODE_STRING *NamesArray;
  4566. ULONG i;
  4567. HANDLE ClassHandle,
  4568. PdoHandle;
  4569. UNICODE_STRING TempUnicodeString;
  4570. PVOID DataBuffer[MAX_STRING_LENGTH];
  4571. PAGED_CODE();
  4572. //
  4573. // allocate space for the array of catagory names
  4574. //
  4575. if (!(NamesArray = ExAllocatePool(PagedPool,
  4576. sizeof(UNICODE_STRING) * ArrayCount))) {
  4577. return;
  4578. }
  4579. //
  4580. // zero the array in case we're unable to fill it in below. the Destroy
  4581. // routine below will then correctly handle this case.
  4582. //
  4583. RtlZeroMemory(NamesArray,
  4584. sizeof(UNICODE_STRING) * ArrayCount);
  4585. DeviceExtension->SymbolicLinks = NamesArray;
  4586. //
  4587. // open the PDO
  4588. //
  4589. if (!NT_SUCCESS(IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
  4590. PLUGPLAY_REGKEY_DRIVER,
  4591. STANDARD_RIGHTS_ALL,
  4592. &PdoHandle))) {
  4593. DebugPrint((DebugLevelError, "StreamCreateSymLinks: couldn't open\n"));
  4594. return;
  4595. }
  4596. //
  4597. // loop through each of the catagory GUID's for each of the pins,
  4598. // creating a symbolic link for each one.
  4599. //
  4600. for (i = 0; i < ArrayCount; i++) {
  4601. //
  4602. // Create the symbolic link
  4603. //
  4604. if (!NT_SUCCESS(IoRegisterDeviceInterface(
  4605. DeviceExtension->PhysicalDeviceObject,
  4606. &GuidIndex[i],
  4607. (PUNICODE_STRING) & CreateItems[0].ObjectClass,
  4608. &NamesArray[i]))) {
  4609. DebugPrint((DebugLevelError, "StreamCreateSymLinks: couldn't register\n"));
  4610. DEBUG_BREAKPOINT();
  4611. return;
  4612. }
  4613. //
  4614. // Now set the symbolic link for the association
  4615. //
  4616. if (!NT_SUCCESS(IoSetDeviceInterfaceState(&NamesArray[i], TRUE))) {
  4617. DebugPrint((DebugLevelError, "StreamCreateSymLinks: couldn't set\n"));
  4618. DEBUG_BREAKPOINT();
  4619. return;
  4620. }
  4621. //
  4622. // add the strings from the PDO's key to the association key.
  4623. // Performance Improvement Chance
  4624. // - the INF should be able to directly propogate these;
  4625. // forrest & lonny are fixing.
  4626. //
  4627. if (NT_SUCCESS(IoOpenDeviceInterfaceRegistryKey(&NamesArray[i],
  4628. STANDARD_RIGHTS_ALL,
  4629. &ClassHandle))) {
  4630. //
  4631. // write the class ID for the proxy, if any.
  4632. //
  4633. if (NT_SUCCESS(SCGetRegistryValue(PdoHandle,
  4634. (PWCHAR) ClsIdString,
  4635. sizeof(ClsIdString),
  4636. &DataBuffer,
  4637. MAX_STRING_LENGTH))) {
  4638. RtlInitUnicodeString(&TempUnicodeString, ClsIdString);
  4639. ZwSetValueKey(ClassHandle,
  4640. &TempUnicodeString,
  4641. 0,
  4642. REG_SZ,
  4643. &DataBuffer,
  4644. MAX_STRING_LENGTH
  4645. );
  4646. } // if cls guid read
  4647. //
  4648. // first check if a friendly name has already been propogated
  4649. // to the class via the INF. If not, we'll just use the device
  4650. // description string for this.
  4651. //
  4652. if (!NT_SUCCESS(SCGetRegistryValue(ClassHandle,
  4653. (PWCHAR) FriendlyNameString,
  4654. sizeof(FriendlyNameString),
  4655. &DataBuffer,
  4656. MAX_STRING_LENGTH))) {
  4657. //
  4658. // write the friendly name for the device, if any.
  4659. //
  4660. if (NT_SUCCESS(SCGetRegistryValue(PdoHandle,
  4661. (PWCHAR) DriverDescString,
  4662. sizeof(DriverDescString),
  4663. &DataBuffer,
  4664. MAX_STRING_LENGTH))) {
  4665. RtlInitUnicodeString(&TempUnicodeString, FriendlyNameString);
  4666. ZwSetValueKey(ClassHandle,
  4667. &TempUnicodeString,
  4668. 0,
  4669. REG_SZ,
  4670. &DataBuffer,
  4671. MAX_STRING_LENGTH
  4672. );
  4673. } // if cls guid read
  4674. } // if !friendly name already
  4675. ZwClose(ClassHandle);
  4676. } // if class key opened
  4677. } // for # Categories
  4678. ZwClose(PdoHandle);
  4679. }
  4680. VOID
  4681. SCDestroySymbolicLinks(
  4682. IN PDEVICE_EXTENSION DeviceExtension
  4683. )
  4684. /*++
  4685. Routine Description:
  4686. Arguments:
  4687. DeviceExtension - Supplies a pointer to the device extension to be processed.
  4688. Return Value:
  4689. None.
  4690. --*/
  4691. {
  4692. PHW_STREAM_DESCRIPTOR StreamDescriptor = DeviceExtension->StreamDescriptor;
  4693. PAGED_CODE();
  4694. if (StreamDescriptor) {
  4695. ULONG ArrayCount = StreamDescriptor->StreamHeader.Topology->CategoriesCount;
  4696. UNICODE_STRING *NamesArray;
  4697. ULONG i;
  4698. //
  4699. // if no names array, we're done.
  4700. //
  4701. if (NULL == DeviceExtension->SymbolicLinks) {
  4702. return;
  4703. }
  4704. NamesArray = DeviceExtension->SymbolicLinks;
  4705. //
  4706. // loop through each of the catagory GUID's for each of the pins,
  4707. // deleting the symbolic link for each one.
  4708. //
  4709. for (i = 0; i < ArrayCount; i++) {
  4710. if (NamesArray[i].Buffer) {
  4711. //
  4712. // Delete the symbolic link, ignoring the status.
  4713. //
  4714. IoSetDeviceInterfaceState(&NamesArray[i], FALSE);
  4715. //
  4716. // free the buffer allocated by
  4717. // IoRegisterDeviceClassAssociation.
  4718. //
  4719. ExFreePool(NamesArray[i].Buffer);
  4720. } // if buffer
  4721. } // for # Categories
  4722. //
  4723. // free the links structure and null the pointer
  4724. //
  4725. ExFreePool(NamesArray);
  4726. DeviceExtension->SymbolicLinks = NULL;
  4727. } // if StreamDescriptor
  4728. }
  4729. #endif // ENABLE_MULTIPLE_FILTER_TYPES
  4730. NTSTATUS
  4731. SCSynchCompletionRoutine(
  4732. IN PDEVICE_OBJECT DeviceObject,
  4733. IN PIRP Irp,
  4734. IN PKEVENT Event
  4735. )
  4736. /*++
  4737. Routine Description:
  4738. This routine is for use with synchronous IRP processing.
  4739. All it does is signal an event, so the driver knows it
  4740. can continue.
  4741. Arguments:
  4742. DriverObject - Pointer to driver object created by system.
  4743. Irp - Irp that just completed
  4744. Event - Event we'll signal to say Irp is done
  4745. Return Value:
  4746. None.
  4747. --*/
  4748. {
  4749. KeSetEvent((PKEVENT) Event, IO_NO_INCREMENT, FALSE);
  4750. return (STATUS_MORE_PROCESSING_REQUIRED);
  4751. }
  4752. NTSTATUS
  4753. SCSynchPowerCompletionRoutine(
  4754. IN PDEVICE_OBJECT DeviceObject,
  4755. IN UCHAR MinorFunction,
  4756. IN POWER_STATE DeviceState,
  4757. IN PVOID Context,
  4758. IN PIO_STATUS_BLOCK IoStatus
  4759. )
  4760. /*++
  4761. Routine Description:
  4762. This routine is for use with synchronous IRP power processing.
  4763. All it does is signal an event, so the driver knows it
  4764. can continue.
  4765. Arguments:
  4766. DeviceObject - Pointer to the device object for the class device.
  4767. SetState - TRUE for set, FALSE for query.
  4768. DevicePowerState - power state
  4769. Context - Driver defined context, in our case, an IRP.
  4770. IoStatus - The status of the IRP.
  4771. Return Value:
  4772. None.
  4773. --*/
  4774. {
  4775. PIRP SystemIrp = Context;
  4776. PDEVICE_EXTENSION DeviceExtension;
  4777. PIO_STACK_LOCATION IrpStack;
  4778. if ( NULL == SystemIrp ) {
  4779. //
  4780. // SystemIrp has been completed if it is a Wake Irp
  4781. //
  4782. return ( IoStatus->Status );
  4783. }
  4784. IrpStack = IoGetCurrentIrpStackLocation(SystemIrp);
  4785. DeviceExtension = (PDEVICE_EXTENSION)
  4786. (IrpStack->DeviceObject)->DeviceExtension;
  4787. //
  4788. // cache the status of the device power irp we sent in the system IRP
  4789. //
  4790. SystemIrp->IoStatus.Status = IoStatus->Status;
  4791. //
  4792. // schedule a worker item to complete processing. note that we can use
  4793. // a global item since we have not yet issued the PoNextPowerIrp call.
  4794. //
  4795. ExInitializeWorkItem(&DeviceExtension->PowerCompletionWorkItem,
  4796. SCPowerCompletionWorker,
  4797. SystemIrp);
  4798. ExQueueWorkItem(&DeviceExtension->PowerCompletionWorkItem,
  4799. DelayedWorkQueue);
  4800. return (IoStatus->Status);
  4801. }
  4802. VOID
  4803. SCPowerCompletionWorker(
  4804. IN PIRP SystemIrp
  4805. )
  4806. /*++
  4807. Routine Description:
  4808. Arguments:
  4809. Return Value:
  4810. None.
  4811. --*/
  4812. {
  4813. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(SystemIrp);
  4814. PDEVICE_EXTENSION DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
  4815. //
  4816. // preset the status to the status of the Device request, which we cached
  4817. // in the system IRP's status field. We'll override it with the status
  4818. // of the system request if we haven't sent it yet.
  4819. //
  4820. NTSTATUS Status = SystemIrp->IoStatus.Status;
  4821. PAGED_CODE();
  4822. //
  4823. // if this is a NOT wakeup, we must first pass the request down
  4824. // to the PDO for postprocessing.
  4825. //
  4826. if (IrpStack->Parameters.Power.State.SystemState != PowerSystemWorking) {
  4827. //
  4828. // send down the system power IRP to the next layer. this routine
  4829. // has a completion routine which does not complete the IRP.
  4830. // preset the status to SUCCESS in this case.
  4831. //
  4832. SystemIrp->IoStatus.Status = STATUS_SUCCESS;
  4833. Status = SCCallNextDriver(DeviceExtension, SystemIrp);
  4834. }
  4835. //
  4836. // indicate that we're ready for the next power IRP.
  4837. //
  4838. PoStartNextPowerIrp(SystemIrp);
  4839. //
  4840. // show one fewer reference to driver.
  4841. //
  4842. SCDereferenceDriver(DeviceExtension);
  4843. //
  4844. // now complete the system power IRP.
  4845. //
  4846. SCCompleteIrp(SystemIrp, Status, DeviceExtension);
  4847. }
  4848. NTSTATUS
  4849. SCBustedSynchPowerCompletionRoutine(
  4850. IN PDEVICE_OBJECT DeviceObject,
  4851. IN UCHAR MinorFunction,
  4852. IN POWER_STATE DeviceState,
  4853. IN PVOID Context,
  4854. IN PIO_STATUS_BLOCK IoStatus
  4855. )
  4856. /*++
  4857. Routine Description:
  4858. (I don't see this can go away) this routine needs to go away
  4859. This routine is for use with synchronous IRP power processing.
  4860. All it does is signal an event, so the driver knows it
  4861. can continue.
  4862. Arguments:
  4863. DeviceObject - Pointer to the device object for the class device.
  4864. SetState - TRUE for set, FALSE for query.
  4865. DevicePowerState - power state
  4866. Context - Driver defined context, in our case, an event.
  4867. IoStatus - The status of the IRP.
  4868. Return Value:
  4869. None.
  4870. --*/
  4871. {
  4872. PPOWER_CONTEXT PowerContext = Context;
  4873. PAGED_CODE();
  4874. PowerContext->Status = IoStatus->Status;
  4875. KeSetEvent(&PowerContext->Event, IO_NO_INCREMENT, FALSE);
  4876. return (PowerContext->Status);
  4877. }
  4878. NTSTATUS
  4879. SCCreateChildPdo(
  4880. IN PVOID PnpId,
  4881. IN PDEVICE_OBJECT DeviceObject,
  4882. IN ULONG InstanceNumber
  4883. )
  4884. /*++
  4885. Routine Description:
  4886. Called to create a PDO for a child device.
  4887. Arguments:
  4888. PnpId - ID of device to create
  4889. ChildNode - node for the device
  4890. Return Value:
  4891. Status is returned.
  4892. --*/
  4893. {
  4894. PDEVICE_OBJECT ChildPdo;
  4895. NTSTATUS Status;
  4896. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  4897. PCHILD_DEVICE_EXTENSION ChildDeviceExtension;
  4898. PWCHAR NameBuffer;
  4899. PAGED_CODE();
  4900. //
  4901. // create a PDO for the child device.
  4902. //
  4903. Status = IoCreateDevice(DeviceObject->DriverObject,
  4904. sizeof(CHILD_DEVICE_EXTENSION),
  4905. NULL,
  4906. FILE_DEVICE_UNKNOWN,
  4907. FILE_AUTOGENERATED_DEVICE_NAME,
  4908. FALSE,
  4909. &ChildPdo);
  4910. if (!NT_SUCCESS(Status)) {
  4911. DEBUG_BREAKPOINT();
  4912. return Status;
  4913. }
  4914. //
  4915. // set the stack size to be the # of stacks used by the FDO.
  4916. //
  4917. ChildPdo->StackSize = DeviceObject->StackSize+1;
  4918. //
  4919. // Initialize fields in the ChildDeviceExtension.
  4920. //
  4921. ChildDeviceExtension = ChildPdo->DeviceExtension;
  4922. ChildDeviceExtension->ChildDeviceObject = ChildPdo;
  4923. ChildDeviceExtension->Flags |= DEVICE_FLAGS_CHILD;
  4924. ChildDeviceExtension->DeviceIndex = InstanceNumber;
  4925. ChildDeviceExtension->ParentDeviceObject = DeviceObject;
  4926. //
  4927. // create a new string for the device name and save it away in the device
  4928. // extension. I spent about 4 hours trying to find a way to
  4929. // get unicode strings to work with this. If you ask me why I didn't
  4930. // use a unicode string, I will taunt you and #%*&# in your general
  4931. // direction.
  4932. //
  4933. if (NameBuffer = ExAllocatePool(PagedPool,
  4934. wcslen(PnpId) * 2 + 2)) {
  4935. wcscpy(NameBuffer,
  4936. PnpId);
  4937. //
  4938. // save the device name pointer. this is freed when the device is
  4939. // removed.
  4940. //
  4941. ChildDeviceExtension->DeviceName = NameBuffer;
  4942. } // if namebuffer
  4943. //
  4944. // initialize the link and insert this node
  4945. //
  4946. InitializeListHead(&ChildDeviceExtension->ChildExtensionList);
  4947. InsertTailList(
  4948. &DeviceExtension->Children,
  4949. &ChildDeviceExtension->ChildExtensionList);
  4950. ChildPdo->Flags |= DO_POWER_PAGABLE;
  4951. ChildPdo->Flags &= ~DO_DEVICE_INITIALIZING;
  4952. return Status;
  4953. }
  4954. NTSTATUS
  4955. SCEnumerateChildren(
  4956. IN PDEVICE_OBJECT DeviceObject,
  4957. IN PIRP Irp
  4958. )
  4959. /*++
  4960. Routine Description:
  4961. Called in the context of an IRP_MN_QUERY_DEVICE_RELATIONS
  4962. Arguments:
  4963. DeviceObject - Pointer to class device object.
  4964. Irp - Pointer to the request packet.
  4965. Return Value:
  4966. Status is returned.
  4967. --*/
  4968. {
  4969. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  4970. PVOID PnpId;
  4971. PCHILD_DEVICE_EXTENSION ChildDeviceExtension = NULL,
  4972. CurrentChildExtension;
  4973. PDEVICE_RELATIONS DeviceRelations = NULL;
  4974. OBJECT_ATTRIBUTES ObjectAttributes;
  4975. NTSTATUS Status;
  4976. HANDLE ParentKey,
  4977. RootKey,
  4978. ChildKey;
  4979. UNICODE_STRING UnicodeEnumName;
  4980. ULONG NumberOfChildren,
  4981. RelationsSize;
  4982. PDEVICE_OBJECT *ChildPdo;
  4983. PLIST_ENTRY ListEntry,
  4984. ChildEntry;
  4985. PAGED_CODE();
  4986. DebugPrint((DebugLevelInfo,
  4987. "EnumChilds for %x %s\n",
  4988. DeviceObject,
  4989. (DeviceExtension->Flags & DEVICE_FLAGS_CHILDREN_ENUMED) == 0 ?
  4990. "1st Time": "has enumed" ));
  4991. if ( 0 == (DeviceExtension->Flags & DEVICE_FLAGS_CHILDREN_ENUMED) ) {
  4992. //
  4993. // we haven't enumerated children from the registry
  4994. // do it now.
  4995. //
  4996. Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
  4997. PLUGPLAY_REGKEY_DRIVER,
  4998. STANDARD_RIGHTS_ALL,
  4999. &ParentKey);
  5000. if (!NT_SUCCESS(Status)) {
  5001. DebugPrint((DebugLevelError, "SCEnumerateChildren: couldn't open\n"));
  5002. return STATUS_NOT_IMPLEMENTED;
  5003. }
  5004. //
  5005. // create the subkey for the enum section, in the form "\enum"
  5006. //
  5007. RtlInitUnicodeString(&UnicodeEnumName, EnumString);
  5008. //
  5009. // read the registry to determine if children are present.
  5010. //
  5011. InitializeObjectAttributes(&ObjectAttributes,
  5012. &UnicodeEnumName,
  5013. OBJ_CASE_INSENSITIVE,
  5014. ParentKey,
  5015. NULL);
  5016. if (!NT_SUCCESS(Status = ZwOpenKey(&RootKey, KEY_READ, &ObjectAttributes))) {
  5017. ZwClose(ParentKey);
  5018. return Status;
  5019. }
  5020. //
  5021. // allocate a buffer to contain the ID string. Performance Improvement Chance
  5022. // - this should
  5023. // really get the size and alloc only that size, but I have an existing
  5024. // routine that reads the registry, & this is a temp allocation only.
  5025. //
  5026. if (!(PnpId = ExAllocatePool(PagedPool, MAX_STRING_LENGTH))) {
  5027. ZwClose(RootKey);
  5028. ZwClose(ParentKey);
  5029. return STATUS_INSUFFICIENT_RESOURCES;
  5030. }
  5031. //
  5032. // Loop through all the values until either no more entries exist, or an
  5033. // error occurs.
  5034. //
  5035. for (NumberOfChildren = 0;; NumberOfChildren++) {
  5036. ULONG BytesReturned;
  5037. PKEY_BASIC_INFORMATION BasicInfoBuffer;
  5038. KEY_BASIC_INFORMATION BasicInfoHeader;
  5039. //
  5040. // Retrieve the value size.
  5041. //
  5042. Status = ZwEnumerateKey(
  5043. RootKey,
  5044. NumberOfChildren,
  5045. KeyBasicInformation,
  5046. &BasicInfoHeader,
  5047. sizeof(BasicInfoHeader),
  5048. &BytesReturned);
  5049. if ((Status != STATUS_BUFFER_OVERFLOW) && !NT_SUCCESS(Status)) {
  5050. //
  5051. // exit the loop, as we either had an error or reached the end
  5052. // of the list of keys.
  5053. //
  5054. break;
  5055. } // if error
  5056. //
  5057. // Allocate a buffer for the actual size of data needed.
  5058. //
  5059. BasicInfoBuffer = (PKEY_BASIC_INFORMATION)
  5060. ExAllocatePool(PagedPool,
  5061. BytesReturned);
  5062. if (!BasicInfoBuffer) {
  5063. break;
  5064. }
  5065. //
  5066. // Retrieve the name of the nth child device
  5067. //
  5068. Status = ZwEnumerateKey(
  5069. RootKey,
  5070. NumberOfChildren,
  5071. KeyBasicInformation,
  5072. BasicInfoBuffer,
  5073. BytesReturned,
  5074. &BytesReturned);
  5075. if (!NT_SUCCESS(Status)) {
  5076. ExFreePool(BasicInfoBuffer);
  5077. break;
  5078. }
  5079. //
  5080. // build object attributes for the key, & try to open it.
  5081. //
  5082. UnicodeEnumName.Length = (USHORT) BasicInfoBuffer->NameLength;
  5083. UnicodeEnumName.MaximumLength = (USHORT) BasicInfoBuffer->NameLength;
  5084. UnicodeEnumName.Buffer = (PWCHAR) BasicInfoBuffer->Name;
  5085. InitializeObjectAttributes(&ObjectAttributes,
  5086. &UnicodeEnumName,
  5087. OBJ_CASE_INSENSITIVE,
  5088. RootKey,
  5089. NULL);
  5090. if (!NT_SUCCESS(Status = ZwOpenKey(&ChildKey, KEY_READ, &ObjectAttributes))) {
  5091. ExFreePool(BasicInfoBuffer);
  5092. break;
  5093. }
  5094. //
  5095. // we've now opened the key for the child. We next read in the PNPID
  5096. // value, and if present, create a PDO of that name.
  5097. //
  5098. if (!NT_SUCCESS(Status = SCGetRegistryValue(ChildKey,
  5099. (PWCHAR) PnpIdString,
  5100. sizeof(PnpIdString),
  5101. PnpId,
  5102. MAX_STRING_LENGTH))) {
  5103. ExFreePool(BasicInfoBuffer);
  5104. ZwClose(ChildKey);
  5105. break;
  5106. }
  5107. //
  5108. // create a PDO representing the child.
  5109. //
  5110. Status = SCCreateChildPdo(PnpId,
  5111. DeviceObject,
  5112. NumberOfChildren);
  5113. //
  5114. // free the Basic info buffer and close the child key
  5115. //
  5116. ExFreePool(BasicInfoBuffer);
  5117. ZwClose(ChildKey);
  5118. if (!NT_SUCCESS(Status)) {
  5119. //
  5120. // break out of the loop if we could not create the
  5121. // PDO
  5122. //
  5123. DEBUG_BREAKPOINT();
  5124. break;
  5125. } // if !success
  5126. } // for NumberOfChildren
  5127. //
  5128. // close the root and parent keys and free the ID buffer
  5129. //
  5130. ZwClose(RootKey);
  5131. ZwClose(ParentKey);
  5132. ExFreePool(PnpId);
  5133. //
  5134. // has enumed, remember this
  5135. //
  5136. DeviceExtension->Flags |= DEVICE_FLAGS_CHILDREN_ENUMED;
  5137. //
  5138. // we now have processed all children, and have a linked list of
  5139. // them.
  5140. //
  5141. if (!NumberOfChildren) {
  5142. //
  5143. // if no children, just return not supported. this means that the
  5144. // device did not have children.
  5145. //
  5146. return (STATUS_NOT_IMPLEMENTED);
  5147. } // if !NumberOfChildren
  5148. }
  5149. else {
  5150. //
  5151. // count children which are not marked delete pending
  5152. //
  5153. ListEntry = ChildEntry = &DeviceExtension->Children;
  5154. NumberOfChildren = 0;
  5155. while (ChildEntry->Flink != ListEntry) {
  5156. ChildEntry = ChildEntry->Flink;
  5157. CurrentChildExtension = CONTAINING_RECORD(ChildEntry,
  5158. CHILD_DEVICE_EXTENSION,
  5159. ChildExtensionList );
  5160. if (!(CurrentChildExtension->Flags & DEVICE_FLAGS_CHILD_MARK_DELETE)){
  5161. NumberOfChildren++;
  5162. }
  5163. }
  5164. }
  5165. //
  5166. // allocate the device relations buffer. This will be freed by the
  5167. // caller.
  5168. //
  5169. RelationsSize = sizeof(DEVICE_RELATIONS) +
  5170. (NumberOfChildren * sizeof(PDEVICE_OBJECT));
  5171. DeviceRelations = ExAllocatePool(PagedPool, RelationsSize);
  5172. if (DeviceRelations == NULL) {
  5173. //
  5174. // return, but keep the list of children allocated.
  5175. //
  5176. DEBUG_BREAKPOINT();
  5177. return STATUS_INSUFFICIENT_RESOURCES;
  5178. } // if no heap
  5179. RtlZeroMemory(DeviceRelations, RelationsSize);
  5180. //
  5181. // Walk our chain of children, and initialize the relations
  5182. //
  5183. ChildPdo = &(DeviceRelations->Objects[0]);
  5184. //
  5185. // get the 1st child from the parent device extension anchor
  5186. //
  5187. ListEntry = ChildEntry = &DeviceExtension->Children;
  5188. while (ChildEntry->Flink != ListEntry) {
  5189. ChildEntry = ChildEntry->Flink;
  5190. CurrentChildExtension = CONTAINING_RECORD(ChildEntry,
  5191. CHILD_DEVICE_EXTENSION,
  5192. ChildExtensionList);
  5193. DebugPrint((DebugLevelInfo,
  5194. "Enumed Child DevObj %x%s marked delete\n",
  5195. CurrentChildExtension->ChildDeviceObject,
  5196. (CurrentChildExtension->Flags & DEVICE_FLAGS_CHILD_MARK_DELETE)==0 ?
  5197. " not" : ""));
  5198. if ( CurrentChildExtension->Flags & DEVICE_FLAGS_CHILD_MARK_DELETE ) {
  5199. continue;
  5200. }
  5201. *ChildPdo = CurrentChildExtension->ChildDeviceObject;
  5202. //
  5203. // per DDK doc we need to inc ref count
  5204. //
  5205. ObReferenceObject( *ChildPdo );
  5206. ChildPdo++;
  5207. } // while Children
  5208. DeviceRelations->Count = NumberOfChildren;
  5209. //
  5210. // Stuff that pDeviceRelations into the IRP and return SUCCESS.
  5211. //
  5212. Irp->IoStatus.Information = (ULONG_PTR) DeviceRelations;
  5213. return STATUS_SUCCESS;
  5214. }
  5215. NTSTATUS
  5216. SCEnumGetCaps(
  5217. IN PCHILD_DEVICE_EXTENSION DeviceExtension,
  5218. OUT PDEVICE_CAPABILITIES Capabilities
  5219. )
  5220. /*++
  5221. Routine Description:
  5222. Called to get the capabilities of a child
  5223. Arguments:
  5224. DeviceExtension - child device extension
  5225. Capibilities - capabilities structure
  5226. Return Value:
  5227. Status is returned.
  5228. --*/
  5229. {
  5230. ULONG i;
  5231. PAGED_CODE();
  5232. //
  5233. // fill in the structure with non-controversial values
  5234. //
  5235. Capabilities->SystemWake = PowerSystemUnspecified;
  5236. Capabilities->DeviceWake = PowerDeviceUnspecified;
  5237. Capabilities->D1Latency = 10;
  5238. Capabilities->D2Latency = 10;
  5239. Capabilities->D3Latency = 10;
  5240. Capabilities->LockSupported = FALSE;
  5241. Capabilities->EjectSupported = FALSE;
  5242. Capabilities->Removable = FALSE;
  5243. Capabilities->DockDevice = FALSE;
  5244. Capabilities->UniqueID = FALSE; // set to false so PNP will make us
  5245. for (i = 0; i < PowerDeviceMaximum; i++) {
  5246. Capabilities->DeviceState[i] = PowerDeviceD0;
  5247. } // for i
  5248. return STATUS_SUCCESS;
  5249. }
  5250. NTSTATUS
  5251. SCQueryEnumId(
  5252. IN PDEVICE_OBJECT DeviceObject,
  5253. IN BUS_QUERY_ID_TYPE BusQueryIdType,
  5254. IN OUT PWSTR * BusQueryId
  5255. )
  5256. /*++
  5257. Routine Description:
  5258. Called to get the ID of a child device
  5259. Arguments:
  5260. DeviceObject - device object from child
  5261. QueryIdType - ID type from PNP
  5262. BusQueryId - buffer containing the info requested if successful
  5263. Return Value:
  5264. Status is returned.
  5265. --*/
  5266. {
  5267. PUSHORT NameBuffer;
  5268. NTSTATUS Status = STATUS_SUCCESS;
  5269. PCHILD_DEVICE_EXTENSION DeviceExtension =
  5270. (PCHILD_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
  5271. PAGED_CODE();
  5272. //
  5273. // Allocate enough space to hold a MULTI_SZ. This will be passed to the
  5274. // Io
  5275. // subsystem (via BusQueryId) who has the responsibility of freeing it.
  5276. //
  5277. NameBuffer = ExAllocatePool(PagedPool, MAX_STRING_LENGTH);
  5278. if (!NameBuffer) {
  5279. return STATUS_INSUFFICIENT_RESOURCES;
  5280. }
  5281. RtlZeroMemory(NameBuffer, MAX_STRING_LENGTH);
  5282. //
  5283. // process the query
  5284. //
  5285. switch (BusQueryIdType) {
  5286. case BusQueryCompatibleIDs:
  5287. //
  5288. // Pierre tells me I do not need to support compat id.
  5289. //
  5290. default:
  5291. ExFreePool(NameBuffer);
  5292. return (STATUS_NOT_SUPPORTED);
  5293. case BusQueryDeviceID:
  5294. //
  5295. // pierre tells me I can use the same name for both Device &
  5296. // HW ID's. Note that the buffer we've allocated has been zero
  5297. // inited, which will ensure the 2nd NULL for the Hardware ID.
  5298. //
  5299. case BusQueryHardwareIDs:
  5300. //
  5301. // create the 1st part of the ID, which consists of "Stream\"
  5302. //
  5303. RtlMoveMemory(NameBuffer,
  5304. L"Stream\\",
  5305. sizeof(L"Stream\\"));
  5306. //
  5307. // create the 2nd part of the ID, which is the PNP ID from the
  5308. // registry.
  5309. //
  5310. wcscat(NameBuffer, DeviceExtension->DeviceName);
  5311. break;
  5312. case BusQueryInstanceID:
  5313. {
  5314. UNICODE_STRING DeviceName;
  5315. WCHAR Buffer[8];
  5316. //
  5317. // convert the instance # from the device extension to unicode,
  5318. // then copy it over to the output buffer.
  5319. //
  5320. DeviceName.Buffer = Buffer;
  5321. DeviceName.Length = 0;
  5322. DeviceName.MaximumLength = 8;
  5323. RtlIntegerToUnicodeString(DeviceExtension->DeviceIndex,
  5324. 10,
  5325. &DeviceName);
  5326. wcscpy(NameBuffer, DeviceName.Buffer);
  5327. break;
  5328. }
  5329. }
  5330. //
  5331. // return the string and good status.
  5332. //
  5333. *BusQueryId = NameBuffer;
  5334. return (Status);
  5335. }
  5336. NTSTATUS
  5337. StreamClassForwardUnsupported(
  5338. IN PDEVICE_OBJECT DeviceObject,
  5339. IN PIRP Irp
  5340. )
  5341. /*++
  5342. Routine Description:
  5343. This routine forwards unsupported major function calls to the PDO.
  5344. Arguments:
  5345. DeviceObject - Pointer to class device object.
  5346. Irp - Pointer to the request packet.
  5347. Return Value:
  5348. Status is returned.
  5349. --*/
  5350. {
  5351. PDEVICE_EXTENSION DeviceExtension;
  5352. NTSTATUS Status;
  5353. PAGED_CODE();
  5354. DeviceExtension = DeviceObject->DeviceExtension;
  5355. Irp->IoStatus.Information = 0;
  5356. DebugPrint((DebugLevelVerbose, "'StreamClassForwardUnsupported: enter\n"));
  5357. if ( !(DeviceExtension->Flags & DEVICE_FLAGS_CHILD)) {
  5358. //
  5359. // show one more reference to driver.
  5360. //
  5361. SCReferenceDriver(DeviceExtension);
  5362. //
  5363. // show one more I/O pending & verify that we can actually do I/O.
  5364. //
  5365. Status = SCShowIoPending(DeviceExtension, Irp);
  5366. if ( !NT_SUCCESS( Status )) {
  5367. //
  5368. // the device is currently not accessible, so just return with error
  5369. //
  5370. Irp->IoStatus.Status= Status;
  5371. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  5372. return Status;
  5373. }
  5374. //
  5375. // synchronouosly call the next driver in the stack.
  5376. //
  5377. SCCallNextDriver(DeviceExtension, Irp);
  5378. //
  5379. // dereference the driver
  5380. //
  5381. SCDereferenceDriver(DeviceExtension);
  5382. //
  5383. // complete the IRP and return status
  5384. //
  5385. return (SCCompleteIrp(Irp, Irp->IoStatus.Status, DeviceExtension));
  5386. } else {
  5387. //
  5388. // We are the PDO, return error and complete the Irp
  5389. //
  5390. Irp->IoStatus.Status = Status = STATUS_NOT_SUPPORTED;
  5391. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  5392. return Status;
  5393. }
  5394. }
  5395. VOID
  5396. SCSendSurpriseNotification(
  5397. IN PDEVICE_EXTENSION DeviceExtension,
  5398. IN PIRP Irp
  5399. )
  5400. /*++
  5401. Routine Description:
  5402. Arguments:
  5403. Return Value:
  5404. --*/
  5405. {
  5406. BOOLEAN RequestIssued;
  5407. PAGED_CODE();
  5408. SCSubmitRequest(SRB_SURPRISE_REMOVAL,
  5409. NULL,
  5410. 0,
  5411. SCDequeueAndDeleteSrb,
  5412. DeviceExtension,
  5413. NULL,
  5414. NULL,
  5415. Irp,
  5416. &RequestIssued,
  5417. &DeviceExtension->PendingQueue,
  5418. (PVOID) DeviceExtension->
  5419. MinidriverData->HwInitData.
  5420. HwReceivePacket
  5421. );
  5422. }