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.

2715 lines
80 KiB

  1. /*****************************************************************************
  2. * portcls.cpp - WDM Streaming port class driver
  3. *****************************************************************************
  4. * Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
  5. */
  6. #define KSDEBUG_INIT
  7. #include "private.h"
  8. #include "perf.h"
  9. #include <ksmediap.h>
  10. #ifdef TIME_BOMB
  11. #include "..\..\..\timebomb\timebomb.c"
  12. #endif
  13. /*****************************************************************************
  14. * Referenced forward.
  15. */
  16. NTSTATUS
  17. DispatchPnp
  18. (
  19. IN PDEVICE_OBJECT pDeviceObject,
  20. IN PIRP pIrp
  21. );
  22. NTSTATUS
  23. DispatchSystemControl
  24. (
  25. IN PDEVICE_OBJECT pDeviceObject,
  26. IN PIRP pIrp
  27. );
  28. #define PORTCLS_DRIVER_EXTENSION_ID 0x0ABADCAFE
  29. /*****************************************************************************
  30. * Globals
  31. */
  32. ULONG gBufferDuration=0;
  33. KAFFINITY gInterruptAffinity=0;
  34. /*****************************************************************************
  35. * Functions.
  36. */
  37. // TODO: put this someplace better?
  38. int __cdecl
  39. _purecall( void )
  40. {
  41. ASSERT(!"Pure virtual function called");
  42. return 0;
  43. }
  44. #pragma code_seg("PAGE")
  45. NTSTATUS
  46. QueryRegistryValueEx(
  47. ULONG Hive,
  48. PWSTR pwstrRegistryPath,
  49. PWSTR pwstrRegistryValue,
  50. ULONG uValueType,
  51. PVOID *ppValue,
  52. PVOID pDefaultData,
  53. ULONG DefaultDataLength
  54. )
  55. {
  56. PRTL_QUERY_REGISTRY_TABLE pRegistryValueTable = NULL;
  57. UNICODE_STRING usString;
  58. DWORD dwValue;
  59. NTSTATUS Status = STATUS_SUCCESS;
  60. usString.Buffer = NULL;
  61. pRegistryValueTable = (PRTL_QUERY_REGISTRY_TABLE) ExAllocatePoolWithTag(
  62. PagedPool,
  63. (sizeof(RTL_QUERY_REGISTRY_TABLE)*2),
  64. 'vRcP');
  65. if(!pRegistryValueTable) {
  66. Status = STATUS_INSUFFICIENT_RESOURCES;
  67. goto exit;
  68. }
  69. RtlZeroMemory(pRegistryValueTable, (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
  70. pRegistryValueTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  71. pRegistryValueTable[0].Name = pwstrRegistryValue;
  72. pRegistryValueTable[0].DefaultType = uValueType;
  73. pRegistryValueTable[0].DefaultLength = DefaultDataLength;
  74. pRegistryValueTable[0].DefaultData = pDefaultData;
  75. switch (uValueType) {
  76. case REG_SZ:
  77. pRegistryValueTable[0].EntryContext = &usString;
  78. break;
  79. case REG_DWORD:
  80. pRegistryValueTable[0].EntryContext = &dwValue;
  81. break;
  82. default:
  83. Status = STATUS_INVALID_PARAMETER ;
  84. goto exit;
  85. }
  86. Status = RtlQueryRegistryValues(
  87. Hive,
  88. pwstrRegistryPath,
  89. pRegistryValueTable,
  90. NULL,
  91. NULL);
  92. if(!NT_SUCCESS(Status)) {
  93. goto exit;
  94. }
  95. switch (uValueType) {
  96. case REG_SZ:
  97. *ppValue = ExAllocatePoolWithTag(
  98. PagedPool,
  99. usString.Length + sizeof(UNICODE_NULL),
  100. 'sUcP');
  101. if(!(*ppValue)) {
  102. RtlFreeUnicodeString(&usString);
  103. Status = STATUS_INSUFFICIENT_RESOURCES;
  104. goto exit;
  105. }
  106. memcpy(*ppValue, usString.Buffer, usString.Length);
  107. ((PWCHAR)*ppValue)[usString.Length/sizeof(WCHAR)] = UNICODE_NULL;
  108. RtlFreeUnicodeString(&usString);
  109. break;
  110. case REG_DWORD:
  111. *ppValue = ExAllocatePoolWithTag(
  112. PagedPool,
  113. sizeof(DWORD),
  114. 'WDcP');
  115. if(!(*ppValue)) {
  116. Status = STATUS_INSUFFICIENT_RESOURCES;
  117. goto exit;
  118. }
  119. *((DWORD *)(*ppValue)) = dwValue;
  120. break;
  121. default:
  122. Status = STATUS_INVALID_PARAMETER ;
  123. goto exit;
  124. }
  125. exit:
  126. if (pRegistryValueTable) {
  127. ExFreePool(pRegistryValueTable);
  128. }
  129. return(Status);
  130. }
  131. ULONG
  132. GetUlongFromRegistry(
  133. PWSTR pwstrRegistryPath,
  134. PWSTR pwstrRegistryValue,
  135. ULONG DefaultValue
  136. )
  137. {
  138. PVOID pulValue ;
  139. ULONG ulValue ;
  140. NTSTATUS Status ;
  141. Status = QueryRegistryValueEx(RTL_REGISTRY_ABSOLUTE,
  142. pwstrRegistryPath,
  143. pwstrRegistryValue,
  144. REG_DWORD,
  145. &pulValue,
  146. &DefaultValue,
  147. sizeof(DWORD));
  148. if (NT_SUCCESS(Status)) {
  149. ulValue = *((PULONG)pulValue);
  150. ExFreePool(pulValue);
  151. }
  152. else {
  153. ulValue = DefaultValue;
  154. }
  155. return ( ulValue ) ;
  156. }
  157. /*****************************************************************************
  158. * DriverEntry()
  159. *****************************************************************************
  160. * Never called. All drivers must have one of these, so...
  161. */
  162. extern "C"
  163. NTSTATUS
  164. DriverEntry
  165. (
  166. IN PDRIVER_OBJECT DriverObject,
  167. IN PUNICODE_STRING RegistryPath
  168. )
  169. {
  170. PAGED_CODE();
  171. ASSERT(! "Port Class DriverEntry was called");
  172. //
  173. // Should never be called, but timebombing is added here for completeness.
  174. //
  175. #ifdef TIME_BOMB
  176. if (HasEvaluationTimeExpired())
  177. {
  178. _DbgPrintF(DEBUGLVL_TERSE,("This evaluation copy of PortCls has expired!!"));
  179. return STATUS_EVALUATION_EXPIRATION;
  180. }
  181. #endif
  182. return STATUS_SUCCESS;
  183. }
  184. /*****************************************************************************
  185. * DllInitialize()
  186. *****************************************************************************
  187. * Entry point for export library drivers.
  188. */
  189. extern "C"
  190. NTSTATUS DllInitialize(PVOID foo)
  191. {
  192. PAGED_CODE();
  193. _DbgPrintF(DEBUGLVL_VERBOSE,("DllInitialize"));
  194. #ifdef TIME_BOMB
  195. if (HasEvaluationTimeExpired())
  196. {
  197. _DbgPrintF(DEBUGLVL_TERSE,("This evaluation copy of PortCls has expired!!"));
  198. return STATUS_EVALUATION_EXPIRATION;
  199. }
  200. #endif
  201. // Query the registry for the default audio buffer duration.
  202. gBufferDuration = GetUlongFromRegistry( CORE_AUDIO_BUFFER_DURATION_PATH,
  203. CORE_AUDIO_BUFFER_DURATION_VALUE,
  204. DEFAULT_CORE_AUDIO_BUFFER_DURATION );
  205. gInterruptAffinity = GetUlongFromRegistry( CORE_AUDIO_BUFFER_DURATION_PATH,
  206. L"InterruptAffinity",
  207. 0 );
  208. // Limit duration maximum.
  209. if ( gBufferDuration > MAX_CORE_AUDIO_BUFFER_DURATION ) {
  210. gBufferDuration = MAX_CORE_AUDIO_BUFFER_DURATION;
  211. }
  212. // Limit duration minimum.
  213. if ( gBufferDuration < MIN_CORE_AUDIO_BUFFER_DURATION ) {
  214. gBufferDuration = MIN_CORE_AUDIO_BUFFER_DURATION;
  215. }
  216. #if !(MIN_CORE_AUDIO_BUFFER_DURATION/1000)
  217. #error MIN_CORE_AUDIO_BUFFER_DURATION less than 1ms not yet supported in portcls!
  218. #endif
  219. gBufferDuration /= 1000;
  220. #if kEnableDebugLogging
  221. if (!gPcDebugLog)
  222. {
  223. gPcDebugLog = (ULONG_PTR *)ExAllocatePoolWithTag(NonPagedPool,(kNumDebugLogEntries * kNumULONG_PTRsPerEntry * sizeof(ULONG_PTR)),'lDcP'); // 'PcDl'
  224. if (gPcDebugLog)
  225. {
  226. RtlZeroMemory(PVOID(gPcDebugLog),kNumDebugLogEntries * kNumULONG_PTRsPerEntry * sizeof(ULONG_PTR));
  227. }
  228. gPcDebugLogIndex = 0;
  229. }
  230. DebugLog(1,0,0,0);
  231. #endif // kEnableDebugLogging
  232. return STATUS_SUCCESS;
  233. }
  234. /*****************************************************************************
  235. * DllUnload()
  236. *****************************************************************************
  237. * Allow unload.
  238. */
  239. extern "C"
  240. NTSTATUS
  241. DllUnload
  242. ( void
  243. )
  244. {
  245. PAGED_CODE();
  246. _DbgPrintF(DEBUGLVL_VERBOSE,("DllUnload"));
  247. #if kEnableDebugLogging
  248. if (gPcDebugLog)
  249. {
  250. ExFreePool(gPcDebugLog);
  251. gPcDebugLog = NULL;
  252. }
  253. #endif // kEnableDebugLogging
  254. return STATUS_SUCCESS;
  255. }
  256. #if kEnableDebugLogging
  257. ULONG_PTR *gPcDebugLog = NULL;
  258. DWORD gPcDebugLogIndex = 0;
  259. void PcDebugLog(ULONG_PTR param1,ULONG_PTR param2,ULONG_PTR param3,ULONG_PTR param4)
  260. {
  261. if (gPcDebugLog)
  262. {
  263. gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry)] = param1;
  264. gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry) + 1] = param2;
  265. gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry) + 2] = param3;
  266. gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry) + 3] = param4;
  267. if (InterlockedIncrement(PLONG(&gPcDebugLogIndex)) >= kNumDebugLogEntries)
  268. {
  269. InterlockedExchange(PLONG(&gPcDebugLogIndex), 0);
  270. }
  271. }
  272. }
  273. #endif // kEnableDebugLogging
  274. /*****************************************************************************
  275. * DupUnicodeString()
  276. *****************************************************************************
  277. * Duplicates a unicode string.
  278. */
  279. NTSTATUS
  280. DupUnicodeString
  281. (
  282. OUT PUNICODE_STRING * ppUnicodeString,
  283. IN PUNICODE_STRING pUnicodeString OPTIONAL
  284. )
  285. {
  286. PAGED_CODE();
  287. ASSERT(ppUnicodeString);
  288. NTSTATUS ntStatus = STATUS_SUCCESS;
  289. if (pUnicodeString)
  290. {
  291. PUNICODE_STRING pUnicodeStringNew =
  292. new(PagedPool,'sUcP') UNICODE_STRING;
  293. if (pUnicodeStringNew)
  294. {
  295. pUnicodeStringNew->Length = pUnicodeString->Length;
  296. pUnicodeStringNew->MaximumLength = pUnicodeString->MaximumLength;
  297. if (pUnicodeString->Buffer)
  298. {
  299. pUnicodeStringNew->Buffer =
  300. new(PagedPool,'sUcP')
  301. WCHAR[pUnicodeString->MaximumLength / sizeof(WCHAR)];
  302. if (pUnicodeStringNew->Buffer)
  303. {
  304. RtlCopyMemory
  305. (
  306. pUnicodeStringNew->Buffer,
  307. pUnicodeString->Buffer,
  308. pUnicodeString->Length
  309. );
  310. *ppUnicodeString = pUnicodeStringNew;
  311. }
  312. else
  313. {
  314. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  315. delete pUnicodeStringNew;
  316. }
  317. }
  318. else
  319. {
  320. pUnicodeStringNew->Buffer = NULL;
  321. *ppUnicodeString = pUnicodeStringNew;
  322. }
  323. }
  324. else
  325. {
  326. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  327. }
  328. }
  329. else
  330. {
  331. *ppUnicodeString = NULL;
  332. }
  333. return ntStatus;
  334. }
  335. /*****************************************************************************
  336. * DelUnicodeString()
  337. *****************************************************************************
  338. * Deletes a unicode string that was allocated using ExAllocatePool().
  339. */
  340. VOID
  341. DelUnicodeString
  342. (
  343. IN PUNICODE_STRING pUnicodeString OPTIONAL
  344. )
  345. {
  346. if (pUnicodeString)
  347. {
  348. if (pUnicodeString->Buffer)
  349. {
  350. delete [] pUnicodeString->Buffer;
  351. }
  352. delete pUnicodeString;
  353. }
  354. }
  355. VOID
  356. KsoNullDriverUnload(
  357. IN PDRIVER_OBJECT DriverObject
  358. )
  359. /*++
  360. Routine Description:
  361. Default function which drivers can use when they do not have anything to do
  362. in their unload function, but must still allow the device to be unloaded by
  363. its presence.
  364. Arguments:
  365. DriverObject -
  366. Contains the driver object for this device.
  367. Return Values:
  368. Nothing.
  369. --*/
  370. {
  371. _DbgPrintF(DEBUGLVL_VERBOSE,("KsoNullDriverUnload"));
  372. if (DriverObject->DeviceObject)
  373. {
  374. _DbgPrintF(DEBUGLVL_TERSE,("KsoNullDriverUnload DEVICES EXIST"));
  375. }
  376. }
  377. /*****************************************************************************
  378. * PcInitializeAdapterDriver()
  379. *****************************************************************************
  380. * Initializes an adapter driver.
  381. */
  382. PORTCLASSAPI
  383. NTSTATUS
  384. NTAPI
  385. PcInitializeAdapterDriver
  386. (
  387. IN PDRIVER_OBJECT DriverObject,
  388. IN PUNICODE_STRING RegistryPathName,
  389. IN PDRIVER_ADD_DEVICE AddDevice
  390. )
  391. {
  392. PAGED_CODE();
  393. ASSERT(DriverObject);
  394. ASSERT(RegistryPathName);
  395. ASSERT(AddDevice);
  396. _DbgPrintF(DEBUGLVL_VERBOSE,("PcInitializeAdapterDriver"));
  397. //
  398. // Validate Parameters.
  399. //
  400. if (NULL == DriverObject ||
  401. NULL == RegistryPathName ||
  402. NULL == AddDevice)
  403. {
  404. _DbgPrintF(DEBUGLVL_TERSE, ("PcInitializeAdapterDriver : Invalid Parameter."));
  405. return STATUS_INVALID_PARAMETER;
  406. }
  407. DriverObject->DriverExtension->AddDevice = AddDevice;
  408. DriverObject->DriverUnload = KsoNullDriverUnload;
  409. DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
  410. DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
  411. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PerfWmiDispatch;
  412. DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
  413. KsSetMajorFunctionHandler(DriverObject,IRP_MJ_DEVICE_CONTROL);
  414. KsSetMajorFunctionHandler(DriverObject,IRP_MJ_READ);
  415. KsSetMajorFunctionHandler(DriverObject,IRP_MJ_WRITE);
  416. KsSetMajorFunctionHandler(DriverObject,IRP_MJ_FLUSH_BUFFERS);
  417. KsSetMajorFunctionHandler(DriverObject,IRP_MJ_CLOSE);
  418. KsSetMajorFunctionHandler(DriverObject,IRP_MJ_QUERY_SECURITY);
  419. KsSetMajorFunctionHandler(DriverObject,IRP_MJ_SET_SECURITY);
  420. return STATUS_SUCCESS;
  421. }
  422. /*****************************************************************************
  423. * PcDispatchIrp()
  424. *****************************************************************************
  425. * Dispatch an IRP.
  426. */
  427. PORTCLASSAPI
  428. NTSTATUS
  429. NTAPI
  430. PcDispatchIrp
  431. (
  432. IN PDEVICE_OBJECT pDeviceObject,
  433. IN PIRP pIrp
  434. )
  435. {
  436. PAGED_CODE();
  437. ASSERT(pDeviceObject);
  438. ASSERT(pIrp);
  439. NTSTATUS ntStatus;
  440. //
  441. // Validate parameters.
  442. //
  443. if (NULL == pDeviceObject ||
  444. NULL == pIrp)
  445. {
  446. _DbgPrintF(DEBUGLVL_TERSE, ("PcDispatchIrp : Invalid Parameter"));
  447. ntStatus = STATUS_INVALID_PARAMETER;
  448. if (pIrp)
  449. {
  450. pIrp->IoStatus.Status = ntStatus;
  451. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  452. }
  453. return ntStatus;
  454. }
  455. switch (IoGetCurrentIrpStackLocation(pIrp)->MajorFunction)
  456. {
  457. case IRP_MJ_PNP:
  458. ntStatus = DispatchPnp(pDeviceObject,pIrp);
  459. break;
  460. case IRP_MJ_POWER:
  461. ntStatus = DispatchPower(pDeviceObject,pIrp);
  462. break;
  463. case IRP_MJ_SYSTEM_CONTROL:
  464. ntStatus = PerfWmiDispatch(pDeviceObject,pIrp);
  465. break;
  466. default:
  467. ntStatus = KsoDispatchIrp(pDeviceObject,pIrp);
  468. break;
  469. }
  470. return ntStatus;
  471. }
  472. #pragma code_seg()
  473. /*****************************************************************************
  474. * AcquireDevice()
  475. *****************************************************************************
  476. * Acquire exclusive access to the device. This function has the semantics of
  477. * a mutex, ie the device must be released on the same thread it was acquired
  478. * from.
  479. */
  480. VOID
  481. AcquireDevice
  482. (
  483. IN PDEVICE_CONTEXT pDeviceContext
  484. )
  485. {
  486. #ifdef UNDER_NT
  487. KeEnterCriticalRegion();
  488. #endif
  489. KeWaitForSingleObject
  490. (
  491. &pDeviceContext->kEventDevice,
  492. Suspended,
  493. KernelMode,
  494. FALSE,
  495. NULL
  496. );
  497. }
  498. /*****************************************************************************
  499. * ReleaseDevice()
  500. *****************************************************************************
  501. * Release exclusive access to the device.
  502. */
  503. VOID
  504. ReleaseDevice
  505. (
  506. IN PDEVICE_CONTEXT pDeviceContext
  507. )
  508. {
  509. KeSetEvent(&pDeviceContext->kEventDevice,0,FALSE);
  510. #ifdef UNDER_NT
  511. KeLeaveCriticalRegion();
  512. #endif
  513. }
  514. /*****************************************************************************
  515. * IncrementPendingIrpCount()
  516. *****************************************************************************
  517. * Increment the pending IRP count for the device.
  518. */
  519. VOID
  520. IncrementPendingIrpCount
  521. (
  522. IN PDEVICE_CONTEXT pDeviceContext
  523. )
  524. {
  525. ASSERT(pDeviceContext);
  526. InterlockedIncrement(PLONG(&pDeviceContext->PendingIrpCount));
  527. }
  528. /*****************************************************************************
  529. * DecrementPendingIrpCount()
  530. *****************************************************************************
  531. * Decrement the pending IRP count for the device.
  532. */
  533. VOID
  534. DecrementPendingIrpCount
  535. (
  536. IN PDEVICE_CONTEXT pDeviceContext
  537. )
  538. {
  539. ASSERT(pDeviceContext);
  540. ASSERT(pDeviceContext->PendingIrpCount > 0);
  541. if (InterlockedDecrement(PLONG(&pDeviceContext->PendingIrpCount)) == 0)
  542. {
  543. KeSetEvent(&pDeviceContext->kEventRemove,0,FALSE);
  544. }
  545. }
  546. /*****************************************************************************
  547. * CompleteIrp()
  548. *****************************************************************************
  549. * Complete an IRP unless status is STATUS_PENDING.
  550. */
  551. NTSTATUS
  552. CompleteIrp
  553. (
  554. IN PDEVICE_CONTEXT pDeviceContext,
  555. IN PIRP pIrp,
  556. IN NTSTATUS ntStatus
  557. )
  558. {
  559. ASSERT(pDeviceContext);
  560. ASSERT(pIrp);
  561. if (ntStatus != STATUS_PENDING)
  562. {
  563. pIrp->IoStatus.Status = ntStatus;
  564. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  565. DecrementPendingIrpCount(pDeviceContext);
  566. }
  567. return ntStatus;
  568. }
  569. /*****************************************************************************
  570. * PcCompleteIrp()
  571. *****************************************************************************
  572. * Complete an IRP unless status is STATUS_PENDING.
  573. */
  574. PORTCLASSAPI
  575. NTSTATUS
  576. NTAPI
  577. PcCompleteIrp
  578. (
  579. IN PDEVICE_OBJECT pDeviceObject,
  580. IN PIRP pIrp,
  581. IN NTSTATUS ntStatus
  582. )
  583. {
  584. ASSERT(pDeviceObject);
  585. ASSERT(pIrp);
  586. if (NULL == pDeviceObject ||
  587. NULL == pIrp ||
  588. NULL == pDeviceObject->DeviceExtension)
  589. {
  590. // don't know what to do, so we'll fail the IRP
  591. ntStatus = STATUS_INVALID_PARAMETER;
  592. pIrp->IoStatus.Status = ntStatus;
  593. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  594. return ntStatus;
  595. }
  596. return
  597. CompleteIrp
  598. (
  599. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension),
  600. pIrp,
  601. ntStatus
  602. );
  603. }
  604. #pragma code_seg("PAGE")
  605. // shamelessly stolen from nt\private\ntos\ks\api.c
  606. NTSTATUS QueryReferenceBusInterface(
  607. IN PDEVICE_OBJECT PnpDeviceObject,
  608. OUT PBUS_INTERFACE_REFERENCE BusInterface
  609. )
  610. /*++
  611. Routine Description:
  612. Queries the bus for the standard information interface.
  613. Arguments:
  614. PnpDeviceObject -
  615. Contains the next device object on the Pnp stack.
  616. PhysicalDeviceObject -
  617. Contains the physical device object which was passed to the FDO during
  618. the Add Device.
  619. BusInterface -
  620. The place in which to return the Reference interface.
  621. Return Value:
  622. Returns STATUS_SUCCESS if the interface was retrieved, else an error.
  623. --*/
  624. {
  625. NTSTATUS Status;
  626. KEVENT Event;
  627. IO_STATUS_BLOCK IoStatusBlock;
  628. PIRP Irp;
  629. PIO_STACK_LOCATION IrpStackNext;
  630. PAGED_CODE();
  631. //
  632. // There is no file object associated with this Irp, so the event may be located
  633. // on the stack as a non-object manager object.
  634. //
  635. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  636. Irp = IoBuildSynchronousFsdRequest(
  637. IRP_MJ_PNP,
  638. PnpDeviceObject,
  639. NULL,
  640. 0,
  641. NULL,
  642. &Event,
  643. &IoStatusBlock);
  644. if (Irp)
  645. {
  646. Irp->RequestorMode = KernelMode;
  647. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  648. IrpStackNext = IoGetNextIrpStackLocation(Irp);
  649. //
  650. // Create an interface query out of the Irp.
  651. //
  652. IrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE;
  653. IrpStackNext->Parameters.QueryInterface.InterfaceType = (GUID*)&REFERENCE_BUS_INTERFACE;
  654. IrpStackNext->Parameters.QueryInterface.Size = sizeof(*BusInterface);
  655. IrpStackNext->Parameters.QueryInterface.Version = BUS_INTERFACE_REFERENCE_VERSION;
  656. IrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
  657. IrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  658. Status = IoCallDriver(PnpDeviceObject, Irp);
  659. if (Status == STATUS_PENDING)
  660. {
  661. //
  662. // This waits using KernelMode, so that the stack, and therefore the
  663. // event on that stack, is not paged out.
  664. //
  665. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  666. Status = IoStatusBlock.Status;
  667. }
  668. }
  669. else
  670. {
  671. Status = STATUS_INSUFFICIENT_RESOURCES;
  672. }
  673. return Status;
  674. }
  675. #pragma code_seg()
  676. /*****************************************************************************
  677. * IoTimeoutRoutine()
  678. *****************************************************************************
  679. * Called by IoTimer for timeout purposes
  680. */
  681. VOID
  682. IoTimeoutRoutine
  683. (
  684. IN PDEVICE_OBJECT pDeviceObject,
  685. IN PVOID pContext
  686. )
  687. {
  688. ASSERT(pDeviceObject);
  689. ASSERT(pContext);
  690. KIRQL OldIrql;
  691. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pContext);
  692. // grab the list spinlock
  693. KeAcquireSpinLock( &(pDeviceContext->TimeoutLock), &OldIrql );
  694. // walk the list if it's not empty
  695. if( !IsListEmpty( &(pDeviceContext->TimeoutList) ) )
  696. {
  697. PLIST_ENTRY ListEntry;
  698. PTIMEOUTCALLBACK pCallback;
  699. for( ListEntry = pDeviceContext->TimeoutList.Flink;
  700. ListEntry != &(pDeviceContext->TimeoutList);
  701. ListEntry = ListEntry->Flink )
  702. {
  703. pCallback = (PTIMEOUTCALLBACK) CONTAINING_RECORD( ListEntry,
  704. TIMEOUTCALLBACK,
  705. ListEntry );
  706. // call the callback
  707. pCallback->TimerRoutine(pDeviceObject,pCallback->Context);
  708. }
  709. }
  710. // release the spinlock
  711. KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
  712. }
  713. #pragma code_seg("PAGE")
  714. /*****************************************************************************
  715. * PcAddAdapterDevice()
  716. *****************************************************************************
  717. * Adds an adapter device.
  718. */
  719. PORTCLASSAPI
  720. NTSTATUS
  721. NTAPI
  722. PcAddAdapterDevice
  723. (
  724. IN PDRIVER_OBJECT DriverObject,
  725. IN PDEVICE_OBJECT PhysicalDeviceObject,
  726. IN PCPFNSTARTDEVICE StartDevice,
  727. IN ULONG MaxObjects,
  728. IN ULONG DeviceExtensionSize
  729. )
  730. {
  731. PAGED_CODE();
  732. ASSERT(DriverObject);
  733. ASSERT(PhysicalDeviceObject);
  734. ASSERT(StartDevice);
  735. ASSERT(MaxObjects);
  736. _DbgPrintF(DEBUGLVL_VERBOSE,("PcAddAdapterDevice"));
  737. //
  738. // Validate Parameters.
  739. //
  740. if (NULL == DriverObject ||
  741. NULL == PhysicalDeviceObject ||
  742. NULL == StartDevice ||
  743. 0 == MaxObjects)
  744. {
  745. _DbgPrintF(DEBUGLVL_TERSE, ("PcAddAdapterDevice : Invalid Parameter"));
  746. return STATUS_INVALID_PARAMETER;
  747. }
  748. //
  749. // Extension size may be zero or >= required size.
  750. //
  751. if (DeviceExtensionSize == 0)
  752. {
  753. DeviceExtensionSize = sizeof(DEVICE_CONTEXT);
  754. }
  755. else
  756. if (DeviceExtensionSize < sizeof(DEVICE_CONTEXT))
  757. {
  758. return STATUS_INVALID_PARAMETER;
  759. }
  760. //
  761. // Create the device object.
  762. //
  763. PDEVICE_OBJECT pDeviceObject;
  764. NTSTATUS ntStatus = IoCreateDevice( DriverObject,
  765. DeviceExtensionSize,
  766. NULL,
  767. FILE_DEVICE_KS,
  768. FILE_DEVICE_SECURE_OPEN |
  769. FILE_AUTOGENERATED_DEVICE_NAME,
  770. FALSE,
  771. &pDeviceObject );
  772. if (NT_SUCCESS(ntStatus))
  773. {
  774. //
  775. // Initialize the device context.
  776. //
  777. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  778. RtlZeroMemory(pDeviceContext,DeviceExtensionSize);
  779. pDeviceContext->Signature = PORTCLS_DEVICE_EXTENSION_SIGNATURE;
  780. pDeviceContext->MaxObjects = MaxObjects;
  781. pDeviceContext->PhysicalDeviceObject = PhysicalDeviceObject;
  782. pDeviceContext->CreateItems =
  783. new(NonPagedPool,'iCcP') KSOBJECT_CREATE_ITEM[MaxObjects];
  784. pDeviceContext->SymbolicLinkNames =
  785. new(NonPagedPool,'lScP') UNICODE_STRING[MaxObjects];
  786. pDeviceContext->StartDevice = StartDevice;
  787. // set the current power states
  788. pDeviceContext->CurrentDeviceState = PowerDeviceUnspecified;
  789. pDeviceContext->CurrentSystemState = PowerSystemWorking;
  790. pDeviceContext->SystemStateHandle = NULL;
  791. // set device stop/remove states
  792. pDeviceContext->DeviceStopState = DeviceStartPending;
  793. pDeviceContext->DeviceRemoveState = DeviceAdded;
  794. // Let's pause I/O during rebalance (as opposed to a full teardown)
  795. //
  796. // Blackcomb ISSUE
  797. // Discovery AdriaO 06/29/1999
  798. // We aren't *quite* there yet.
  799. // Commentary MartinP 11/28/2000
  800. // So true. Our problem: PortCls might be restarted
  801. // with different resources, even one less IRQ or DMA channel,
  802. // when rebalance completes. In a way, this would require our
  803. // stack to support dynamic graph changes, which it currently
  804. // does not. AdriaO suggests we implement something along the
  805. // lines of "IsFilterCompatible(RESOURCE_LIST)". It's too late
  806. // for a change like this in Windows XP, let's fix this for
  807. // Blackcomb and PortCls2.
  808. //
  809. pDeviceContext->PauseForRebalance = FALSE;
  810. //
  811. // Initialize list of device interfaces.
  812. //
  813. InitializeListHead(&pDeviceContext->DeviceInterfaceList);
  814. //
  815. // Initialize list of physical connections.
  816. //
  817. InitializeListHead(&pDeviceContext->PhysicalConnectionList);
  818. //
  819. // Initialize list of pended IRPs.
  820. //
  821. InitializeListHead(&pDeviceContext->PendedIrpList);
  822. KeInitializeSpinLock(&pDeviceContext->PendedIrpLock);
  823. //
  824. // Initialize events for device synchronization and removal.
  825. //
  826. KeInitializeEvent(&pDeviceContext->kEventDevice,SynchronizationEvent,TRUE);
  827. KeInitializeEvent(&pDeviceContext->kEventRemove,SynchronizationEvent,FALSE);
  828. //
  829. // Set up the DPC for fast resume
  830. //
  831. KeInitializeDpc(&pDeviceContext->DevicePowerRequestDpc, DevicePowerRequestRoutine, pDeviceContext);
  832. //
  833. // Set the idle timeouts to the defaults. Note that the
  834. // actual value will be read from the registry later.
  835. //
  836. pDeviceContext->ConservationIdleTime = DEFAULT_CONSERVATION_IDLE_TIME;
  837. pDeviceContext->PerformanceIdleTime = DEFAULT_PERFORMANCE_IDLE_TIME;
  838. pDeviceContext->IdleDeviceState = DEFAULT_IDLE_DEVICE_POWER_STATE;
  839. // setup the driver object DMA spinlock
  840. NTSTATUS ntStatus2 = IoAllocateDriverObjectExtension( DriverObject,
  841. PVOID((DWORD_PTR)PORTCLS_DRIVER_EXTENSION_ID),
  842. sizeof(KSPIN_LOCK),
  843. (PVOID *)&pDeviceContext->DriverDmaLock );
  844. if( STATUS_SUCCESS == ntStatus2 )
  845. {
  846. // if we allocated it we need to initialize it
  847. KeInitializeSpinLock( pDeviceContext->DriverDmaLock );
  848. } else if( STATUS_OBJECT_NAME_COLLISION == ntStatus2 )
  849. {
  850. // we had a collision so it was alread allocated, just get the pointer and don't initialize
  851. pDeviceContext->DriverDmaLock = (PKSPIN_LOCK)IoGetDriverObjectExtension( DriverObject,
  852. PVOID((DWORD_PTR)PORTCLS_DRIVER_EXTENSION_ID) );
  853. } else
  854. {
  855. // propagate the failure (STATUS_INSUFFICIENT_RESOURCES)
  856. ntStatus = ntStatus2;
  857. }
  858. if( NT_SUCCESS(ntStatus) )
  859. {
  860. if( ( !pDeviceContext->CreateItems ) || ( !pDeviceContext->SymbolicLinkNames) )
  861. {
  862. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  863. } else
  864. {
  865. //
  866. // When this reaches zero, it'll be time to remove the device.
  867. //
  868. pDeviceContext->PendingIrpCount = 1;
  869. //
  870. // Initialize suspend and stop counts (used for debugging only)
  871. //
  872. pDeviceContext->SuspendCount = 0;
  873. pDeviceContext->StopCount = 0;
  874. //
  875. // Initialize the IoTimer
  876. //
  877. InitializeListHead(&pDeviceContext->TimeoutList);
  878. KeInitializeSpinLock(&pDeviceContext->TimeoutLock);
  879. pDeviceContext->IoTimeoutsOk = FALSE;
  880. if( NT_SUCCESS(IoInitializeTimer(pDeviceObject,IoTimeoutRoutine,pDeviceContext)) )
  881. {
  882. pDeviceContext->IoTimeoutsOk = TRUE;
  883. }
  884. //
  885. // Allocate the KS device header
  886. //
  887. ntStatus = KsAllocateDeviceHeader( &pDeviceContext->pDeviceHeader,
  888. MaxObjects,
  889. pDeviceContext->CreateItems );
  890. if( NT_SUCCESS(ntStatus) )
  891. {
  892. PDEVICE_OBJECT pReturnDevice = IoAttachDeviceToDeviceStack( pDeviceObject,
  893. PhysicalDeviceObject );
  894. if (! pReturnDevice)
  895. {
  896. // free the KS device header
  897. KsFreeDeviceHeader( pDeviceContext->pDeviceHeader );
  898. pDeviceContext->pDeviceHeader = NULL;
  899. ntStatus = STATUS_UNSUCCESSFUL;
  900. }
  901. else
  902. {
  903. BUS_INTERFACE_REFERENCE BusInterface;
  904. KsSetDevicePnpAndBaseObject(pDeviceContext->pDeviceHeader,
  905. pReturnDevice,
  906. pDeviceObject );
  907. pDeviceContext->NextDeviceInStack = pReturnDevice;
  908. //
  909. // Here we try to detect the case where we really aren't
  910. // an audio miniport, but rather helping out an swenum
  911. // dude like dmusic. In the later case, we disallow
  912. // (nonsensical) registration.
  913. //
  914. pDeviceContext->AllowRegisterDeviceInterface=TRUE;
  915. if (NT_SUCCESS(QueryReferenceBusInterface(pReturnDevice,&BusInterface)))
  916. {
  917. BusInterface.Interface.InterfaceDereference( BusInterface.Interface.Context );
  918. pDeviceContext->AllowRegisterDeviceInterface=FALSE;
  919. }
  920. }
  921. pDeviceObject->Flags |= DO_DIRECT_IO;
  922. pDeviceObject->Flags |= DO_POWER_PAGABLE;
  923. pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  924. }
  925. }
  926. }
  927. if (!NT_SUCCESS(ntStatus))
  928. {
  929. if (pDeviceContext->CreateItems)
  930. {
  931. delete [] pDeviceContext->CreateItems;
  932. }
  933. if (pDeviceContext->SymbolicLinkNames)
  934. {
  935. delete [] pDeviceContext->SymbolicLinkNames;
  936. }
  937. IoDeleteDevice(pDeviceObject);
  938. }
  939. else
  940. {
  941. PerfRegisterProvider(pDeviceObject);
  942. }
  943. }
  944. else
  945. {
  946. _DbgPrintF(DEBUGLVL_TERSE,("PcAddAdapterDevice IoCreateDevice failed with status 0x%08x",ntStatus));
  947. }
  948. return ntStatus;
  949. }
  950. #pragma code_seg()
  951. /*****************************************************************************
  952. * ForwardIrpCompletionRoutine()
  953. *****************************************************************************
  954. * Completion routine for ForwardIrp.
  955. */
  956. static
  957. NTSTATUS
  958. ForwardIrpCompletionRoutine
  959. (
  960. IN PDEVICE_OBJECT DeviceObject,
  961. IN PIRP Irp,
  962. IN PVOID Context
  963. )
  964. {
  965. ASSERT(DeviceObject);
  966. ASSERT(Irp);
  967. ASSERT(Context);
  968. KeSetEvent((PKEVENT) Context,0,FALSE);
  969. return STATUS_MORE_PROCESSING_REQUIRED;
  970. }
  971. /*****************************************************************************
  972. * ForwardIrpAsynchronous()
  973. *****************************************************************************
  974. * Forward a PnP IRP to the PDO. The IRP is completed at this level
  975. * regardless of the outcome, this function returns immediately regardless of
  976. * whether the IRP is pending in the lower driver, and
  977. * DecrementPendingIrpCount() is called in all cases.
  978. */
  979. NTSTATUS
  980. ForwardIrpAsynchronous
  981. (
  982. IN PDEVICE_CONTEXT pDeviceContext,
  983. IN PIRP pIrp
  984. )
  985. {
  986. ASSERT(pDeviceContext);
  987. ASSERT(pIrp);
  988. NTSTATUS ntStatus;
  989. if (pDeviceContext->DeviceRemoveState == DeviceRemoved)
  990. {
  991. _DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpAsynchronous delete pending"));
  992. ntStatus = CompleteIrp(pDeviceContext,pIrp,STATUS_DELETE_PENDING);
  993. }
  994. else
  995. {
  996. _DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpAsynchronous"));
  997. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(pIrp);
  998. IoSkipCurrentIrpStackLocation(pIrp);
  999. if (irpSp->MajorFunction == IRP_MJ_POWER)
  1000. {
  1001. ntStatus = PoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
  1002. }
  1003. else
  1004. {
  1005. ntStatus = IoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
  1006. }
  1007. DecrementPendingIrpCount(pDeviceContext);
  1008. }
  1009. return ntStatus;
  1010. }
  1011. /*****************************************************************************
  1012. * ForwardIrpSynchronous()
  1013. *****************************************************************************
  1014. * Forward a PnP IRP to the PDO. The IRP is not completed at this level,
  1015. * this function does not return until the lower driver has completed the IRP,
  1016. * and DecrementPendingIrpCount() is not called.
  1017. */
  1018. NTSTATUS
  1019. ForwardIrpSynchronous
  1020. (
  1021. IN PDEVICE_CONTEXT pDeviceContext,
  1022. IN PIRP pIrp
  1023. )
  1024. {
  1025. ASSERT(pDeviceContext);
  1026. ASSERT(pIrp);
  1027. NTSTATUS ntStatus;
  1028. if (pDeviceContext->DeviceRemoveState == DeviceRemoved)
  1029. {
  1030. ntStatus = STATUS_DELETE_PENDING;
  1031. _DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous delete pending"));
  1032. }
  1033. else
  1034. {
  1035. _DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous"));
  1036. PIO_STACK_LOCATION irpStackPointer = IoGetCurrentIrpStackLocation(pIrp);
  1037. // setup next stack location
  1038. IoCopyCurrentIrpStackLocationToNext( pIrp );
  1039. KEVENT kEvent;
  1040. KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
  1041. IoSetCompletionRoutine
  1042. (
  1043. pIrp,
  1044. ForwardIrpCompletionRoutine,
  1045. &kEvent, // Context
  1046. TRUE, // InvokeOnSuccess
  1047. TRUE, // InvokeOnError
  1048. TRUE // InvokeOnCancel
  1049. );
  1050. if (irpStackPointer->MajorFunction == IRP_MJ_POWER)
  1051. {
  1052. ntStatus = PoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
  1053. }
  1054. else
  1055. {
  1056. ntStatus = IoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
  1057. }
  1058. if (ntStatus == STATUS_PENDING)
  1059. {
  1060. LARGE_INTEGER Timeout = RtlConvertLongToLargeInteger( 0L );
  1061. _DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous pending..."));
  1062. KeWaitForSingleObject
  1063. (
  1064. &kEvent,
  1065. Suspended,
  1066. KernelMode,
  1067. FALSE,
  1068. (KeGetCurrentIrql() < DISPATCH_LEVEL) ? NULL : &Timeout
  1069. );
  1070. ntStatus = pIrp->IoStatus.Status;
  1071. _DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous complete"));
  1072. }
  1073. }
  1074. ASSERT(ntStatus != STATUS_PENDING);
  1075. return ntStatus;
  1076. }
  1077. #pragma code_seg("PAGE")
  1078. /*****************************************************************************
  1079. * PcForwardIrpSynchronous()
  1080. *****************************************************************************
  1081. * Forward a PnP IRP to the PDO. The IRP is not completed at this level,
  1082. * this function does not return until the lower driver has completed the IRP,
  1083. * and DecrementPendingIrpCount() is not called.
  1084. */
  1085. PORTCLASSAPI
  1086. NTSTATUS
  1087. NTAPI
  1088. PcForwardIrpSynchronous
  1089. (
  1090. IN PDEVICE_OBJECT DeviceObject,
  1091. IN PIRP Irp
  1092. )
  1093. {
  1094. ASSERT(DeviceObject);
  1095. ASSERT(Irp);
  1096. PAGED_CODE();
  1097. //
  1098. // Validate Parameters.
  1099. //
  1100. if (NULL == DeviceObject ||
  1101. NULL == Irp)
  1102. {
  1103. // don't know what to do, so we'll fail the IRP
  1104. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1105. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1106. return STATUS_INVALID_PARAMETER;
  1107. }
  1108. return
  1109. ForwardIrpSynchronous
  1110. (
  1111. PDEVICE_CONTEXT(DeviceObject->DeviceExtension),
  1112. Irp
  1113. );
  1114. }
  1115. /*****************************************************************************
  1116. * DispatchSystemControl()
  1117. *****************************************************************************
  1118. * Device objects that do not handle this IRP should leave it untouched.
  1119. */
  1120. NTSTATUS
  1121. PcDispatchSystemControl
  1122. (
  1123. IN PDEVICE_OBJECT pDeviceObject,
  1124. IN PIRP pIrp
  1125. )
  1126. {
  1127. ASSERT(pDeviceObject);
  1128. ASSERT(pIrp);
  1129. PAGED_CODE();
  1130. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchSystemControl"));
  1131. PDEVICE_CONTEXT pDeviceContext =
  1132. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  1133. NTSTATUS ntStatus = PcValidateDeviceContext(pDeviceContext, pIrp);
  1134. if (!NT_SUCCESS(ntStatus))
  1135. {
  1136. // Don't know what to do, but this is probably a PDO.
  1137. // We'll try to make this right by completing the IRP
  1138. // untouched (per PnP, WMI, and Power rules). Note
  1139. // that if this isn't a PDO, and isn't a portcls FDO, then
  1140. // the driver messed up by using Portcls as a filter (huh?)
  1141. // In this case the verifier will fail us, WHQL will catch
  1142. // them, and the driver will be fixed. We'd be very surprised
  1143. // to see such a case.
  1144. // Assume FDO, no PoStartNextPowerIrp as this isn't IRP_MJ_POWER
  1145. ntStatus = pIrp->IoStatus.Status;
  1146. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  1147. return ntStatus;
  1148. }
  1149. IncrementPendingIrpCount(pDeviceContext);
  1150. return ForwardIrpAsynchronous(pDeviceContext,pIrp);
  1151. }
  1152. /*****************************************************************************
  1153. * PnpStopDevice()
  1154. *****************************************************************************
  1155. * Stop the device.
  1156. */
  1157. NTSTATUS
  1158. PnpStopDevice
  1159. (
  1160. IN PDEVICE_OBJECT pDeviceObject,
  1161. IN PNPSTOP_STYLE StopStyle
  1162. )
  1163. {
  1164. PAGED_CODE();
  1165. ASSERT(pDeviceObject);
  1166. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpStopDevice stopping"));
  1167. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  1168. ASSERT(pDeviceContext);
  1169. ASSERT(pDeviceContext->StartDevice);
  1170. ASSERT(pDeviceContext->DeviceStopState != DeviceStopped);
  1171. pDeviceContext->PendCreates = TRUE;
  1172. pDeviceContext->StopCount++;
  1173. if (StopStyle == STOPSTYLE_PAUSE_FOR_REBALANCE)
  1174. {
  1175. //
  1176. // Blackcomb ISSUE
  1177. // Discovery AdriaO 06/29/1999
  1178. // We don't support this quite yet (see above, in
  1179. // PcAddAdapterDevice, where PauseForRebalance is set false).
  1180. // Commentary MartinP 11/28/2000
  1181. // So true. Our problem: PortCls might be restarted
  1182. // with different resources, even one less IRQ or DMA channel,
  1183. // when rebalance completes. In a way, this would require our
  1184. // stack to support dynamic graph changes, which it currently
  1185. // does not. AdriaO suggests we implement something along the
  1186. // lines of "IsFilterCompatible(RESOURCE_LIST)". It's too late
  1187. // for a change like this in Windows XP, let's fix this for
  1188. // Blackcomb and PortCls2.
  1189. //
  1190. ASSERT(0);
  1191. pDeviceContext->DeviceStopState = DevicePausedForRebalance;
  1192. }
  1193. else
  1194. {
  1195. pDeviceContext->DeviceStopState = DeviceStopped;
  1196. }
  1197. // stop the IoTimeout timer
  1198. if( pDeviceContext->IoTimeoutsOk )
  1199. {
  1200. IoStopTimer( pDeviceObject );
  1201. }
  1202. POWER_STATE newPowerState;
  1203. newPowerState.DeviceState = PowerDeviceD3;
  1204. PoSetPowerState(pDeviceObject,
  1205. DevicePowerState,
  1206. newPowerState
  1207. );
  1208. pDeviceContext->CurrentDeviceState = PowerDeviceD3;
  1209. //
  1210. // Delete all physical connections.
  1211. //
  1212. while (! IsListEmpty(&pDeviceContext->PhysicalConnectionList))
  1213. {
  1214. PPHYSICALCONNECTION pPhysicalConnection =
  1215. (PPHYSICALCONNECTION)RemoveHeadList(&pDeviceContext->PhysicalConnectionList);
  1216. ASSERT(pPhysicalConnection);
  1217. ASSERT(pPhysicalConnection->FromSubdevice);
  1218. ASSERT(pPhysicalConnection->ToSubdevice);
  1219. if (pPhysicalConnection->FromSubdevice)
  1220. {
  1221. pPhysicalConnection->FromSubdevice->Release();
  1222. }
  1223. if (pPhysicalConnection->ToSubdevice)
  1224. {
  1225. pPhysicalConnection->ToSubdevice->Release();
  1226. }
  1227. if (pPhysicalConnection->FromString)
  1228. {
  1229. DelUnicodeString(pPhysicalConnection->FromString);
  1230. }
  1231. if (pPhysicalConnection->ToString)
  1232. {
  1233. DelUnicodeString(pPhysicalConnection->ToString);
  1234. }
  1235. delete pPhysicalConnection;
  1236. }
  1237. //
  1238. // Disable and delete all the device interfaces.
  1239. //
  1240. while (! IsListEmpty(&pDeviceContext->DeviceInterfaceList))
  1241. {
  1242. PDEVICEINTERFACE pDeviceInterface =
  1243. (PDEVICEINTERFACE)
  1244. RemoveHeadList(&pDeviceContext->DeviceInterfaceList);
  1245. ASSERT(pDeviceInterface);
  1246. ASSERT(pDeviceInterface->SymbolicLinkName.Buffer);
  1247. NTSTATUS ntStatus = STATUS_SUCCESS;
  1248. if (pDeviceContext->AllowRegisterDeviceInterface)
  1249. {
  1250. ntStatus = IoSetDeviceInterfaceState(&pDeviceInterface->SymbolicLinkName,FALSE);
  1251. }
  1252. #if DBG
  1253. if (NT_SUCCESS(ntStatus))
  1254. {
  1255. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpStopDevice disabled device interface %S",pDeviceInterface->SymbolicLinkName.Buffer));
  1256. }
  1257. else
  1258. {
  1259. _DbgPrintF(DEBUGLVL_TERSE,("PnpStopDevice failed to disable device interface %S (0x%08x)",pDeviceInterface->SymbolicLinkName.Buffer,ntStatus));
  1260. }
  1261. #endif
  1262. RtlFreeUnicodeString(&pDeviceInterface->SymbolicLinkName);
  1263. delete pDeviceInterface;
  1264. }
  1265. //
  1266. // Clear the symbolic link names table.
  1267. //
  1268. RtlZeroMemory
  1269. ( pDeviceContext->SymbolicLinkNames
  1270. , sizeof(UNICODE_STRING) * pDeviceContext->MaxObjects
  1271. );
  1272. //
  1273. // Unload each subdevice for this device.
  1274. //
  1275. PKSOBJECT_CREATE_ITEM pKsObjectCreateItem =
  1276. pDeviceContext->CreateItems;
  1277. for
  1278. ( ULONG ul = pDeviceContext->MaxObjects;
  1279. ul--;
  1280. pKsObjectCreateItem++
  1281. )
  1282. {
  1283. if (pKsObjectCreateItem->Create)
  1284. {
  1285. //
  1286. // Zero the create function so we won't get creates.
  1287. //
  1288. pKsObjectCreateItem->Create = NULL;
  1289. //
  1290. // Release the subdevice referenced by this create item.
  1291. //
  1292. ASSERT(pKsObjectCreateItem->Context);
  1293. PSUBDEVICE(pKsObjectCreateItem->Context)->ReleaseChildren();
  1294. PSUBDEVICE(pKsObjectCreateItem->Context)->Release();
  1295. }
  1296. }
  1297. //
  1298. // If the Adapter registered a Power Management interface
  1299. //
  1300. if( NULL != pDeviceContext->pAdapterPower )
  1301. {
  1302. // Release it
  1303. pDeviceContext->pAdapterPower->Release();
  1304. pDeviceContext->pAdapterPower = NULL;
  1305. }
  1306. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpStopDevice exiting"));
  1307. return STATUS_SUCCESS;
  1308. }
  1309. /*****************************************************************************
  1310. * PnpStartDevice()
  1311. *****************************************************************************
  1312. * Start the device in the PnP style.
  1313. */
  1314. QUEUED_CALLBACK_RETURN
  1315. PnpStartDevice
  1316. (
  1317. IN PDEVICE_OBJECT pDeviceObject,
  1318. IN PVOID pNotUsed
  1319. )
  1320. {
  1321. PAGED_CODE();
  1322. ASSERT(pDeviceObject);
  1323. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpStartDevice starting (0x%X)",pDeviceObject));
  1324. PDEVICE_CONTEXT pDeviceContext =
  1325. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  1326. ASSERT(pDeviceContext);
  1327. ASSERT(pDeviceContext->StartDevice);
  1328. ASSERT(pDeviceContext->DeviceStopState != DeviceStarted);
  1329. ASSERT(pDeviceContext->DeviceRemoveState == DeviceAdded);
  1330. pDeviceContext->DeviceStopState = DeviceStartPending;
  1331. PIRP pIrp = pDeviceContext->IrpStart;
  1332. ASSERT(pIrp);
  1333. PIO_STACK_LOCATION pIrpStack =
  1334. IoGetCurrentIrpStackLocation(pIrp);
  1335. //
  1336. // Encapsulate the resource lists.
  1337. //
  1338. PRESOURCELIST pResourceList;
  1339. NTSTATUS ntStatus;
  1340. BOOL bCompletePendedIrps=FALSE;
  1341. // in case there is no resource list in IO_STACK_LOCATION, PcNewResourceList
  1342. // just creates an empty resource list.
  1343. ntStatus = PcNewResourceList
  1344. (
  1345. &pResourceList,
  1346. NULL,
  1347. PagedPool,
  1348. pIrpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
  1349. pIrpStack->Parameters.StartDevice.AllocatedResources
  1350. );
  1351. if (NT_SUCCESS(ntStatus))
  1352. {
  1353. ASSERT(pResourceList);
  1354. //
  1355. // Acquire the device to prevent creates during interface registration.
  1356. //
  1357. AcquireDevice(pDeviceContext);
  1358. //
  1359. // Start the adapter.
  1360. //
  1361. ntStatus = pDeviceContext->StartDevice(pDeviceObject,
  1362. pIrp,
  1363. pResourceList);
  1364. ASSERT(ntStatus != STATUS_PENDING);
  1365. pResourceList->Release();
  1366. pDeviceContext->DeviceStopState = DeviceStarted;
  1367. if (NT_SUCCESS(ntStatus))
  1368. {
  1369. // Start is always an implicit power up
  1370. POWER_STATE newPowerState;
  1371. pDeviceContext->CurrentDeviceState = PowerDeviceD0;
  1372. newPowerState.DeviceState = PowerDeviceD0;
  1373. PoSetPowerState(pDeviceObject,
  1374. DevicePowerState,
  1375. newPowerState
  1376. );
  1377. // start the IoTimeout timer
  1378. if( pDeviceContext->IoTimeoutsOk )
  1379. {
  1380. IoStartTimer( pDeviceObject );
  1381. }
  1382. // allow create
  1383. pDeviceContext->PendCreates = FALSE;
  1384. // Can't actually complete pended irps until we call ReleaseDevice, or we might deadlock
  1385. bCompletePendedIrps=TRUE;
  1386. }
  1387. else
  1388. {
  1389. _DbgPrintF(DEBUGLVL_TERSE,("PnpStartDevice adapter failed to start (0x%08x)",ntStatus));
  1390. // stop the device (note: this will set DeviceStopState back to DeviceStopped)
  1391. PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
  1392. }
  1393. //
  1394. // Release the device to allow creates.
  1395. //
  1396. ReleaseDevice(pDeviceContext);
  1397. // Now we can complete pended irps
  1398. if (bCompletePendedIrps)
  1399. {
  1400. CompletePendedIrps( pDeviceObject,
  1401. pDeviceContext,
  1402. EMPTY_QUEUE_AND_PROCESS );
  1403. }
  1404. }
  1405. else
  1406. {
  1407. _DbgPrintF(DEBUGLVL_TERSE,("PnpStartDevice failed to create resource list object (0x%08x)",ntStatus));
  1408. }
  1409. CompleteIrp(pDeviceContext,pIrp,ntStatus);
  1410. _DbgPrintF(DEBUGLVL_VERBOSE,("PnPStartDevice completing with 0x%X status for 0x%X",ntStatus,pDeviceObject));
  1411. return QUEUED_CALLBACK_FREE;
  1412. }
  1413. /*****************************************************************************
  1414. * PnpRemoveDevice()
  1415. *****************************************************************************
  1416. * Dispatch IRP_MJ_PNP/IRP_MN_REMOVE_DEVICE.
  1417. */
  1418. NTSTATUS
  1419. PnpRemoveDevice
  1420. (
  1421. IN PDEVICE_OBJECT pDeviceObject
  1422. )
  1423. {
  1424. PAGED_CODE();
  1425. ASSERT(pDeviceObject);
  1426. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice"));
  1427. PDEVICE_CONTEXT pDeviceContext =
  1428. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  1429. ASSERT( pDeviceContext );
  1430. pDeviceContext->DeviceRemoveState = DeviceRemoved;
  1431. if (InterlockedDecrement(PLONG(&pDeviceContext->PendingIrpCount)) != 0)
  1432. {
  1433. // setup for 15 second timeout (PASSIVE_LEVEL only!!)
  1434. LARGE_INTEGER Timeout = RtlConvertLongToLargeInteger( -15L * 10000000L );
  1435. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice pending irp count is %d, waiting up to 15 seconds",pDeviceContext->PendingIrpCount));
  1436. KeWaitForSingleObject( &pDeviceContext->kEventRemove,
  1437. Executive,
  1438. KernelMode,
  1439. FALSE,
  1440. (PASSIVE_LEVEL == KeGetCurrentIrql()) ? &Timeout : NULL );
  1441. }
  1442. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice pending irp count is 0"));
  1443. IoDetachDevice(pDeviceContext->NextDeviceInStack);
  1444. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice detached"));
  1445. if (pDeviceContext->CreateItems)
  1446. {
  1447. delete [] pDeviceContext->CreateItems;
  1448. }
  1449. if (pDeviceContext->SymbolicLinkNames)
  1450. {
  1451. delete [] pDeviceContext->SymbolicLinkNames;
  1452. }
  1453. PDRIVER_OBJECT pDriverObject = pDeviceObject->DriverObject;
  1454. if (pDeviceObject->NextDevice)
  1455. {
  1456. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice there is a next device"));
  1457. }
  1458. if (pDriverObject->DeviceObject != pDeviceObject)
  1459. {
  1460. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice there is a previous device"));
  1461. }
  1462. IoDeleteDevice(pDeviceObject);
  1463. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice device deleted"));
  1464. PerfUnregisterProvider(pDeviceObject);
  1465. if (pDriverObject->DeviceObject)
  1466. {
  1467. if (pDriverObject->DeviceObject != pDeviceObject)
  1468. {
  1469. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice driver object still has some other device object"));
  1470. }
  1471. else
  1472. {
  1473. _DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice driver object still has this device object"));
  1474. }
  1475. }
  1476. return STATUS_SUCCESS;
  1477. }
  1478. /*****************************************************************************
  1479. * DispatchPnp()
  1480. *****************************************************************************
  1481. * Supplying your PnP needs for over 20 min
  1482. */
  1483. NTSTATUS
  1484. DispatchPnp
  1485. (
  1486. IN PDEVICE_OBJECT pDeviceObject,
  1487. IN PIRP pIrp
  1488. )
  1489. {
  1490. PAGED_CODE();
  1491. ASSERT(pDeviceObject);
  1492. ASSERT(pIrp);
  1493. NTSTATUS ntStatus = STATUS_SUCCESS;
  1494. PIO_STACK_LOCATION pIrpStack =
  1495. IoGetCurrentIrpStackLocation(pIrp);
  1496. PDEVICE_CONTEXT pDeviceContext =
  1497. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  1498. #if (DBG)
  1499. static PCHAR aszMnNames[] =
  1500. {
  1501. "IRP_MN_START_DEVICE",
  1502. "IRP_MN_QUERY_REMOVE_DEVICE",
  1503. "IRP_MN_REMOVE_DEVICE",
  1504. "IRP_MN_CANCEL_REMOVE_DEVICE",
  1505. "IRP_MN_STOP_DEVICE",
  1506. "IRP_MN_QUERY_STOP_DEVICE",
  1507. "IRP_MN_CANCEL_STOP_DEVICE",
  1508. "IRP_MN_QUERY_DEVICE_RELATIONS",
  1509. "IRP_MN_QUERY_INTERFACE",
  1510. "IRP_MN_QUERY_CAPABILITIES",
  1511. "IRP_MN_QUERY_RESOURCES",
  1512. "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
  1513. "IRP_MN_QUERY_DEVICE_TEXT",
  1514. "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
  1515. "IRP_MN_UNKNOWN_0x0e",
  1516. "IRP_MN_READ_CONFIG",
  1517. "IRP_MN_WRITE_CONFIG",
  1518. "IRP_MN_EJECT",
  1519. "IRP_MN_SET_LOCK",
  1520. "IRP_MN_QUERY_ID",
  1521. "IRP_MN_QUERY_PNP_DEVICE_STATE",
  1522. "IRP_MN_QUERY_BUS_INFORMATION",
  1523. "IRP_MN_PAGING_NOTIFICATION",
  1524. "IRP_MN_SURPRISE_REMOVAL"
  1525. };
  1526. if (pIrpStack->MinorFunction >= SIZEOF_ARRAY(aszMnNames))
  1527. {
  1528. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp function 0x%02x",pIrpStack->MinorFunction));
  1529. }
  1530. else
  1531. {
  1532. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp function %s",aszMnNames[pIrpStack->MinorFunction]));
  1533. }
  1534. #endif
  1535. ntStatus = PcValidateDeviceContext(pDeviceContext, pIrp);
  1536. if (!NT_SUCCESS(ntStatus))
  1537. {
  1538. // Don't know what to do, but this is probably a PDO.
  1539. // We'll try to make this right by completing the IRP
  1540. // untouched (per PnP, WMI, and Power rules). Note
  1541. // that if this isn't a PDO, and isn't a portcls FDO, then
  1542. // the driver messed up by using Portcls as a filter (huh?)
  1543. // In this case the verifier will fail us, WHQL will catch
  1544. // them, and the driver will be fixed. We'd be very surprised
  1545. // to see such a case.
  1546. // Assume FDO, no PoStartNextPowerIrp as this isn't IRP_MJ_POWER
  1547. ntStatus = pIrp->IoStatus.Status;
  1548. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  1549. return ntStatus;
  1550. }
  1551. IncrementPendingIrpCount(pDeviceContext);
  1552. switch (pIrpStack->MinorFunction)
  1553. {
  1554. case IRP_MN_START_DEVICE:
  1555. // if we are already started, something wrong happened
  1556. if( pDeviceContext->DeviceStopState == DeviceStarted )
  1557. {
  1558. //
  1559. // In theory, this is the path that would be exercized by non-stop
  1560. // rebalance. As it's the Fdo's choice to do so via
  1561. // IoInvalidateDeviceState(...), and as we don't do this, we should
  1562. // never ever be here unless something really strange happened...
  1563. //
  1564. // ASSERT(0);
  1565. // ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1566. _DbgPrintF(DEBUGLVL_TERSE,("DispatchPnP IRP_MN_START_DEVICE received when already started"));
  1567. //CompleteIrp( pDeviceContext, pIrp, ntStatus );
  1568. ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp); // for some reason we get nested starts
  1569. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  1570. } else {
  1571. //
  1572. // Forward request and start.
  1573. //
  1574. ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp);
  1575. if (NT_SUCCESS(ntStatus))
  1576. {
  1577. // Do a real start. Begin by pending the irp
  1578. IoMarkIrpPending(pIrp);
  1579. pDeviceContext->IrpStart = pIrp;
  1580. // queue the start work item
  1581. _DbgPrintF(DEBUGLVL_VERBOSE,("Queueing WorkQueueItemStart for 0x%X",pDeviceObject));
  1582. ntStatus = CallbackEnqueue(
  1583. &pDeviceContext->pWorkQueueItemStart,
  1584. PnpStartDevice,
  1585. pDeviceObject,
  1586. NULL,
  1587. PASSIVE_LEVEL,
  1588. EQCF_DIFFERENT_THREAD_REQUIRED
  1589. );
  1590. if (!NT_SUCCESS(ntStatus)) {
  1591. _DbgPrintF(DEBUGLVL_TERSE,("DispatchPnp failed to queue callback (%08x)",ntStatus));
  1592. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  1593. }
  1594. ntStatus = STATUS_PENDING;
  1595. }
  1596. else
  1597. {
  1598. _DbgPrintF(DEBUGLVL_TERSE,("DispatchPnp parent failed to start (%08x)",ntStatus));
  1599. CompleteIrp(pDeviceContext,pIrp,ntStatus);
  1600. }
  1601. }
  1602. break;
  1603. case IRP_MN_QUERY_STOP_DEVICE:
  1604. //
  1605. // Acquire the device to avoid race condition with Create
  1606. //
  1607. AcquireDevice( pDeviceContext );
  1608. LONG handleCount;
  1609. ntStatus = STATUS_SUCCESS;
  1610. //
  1611. // If we are tearing everything down, we must check for open handles,
  1612. // otherwise we do a quick activity check.
  1613. //
  1614. handleCount = (pDeviceContext->PauseForRebalance) ?
  1615. pDeviceContext->ActivePinCount :
  1616. pDeviceContext->ExistingObjectCount;
  1617. if ( handleCount != 0 ) {
  1618. //
  1619. // Sorry Joe User, we must fail this QUERY_STOP_DEVICE request
  1620. //
  1621. ntStatus = STATUS_DEVICE_BUSY;
  1622. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  1623. }
  1624. else {
  1625. //
  1626. // Pass down the query.
  1627. //
  1628. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1629. ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp);
  1630. if (NT_SUCCESS(ntStatus)) {
  1631. //
  1632. // pend new creates, this'll keep the active counts from changing.
  1633. //
  1634. pDeviceContext->PendCreates = TRUE;
  1635. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp query STOP succeeded",ntStatus));
  1636. pDeviceContext->DeviceStopState = DeviceStopPending;
  1637. }
  1638. else {
  1639. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp parent failed query STOP (0x%08x)",ntStatus));
  1640. }
  1641. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  1642. }
  1643. ReleaseDevice( pDeviceContext );
  1644. break ;
  1645. case IRP_MN_CANCEL_STOP_DEVICE:
  1646. //ASSERT( DeviceStopPending == pDeviceContext->DeviceStopState );
  1647. if (pDeviceContext->DeviceStopState == DeviceStopPending)
  1648. {
  1649. pDeviceContext->DeviceStopState = DeviceStarted;
  1650. }
  1651. //
  1652. // allow creates if in D0
  1653. //
  1654. if( NT_SUCCESS(CheckCurrentPowerState(pDeviceObject)) )
  1655. {
  1656. pDeviceContext->PendCreates = FALSE;
  1657. //
  1658. // Pull any pended irps off the pended irp list and
  1659. // pass them back to PcDispatchIrp
  1660. //
  1661. CompletePendedIrps( pDeviceObject,
  1662. pDeviceContext,
  1663. EMPTY_QUEUE_AND_PROCESS );
  1664. }
  1665. // forward the irp
  1666. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1667. ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
  1668. break ;
  1669. case IRP_MN_STOP_DEVICE:
  1670. if (pDeviceContext->PauseForRebalance &&
  1671. (pDeviceContext->DeviceStopState == DeviceStopPending))
  1672. {
  1673. ntStatus = PnpStopDevice(pDeviceObject, STOPSTYLE_PAUSE_FOR_REBALANCE);
  1674. }
  1675. else
  1676. {
  1677. //
  1678. // Either we've decided not to pause during rebalance, or this is
  1679. // a "naked" stop on Win9x, which occurs when the OS wishes to
  1680. // disable us.
  1681. //
  1682. //
  1683. // Stopping us will change our state and tear everything down
  1684. //
  1685. if (pDeviceContext->DeviceStopState != DeviceStopped)
  1686. {
  1687. ntStatus = PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
  1688. }
  1689. else
  1690. {
  1691. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp stop received in unstarted state"));
  1692. }
  1693. //
  1694. // Now fail any pended irps.
  1695. //
  1696. CompletePendedIrps( pDeviceObject,
  1697. pDeviceContext,
  1698. EMPTY_QUEUE_AND_FAIL );
  1699. }
  1700. if (NT_SUCCESS(ntStatus))
  1701. {
  1702. // forward the irp
  1703. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1704. ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
  1705. }
  1706. else
  1707. {
  1708. CompleteIrp(pDeviceContext,pIrp,ntStatus);
  1709. }
  1710. break;
  1711. case IRP_MN_QUERY_REMOVE_DEVICE:
  1712. //
  1713. // Acquire the device because we don't want to race with creates.
  1714. //
  1715. AcquireDevice(pDeviceContext);
  1716. if ( pDeviceContext->ExistingObjectCount != 0 ) {
  1717. //
  1718. // Somebody has open handles on us, so fail the QUERY_REMOVE_DEVICE
  1719. // request.
  1720. //
  1721. ntStatus = STATUS_DEVICE_BUSY;
  1722. } else {
  1723. //
  1724. // Lookin good, pass down the query.
  1725. //
  1726. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1727. ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp);
  1728. if (NT_SUCCESS(ntStatus))
  1729. {
  1730. //
  1731. // Pend future creates.
  1732. //
  1733. pDeviceContext->PendCreates = TRUE;
  1734. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp query REMOVE succeeded",ntStatus));
  1735. pDeviceContext->DeviceRemoveState = DeviceRemovePending;
  1736. }
  1737. else
  1738. {
  1739. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp parent failed query REMOVE (0x%08x)",ntStatus));
  1740. }
  1741. }
  1742. ReleaseDevice(pDeviceContext);
  1743. CompleteIrp(pDeviceContext,pIrp,ntStatus);
  1744. break;
  1745. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1746. //ASSERT( DeviceRemovePending == pDeviceContext->DeviceRemoveState );
  1747. pDeviceContext->DeviceRemoveState = DeviceAdded;
  1748. //
  1749. // allow creates if in D0
  1750. //
  1751. if( NT_SUCCESS(CheckCurrentPowerState(pDeviceObject)) )
  1752. {
  1753. pDeviceContext->PendCreates = FALSE;
  1754. //
  1755. // Pull any pended irps off the pended irp list and
  1756. // pass them back to PcDispatchIrp
  1757. //
  1758. CompletePendedIrps( pDeviceObject,
  1759. pDeviceContext,
  1760. EMPTY_QUEUE_AND_PROCESS );
  1761. }
  1762. // forward the irp
  1763. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1764. ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
  1765. break;
  1766. case IRP_MN_SURPRISE_REMOVAL:
  1767. //
  1768. // Acquire the device
  1769. //
  1770. AcquireDevice(pDeviceContext);
  1771. pDeviceContext->DeviceRemoveState = DeviceSurpriseRemoved;
  1772. //
  1773. // Release the device
  1774. //
  1775. ReleaseDevice(pDeviceContext);
  1776. //
  1777. // Fail any pended irps.
  1778. //
  1779. CompletePendedIrps( pDeviceObject,
  1780. pDeviceContext,
  1781. EMPTY_QUEUE_AND_FAIL );
  1782. if (pDeviceContext->DeviceStopState != DeviceStopped)
  1783. {
  1784. PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
  1785. }
  1786. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1787. ntStatus = ForwardIrpAsynchronous( pDeviceContext, pIrp );
  1788. break;
  1789. case IRP_MN_REMOVE_DEVICE:
  1790. //
  1791. // Perform stop if required.
  1792. //
  1793. if (pDeviceContext->DeviceStopState != DeviceStopped)
  1794. {
  1795. _DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp remove received in started state"));
  1796. PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
  1797. }
  1798. //
  1799. // Fail any pended irps.
  1800. //
  1801. CompletePendedIrps( pDeviceObject,
  1802. pDeviceContext,
  1803. EMPTY_QUEUE_AND_FAIL );
  1804. //
  1805. // Free device header, must be done before forwarding irp
  1806. //
  1807. if( pDeviceContext->pDeviceHeader )
  1808. {
  1809. KsFreeDeviceHeader(pDeviceContext->pDeviceHeader);
  1810. }
  1811. //
  1812. // Forward the request.
  1813. //
  1814. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1815. ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
  1816. //
  1817. // Remove the device.
  1818. //
  1819. PnpRemoveDevice(pDeviceObject);
  1820. break;
  1821. case IRP_MN_QUERY_CAPABILITIES:
  1822. //
  1823. // Fill out power management / ACPI stuff
  1824. // for this device.
  1825. //
  1826. ntStatus = GetDeviceACPIInfo( pIrp, pDeviceObject );
  1827. break;
  1828. case IRP_MN_READ_CONFIG:
  1829. case IRP_MN_WRITE_CONFIG:
  1830. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1831. case IRP_MN_QUERY_INTERFACE:
  1832. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  1833. //
  1834. // TODO: Make sure functions listed below are ok left unhandled.
  1835. //
  1836. case IRP_MN_QUERY_RESOURCES:
  1837. case IRP_MN_QUERY_DEVICE_TEXT:
  1838. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  1839. case IRP_MN_EJECT:
  1840. case IRP_MN_SET_LOCK:
  1841. case IRP_MN_QUERY_ID:
  1842. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  1843. case IRP_MN_QUERY_BUS_INFORMATION:
  1844. // case IRP_MN_PAGING_NOTIFICATION:
  1845. default:
  1846. ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
  1847. break;
  1848. }
  1849. return ntStatus;
  1850. }
  1851. /*****************************************************************************
  1852. * SubdeviceIndex()
  1853. *****************************************************************************
  1854. * Returns the index of a subdevice in the create items list or ULONG(-1) if
  1855. * not found.
  1856. */
  1857. ULONG
  1858. SubdeviceIndex
  1859. (
  1860. IN PDEVICE_OBJECT DeviceObject,
  1861. IN PSUBDEVICE Subdevice
  1862. )
  1863. {
  1864. ASSERT(DeviceObject);
  1865. ASSERT(Subdevice);
  1866. PDEVICE_CONTEXT pDeviceContext =
  1867. PDEVICE_CONTEXT(DeviceObject->DeviceExtension);
  1868. ASSERT(pDeviceContext);
  1869. PKSOBJECT_CREATE_ITEM createItem =
  1870. pDeviceContext->CreateItems;
  1871. for
  1872. (
  1873. ULONG index = 0;
  1874. index < pDeviceContext->MaxObjects;
  1875. index++, createItem++
  1876. )
  1877. {
  1878. if (PSUBDEVICE(createItem->Context) == Subdevice)
  1879. {
  1880. break;
  1881. }
  1882. }
  1883. if (index == pDeviceContext->MaxObjects)
  1884. {
  1885. index = ULONG(-1);
  1886. }
  1887. return index;
  1888. }
  1889. /*****************************************************************************
  1890. * PcRegisterSubdevice()
  1891. *****************************************************************************
  1892. * Registers a subdevice.
  1893. */
  1894. PORTCLASSAPI
  1895. NTSTATUS
  1896. NTAPI
  1897. PcRegisterSubdevice
  1898. (
  1899. IN PDEVICE_OBJECT DeviceObject,
  1900. IN PWCHAR Name,
  1901. IN PUNKNOWN Unknown
  1902. )
  1903. {
  1904. PAGED_CODE();
  1905. ASSERT(DeviceObject);
  1906. ASSERT(Name);
  1907. ASSERT(Unknown);
  1908. _DbgPrintF(DEBUGLVL_VERBOSE,("PcRegisterSubdevice %S",Name));
  1909. //
  1910. // Validate Parameters.
  1911. //
  1912. if (NULL == DeviceObject ||
  1913. NULL == Name ||
  1914. NULL == Unknown)
  1915. {
  1916. _DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterSubDevice : Invalid Parameter."));
  1917. return STATUS_INVALID_PARAMETER;
  1918. }
  1919. PSUBDEVICE pSubdevice;
  1920. NTSTATUS ntStatus =
  1921. Unknown->QueryInterface
  1922. (
  1923. IID_ISubdevice,
  1924. (PVOID *) &pSubdevice
  1925. );
  1926. if (NT_SUCCESS(ntStatus))
  1927. {
  1928. ntStatus =
  1929. AddIrpTargetFactoryToDevice
  1930. (
  1931. DeviceObject,
  1932. pSubdevice,
  1933. Name,
  1934. NULL // TODO: Security.
  1935. );
  1936. const SUBDEVICE_DESCRIPTOR *pSubdeviceDescriptor;
  1937. if (NT_SUCCESS(ntStatus))
  1938. {
  1939. ntStatus = pSubdevice->GetDescriptor(&pSubdeviceDescriptor);
  1940. }
  1941. else
  1942. {
  1943. _DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice AddIrpTargetFactoryToDevice failed (0x%08x)",ntStatus));
  1944. }
  1945. if (NT_SUCCESS(ntStatus) && pSubdeviceDescriptor->Topology->CategoriesCount)
  1946. {
  1947. PDEVICE_CONTEXT pDeviceContext =
  1948. PDEVICE_CONTEXT(DeviceObject->DeviceExtension);
  1949. ULONG index = SubdeviceIndex(DeviceObject,pSubdevice);
  1950. ASSERT(pSubdeviceDescriptor->Topology->Categories);
  1951. ASSERT(pDeviceContext);
  1952. UNICODE_STRING referenceString;
  1953. RtlInitUnicodeString(&referenceString,Name);
  1954. const GUID *pGuidCategories =
  1955. pSubdeviceDescriptor->Topology->Categories;
  1956. for
  1957. ( ULONG ul = pSubdeviceDescriptor->Topology->CategoriesCount
  1958. ; ul--
  1959. ; pGuidCategories++
  1960. )
  1961. {
  1962. UNICODE_STRING linkName;
  1963. if (pDeviceContext->AllowRegisterDeviceInterface)
  1964. {
  1965. ntStatus
  1966. = IoRegisterDeviceInterface
  1967. (
  1968. pDeviceContext->PhysicalDeviceObject,
  1969. pGuidCategories,
  1970. &referenceString,
  1971. &linkName
  1972. );
  1973. if (NT_SUCCESS(ntStatus))
  1974. {
  1975. ntStatus =
  1976. IoSetDeviceInterfaceState
  1977. (
  1978. &linkName,
  1979. TRUE
  1980. );
  1981. if (NT_SUCCESS(ntStatus))
  1982. {
  1983. _DbgPrintF(DEBUGLVL_VERBOSE,("PcRegisterSubdevice device interface %S set to state TRUE",linkName.Buffer));
  1984. }
  1985. else
  1986. {
  1987. _DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice IoSetDeviceInterfaceState failed (0x%08x)",ntStatus));
  1988. }
  1989. }
  1990. else
  1991. {
  1992. _DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice IoRegisterDeviceInterface failed (0x%08x)",ntStatus));
  1993. }
  1994. }
  1995. else
  1996. {
  1997. linkName.Length = wcslen(Name) * sizeof(WCHAR);
  1998. linkName.MaximumLength = linkName.Length + sizeof(UNICODE_NULL);
  1999. linkName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, linkName.MaximumLength,'NLcP'); // 'PcLN'
  2000. if (!linkName.Buffer)
  2001. {
  2002. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2003. }
  2004. else
  2005. {
  2006. wcscpy(linkName.Buffer,Name);
  2007. }
  2008. }
  2009. if (NT_SUCCESS(ntStatus))
  2010. {
  2011. //
  2012. // Save the first symbolic link name in the table.
  2013. //
  2014. if (! pDeviceContext->SymbolicLinkNames[index].Buffer)
  2015. {
  2016. pDeviceContext->SymbolicLinkNames[index] = linkName;
  2017. }
  2018. //
  2019. // Save the interface in a list for cleanup.
  2020. //
  2021. PDEVICEINTERFACE pDeviceInterface = new(PagedPool,'iDcP') DEVICEINTERFACE;
  2022. if (pDeviceInterface)
  2023. {
  2024. pDeviceInterface->Interface = *pGuidCategories;
  2025. pDeviceInterface->SymbolicLinkName = linkName;
  2026. pDeviceInterface->Subdevice = pSubdevice;
  2027. InsertTailList
  2028. (
  2029. &pDeviceContext->DeviceInterfaceList,
  2030. &pDeviceInterface->ListEntry
  2031. );
  2032. }
  2033. else
  2034. {
  2035. _DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice failed to allocate device interface structure for later cleanup"));
  2036. RtlFreeUnicodeString(&linkName);
  2037. }
  2038. }
  2039. }
  2040. }
  2041. pSubdevice->Release();
  2042. }
  2043. else
  2044. {
  2045. _DbgPrintF(DEBUGLVL_TERSE,("QI for IID_ISubdevice failed on UNKNOWN 0x%08x",pSubdevice));
  2046. }
  2047. return ntStatus;
  2048. }
  2049. /*****************************************************************************
  2050. * RegisterPhysicalConnection_()
  2051. *****************************************************************************
  2052. * Registers a physical connection between subdevices or external devices.
  2053. */
  2054. static
  2055. NTSTATUS
  2056. RegisterPhysicalConnection_
  2057. (
  2058. IN PDEVICE_OBJECT pDeviceObject,
  2059. IN PUNKNOWN pUnknownFrom OPTIONAL,
  2060. IN PUNICODE_STRING pUnicodeStringFrom OPTIONAL,
  2061. IN ULONG ulFromPin,
  2062. IN PUNKNOWN pUnknownTo OPTIONAL,
  2063. IN PUNICODE_STRING pUnicodeStringTo OPTIONAL,
  2064. IN ULONG ulToPin
  2065. )
  2066. {
  2067. PAGED_CODE();
  2068. ASSERT(pDeviceObject);
  2069. ASSERT(pUnknownFrom || pUnicodeStringFrom);
  2070. ASSERT(pUnknownTo || pUnicodeStringTo);
  2071. ASSERT(! (pUnknownFrom && pUnicodeStringFrom));
  2072. ASSERT(! (pUnknownTo && pUnicodeStringTo));
  2073. PDEVICE_CONTEXT pDeviceContext =
  2074. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  2075. ASSERT(pDeviceContext);
  2076. PSUBDEVICE pSubdeviceFrom = NULL;
  2077. PSUBDEVICE pSubdeviceTo = NULL;
  2078. NTSTATUS ntStatus = STATUS_SUCCESS;
  2079. if (pUnknownFrom)
  2080. {
  2081. ntStatus =
  2082. pUnknownFrom->QueryInterface
  2083. (
  2084. IID_ISubdevice,
  2085. (PVOID *) &pSubdeviceFrom
  2086. );
  2087. }
  2088. else
  2089. {
  2090. ntStatus =
  2091. DupUnicodeString
  2092. (
  2093. &pUnicodeStringFrom,
  2094. pUnicodeStringFrom
  2095. );
  2096. }
  2097. if (NT_SUCCESS(ntStatus))
  2098. {
  2099. if (pUnknownTo)
  2100. {
  2101. ntStatus =
  2102. pUnknownTo->QueryInterface
  2103. (
  2104. IID_ISubdevice,
  2105. (PVOID *) &pSubdeviceTo
  2106. );
  2107. }
  2108. else
  2109. {
  2110. ntStatus =
  2111. DupUnicodeString
  2112. (
  2113. &pUnicodeStringTo,
  2114. pUnicodeStringTo
  2115. );
  2116. }
  2117. }
  2118. else
  2119. {
  2120. pUnicodeStringTo = NULL;
  2121. }
  2122. if (NT_SUCCESS(ntStatus))
  2123. {
  2124. PPHYSICALCONNECTION pPhysicalConnection =
  2125. new(PagedPool,'cPcP') PHYSICALCONNECTION;
  2126. if (pPhysicalConnection)
  2127. {
  2128. pPhysicalConnection->FromSubdevice = pSubdeviceFrom;
  2129. pPhysicalConnection->FromString = pUnicodeStringFrom;
  2130. pPhysicalConnection->FromPin = ulFromPin;
  2131. pPhysicalConnection->ToSubdevice = pSubdeviceTo;
  2132. pPhysicalConnection->ToString = pUnicodeStringTo;
  2133. pPhysicalConnection->ToPin = ulToPin;
  2134. if (pPhysicalConnection->FromSubdevice)
  2135. {
  2136. pPhysicalConnection->FromSubdevice->AddRef();
  2137. }
  2138. if (pPhysicalConnection->ToSubdevice)
  2139. {
  2140. pPhysicalConnection->ToSubdevice->AddRef();
  2141. }
  2142. //
  2143. // So they don't get deleted.
  2144. //
  2145. pUnicodeStringFrom = NULL;
  2146. pUnicodeStringTo = NULL;
  2147. InsertTailList
  2148. (
  2149. &pDeviceContext->PhysicalConnectionList,
  2150. &pPhysicalConnection->ListEntry
  2151. );
  2152. }
  2153. else
  2154. {
  2155. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2156. }
  2157. }
  2158. if (pSubdeviceFrom)
  2159. {
  2160. pSubdeviceFrom->Release();
  2161. }
  2162. if (pSubdeviceTo)
  2163. {
  2164. pSubdeviceTo->Release();
  2165. }
  2166. if (pUnicodeStringFrom)
  2167. {
  2168. DelUnicodeString(pUnicodeStringFrom);
  2169. }
  2170. if (pUnicodeStringTo)
  2171. {
  2172. DelUnicodeString(pUnicodeStringTo);
  2173. }
  2174. return ntStatus;
  2175. }
  2176. /*****************************************************************************
  2177. * PcRegisterPhysicalConnection()
  2178. *****************************************************************************
  2179. * Registers a physical connection between subdevices.
  2180. */
  2181. PORTCLASSAPI
  2182. NTSTATUS
  2183. NTAPI
  2184. PcRegisterPhysicalConnection
  2185. (
  2186. IN PDEVICE_OBJECT pDeviceObject,
  2187. IN PUNKNOWN pUnknownFrom,
  2188. IN ULONG ulFromPin,
  2189. IN PUNKNOWN pUnknownTo,
  2190. IN ULONG ulToPin
  2191. )
  2192. {
  2193. PAGED_CODE();
  2194. ASSERT(pDeviceObject);
  2195. ASSERT(pUnknownFrom);
  2196. ASSERT(pUnknownTo);
  2197. //
  2198. // Validate Parameters.
  2199. //
  2200. if (NULL == pDeviceObject ||
  2201. NULL == pUnknownFrom ||
  2202. NULL == pUnknownTo)
  2203. {
  2204. _DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterPhysicalConnection : Invalid Parameter."));
  2205. return STATUS_INVALID_PARAMETER;
  2206. }
  2207. return
  2208. RegisterPhysicalConnection_
  2209. (
  2210. pDeviceObject,
  2211. pUnknownFrom,
  2212. NULL,
  2213. ulFromPin,
  2214. pUnknownTo,
  2215. NULL,
  2216. ulToPin
  2217. );
  2218. }
  2219. /*****************************************************************************
  2220. * PcRegisterPhysicalConnectionToExternal()
  2221. *****************************************************************************
  2222. * Registers a physical connection from a subdevice to an external device.
  2223. */
  2224. PORTCLASSAPI
  2225. NTSTATUS
  2226. NTAPI
  2227. PcRegisterPhysicalConnectionToExternal
  2228. (
  2229. IN PDEVICE_OBJECT pDeviceObject,
  2230. IN PUNKNOWN pUnknownFrom,
  2231. IN ULONG ulFromPin,
  2232. IN PUNICODE_STRING pUnicodeStringTo,
  2233. IN ULONG ulToPin
  2234. )
  2235. {
  2236. PAGED_CODE();
  2237. ASSERT(pDeviceObject);
  2238. ASSERT(pUnknownFrom);
  2239. ASSERT(pUnicodeStringTo);
  2240. //
  2241. // Validate Parameters.
  2242. //
  2243. if (NULL == pDeviceObject ||
  2244. NULL == pUnknownFrom ||
  2245. NULL == pUnicodeStringTo)
  2246. {
  2247. _DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterPhysicalConnectionToExternal : Invalid Parameter."));
  2248. return STATUS_INVALID_PARAMETER;
  2249. }
  2250. return
  2251. RegisterPhysicalConnection_
  2252. (
  2253. pDeviceObject,
  2254. pUnknownFrom,
  2255. NULL,
  2256. ulFromPin,
  2257. NULL,
  2258. pUnicodeStringTo,
  2259. ulToPin
  2260. );
  2261. }
  2262. /*****************************************************************************
  2263. * PcRegisterPhysicalConnectionFromExternal()
  2264. *****************************************************************************
  2265. * Registers a physical connection to a subdevice from an external device.
  2266. */
  2267. PORTCLASSAPI
  2268. NTSTATUS
  2269. NTAPI
  2270. PcRegisterPhysicalConnectionFromExternal
  2271. (
  2272. IN PDEVICE_OBJECT pDeviceObject,
  2273. IN PUNICODE_STRING pUnicodeStringFrom,
  2274. IN ULONG ulFromPin,
  2275. IN PUNKNOWN pUnknownTo,
  2276. IN ULONG ulToPin
  2277. )
  2278. {
  2279. PAGED_CODE();
  2280. ASSERT(pDeviceObject);
  2281. ASSERT(pUnicodeStringFrom);
  2282. ASSERT(pUnknownTo);
  2283. //
  2284. // Validate Parameters.
  2285. //
  2286. if (NULL == pDeviceObject ||
  2287. NULL == pUnicodeStringFrom ||
  2288. NULL == pUnknownTo)
  2289. {
  2290. _DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterPhysicalConnectionFromExternal : Invalid Parameter."));
  2291. return STATUS_INVALID_PARAMETER;
  2292. }
  2293. return
  2294. RegisterPhysicalConnection_
  2295. (
  2296. pDeviceObject,
  2297. NULL,
  2298. pUnicodeStringFrom,
  2299. ulFromPin,
  2300. pUnknownTo,
  2301. NULL,
  2302. ulToPin
  2303. );
  2304. }
  2305. #pragma code_seg()