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

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