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.

602 lines
20 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract: NULL filter driver -- boilerplate code
  6. Author:
  7. ervinp
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include <WDM.H>
  13. #include "filter.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, VA_PnP)
  16. #pragma alloc_text(PAGE, GetDeviceCapabilities)
  17. #ifdef HANDLE_DEVICE_USAGE
  18. #pragma alloc_text(PAGE, VA_DeviceUsageNotification)
  19. #endif // HANDLE_DEVICE_USAGE
  20. #endif
  21. NTSTATUS VA_PnP(struct DEVICE_EXTENSION *devExt, PIRP irp)
  22. /*++
  23. Routine Description:
  24. Dispatch routine for PnP IRPs (MajorFunction == IRP_MJ_PNP)
  25. Arguments:
  26. devExt - device extension for the targetted device object
  27. irp - IO Request Packet
  28. Return Value:
  29. NT status code
  30. --*/
  31. {
  32. PIO_STACK_LOCATION irpSp;
  33. NTSTATUS status = STATUS_SUCCESS;
  34. BOOLEAN completeIrpHere = FALSE;
  35. BOOLEAN justReturnStatus = FALSE;
  36. PAGED_CODE();
  37. irpSp = IoGetCurrentIrpStackLocation(irp);
  38. TRACE(TL_PNP_TRACE,("VA_PnP, minorFunc = %d \n", (ULONG)irpSp->MinorFunction));
  39. switch (irpSp->MinorFunction){
  40. case IRP_MN_START_DEVICE:
  41. TRACE(TL_PNP_WARNING,("START_DEVICE\n"));
  42. devExt->state = STATE_STARTING;
  43. /*
  44. * First, send the START_DEVICE irp down the stack
  45. * synchronously to start the lower stack.
  46. * We cannot do anything with our device object
  47. * before propagating the START_DEVICE this way.
  48. */
  49. IoCopyCurrentIrpStackLocationToNext(irp);
  50. status = CallNextDriverSync(devExt, irp);
  51. if (NT_SUCCESS(status)){
  52. /*
  53. * Now that the lower stack is started,
  54. * do any initialization required by this device object.
  55. */
  56. status = GetDeviceCapabilities(devExt);
  57. if (NT_SUCCESS(status)){
  58. devExt->state = STATE_STARTED;
  59. }
  60. else {
  61. devExt->state = STATE_START_FAILED;
  62. }
  63. }
  64. else {
  65. devExt->state = STATE_START_FAILED;
  66. }
  67. completeIrpHere = TRUE;
  68. break;
  69. case IRP_MN_QUERY_STOP_DEVICE:
  70. case IRP_MN_QUERY_REMOVE_DEVICE:
  71. TRACE(TL_PNP_WARNING,("QUERY_STOP_DEVICE (%d)or QUERY_REMOVE_DEVICE(%d)\n", IRP_MN_QUERY_STOP_DEVICE, IRP_MN_QUERY_REMOVE_DEVICE));
  72. #ifdef HANDLE_DEVICE_USAGE
  73. //
  74. // Need to fail these IRPs if a paging, hibernation, or crashdump
  75. // file is currently open on this device
  76. //
  77. if( devExt->pagingFileCount != 0
  78. || devExt->hibernationFileCount != 0
  79. || devExt->crashdumpFileCount != 0 )
  80. {
  81. // Fail the IRP
  82. TRACE(TL_PNP_WARNING,("Failing QUERY_(STOP,REMOVE)_DEVICE request b/c \n"
  83. "paging, hiber, or crashdump file is present on device." ));
  84. status = STATUS_UNSUCCESSFUL;
  85. completeIrpHere = TRUE;
  86. }
  87. else
  88. {
  89. // We'll just pass this IRP down the driver stack. But
  90. // first, must change the IRP's status to STATUS_SUCCESS
  91. // (default is STATUS_NOT_SUPPORTED)
  92. irp->IoStatus.Status = STATUS_SUCCESS;
  93. }
  94. #else
  95. /*
  96. * We will pass this IRP down the driver stack.
  97. * However, we need to change the default status
  98. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  99. */
  100. irp->IoStatus.Status = STATUS_SUCCESS;
  101. #endif
  102. break;
  103. case IRP_MN_STOP_DEVICE:
  104. TRACE(TL_PNP_WARNING,("STOP_DEVICE\n"));
  105. if (devExt->state == STATE_SUSPENDED){
  106. status = STATUS_DEVICE_POWER_FAILURE;
  107. completeIrpHere = TRUE;
  108. }
  109. else {
  110. /*
  111. * Only set state to STOPPED if the device was
  112. * previously started successfully.
  113. */
  114. if (devExt->state == STATE_STARTED){
  115. devExt->state = STATE_STOPPED;
  116. }
  117. }
  118. break;
  119. case IRP_MN_SURPRISE_REMOVAL: // Win2000 code base only
  120. TRACE(TL_PNP_WARNING,("SURPRISE_REMOVAL\n"));
  121. /*
  122. * We will pass this IRP down the driver stack.
  123. * However, we need to change the default status
  124. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  125. */
  126. irp->IoStatus.Status = STATUS_SUCCESS;
  127. /*
  128. * For now just set the STATE_REMOVING state so that
  129. * we don't do any more IO. We are guaranteed to get
  130. * IRP_MN_REMOVE_DEVICE soon; we'll do the rest of
  131. * the remove processing there.
  132. */
  133. devExt->state = STATE_REMOVING;
  134. /*
  135. * Clean up and make sure to cancel pending request
  136. */
  137. AVCStreamSurpriseRemoval(devExt);
  138. break;
  139. case IRP_MN_REMOVE_DEVICE:
  140. /*
  141. * Check the current state to guard against multiple
  142. * REMOVE_DEVICE IRPs.
  143. */
  144. TRACE(TL_PNP_WARNING,("REMOVE_DEVICE\n"));
  145. if (devExt->state != STATE_REMOVED){
  146. devExt->state = STATE_REMOVED;
  147. /*
  148. * Clean up and make sure to cancel pending request
  149. * Note: there is no IRP_MN_SURPRISE_REMOVAL for Win9X
  150. */
  151. AVCStreamSurpriseRemoval(devExt);
  152. /*
  153. * Send the REMOVE IRP down the stack asynchronously.
  154. * Do not synchronize sending down the REMOVE_DEVICE
  155. * IRP, because the REMOVE_DEVICE IRP must be sent
  156. * down and completed all the way back up to the sender
  157. * before we continue.
  158. */
  159. IoCopyCurrentIrpStackLocationToNext(irp);
  160. status = IoCallDriver(devExt->topDevObj, irp);
  161. justReturnStatus = TRUE;
  162. TRACE(TL_PNP_WARNING,("REMOVE_DEVICE - waiting for %d irps to complete...\n",
  163. devExt->pendingActionCount));
  164. /*
  165. * We must for all outstanding IO to complete before
  166. * completing the REMOVE_DEVICE IRP.
  167. *
  168. * First do an extra decrement on the pendingActionCount.
  169. * This will cause pendingActionCount to eventually
  170. * go to -1 once all asynchronous actions on this
  171. * device object are complete.
  172. * Then wait on the event that gets set when the
  173. * pendingActionCount actually reaches -1.
  174. */
  175. DecrementPendingActionCount(devExt);
  176. KeWaitForSingleObject( &devExt->removeEvent,
  177. Executive, // wait reason
  178. KernelMode,
  179. FALSE, // not alertable
  180. NULL ); // no timeout
  181. TRACE(TL_PNP_WARNING,("REMOVE_DEVICE - ... DONE waiting. \n"));
  182. #ifdef HANDLE_DEVICE_USAGE
  183. /*
  184. * If we locked-down certain paged code sections earlier
  185. * because of this device, then need to unlock them now
  186. * (before calling IoDeleteDevice)
  187. */
  188. if( NULL != devExt->pagingPathUnlockHandle )
  189. {
  190. TRACE(TL_PNP_WARNING,("UNLOCKing some driver code (non-pageable) (b/c paging path)\n" ));
  191. MmUnlockPagableImageSection( devExt->pagingPathUnlockHandle );
  192. devExt->pagingPathUnlockHandle = NULL;
  193. }
  194. if( NULL != devExt->initUnlockHandle )
  195. {
  196. TRACE(TL_PNP_WARNING,("UNLOCKing some driver code (non-pageable) (b/c init conditions)\n" ));
  197. MmUnlockPagableImageSection( devExt->initUnlockHandle );
  198. devExt->initUnlockHandle = NULL;
  199. }
  200. #endif // HANDLE_DEVICE_USAGE
  201. /*
  202. * Detach our device object from the lower
  203. * device object stack.
  204. */
  205. IoDetachDevice(devExt->topDevObj);
  206. /*
  207. * Delete our device object.
  208. * This will also delete the associated device extension.
  209. */
  210. IoDeleteDevice(devExt->filterDevObj);
  211. }
  212. break;
  213. #ifdef HANDLE_DEVICE_USAGE
  214. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  215. //
  216. // Make sure the Type of this UsageNotification is one that we handle
  217. //
  218. if( irpSp->Parameters.UsageNotification.Type != DeviceUsageTypePaging
  219. && irpSp->Parameters.UsageNotification.Type != DeviceUsageTypeHibernation
  220. && irpSp->Parameters.UsageNotification.Type != DeviceUsageTypeDumpFile )
  221. {
  222. break; // out of the big switch statement (and just forward this IRP)
  223. }
  224. status = VA_DeviceUsageNotification(devExt, irp);
  225. justReturnStatus = TRUE;
  226. break;
  227. #endif // HANDLE_DEVICE_USAGE
  228. #ifdef HANDLE_DEVICE_USAGE
  229. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  230. //
  231. // If a paging, hibernation, or crashdump file is currently open
  232. // on this device, must set NOT_DISABLEABLE flag in DeviceState
  233. //
  234. if( devExt->pagingFileCount != 0
  235. || devExt->hibernationFileCount != 0
  236. || devExt->crashdumpFileCount != 0 )
  237. {
  238. // Mark the device as not disableable
  239. PPNP_DEVICE_STATE pDeviceState;
  240. pDeviceState = (PPNP_DEVICE_STATE) &irp->IoStatus.Information;
  241. *pDeviceState |= PNP_DEVICE_NOT_DISABLEABLE;
  242. }
  243. //
  244. // We _did_ handle this IRP (as best we could), so set IRP's
  245. // status to STATUS_SUCCESS (default is STATUS_NOT_SUPPORTED)
  246. // before passing it down the driver stack
  247. //
  248. irp->IoStatus.Status = STATUS_SUCCESS;
  249. break;
  250. #endif // HANDLE_DEVICE_USAGE
  251. case IRP_MN_QUERY_DEVICE_RELATIONS:
  252. TRACE(TL_PNP_WARNING,("QUERY_DEVICE_RELATIONS\n"));
  253. break;
  254. default:
  255. TRACE(TL_PNP_WARNING,("Unprocessed PnP minorFunc (%d)\n", irpSp->MinorFunction));
  256. break;
  257. }
  258. if (justReturnStatus){
  259. /*
  260. * We've already sent this IRP down the stack.
  261. */
  262. TRACE(TL_PNP_WARNING,("VA_PnP: St:%x; minor:%d; Already sent down the irp.\n", status, (ULONG)irpSp->MinorFunction));
  263. }
  264. else if (completeIrpHere){
  265. TRACE(TL_PNP_WARNING,("VA_PnP: St:%x; minor:%d; Completed Status:%x\n", status, (ULONG)irpSp->MinorFunction, status));
  266. irp->IoStatus.Status = status;
  267. IoCompleteRequest(irp, IO_NO_INCREMENT);
  268. }
  269. else {
  270. TRACE(TL_PNP_WARNING,("VA_PnP: ST:%x; minor:%d; Pass down irp:%x; devObj:%x\n", status, (ULONG)irpSp->MinorFunction, irp, devExt->topDevObj));
  271. IoCopyCurrentIrpStackLocationToNext(irp);
  272. status = IoCallDriver(devExt->topDevObj, irp);
  273. }
  274. EXIT("VA_PnP",status);
  275. return status;
  276. }
  277. #ifdef HANDLE_DEVICE_USAGE
  278. NTSTATUS
  279. VA_DeviceUsageNotification(struct DEVICE_EXTENSION *devExt, PIRP irp)
  280. {
  281. PIO_STACK_LOCATION irpSp;
  282. NTSTATUS status;
  283. BOOLEAN fSetPagable = FALSE; // whether we set the PAGABLE bit
  284. /// before we passed-on this IRP
  285. PAGED_CODE();
  286. irpSp = IoGetCurrentIrpStackLocation(irp);
  287. TRACE(TL_PNP_WARNING,("DEVICE_USAGE_NOTIFICATION (Type==%d , InPath==%d)\n"
  288. , irpSp->Parameters.UsageNotification.Type
  289. , irpSp->Parameters.UsageNotification.InPath
  290. ));
  291. TRACE(TL_PNP_WARNING,(" [devExt=0x%08X fltrDevObj=0x%08X]\n", devExt, devExt->filterDevObj ));
  292. //
  293. // Wait on the paging path event (to prevent several instances of
  294. // this IRP from being processed at once)
  295. //
  296. status = KeWaitForSingleObject( &devExt->deviceUsageNotificationEvent
  297. , Executive // wait reason
  298. , KernelMode
  299. , FALSE // not alertable
  300. , NULL // no timeout
  301. );
  302. /*
  303. * IMPORTANT NOTE: When to modify our DO_POWER_PAGABLE bit depends
  304. * on whether it needs to be set or cleared. If the IRP indicates
  305. * our PAGABLE bit should be set, then we must set it _before_
  306. * forwarding the IRP down the driver stack (and possibly clear it
  307. * afterward, if lower drivers fail the IRP). But if the IRP
  308. * indicates that our PAGABLE bit should be cleared, then we must
  309. * first forward the IRP to lower drivers, and then clear our bit
  310. * only if the lower drivers return STATUS_SUCCESS.
  311. */
  312. //
  313. // If removing last paging file from this device...
  314. //
  315. if( irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging
  316. && !irpSp->Parameters.UsageNotification.InPath
  317. && devExt->pagingFileCount == 1 )
  318. {
  319. //
  320. // Set DO_POWER_PAGABLE bit (if it was set at startup).
  321. // If lower drivers fail this IRP, we'll clear it later.
  322. //
  323. TRACE(TL_PNP_WARNING,("Removing last paging file...\n" ));
  324. if( devExt->initialFlags & DO_POWER_PAGABLE )
  325. {
  326. TRACE(TL_PNP_WARNING,( "...so RE-setting PAGABLE bit\n" ));
  327. devExt->filterDevObj->Flags |= DO_POWER_PAGABLE;
  328. fSetPagable = TRUE;
  329. }
  330. else
  331. {
  332. TRACE(TL_PNP_WARNING,( "...but PAGABLE bit wasn't set initially, so not setting it now.\n" ));
  333. }
  334. }
  335. //
  336. // Forward the irp synchronously
  337. //
  338. IoCopyCurrentIrpStackLocationToNext( irp );
  339. status = CallNextDriverSync( devExt, irp );
  340. //
  341. // Now deal with the failure and success cases.
  342. //
  343. if( ! NT_SUCCESS(status) )
  344. {
  345. //
  346. // Lower drivers failed the IRP, so _undo_ any changes we
  347. // made before passing-on the IRP to those drivers.
  348. //
  349. if( fSetPagable )
  350. {
  351. TRACE(TL_PNP_WARNING,("IRP was failed, so UN-setting PAGABLE bit\n" ));
  352. devExt->filterDevObj->Flags &= ~DO_POWER_PAGABLE;
  353. }
  354. }
  355. else
  356. {
  357. //
  358. // Lower drivers returned SUCCESS, so we can do everything
  359. // that must be done in response to this IRP...
  360. //
  361. switch( irpSp->Parameters.UsageNotification.Type )
  362. {
  363. case DeviceUsageTypeHibernation:
  364. // Adjust counter
  365. IoAdjustPagingPathCount( &devExt->hibernationFileCount,
  366. irpSp->Parameters.UsageNotification.InPath );
  367. TRACE(TL_PNP_WARNING,("Num. Hibernation files is now %d\n", devExt->hibernationFileCount ));
  368. ASSERT( devExt->hibernationFileCount >= 0 );
  369. break;
  370. case DeviceUsageTypeDumpFile:
  371. // Adjust counter
  372. IoAdjustPagingPathCount( &devExt->crashdumpFileCount,
  373. irpSp->Parameters.UsageNotification.InPath );
  374. TRACE(TL_PNP_WARNING,("Num. Crashdump files is now %d\n", devExt->crashdumpFileCount ));
  375. ASSERT( devExt->crashdumpFileCount >= 0 );
  376. break;
  377. case DeviceUsageTypePaging:
  378. // Adjust counter
  379. IoAdjustPagingPathCount( &devExt->pagingFileCount,
  380. irpSp->Parameters.UsageNotification.InPath );
  381. TRACE(TL_PNP_WARNING,("Num. Paging files is now %d\n", devExt->pagingFileCount ));
  382. ASSERT( devExt->pagingFileCount >= 0 );
  383. //
  384. // If we've just switched between being pageable<->nonpageable...
  385. //
  386. if( irpSp->Parameters.UsageNotification.InPath
  387. && devExt->pagingFileCount == 1 )
  388. {
  389. //
  390. // Just added a paging file, so clear the PAGABLE
  391. // flag, and lock-down the code for all routines
  392. // that could be called at IRQL >= DISPATCH_LEVEL
  393. // (so that they're _non-pageable_).
  394. //
  395. TRACE(TL_PNP_WARNING,("Just added first paging file...\n" ));
  396. TRACE(TL_PNP_WARNING,("...so clearing PAGABLE bit\n" ));
  397. devExt->filterDevObj->Flags &= ~DO_POWER_PAGABLE;
  398. TRACE(TL_PNP_WARNING,("LOCKing some driver code (non-pageable) (b/c paging path)\n" ));
  399. devExt->pagingPathUnlockHandle = MmLockPagableCodeSection( VA_Power ); // some func that's inside the code section that we want to lock
  400. ASSERT( NULL != devExt->pagingPathUnlockHandle );
  401. }
  402. else if ( !irpSp->Parameters.UsageNotification.InPath
  403. && devExt->pagingFileCount == 0 )
  404. {
  405. //
  406. // Just removed the last paging file, but we
  407. // already set the PAGABLE flag (if necessary)
  408. // before forwarding IRP, so just remove the
  409. // _paging-path_ lock from this driver. (NOTE:
  410. // initial-condition lock might still be in place,
  411. // but that's what we want.)
  412. //
  413. TRACE(TL_PNP_WARNING,("UNLOCKing some driver code (pageable) (b/c paging path)\n" ));
  414. ASSERT( NULL != devExt->pagingPathUnlockHandle );
  415. MmUnlockPagableImageSection( devExt->pagingPathUnlockHandle );
  416. devExt->pagingPathUnlockHandle = NULL;
  417. }
  418. break;
  419. default:
  420. ASSERT( FALSE ); // should never get here (b/c checked for invalid Type earlier)
  421. } //END: switch on Type of special-file
  422. //
  423. // Invalidate state, so that certain flags will get updated
  424. //
  425. IoInvalidateDeviceState( devExt->physicalDevObj );
  426. }//END: handling of irp success/failure cases
  427. //
  428. // Set event so that the next DEVICE_USAGE_NOTIFICATION IRP that
  429. // comes along can be processed.
  430. //
  431. KeSetEvent( &devExt->deviceUsageNotificationEvent
  432. , IO_NO_INCREMENT
  433. , FALSE
  434. );
  435. //
  436. // Complete the irp
  437. //
  438. IoCompleteRequest( irp, IO_NO_INCREMENT );
  439. return status;
  440. }
  441. #endif // HANDLE_DEVICE_USAGE
  442. NTSTATUS GetDeviceCapabilities(struct DEVICE_EXTENSION *devExt)
  443. /*++
  444. Routine Description:
  445. Function retrieves the DEVICE_CAPABILITIES descriptor from the device
  446. Arguments:
  447. devExt - device extension for targetted device object
  448. Return Value:
  449. NT status code
  450. --*/
  451. {
  452. NTSTATUS status;
  453. PIRP irp;
  454. PAGED_CODE();
  455. irp = IoAllocateIrp(devExt->topDevObj->StackSize, FALSE);
  456. if (irp){
  457. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  458. // must initialize DeviceCapabilities before sending...
  459. RtlZeroMemory( &devExt->deviceCapabilities,
  460. sizeof(DEVICE_CAPABILITIES));
  461. devExt->deviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES);
  462. devExt->deviceCapabilities.Version = 1;
  463. devExt->deviceCapabilities.Address = -1;
  464. devExt->deviceCapabilities.UINumber= -1;
  465. // setup irp stack location...
  466. nextSp->MajorFunction = IRP_MJ_PNP;
  467. nextSp->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  468. nextSp->Parameters.DeviceCapabilities.Capabilities =
  469. &devExt->deviceCapabilities;
  470. /*
  471. * For any IRP you create, you must set the default status
  472. * to STATUS_NOT_SUPPORTED before sending it.
  473. */
  474. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  475. status = CallNextDriverSync(devExt, irp);
  476. IoFreeIrp(irp);
  477. }
  478. else {
  479. status = STATUS_INSUFFICIENT_RESOURCES;
  480. }
  481. ASSERT(NT_SUCCESS(status));
  482. return status;
  483. }