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.

877 lines
30 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. device.c
  5. Abstract
  6. Resource management routines for devices and collections
  7. Author:
  8. ervinp
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, HidpStartDevice)
  16. #pragma alloc_text(PAGE, HidpStartCollectionPDO)
  17. #pragma alloc_text(PAGE, AllocDeviceResources)
  18. #pragma alloc_text(PAGE, FreeDeviceResources)
  19. #pragma alloc_text(PAGE, AllocCollectionResources)
  20. #pragma alloc_text(PAGE, FreeCollectionResources)
  21. #pragma alloc_text(PAGE, InitializeCollection)
  22. #pragma alloc_text(PAGE, HidpCleanUpFdo)
  23. #pragma alloc_text(PAGE, HidpRemoveDevice)
  24. #pragma alloc_text(PAGE, HidpRemoveCollection)
  25. #endif
  26. /*
  27. ********************************************************************************
  28. * AllocDeviceResources
  29. ********************************************************************************
  30. *
  31. *
  32. */
  33. NTSTATUS AllocDeviceResources(FDO_EXTENSION *fdoExt)
  34. {
  35. ULONG numCollections;
  36. NTSTATUS status = STATUS_SUCCESS;
  37. PAGED_CODE();
  38. /*
  39. * This will allocate fdoExt->rawReportDescription
  40. */
  41. status = HidpGetDeviceDescriptor(fdoExt);
  42. if (NT_SUCCESS(status)){
  43. /*
  44. * Ask HIDPARSE to fill in the HIDP_DEVICE_DESC for this device.
  45. */
  46. status = HidP_GetCollectionDescription(
  47. fdoExt->rawReportDescription,
  48. fdoExt->rawReportDescriptionLength,
  49. NonPagedPool,
  50. &fdoExt->deviceDesc);
  51. if (NT_SUCCESS(status)){
  52. fdoExt->devDescInitialized = TRUE;
  53. numCollections = fdoExt->deviceDesc.CollectionDescLength;
  54. ASSERT(numCollections);
  55. fdoExt->classCollectionArray = ALLOCATEPOOL(NonPagedPool, numCollections*sizeof(HIDCLASS_COLLECTION));
  56. if (!fdoExt->classCollectionArray){
  57. fdoExt->classCollectionArray = BAD_POINTER;
  58. status = STATUS_INSUFFICIENT_RESOURCES;
  59. } else {
  60. RtlZeroMemory(fdoExt->classCollectionArray, numCollections*sizeof(HIDCLASS_COLLECTION));
  61. }
  62. }
  63. }
  64. else {
  65. fdoExt->rawReportDescription = BAD_POINTER;
  66. }
  67. DBGSUCCESS(status, FALSE)
  68. return status;
  69. }
  70. /*
  71. ********************************************************************************
  72. * FreeDeviceResources
  73. ********************************************************************************
  74. *
  75. *
  76. */
  77. VOID FreeDeviceResources(FDO_EXTENSION *fdoExt)
  78. {
  79. ULONG i;
  80. PAGED_CODE();
  81. for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++) {
  82. FreeCollectionResources(fdoExt, fdoExt->classCollectionArray[i].CollectionNumber);
  83. }
  84. /*
  85. * Free the stuff returned by HIDPARSE's HidP_GetCollectionDescription.
  86. */
  87. if (fdoExt->devDescInitialized){
  88. HidP_FreeCollectionDescription(&fdoExt->deviceDesc);
  89. #if DBG
  90. fdoExt->deviceDesc.CollectionDesc = BAD_POINTER;
  91. fdoExt->deviceDesc.ReportIDs = BAD_POINTER;
  92. #endif
  93. }
  94. fdoExt->deviceDesc.CollectionDescLength = 0;
  95. /*
  96. * Free the raw report descriptor allocated during START_DEVICE by HidpGetDeviceDescriptor().
  97. */
  98. if (ISPTR(fdoExt->rawReportDescription)){
  99. ExFreePool(fdoExt->rawReportDescription);
  100. }
  101. fdoExt->rawReportDescription = BAD_POINTER;
  102. if (ISPTR(fdoExt->classCollectionArray)){
  103. ExFreePool(fdoExt->classCollectionArray);
  104. }
  105. fdoExt->classCollectionArray = BAD_POINTER;
  106. }
  107. /*
  108. ********************************************************************************
  109. * AllocCollectionResources
  110. ********************************************************************************
  111. *
  112. *
  113. */
  114. NTSTATUS AllocCollectionResources(FDO_EXTENSION *fdoExt, ULONG collectionNum)
  115. {
  116. PHIDCLASS_COLLECTION collection;
  117. NTSTATUS status = STATUS_SUCCESS;
  118. PAGED_CODE();
  119. collection = GetHidclassCollection(fdoExt, collectionNum);
  120. if (collection){
  121. ULONG descriptorLen;
  122. descriptorLen = collection->hidCollectionInfo.DescriptorSize;
  123. if (descriptorLen){
  124. collection->phidDescriptor = ALLOCATEPOOL(NonPagedPool, descriptorLen);
  125. if (collection->phidDescriptor){
  126. status = HidpGetCollectionDescriptor(
  127. fdoExt,
  128. collection->CollectionNumber,
  129. collection->phidDescriptor,
  130. &descriptorLen);
  131. }
  132. else {
  133. collection->phidDescriptor = BAD_POINTER;
  134. status = STATUS_INSUFFICIENT_RESOURCES;
  135. }
  136. if (NT_SUCCESS(status)){
  137. ULONG i = collection->CollectionIndex;
  138. ULONG inputLength;
  139. ASSERT(fdoExt->devDescInitialized);
  140. inputLength = fdoExt->deviceDesc.CollectionDesc[i].InputLength;
  141. if (inputLength){
  142. if (collection->hidCollectionInfo.Polled){
  143. collection->cookedInterruptReportBuf = BAD_POINTER;
  144. }
  145. else {
  146. collection->cookedInterruptReportBuf = ALLOCATEPOOL(NonPagedPool, inputLength);
  147. if (!collection->cookedInterruptReportBuf){
  148. status = STATUS_INSUFFICIENT_RESOURCES;
  149. }
  150. }
  151. fdoExt->isOutputOnlyDevice = FALSE;
  152. }
  153. else {
  154. /*
  155. * This is an output-only device (e.g. USB monitor)
  156. */
  157. DBGINFO(("Zero input length -> output-only device."))
  158. collection->cookedInterruptReportBuf = BAD_POINTER;
  159. }
  160. }
  161. }
  162. else {
  163. ASSERT(descriptorLen > 0);
  164. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  165. }
  166. }
  167. else {
  168. status = STATUS_DEVICE_DATA_ERROR;
  169. }
  170. DBGSUCCESS(status, TRUE)
  171. return status;
  172. }
  173. /*
  174. ********************************************************************************
  175. * FreeCollectionResources
  176. ********************************************************************************
  177. *
  178. *
  179. */
  180. VOID FreeCollectionResources(FDO_EXTENSION *fdoExt, ULONG collectionNum)
  181. {
  182. PHIDCLASS_COLLECTION collection;
  183. PAGED_CODE();
  184. collection = GetHidclassCollection(fdoExt, collectionNum);
  185. if (collection){
  186. if (collection->hidCollectionInfo.Polled){
  187. if (ISPTR(collection->savedPolledReportBuf)){
  188. ExFreePool(collection->savedPolledReportBuf);
  189. }
  190. collection->savedPolledReportBuf = BAD_POINTER;
  191. }
  192. else {
  193. if (ISPTR(collection->cookedInterruptReportBuf)){
  194. ExFreePool(collection->cookedInterruptReportBuf);
  195. }
  196. else {
  197. // this is an output-only collection
  198. }
  199. }
  200. collection->cookedInterruptReportBuf = BAD_POINTER;
  201. if (ISPTR(collection->phidDescriptor)){
  202. ExFreePool(collection->phidDescriptor);
  203. }
  204. collection->phidDescriptor = BAD_POINTER;
  205. }
  206. else {
  207. TRAP;
  208. }
  209. }
  210. /*
  211. ********************************************************************************
  212. * InitializeCollection
  213. ********************************************************************************
  214. *
  215. *
  216. */
  217. NTSTATUS InitializeCollection(FDO_EXTENSION *fdoExt, ULONG collectionIndex)
  218. {
  219. PHIDCLASS_COLLECTION collection;
  220. ULONG descriptorBufLen;
  221. NTSTATUS status = STATUS_SUCCESS;
  222. PAGED_CODE();
  223. ASSERT(ISPTR(fdoExt->classCollectionArray));
  224. collection = &fdoExt->classCollectionArray[collectionIndex];
  225. RtlZeroMemory(collection, sizeof(HIDCLASS_COLLECTION));
  226. ASSERT(fdoExt->devDescInitialized);
  227. collection->CollectionNumber = fdoExt->deviceDesc.CollectionDesc[collectionIndex].CollectionNumber;
  228. collection->CollectionIndex = collectionIndex;
  229. InitializeListHead(&collection->FileExtensionList);
  230. KeInitializeSpinLock(&collection->FileExtensionListSpinLock);
  231. KeInitializeSpinLock(&collection->powerEventSpinLock);
  232. KeInitializeSpinLock(&collection->secureReadLock);
  233. collection->secureReadMode = 0;
  234. descriptorBufLen = sizeof(HID_COLLECTION_INFORMATION);
  235. status = HidpGetCollectionInformation( fdoExt,
  236. collection->CollectionNumber,
  237. &collection->hidCollectionInfo,
  238. &descriptorBufLen);
  239. DBGSUCCESS(status, TRUE)
  240. return status;
  241. }
  242. void
  243. HidpGetRemoteWakeEnableState(
  244. PDO_EXTENSION *pdoExt
  245. )
  246. {
  247. HANDLE hKey;
  248. NTSTATUS status;
  249. ULONG tmp;
  250. BOOLEAN wwEnableFound;
  251. hKey = NULL;
  252. wwEnableFound = FALSE;
  253. status = IoOpenDeviceRegistryKey (pdoExt->pdo,
  254. PLUGPLAY_REGKEY_DEVICE,
  255. STANDARD_RIGHTS_ALL,
  256. &hKey);
  257. if (NT_SUCCESS (status)) {
  258. UNICODE_STRING valueName;
  259. ULONG length;
  260. ULONG value = 0;
  261. PKEY_VALUE_FULL_INFORMATION fullInfo;
  262. PAGED_CODE();
  263. RtlInitUnicodeString (&valueName, HIDCLASS_REMOTE_WAKE_ENABLE);
  264. length = sizeof (KEY_VALUE_FULL_INFORMATION)
  265. + valueName.MaximumLength
  266. + sizeof(value);
  267. fullInfo = ExAllocatePool (PagedPool, length);
  268. if (fullInfo) {
  269. status = ZwQueryValueKey (hKey,
  270. &valueName,
  271. KeyValueFullInformation,
  272. fullInfo,
  273. length,
  274. &length);
  275. if (NT_SUCCESS (status)) {
  276. DBGASSERT (sizeof(value) == fullInfo->DataLength,
  277. ("Value data wrong length for REmote wake reg value."),
  278. TRUE);
  279. RtlCopyMemory (&value,
  280. ((PUCHAR) fullInfo) + fullInfo->DataOffset,
  281. fullInfo->DataLength);
  282. pdoExt->remoteWakeEnabled = (value ? TRUE : FALSE);
  283. }
  284. ExFreePool (fullInfo);
  285. }
  286. ZwClose (hKey);
  287. hKey = NULL;
  288. }
  289. }
  290. WMIGUIDREGINFO HidClassWmiGuidList =
  291. {
  292. &GUID_POWER_DEVICE_WAKE_ENABLE,
  293. 1,
  294. 0 // wait wake
  295. };
  296. WMIGUIDREGINFO HidClassFdoWmiGuidList =
  297. {
  298. &GUID_POWER_DEVICE_ENABLE,
  299. 1,
  300. 0
  301. };
  302. /*
  303. ********************************************************************************
  304. * HidpStartCollectionPDO
  305. ********************************************************************************
  306. *
  307. *
  308. */
  309. NTSTATUS HidpStartCollectionPDO(FDO_EXTENSION *fdoExt, PDO_EXTENSION *pdoExt, PIRP Irp)
  310. {
  311. NTSTATUS status = STATUS_SUCCESS;
  312. PAGED_CODE();
  313. /*
  314. * Initialize the collection only if it's not already initialized.
  315. * This is so we don't destroy the FileExtensionList after a STOP/START.
  316. */
  317. if (pdoExt->state == COLLECTION_STATE_UNINITIALIZED){
  318. pdoExt->state = COLLECTION_STATE_INITIALIZED;
  319. }
  320. if (NT_SUCCESS(status)){
  321. PHIDCLASS_COLLECTION collection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  322. if (collection){
  323. /*
  324. * If all collection PDOs for this device FDO are initialized,
  325. * figure out the maximum report size and finish starting the device.
  326. */
  327. if (AnyClientPDOsInitialized(fdoExt, TRUE)){
  328. DBGSTATE(fdoExt->state, DEVICE_STATE_START_SUCCESS, FALSE)
  329. /*
  330. * If this is a polled collection,
  331. * start the background polling loop FOR EACH COLLECTION.
  332. * Otherwise, if it's an ordinary interrupt collection,
  333. * start the ping-pong IRPs for it.
  334. */
  335. if (collection->hidCollectionInfo.Polled){
  336. if (HidpSetMaxReportSize(fdoExt)){
  337. ULONG i;
  338. for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++){
  339. PHIDCLASS_COLLECTION ctn;
  340. ctn = &fdoExt->classCollectionArray[i];
  341. /*
  342. * If one of the collections is polled, they
  343. * should ALL be polled.
  344. */
  345. ASSERT(ctn->hidCollectionInfo.Polled);
  346. ctn->PollInterval_msec = DEFAULT_POLL_INTERVAL_MSEC;
  347. /*
  348. * Allocate the buffer for saving the polled device's
  349. * last report. Allocate one more byte than the max
  350. * report size for the device in case we have to
  351. * prepend a report id byte.
  352. */
  353. ctn->savedPolledReportBuf = ALLOCATEPOOL(NonPagedPool, fdoExt->maxReportSize+1);
  354. if (ctn->savedPolledReportBuf){
  355. ctn->polledDataIsStale = TRUE;
  356. StartPollingLoop(fdoExt, ctn, TRUE);
  357. status = STATUS_SUCCESS;
  358. }
  359. else {
  360. ASSERT(ctn->savedPolledReportBuf);
  361. status = STATUS_INSUFFICIENT_RESOURCES;
  362. }
  363. }
  364. }
  365. }
  366. else if (fdoExt->isOutputOnlyDevice){
  367. /*
  368. * Don't start ping-pong IRPs.
  369. */
  370. }
  371. else {
  372. status = HidpStartAllPingPongs(fdoExt);
  373. }
  374. }
  375. if (NT_SUCCESS(status)) {
  376. pdoExt->state = COLLECTION_STATE_RUNNING;
  377. #if DBG
  378. collection->Signature = HIDCLASS_COLLECTION_SIG;
  379. #endif
  380. /*
  381. * Create the 'file-name' used by clients to open this device.
  382. */
  383. if (!pdoExt->MouseOrKeyboard) {
  384. HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, TRUE, pdoExt->pdo);
  385. }
  386. if (!pdoExt->MouseOrKeyboard &&
  387. WAITWAKE_SUPPORTED(fdoExt)) {
  388. //
  389. // register for the wait wake guid as well
  390. //
  391. pdoExt->WmiLibInfo.GuidCount = sizeof (HidClassWmiGuidList) /
  392. sizeof (WMIGUIDREGINFO);
  393. ASSERT (1 == pdoExt->WmiLibInfo.GuidCount);
  394. //
  395. // See if the user has enabled remote wake for the device
  396. // PRIOR to registering with WMI.
  397. //
  398. HidpGetRemoteWakeEnableState(pdoExt);
  399. pdoExt->WmiLibInfo.GuidList = &HidClassWmiGuidList;
  400. pdoExt->WmiLibInfo.QueryWmiRegInfo = HidpQueryWmiRegInfo;
  401. pdoExt->WmiLibInfo.QueryWmiDataBlock = HidpQueryWmiDataBlock;
  402. pdoExt->WmiLibInfo.SetWmiDataBlock = HidpSetWmiDataBlock;
  403. pdoExt->WmiLibInfo.SetWmiDataItem = HidpSetWmiDataItem;
  404. pdoExt->WmiLibInfo.ExecuteWmiMethod = NULL;
  405. pdoExt->WmiLibInfo.WmiFunctionControl = NULL;
  406. IoWMIRegistrationControl(pdoExt->pdo, WMIREG_ACTION_REGISTER);
  407. if (SHOULD_SEND_WAITWAKE(pdoExt)) {
  408. HidpCreateRemoteWakeIrp(pdoExt);
  409. }
  410. }
  411. if (AllClientPDOsInitialized(fdoExt, TRUE)){
  412. HidpStartIdleTimeout(fdoExt, TRUE);
  413. }
  414. }
  415. }
  416. else {
  417. status = STATUS_DEVICE_DATA_ERROR;
  418. }
  419. }
  420. DBGSUCCESS(status, FALSE)
  421. return status;
  422. }
  423. /*
  424. ********************************************************************************
  425. * HidpStartDevice
  426. ********************************************************************************
  427. *
  428. *
  429. */
  430. NTSTATUS HidpStartDevice(PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, PIRP Irp)
  431. {
  432. FDO_EXTENSION *fdoExt;
  433. enum deviceState previousState;
  434. NTSTATUS status;
  435. ULONG i;
  436. PAGED_CODE();
  437. ASSERT(!HidDeviceExtension->isClientPdo);
  438. fdoExt = &HidDeviceExtension->fdoExt;
  439. previousState = fdoExt->state;
  440. fdoExt->state = DEVICE_STATE_STARTING;
  441. /*
  442. * Get the power-state conversion table
  443. */
  444. status = HidpQueryDeviceCapabilities(
  445. HidDeviceExtension->hidExt.PhysicalDeviceObject,
  446. &fdoExt->deviceCapabilities);
  447. if (NT_SUCCESS(status)){
  448. /*
  449. * Alert the rest of the driver stack that the device is starting.
  450. */
  451. IoCopyCurrentIrpStackLocationToNext(Irp);
  452. status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
  453. if (NT_SUCCESS(status)){
  454. /*
  455. * If we're just resuming from STOP,
  456. * there's nothing else to do;
  457. * otherwise, need to call down the USB stack
  458. * for some info and allocate some resources.
  459. */
  460. if (previousState == DEVICE_STATE_INITIALIZED){
  461. status = AllocDeviceResources(fdoExt);
  462. if (NT_SUCCESS(status)){
  463. /*
  464. * Assume this is an output-only device until we start
  465. * a collection-pdo which handles inputs.
  466. * Only set fdoExt->isOutputOnlyDevice on the first start
  467. * not on a subsequent start following a stop.
  468. */
  469. fdoExt->isOutputOnlyDevice = TRUE;
  470. /*
  471. * Initialize WMI stuff
  472. */
  473. fdoExt->WmiLibInfo.GuidCount = sizeof(HidClassFdoWmiGuidList) /
  474. sizeof (WMIGUIDREGINFO);
  475. fdoExt->WmiLibInfo.GuidList = &HidClassFdoWmiGuidList;
  476. fdoExt->WmiLibInfo.QueryWmiRegInfo = HidpQueryWmiRegInfo;
  477. fdoExt->WmiLibInfo.QueryWmiDataBlock = HidpQueryWmiDataBlock;
  478. fdoExt->WmiLibInfo.SetWmiDataBlock = HidpSetWmiDataBlock;
  479. fdoExt->WmiLibInfo.SetWmiDataItem = HidpSetWmiDataItem;
  480. fdoExt->WmiLibInfo.ExecuteWmiMethod = NULL;
  481. fdoExt->WmiLibInfo.WmiFunctionControl = NULL;
  482. /*
  483. * Allocate all the collection resources before allocating
  484. * the pingpong irps, so that we can set a maximum report
  485. * size.
  486. */
  487. for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++) {
  488. // If one of these fails, we will clean up properly
  489. // in the remove routine, so there's no need to
  490. // bother cleaning up here.
  491. status = InitializeCollection(fdoExt, i);
  492. if (!NT_SUCCESS(status)){
  493. break;
  494. }
  495. status = AllocCollectionResources(fdoExt, fdoExt->deviceDesc.CollectionDesc[i].CollectionNumber);
  496. if (!NT_SUCCESS(status)){
  497. break;
  498. }
  499. }
  500. /*
  501. * We need ot allocate the pingpongs in the fdo start
  502. * routine due to race conditions introduced by selective
  503. * suspend.
  504. */
  505. if (!fdoExt->isOutputOnlyDevice &&
  506. !fdoExt->driverExt->DevicesArePolled) {
  507. status = HidpReallocPingPongIrps(fdoExt, MIN_PINGPONG_IRPS);
  508. }
  509. if (NT_SUCCESS(status)){
  510. /*
  511. * We will have to create an array of PDOs, one for each device class.
  512. * The following call will cause NTKERN to call us back with
  513. * IRP_MN_QUERY_DEVICE_RELATIONS and initialize its collection-PDOs.
  514. */
  515. IoInvalidateDeviceRelations(HidDeviceExtension->hidExt.PhysicalDeviceObject, BusRelations);
  516. }
  517. }
  518. }
  519. else if (previousState == DEVICE_STATE_STOPPED){
  520. //
  521. // Any request that comes in when we are in low power will be
  522. // dealt with at that time
  523. //
  524. DBGSTATE(fdoExt->prevState, DEVICE_STATE_START_SUCCESS, TRUE)
  525. }
  526. else {
  527. TRAP;
  528. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  529. }
  530. }
  531. }
  532. if (NT_SUCCESS(status)){
  533. fdoExt->state = DEVICE_STATE_START_SUCCESS;
  534. #if DBG
  535. {
  536. ULONG i;
  537. // Win98 doesn't have good debug extensions
  538. DBGVERBOSE(("Started fdoExt %ph with %d collections: ", fdoExt, fdoExt->deviceDesc.CollectionDescLength))
  539. for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++){
  540. DBGVERBOSE((" - collection #%d: (in=%xh,out=%xh,feature=%xh) usagePage %xh, usage %xh ",
  541. fdoExt->deviceDesc.CollectionDesc[i].CollectionNumber,
  542. fdoExt->deviceDesc.CollectionDesc[i].InputLength,
  543. fdoExt->deviceDesc.CollectionDesc[i].OutputLength,
  544. fdoExt->deviceDesc.CollectionDesc[i].FeatureLength,
  545. fdoExt->deviceDesc.CollectionDesc[i].UsagePage,
  546. fdoExt->deviceDesc.CollectionDesc[i].Usage))
  547. }
  548. }
  549. #endif
  550. }
  551. else {
  552. fdoExt->state = DEVICE_STATE_START_FAILURE;
  553. }
  554. DBGSUCCESS(status, FALSE)
  555. return status;
  556. }
  557. VOID
  558. HidpCleanUpFdo(FDO_EXTENSION *fdoExt)
  559. {
  560. PAGED_CODE();
  561. if (fdoExt->openCount == 0){
  562. /*
  563. * This is the last CLOSE on an alreay-removed device.
  564. *
  565. * Free resources and the FDO name
  566. * (wPdoName that was allocated in HidpAddDevice);
  567. *
  568. */
  569. DequeueFdoExt(fdoExt);
  570. FreeDeviceResources(fdoExt);
  571. RtlFreeUnicodeString(&fdoExt->name);
  572. IoWMIRegistrationControl(fdoExt->fdo, WMIREG_ACTION_DEREGISTER);
  573. /*
  574. * Delete the device-FDO and all collection-PDOs
  575. * Don't touch fdoExt after this.
  576. */
  577. HidpDeleteDeviceObjects(fdoExt);
  578. }
  579. }
  580. /*
  581. ********************************************************************************
  582. * HidpRemoveDevice
  583. ********************************************************************************
  584. *
  585. */
  586. NTSTATUS HidpRemoveDevice(FDO_EXTENSION *fdoExt, IN PIRP Irp)
  587. {
  588. BOOLEAN proceedWithRemove;
  589. NTSTATUS status;
  590. PIRP IdleIrp;
  591. PAGED_CODE();
  592. /*
  593. * All collection-PDOs should have been removed by now,
  594. * but we want to verify this.
  595. * Only allow removal of this device-FDO if all the
  596. * collection-PDOs are removed
  597. * (or if they never got created in the first place).
  598. */
  599. if (fdoExt->prevState == DEVICE_STATE_START_FAILURE){
  600. proceedWithRemove = TRUE;
  601. }
  602. else if (fdoExt->prevState == DEVICE_STATE_STOPPED){
  603. /*
  604. * If a device fails to initialize, it may get
  605. * STOP_DEVICE before being removed, so we want to
  606. * go ahead and remove it without calling
  607. * AllClientPDOsInitialized, which accesses some
  608. * data which may not have been initialized.
  609. * In this case we're never checking for the
  610. * case that the device was initialized successfully,
  611. * then stopped, and then removed without its
  612. * collection-PDOs being removed; but this is an
  613. * illegal case, so we'll just punt on it.
  614. */
  615. proceedWithRemove = TRUE;
  616. }
  617. else if (AllClientPDOsInitialized(fdoExt, FALSE)){
  618. proceedWithRemove = TRUE;
  619. }
  620. else {
  621. /*
  622. * This shouldn't happen -- all the collection-PDOs
  623. * should have been removed before the device-FDO.
  624. */
  625. DBGERR(("State of fdo %x state is %d",fdoExt->fdo,fdoExt->state))
  626. TRAP;
  627. proceedWithRemove = FALSE;
  628. }
  629. if (proceedWithRemove){
  630. PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension =
  631. CONTAINING_RECORD(fdoExt, HIDCLASS_DEVICE_EXTENSION, fdoExt);
  632. DBGASSERT((fdoExt->state == DEVICE_STATE_REMOVING ||
  633. fdoExt->state == DEVICE_STATE_INITIALIZED ||
  634. fdoExt->state == DEVICE_STATE_START_FAILURE),
  635. ("Device is in incorrect state: %x", fdoExt->state),
  636. TRUE)
  637. if (ISPTR(fdoExt->waitWakeIrp)){
  638. IoCancelIrp(fdoExt->waitWakeIrp);
  639. fdoExt->waitWakeIrp = BAD_POINTER;
  640. }
  641. HidpCancelIdleNotification(fdoExt, TRUE);
  642. if (ISPTR(fdoExt->idleNotificationRequest)) {
  643. IoFreeIrp(fdoExt->idleNotificationRequest);
  644. fdoExt->idleNotificationRequest = BAD_POINTER;
  645. }
  646. while (IdleIrp = DequeuePowerDelayedIrp(fdoExt)) {
  647. IdleIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  648. IoCompleteRequest(IdleIrp, IO_NO_INCREMENT);
  649. }
  650. DestroyPingPongs(fdoExt);
  651. /*
  652. * Note: THE ORDER OF THESE ACTIONS IS VERY CRITICAL
  653. */
  654. Irp->IoStatus.Status = STATUS_SUCCESS;
  655. IoSkipCurrentIrpStackLocation (Irp);
  656. status = HidpCallDriver(fdoExt->fdo, Irp);
  657. fdoExt->state = DEVICE_STATE_REMOVED;
  658. DerefDriverExt(fdoExt->driverExt->MinidriverObject);
  659. fdoExt->driverExt = BAD_POINTER;
  660. /*
  661. * After Detach we can no longer send IRPS to this device
  662. * object as it will be GONE!
  663. */
  664. IoDetachDevice(HidDeviceExtension->hidExt.NextDeviceObject);
  665. /*
  666. * If all client handles on this device have been closed,
  667. * destroy the objects and our context for it;
  668. * otherwise, we'll do this when the last client closes
  669. * their handle.
  670. *
  671. * On NT we can only get here if all our creates have been closed, so
  672. * this is unnecessary, but on Win9x, a remove can be sent with valid
  673. * opens against the stack.
  674. *
  675. * Don't touch fdoExt after this.
  676. */
  677. HidpCleanUpFdo(fdoExt);
  678. }
  679. else {
  680. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  681. }
  682. DBGSUCCESS(status, FALSE)
  683. return status;
  684. }
  685. /*
  686. ********************************************************************************
  687. * HidpRemoveCollection
  688. ********************************************************************************
  689. *
  690. */
  691. VOID HidpRemoveCollection(FDO_EXTENSION *fdoExt, PDO_EXTENSION *pdoExt, IN PIRP Irp)
  692. {
  693. PAGED_CODE();
  694. //
  695. // This pdo is no longer available as it has been removed.
  696. // It should still be returned for each Query Device Relations
  697. // IRPS to the HID bus, but it itself should respond to all
  698. // IRPS with STATUS_DELETE_PENDING.
  699. //
  700. if (pdoExt->prevState == COLLECTION_STATE_UNINITIALIZED || // for started pdos
  701. pdoExt->state == COLLECTION_STATE_UNINITIALIZED){ // For unstarted pdos
  702. pdoExt->state = COLLECTION_STATE_UNINITIALIZED;
  703. DBGVERBOSE(("HidpRemoveCollection: collection uninitialized."))
  704. }
  705. else {
  706. ULONG ctnIndx = pdoExt->collectionIndex;
  707. PHIDCLASS_COLLECTION collection = &fdoExt->classCollectionArray[ctnIndx];
  708. ULONG numReportIDs = fdoExt->deviceDesc.ReportIDsLength;
  709. PIRP remoteWakeIrp;
  710. if (!pdoExt->MouseOrKeyboard &&
  711. WAITWAKE_SUPPORTED(fdoExt)) {
  712. //
  713. // Unregister for remote wakeup.
  714. //
  715. IoWMIRegistrationControl (pdoExt->pdo, WMIREG_ACTION_DEREGISTER);
  716. }
  717. remoteWakeIrp = (PIRP)
  718. InterlockedExchangePointer(&pdoExt->remoteWakeIrp, NULL);
  719. if (remoteWakeIrp) {
  720. IoCancelIrp(remoteWakeIrp);
  721. }
  722. pdoExt->state = COLLECTION_STATE_UNINITIALIZED;
  723. /*
  724. * Destroy this collection.
  725. * This will also abort all pending reads on this collection-PDO.
  726. */
  727. HidpDestroyCollection(fdoExt, collection);
  728. }
  729. DBGVERBOSE(("HidpRemoveCollection: removed pdo %ph (refCount=%xh)", pdoExt->pdo, (ULONG)(*(((PUCHAR)pdoExt->pdo)-0x18))))
  730. }