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.

799 lines
21 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. mouhid.c
  5. Abstract:
  6. This module contains the code for the DriverEntry, Unload, IRP_MJ_FLUSH,
  7. and IRP_MJ_INTERNAL_DEVICE_CONTROL dispatch functions for the HID Mouse
  8. Filter Driver.
  9. Note: This is NOT a WDM driver, since it cannot run as a HID mapper on
  10. Memphis (Memphis requires that the mouse to HID mapper be a VXD) and since
  11. it uses EVent logs, which are not part of WDM 1.0.
  12. Environment:
  13. Kernel mode only.
  14. Revision History:
  15. Jan-1997 : Initial writing, Dan Markarian
  16. May-1197 : Kenneth D. Ray : Rewritten as PnP filter for Mouse Class
  17. Notes:
  18. - IOCTL_INTERNAL_MOUSE_DISCONNECT has not been implemented. It's not
  19. needed until the class unload routine is implemented. Right now,
  20. we don't want to allow the mouse class driver to unload.
  21. - Powerfail not implemented.
  22. --*/
  23. #include "mouhid.h"
  24. #include "hidclass.h"
  25. //
  26. // Use the alloc_text pragma to specify the driver initialization routines
  27. // (they can be paged out).
  28. //
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(INIT,DriverEntry)
  31. #pragma alloc_text(INIT,MouHid_GetRegistryParameters)
  32. #pragma alloc_text(PAGE,MouHid_UpdateRegistryProblemFlagsCallback)
  33. #pragma alloc_text(PAGE,MouHid_Unload)
  34. #endif
  35. GLOBALS Globals;
  36. NTSTATUS
  37. DriverEntry(
  38. IN PDRIVER_OBJECT DriverObject,
  39. IN PUNICODE_STRING RegistryPath
  40. )
  41. /*++
  42. Routine Description:
  43. This routine initializes the HID mouse filter driver.
  44. Arguments:
  45. DriverObject - Pointer to driver object created by system.
  46. RegistryPath - Pointer to the Unicode name of the registry path for this
  47. driver.
  48. Return Value:
  49. The function value is the final status from the initialization operation.
  50. --*/
  51. {
  52. NTSTATUS status = STATUS_SUCCESS;
  53. PUNICODE_STRING registryPath = &Globals.RegistryPath;
  54. Print (DBG_SS_TRACE, ("entering DriverEntry\n"));
  55. Print (DBG_SS_INFO, ("Mouse to hid mapper\n"));
  56. RtlZeroMemory (&Globals, sizeof (GLOBALS));
  57. //
  58. // Need to ensure that the registry path is null-terminated.
  59. // Allocate pool to hold a null-terminated copy of the path.
  60. // Safe in paged pool since all registry routines execute at
  61. // PASSIVE_LEVEL.
  62. //
  63. registryPath->MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
  64. registryPath->Length = RegistryPath->Length;
  65. registryPath->Buffer = ExAllocatePool(
  66. PagedPool,
  67. registryPath->MaximumLength
  68. );
  69. if (!registryPath->Buffer) {
  70. Print (DBG_SS_ERROR,
  71. ("Initialize: Couldn't allocate pool for registry path."));
  72. status = STATUS_INSUFFICIENT_RESOURCES;
  73. goto DriverEntryReject;
  74. }
  75. RtlZeroMemory (registryPath->Buffer, registryPath->MaximumLength);
  76. RtlMoveMemory (registryPath->Buffer,
  77. RegistryPath->Buffer,
  78. RegistryPath->Length);
  79. //
  80. // Obtain configuration information for this driver.
  81. //
  82. status = MouHid_GetRegistryParameters();
  83. if (!NT_SUCCESS (status)) {
  84. goto DriverEntryReject;
  85. }
  86. //
  87. // Set up the device driver entry points.
  88. //
  89. DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create;
  90. DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close;
  91. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]=MouHid_IOCTL;
  92. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouHid_PassThrough;
  93. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = MouHid_Flush;
  94. DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_PnP;
  95. DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power;
  96. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = MouHid_SystemControl;
  97. DriverObject->DriverUnload = MouHid_Unload;
  98. DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;
  99. Print (DBG_SS_TRACE, ("exit DriverEntry (0x%x) \n", status));
  100. return status;
  101. DriverEntryReject:
  102. if (registryPath->Buffer) {
  103. ExFreePool (registryPath->Buffer);
  104. }
  105. return status;
  106. }
  107. NTSTATUS
  108. MouHid_PassThrough (
  109. IN PDEVICE_OBJECT DeviceObject,
  110. IN PIRP Irp
  111. )
  112. /*++
  113. Routine Description:
  114. Pass the irp on through
  115. --*/
  116. {
  117. NTSTATUS status;
  118. PDEVICE_EXTENSION data;
  119. data = DeviceObject->DeviceExtension;
  120. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  121. if (!NT_SUCCESS (status)) {
  122. Irp->IoStatus.Status = status;
  123. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  124. return status;
  125. }
  126. IoSkipCurrentIrpStackLocation (Irp);
  127. status = IoCallDriver (data->TopOfStack, Irp);
  128. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  129. return status;
  130. }
  131. VOID
  132. MouHid_Unload(
  133. IN PDRIVER_OBJECT Driver
  134. )
  135. /*++
  136. Routine Description:
  137. Free all the allocated resources associated with this driver.
  138. Arguments:
  139. DriverObject - Pointer to the driver object.
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. PAGED_CODE ();
  145. ASSERT (NULL == Driver->DeviceObject);
  146. Print (DBG_SS_INFO, ("Unload \n"));
  147. //
  148. // Free resources in device extension.
  149. //
  150. ExFreePool (Globals.RegistryPath.Buffer);
  151. return;
  152. }
  153. NTSTATUS
  154. MouHid_Flush (
  155. IN PDEVICE_OBJECT DeviceObject,
  156. IN PIRP Irp
  157. )
  158. /*++
  159. Routine Description:
  160. Respond to flush requests from the mouse class driver. Currently does
  161. nothing but pass IRP down to next lower driver. This routine expects
  162. the current IRQL to be < DISPATCH_LEVEL.
  163. Arguments:
  164. DeviceObject - Pointer to the device object.
  165. Irp - Pointer to the request packet.
  166. Return Value:
  167. NT status code.
  168. --*/
  169. {
  170. PDEVICE_EXTENSION data;
  171. NTSTATUS status;
  172. PIO_STACK_LOCATION stack;
  173. Print (DBG_CALL_INFO, ("Flush \n"));
  174. TRAP();
  175. //
  176. // Get a pointer to the device extension.
  177. //
  178. data = DeviceObject->DeviceExtension;
  179. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  180. if (!NT_SUCCESS (status)) {
  181. Irp->IoStatus.Status = status;
  182. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  183. return status;
  184. }
  185. //
  186. // Send the flush request down to the HID class driver, one for each
  187. // of our mouse device context structures.
  188. //
  189. IoCopyCurrentIrpStackLocationToNext (Irp);
  190. stack = IoGetNextIrpStackLocation (Irp);
  191. stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  192. stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
  193. //
  194. // Fire and forget
  195. //
  196. status = IoCallDriver (data->TopOfStack, Irp);
  197. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  198. return status;
  199. }
  200. NTSTATUS
  201. MouHid_IOCTL (
  202. IN PDEVICE_OBJECT DeviceObject,
  203. IN PIRP Irp
  204. )
  205. /*++
  206. Routine Description:
  207. Respond to queries from the mouse class driver.
  208. The IOCTLs for DISABLE, ENABLE, and QUERY_ATTRIBUTES, expect the current
  209. IRQL to be < DISPATCH_LEVEL.
  210. Arguments:
  211. DeviceObject - Pointer to the device object.
  212. Irp - Pointer to the request packet.
  213. Return Value:
  214. NT status code.
  215. --*/
  216. {
  217. PIO_STACK_LOCATION stack;
  218. NTSTATUS status = STATUS_SUCCESS;
  219. PDEVICE_EXTENSION data;
  220. BOOLEAN completeIt = TRUE;
  221. data = DeviceObject->DeviceExtension;
  222. Irp->IoStatus.Information = 0;
  223. stack = IoGetCurrentIrpStackLocation (Irp);
  224. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  225. if (!NT_SUCCESS (status)) {
  226. Irp->IoStatus.Status = status;
  227. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  228. return status;
  229. }
  230. ASSERT (data->Started ||
  231. (IOCTL_INTERNAL_MOUSE_CONNECT ==
  232. stack->Parameters.DeviceIoControl.IoControlCode));
  233. switch (stack->Parameters.DeviceIoControl.IoControlCode) {
  234. case IOCTL_INTERNAL_MOUSE_CONNECT:
  235. //
  236. // Connect the mouse class device driver to the port driver.
  237. //
  238. Print (DBG_IOCTL_TRACE, ("enter Connect \n"));
  239. //
  240. // Connect a mouse class device driver to the filter driver.
  241. // Only allow one connection.
  242. //
  243. if (NULL != data->ConnectData.ClassService) {
  244. Print (DBG_IOCTL_ERROR, ("ERROR: Multiple connects \n"));
  245. TRAP();
  246. status = STATUS_SHARING_VIOLATION;
  247. break;
  248. } else if (stack->Parameters.DeviceIoControl.InputBufferLength <
  249. sizeof(CONNECT_DATA)) {
  250. Print (DBG_IOCTL_ERROR, ("ERROR: Invalid connect parameter size. \n"));
  251. TRAP();
  252. status = STATUS_INVALID_PARAMETER;
  253. break;
  254. }
  255. //
  256. // Copy the connection parameters to the device extension.
  257. //
  258. data->ConnectData = *(PCONNECT_DATA)
  259. stack->Parameters.DeviceIoControl.Type3InputBuffer;
  260. status = STATUS_SUCCESS;
  261. break;
  262. case IOCTL_INTERNAL_MOUSE_DISCONNECT:
  263. //
  264. // Disconnect a keyboard class device driver from the port driver.
  265. //
  266. Print (DBG_IOCTL_TRACE, ("Disconnect \n"));
  267. TRAP();
  268. //
  269. // Not implemented.
  270. //
  271. // To implement, code the following:
  272. // ---------------------------------
  273. // o ENSURE that we are NOT enabled (mouHidDeviceExt->EnableCount);
  274. // o If we are, then (a) return STATUS_UNSUCCESSFUL, or
  275. // (b) disable all devices immediately; see
  276. // DISABLE IOCTL call for necessary code.
  277. // o SYNCHRONIZE with the mouse read completion routine (must
  278. // protect the callback pointer from being dereferenced when
  279. // it becomes null). Note that no mechanism currently exists
  280. // for this.
  281. // o CLEAR the connection parameters in the device extension;
  282. // ie. mouHidDeviceExt->MouClassObject = NULL;
  283. // mouHidDeviceExt->MouClassCallback = NULL;
  284. // o RELEASE the synchronizing lock.
  285. // o RETURN STATUS_SUCCESS.
  286. //
  287. status = STATUS_NOT_IMPLEMENTED;
  288. break;
  289. case IOCTL_INTERNAL_MOUSE_ENABLE:
  290. //
  291. // Enable keyboard interrupts which really means start the ping pong
  292. // down to hid class.
  293. //
  294. Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use create not enable! \n"));
  295. status = STATUS_NOT_SUPPORTED;
  296. break;
  297. case IOCTL_INTERNAL_MOUSE_DISABLE:
  298. //
  299. // Disable Mouse interrupts which really means stop the ping pongs
  300. // down to hid class.
  301. //
  302. Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use close not Disable! \n"));
  303. status = STATUS_NOT_SUPPORTED;
  304. break;
  305. case IOCTL_MOUSE_QUERY_ATTRIBUTES:
  306. //
  307. // Query the mouse attributes. First check for adequate buffer
  308. // length. Then, copy the mouse attributes from the device
  309. // extension to the output buffer.
  310. //
  311. Print (DBG_IOCTL_TRACE, ("Query Attributes \n"));
  312. if (stack->Parameters.DeviceIoControl.OutputBufferLength <
  313. sizeof(MOUSE_ATTRIBUTES)) {
  314. Print (DBG_IOCTL_ERROR, ("ERROR: Query Attr buffer too small \n"));
  315. TRAP();
  316. status = STATUS_BUFFER_TOO_SMALL;
  317. } else {
  318. //
  319. // Copy the mouse attributes to the buffer.
  320. //
  321. *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
  322. data->Attributes;
  323. Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
  324. status = STATUS_SUCCESS;
  325. }
  326. break;
  327. default:
  328. Print (DBG_IOCTL_ERROR,
  329. ("ERROR: unknown IOCTL: 0x%x \n",
  330. stack->Parameters.DeviceIoControl.IoControlCode));
  331. TRAP();
  332. status = STATUS_INVALID_DEVICE_REQUEST;
  333. break;
  334. }
  335. if (completeIt) {
  336. Irp->IoStatus.Status = status;
  337. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  338. }
  339. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  340. Print (DBG_IOCTL_TRACE, ("IOCTL exit (%x)\n", status));
  341. return status;
  342. }
  343. NTSTATUS
  344. MouHid_GetRegistryParameters()
  345. /*++
  346. Routine Description:
  347. This routine retrieves this driver's parameters from the registry,
  348. including it's base device name.
  349. Return Value:
  350. --*/
  351. {
  352. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  353. UNICODE_STRING parametersPath = {0,0,0};
  354. PWSTR path = NULL;
  355. USHORT queriesPlus1 = 4;
  356. NTSTATUS status = STATUS_SUCCESS;
  357. ULONG useOnlyMice;
  358. ULONG treatAbsoluteAsRelative;
  359. ULONG treatAbsolutePointerAsAbsolute;
  360. PAGED_CODE ();
  361. parametersPath.Buffer = NULL;
  362. //
  363. // Registry path is already null-terminated, so just use it as a string.
  364. //
  365. path = Globals.RegistryPath.Buffer;
  366. //
  367. // Allocate the Rtl query table.
  368. //
  369. parameters = ExAllocatePool(
  370. PagedPool,
  371. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlus1);
  372. if (!parameters) {
  373. Print (DBG_SS_ERROR,
  374. ("Initialize: Couldn't allocate table for Rtl query to parameters for %ws.",
  375. path));
  376. status = STATUS_UNSUCCESSFUL;
  377. goto MouHid_GetRegistryParametersExit;
  378. }
  379. RtlZeroMemory(parameters, sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlus1);
  380. //
  381. // Form a path to this driver's Parameters subkey.
  382. //
  383. parametersPath.MaximumLength = Globals.RegistryPath.Length
  384. + sizeof(L"\\Parameters");
  385. parametersPath.Buffer = ExAllocatePool(PagedPool,
  386. parametersPath.MaximumLength);
  387. if (!parametersPath.Buffer) {
  388. Print (DBG_SS_ERROR,
  389. ("Initialize: Couldn't allocate string for path to parameters for %ws.",
  390. path));
  391. status = STATUS_INSUFFICIENT_RESOURCES;
  392. goto MouHid_GetRegistryParametersExit;
  393. }
  394. //
  395. // Form the parameters path.
  396. //
  397. RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength);
  398. RtlAppendUnicodeToString(&parametersPath, path);
  399. RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
  400. //
  401. // Gather all of the "user specified" information from
  402. // the registry.
  403. //
  404. useOnlyMice = Globals.UseOnlyMice;
  405. parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  406. parameters[0].Name = L"UseOnlyMice";
  407. parameters[0].EntryContext = &useOnlyMice;
  408. parameters[0].DefaultType = REG_DWORD;
  409. parameters[0].DefaultData = &useOnlyMice;
  410. parameters[0].DefaultLength = sizeof(ULONG);
  411. Globals.UseOnlyMice = (BOOLEAN) useOnlyMice;
  412. treatAbsoluteAsRelative = Globals.TreatAbsoluteAsRelative;
  413. parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  414. parameters[1].Name = L"TreatAbsoluteAsRelative";
  415. parameters[1].EntryContext = &treatAbsoluteAsRelative;
  416. parameters[1].DefaultType = REG_DWORD;
  417. parameters[1].DefaultData = &treatAbsoluteAsRelative;
  418. parameters[1].DefaultLength = sizeof(ULONG);
  419. Globals.TreatAbsoluteAsRelative = (BOOLEAN) treatAbsoluteAsRelative;
  420. treatAbsolutePointerAsAbsolute = Globals.TreatAbsolutePointerAsAbsolute;
  421. parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  422. parameters[2].Name = L"TreatAbsolutePointerAsAbsolute";
  423. parameters[2].EntryContext = &treatAbsolutePointerAsAbsolute;
  424. parameters[2].DefaultType = REG_DWORD;
  425. parameters[2].DefaultData = &treatAbsolutePointerAsAbsolute;
  426. parameters[2].DefaultLength = sizeof(ULONG);
  427. Globals.TreatAbsolutePointerAsAbsolute = (BOOLEAN) treatAbsolutePointerAsAbsolute;
  428. status = RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE,
  429. parametersPath.Buffer,
  430. parameters,
  431. NULL,
  432. NULL);
  433. if (!NT_SUCCESS(status)) {
  434. Print (DBG_SS_ERROR,
  435. ("ERROR: Initialize: RtlQueryRegistryValues (0x%x).", status));
  436. Globals.UseOnlyMice =
  437. Globals.TreatAbsoluteAsRelative =
  438. Globals.TreatAbsolutePointerAsAbsolute = 0;
  439. status = STATUS_SUCCESS;
  440. }
  441. ASSERT (!Globals.TreatAbsoluteAsRelative);
  442. ASSERT (!Globals.TreatAbsolutePointerAsAbsolute);
  443. ASSERT (!Globals.UseOnlyMice);
  444. MouHid_GetRegistryParametersExit:
  445. //
  446. // Free the allocated memory before returning.
  447. //
  448. if (parametersPath.Buffer)
  449. ExFreePool(parametersPath.Buffer);
  450. if (parameters)
  451. ExFreePool(parameters);
  452. return status;
  453. }
  454. VOID
  455. MouHid_UpdateRegistryProblemFlags(
  456. IN PDEVICE_EXTENSION Data
  457. )
  458. /*++
  459. Routine Description:
  460. This routine stores the OR'd ProblemFlags value into the registry.
  461. It will queue the write to the registry if this routine is not run
  462. at PASSIVE_LEVEL.
  463. Arguments:
  464. MouHidDeviceExt - HID Mouse Filter Driver device extension.
  465. Return Value:
  466. None.
  467. --*/
  468. {
  469. PIO_WORKITEM item;
  470. NTSTATUS status;
  471. status = IoAcquireRemoveLock (&Data->RemoveLock, MouHid_UpdateRegistryProblemFlags);
  472. if (!NT_SUCCESS (status)) {
  473. //
  474. // Device has gone away, just silently exit
  475. //
  476. return;
  477. }
  478. item = IoAllocateWorkItem (Data->Self);
  479. if (item) {
  480. if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
  481. //
  482. // We are safely at PASSIVE_LEVEL, call callback directly to perform
  483. // this operation immediately.
  484. //
  485. MouHid_UpdateRegistryProblemFlagsCallback (Data->Self, item);
  486. } else {
  487. //
  488. // We are not at PASSIVE_LEVEL, so queue a workitem to handle this
  489. // at a later time.
  490. //
  491. IoQueueWorkItem (item,
  492. MouHid_UpdateRegistryProblemFlagsCallback,
  493. DelayedWorkQueue,
  494. item);
  495. }
  496. }
  497. else {
  498. IoReleaseRemoveLock (&Data->RemoveLock, MouHid_UpdateRegistryProblemFlags);
  499. }
  500. }
  501. VOID
  502. MouHid_UpdateRegistryProblemFlagsCallback (
  503. IN PDEVICE_OBJECT DeviceObject,
  504. IN PIO_WORKITEM Item
  505. )
  506. /*++
  507. Routine Description:
  508. This routine stores the OR'd ProblemFlags value into the registry. This
  509. routine must execute at PASSIVE_LEVEL.
  510. Arguments:
  511. MouHidDeviceExt - HID Mouse Filter Driver device extension.
  512. Return Value:
  513. None.
  514. --*/
  515. {
  516. NTSTATUS status;
  517. PDEVICE_EXTENSION data;
  518. HANDLE hDevNode;
  519. UNICODE_STRING strProblemFlags;
  520. PAGED_CODE ();
  521. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  522. status = IoOpenDeviceRegistryKey (data->PDO,
  523. PLUGPLAY_REGKEY_DEVICE,
  524. STANDARD_RIGHTS_ALL,
  525. &hDevNode);
  526. if (NT_SUCCESS(status)) {
  527. RtlInitUnicodeString (&strProblemFlags, L"ProblemFlags");
  528. ZwSetValueKey (hDevNode,
  529. &strProblemFlags,
  530. 0,
  531. REG_DWORD,
  532. &data->ProblemFlags,
  533. sizeof(data->ProblemFlags));
  534. ZwClose(hDevNode);
  535. }
  536. else {
  537. Print(DBG_SS_ERROR,
  538. ("UpdateRegistryProblemFlags: failed (%x).\n", status));
  539. }
  540. IoReleaseRemoveLock (&data->RemoveLock, MouHid_UpdateRegistryProblemFlags);
  541. IoFreeWorkItem (Item);
  542. }
  543. VOID
  544. MouHid_LogError(
  545. IN PDRIVER_OBJECT DriverObject,
  546. IN NTSTATUS ErrorCode,
  547. IN PWSTR ErrorInsertionString OPTIONAL)
  548. /*++
  549. [DAN]
  550. Routine Description:
  551. Logs an error to the system.
  552. Arguments:
  553. DriverObject - Pointer to driver object reporting the error.
  554. ErrorCode - Indicates the type of error, system or driver-defined.
  555. ErrorInsertionString - Null-terminated Unicode string inserted into error
  556. description, as defined by error code. Must be no
  557. no longer than 50 characters.
  558. Return Value:
  559. None.
  560. --*/
  561. {
  562. ULONG errorInsertionStringSize = 0;
  563. PIO_ERROR_LOG_PACKET errorLogEntry;
  564. ULONG errorLogEntrySize; // [including null]
  565. PWCHAR pWChar;
  566. if (ErrorInsertionString) {
  567. for (pWChar = ErrorInsertionString; *pWChar; pWChar++) {
  568. errorInsertionStringSize += sizeof(WCHAR);
  569. }
  570. errorInsertionStringSize += sizeof(UNICODE_NULL);
  571. }
  572. errorLogEntrySize = sizeof(IO_ERROR_LOG_PACKET) + errorInsertionStringSize;
  573. //
  574. // Log an error.
  575. //
  576. if (errorLogEntrySize <= ERROR_LOG_MAXIMUM_SIZE) {
  577. errorLogEntry = IoAllocateErrorLogEntry(DriverObject,
  578. (UCHAR)errorLogEntrySize);
  579. if (errorLogEntry != NULL) {
  580. RtlZeroMemory(errorLogEntry, errorLogEntrySize);
  581. errorLogEntry->ErrorCode = ErrorCode;
  582. errorLogEntry->FinalStatus = ErrorCode;
  583. errorLogEntry->NumberOfStrings = (ErrorInsertionString) ? 1 : 0;
  584. if (ErrorInsertionString) {
  585. RtlCopyMemory(errorLogEntry->DumpData,
  586. ErrorInsertionString,
  587. errorInsertionStringSize);
  588. }
  589. IoWriteErrorLogEntry(errorLogEntry);
  590. }
  591. }
  592. return;
  593. }