Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

754 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. tracekmp.c
  5. Abstract:
  6. Sample kernel mode trace provider/driver.
  7. Author:
  8. Jee Fung Pang (jeepang) 03-Dec-1997
  9. Revision History:
  10. --*/
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <ntddk.h>
  14. #include <wmistr.h>
  15. #include <evntrace.h>
  16. #include "kmpioctl.h"
  17. #include <wmikm.h>
  18. #define TRACEKMP_NT_DEVICE_NAME L"\\Device\\TraceKmp"
  19. #define TRACEKMP_WIN32_DEVICE_NAME L"\\DosDevices\\TRACEKMP"
  20. #define TRACEKMP_DRIVER_NAME L"TRACEKMP"
  21. typedef struct _DEVICE_EXTENSION {
  22. PDEVICE_OBJECT DeviceObject;
  23. ULONG IrpSequenceNumber;
  24. UCHAR IrpRetryCount;
  25. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  26. //
  27. // Proc Ctrs Device Extension Object
  28. //
  29. //extern PDEVICE_OBJECT pTracekmpDeviceObject;
  30. NTSTATUS
  31. DriverEntry(
  32. IN PDRIVER_OBJECT DriverObject,
  33. IN PUNICODE_STRING RegistryPath
  34. );
  35. VOID
  36. TraceEventLogger(
  37. IN PTRACEHANDLE pLoggerHandle
  38. );
  39. NTSTATUS
  40. TracekmpDispatchOpen(
  41. IN PDEVICE_OBJECT pDO,
  42. IN PIRP Irp
  43. );
  44. NTSTATUS
  45. TracekmpDispatchClose(
  46. IN PDEVICE_OBJECT pDO,
  47. IN PIRP Irp
  48. );
  49. NTSTATUS
  50. TracekmpDispatchDeviceControl(
  51. IN PDEVICE_OBJECT pDO,
  52. IN PIRP Irp
  53. );
  54. NTSTATUS
  55. PcWmiRegisterGuids(
  56. IN PWMIREGINFO WmiRegInfo,
  57. IN ULONG wmiRegInfoSize,
  58. IN PULONG pReturnSize
  59. );
  60. #ifdef USE_CALLBACK
  61. NTSTATUS
  62. TracekmpControlCallback(
  63. IN ULONG ActionCode,
  64. IN PVOID DataPath,
  65. IN ULONG BufferSize,
  66. IN OUT PVOID Buffer,
  67. IN PVOID Context,
  68. OUT PULONG Size
  69. );
  70. #else
  71. NTSTATUS
  72. PcWmiDispatch(
  73. IN PDEVICE_OBJECT pDO,
  74. IN PIRP Irp
  75. );
  76. #endif
  77. VOID
  78. TracekmpDriverUnload(
  79. IN PDRIVER_OBJECT DriverObject
  80. );
  81. #ifdef ALLOC_PRAGMA
  82. #pragma alloc_text( page, TracekmpDispatchOpen )
  83. #pragma alloc_text( page, TracekmpDispatchClose )
  84. #pragma alloc_text( page, TracekmpDispatchDeviceControl )
  85. #ifdef USE_CALLBACK
  86. #pragma alloc_text( page, TracekmpControlCallback )
  87. #else
  88. #pragma alloc_text( page, PcWmiDispatch )
  89. #endif
  90. #pragma alloc_text( init, DriverEntry )
  91. #pragma alloc_text( page, TracekmpDriverUnload )
  92. #endif // ALLOC_PRAGMA
  93. #define PROC_REG_PATH L"System\\CurrentControlSet\\Services\\TRACEKMP"
  94. #define MAXEVENTS 100
  95. GUID TracekmpGuid =
  96. {0xd58c126f, 0xb309, 0x11d1, 0x96, 0x9e, 0x00, 0x00, 0xf8, 0x75, 0xa5, 0xbc};
  97. ULONG TracekmpEnable = 0;
  98. TRACEHANDLE LoggerHandle;
  99. PDEVICE_OBJECT pTracekmpDeviceObject;
  100. NTSTATUS
  101. DriverEntry(
  102. IN PDRIVER_OBJECT DriverObject,
  103. IN PUNICODE_STRING RegistryPath
  104. )
  105. /*++
  106. Routine Description:
  107. This is the callback function when we call IoCreateDriver to create a
  108. WMI Driver Object. In this function, we need to remember the
  109. DriverObject, create a device object and then create a Win32 visible
  110. symbolic link name so that the WMI user mode component can access us.
  111. Arguments:
  112. DriverObject - pointer to the driver object
  113. RegistryPath - pointer to a unicode string representing the path
  114. to driver-specific key in the registry
  115. Return Value:
  116. STATUS_SUCCESS if successful
  117. STATUS_UNSUCCESSFUL otherwise
  118. --*/
  119. {
  120. NTSTATUS status = STATUS_SUCCESS;
  121. ULONG i;
  122. UNICODE_STRING deviceName;
  123. UNICODE_STRING linkName;
  124. //
  125. // Create Dispatch Entry Points.
  126. //
  127. DriverObject->DriverUnload = TracekmpDriverUnload;
  128. DriverObject->MajorFunction[ IRP_MJ_CREATE ] = TracekmpDispatchOpen;
  129. DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = TracekmpDispatchClose;
  130. DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] =
  131. TracekmpDispatchDeviceControl;
  132. //
  133. // Wire a function to start fielding WMI IRPS
  134. //
  135. #ifndef USE_CALLBACK
  136. DriverObject->MajorFunction[ IRP_MJ_SYSTEM_CONTROL ] = PcWmiDispatch;
  137. #endif
  138. RtlInitUnicodeString( &deviceName, TRACEKMP_NT_DEVICE_NAME );
  139. //
  140. // Create the Device object
  141. //
  142. status = IoCreateDevice(
  143. DriverObject,
  144. sizeof( DEVICE_EXTENSION ),
  145. &deviceName,
  146. FILE_DEVICE_UNKNOWN,
  147. 0,
  148. FALSE,
  149. &pTracekmpDeviceObject);
  150. if( !NT_SUCCESS( status )) {
  151. return status;
  152. }
  153. RtlInitUnicodeString( &linkName, TRACEKMP_WIN32_DEVICE_NAME );
  154. status = IoCreateSymbolicLink( &linkName, &deviceName );
  155. if( !NT_SUCCESS( status )) {
  156. IoDeleteDevice( pTracekmpDeviceObject );
  157. return status;
  158. }
  159. //
  160. // Choose a buffering mechanism
  161. //
  162. pTracekmpDeviceObject->Flags |= DO_BUFFERED_IO;
  163. //
  164. // Register with WMI here
  165. //
  166. #ifdef USE_CALLBACK
  167. status = IoWMIRegistrationControl(
  168. (PDEVICE_OBJECT) TracekmpControlCallback,
  169. WMIREG_ACTION_REGISTER | WMIREG_FLAG_CALLBACK);
  170. #else
  171. status = IoWMIRegistrationControl(pTracekmpDeviceObject,
  172. WMIREG_ACTION_REGISTER);
  173. #endif
  174. if (!NT_SUCCESS(status))
  175. {
  176. DbgPrint("TRACEKMP: Failed to register for WMI support\n");
  177. }
  178. return STATUS_SUCCESS;
  179. }
  180. NTSTATUS
  181. TracekmpDispatchOpen(
  182. IN PDEVICE_OBJECT pDO,
  183. IN PIRP Irp
  184. )
  185. {
  186. Irp->IoStatus.Status = STATUS_SUCCESS;
  187. Irp->IoStatus.Information = 0;
  188. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  189. return STATUS_SUCCESS;
  190. }
  191. //++
  192. // Function:
  193. // TracekmpDispatchClose
  194. //
  195. // Description:
  196. // This function dispatches CloseHandle
  197. // requests from Win32
  198. //
  199. // Arguments:
  200. // Pointer to Device object
  201. // Pointer to IRP for this request
  202. //
  203. // Return Value:
  204. // This function returns STATUS_XXX
  205. //--
  206. NTSTATUS
  207. TracekmpDispatchClose(
  208. IN PDEVICE_OBJECT pDO,
  209. IN PIRP Irp
  210. )
  211. {
  212. Irp->IoStatus.Status = STATUS_SUCCESS;
  213. Irp->IoStatus.Information = 0;
  214. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  215. return STATUS_SUCCESS;
  216. }
  217. //++
  218. // Function:
  219. // TracekmpDispatchDeviceControl
  220. //
  221. // Description:
  222. // This function dispatches DeviceIoControl
  223. // requests from Win32
  224. //
  225. // Arguments:
  226. // Pointer to Device object
  227. // Pointer to IRP for this request
  228. //
  229. // Return Value:
  230. // This function returns STATUS_XXX
  231. //--
  232. NTSTATUS
  233. TracekmpDispatchDeviceControl(
  234. IN PDEVICE_OBJECT pDO,
  235. IN PIRP Irp
  236. )
  237. {
  238. NTSTATUS status;
  239. EVENT_TRACE_HEADER Header, *Wnode;
  240. PIO_STACK_LOCATION irpStack =
  241. IoGetCurrentIrpStackLocation( Irp );
  242. PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
  243. ULONG InBufferLen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  244. ULONG OutBufferLen= irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  245. // WMI_LOGGER_INFORMATION LoggerInfo;
  246. ULONG ControlCode =
  247. irpStack->Parameters.
  248. DeviceIoControl.IoControlCode;
  249. // RtlZeroMemory(&LoggerInfo, sizeof(LoggerInfo));
  250. // LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo);
  251. // LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  252. // RtlInitUnicodeString(&LoggerInfo.LoggerName, L"TraceKmp");
  253. // RtlInitUnicodeString(&LoggerInfo.LogFileName, L"C:\\tracekmp.etl");
  254. Irp->IoStatus.Information = OutBufferLen;
  255. switch( ControlCode )
  256. {
  257. case IOCTL_TRACEKMP_TRACE_EVENT:
  258. //
  259. // Every time you get this IOCTL, we also log a trace event
  260. // to illustrate that the event can be caused by user-mode
  261. //
  262. if (TracekmpEnable) {
  263. Wnode = &Header;
  264. RtlZeroMemory(Wnode, sizeof(EVENT_TRACE_HEADER));
  265. Wnode->Size = sizeof(EVENT_TRACE_HEADER);
  266. Wnode->Flags |= WNODE_FLAG_TRACED_GUID;
  267. Wnode->Guid = TracekmpGuid;
  268. ((PWNODE_HEADER)Wnode)->HistoricalContext = LoggerHandle;
  269. status = IoWMIWriteEvent((PVOID)Wnode);
  270. }
  271. else {
  272. status = STATUS_SUCCESS;
  273. }
  274. Irp->IoStatus.Information = 0;
  275. break;
  276. case IOCTL_TRACEKMP_START:
  277. status = WmiStartTrace(Buffer);
  278. DbgPrint("Start status = %X\n", status);
  279. break;
  280. case IOCTL_TRACEKMP_STOP:
  281. status = WmiStopTrace(Buffer);
  282. DbgPrint("Stop status = %X\n", status);
  283. break;
  284. case IOCTL_TRACEKMP_QUERY:
  285. status = WmiQueryTrace(Buffer);
  286. DbgPrint("Query status = %X\n", status);
  287. break;
  288. case IOCTL_TRACEKMP_UPDATE:
  289. status = WmiUpdateTrace(Buffer);
  290. DbgPrint("Update status = %X\n", status);
  291. break;
  292. case IOCTL_TRACEKMP_FLUSH:
  293. status = WmiFlushTrace(Buffer);
  294. DbgPrint("Flush status = %X\n", status);
  295. break;
  296. //
  297. // Not one we recognize. Error.
  298. //
  299. default:
  300. status = STATUS_INVALID_PARAMETER;
  301. Irp->IoStatus.Information = 0;
  302. break;
  303. }
  304. //
  305. // Get rid of this request
  306. //
  307. Irp->IoStatus.Status = status;
  308. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  309. return status;
  310. }
  311. NTSTATUS
  312. PcWmiRegisterGuids(
  313. IN PWMIREGINFO WmiRegInfo,
  314. IN ULONG wmiRegInfoSize,
  315. IN PULONG pReturnSize
  316. )
  317. {
  318. //
  319. // Register a Control Guid as a Trace Guid.
  320. //
  321. ULONG SizeNeeded;
  322. PWMIREGGUIDW WmiRegGuidPtr;
  323. ULONG Status;
  324. ULONG GuidCount;
  325. LPGUID ControlGuid;
  326. ULONG RegistryPathSize;
  327. PUCHAR ptmp;
  328. *pReturnSize = 0;
  329. GuidCount = 1;
  330. ControlGuid = &TracekmpGuid;
  331. //
  332. // Allocate WMIREGINFO for controlGuid + GuidCount.
  333. //
  334. RegistryPathSize = sizeof(PROC_REG_PATH) - sizeof(WCHAR) + sizeof(USHORT);
  335. SizeNeeded = sizeof(WMIREGINFOW) + GuidCount * sizeof(WMIREGGUIDW) +
  336. RegistryPathSize;
  337. if (SizeNeeded > wmiRegInfoSize) {
  338. *((PULONG)WmiRegInfo) = SizeNeeded;
  339. *pReturnSize = sizeof(ULONG);
  340. return STATUS_SUCCESS;
  341. }
  342. RtlZeroMemory(WmiRegInfo, SizeNeeded);
  343. WmiRegInfo->BufferSize = SizeNeeded;
  344. WmiRegInfo->GuidCount = GuidCount;
  345. WmiRegInfo->NextWmiRegInfo =
  346. WmiRegInfo->RegistryPath =
  347. WmiRegInfo->MofResourceName = 0;
  348. WmiRegGuidPtr = &WmiRegInfo->WmiRegGuid[0];
  349. WmiRegGuidPtr->Guid = *ControlGuid;
  350. WmiRegGuidPtr->Flags |= WMIREG_FLAG_TRACED_GUID;
  351. WmiRegGuidPtr->Flags |= WMIREG_FLAG_TRACE_CONTROL_GUID;
  352. WmiRegGuidPtr->InstanceCount = 0;
  353. WmiRegGuidPtr->InstanceInfo = 0;
  354. ptmp = (PUCHAR)&WmiRegInfo->WmiRegGuid[1];
  355. WmiRegInfo->RegistryPath = PtrToUlong((PVOID) (ptmp - (PUCHAR)WmiRegInfo));
  356. *((PUSHORT)ptmp) = sizeof(PROC_REG_PATH) - sizeof(WCHAR);
  357. ptmp += sizeof(USHORT);
  358. RtlCopyMemory(ptmp, PROC_REG_PATH, sizeof(PROC_REG_PATH) - sizeof(WCHAR));
  359. *pReturnSize = SizeNeeded;
  360. return(STATUS_SUCCESS);
  361. }
  362. #ifndef USE_CALLBACK
  363. NTSTATUS
  364. PcWmiDispatch(
  365. IN PDEVICE_OBJECT pDO,
  366. IN PIRP Irp
  367. )
  368. {
  369. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  370. ULONG BufferSize = irpSp->Parameters.WMI.BufferSize;
  371. PVOID Buffer = irpSp->Parameters.WMI.Buffer;
  372. ULONG ReturnSize = 0;
  373. NTSTATUS Status = STATUS_SUCCESS;
  374. PWNODE_HEADER Wnode=NULL;
  375. HANDLE ThreadHandle;
  376. UNREFERENCED_PARAMETER(pDO);
  377. switch (irpSp->MinorFunction) {
  378. case IRP_MN_REGINFO:
  379. #if DBG
  380. DbgPrint("IRP_MN_REG_INFO\n");
  381. #endif
  382. Status = PcWmiRegisterGuids( Buffer,
  383. BufferSize,
  384. &ReturnSize);
  385. break;
  386. case IRP_MN_ENABLE_EVENTS:
  387. InterlockedExchange(&TracekmpEnable, 1);
  388. Wnode = (PWNODE_HEADER)Buffer;
  389. if (BufferSize >= sizeof(WNODE_HEADER)) {
  390. LoggerHandle = Wnode->HistoricalContext;
  391. #if DBG
  392. DbgPrint("LoggerHandle %I64u\n", Wnode->HistoricalContext);
  393. DbgPrint("BufferSize %d\n", Wnode->BufferSize);
  394. DbgPrint("Flags %x\n", Wnode->Flags);
  395. DbgPrint("Version %x\n", Wnode->Version);
  396. #endif
  397. }
  398. //
  399. // After getting enabled, create a thread to log a few events
  400. // to test this out.
  401. Status = PsCreateSystemThread(
  402. &ThreadHandle,
  403. THREAD_ALL_ACCESS,
  404. NULL,
  405. NULL,
  406. NULL,
  407. TraceEventLogger,
  408. &LoggerHandle );
  409. if (NT_SUCCESS(Status)) { // if SystemThread is started
  410. ZwClose (ThreadHandle);
  411. }
  412. #if DBG
  413. DbgPrint("IRP_MN_ENABLE_EVENTS\n");
  414. #endif
  415. break;
  416. case IRP_MN_DISABLE_EVENTS:
  417. InterlockedExchange(&TracekmpEnable, 0);
  418. #if DBG
  419. DbgPrint(" IRP_MN_DISABLE_EVENTS\n");
  420. #endif
  421. break;
  422. case IRP_MN_ENABLE_COLLECTION:
  423. #if DBG
  424. DbgPrint("IRP_MN_ENABLE_COLLECTION\n");
  425. #endif
  426. break;
  427. case IRP_MN_DISABLE_COLLECTION:
  428. #if DBG
  429. DbgPrint("IRP_MN_DISABLE_COLLECTION\n");
  430. #endif
  431. break;
  432. default:
  433. Status = STATUS_INVALID_DEVICE_REQUEST;
  434. Irp->IoStatus.Status = Status;
  435. Irp->IoStatus.Information = 0;
  436. #if DBG
  437. DbgPrint("DEFAULT\n");
  438. #endif
  439. return Status;
  440. }
  441. //
  442. // Before the packet goes back to the
  443. // I/O Manager, log a message.
  444. //
  445. Irp->IoStatus.Status = Status;
  446. Irp->IoStatus.Information = ReturnSize;
  447. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  448. return Status;
  449. }
  450. #endif
  451. VOID
  452. TraceEventLogger(
  453. IN PTRACEHANDLE pLoggerHandle
  454. )
  455. {
  456. NTSTATUS status;
  457. EVENT_TRACE_HEADER Header, *Wnode;
  458. PULONG TraceMarker;
  459. ULONG i = 0;
  460. TRACEHANDLE LoggerHandle = *pLoggerHandle;
  461. while (TracekmpEnable) {
  462. //
  463. // NOTE: For optimization, the set up of the HEADER should be done
  464. // one outside of this while loop. It is left here so that the caller
  465. // at least needs to be conscious of what is being sent
  466. //
  467. Wnode = &Header;
  468. RtlZeroMemory(Wnode, sizeof(EVENT_TRACE_HEADER));
  469. Wnode->Size = sizeof(EVENT_TRACE_HEADER);
  470. Wnode->Flags = WNODE_FLAG_TRACED_GUID;
  471. Wnode->Guid = TracekmpGuid;
  472. ((PWNODE_HEADER)Wnode)->HistoricalContext = LoggerHandle;
  473. //
  474. // Call TraceLogger to write this event
  475. //
  476. status = IoWMIWriteEvent((PVOID)Wnode);
  477. #ifdef DBG
  478. if ( !(i%100) ) {
  479. DbgPrint("Another Hundred Events Written \n");
  480. DbgPrint("Status %x LoggerHandle %I64X\n", status, LoggerHandle);
  481. }
  482. #endif
  483. if (i++ > MAXEVENTS)
  484. break;
  485. }
  486. PsTerminateSystemThread(status);
  487. return;
  488. }
  489. VOID
  490. TracekmpDriverUnload(
  491. IN PDRIVER_OBJECT DriverObject
  492. )
  493. {
  494. PDEVICE_OBJECT pDevObj;
  495. UNICODE_STRING linkName;
  496. #if DBG
  497. DbgPrint("Unloading the Driver\n");
  498. #endif
  499. //
  500. // Get pointer to Device object
  501. //
  502. pDevObj = DriverObject->DeviceObject;
  503. //
  504. IoWMIRegistrationControl(pDevObj, WMIREG_ACTION_DEREGISTER);
  505. //
  506. // Form the Win32 symbolic link name.
  507. //
  508. RtlInitUnicodeString(
  509. &linkName,
  510. TRACEKMP_WIN32_DEVICE_NAME );
  511. //
  512. // Remove symbolic link from Object
  513. // namespace...
  514. //
  515. IoDeleteSymbolicLink( &linkName );
  516. //
  517. // Unload the callbacks from the kernel to this driver
  518. //
  519. IoDeleteDevice( pDevObj );
  520. }
  521. #ifdef USE_CALLBACK
  522. NTSTATUS
  523. TracekmpControlCallback(
  524. IN WMIACTIONCODE ActionCode,
  525. IN PVOID DataPath,
  526. IN ULONG BufferSize,
  527. IN OUT PVOID Buffer,
  528. IN PVOID Context,
  529. OUT PULONG Size
  530. )
  531. //
  532. // This callback routine is called to process enable/disable action codes
  533. //
  534. {
  535. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  536. ULONG BufferSize = irpSp->Parameters.WMI.BufferSize;
  537. PVOID Buffer = irpSp->Parameters.WMI.Buffer;
  538. ULONG ReturnSize = 0;
  539. NTSTATUS Status = STATUS_SUCCESS;
  540. PWNODE_HEADER Wnode=NULL;
  541. HANDLE ThreadHandle;
  542. UNREFERENCED_PARAMETER(pDO);
  543. switch (ActionCode) {
  544. case IRP_MN_REG_INFO :
  545. #if DBG
  546. DbgPrint("IRP_MN_REG_INFO\n");
  547. #endif
  548. Status = PcWmiRegisterGuids( Buffer,
  549. BufferSize,
  550. &ReturnSize);
  551. break;
  552. case IRP_MN_ENABLE_EVENTS :
  553. InterlockedExchange(&TracekmpEnable, 1);
  554. Wnode = (PWNODE_HEADER)Buffer;
  555. if (BufferSize >= sizeof(WNODE_HEADER)) {
  556. LoggerHandle = Wnode->HistoricalContext;
  557. #if DBG
  558. DbgPrint("LoggerHandle %I64u\n", Wnode->HistoricalContext);
  559. DbgPrint("BufferSize %d\n", Wnode->BufferSize);
  560. DbgPrint("Flags %x\n", Wnode->Flags);
  561. DbgPrint("Version %x\n", Wnode->Version);
  562. #endif
  563. }
  564. //
  565. // After getting enabled, create a thread to log a few events
  566. // to test this out.
  567. Status = PsCreateSystemThread(
  568. &ThreadHandle,
  569. THREAD_ALL_ACCESS,
  570. NULL,
  571. NULL,
  572. NULL,
  573. TraceEventLogger,
  574. &LoggerHandle );
  575. if (NT_SUCCESS(Status)) { // if SystemThread is started
  576. ZwClose (ThreadHandle);
  577. }
  578. #if DBG
  579. DbgPrint("IRP_MN_ENABLE_EVENTS\n");
  580. #endif
  581. break;
  582. case IRP_MN_DISABLE_EVENTS :
  583. InterlockedExchange(&TracekmpEnable, 0);
  584. #if DBG
  585. DbgPrint(" IRP_MN_DISABLE_EVENTS\n");
  586. #endif
  587. break;
  588. case IRP_MN_ENABLE_COLLECTION :
  589. #if DBG
  590. DbgPrint("IRP_MN_ENABLE_COLLECTION\n");
  591. #endif
  592. break;
  593. case IRP_MN_DISABLE_COLLECTION :
  594. #if DBG
  595. DbgPrint("IRP_MN_DISABLE_COLLECTION\n");
  596. #endif
  597. break;
  598. default:
  599. Status = STATUS_INVALID_DEVICE_REQUEST;
  600. ReturnSize = 0;
  601. #if DBG
  602. DbgPrint("DEFAULT\n");
  603. #endif
  604. return Status;
  605. }
  606. //
  607. // Before the packet goes back to the
  608. // I/O Manager, log a message.
  609. //
  610. if (Size)
  611. *Size = ReturnSize;
  612. return Status;
  613. }
  614. #endif // USE_CALLBACK