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.

813 lines
20 KiB

  1. #include "ntos.h"
  2. #include "io.h"
  3. #include <stdarg.h>
  4. #include <wmistr.h>
  5. NTSTATUS
  6. WmiSampSystemControl(
  7. IN PDEVICE_OBJECT DeviceObject,
  8. IN PIRP Irp
  9. );
  10. NTSTATUS
  11. WmiSampFunctionControl(
  12. IN PDEVICE_OBJECT DeviceObject,
  13. IN PIRP Irp,
  14. IN ULONG GuidIndex,
  15. IN WMIENABLEDISABLEFUNCTION Function,
  16. IN BOOLEAN Enable
  17. );
  18. NTSTATUS
  19. WmiSampExecuteWmiMethod(
  20. IN PDEVICE_OBJECT DeviceObject,
  21. IN PIRP Irp,
  22. IN ULONG GuidIndex,
  23. IN ULONG MethodId,
  24. IN ULONG InBufferSize,
  25. IN ULONG OutBufferSize,
  26. IN PUCHAR Buffer
  27. );
  28. NTSTATUS
  29. WmiSampSetWmiDataItem(
  30. IN PDEVICE_OBJECT DeviceObject,
  31. IN PIRP Irp,
  32. IN ULONG GuidIndex,
  33. IN ULONG DataItemId,
  34. IN ULONG BufferSize,
  35. IN PUCHAR Buffer
  36. );
  37. NTSTATUS
  38. WmiSampSetWmiDataBlock(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp,
  41. IN ULONG GuidIndex,
  42. IN ULONG BufferSize,
  43. IN PUCHAR Buffer
  44. );
  45. NTSTATUS
  46. WmiSampQueryWmiDataBlock(
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PIRP Irp,
  49. IN ULONG GuidIndex,
  50. IN ULONG BufferAvail,
  51. OUT PUCHAR Buffer
  52. );
  53. NTSTATUS
  54. WmiSampQueryWmiRegInfo(
  55. IN PDEVICE_OBJECT DeviceObject,
  56. OUT ULONG *RegFlags,
  57. OUT PUNICODE_STRING InstanceName,
  58. OUT PUNICODE_STRING *RegistryPath
  59. );
  60. NTSTATUS
  61. DriverEntry(
  62. IN PDRIVER_OBJECT DriverObject,
  63. IN PUNICODE_STRING RegistryPath
  64. );
  65. NTSTATUS
  66. WmiSampPnP(
  67. IN PDEVICE_OBJECT DeviceObject,
  68. IN PIRP Irp
  69. );
  70. NTSTATUS
  71. WmiSampForward(
  72. IN PDEVICE_OBJECT DeviceObject,
  73. IN PIRP Irp
  74. );
  75. VOID
  76. WmiSampUnload(
  77. IN PDRIVER_OBJECT DriverObject
  78. );
  79. NTSTATUS
  80. WmiSampCreateDeviceObject(
  81. IN PDRIVER_OBJECT DriverObject,
  82. IN PDEVICE_OBJECT *DeviceObject,
  83. LONG Instance
  84. );
  85. NTSTATUS
  86. WmiSampAddDevice(
  87. IN PDRIVER_OBJECT DriverObject,
  88. IN PDEVICE_OBJECT PhysicalDeviceObject
  89. );
  90. #ifdef ALLOC_PRAGMA
  91. #pragma alloc_text(INIT,DriverEntry)
  92. #pragma alloc_text(PAGE,WmiSampQueryWmiRegInfo)
  93. #pragma alloc_text(PAGE,WmiSampQueryWmiDataBlock)
  94. #pragma alloc_text(PAGE,WmiSampSetWmiDataBlock)
  95. #pragma alloc_text(PAGE,WmiSampSetWmiDataItem)
  96. #pragma alloc_text(PAGE,WmiSampExecuteWmiMethod)
  97. #pragma alloc_text(PAGE,WmiSampFunctionControl)
  98. #endif
  99. // {15D851F1-6539-11d1-A529-00A0C9062910}
  100. GUIDREGINFO WmiSampGuidList[] =
  101. {
  102. {
  103. { 0x15d851f1, 0x6539, 0x11d1, 0xa5, 0x29, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 },
  104. WMIREG_FLAG_EXPENSIVE
  105. },
  106. };
  107. ULONG WmiSampDummyData[4] = { 1, 2, 3, 4};
  108. UNICODE_STRING WmiSampRegistryPath;
  109. NTSTATUS
  110. DriverEntry(
  111. IN PDRIVER_OBJECT DriverObject,
  112. IN PUNICODE_STRING RegistryPath
  113. )
  114. /*++
  115. Routine Description:
  116. Installable driver initialization entry point.
  117. This is where the driver is called when the driver is being loaded
  118. by the I/O system. This entry point is called directly by the I/O system.
  119. Arguments:
  120. DriverObject - pointer to the driver object
  121. RegistryPath - pointer to a unicode string representing the path
  122. to driver-specific key in the registry
  123. Return Value:
  124. STATUS_SUCCESS if successful,
  125. STATUS_UNSUCCESSFUL otherwise
  126. --*/
  127. {
  128. NTSTATUS ntStatus = STATUS_SUCCESS;
  129. PDEVICE_OBJECT deviceObject = NULL;
  130. WmiSampRegistryPath.Length = 0;
  131. WmiSampRegistryPath.MaximumLength = RegistryPath->Length;
  132. WmiSampRegistryPath.Buffer = ExAllocatePool(PagedPool,
  133. RegistryPath->Length+2);
  134. RtlCopyUnicodeString(&WmiSampRegistryPath, RegistryPath);
  135. /*
  136. // Create dispatch points for the various events handled by this
  137. // driver. For example, device I/O control calls (e.g., when a Win32
  138. // application calls the DeviceIoControl function) will be dispatched to
  139. // routine specified below in the IRP_MJ_DEVICE_CONTROL case.
  140. //
  141. // For more information about the IRP_XX_YYYY codes, please consult the
  142. // Windows NT DDK documentation.
  143. //
  144. */
  145. DriverObject->MajorFunction[IRP_MJ_CREATE] = WmiSampForward;
  146. DriverObject->MajorFunction[IRP_MJ_CLOSE] = WmiSampForward;
  147. DriverObject->DriverUnload = WmiSampUnload;
  148. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WmiSampForward;
  149. DriverObject->MajorFunction[IRP_MJ_PNP] = WmiSampPnP;
  150. DriverObject->MajorFunction[IRP_MJ_POWER] = WmiSampForward;
  151. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = WmiSampSystemControl;
  152. DriverObject->DriverExtension->AddDevice = WmiSampAddDevice;
  153. return ntStatus;
  154. }
  155. NTSTATUS
  156. WmiSampSystemControl(
  157. IN PDEVICE_OBJECT DeviceObject,
  158. IN PIRP Irp
  159. )
  160. {
  161. return(IoWMISystemControl((PWMILIB_INFO)DeviceObject->DeviceExtension,
  162. DeviceObject,
  163. Irp));
  164. }
  165. NTSTATUS
  166. WmiSampPnP(
  167. IN PDEVICE_OBJECT DeviceObject,
  168. IN PIRP Irp
  169. )
  170. /*++
  171. Routine Description:
  172. Process the IRPs sent to this device.
  173. Arguments:
  174. DeviceObject - pointer to a device object
  175. Irp - pointer to an I/O Request Packet
  176. Return Value:
  177. NTSTATUS
  178. --*/
  179. {
  180. PIO_STACK_LOCATION irpStack, nextStack;
  181. PWMILIB_INFO wmilibInfo;
  182. NTSTATUS status;
  183. irpStack = IoGetCurrentIrpStackLocation (Irp);
  184. /*
  185. // Get a pointer to the device extension
  186. */
  187. wmilibInfo = (PWMILIB_INFO)DeviceObject->DeviceExtension;
  188. switch (irpStack->MinorFunction)
  189. {
  190. case IRP_MN_START_DEVICE:
  191. {
  192. IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_REGISTER);
  193. break; //IRP_MN_START_DEVICE
  194. }
  195. case IRP_MN_REMOVE_DEVICE:
  196. {
  197. IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_DEREGISTER);
  198. IoDetachDevice(wmilibInfo->LowerDeviceObject);
  199. IoDeleteDevice (DeviceObject);
  200. break; //IRP_MN_REMOVE_DEVICE
  201. }
  202. }
  203. IoSkipCurrentIrpStackLocation(Irp);
  204. status = IoCallDriver(wmilibInfo->LowerDeviceObject, Irp);
  205. return(status);
  206. }
  207. NTSTATUS
  208. WmiSampForward(
  209. IN PDEVICE_OBJECT DeviceObject,
  210. IN PIRP Irp
  211. )
  212. {
  213. PIO_STACK_LOCATION irpStack, nextStack;
  214. PWMILIB_INFO wmilibInfo;
  215. NTSTATUS status;
  216. irpStack = IoGetCurrentIrpStackLocation (Irp);
  217. /*
  218. // Get a pointer to the device extension
  219. */
  220. wmilibInfo = (PWMILIB_INFO)DeviceObject->DeviceExtension;
  221. IoSkipCurrentIrpStackLocation(Irp);
  222. status = IoCallDriver(wmilibInfo->LowerDeviceObject, Irp);
  223. return(status);
  224. }
  225. VOID
  226. WmiSampUnload(
  227. IN PDRIVER_OBJECT DriverObject
  228. )
  229. /*++
  230. Routine Description:
  231. Free all the allocated resources, etc.
  232. TODO: This is a placeholder for driver writer to add code on unload
  233. Arguments:
  234. DriverObject - pointer to a driver object
  235. Return Value:
  236. None
  237. --*/
  238. {
  239. ExFreePool(WmiSampRegistryPath.Buffer);
  240. }
  241. NTSTATUS
  242. WmiSampCreateDeviceObject(
  243. IN PDRIVER_OBJECT DriverObject,
  244. IN PDEVICE_OBJECT *DeviceObject,
  245. LONG Instance
  246. )
  247. /*++
  248. Routine Description:
  249. Creates a Functional DeviceObject
  250. Arguments:
  251. DriverObject - pointer to the driver object for device
  252. DeviceObject - pointer to DeviceObject pointer to return
  253. created device object.
  254. Instance - instnace of the device create.
  255. Return Value:
  256. STATUS_SUCCESS if successful,
  257. STATUS_UNSUCCESSFUL otherwise
  258. --*/
  259. {
  260. NTSTATUS status;
  261. WCHAR deviceNameBuffer[] = L"\\Device\\Sample-0";
  262. UNICODE_STRING deviceNameUnicodeString;
  263. deviceNameBuffer[15] = (USHORT) ('0' + Instance);
  264. RtlInitUnicodeString (&deviceNameUnicodeString,
  265. deviceNameBuffer);
  266. status = IoCreateDevice (DriverObject,
  267. sizeof(WMILIB_INFO),
  268. &deviceNameUnicodeString,
  269. FILE_DEVICE_UNKNOWN,
  270. 0,
  271. FALSE,
  272. DeviceObject);
  273. return status;
  274. }
  275. ULONG Instance;
  276. NTSTATUS
  277. WmiSampAddDevice(
  278. IN PDRIVER_OBJECT DriverObject,
  279. IN PDEVICE_OBJECT PhysicalDeviceObject
  280. )
  281. /*++
  282. Routine Description:
  283. This routine is called to create a new instance of the device
  284. Arguments:
  285. DriverObject - pointer to the driver object for this instance of Sample
  286. PhysicalDeviceObject - pointer to a device object created by the bus
  287. Return Value:
  288. STATUS_SUCCESS if successful,
  289. STATUS_UNSUCCESSFUL otherwise
  290. --*/
  291. {
  292. NTSTATUS status;
  293. PDEVICE_OBJECT deviceObject = NULL;
  294. PWMILIB_INFO wmilibInfo;
  295. DbgBreakPoint();
  296. // create our functional device object (FDO)
  297. status = WmiSampCreateDeviceObject(DriverObject, &deviceObject, Instance++);
  298. if (NT_SUCCESS(status)) {
  299. wmilibInfo = deviceObject->DeviceExtension;
  300. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  301. /*
  302. // Add more flags here if your driver supports other specific
  303. // behavior. For example, if your IRP_MJ_READ and IRP_MJ_WRITE
  304. // handlers support DIRECT_IO, you would set that flag here.
  305. //
  306. // Also, store away the Physical device Object
  307. */
  308. wmilibInfo->LowerPDO = PhysicalDeviceObject;
  309. //
  310. // Attach to the StackDeviceObject. This is the device object that what we
  311. // use to send Irps and Urbs down the USB software stack
  312. //
  313. wmilibInfo->LowerDeviceObject =
  314. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  315. wmilibInfo->GuidCount = 1;
  316. wmilibInfo->GuidList = WmiSampGuidList;
  317. wmilibInfo->QueryWmiRegInfo = WmiSampQueryWmiRegInfo;
  318. wmilibInfo->QueryWmiDataBlock = WmiSampQueryWmiDataBlock;
  319. wmilibInfo->SetWmiDataBlock = WmiSampSetWmiDataBlock;
  320. wmilibInfo->SetWmiDataItem = WmiSampSetWmiDataItem;
  321. wmilibInfo->ExecuteWmiMethod = WmiSampExecuteWmiMethod;
  322. wmilibInfo->WmiFunctionControl = WmiSampFunctionControl;
  323. }
  324. return(status);
  325. }
  326. NTSTATUS
  327. WmiSampQueryWmiRegInfo(
  328. IN PDEVICE_OBJECT DeviceObject,
  329. OUT ULONG *RegFlags,
  330. OUT PUNICODE_STRING InstanceName,
  331. OUT PUNICODE_STRING *RegistryPath
  332. )
  333. /*++
  334. Routine Description:
  335. This routine is a callback into the driver to retrieve the list of
  336. guids or data blocks that the driver wants to register with WMI. This
  337. routine may not pend or block. Driver should NOT call
  338. ClassWmiCompleteRequest.
  339. Arguments:
  340. DeviceObject is the device whose data block is being queried
  341. *RegFlags returns with a set of flags that describe the guids being
  342. registered for this device. If the device wants enable and disable
  343. collection callbacks before receiving queries for the registered
  344. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  345. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  346. the instance name is determined from the PDO associated with the
  347. device object. Note that the PDO must have an associated devnode. If
  348. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  349. name for the device.
  350. InstanceName returns with the instance name for the guids if
  351. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  352. caller will call ExFreePool with the buffer returned.
  353. *RegistryPath returns with the registry path of the driver
  354. Return Value:
  355. status
  356. --*/
  357. {
  358. *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
  359. *RegistryPath = &WmiSampRegistryPath;
  360. return(STATUS_SUCCESS);
  361. }
  362. NTSTATUS
  363. WmiSampQueryWmiDataBlock(
  364. IN PDEVICE_OBJECT DeviceObject,
  365. IN PIRP Irp,
  366. IN ULONG GuidIndex,
  367. IN ULONG BufferAvail,
  368. OUT PUCHAR Buffer
  369. )
  370. /*++
  371. Routine Description:
  372. This routine is a callback into the driver to query for the contents of
  373. a data block. When the driver has finished filling the data block it
  374. must call ClassWmiCompleteRequest to complete the irp. The driver can
  375. return STATUS_PENDING if the irp cannot be completed immediately.
  376. Arguments:
  377. DeviceObject is the device whose data block is being queried
  378. Irp is the Irp that makes this request
  379. GuidIndex is the index into the list of guids provided when the
  380. device registered
  381. BufferAvail on has the maximum size available to write the data
  382. block.
  383. Buffer on return is filled with the returned data block
  384. Return Value:
  385. status
  386. --*/
  387. {
  388. NTSTATUS status;
  389. ULONG sizeNeeded;
  390. switch (GuidIndex)
  391. {
  392. case 0:
  393. {
  394. sizeNeeded = 4 * sizeof(ULONG);
  395. if (BufferAvail >= sizeNeeded)
  396. {
  397. RtlCopyMemory(Buffer, WmiSampDummyData, sizeNeeded);
  398. status = STATUS_SUCCESS;
  399. } else {
  400. status = STATUS_BUFFER_TOO_SMALL;
  401. }
  402. break;
  403. }
  404. default:
  405. {
  406. status = STATUS_WMI_GUID_NOT_FOUND;
  407. }
  408. }
  409. status = IoWMICompleteRequest((PWMILIB_INFO)DeviceObject->DeviceExtension,
  410. DeviceObject,
  411. Irp,
  412. status,
  413. sizeNeeded,
  414. IO_NO_INCREMENT);
  415. return(status);
  416. }
  417. NTSTATUS
  418. WmiSampSetWmiDataBlock(
  419. IN PDEVICE_OBJECT DeviceObject,
  420. IN PIRP Irp,
  421. IN ULONG GuidIndex,
  422. IN ULONG BufferSize,
  423. IN PUCHAR Buffer
  424. )
  425. /*++
  426. Routine Description:
  427. This routine is a callback into the driver to query for the contents of
  428. a data block. When the driver has finished filling the data block it
  429. must call ClassWmiCompleteRequest to complete the irp. The driver can
  430. return STATUS_PENDING if the irp cannot be completed immediately.
  431. Arguments:
  432. DeviceObject is the device whose data block is being queried
  433. Irp is the Irp that makes this request
  434. GuidIndex is the index into the list of guids provided when the
  435. device registered
  436. BufferSize has the size of the data block passed
  437. Buffer has the new values for the data block
  438. Return Value:
  439. status
  440. --*/
  441. {
  442. NTSTATUS status;
  443. ULONG sizeNeeded;
  444. switch(GuidIndex)
  445. {
  446. case 0:
  447. {
  448. sizeNeeded = 4 * sizeof(ULONG);
  449. if (BufferSize == sizeNeeded)
  450. {
  451. RtlCopyMemory(WmiSampDummyData, Buffer, sizeNeeded);
  452. status = STATUS_SUCCESS;
  453. } else {
  454. status = STATUS_INFO_LENGTH_MISMATCH;
  455. }
  456. break;
  457. }
  458. default:
  459. {
  460. status = STATUS_WMI_GUID_NOT_FOUND;
  461. }
  462. }
  463. status = IoWMICompleteRequest((PWMILIB_INFO)DeviceObject->DeviceExtension,
  464. DeviceObject,
  465. Irp,
  466. status,
  467. 0,
  468. IO_NO_INCREMENT);
  469. return(status);
  470. }
  471. NTSTATUS
  472. WmiSampSetWmiDataItem(
  473. IN PDEVICE_OBJECT DeviceObject,
  474. IN PIRP Irp,
  475. IN ULONG GuidIndex,
  476. IN ULONG DataItemId,
  477. IN ULONG BufferSize,
  478. IN PUCHAR Buffer
  479. )
  480. /*++
  481. Routine Description:
  482. This routine is a callback into the driver to query for the contents of
  483. a data block. When the driver has finished filling the data block it
  484. must call ClassWmiCompleteRequest to complete the irp. The driver can
  485. return STATUS_PENDING if the irp cannot be completed immediately.
  486. Arguments:
  487. DeviceObject is the device whose data block is being queried
  488. Irp is the Irp that makes this request
  489. GuidIndex is the index into the list of guids provided when the
  490. device registered
  491. DataItemId has the id of the data item being set
  492. BufferSize has the size of the data item passed
  493. Buffer has the new values for the data item
  494. Return Value:
  495. status
  496. --*/
  497. {
  498. NTSTATUS status;
  499. switch(GuidIndex)
  500. {
  501. case 0:
  502. {
  503. if ((BufferSize == sizeof(ULONG)) &&
  504. (DataItemId <= 3))
  505. {
  506. WmiSampDummyData[DataItemId] = *((PULONG)Buffer);
  507. status = STATUS_SUCCESS;
  508. } else {
  509. status = STATUS_INVALID_DEVICE_REQUEST;
  510. }
  511. break;
  512. }
  513. default:
  514. {
  515. status = STATUS_WMI_GUID_NOT_FOUND;
  516. }
  517. }
  518. status = IoWMICompleteRequest((PWMILIB_INFO)DeviceObject->DeviceExtension,
  519. DeviceObject,
  520. Irp,
  521. status,
  522. 0,
  523. IO_NO_INCREMENT);
  524. return(status);
  525. }
  526. NTSTATUS
  527. WmiSampExecuteWmiMethod(
  528. IN PDEVICE_OBJECT DeviceObject,
  529. IN PIRP Irp,
  530. IN ULONG GuidIndex,
  531. IN ULONG MethodId,
  532. IN ULONG InBufferSize,
  533. IN ULONG OutBufferSize,
  534. IN PUCHAR Buffer
  535. )
  536. /*++
  537. Routine Description:
  538. This routine is a callback into the driver to execute a method. When the
  539. driver has finished filling the data block it must call
  540. ClassWmiCompleteRequest to complete the irp. The driver can
  541. return STATUS_PENDING if the irp cannot be completed immediately.
  542. Arguments:
  543. DeviceObject is the device whose data block is being queried
  544. Irp is the Irp that makes this request
  545. GuidIndex is the index into the list of guids provided when the
  546. device registered
  547. MethodId has the id of the method being called
  548. InBufferSize has the size of the data block passed in as the input to
  549. the method.
  550. OutBufferSize on entry has the maximum size available to write the
  551. returned data block.
  552. Buffer is filled with the returned data block
  553. Return Value:
  554. status
  555. --*/
  556. {
  557. ULONG sizeNeeded = 4 * sizeof(ULONG);
  558. NTSTATUS status;
  559. ULONG tempData[4];
  560. switch(GuidIndex)
  561. {
  562. case 0:
  563. {
  564. if (MethodId == 1)
  565. {
  566. if (OutBufferSize >= sizeNeeded)
  567. {
  568. if (InBufferSize == sizeNeeded)
  569. {
  570. RtlCopyMemory(tempData, Buffer, sizeNeeded);
  571. RtlCopyMemory(Buffer, WmiSampDummyData, sizeNeeded);
  572. RtlCopyMemory(WmiSampDummyData, tempData, sizeNeeded);
  573. status = STATUS_SUCCESS;
  574. } else {
  575. status = STATUS_INVALID_DEVICE_REQUEST;
  576. }
  577. } else {
  578. status = STATUS_BUFFER_TOO_SMALL;
  579. }
  580. } else {
  581. status = STATUS_INVALID_DEVICE_REQUEST;
  582. }
  583. break;
  584. }
  585. default:
  586. {
  587. status = STATUS_WMI_GUID_NOT_FOUND;
  588. }
  589. }
  590. status = IoWMICompleteRequest((PWMILIB_INFO)DeviceObject->DeviceExtension,
  591. DeviceObject,
  592. Irp,
  593. status,
  594. 0,
  595. IO_NO_INCREMENT);
  596. return(status);
  597. }
  598. NTSTATUS
  599. WmiSampFunctionControl(
  600. IN PDEVICE_OBJECT DeviceObject,
  601. IN PIRP Irp,
  602. IN ULONG GuidIndex,
  603. IN WMIENABLEDISABLEFUNCTION Function,
  604. IN BOOLEAN Enable
  605. )
  606. /*++
  607. Routine Description:
  608. This routine is a callback into the driver to enabled or disable event
  609. generation or data block collection. A device should only expect a
  610. single enable when the first event or data consumer enables events or
  611. data collection and a single disable when the last event or data
  612. consumer disables events or data collection. Data blocks will only
  613. receive collection enable/disable if they were registered as requiring
  614. it.
  615. Arguments:
  616. DeviceObject is the device whose data block is being queried
  617. GuidIndex is the index into the list of guids provided when the
  618. device registered
  619. Function specifies which functionality is being enabled or disabled
  620. Enable is TRUE then the function is being enabled else disabled
  621. Return Value:
  622. status
  623. --*/
  624. {
  625. NTSTATUS status;
  626. status = IoWMICompleteRequest((PWMILIB_INFO)DeviceObject->DeviceExtension,
  627. DeviceObject,
  628. Irp,
  629. STATUS_SUCCESS,
  630. 0,
  631. IO_NO_INCREMENT);
  632. return(status);
  633. }