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.

6210 lines
179 KiB

  1. /*++
  2. Copyright (c) 1990, 1991, 1992, 1993, 1994 - 1998 Microsoft Corporation
  3. Module Name:
  4. mouclass.c
  5. Abstract:
  6. Mouse class driver.
  7. Environment:
  8. Kernel mode only.
  9. Notes:
  10. NOTES: (Future/outstanding issues)
  11. - Powerfail not implemented.
  12. - Consolidate duplicate code, where possible and appropriate.
  13. @@BEGIN_DDKSPLIT
  14. Revision History:
  15. May 1997 Kenneth D. Ray: liberal additions of plug and play
  16. @@END_DDKSPLIT
  17. --*/
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <ntddk.h>
  21. //@@BEGIN_DDKSPLIT
  22. #include <ntpoapi.h>
  23. //@@END_DDKSPLIT
  24. #include <hidclass.h>
  25. #include <initguid.h>
  26. #include <kbdmou.h>
  27. #include <moulog.h>
  28. #include "mouclass.h"
  29. #include <poclass.h>
  30. #include <wmistr.h>
  31. #define INITGUID
  32. #include "wdmguid.h"
  33. GLOBALS Globals;
  34. //@@BEGIN_DDKSPLIT
  35. NTSYSAPI
  36. NTSTATUS
  37. NTAPI
  38. ZwPowerInformation(
  39. IN POWER_INFORMATION_LEVEL InformationLevel,
  40. IN PVOID InputBuffer OPTIONAL,
  41. IN ULONG InputBufferLength,
  42. OUT PVOID OutputBuffer OPTIONAL,
  43. IN ULONG OutputBufferLength
  44. );
  45. //@@END_DDKSPLIT
  46. //
  47. // Use the alloc_text pragma to specify the driver initialization routines
  48. // (they can be paged out).
  49. //
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text(INIT,DriverEntry)
  52. #pragma alloc_text(INIT,MouConfiguration)
  53. #pragma alloc_text(PAGE,MouseClassPassThrough)
  54. #pragma alloc_text(PAGE,MouseQueryDeviceKey)
  55. #pragma alloc_text(PAGE,MouDeterminePortsServiced)
  56. #pragma alloc_text(PAGE,MouDeviceMapQueryCallback)
  57. #pragma alloc_text(PAGE,MouSendConnectRequest)
  58. #pragma alloc_text(PAGE,MouseAddDevice)
  59. #pragma alloc_text(PAGE,MouseAddDeviceEx)
  60. #pragma alloc_text(PAGE,MouseClassDeviceControl)
  61. #pragma alloc_text(PAGE,MouseSendIrpSynchronously)
  62. #pragma alloc_text(PAGE,MouCreateClassObject)
  63. #pragma alloc_text(PAGE,MouseClassFindMorePorts)
  64. #pragma alloc_text(PAGE,MouseClassGetWaitWakeEnableState)
  65. #pragma alloc_text(PAGE,MouseClassEnableGlobalPort)
  66. #pragma alloc_text(PAGE,MouseClassPlugPlayNotification)
  67. #pragma alloc_text(PAGE,MouseClassSystemControl)
  68. #pragma alloc_text(PAGE,MouseClassSetWmiDataItem)
  69. #pragma alloc_text(PAGE,MouseClassSetWmiDataBlock)
  70. #pragma alloc_text(PAGE,MouseClassQueryWmiDataBlock)
  71. #pragma alloc_text(PAGE,MouseClassQueryWmiRegInfo)
  72. #pragma alloc_text(PAGE,MouseClassPower)
  73. #pragma alloc_text(PAGE,MouseClassCreateWaitWakeIrpWorker)
  74. #pragma alloc_text(PAGE,MouseClassCreateWaitWakeIrp)
  75. // #pragma alloc_text(PAGE,MouseToggleWaitWakeWorker)
  76. #pragma alloc_text(PAGE,MouseClassUnload)
  77. #endif
  78. #define WMI_CLASS_DRIVER_INFORMATION 0
  79. #define WMI_WAIT_WAKE 1
  80. GUID MouseClassGuid = MSMouse_ClassInformationGuid;
  81. WMIGUIDREGINFO MouseClassWmiGuidList[] =
  82. {
  83. {
  84. &MouseClassGuid,
  85. 1,
  86. 0 // Mouse class driver information
  87. },
  88. {
  89. &GUID_POWER_DEVICE_WAKE_ENABLE,
  90. 1,
  91. 0
  92. }
  93. };
  94. NTSTATUS
  95. DriverEntry(
  96. IN PDRIVER_OBJECT DriverObject,
  97. IN PUNICODE_STRING RegistryPath
  98. )
  99. /*++
  100. Routine Description:
  101. This routine initializes the mouse class driver.
  102. Arguments:
  103. DriverObject - Pointer to driver object created by system.
  104. RegistryPath - Pointer to the Unicode name of the registry path
  105. for this driver.
  106. Return Value:
  107. The function value is the final status from the initialization operation.
  108. --*/
  109. {
  110. NTSTATUS status = STATUS_SUCCESS;
  111. PDEVICE_EXTENSION deviceExtension = NULL;
  112. PDEVICE_OBJECT classDeviceObject = NULL;
  113. ULONG dumpCount = 0;
  114. ULONG dumpData[DUMP_COUNT];
  115. ULONG i;
  116. ULONG numPorts;
  117. ULONG uniqueErrorValue;
  118. UNICODE_STRING basePortName;
  119. UNICODE_STRING fullPortName;
  120. WCHAR basePortBuffer[NAME_MAX];
  121. PWCHAR fullClassName = NULL;
  122. PFILE_OBJECT file;
  123. PLIST_ENTRY entry;
  124. MouPrint((1,"\n\nMOUCLASS-MouseClassInitialize: enter\n"));
  125. //
  126. // Zero-initialize various structures.
  127. //
  128. RtlZeroMemory(&Globals, sizeof(GLOBALS));
  129. Globals.Debug = DEFAULT_DEBUG_LEVEL;
  130. InitializeListHead(&Globals.LegacyDeviceList);
  131. fullPortName.MaximumLength = 0;
  132. ExInitializeFastMutex (&Globals.Mutex);
  133. Globals.BaseClassName.Buffer = Globals.BaseClassBuffer;
  134. Globals.BaseClassName.Length = 0;
  135. Globals.BaseClassName.MaximumLength = NAME_MAX * sizeof(WCHAR);
  136. RtlZeroMemory(basePortBuffer, NAME_MAX * sizeof(WCHAR));
  137. basePortName.Buffer = basePortBuffer;
  138. basePortName.Length = 0;
  139. basePortName.MaximumLength = NAME_MAX * sizeof(WCHAR);
  140. //
  141. // Need to ensure that the registry path is null-terminated.
  142. // Allocate pool to hold a null-terminated copy of the path.
  143. //
  144. Globals.RegistryPath.Length = RegistryPath->Length;
  145. Globals.RegistryPath.MaximumLength = RegistryPath->Length
  146. + sizeof (UNICODE_NULL);
  147. Globals.RegistryPath.Buffer = ExAllocatePool(
  148. NonPagedPool,
  149. Globals.RegistryPath.MaximumLength);
  150. if (!Globals.RegistryPath.Buffer) {
  151. MouPrint((
  152. 1,
  153. "MOUCLASS-MouseClassInitialize: Couldn't allocate pool for registry path\n"
  154. ));
  155. status = STATUS_UNSUCCESSFUL;
  156. dumpData[0] = (ULONG) RegistryPath->Length + sizeof(UNICODE_NULL);
  157. MouseClassLogError (DriverObject,
  158. MOUCLASS_INSUFFICIENT_RESOURCES,
  159. MOUSE_ERROR_VALUE_BASE + 2,
  160. STATUS_UNSUCCESSFUL,
  161. 1,
  162. dumpData,
  163. 0);
  164. goto MouseClassInitializeExit;
  165. }
  166. RtlMoveMemory(Globals.RegistryPath.Buffer,
  167. RegistryPath->Buffer,
  168. RegistryPath->Length);
  169. Globals.RegistryPath.Buffer [RegistryPath->Length / sizeof (WCHAR)] = L'\0';
  170. //
  171. // Get the configuration information for this driver.
  172. //
  173. MouConfiguration();
  174. //
  175. // If there is only one class device object then create it as the grand
  176. // master device object. Otherwise let all the FDOs also double as the
  177. // class DO.
  178. //
  179. if (!Globals.ConnectOneClassToOnePort) {
  180. status = MouCreateClassObject (DriverObject,
  181. &Globals.InitExtension,
  182. &classDeviceObject,
  183. &fullClassName,
  184. TRUE);
  185. if (!NT_SUCCESS (status)) {
  186. // ISSUE: should log an error that we could not create a GM
  187. goto MouseClassInitializeExit;
  188. }
  189. deviceExtension = (PDEVICE_EXTENSION)classDeviceObject->DeviceExtension;
  190. Globals.GrandMaster = deviceExtension;
  191. deviceExtension->PnP = FALSE;
  192. MouseAddDeviceEx (deviceExtension, fullClassName, NULL);
  193. ASSERT (NULL != fullClassName);
  194. ExFreePool (fullClassName);
  195. fullClassName = NULL;
  196. classDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  197. }
  198. //
  199. // Set up the base device name for the associated port device.
  200. // It is the same as the base class name, with "Class" replaced
  201. // by "Port".
  202. //
  203. RtlCopyUnicodeString(&basePortName, &Globals.BaseClassName);
  204. basePortName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
  205. RtlAppendUnicodeToString(&basePortName, L"Port");
  206. //
  207. // Determine how many (static) ports this class driver is to service.
  208. //
  209. //
  210. // If this returns zero, then all ports will be dynamically PnP added later
  211. //
  212. MouDeterminePortsServiced(&basePortName, &numPorts);
  213. ASSERT (numPorts <= MAXIMUM_PORTS_SERVICED);
  214. MouPrint((
  215. 1,
  216. "MOUCLASS-MouseClassInitialize: Will service %d port devices\n",
  217. numPorts
  218. ));
  219. //
  220. // Set up space for the full device object name for the ports.
  221. //
  222. RtlInitUnicodeString(&fullPortName, NULL);
  223. fullPortName.MaximumLength = sizeof(L"\\Device\\")
  224. + basePortName.Length
  225. + sizeof (UNICODE_NULL);
  226. fullPortName.Buffer = ExAllocatePool(PagedPool,
  227. fullPortName.MaximumLength);
  228. if (!fullPortName.Buffer) {
  229. MouPrint((
  230. 1,
  231. "MOUCLASS-MouseClassInitialize: Couldn't allocate string for port device object name\n"
  232. ));
  233. status = STATUS_UNSUCCESSFUL;
  234. dumpData[0] = (ULONG) fullPortName.MaximumLength;
  235. MouseClassLogError (DriverObject,
  236. MOUCLASS_INSUFFICIENT_RESOURCES,
  237. MOUSE_ERROR_VALUE_BASE + 8,
  238. status,
  239. 1,
  240. dumpData,
  241. 0);
  242. goto MouseClassInitializeExit;
  243. }
  244. RtlZeroMemory(fullPortName.Buffer, fullPortName.MaximumLength);
  245. RtlAppendUnicodeToString(&fullPortName, L"\\Device\\");
  246. RtlAppendUnicodeToString(&fullPortName, basePortName.Buffer);
  247. RtlAppendUnicodeToString(&fullPortName, L"0");
  248. //
  249. // Set up the class device object(s) to handle the associated
  250. // port devices.
  251. //
  252. for (i = 0; (i < Globals.PortsServiced) && (i < numPorts); i++) {
  253. //
  254. // Append the suffix to the device object name string. E.g., turn
  255. // \Device\PointerClass into \Device\PointerClass0. Then attempt
  256. // to create the device object. If the device object already
  257. // exists increment the suffix and try again.
  258. //
  259. fullPortName.Buffer[(fullPortName.Length / sizeof(WCHAR)) - 1]
  260. = L'0' + (WCHAR) i;
  261. //
  262. // Create the class device object.
  263. //
  264. status = MouCreateClassObject (DriverObject,
  265. &Globals.InitExtension,
  266. &classDeviceObject,
  267. &fullClassName,
  268. TRUE);
  269. if (!NT_SUCCESS(status)) {
  270. MouseClassLogError (DriverObject,
  271. MOUCLASS_INSUFFICIENT_RESOURCES,
  272. MOUSE_ERROR_VALUE_BASE + 8,
  273. status,
  274. 0,
  275. NULL,
  276. 0);
  277. continue;
  278. }
  279. deviceExtension = (PDEVICE_EXTENSION)classDeviceObject->DeviceExtension;
  280. deviceExtension->PnP = FALSE;
  281. classDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  282. //
  283. // Connect to the port device.
  284. //
  285. status = IoGetDeviceObjectPointer (&fullPortName,
  286. FILE_READ_ATTRIBUTES,
  287. &file,
  288. &deviceExtension->TopPort);
  289. //
  290. // In case of failure, just delete the device and continue
  291. //
  292. if (status != STATUS_SUCCESS) {
  293. // ISSUE: log error
  294. MouseClassDeleteLegacyDevice (deviceExtension);
  295. continue;
  296. }
  297. classDeviceObject->StackSize = 1 + deviceExtension->TopPort->StackSize;
  298. status = MouseAddDeviceEx (deviceExtension, fullClassName, file);
  299. if (Globals.GrandMaster == NULL) {
  300. deviceExtension->File = file;
  301. }
  302. if (fullClassName) {
  303. ExFreePool(fullClassName);
  304. fullClassName = NULL;
  305. }
  306. if (!NT_SUCCESS (status)) {
  307. if (Globals.GrandMaster == NULL) {
  308. if (deviceExtension->File) {
  309. file = deviceExtension->File;
  310. deviceExtension->File = NULL;
  311. }
  312. }
  313. else {
  314. PPORT port;
  315. ExAcquireFastMutex (&Globals.Mutex);
  316. file = Globals.AssocClassList[deviceExtension->UnitId].File;
  317. Globals.AssocClassList[deviceExtension->UnitId].File = NULL;
  318. Globals.AssocClassList[deviceExtension->UnitId].Free = TRUE;
  319. Globals.AssocClassList[deviceExtension->UnitId].Port = NULL;
  320. ExReleaseFastMutex (&Globals.Mutex);
  321. }
  322. if (file) {
  323. ObDereferenceObject (file);
  324. }
  325. MouseClassDeleteLegacyDevice (deviceExtension);
  326. continue;
  327. }
  328. //
  329. // Store this device object in a linked list regardless if we are in
  330. // grand master mode or not
  331. //
  332. InsertTailList (&Globals.LegacyDeviceList, &deviceExtension->Link);
  333. } // for
  334. //
  335. // If we had any failures creating legacy device objects, we must still
  336. // succeed b/c we need to service pnp ports later on
  337. //
  338. status = STATUS_SUCCESS;
  339. //
  340. // Count the number of legacy device ports we created
  341. //
  342. for (entry = Globals.LegacyDeviceList.Flink;
  343. entry != &Globals.LegacyDeviceList;
  344. entry = entry->Flink) {
  345. Globals.NumberLegacyPorts++;
  346. }
  347. MouseClassInitializeExit:
  348. //
  349. // Free the unicode strings.
  350. //
  351. if (fullPortName.MaximumLength != 0) {
  352. ExFreePool(fullPortName.Buffer);
  353. }
  354. if (fullClassName) {
  355. ExFreePool(fullClassName);
  356. }
  357. if (NT_SUCCESS (status)) {
  358. IoRegisterDriverReinitialization(DriverObject,
  359. MouseClassFindMorePorts,
  360. NULL);
  361. //
  362. // Set up the device driver entry points.
  363. //
  364. DriverObject->MajorFunction[IRP_MJ_CREATE] = MouseClassCreate;
  365. DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassClose;
  366. DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassRead;
  367. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = MouseClassFlush;
  368. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouseClassDeviceControl;
  369. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  370. MouseClassPassThrough;
  371. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MouseClassCleanup;
  372. DriverObject->MajorFunction[IRP_MJ_PNP] = MousePnP;
  373. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = MouseClassSystemControl;
  374. DriverObject->MajorFunction[IRP_MJ_POWER] = MouseClassPower;
  375. DriverObject->DriverExtension->AddDevice = MouseAddDevice;
  376. // DriverObject->DriverUnload = MouseClassUnload;
  377. status = STATUS_SUCCESS;
  378. } else {
  379. //
  380. // Clean up all the pool we created and delete the GM if it exists
  381. //
  382. if (Globals.RegistryPath.Buffer != NULL) {
  383. ExFreePool (Globals.RegistryPath.Buffer);
  384. Globals.RegistryPath.Buffer = NULL;
  385. }
  386. if (Globals.AssocClassList) {
  387. ExFreePool (Globals.AssocClassList);
  388. Globals.AssocClassList = NULL;
  389. }
  390. if (Globals.GrandMaster) {
  391. MouseClassDeleteLegacyDevice(Globals.GrandMaster);
  392. Globals.GrandMaster = NULL;
  393. }
  394. }
  395. MouPrint((1,"MOUCLASS-MouseClassInitialize: exit, 0x%x\n", status));
  396. return status;
  397. }
  398. NTSTATUS
  399. MouseClassPassThrough(
  400. IN PDEVICE_OBJECT DeviceObject,
  401. IN PIRP Irp
  402. )
  403. /*++
  404. Routine Description:
  405. Passes a request on to the lower driver.
  406. --*/
  407. {
  408. //
  409. // Pass the IRP to the target
  410. //
  411. IoSkipCurrentIrpStackLocation (Irp);
  412. return IoCallDriver (
  413. ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->TopPort,
  414. Irp);
  415. }
  416. NTSTATUS
  417. MouseQueryDeviceKey (
  418. IN HANDLE Handle,
  419. IN PWCHAR ValueNameString,
  420. OUT PVOID Data,
  421. IN ULONG DataLength
  422. )
  423. {
  424. NTSTATUS status;
  425. UNICODE_STRING valueName;
  426. ULONG length;
  427. PKEY_VALUE_FULL_INFORMATION fullInfo;
  428. PAGED_CODE();
  429. RtlInitUnicodeString (&valueName, ValueNameString);
  430. length = sizeof (KEY_VALUE_FULL_INFORMATION)
  431. + valueName.MaximumLength
  432. + DataLength;
  433. fullInfo = ExAllocatePool (PagedPool, length);
  434. if (fullInfo) {
  435. status = ZwQueryValueKey (Handle,
  436. &valueName,
  437. KeyValueFullInformation,
  438. fullInfo,
  439. length,
  440. &length);
  441. if (NT_SUCCESS (status)) {
  442. ASSERT (DataLength == fullInfo->DataLength);
  443. RtlCopyMemory (Data,
  444. ((PUCHAR) fullInfo) + fullInfo->DataOffset,
  445. fullInfo->DataLength);
  446. }
  447. ExFreePool (fullInfo);
  448. } else {
  449. status = STATUS_NO_MEMORY;
  450. }
  451. return status;
  452. }
  453. NTSTATUS
  454. MouseAddDevice(
  455. IN PDRIVER_OBJECT DriverObject,
  456. IN PDEVICE_OBJECT PhysicalDeviceObject
  457. )
  458. /*++
  459. Description:
  460. The plug play entry point "AddDevice"
  461. --*/
  462. {
  463. NTSTATUS status;
  464. PDEVICE_OBJECT fdo;
  465. PDEVICE_EXTENSION port;
  466. PWCHAR fullClassName = NULL;
  467. POWER_STATE state;
  468. PAGED_CODE ();
  469. status = MouCreateClassObject (DriverObject,
  470. &Globals.InitExtension,
  471. &fdo,
  472. &fullClassName,
  473. FALSE);
  474. if (!NT_SUCCESS (status)) {
  475. return status;
  476. }
  477. port = (PDEVICE_EXTENSION) fdo->DeviceExtension;
  478. port->TopPort = IoAttachDeviceToDeviceStack (fdo, PhysicalDeviceObject);
  479. if (port->TopPort == NULL) {
  480. PIO_ERROR_LOG_PACKET errorLogEntry;
  481. //
  482. // Not good; in only extreme cases will this fail
  483. //
  484. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  485. IoAllocateErrorLogEntry (DriverObject,
  486. (UCHAR) sizeof(IO_ERROR_LOG_PACKET));
  487. if (errorLogEntry) {
  488. errorLogEntry->ErrorCode = MOUCLASS_ATTACH_DEVICE_FAILED;
  489. errorLogEntry->DumpDataSize = 0;
  490. errorLogEntry->SequenceNumber = 0;
  491. errorLogEntry->MajorFunctionCode = 0;
  492. errorLogEntry->IoControlCode = 0;
  493. errorLogEntry->RetryCount = 0;
  494. errorLogEntry->UniqueErrorValue = 0;
  495. errorLogEntry->FinalStatus = STATUS_DEVICE_NOT_CONNECTED;
  496. IoWriteErrorLogEntry (errorLogEntry);
  497. }
  498. IoDeleteDevice (fdo);
  499. return STATUS_DEVICE_NOT_CONNECTED;
  500. }
  501. port->PDO = PhysicalDeviceObject;
  502. port->PnP = TRUE;
  503. port->Started = FALSE;
  504. port->DeviceState = PowerDeviceD0;
  505. port->SystemState = PowerSystemWorking;
  506. state.DeviceState = PowerDeviceD0;
  507. PoSetPowerState (fdo, DevicePowerState, state);
  508. port->MinDeviceWakeState = PowerDeviceUnspecified;
  509. port->MinSystemWakeState = PowerSystemUnspecified;
  510. port->WaitWakeEnabled = FALSE;
  511. fdo->Flags |= DO_POWER_PAGABLE;
  512. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  513. status = IoRegisterDeviceInterface (PhysicalDeviceObject,
  514. (LPGUID)&GUID_CLASS_MOUSE,
  515. NULL,
  516. &port->SymbolicLinkName );
  517. if (!NT_SUCCESS (status)) {
  518. IoDetachDevice (port->TopPort);
  519. port->TopPort = NULL;
  520. IoDeleteDevice (fdo);
  521. } else {
  522. status = MouseAddDeviceEx (port, fullClassName, NULL);
  523. }
  524. if (fullClassName) {
  525. ExFreePool(fullClassName);
  526. }
  527. return status;
  528. }
  529. void
  530. MouseClassGetWaitWakeEnableState(
  531. IN PDEVICE_EXTENSION Data
  532. )
  533. {
  534. HANDLE hKey;
  535. NTSTATUS status;
  536. ULONG tmp;
  537. BOOLEAN wwEnableFound;
  538. PAGED_CODE();
  539. hKey = NULL;
  540. wwEnableFound = FALSE;
  541. status = IoOpenDeviceRegistryKey (Data->PDO,
  542. PLUGPLAY_REGKEY_DEVICE,
  543. STANDARD_RIGHTS_ALL,
  544. &hKey);
  545. if (NT_SUCCESS (status)) {
  546. status = MouseQueryDeviceKey (hKey,
  547. MOUSE_WAIT_WAKE_ENABLE,
  548. &tmp,
  549. sizeof (tmp));
  550. if (NT_SUCCESS (status)) {
  551. wwEnableFound = TRUE;
  552. Data->WaitWakeEnabled = (tmp ? TRUE : FALSE);
  553. }
  554. ZwClose (hKey);
  555. hKey = NULL;
  556. }
  557. //@@BEGIN_DDKSPLIT
  558. if (wwEnableFound == FALSE && Data->WaitWakeEnabled == FALSE) {
  559. RTL_OSVERSIONINFOEXW osVerInfo;
  560. ULONGLONG mask = 0;
  561. //
  562. // Only auto enable wait wake on workstation installs (pro and personal)
  563. //
  564. RtlZeroMemory(&osVerInfo, sizeof(osVerInfo));
  565. osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
  566. osVerInfo.wProductType = VER_NT_WORKSTATION;
  567. VER_SET_CONDITION(mask, VER_PRODUCT_TYPE, VER_EQUAL);
  568. if (NT_SUCCESS(RtlVerifyVersionInfo(&osVerInfo,
  569. VER_PRODUCT_TYPE,
  570. mask))) {
  571. SYSTEM_POWER_CAPABILITIES sysPowerCaps;
  572. RtlZeroMemory(&sysPowerCaps, sizeof(sysPowerCaps));
  573. status = ZwPowerInformation (SystemPowerCapabilities,
  574. NULL,
  575. 0,
  576. &sysPowerCaps,
  577. sizeof(SYSTEM_POWER_CAPABILITIES));
  578. if (NT_SUCCESS (status)) {
  579. SYSTEM_POWER_STATE maxSysWake;
  580. //
  581. // Get the deepest sleep state the machine is capable of
  582. //
  583. if (sysPowerCaps.SystemS3) {
  584. maxSysWake = PowerSystemSleeping3;
  585. }
  586. else if (sysPowerCaps.SystemS2) {
  587. maxSysWake = PowerSystemSleeping2;
  588. }
  589. else if (sysPowerCaps.SystemS1) {
  590. maxSysWake = PowerSystemSleeping1;
  591. }
  592. else {
  593. maxSysWake = PowerSystemUnspecified;
  594. }
  595. //
  596. // See if the system wake state for the device is as deep (or
  597. // deeper) than the deepest system sleep state. This will
  598. // prevent us from auto enabling wake and then only allowing the
  599. // machine to go into S1 instead of S3 (which is the case on a
  600. // lot of laptops).
  601. //
  602. if (Data->MinSystemWakeState >= maxSysWake) {
  603. //
  604. // Success!
  605. //
  606. Data->WaitWakeEnabled = TRUE;
  607. }
  608. }
  609. }
  610. }
  611. //@@END_DDKSPLIT
  612. }
  613. NTSTATUS
  614. MouseAddDeviceEx(
  615. IN PDEVICE_EXTENSION ClassData,
  616. IN PWCHAR FullClassName,
  617. IN PFILE_OBJECT File
  618. )
  619. /*++ Description:
  620. *
  621. * Called whenever the Mouse Class driver is loaded to control a device.
  622. *
  623. * Two possible reasons.
  624. * 1) Plug and Play found a PNP enumerated Mouse.
  625. * 2) Driver Entry found this device via old crusty legacy reasons.
  626. *
  627. * Arguments:
  628. *
  629. *
  630. * Return:
  631. *
  632. * STATUS_SUCCESS - if successful STATUS_UNSUCCESSFUL - otherwise
  633. *
  634. * --*/
  635. {
  636. NTSTATUS errorCode = STATUS_SUCCESS;
  637. NTSTATUS status = STATUS_SUCCESS;
  638. PDEVICE_EXTENSION trueClassData;
  639. PPORT classDataList;
  640. ULONG uniqueErrorValue = 0;
  641. PIO_ERROR_LOG_PACKET errorLogEntry;
  642. ULONG dumpCount = 0;
  643. ULONG dumpData[DUMP_COUNT];
  644. ULONG i;
  645. PAGED_CODE ();
  646. KeInitializeSpinLock (&ClassData->WaitWakeSpinLock);
  647. if (Globals.ConnectOneClassToOnePort) {
  648. ASSERT (NULL == Globals.GrandMaster);
  649. trueClassData = ClassData;
  650. } else {
  651. trueClassData = Globals.GrandMaster;
  652. }
  653. ClassData->TrueClassDevice = trueClassData->Self;
  654. if ((Globals.GrandMaster != ClassData) &&
  655. (Globals.GrandMaster == trueClassData)) {
  656. //
  657. // We have a grand master, and are adding a port device object.
  658. //
  659. //
  660. // Connect to port device.
  661. //
  662. status = MouSendConnectRequest(ClassData, MouseClassServiceCallback);
  663. //
  664. // Link this class device object in the list of class devices object
  665. // associated with the true class device object
  666. //
  667. ExAcquireFastMutex (&Globals.Mutex);
  668. for (i=0; i < Globals.NumAssocClass; i++) {
  669. if (Globals.AssocClassList[i].Free) {
  670. Globals.AssocClassList[i].Free = FALSE;
  671. break;
  672. }
  673. }
  674. if (i == Globals.NumAssocClass) {
  675. classDataList = ExAllocatePool (
  676. NonPagedPool,
  677. (Globals.NumAssocClass + 1) * sizeof (PORT));
  678. if (NULL == classDataList) {
  679. status = STATUS_INSUFFICIENT_RESOURCES;
  680. // ISSUE: log error
  681. ExReleaseFastMutex (&Globals.Mutex);
  682. goto MouseAddDeviceExReject;
  683. }
  684. RtlZeroMemory (classDataList,
  685. (Globals.NumAssocClass + 1) * sizeof (PORT));
  686. if (0 != Globals.NumAssocClass) {
  687. RtlCopyMemory (classDataList,
  688. Globals.AssocClassList,
  689. Globals.NumAssocClass * sizeof (PORT));
  690. ExFreePool (Globals.AssocClassList);
  691. }
  692. Globals.AssocClassList = classDataList;
  693. Globals.NumAssocClass++;
  694. }
  695. ClassData->UnitId = i;
  696. Globals.AssocClassList [i].Port = ClassData;
  697. Globals.AssocClassList [i].File = File;
  698. trueClassData->Self->StackSize =
  699. MAX (trueClassData->Self->StackSize, ClassData->Self->StackSize);
  700. ExReleaseFastMutex (&Globals.Mutex);
  701. } else if ((Globals.GrandMaster != ClassData) &&
  702. (ClassData == trueClassData)) {
  703. //
  704. // Connect to port device.
  705. //
  706. status = MouSendConnectRequest(ClassData, MouseClassServiceCallback);
  707. ASSERT (STATUS_SUCCESS == status);
  708. }
  709. if (ClassData == trueClassData) {
  710. ASSERT (NULL != FullClassName);
  711. //
  712. // Load the device map information into the registry so
  713. // that setup can determine which mouse class driver is active.
  714. //
  715. status = RtlWriteRegistryValue(
  716. RTL_REGISTRY_DEVICEMAP,
  717. Globals.BaseClassName.Buffer, // key name
  718. FullClassName, // value name
  719. REG_SZ,
  720. Globals.RegistryPath.Buffer, // The value
  721. Globals.RegistryPath.Length + sizeof(UNICODE_NULL));
  722. if (!NT_SUCCESS(status)) {
  723. MouPrint((
  724. 1,
  725. "MOUCLASS-MouseClassInitialize: Could not store %ws in DeviceMap\n",
  726. FullClassName));
  727. MouseClassLogError (ClassData,
  728. MOUCLASS_NO_DEVICEMAP_CREATED,
  729. MOUSE_ERROR_VALUE_BASE + 14,
  730. status,
  731. 0,
  732. NULL,
  733. 0);
  734. } else {
  735. MouPrint((
  736. 1,
  737. "MOUCLASS-MouseClassInitialize: Stored %ws in DeviceMap\n",
  738. FullClassName));
  739. }
  740. }
  741. return status;
  742. MouseAddDeviceExReject:
  743. //
  744. // Some part of the initialization failed. Log an error, and
  745. // clean up the resources for the failed part of the initialization.
  746. //
  747. if (errorCode != STATUS_SUCCESS) {
  748. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  749. IoAllocateErrorLogEntry(
  750. trueClassData->Self,
  751. (UCHAR) (sizeof(IO_ERROR_LOG_PACKET)
  752. + (dumpCount * sizeof(ULONG)))
  753. );
  754. if (errorLogEntry != NULL) {
  755. errorLogEntry->ErrorCode = errorCode;
  756. errorLogEntry->DumpDataSize = (USHORT) (dumpCount * sizeof (ULONG));
  757. errorLogEntry->SequenceNumber = 0;
  758. errorLogEntry->MajorFunctionCode = 0;
  759. errorLogEntry->IoControlCode = 0;
  760. errorLogEntry->RetryCount = 0;
  761. errorLogEntry->UniqueErrorValue = uniqueErrorValue;
  762. errorLogEntry->FinalStatus = status;
  763. for (i = 0; i < dumpCount; i++)
  764. errorLogEntry->DumpData[i] = dumpData[i];
  765. IoWriteErrorLogEntry(errorLogEntry);
  766. }
  767. }
  768. return status;
  769. }
  770. VOID
  771. MouseClassCancel(
  772. IN PDEVICE_OBJECT DeviceObject,
  773. IN PIRP Irp
  774. )
  775. /*++
  776. Routine Description:
  777. This routine is the class cancellation routine. It is
  778. called from the I/O system when a request is cancelled. Read requests
  779. are currently the only cancellable requests.
  780. N.B. The cancel spinlock is already held upon entry to this routine.
  781. Arguments:
  782. DeviceObject - Pointer to class device object.
  783. Irp - Pointer to the request packet to be cancelled.
  784. Return Value:
  785. None.
  786. --*/
  787. {
  788. PDEVICE_EXTENSION deviceExtension;
  789. KIRQL irql;
  790. deviceExtension = DeviceObject->DeviceExtension;
  791. //
  792. // Release the global cancel spinlock.
  793. // Do this while not holding any other spinlocks so that we exit at the
  794. // right IRQL.
  795. //
  796. IoReleaseCancelSpinLock (Irp->CancelIrql);
  797. //
  798. // Dequeue and complete the IRP. The enqueue and dequeue functions
  799. // synchronize properly so that if this cancel routine is called,
  800. // the dequeue is safe and only the cancel routine will complete the IRP.
  801. //
  802. KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
  803. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  804. KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
  805. //
  806. // Complete the IRP. This is a call outside the driver, so all spinlocks
  807. // must be released by this point.
  808. //
  809. Irp->IoStatus.Status = STATUS_CANCELLED;
  810. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  811. //
  812. // Remove the lock we took in the read handler
  813. //
  814. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  815. }
  816. VOID
  817. MouseClassCleanupQueue (
  818. IN PDEVICE_OBJECT DeviceObject,
  819. IN PDEVICE_EXTENSION DeviceExtension,
  820. IN PFILE_OBJECT FileObject
  821. )
  822. /*++
  823. Routine Description:
  824. This does the work of MouseClassCleanup so that we can also do that work
  825. during remove device for when the grand master isn't enabled.
  826. --*/
  827. {
  828. PIRP irp;
  829. LIST_ENTRY listHead, *entry;
  830. KIRQL irql;
  831. InitializeListHead (&listHead);
  832. KeAcquireSpinLock (&DeviceExtension->SpinLock, &irql);
  833. do {
  834. irp = MouseClassDequeueReadByFileObject (DeviceExtension, FileObject);
  835. if (irp) {
  836. irp->IoStatus.Status = STATUS_CANCELLED;
  837. irp->IoStatus.Information = 0;
  838. InsertTailList (&listHead, &irp->Tail.Overlay.ListEntry);
  839. }
  840. } while (irp != NULL);
  841. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  842. //
  843. // Complete these irps outside of the spin lock
  844. //
  845. while (! IsListEmpty (&listHead)) {
  846. entry = RemoveHeadList (&listHead);
  847. irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
  848. IoCompleteRequest (irp, IO_NO_INCREMENT);
  849. IoReleaseRemoveLock (&DeviceExtension->RemoveLock, irp);
  850. }
  851. }
  852. NTSTATUS
  853. MouseClassCleanup(
  854. IN PDEVICE_OBJECT DeviceObject,
  855. IN PIRP Irp
  856. )
  857. /*++
  858. Routine Description:
  859. This routine is the dispatch routine for cleanup requests.
  860. All requests queued to the mouse class device (on behalf of
  861. the thread for whom the cleanup request was generated) are
  862. completed with STATUS_CANCELLED.
  863. Arguments:
  864. DeviceObject - Pointer to class device object.
  865. Irp - Pointer to the request packet.
  866. Return Value:
  867. Status is returned.
  868. --*/
  869. {
  870. PDEVICE_EXTENSION deviceExtension;
  871. PIO_STACK_LOCATION irpSp;
  872. MouPrint((2,"MOUCLASS-MouseClassCleanup: enter\n"));
  873. deviceExtension = DeviceObject->DeviceExtension;
  874. //
  875. // Get a pointer to the current stack location for this request.
  876. //
  877. irpSp = IoGetCurrentIrpStackLocation(Irp);
  878. //
  879. // If the file object is the FileTrustedForRead, then the cleanup
  880. // request is being executed by the trusted subsystem. Since the
  881. // trusted subsystem is the only one with sufficient privilege to make
  882. // Read requests to the driver, and since only Read requests get queued
  883. // to the device queue, a cleanup request from the trusted subsystem is
  884. // handled by cancelling all queued requests.
  885. //
  886. // If not, there is no cleanup work to perform
  887. // (only read requests can be cancelled).
  888. //
  889. if (IS_TRUSTED_FILE_FOR_READ (irpSp->FileObject)) {
  890. MouseClassCleanupQueue (DeviceObject, deviceExtension, irpSp->FileObject);
  891. }
  892. //
  893. // Complete the cleanup request with STATUS_SUCCESS.
  894. //
  895. Irp->IoStatus.Status = STATUS_SUCCESS;
  896. Irp->IoStatus.Information = 0;
  897. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  898. MouPrint((2,"MOUCLASS-MouseClassCleanup: exit\n"));
  899. return(STATUS_SUCCESS);
  900. }
  901. NTSTATUS
  902. MouseClassDeviceControl(
  903. IN PDEVICE_OBJECT DeviceObject,
  904. IN PIRP Irp
  905. )
  906. /*++
  907. Routine Description:
  908. This routine is the dispatch routine for device control requests.
  909. All device control subfunctions are passed, asynchronously, to the
  910. connected port driver for processing and completion.
  911. Arguments:
  912. DeviceObject - Pointer to class device object.
  913. Irp - Pointer to the request packet.
  914. Return Value:
  915. Status is returned.
  916. --*/
  917. {
  918. PIO_STACK_LOCATION stack;
  919. PDEVICE_EXTENSION deviceExtension;
  920. PDEVICE_EXTENSION port;
  921. NTSTATUS status = STATUS_SUCCESS;
  922. ULONG unitId;
  923. ULONG ioctl;
  924. PAGED_CODE ();
  925. MouPrint((2,"MOUCLASS-MouseClassDeviceControl: enter\n"));
  926. //
  927. // Get a pointer to the device extension.
  928. //
  929. deviceExtension = DeviceObject->DeviceExtension;
  930. //
  931. // Get a pointer to the current parameters for this request. The
  932. // information is contained in the current stack location.
  933. //
  934. stack = IoGetCurrentIrpStackLocation(Irp);
  935. status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
  936. if (!NT_SUCCESS (status)) {
  937. Irp->IoStatus.Status = status;
  938. Irp->IoStatus.Information = 0;
  939. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  940. return status;
  941. }
  942. //
  943. // Check for adequate input buffer length. The input buffer
  944. // should, at a minimum, contain the unit ID specifying one of
  945. // the connected port devices. If there is no input buffer (i.e.,
  946. // the input buffer length is zero), then we assume the unit ID
  947. // is zero (for backwards compatibility).
  948. //
  949. unitId = 0;
  950. switch (ioctl = stack->Parameters.DeviceIoControl.IoControlCode) {
  951. case IOCTL_MOUSE_QUERY_ATTRIBUTES:
  952. if (stack->Parameters.DeviceIoControl.InputBufferLength == 0) {
  953. unitId = 0;
  954. } else if (stack->Parameters.DeviceIoControl.InputBufferLength <
  955. sizeof(MOUSE_UNIT_ID_PARAMETER)) {
  956. status = STATUS_BUFFER_TOO_SMALL;
  957. Irp->IoStatus.Status = status;
  958. Irp->IoStatus.Information = 0;
  959. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  960. goto MouseClassDeviceControlReject;
  961. } else {
  962. unitId = ((PMOUSE_UNIT_ID_PARAMETER)
  963. Irp->AssociatedIrp.SystemBuffer)->UnitId;
  964. }
  965. if (deviceExtension->Self != deviceExtension->TrueClassDevice) {
  966. status = STATUS_NOT_SUPPORTED;
  967. Irp->IoStatus.Status = status;
  968. Irp->IoStatus.Information = 0;
  969. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  970. goto MouseClassDeviceControlReject;
  971. } else if (deviceExtension == Globals.GrandMaster) {
  972. ExAcquireFastMutex (&Globals.Mutex);
  973. if (Globals.NumAssocClass <= unitId) {
  974. ExReleaseFastMutex (&Globals.Mutex);
  975. status = STATUS_INVALID_PARAMETER;
  976. Irp->IoStatus.Status = status;
  977. Irp->IoStatus.Information = 0;
  978. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  979. goto MouseClassDeviceControlReject;
  980. }
  981. if (0 < Globals.NumAssocClass) {
  982. if (!PORT_WORKING (&Globals.AssocClassList[unitId])) {
  983. unitId = 0;
  984. }
  985. while (!PORT_WORKING (&Globals.AssocClassList [unitId])) {
  986. if (Globals.NumAssocClass <= unitId) {
  987. break;
  988. }
  989. unitId++;
  990. }
  991. }
  992. if (Globals.NumAssocClass <= unitId) {
  993. ExReleaseFastMutex (&Globals.Mutex);
  994. status = STATUS_INVALID_PARAMETER;
  995. Irp->IoStatus.Status = status;
  996. Irp->IoStatus.Information = 0;
  997. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  998. goto MouseClassDeviceControlReject;
  999. }
  1000. port = Globals.AssocClassList [unitId].Port;
  1001. stack->FileObject = Globals.AssocClassList[unitId].File;
  1002. ExReleaseFastMutex (&Globals.Mutex);
  1003. } else {
  1004. port = deviceExtension;
  1005. }
  1006. //
  1007. // Pass the device control request on to the port driver,
  1008. // asynchronously. Get the next IRP stack location and copy the
  1009. // input parameters to the next stack location. Change the major
  1010. // function to internal device control.
  1011. //
  1012. IoCopyCurrentIrpStackLocationToNext (Irp);
  1013. (IoGetNextIrpStackLocation (Irp))->MajorFunction =
  1014. IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1015. status = IoCallDriver (port->TopPort, Irp);
  1016. break;
  1017. case IOCTL_GET_SYS_BUTTON_CAPS:
  1018. case IOCTL_GET_SYS_BUTTON_EVENT:
  1019. case IOCTL_HID_GET_DRIVER_CONFIG:
  1020. case IOCTL_HID_SET_DRIVER_CONFIG:
  1021. case IOCTL_HID_GET_POLL_FREQUENCY_MSEC:
  1022. case IOCTL_HID_SET_POLL_FREQUENCY_MSEC:
  1023. case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS:
  1024. case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS:
  1025. case IOCTL_HID_GET_COLLECTION_INFORMATION:
  1026. case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
  1027. case IOCTL_HID_FLUSH_QUEUE:
  1028. case IOCTL_HID_SET_FEATURE:
  1029. case IOCTL_HID_GET_FEATURE:
  1030. case IOCTL_GET_PHYSICAL_DESCRIPTOR:
  1031. case IOCTL_HID_GET_HARDWARE_ID:
  1032. case IOCTL_HID_GET_MANUFACTURER_STRING:
  1033. case IOCTL_HID_GET_PRODUCT_STRING:
  1034. case IOCTL_HID_GET_SERIALNUMBER_STRING:
  1035. case IOCTL_HID_GET_INDEXED_STRING:
  1036. if (deviceExtension->PnP && (deviceExtension != Globals.GrandMaster)) {
  1037. IoSkipCurrentIrpStackLocation (Irp);
  1038. status = IoCallDriver (deviceExtension->TopPort, Irp);
  1039. break;
  1040. }
  1041. default:
  1042. status = STATUS_INVALID_DEVICE_REQUEST;
  1043. Irp->IoStatus.Status = status;
  1044. Irp->IoStatus.Information = 0;
  1045. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1046. break;
  1047. }
  1048. MouseClassDeviceControlReject:
  1049. IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
  1050. MouPrint((2,"MOUCLASS-MouseClassDeviceControl: exit\n"));
  1051. return(status);
  1052. }
  1053. NTSTATUS
  1054. MouseClassFlush(
  1055. IN PDEVICE_OBJECT DeviceObject,
  1056. IN PIRP Irp
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine is the dispatch routine for flush requests. The class
  1061. input data queue is reinitialized.
  1062. Arguments:
  1063. DeviceObject - Pointer to class device object.
  1064. Irp - Pointer to the request packet.
  1065. Return Value:
  1066. Status is returned.
  1067. --*/
  1068. {
  1069. PDEVICE_EXTENSION deviceExtension;
  1070. NTSTATUS status = STATUS_SUCCESS;
  1071. PIO_STACK_LOCATION irpSp;
  1072. MouPrint((2,"MOUCLASS-MouseClassFlush: enter\n"));
  1073. deviceExtension = DeviceObject->DeviceExtension;
  1074. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1075. if (deviceExtension->Self != deviceExtension->TrueClassDevice) {
  1076. status = STATUS_NOT_SUPPORTED;
  1077. } else if (!IS_TRUSTED_FILE_FOR_READ (irpSp->FileObject)) {
  1078. status = STATUS_PRIVILEGE_NOT_HELD;
  1079. }
  1080. if (NT_SUCCESS (status)) {
  1081. //
  1082. // Initialize mouse class input data queue.
  1083. //
  1084. MouInitializeDataQueue((PVOID)deviceExtension);
  1085. }
  1086. //
  1087. // Complete the request and return status.
  1088. //
  1089. Irp->IoStatus.Status = status;
  1090. Irp->IoStatus.Information = 0;
  1091. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1092. MouPrint((2,"MOUCLASS-MouseClassFlush: exit\n"));
  1093. return(status);
  1094. } // end MouseClassFlush
  1095. NTSTATUS
  1096. MouSyncComplete (
  1097. IN PDEVICE_OBJECT DeviceObject,
  1098. IN PIRP Irp,
  1099. IN PVOID Context
  1100. )
  1101. /*++
  1102. Routine Description:
  1103. The pnp IRP is in the process of completing.
  1104. signal
  1105. Arguments:
  1106. Context set to the device object in question.
  1107. --*/
  1108. {
  1109. PIO_STACK_LOCATION stack;
  1110. UNREFERENCED_PARAMETER (DeviceObject);
  1111. stack = IoGetCurrentIrpStackLocation (Irp);
  1112. //
  1113. // Since this completion routines sole purpose in life is to synchronize
  1114. // Irp, we know that unless something else happens that the IoCallDriver
  1115. // will unwind AFTER the we have complete this Irp. Therefore we should
  1116. // NOT buble up the pending bit.
  1117. //
  1118. // if (Irp->PendingReturned) {
  1119. // IoMarkIrpPending( Irp );
  1120. // }
  1121. //
  1122. KeSetEvent ((PKEVENT) Context, 0, FALSE);
  1123. return STATUS_MORE_PROCESSING_REQUIRED;
  1124. }
  1125. NTSTATUS
  1126. MouseSendIrpSynchronously (
  1127. IN PDEVICE_OBJECT DeviceObject,
  1128. IN PIRP Irp,
  1129. IN BOOLEAN CopyToNext
  1130. )
  1131. {
  1132. KEVENT event;
  1133. NTSTATUS status;
  1134. PAGED_CODE ();
  1135. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1136. if (CopyToNext) {
  1137. IoCopyCurrentIrpStackLocationToNext(Irp);
  1138. }
  1139. IoSetCompletionRoutine(Irp,
  1140. MouSyncComplete,
  1141. &event,
  1142. TRUE, // on success
  1143. TRUE, // on error
  1144. TRUE // on cancel
  1145. );
  1146. IoCallDriver(DeviceObject, Irp);
  1147. //
  1148. // Wait for lower drivers to be done with the Irp
  1149. //
  1150. KeWaitForSingleObject(&event,
  1151. Executive,
  1152. KernelMode,
  1153. FALSE,
  1154. NULL
  1155. );
  1156. status = Irp->IoStatus.Status;
  1157. return status;
  1158. }
  1159. NTSTATUS
  1160. MouseClassCreate (
  1161. IN PDEVICE_OBJECT DeviceObject,
  1162. IN PIRP Irp
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. This routine is the dispatch routine for create/open and close requests.
  1167. Open/close requests are completed here.
  1168. Arguments:
  1169. DeviceObject - Pointer to class device object.
  1170. Irp - Pointer to the request packet.
  1171. Return Value:
  1172. Status is returned.
  1173. --*/
  1174. {
  1175. PIO_STACK_LOCATION irpSp;
  1176. PDEVICE_EXTENSION deviceExtension;
  1177. PPORT port;
  1178. KIRQL oldIrql;
  1179. NTSTATUS status = STATUS_SUCCESS;
  1180. ULONG i;
  1181. LUID priv;
  1182. KEVENT event;
  1183. BOOLEAN someEnableDisableSucceeded = FALSE;
  1184. BOOLEAN enabled;
  1185. MouPrint((2,"MOUCLASS-MouseClassCreate: enter\n"));
  1186. //
  1187. // Get a pointer to the device extension.
  1188. //
  1189. deviceExtension = DeviceObject->DeviceExtension;
  1190. //
  1191. // Get a pointer to the current parameters for this request. The
  1192. // information is contained in the current stack location.
  1193. //
  1194. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1195. ASSERT (IRP_MJ_CREATE == irpSp->MajorFunction);
  1196. //
  1197. // We do not allow user mode opens for read. This includes services (who
  1198. // have the TCB privilege).
  1199. //
  1200. if (Irp->RequestorMode == UserMode &&
  1201. (irpSp->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA)) {
  1202. status = STATUS_ACCESS_DENIED;
  1203. goto MouseClassCreateEnd;
  1204. }
  1205. status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
  1206. if (!NT_SUCCESS (status)) {
  1207. goto MouseClassCreateEnd;
  1208. }
  1209. if ((deviceExtension->PnP) && (!deviceExtension->Started)) {
  1210. MouPrint((
  1211. 1,
  1212. "MOUCLASS-Create: failed create because PnP and Not started\n"
  1213. ));
  1214. status = STATUS_UNSUCCESSFUL;
  1215. IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
  1216. goto MouseClassCreateEnd;
  1217. }
  1218. //
  1219. // For the create/open operation, send a MOUSE_ENABLE internal
  1220. // device control request to the port driver to enable interrupts.
  1221. //
  1222. if (deviceExtension->Self == deviceExtension->TrueClassDevice) {
  1223. //
  1224. // First, if the requestor is the trusted subsystem (the single
  1225. // reader), reset the the cleanup indicator and place a pointer to
  1226. // the file object which this class driver uses
  1227. // to determine if the requestor has sufficient
  1228. // privilege to perform the read operation).
  1229. //
  1230. // Only allow one trusted subsystem to do READs.
  1231. //
  1232. priv = RtlConvertLongToLuid(SE_TCB_PRIVILEGE);
  1233. if (SeSinglePrivilegeCheck(priv, Irp->RequestorMode)) {
  1234. KeAcquireSpinLock(&deviceExtension->SpinLock, &oldIrql);
  1235. ASSERT (!IS_TRUSTED_FILE_FOR_READ (irpSp->FileObject));
  1236. SET_TRUSTED_FILE_FOR_READ (irpSp->FileObject);
  1237. deviceExtension->TrustedSubsystemCount++;
  1238. KeReleaseSpinLock(&deviceExtension->SpinLock, oldIrql);
  1239. }
  1240. }
  1241. //
  1242. // Pass on enables for opens to the true class device
  1243. //
  1244. ExAcquireFastMutex (&Globals.Mutex);
  1245. if ((Globals.GrandMaster == deviceExtension) && (1 == ++Globals.Opens)) {
  1246. for (i = 0; i < Globals.NumAssocClass; i++) {
  1247. port = &Globals.AssocClassList[i];
  1248. if (port->Free) {
  1249. continue;
  1250. }
  1251. enabled = port->Enabled;
  1252. port->Enabled = TRUE;
  1253. ExReleaseFastMutex (&Globals.Mutex);
  1254. if (!enabled) {
  1255. status = MouEnableDisablePort(TRUE,
  1256. Irp,
  1257. port->Port,
  1258. &port->File);
  1259. }
  1260. if (status != STATUS_SUCCESS) {
  1261. MouPrint((0,
  1262. "MOUCLASS-MouseClassOpenClose: Could not enable/disable interrupts for port device object @ 0x%x\n",
  1263. deviceExtension->TopPort));
  1264. MouseClassLogError (DeviceObject,
  1265. MOUCLASS_PORT_INTERRUPTS_NOT_ENABLED,
  1266. MOUSE_ERROR_VALUE_BASE + 120,
  1267. status,
  1268. 0,
  1269. NULL,
  1270. irpSp->MajorFunction);
  1271. port->Enabled = FALSE;
  1272. }
  1273. else {
  1274. someEnableDisableSucceeded = TRUE;
  1275. }
  1276. ExAcquireFastMutex (&Globals.Mutex);
  1277. }
  1278. ExReleaseFastMutex (&Globals.Mutex);
  1279. } else if (Globals.GrandMaster != deviceExtension) {
  1280. ExReleaseFastMutex (&Globals.Mutex);
  1281. if (deviceExtension->TrueClassDevice == DeviceObject) {
  1282. //
  1283. // An open to the true class Device => enable the one and only port
  1284. //
  1285. status = MouEnableDisablePort (TRUE,
  1286. Irp,
  1287. deviceExtension,
  1288. &irpSp->FileObject);
  1289. } else {
  1290. IoSkipCurrentIrpStackLocation (Irp);
  1291. status = IoCallDriver (deviceExtension->TopPort, Irp);
  1292. IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
  1293. return status;
  1294. }
  1295. if (status != STATUS_SUCCESS) {
  1296. MouPrint((0,
  1297. "MOUCLASS-MouseClassOpenClose: Create failed (0x%x) port device object @ 0x%x\n",
  1298. status, deviceExtension->TopPort));
  1299. //
  1300. // Log an error.
  1301. //
  1302. // Do not log an error for a failed open on a PNP device, esp HID
  1303. // devices which can be easily opened from user mode
  1304. //
  1305. #if 0
  1306. MouseClassLogError (DeviceObject,
  1307. MOUCLASS_PORT_INTERRUPTS_NOT_ENABLED,
  1308. MOUSE_ERROR_VALUE_BASE + 120,
  1309. status,
  1310. 0,
  1311. NULL,
  1312. irpSp->MajorFunction);
  1313. #endif
  1314. }
  1315. else {
  1316. someEnableDisableSucceeded = TRUE;
  1317. }
  1318. } else {
  1319. ExReleaseFastMutex (&Globals.Mutex);
  1320. }
  1321. //
  1322. // Complete the request and return status.
  1323. //
  1324. // NOTE: We complete the request successfully if any one of the
  1325. // connected port devices successfully handled the request.
  1326. // The RIT only knows about one pointing device.
  1327. //
  1328. if (someEnableDisableSucceeded) {
  1329. status = STATUS_SUCCESS;
  1330. }
  1331. IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
  1332. MouseClassCreateEnd:
  1333. Irp->IoStatus.Status = status;
  1334. Irp->IoStatus.Information = 0;
  1335. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1336. MouPrint((2,"MOUCLASS-MouseClassOpenClose: exit\n"));
  1337. return(status);
  1338. }
  1339. NTSTATUS
  1340. MouseClassClose(
  1341. IN PDEVICE_OBJECT DeviceObject,
  1342. IN PIRP Irp
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. This routine is the dispatch routine for create/open and close requests.
  1347. Open/close requests are completed here.
  1348. Arguments:
  1349. DeviceObject - Pointer to class device object.
  1350. Irp - Pointer to the request packet.
  1351. Return Value:
  1352. Status is returned.
  1353. --*/
  1354. {
  1355. PIO_STACK_LOCATION irpSp;
  1356. PDEVICE_EXTENSION deviceExtension;
  1357. PPORT port;
  1358. KIRQL oldIrql;
  1359. NTSTATUS status = STATUS_SUCCESS;
  1360. ULONG i;
  1361. LUID priv;
  1362. KEVENT event;
  1363. PFILE_OBJECT file;
  1364. BOOLEAN someEnableDisableSucceeded = FALSE;
  1365. BOOLEAN enabled;
  1366. PVOID notifyHandle;
  1367. MouPrint((2,"MOUCLASS-MouseClassOpenClose: enter\n"));
  1368. //
  1369. // Get a pointer to the device extension.
  1370. //
  1371. deviceExtension = DeviceObject->DeviceExtension;
  1372. //
  1373. // Get a pointer to the current parameters for this request. The
  1374. // information is contained in the current stack location.
  1375. //
  1376. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1377. //
  1378. // Let the close go through even if the device is removed
  1379. // AKA do not call MouIncIoCount
  1380. //
  1381. //
  1382. // For the create/open operation, send a MOUSE_ENABLE internal
  1383. // device control request to the port driver to enable interrupts.
  1384. //
  1385. ASSERT (IRP_MJ_CLOSE == irpSp->MajorFunction);
  1386. if (deviceExtension->Self == deviceExtension->TrueClassDevice) {
  1387. KeAcquireSpinLock(&deviceExtension->SpinLock, &oldIrql);
  1388. if (IS_TRUSTED_FILE_FOR_READ (irpSp->FileObject)) {
  1389. ASSERT(0 < deviceExtension->TrustedSubsystemCount);
  1390. deviceExtension->TrustedSubsystemCount--;
  1391. CLEAR_TRUSTED_FILE_FOR_READ (irpSp->FileObject);
  1392. }
  1393. KeReleaseSpinLock(&deviceExtension->SpinLock, oldIrql);
  1394. }
  1395. //
  1396. // Pass on enables for closes to the true class device
  1397. //
  1398. ExAcquireFastMutex (&Globals.Mutex);
  1399. if ((Globals.GrandMaster == deviceExtension) && (0 == --Globals.Opens)) {
  1400. for (i = 0; i < Globals.NumAssocClass; i++) {
  1401. port = &Globals.AssocClassList[i];
  1402. if (port->Free) {
  1403. continue;
  1404. }
  1405. enabled = port->Enabled;
  1406. port->Enabled = FALSE;
  1407. ExReleaseFastMutex (&Globals.Mutex);
  1408. if (enabled) {
  1409. notifyHandle = InterlockedExchangePointer (
  1410. &port->Port->TargetNotifyHandle,
  1411. NULL);
  1412. if (NULL != notifyHandle) {
  1413. IoUnregisterPlugPlayNotification (notifyHandle);
  1414. }
  1415. status = MouEnableDisablePort(FALSE,
  1416. Irp,
  1417. port->Port,
  1418. &port->File);
  1419. } else {
  1420. ASSERT (NULL == port->Port->TargetNotifyHandle);
  1421. }
  1422. if (status != STATUS_SUCCESS) {
  1423. MouPrint((0,
  1424. "MOUCLASS-MouseClassOpenClose: Could not enable/disable interrupts for port device object @ 0x%x\n",
  1425. port->Port->TopPort));
  1426. //
  1427. // Log an error.
  1428. //
  1429. MouseClassLogError (DeviceObject,
  1430. MOUCLASS_PORT_INTERRUPTS_NOT_DISABLED,
  1431. MOUSE_ERROR_VALUE_BASE + 120,
  1432. status,
  1433. 0,
  1434. NULL,
  1435. irpSp->MajorFunction);
  1436. ASSERTMSG ("Could not close open port!", FALSE);
  1437. }
  1438. else {
  1439. someEnableDisableSucceeded = TRUE;
  1440. }
  1441. ExAcquireFastMutex (&Globals.Mutex);
  1442. }
  1443. ExReleaseFastMutex (&Globals.Mutex);
  1444. } else if (Globals.GrandMaster != deviceExtension) {
  1445. ExReleaseFastMutex (&Globals.Mutex);
  1446. if (deviceExtension->TrueClassDevice == DeviceObject) {
  1447. //
  1448. // A close to the true class Device => disable the one and only port
  1449. //
  1450. status = MouEnableDisablePort (FALSE,
  1451. Irp,
  1452. deviceExtension,
  1453. &irpSp->FileObject);
  1454. } else {
  1455. IoSkipCurrentIrpStackLocation (Irp);
  1456. status = IoCallDriver (deviceExtension->TopPort, Irp);
  1457. return status;
  1458. }
  1459. if (status != STATUS_SUCCESS) {
  1460. MouPrint((0,
  1461. "MOUCLASS-MouseClassOpenClose: Could not enable/disable interrupts for port device object @ 0x%x\n",
  1462. deviceExtension->TopPort));
  1463. //
  1464. // Log an error.
  1465. //
  1466. MouseClassLogError (DeviceObject,
  1467. MOUCLASS_PORT_INTERRUPTS_NOT_DISABLED,
  1468. MOUSE_ERROR_VALUE_BASE + 120,
  1469. status,
  1470. 0,
  1471. NULL,
  1472. irpSp->MajorFunction);
  1473. }
  1474. else {
  1475. someEnableDisableSucceeded = TRUE;
  1476. }
  1477. } else {
  1478. ExReleaseFastMutex (&Globals.Mutex);
  1479. }
  1480. //
  1481. // Complete the request and return status.
  1482. //
  1483. // NOTE: We complete the request successfully if any one of the
  1484. // connected port devices successfully handled the request.
  1485. // The RIT only knows about one pointing device.
  1486. //
  1487. if (someEnableDisableSucceeded) {
  1488. status = STATUS_SUCCESS;
  1489. }
  1490. Irp->IoStatus.Status = status;
  1491. Irp->IoStatus.Information = 0;
  1492. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1493. MouPrint((2,"MOUCLASS-MouseClassOpenClose: exit\n"));
  1494. return(status);
  1495. }
  1496. NTSTATUS
  1497. MouseClassReadCopyData(
  1498. IN PDEVICE_EXTENSION DeviceExtension,
  1499. IN PIRP Irp
  1500. )
  1501. /*++
  1502. Routine Description:
  1503. Copies data as much from the internal queue to the irp as possible.
  1504. Assumptions:
  1505. DeviceExtension->SpinLock is already held (so no further synch is required).
  1506. --*/
  1507. {
  1508. PIO_STACK_LOCATION irpSp;
  1509. PCHAR destination;
  1510. ULONG bytesInQueue;
  1511. ULONG bytesToMove;
  1512. ULONG moveSize;
  1513. //
  1514. // Bump the error log sequence number.
  1515. //
  1516. DeviceExtension->SequenceNumber += 1;
  1517. //
  1518. // Copy as much of the input data as possible from the class input
  1519. // data queue to the SystemBuffer to satisfy the read. It may be
  1520. // necessary to copy the data in two chunks (i.e., if the circular
  1521. // queue wraps).
  1522. //
  1523. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1524. //
  1525. // bytesToMove <- MIN(Number of filled bytes in class input data queue,
  1526. // Requested read length).
  1527. //
  1528. bytesInQueue = DeviceExtension->InputCount *
  1529. sizeof(MOUSE_INPUT_DATA);
  1530. bytesToMove = irpSp->Parameters.Read.Length;
  1531. MouPrint((
  1532. 3,
  1533. "MOUCLASS-MouseClassCopyReadData: queue size 0x%lx, read length 0x%lx\n",
  1534. bytesInQueue,
  1535. bytesToMove
  1536. ));
  1537. bytesToMove = (bytesInQueue < bytesToMove) ?
  1538. bytesInQueue:bytesToMove;
  1539. //
  1540. // moveSize <- MIN(Number of bytes to be moved from the class queue,
  1541. // Number of bytes to end of class input data queue).
  1542. //
  1543. bytesInQueue = (ULONG)(((PCHAR) DeviceExtension->InputData +
  1544. DeviceExtension->MouseAttributes.InputDataQueueLength) -
  1545. (PCHAR) DeviceExtension->DataOut);
  1546. moveSize = (bytesToMove < bytesInQueue) ?
  1547. bytesToMove:bytesInQueue;
  1548. MouPrint((
  1549. 3,
  1550. "MOUCLASS-MouseClassCopyReadData: bytes to end of queue 0x%lx\n",
  1551. bytesInQueue
  1552. ));
  1553. //
  1554. // Move bytes from the class input data queue to SystemBuffer, until
  1555. // the request is satisfied or we wrap the class input data buffer.
  1556. //
  1557. destination = Irp->AssociatedIrp.SystemBuffer;
  1558. MouPrint((
  1559. 3,
  1560. "MOUCLASS-MouseClassCopyReadData: number of bytes in first move 0x%lx\n",
  1561. moveSize
  1562. ));
  1563. MouPrint((
  1564. 3,
  1565. "MOUCLASS-MouseClassCopyReadData: move bytes from 0x%lx to 0x%lx\n",
  1566. (PCHAR) DeviceExtension->DataOut,
  1567. destination
  1568. ));
  1569. RtlMoveMemory(
  1570. destination,
  1571. (PCHAR) DeviceExtension->DataOut,
  1572. moveSize
  1573. );
  1574. destination += moveSize;
  1575. //
  1576. // If the data wraps in the class input data buffer, copy the rest
  1577. // of the data from the start of the input data queue
  1578. // buffer through the end of the queued data.
  1579. //
  1580. if ((bytesToMove - moveSize) > 0) {
  1581. //
  1582. // moveSize <- Remaining number bytes to move.
  1583. //
  1584. moveSize = bytesToMove - moveSize;
  1585. //
  1586. // Move the bytes from the class input data queue to SystemBuffer.
  1587. //
  1588. MouPrint((
  1589. 3,
  1590. "MOUCLASS-MouseClassCopyReadData: number of bytes in second move 0x%lx\n",
  1591. moveSize
  1592. ));
  1593. MouPrint((
  1594. 3,
  1595. "MOUCLASS-MouseClassCopyReadData: move bytes from 0x%lx to 0x%lx\n",
  1596. (PCHAR) DeviceExtension->InputData,
  1597. destination
  1598. ));
  1599. RtlMoveMemory(
  1600. destination,
  1601. (PCHAR) DeviceExtension->InputData,
  1602. moveSize
  1603. );
  1604. //
  1605. // Update the class input data queue removal pointer.
  1606. //
  1607. DeviceExtension->DataOut = (PMOUSE_INPUT_DATA)
  1608. (((PCHAR) DeviceExtension->InputData) + moveSize);
  1609. }
  1610. else {
  1611. //
  1612. // Update the input data queue removal pointer.
  1613. //
  1614. DeviceExtension->DataOut = (PMOUSE_INPUT_DATA)
  1615. (((PCHAR) DeviceExtension->DataOut) + moveSize);
  1616. }
  1617. //
  1618. // Update the class input data queue InputCount.
  1619. //
  1620. DeviceExtension->InputCount -=
  1621. (bytesToMove / sizeof(MOUSE_INPUT_DATA));
  1622. if (DeviceExtension->InputCount == 0) {
  1623. //
  1624. // Reset the flag that determines whether it is time to log
  1625. // queue overflow errors. We don't want to log errors too often.
  1626. // Instead, log an error on the first overflow that occurs after
  1627. // the ring buffer has been emptied, and then stop logging errors
  1628. // until it gets cleared out and overflows again.
  1629. //
  1630. MouPrint((
  1631. 1,
  1632. "MOUCLASS-MouseClassCopyReadData: Okay to log overflow\n"
  1633. ));
  1634. DeviceExtension->OkayToLogOverflow = TRUE;
  1635. }
  1636. MouPrint((
  1637. 3,
  1638. "MOUCLASS-MouseClassCopyReadData: new DataIn 0x%lx, DataOut 0x%lx\n",
  1639. DeviceExtension->DataIn,
  1640. DeviceExtension->DataOut
  1641. ));
  1642. MouPrint((
  1643. 3,
  1644. "MOUCLASS-MouseClassCopyReadData: new InputCount %ld\n",
  1645. DeviceExtension->InputCount
  1646. ));
  1647. //
  1648. // Record how many bytes we have satisfied
  1649. //
  1650. Irp->IoStatus.Information = bytesToMove;
  1651. irpSp->Parameters.Read.Length = bytesToMove;
  1652. return STATUS_SUCCESS;
  1653. }
  1654. NTSTATUS
  1655. MouseClassHandleRead(
  1656. PDEVICE_EXTENSION DeviceExtension,
  1657. PIRP Irp
  1658. )
  1659. /*++
  1660. Routine Description:
  1661. If there is queued data, the Irp will be completed immediately. If there is
  1662. no data to report, queue the irp.
  1663. --*/
  1664. {
  1665. PDRIVER_CANCEL oldCancelRoutine;
  1666. NTSTATUS status = STATUS_PENDING;
  1667. KIRQL irql;
  1668. BOOLEAN completeIrp = FALSE;
  1669. KeAcquireSpinLock(&DeviceExtension->SpinLock, &irql);
  1670. if (DeviceExtension->InputCount == 0) {
  1671. //
  1672. // Easy case to handle, just enqueue the irp
  1673. //
  1674. InsertTailList (&DeviceExtension->ReadQueue, &Irp->Tail.Overlay.ListEntry);
  1675. IoMarkIrpPending (Irp);
  1676. //
  1677. // Must set a cancel routine before checking the Cancel flag.
  1678. //
  1679. oldCancelRoutine = IoSetCancelRoutine (Irp, MouseClassCancel);
  1680. ASSERT (!oldCancelRoutine);
  1681. if (Irp->Cancel) {
  1682. //
  1683. // The IRP was cancelled. Check whether or not the cancel
  1684. // routine was called.
  1685. //
  1686. oldCancelRoutine = IoSetCancelRoutine (Irp, NULL);
  1687. if (oldCancelRoutine) {
  1688. //
  1689. // The cancel routine was NOT called so dequeue the IRP now and
  1690. // complete it after releasing the spinlock.
  1691. //
  1692. RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
  1693. status = Irp->IoStatus.Status = STATUS_CANCELLED;
  1694. }
  1695. else {
  1696. //
  1697. // The cancel routine WAS called.
  1698. //
  1699. // As soon as we drop the spinlock it will dequeue and complete
  1700. // the IRP. So leave the IRP in the queue and otherwise don't
  1701. // touch it. Return pending since we're not completing the IRP
  1702. // here.
  1703. //
  1704. ;
  1705. }
  1706. }
  1707. if (status != STATUS_PENDING){
  1708. completeIrp = TRUE;
  1709. }
  1710. }
  1711. else {
  1712. //
  1713. // If we have outstanding input to report, our queue better be empty!
  1714. //
  1715. ASSERT (IsListEmpty (&DeviceExtension->ReadQueue));
  1716. status = MouseClassReadCopyData (DeviceExtension, Irp);
  1717. Irp->IoStatus.Status = status;
  1718. completeIrp = TRUE;
  1719. }
  1720. KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
  1721. if (completeIrp) {
  1722. IoReleaseRemoveLock (&DeviceExtension->RemoveLock, Irp);
  1723. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1724. }
  1725. return status;
  1726. }
  1727. NTSTATUS
  1728. MouseClassRead(
  1729. IN PDEVICE_OBJECT Device,
  1730. IN PIRP Irp
  1731. )
  1732. /*++
  1733. Routine Description:
  1734. This routine is the dispatch routine for read requests. Valid read
  1735. requests are either marked pending if no data has been queued or completed
  1736. immediatedly with available data.
  1737. Arguments:
  1738. DeviceObject - Pointer to class device object.
  1739. Irp - Pointer to the request packet.
  1740. Return Value:
  1741. Status is returned.
  1742. --*/
  1743. {
  1744. NTSTATUS status;
  1745. PIO_STACK_LOCATION irpSp;
  1746. PDEVICE_EXTENSION deviceExtension;
  1747. MouPrint((2,"MOUCLASS-MouseClassRead: enter\n"));
  1748. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1749. //
  1750. // Validate the read request parameters. The read length should be an
  1751. // integral number of MOUSE_INPUT_DATA structures.
  1752. //
  1753. deviceExtension = (PDEVICE_EXTENSION) Device->DeviceExtension;
  1754. if (irpSp->Parameters.Read.Length == 0) {
  1755. status = STATUS_SUCCESS;
  1756. } else if (irpSp->Parameters.Read.Length % sizeof(MOUSE_INPUT_DATA)) {
  1757. status = STATUS_BUFFER_TOO_SMALL;
  1758. } else if (deviceExtension->SurpriseRemoved) {
  1759. status = STATUS_DEVICE_NOT_CONNECTED;
  1760. } else if (IS_TRUSTED_FILE_FOR_READ (irpSp->FileObject)) {
  1761. //
  1762. // If the file object's FsContext is non-null, then we've already
  1763. // done the Read privilege check once before for this thread. Skip
  1764. // the privilege check.
  1765. //
  1766. deviceExtension = (PDEVICE_EXTENSION) Device->DeviceExtension;
  1767. status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
  1768. if (NT_SUCCESS (status)) {
  1769. status = STATUS_PENDING;
  1770. }
  1771. } else {
  1772. //
  1773. // We only allow a trusted subsystem with the appropriate privilege
  1774. // level to execute a Read call.
  1775. //
  1776. status = STATUS_PRIVILEGE_NOT_HELD;
  1777. }
  1778. //
  1779. // If status is pending, mark the packet pending and start the packet
  1780. // in a cancellable state. Otherwise, complete the request.
  1781. //
  1782. Irp->IoStatus.Status = status;
  1783. Irp->IoStatus.Information = 0;
  1784. if (status == STATUS_PENDING) {
  1785. return MouseClassHandleRead(deviceExtension, Irp);
  1786. }
  1787. else {
  1788. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1789. }
  1790. MouPrint((2,"MOUCLASS-MouseClassRead: exit\n"));
  1791. return status;
  1792. }
  1793. PIRP
  1794. MouseClassDequeueRead(
  1795. IN PDEVICE_EXTENSION DeviceExtension
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. Dequeues the next available read irp regardless of FileObject
  1800. Assumptions:
  1801. DeviceExtension->SpinLock is already held (so no further sync is required).
  1802. --*/
  1803. {
  1804. PIRP nextIrp = NULL;
  1805. KIRQL oldIrql;
  1806. while (!nextIrp && !IsListEmpty (&DeviceExtension->ReadQueue)){
  1807. PDRIVER_CANCEL oldCancelRoutine;
  1808. PLIST_ENTRY listEntry = RemoveHeadList (&DeviceExtension->ReadQueue);
  1809. //
  1810. // Get the next IRP off the queue and clear the cancel routine
  1811. //
  1812. nextIrp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
  1813. oldCancelRoutine = IoSetCancelRoutine (nextIrp, NULL);
  1814. //
  1815. // IoCancelIrp() could have just been called on this IRP.
  1816. // What we're interested in is not whether IoCancelIrp() was called
  1817. // (ie, nextIrp->Cancel is set), but whether IoCancelIrp() called (or
  1818. // is about to call) our cancel routine. To check that, check the result
  1819. // of the test-and-set macro IoSetCancelRoutine.
  1820. //
  1821. if (oldCancelRoutine) {
  1822. //
  1823. // Cancel routine not called for this IRP. Return this IRP.
  1824. //
  1825. ASSERT (oldCancelRoutine == MouseClassCancel);
  1826. }
  1827. else {
  1828. //
  1829. // This IRP was just cancelled and the cancel routine was (or will
  1830. // be) called. The cancel routine will complete this IRP as soon as
  1831. // we drop the spinlock. So don't do anything with the IRP.
  1832. //
  1833. // Also, the cancel routine will try to dequeue the IRP, so make the
  1834. // IRP's listEntry point to itself.
  1835. //
  1836. ASSERT (nextIrp->Cancel);
  1837. InitializeListHead (&nextIrp->Tail.Overlay.ListEntry);
  1838. nextIrp = NULL;
  1839. }
  1840. }
  1841. return nextIrp;
  1842. }
  1843. PIRP
  1844. MouseClassDequeueReadByFileObject(
  1845. IN PDEVICE_EXTENSION DeviceExtension,
  1846. IN PFILE_OBJECT FileObject
  1847. )
  1848. /*++
  1849. Routine Description:
  1850. Dequeues the next available read with a matching FileObject
  1851. Assumptions:
  1852. DeviceExtension->SpinLock is already held (so no further sync is required).
  1853. --*/
  1854. {
  1855. PIRP irp = NULL;
  1856. PLIST_ENTRY entry;
  1857. PIO_STACK_LOCATION stack;
  1858. PDRIVER_CANCEL oldCancelRoutine;
  1859. KIRQL oldIrql;
  1860. if (FileObject == NULL) {
  1861. return MouseClassDequeueRead (DeviceExtension);
  1862. }
  1863. for (entry = DeviceExtension->ReadQueue.Flink;
  1864. entry != &DeviceExtension->ReadQueue;
  1865. entry = entry->Flink) {
  1866. irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
  1867. stack = IoGetCurrentIrpStackLocation (irp);
  1868. if (stack->FileObject == FileObject) {
  1869. RemoveEntryList (entry);
  1870. oldCancelRoutine = IoSetCancelRoutine (irp, NULL);
  1871. //
  1872. // IoCancelIrp() could have just been called on this IRP.
  1873. // What we're interested in is not whether IoCancelIrp() was called
  1874. // (ie, nextIrp->Cancel is set), but whether IoCancelIrp() called (or
  1875. // is about to call) our cancel routine. To check that, check the result
  1876. // of the test-and-set macro IoSetCancelRoutine.
  1877. //
  1878. if (oldCancelRoutine) {
  1879. //
  1880. // Cancel routine not called for this IRP. Return this IRP.
  1881. //
  1882. return irp;
  1883. }
  1884. else {
  1885. //
  1886. // This IRP was just cancelled and the cancel routine was (or will
  1887. // be) called. The cancel routine will complete this IRP as soon as
  1888. // we drop the spinlock. So don't do anything with the IRP.
  1889. //
  1890. // Also, the cancel routine will try to dequeue the IRP, so make the
  1891. // IRP's listEntry point to itself.
  1892. //
  1893. ASSERT (irp->Cancel);
  1894. InitializeListHead (&irp->Tail.Overlay.ListEntry);
  1895. }
  1896. }
  1897. }
  1898. return NULL;
  1899. }
  1900. VOID
  1901. MouseClassServiceCallback(
  1902. IN PDEVICE_OBJECT DeviceObject,
  1903. IN PMOUSE_INPUT_DATA InputDataStart,
  1904. IN PMOUSE_INPUT_DATA InputDataEnd,
  1905. IN OUT PULONG InputDataConsumed
  1906. )
  1907. /*++
  1908. Routine Description:
  1909. This routine is the class service callback routine. It is
  1910. called from the port driver's interrupt service DPC. If there is an
  1911. outstanding read request, the request is satisfied from the port input
  1912. data queue. Unsolicited mouse input is moved from the port input
  1913. data queue to the class input data queue.
  1914. N.B. This routine is entered at DISPATCH_LEVEL IRQL from the port
  1915. driver's ISR DPC routine.
  1916. Arguments:
  1917. DeviceObject - Pointer to class device object.
  1918. InputDataStart - Pointer to the start of the data in the port input
  1919. data queue.
  1920. InputDataEnd - Points one input data structure past the end of the
  1921. valid port input data.
  1922. InputDataConsumed - Pointer to storage in which the number of input
  1923. data structures consumed by this call is returned.
  1924. NOTE: Could pull the duplicate code out into a called procedure.
  1925. Return Value:
  1926. None.
  1927. --*/
  1928. {
  1929. PDEVICE_EXTENSION deviceExtension;
  1930. PIO_STACK_LOCATION irpSp;
  1931. LIST_ENTRY listHead;
  1932. PIRP irp;
  1933. ULONG bytesInQueue;
  1934. ULONG bytesToMove;
  1935. ULONG moveSize;
  1936. ULONG dumpData[2];
  1937. BOOLEAN logOverflow;
  1938. MouPrint((2,"MOUCLASS-MouseClassServiceCallback: enter\n"));
  1939. deviceExtension = DeviceObject->DeviceExtension;
  1940. bytesInQueue = (ULONG)((PCHAR) InputDataEnd - (PCHAR) InputDataStart);
  1941. moveSize = 0;
  1942. *InputDataConsumed = 0;
  1943. logOverflow = FALSE;
  1944. if ((InputDataEnd == InputDataStart + 1) &&
  1945. (InputDataStart->Flags & MOUSE_ATTRIBUTES_CHANGED)) {
  1946. //
  1947. // This is a notification packet that is not indicative of the user
  1948. // being present. It is instead just a blank packet for the Raw
  1949. // Input User Thread.
  1950. //
  1951. // We will pass it on, but we will not treat this as human input.
  1952. //
  1953. ;
  1954. } else {
  1955. //
  1956. // Notify system that human input has occured
  1957. //
  1958. PoSetSystemState (ES_USER_PRESENT);
  1959. }
  1960. //
  1961. // N.B. We can use KeAcquireSpinLockAtDpcLevel, instead of
  1962. // KeAcquireSpinLock, because this routine is already running
  1963. // at DISPATCH_IRQL.
  1964. //
  1965. KeAcquireSpinLockAtDpcLevel (&deviceExtension->SpinLock);
  1966. InitializeListHead (&listHead);
  1967. irp = MouseClassDequeueRead (deviceExtension);
  1968. if (irp) {
  1969. //
  1970. // An outstanding read request exists.
  1971. //
  1972. // Copy as much of the input data possible from the port input
  1973. // data queue to the SystemBuffer to satisfy the read.
  1974. //
  1975. irpSp = IoGetCurrentIrpStackLocation (irp);
  1976. bytesToMove = irpSp->Parameters.Read.Length;
  1977. moveSize = (bytesInQueue < bytesToMove) ? bytesInQueue
  1978. : bytesToMove;
  1979. *InputDataConsumed += (moveSize / sizeof(MOUSE_INPUT_DATA));
  1980. MouPrint((
  1981. 3,
  1982. "MOUCLASS-MouseClassServiceCallback: port queue length 0x%lx, read length 0x%lx\n",
  1983. bytesInQueue,
  1984. bytesToMove
  1985. ));
  1986. MouPrint((
  1987. 3,
  1988. "MOUCLASS-MouseClassServiceCallback: number of bytes to move from port to SystemBuffer 0x%lx\n",
  1989. moveSize
  1990. ));
  1991. MouPrint((
  1992. 3,
  1993. "MOUCLASS-MouseClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
  1994. (PCHAR) InputDataStart,
  1995. irp->AssociatedIrp.SystemBuffer
  1996. ));
  1997. RtlMoveMemory(
  1998. irp->AssociatedIrp.SystemBuffer,
  1999. (PCHAR) InputDataStart,
  2000. moveSize
  2001. );
  2002. //
  2003. // Set the flag so that we start the next packet and complete
  2004. // this read request (with STATUS_SUCCESS) prior to return.
  2005. //
  2006. irp->IoStatus.Status = STATUS_SUCCESS;
  2007. irp->IoStatus.Information = moveSize;
  2008. irpSp->Parameters.Read.Length = moveSize;
  2009. InsertTailList (&listHead, &irp->Tail.Overlay.ListEntry);
  2010. }
  2011. //
  2012. // If there is still data in the port input data queue, move it to the class
  2013. // input data queue.
  2014. //
  2015. InputDataStart = (PMOUSE_INPUT_DATA) ((PCHAR) InputDataStart + moveSize);
  2016. moveSize = bytesInQueue - moveSize;
  2017. MouPrint((
  2018. 3,
  2019. "MOUCLASS-MouseClassServiceCallback: bytes remaining after move to SystemBuffer 0x%lx\n",
  2020. moveSize
  2021. ));
  2022. if (moveSize > 0) {
  2023. //
  2024. // Move the remaining data from the port input data queue to
  2025. // the class input data queue. The move will happen in two
  2026. // parts in the case where the class input data buffer wraps.
  2027. //
  2028. bytesInQueue =
  2029. deviceExtension->MouseAttributes.InputDataQueueLength -
  2030. (deviceExtension->InputCount * sizeof(MOUSE_INPUT_DATA));
  2031. bytesToMove = moveSize;
  2032. MouPrint((
  2033. 3,
  2034. "MOUCLASS-MouseClassServiceCallback: unused bytes in class queue 0x%lx, remaining bytes in port queue 0x%lx\n",
  2035. bytesInQueue,
  2036. bytesToMove
  2037. ));
  2038. #if ALLOW_OVERFLOW
  2039. #else
  2040. if (bytesInQueue == 0) {
  2041. //
  2042. // Refuse to move any bytes that would cause a class input data
  2043. // queue overflow. Just drop the bytes on the floor, and
  2044. // log an overrun error.
  2045. //
  2046. MouPrint((
  2047. 1,
  2048. "MOUCLASS-MouseClassServiceCallback: Class input data queue OVERRUN\n"
  2049. ));
  2050. if (deviceExtension->OkayToLogOverflow) {
  2051. //
  2052. // Allocate and report the error log entry outside of any locks
  2053. // we are currently holding
  2054. //
  2055. logOverflow = TRUE
  2056. dumpData[0] = bytesToMove;
  2057. dumpData[1] =
  2058. deviceExtension->MouseAttributes.InputDataQueueLength;
  2059. deviceExtension->OkayToLogOverflow = FALSE;
  2060. }
  2061. } else {
  2062. #endif
  2063. //
  2064. // There is room in the class input data queue, so move
  2065. // the remaining port input data to it.
  2066. //
  2067. // bytesToMove <- MIN(Number of unused bytes in class input data
  2068. // queue, Number of bytes remaining in port
  2069. // input queue).
  2070. // This is the total number of bytes that actually will move from
  2071. // the port input data queue to the class input data queue.
  2072. //
  2073. #if ALLOW_OVERFLOW
  2074. bytesInQueue = deviceExtension->MouseAttributes.InputDataQueueLength;
  2075. #endif
  2076. bytesToMove = (bytesInQueue < bytesToMove) ?
  2077. bytesInQueue:bytesToMove;
  2078. //
  2079. // bytesInQueue <- Number of unused bytes from insertion pointer to
  2080. // the end of the class input data queue (i.e., until the buffer
  2081. // wraps).
  2082. //
  2083. bytesInQueue = (ULONG)(((PCHAR) deviceExtension->InputData +
  2084. deviceExtension->MouseAttributes.InputDataQueueLength) -
  2085. (PCHAR) deviceExtension->DataIn);
  2086. MouPrint((
  2087. 3,
  2088. "MOUCLASS-MouseClassServiceCallback: total number of bytes to move to class queue 0x%lx\n",
  2089. bytesToMove
  2090. ));
  2091. MouPrint((
  2092. 3,
  2093. "MOUCLASS-MouseClassServiceCallback: number of bytes to end of class buffer 0x%lx\n",
  2094. bytesInQueue
  2095. ));
  2096. //
  2097. // moveSize <- Number of bytes to handle in the first move.
  2098. //
  2099. moveSize = (bytesToMove < bytesInQueue) ?
  2100. bytesToMove:bytesInQueue;
  2101. MouPrint((
  2102. 3,
  2103. "MOUCLASS-MouseClassServiceCallback: number of bytes in first move to class 0x%lx\n",
  2104. moveSize
  2105. ));
  2106. //
  2107. // Do the move from the port data queue to the class data queue.
  2108. //
  2109. MouPrint((
  2110. 3,
  2111. "MOUCLASS-MouseClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
  2112. (PCHAR) InputDataStart,
  2113. (PCHAR) deviceExtension->DataIn
  2114. ));
  2115. RtlMoveMemory(
  2116. (PCHAR) deviceExtension->DataIn,
  2117. (PCHAR) InputDataStart,
  2118. moveSize
  2119. );
  2120. //
  2121. // Increment the port data queue pointer and the class input
  2122. // data queue insertion pointer. Wrap the insertion pointer,
  2123. // if necessary.
  2124. //
  2125. InputDataStart = (PMOUSE_INPUT_DATA)
  2126. (((PCHAR) InputDataStart) + moveSize);
  2127. deviceExtension->DataIn = (PMOUSE_INPUT_DATA)
  2128. (((PCHAR) deviceExtension->DataIn) + moveSize);
  2129. if ((PCHAR) deviceExtension->DataIn >=
  2130. ((PCHAR) deviceExtension->InputData +
  2131. deviceExtension->MouseAttributes.InputDataQueueLength)) {
  2132. deviceExtension->DataIn = deviceExtension->InputData;
  2133. }
  2134. if ((bytesToMove - moveSize) > 0) {
  2135. //
  2136. // Special case. The data must wrap in the class input data buffer.
  2137. // Copy the rest of the port input data into the beginning of the
  2138. // class input data queue.
  2139. //
  2140. //
  2141. // moveSize <- Number of bytes to handle in the second move.
  2142. //
  2143. moveSize = bytesToMove - moveSize;
  2144. //
  2145. // Do the move from the port data queue to the class data queue.
  2146. //
  2147. MouPrint((
  2148. 3,
  2149. "MOUCLASS-MouseClassServiceCallback: number of bytes in second move to class 0x%lx\n",
  2150. moveSize
  2151. ));
  2152. MouPrint((
  2153. 3,
  2154. "MOUCLASS-MouseClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
  2155. (PCHAR) InputDataStart,
  2156. (PCHAR) deviceExtension->DataIn
  2157. ));
  2158. RtlMoveMemory(
  2159. (PCHAR) deviceExtension->DataIn,
  2160. (PCHAR) InputDataStart,
  2161. moveSize
  2162. );
  2163. //
  2164. // Update the class input data queue insertion pointer.
  2165. //
  2166. deviceExtension->DataIn = (PMOUSE_INPUT_DATA)
  2167. (((PCHAR) deviceExtension->DataIn) + moveSize);
  2168. }
  2169. //
  2170. // Update the input data queue counter.
  2171. //
  2172. deviceExtension->InputCount +=
  2173. (bytesToMove / sizeof(MOUSE_INPUT_DATA));
  2174. *InputDataConsumed += (bytesToMove / sizeof(MOUSE_INPUT_DATA));
  2175. MouPrint((
  2176. 3,
  2177. "MOUCLASS-MouseClassServiceCallback: changed InputCount to %ld entries in the class queue\n",
  2178. deviceExtension->InputCount
  2179. ));
  2180. MouPrint((
  2181. 3,
  2182. "MOUCLASS-MouseClassServiceCallback: DataIn 0x%lx, DataOut 0x%lx\n",
  2183. deviceExtension->DataIn,
  2184. deviceExtension->DataOut
  2185. ));
  2186. MouPrint((
  2187. 3,
  2188. "MOUCLASS-MouseClassServiceCallback: Input data items consumed = %d\n",
  2189. *InputDataConsumed
  2190. ));
  2191. #if ALLOW_OVERFLOW
  2192. #else
  2193. }
  2194. #endif
  2195. }
  2196. //
  2197. // If we still have data in our internal queue, fulfill any outstanding
  2198. // reads now until either we run out of data or outstanding reads
  2199. //
  2200. while (deviceExtension->InputCount > 0 &&
  2201. (irp = MouseClassDequeueRead (deviceExtension)) != NULL) {
  2202. irp->IoStatus.Status = MouseClassReadCopyData (deviceExtension, irp);
  2203. InsertTailList (&listHead, &irp->Tail.Overlay.ListEntry);
  2204. }
  2205. //
  2206. // Release the class input data queue spinlock.
  2207. //
  2208. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  2209. if (logOverflow) {
  2210. MouseClassLogError (DeviceObject,
  2211. MOUCLASS_MOU_BUFFER_OVERFLOW,
  2212. MOUSE_ERROR_VALUE_BASE + 210,
  2213. 0,
  2214. 2,
  2215. dumpData,
  2216. 0);
  2217. }
  2218. //
  2219. // Complete all the read requests we have fulfilled outside of the spin lock
  2220. //
  2221. while (! IsListEmpty (&listHead)) {
  2222. PLIST_ENTRY entry = RemoveHeadList (&listHead);
  2223. irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
  2224. ASSERT (NT_SUCCESS (irp->IoStatus.Status) &&
  2225. irp->IoStatus.Status != STATUS_PENDING);
  2226. IoCompleteRequest (irp, IO_KEYBOARD_INCREMENT);
  2227. IoReleaseRemoveLock (&deviceExtension->RemoveLock, irp);
  2228. }
  2229. MouPrint((2,"MOUCLASS-MouseClassServiceCallback: exit\n"));
  2230. }
  2231. VOID
  2232. MouseClassUnload(
  2233. IN PDRIVER_OBJECT DriverObject
  2234. )
  2235. /*++
  2236. Routine Description:
  2237. This routine is the class driver unload routine.
  2238. NOTE: Not currently implemented.
  2239. Arguments:
  2240. DeviceObject - Pointer to class device object.
  2241. Return Value:
  2242. None.
  2243. --*/
  2244. {
  2245. PLIST_ENTRY entry;
  2246. PDEVICE_EXTENSION data;
  2247. PPORT port;
  2248. PIRP irp;
  2249. UNREFERENCED_PARAMETER(DriverObject);
  2250. PAGED_CODE ();
  2251. MouPrint((2,"MOUCLASS-MouseClassUnload: enter\n"));
  2252. //
  2253. // Delete all of our legacy devices
  2254. //
  2255. for (entry = Globals.LegacyDeviceList.Flink;
  2256. entry != &Globals.LegacyDeviceList;
  2257. /* advance to next before deleting the devobj */) {
  2258. BOOLEAN enabled = FALSE;
  2259. PFILE_OBJECT file = NULL;
  2260. data = CONTAINING_RECORD (entry, DEVICE_EXTENSION, Link);
  2261. ASSERT (data->PnP == FALSE);
  2262. if (Globals.GrandMaster) {
  2263. port = &Globals.AssocClassList[data->UnitId];
  2264. ASSERT (port->Port == data);
  2265. enabled = port->Enabled;
  2266. file = port->File;
  2267. port->Enabled = FALSE;
  2268. port->File = NULL;
  2269. port->Free = TRUE;
  2270. }
  2271. else {
  2272. enabled = data->Enabled;
  2273. file = data->File;
  2274. ASSERT (data->File);
  2275. data->Enabled = FALSE;
  2276. }
  2277. if (enabled) {
  2278. irp = IoAllocateIrp(data->TopPort->StackSize+1, FALSE);
  2279. if (irp) {
  2280. MouEnableDisablePort (FALSE, irp, data, &file);
  2281. IoFreeIrp (irp);
  2282. }
  2283. }
  2284. //
  2285. // This file object represents the open we performed on the legacy
  2286. // port device object. It does NOT represent the open that the RIT
  2287. // performed on our DO.
  2288. //
  2289. if (file) {
  2290. ObDereferenceObject(file);
  2291. }
  2292. //
  2293. // Clean out the queue only if there is no GM
  2294. //
  2295. if (Globals.GrandMaster == NULL) {
  2296. MouseClassCleanupQueue (data->Self, data, NULL);
  2297. }
  2298. RemoveEntryList (&data->Link);
  2299. entry = entry->Flink;
  2300. MouseClassDeleteLegacyDevice (data);
  2301. }
  2302. //
  2303. // Delete the grandmaster if it exists
  2304. //
  2305. if (Globals.GrandMaster) {
  2306. data = Globals.GrandMaster;
  2307. Globals.GrandMaster = NULL;
  2308. MouseClassCleanupQueue (data->Self, data, NULL);
  2309. MouseClassDeleteLegacyDevice (data);
  2310. }
  2311. ExFreePool(Globals.RegistryPath.Buffer);
  2312. if (Globals.AssocClassList) {
  2313. #if DBG
  2314. ULONG i;
  2315. for (i = 0; i < Globals.NumAssocClass; i++) {
  2316. ASSERT (Globals.AssocClassList[i].Free == TRUE);
  2317. ASSERT (Globals.AssocClassList[i].Enabled == FALSE);
  2318. ASSERT (Globals.AssocClassList[i].File == NULL);
  2319. }
  2320. #endif
  2321. ExFreePool(Globals.AssocClassList);
  2322. }
  2323. MouPrint((2,"MOUCLASS-MouseClassUnload: exit\n"));
  2324. }
  2325. VOID
  2326. MouConfiguration()
  2327. /*++
  2328. Routine Description:
  2329. This routine stores the configuration information for this device.
  2330. Return Value:
  2331. None. As a side-effect, sets fields in DeviceExtension->MouseAttributes.
  2332. --*/
  2333. {
  2334. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  2335. ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
  2336. ULONG defaultMaximumPortsServiced = 1;
  2337. ULONG defaultConnectMultiplePorts = 0;
  2338. NTSTATUS status = STATUS_SUCCESS;
  2339. UNICODE_STRING parametersPath;
  2340. UNICODE_STRING defaultUnicodeName;
  2341. PWSTR path = NULL;
  2342. USHORT queriesPlusOne = 5;
  2343. PAGED_CODE ();
  2344. parametersPath.Buffer = NULL;
  2345. //
  2346. // Registry path is already null-terminated, so just use it.
  2347. //
  2348. path = Globals.RegistryPath.Buffer;
  2349. //
  2350. // Allocate the Rtl query table.
  2351. //
  2352. parameters = ExAllocatePool(
  2353. PagedPool,
  2354. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
  2355. );
  2356. if (!parameters) {
  2357. MouPrint((
  2358. 1,
  2359. "MOUCLASS-MouConfiguration: Couldn't allocate table for Rtl query to parameters for %ws\n",
  2360. path
  2361. ));
  2362. status = STATUS_UNSUCCESSFUL;
  2363. } else {
  2364. RtlZeroMemory(
  2365. parameters,
  2366. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
  2367. );
  2368. //
  2369. // Form a path to this driver's Parameters subkey.
  2370. //
  2371. RtlInitUnicodeString(
  2372. &parametersPath,
  2373. NULL
  2374. );
  2375. parametersPath.MaximumLength = Globals.RegistryPath.Length +
  2376. sizeof(L"\\Parameters");
  2377. parametersPath.Buffer = ExAllocatePool(
  2378. PagedPool,
  2379. parametersPath.MaximumLength
  2380. );
  2381. if (!parametersPath.Buffer) {
  2382. MouPrint((
  2383. 1,
  2384. "MOUCLASS-MouConfiguration: Couldn't allocate string for path to parameters for %ws\n",
  2385. path
  2386. ));
  2387. status = STATUS_UNSUCCESSFUL;
  2388. }
  2389. }
  2390. if (NT_SUCCESS(status)) {
  2391. //
  2392. // Form the parameters path.
  2393. //
  2394. RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength);
  2395. RtlAppendUnicodeToString(&parametersPath, path);
  2396. RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
  2397. MouPrint((
  2398. 1,
  2399. "MOUCLASS-MouConfiguration: parameters path is %ws\n",
  2400. parametersPath.Buffer
  2401. ));
  2402. //
  2403. // Form the default pointer class device name, in case it is not
  2404. // specified in the registry.
  2405. //
  2406. RtlInitUnicodeString(
  2407. &defaultUnicodeName,
  2408. DD_POINTER_CLASS_BASE_NAME_U
  2409. );
  2410. //
  2411. // Gather all of the "user specified" information from
  2412. // the registry.
  2413. //
  2414. parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  2415. parameters[0].Name = L"MouseDataQueueSize";
  2416. parameters[0].EntryContext =
  2417. &Globals.InitExtension.MouseAttributes.InputDataQueueLength;
  2418. parameters[0].DefaultType = REG_DWORD;
  2419. parameters[0].DefaultData = &defaultDataQueueSize;
  2420. parameters[0].DefaultLength = sizeof(ULONG);
  2421. parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  2422. parameters[1].Name = L"MaximumPortsServiced";
  2423. parameters[1].EntryContext = &Globals.PortsServiced;
  2424. parameters[1].DefaultType = REG_DWORD;
  2425. parameters[1].DefaultData = &defaultMaximumPortsServiced;
  2426. parameters[1].DefaultLength = sizeof(ULONG);
  2427. parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  2428. parameters[2].Name = L"PointerDeviceBaseName";
  2429. parameters[2].EntryContext = &Globals.BaseClassName;
  2430. parameters[2].DefaultType = REG_SZ;
  2431. parameters[2].DefaultData = defaultUnicodeName.Buffer;
  2432. parameters[2].DefaultLength = 0;
  2433. parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  2434. parameters[3].Name = L"ConnectMultiplePorts";
  2435. parameters[3].EntryContext = &Globals.ConnectOneClassToOnePort;
  2436. parameters[3].DefaultType = REG_DWORD;
  2437. parameters[3].DefaultData = &defaultConnectMultiplePorts;
  2438. parameters[3].DefaultLength = sizeof(ULONG);
  2439. status = RtlQueryRegistryValues(
  2440. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  2441. parametersPath.Buffer,
  2442. parameters,
  2443. NULL,
  2444. NULL
  2445. );
  2446. if (!NT_SUCCESS(status)) {
  2447. MouPrint((
  2448. 1,
  2449. "MOUCLASS-MouConfiguration: RtlQueryRegistryValues failed with 0x%x\n",
  2450. status
  2451. ));
  2452. }
  2453. }
  2454. if (!NT_SUCCESS(status)) {
  2455. //
  2456. // Go ahead and assign driver defaults.
  2457. //
  2458. Globals.InitExtension.MouseAttributes.InputDataQueueLength =
  2459. defaultDataQueueSize;
  2460. Globals.PortsServiced = defaultMaximumPortsServiced;
  2461. Globals.ConnectOneClassToOnePort = defaultConnectMultiplePorts;
  2462. RtlCopyUnicodeString(&Globals.BaseClassName, &defaultUnicodeName);
  2463. }
  2464. MouPrint((
  2465. 1,
  2466. "MOUCLASS-MouConfiguration: Mouse class base name = %ws\n",
  2467. Globals.BaseClassName.Buffer
  2468. ));
  2469. if (Globals.InitExtension.MouseAttributes.InputDataQueueLength == 0) {
  2470. MouPrint((
  2471. 1,
  2472. "MOUCLASS-MouConfiguration: overriding MouseInputDataQueueLength = 0x%x\n",
  2473. Globals.InitExtension.MouseAttributes.InputDataQueueLength
  2474. ));
  2475. Globals.InitExtension.MouseAttributes.InputDataQueueLength =
  2476. defaultDataQueueSize;
  2477. }
  2478. Globals.InitExtension.MouseAttributes.InputDataQueueLength *=
  2479. sizeof(MOUSE_INPUT_DATA);
  2480. MouPrint((
  2481. 1,
  2482. "MOUCLASS-MouConfiguration: MouseInputDataQueueLength = 0x%x\n",
  2483. Globals.InitExtension.MouseAttributes.InputDataQueueLength
  2484. ));
  2485. MouPrint((
  2486. 1,
  2487. "MOUCLASS-MouConfiguration: MaximumPortsServiced = %d\n",
  2488. Globals.PortsServiced
  2489. ));
  2490. //
  2491. // Invert the flag that specifies the type of class/port connections.
  2492. // We used it in the RtlQuery call in an inverted fashion.
  2493. //
  2494. Globals.ConnectOneClassToOnePort = !Globals.ConnectOneClassToOnePort;
  2495. MouPrint((
  2496. 1,
  2497. "MOUCLASS-MouConfiguration: Connection Type = %d\n",
  2498. Globals.ConnectOneClassToOnePort
  2499. ));
  2500. //
  2501. // Free the allocated memory before returning.
  2502. //
  2503. if (parametersPath.Buffer)
  2504. ExFreePool(parametersPath.Buffer);
  2505. if (parameters)
  2506. ExFreePool(parameters);
  2507. }
  2508. NTSTATUS
  2509. MouCreateClassObject(
  2510. IN PDRIVER_OBJECT DriverObject,
  2511. IN PDEVICE_EXTENSION TmpDeviceExtension,
  2512. OUT PDEVICE_OBJECT * ClassDeviceObject,
  2513. OUT PWCHAR * FullDeviceName,
  2514. IN BOOLEAN Legacy
  2515. )
  2516. /*++
  2517. Routine Description:
  2518. This routine creates the mouse class device object.
  2519. Arguments:
  2520. DriverObject - Pointer to driver object created by system.
  2521. TmpDeviceExtension - Pointer to the template device extension.
  2522. FullDeviceName - Pointer to the Unicode string that is the full path name
  2523. for the class device object.
  2524. ClassDeviceObject - Pointer to a pointer to the class device object.
  2525. Return Value:
  2526. The function value is the final status from the operation.
  2527. --*/
  2528. {
  2529. NTSTATUS status;
  2530. ULONG uniqueErrorValue;
  2531. PDEVICE_EXTENSION deviceExtension = NULL;
  2532. NTSTATUS errorCode = STATUS_SUCCESS;
  2533. UNICODE_STRING fullClassName = {0,0,0};
  2534. ULONG dumpCount = 0;
  2535. ULONG dumpData[DUMP_COUNT];
  2536. ULONG i;
  2537. WCHAR nameIndex;
  2538. PAGED_CODE ();
  2539. MouPrint((1,"\n\nMOUCLASS-MouCreateClassObject: enter\n"));
  2540. //
  2541. // Create a non-exclusive device object for the mouse class device.
  2542. //
  2543. ExAcquireFastMutex (&Globals.Mutex);
  2544. //
  2545. // Make sure ClassDeviceObject isn't pointing to a random pointer value
  2546. //
  2547. *ClassDeviceObject = NULL;
  2548. if (NULL == Globals.GrandMaster) {
  2549. //
  2550. // Create a legacy name for this DO.
  2551. //
  2552. ExReleaseFastMutex (&Globals.Mutex);
  2553. //
  2554. // Set up space for the class's full device object name.
  2555. //
  2556. fullClassName.MaximumLength = sizeof(L"\\Device\\") +
  2557. + Globals.BaseClassName.Length
  2558. + sizeof(L"0");
  2559. if (Globals.ConnectOneClassToOnePort && Legacy) {
  2560. fullClassName.MaximumLength += sizeof(L"Legacy");
  2561. }
  2562. fullClassName.Buffer = ExAllocatePool(PagedPool,
  2563. fullClassName.MaximumLength);
  2564. if (!fullClassName.Buffer) {
  2565. MouPrint((
  2566. 1,
  2567. "MOUCLASS-MouseClassInitialize: Couldn't allocate string for device object name\n"
  2568. ));
  2569. status = STATUS_UNSUCCESSFUL;
  2570. errorCode = MOUCLASS_INSUFFICIENT_RESOURCES;
  2571. uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 6;
  2572. dumpData[0] = (ULONG) fullClassName.MaximumLength;
  2573. dumpCount = 1;
  2574. goto MouCreateClassObjectExit;
  2575. }
  2576. RtlZeroMemory(fullClassName.Buffer, fullClassName.MaximumLength);
  2577. RtlAppendUnicodeToString(&fullClassName, L"\\Device\\");
  2578. RtlAppendUnicodeToString(&fullClassName, Globals.BaseClassName.Buffer);
  2579. if (Globals.ConnectOneClassToOnePort && Legacy) {
  2580. RtlAppendUnicodeToString(&fullClassName, L"Legacy");
  2581. }
  2582. RtlAppendUnicodeToString(&fullClassName, L"0");
  2583. //
  2584. // Using the base name start trying to create device names until
  2585. // one succeeds. Everytime start over at 0 to eliminate gaps.
  2586. //
  2587. nameIndex = 0;
  2588. do {
  2589. fullClassName.Buffer [ (fullClassName.Length / sizeof (WCHAR)) - 1]
  2590. = L'0' + nameIndex++;
  2591. MouPrint((
  2592. 1,
  2593. "MOUCLASS-MouCreateClassObject: Creating device object named %ws\n",
  2594. fullClassName.Buffer
  2595. ));
  2596. status = IoCreateDevice(DriverObject,
  2597. sizeof (DEVICE_EXTENSION),
  2598. &fullClassName,
  2599. FILE_DEVICE_MOUSE,
  2600. 0,
  2601. FALSE,
  2602. ClassDeviceObject);
  2603. } while (STATUS_OBJECT_NAME_COLLISION == status);
  2604. *FullDeviceName = fullClassName.Buffer;
  2605. } else {
  2606. ExReleaseFastMutex (&Globals.Mutex);
  2607. status = IoCreateDevice(DriverObject,
  2608. sizeof(DEVICE_EXTENSION),
  2609. NULL, // no name for this FDO
  2610. FILE_DEVICE_MOUSE,
  2611. 0,
  2612. FALSE,
  2613. ClassDeviceObject);
  2614. *FullDeviceName = NULL;
  2615. }
  2616. if (!NT_SUCCESS(status)) {
  2617. MouPrint((
  2618. 1,
  2619. "MOUCLASS-MouCreateClassObject: Could not create class device object = %ws\n",
  2620. fullClassName.Buffer
  2621. ));
  2622. errorCode = MOUCLASS_COULD_NOT_CREATE_DEVICE;
  2623. uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 6;
  2624. dumpData[0] = (ULONG) fullClassName.MaximumLength;
  2625. dumpCount = 1;
  2626. goto MouCreateClassObjectExit;
  2627. }
  2628. //
  2629. // Do buffered I/O. I.e., the I/O system will copy to/from user data
  2630. // from/to a system buffer.
  2631. //
  2632. (*ClassDeviceObject)->Flags |= DO_BUFFERED_IO;
  2633. deviceExtension =
  2634. (PDEVICE_EXTENSION)(*ClassDeviceObject)->DeviceExtension;
  2635. *deviceExtension = *TmpDeviceExtension;
  2636. deviceExtension->Self = *ClassDeviceObject;
  2637. IoInitializeRemoveLock (&deviceExtension->RemoveLock, MOUSE_POOL_TAG, 0, 10);
  2638. //
  2639. // Initialize spin lock for critical sections.
  2640. //
  2641. KeInitializeSpinLock(&deviceExtension->SpinLock);
  2642. //
  2643. // Initialize mouse class flags to indicate there is no outstanding
  2644. // read request pending and cleanup has not been initiated.
  2645. //
  2646. InitializeListHead (&deviceExtension->ReadQueue);
  2647. //
  2648. // No trusted subsystem has sent us an open yet.
  2649. //
  2650. deviceExtension->TrustedSubsystemCount = 0;
  2651. //
  2652. // Allocate the ring buffer for the mouse class input data.
  2653. //
  2654. deviceExtension->InputData =
  2655. ExAllocatePool(
  2656. NonPagedPool,
  2657. deviceExtension->MouseAttributes.InputDataQueueLength
  2658. );
  2659. if (!deviceExtension->InputData) {
  2660. //
  2661. // Could not allocate memory for the mouse class data queue.
  2662. //
  2663. MouPrint((
  2664. 1,
  2665. "MOUCLASS-MouCreateClassObject: Could not allocate input data queue for %ws\n",
  2666. fullClassName.Buffer
  2667. ));
  2668. status = STATUS_INSUFFICIENT_RESOURCES;
  2669. //
  2670. // Log an error.
  2671. //
  2672. errorCode = MOUCLASS_NO_BUFFER_ALLOCATED;
  2673. uniqueErrorValue = MOUSE_ERROR_VALUE_BASE + 20;
  2674. goto MouCreateClassObjectExit;
  2675. }
  2676. //
  2677. // Initialize mouse class input data queue.
  2678. //
  2679. MouInitializeDataQueue((PVOID)deviceExtension);
  2680. MouCreateClassObjectExit:
  2681. if (status != STATUS_SUCCESS) {
  2682. //
  2683. // Some part of the initialization failed. Log an error, and
  2684. // clean up the resources for the failed part of the initialization.
  2685. //
  2686. RtlFreeUnicodeString (&fullClassName);
  2687. *FullDeviceName = NULL;
  2688. if (errorCode != STATUS_SUCCESS) {
  2689. MouseClassLogError (
  2690. (*ClassDeviceObject == NULL) ?
  2691. (PVOID) DriverObject : (PVOID) *ClassDeviceObject,
  2692. errorCode,
  2693. uniqueErrorValue,
  2694. status,
  2695. dumpCount,
  2696. dumpData,
  2697. 0);
  2698. }
  2699. if ((deviceExtension) && (deviceExtension->InputData)) {
  2700. ExFreePool(deviceExtension->InputData);
  2701. deviceExtension->InputData = NULL;
  2702. }
  2703. if (*ClassDeviceObject) {
  2704. IoDeleteDevice(*ClassDeviceObject);
  2705. *ClassDeviceObject = NULL;
  2706. }
  2707. }
  2708. MouPrint((1,"MOUCLASS-MouCreateClassObject: exit\n"));
  2709. return(status);
  2710. }
  2711. #if DBG
  2712. VOID
  2713. MouDebugPrint(
  2714. ULONG DebugPrintLevel,
  2715. PCCHAR DebugMessage,
  2716. ...
  2717. )
  2718. /*++
  2719. Routine Description:
  2720. Debug print routine.
  2721. Arguments:
  2722. Debug print level between 0 and 3, with 3 being the most verbose.
  2723. Return Value:
  2724. None.
  2725. --*/
  2726. {
  2727. va_list ap;
  2728. va_start(ap, DebugMessage);
  2729. if (DebugPrintLevel <= Globals.Debug) {
  2730. char buffer[256];
  2731. (VOID) vsprintf(buffer, DebugMessage, ap);
  2732. DbgPrint(buffer);
  2733. }
  2734. va_end(ap);
  2735. }
  2736. #endif
  2737. NTSTATUS
  2738. MouDeterminePortsServiced(
  2739. IN PUNICODE_STRING BasePortName,
  2740. IN OUT PULONG NumberPortsServiced
  2741. )
  2742. /*++
  2743. Routine Description:
  2744. This routine reads the DEVICEMAP portion of the registry to determine
  2745. how many ports the class driver is to service. Depending on the
  2746. value of DeviceExtension->ConnectOneClassToOnePort, the class driver
  2747. will eventually create one device object per port device serviced, or
  2748. one class device object that connects to multiple port device objects.
  2749. Assumptions:
  2750. 1. If the base device name for the class driver is "PointerClass",
  2751. ^^^^^
  2752. then the port drivers it can service are found under the
  2753. "PointerPort" subkey in the DEVICEMAP portion of the registry.
  2754. ^^^^
  2755. 2. The port device objects are created with suffixes in strictly
  2756. ascending order, starting with suffix 0. E.g.,
  2757. \Device\PointerPort0 indicates the first pointer port device,
  2758. \Device\PointerPort1 the second, and so on. There are no gaps
  2759. in the list.
  2760. 3. If ConnectOneClassToOnePort is non-zero, there is a 1:1
  2761. correspondence between class device objects and port device
  2762. objects. I.e., \Device\PointerClass0 will connect to
  2763. \Device\PointerPort0, \Device\PointerClass1 to
  2764. \Device\PointerPort1, and so on.
  2765. 4. If ConnectOneClassToOnePort is zero, there is a 1:many
  2766. correspondence between class device objects and port device
  2767. objects. I.e., \Device\PointerClass0 will connect to
  2768. \Device\PointerPort0, and \Device\PointerPort1, and so on.
  2769. Note that for Product 1, the Raw Input Thread (Windows USER) will
  2770. only deign to open and read from one pointing device. Hence, it is
  2771. safe to make simplifying assumptions because the driver is basically
  2772. providing much more functionality than the RIT will use.
  2773. Arguments:
  2774. BasePortName - Pointer to the Unicode string that is the base path name
  2775. for the port device.
  2776. NumberPortsServiced - Pointer to storage that will receive the
  2777. number of ports this class driver should service.
  2778. Return Value:
  2779. The function value is the final status from the operation.
  2780. --*/
  2781. {
  2782. NTSTATUS status;
  2783. PRTL_QUERY_REGISTRY_TABLE registryTable = NULL;
  2784. USHORT queriesPlusOne = 2;
  2785. PAGED_CODE ();
  2786. //
  2787. // Initialize the result.
  2788. //
  2789. *NumberPortsServiced = 0;
  2790. //
  2791. // Allocate the Rtl query table.
  2792. //
  2793. registryTable = ExAllocatePool(
  2794. PagedPool,
  2795. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
  2796. );
  2797. if (!registryTable) {
  2798. MouPrint((
  2799. 1,
  2800. "MOUCLASS-MouDeterminePortsServiced: Couldn't allocate table for Rtl query\n"
  2801. ));
  2802. status = STATUS_UNSUCCESSFUL;
  2803. } else {
  2804. RtlZeroMemory(
  2805. registryTable,
  2806. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
  2807. );
  2808. //
  2809. // Set things up so that MouDeviceMapQueryCallback will be
  2810. // called once for every value in the pointer port section
  2811. // of the registry's hardware devicemap.
  2812. //
  2813. registryTable[0].QueryRoutine = MouDeviceMapQueryCallback;
  2814. registryTable[0].Name = NULL;
  2815. status = RtlQueryRegistryValues(
  2816. RTL_REGISTRY_DEVICEMAP | RTL_REGISTRY_OPTIONAL,
  2817. BasePortName->Buffer,
  2818. registryTable,
  2819. NumberPortsServiced,
  2820. NULL
  2821. );
  2822. if (!NT_SUCCESS(status)) {
  2823. MouPrint((
  2824. 1,
  2825. "MOUCLASS-MouDeterminePortsServiced: RtlQueryRegistryValues failed with 0x%x\n",
  2826. status
  2827. ));
  2828. }
  2829. ExFreePool(registryTable);
  2830. }
  2831. return(status);
  2832. }
  2833. NTSTATUS
  2834. MouDeviceMapQueryCallback(
  2835. IN PWSTR ValueName,
  2836. IN ULONG ValueType,
  2837. IN PVOID ValueData,
  2838. IN ULONG ValueLength,
  2839. IN PVOID Context,
  2840. IN PVOID EntryContext
  2841. )
  2842. /*++
  2843. Routine Description:
  2844. This is the callout routine specified in a call to
  2845. RtlQueryRegistryValues. It increments the value pointed
  2846. to by the Context parameter.
  2847. Arguments:
  2848. ValueName - Unused.
  2849. ValueType - Unused.
  2850. ValueData - Unused.
  2851. ValueLength - Unused.
  2852. Context - Pointer to a count of the number of times this
  2853. routine has been called. This is the number of ports
  2854. the class driver needs to service.
  2855. EntryContext - Unused.
  2856. Return Value:
  2857. The function value is the final status from the operation.
  2858. --*/
  2859. {
  2860. PAGED_CODE ();
  2861. *(PULONG)Context += 1;
  2862. return(STATUS_SUCCESS);
  2863. }
  2864. NTSTATUS
  2865. MouEnableDisablePort(
  2866. IN BOOLEAN EnableFlag,
  2867. IN PIRP Irp,
  2868. IN PDEVICE_EXTENSION Port,
  2869. IN OUT PFILE_OBJECT * File
  2870. )
  2871. /*++
  2872. Routine Description:
  2873. This routine sends an enable or a disable request to the port driver.
  2874. The legacy port drivers require an enable or disable ioctl, while the
  2875. plug and play drivers require merely a create.
  2876. Arguments:
  2877. DeviceObject - Pointer to class device object.
  2878. EnableFlag - If TRUE, send an ENABLE request; otherwise, send DISABLE.
  2879. PortIndex - Index into the PortDeviceObjectList[] for the current
  2880. enable/disable request.
  2881. Return Value:
  2882. Status is returned.
  2883. --*/
  2884. {
  2885. IO_STATUS_BLOCK ioStatus;
  2886. UNICODE_STRING name = {0,0,0};
  2887. PDEVICE_OBJECT device = NULL;
  2888. NTSTATUS status = STATUS_SUCCESS;
  2889. PWCHAR buffer = NULL;
  2890. ULONG bufferLength = 0;
  2891. PIO_STACK_LOCATION stack;
  2892. PAGED_CODE ();
  2893. MouPrint((2,"MOUCLASS-MouEnableDisablePort: enter\n"));
  2894. //
  2895. // Create notification event object to be used to signal the
  2896. // request completion.
  2897. //
  2898. if ((Port->TrueClassDevice == Port->Self) && (Port->PnP)) {
  2899. IoCopyCurrentIrpStackLocationToNext (Irp);
  2900. stack = IoGetNextIrpStackLocation (Irp);
  2901. if (EnableFlag) {
  2902. //
  2903. // Since there is no grand master there could not have been a
  2904. // create file against the FDO before it was started. Therefore
  2905. // the only time we would enable is during a create and not a
  2906. // start as we might with another FDO attached to an already open
  2907. // grand master.
  2908. //
  2909. ASSERT (IRP_MJ_CREATE == stack->MajorFunction);
  2910. } else {
  2911. if (IRP_MJ_CLOSE != stack->MajorFunction) {
  2912. //
  2913. // We are disabling. This could be because the device was
  2914. // closed, or because the device was removed out from
  2915. // underneath us.
  2916. //
  2917. ASSERT (IRP_MJ_PNP == stack->MajorFunction);
  2918. ASSERT ((IRP_MN_REMOVE_DEVICE == stack->MinorFunction) ||
  2919. (IRP_MN_STOP_DEVICE == stack->MinorFunction));
  2920. stack->MajorFunction = IRP_MJ_CLOSE;
  2921. }
  2922. }
  2923. //
  2924. // Either way we need only pass the Irp down without mucking with the
  2925. // file object.
  2926. //
  2927. status = MouseSendIrpSynchronously (Port->TopPort, Irp, FALSE);
  2928. } else if (!Port->PnP) {
  2929. Port->Enabled = EnableFlag;
  2930. //
  2931. // We have here an old style Port Object. Therefore we send it the
  2932. // old style internal IOCTLs of ENABLE and DISABLE, and not the new
  2933. // style of passing on a create and close.
  2934. //
  2935. IoCopyCurrentIrpStackLocationToNext (Irp);
  2936. stack = IoGetNextIrpStackLocation (Irp);
  2937. stack->Parameters.DeviceIoControl.OutputBufferLength = 0;
  2938. stack->Parameters.DeviceIoControl.InputBufferLength = 0;
  2939. stack->Parameters.DeviceIoControl.IoControlCode
  2940. = EnableFlag ? IOCTL_INTERNAL_MOUSE_ENABLE
  2941. : IOCTL_INTERNAL_MOUSE_DISABLE;
  2942. stack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2943. stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  2944. status = MouseSendIrpSynchronously (Port->TopPort, Irp, FALSE);
  2945. } else {
  2946. //
  2947. // We are dealing with a plug and play port and we have a Grand
  2948. // Master.
  2949. //
  2950. ASSERT (Port->TrueClassDevice == Globals.GrandMaster->Self);
  2951. //
  2952. // Therefore we need to substitute the given file object for a new
  2953. // one for use with each individual ports.
  2954. // For enable, we need to create this file object against the given
  2955. // port and then hand it back in the File parameter, or for disable,
  2956. // deref the File parameter and free that file object.
  2957. //
  2958. // Of course, there must be storage for a file pointer pointed to by
  2959. // the File parameter.
  2960. //
  2961. ASSERT (NULL != File);
  2962. if (EnableFlag) {
  2963. ASSERT (NULL == *File);
  2964. //
  2965. // The following long list of rigamaroll translates into
  2966. // sending the lower driver a create file IRP and creating a
  2967. // NEW file object disjoint from the one given us in our create
  2968. // file routine.
  2969. //
  2970. // Normally we would just pass down the Create IRP we were
  2971. // given, but we do not have a one to one correspondance of
  2972. // top device objects and port device objects.
  2973. // This means we need more file objects: one for each of the
  2974. // miriad of lower DOs.
  2975. //
  2976. bufferLength = 0;
  2977. status = IoGetDeviceProperty (
  2978. Port->PDO,
  2979. DevicePropertyPhysicalDeviceObjectName,
  2980. bufferLength,
  2981. buffer,
  2982. &bufferLength);
  2983. ASSERT (STATUS_BUFFER_TOO_SMALL == status);
  2984. buffer = ExAllocatePool (PagedPool, bufferLength);
  2985. if (NULL == buffer) {
  2986. return STATUS_INSUFFICIENT_RESOURCES;
  2987. }
  2988. status = IoGetDeviceProperty (
  2989. Port->PDO,
  2990. DevicePropertyPhysicalDeviceObjectName,
  2991. bufferLength,
  2992. buffer,
  2993. &bufferLength);
  2994. name.MaximumLength = (USHORT) bufferLength;
  2995. name.Length = (USHORT) bufferLength - sizeof (UNICODE_NULL);
  2996. name.Buffer = buffer;
  2997. status = IoGetDeviceObjectPointer (&name,
  2998. FILE_ALL_ACCESS,
  2999. File,
  3000. &device);
  3001. ExFreePool (buffer);
  3002. //
  3003. // Note, that this create will first go to ourselves since we
  3004. // are attached to this PDO stack. Therefore two things are
  3005. // noteworthy. This driver will receive another Create IRP
  3006. // (with a different file object) (not to the grand master but
  3007. // to one of the subordenant FDO's). The device object returned
  3008. // will be the subordenant FDO, which in this case is the "self"
  3009. // device object of this Port.
  3010. //
  3011. if (NT_SUCCESS (status)) {
  3012. ASSERT (device == Port->Self);
  3013. //
  3014. // Register for Target device removal events
  3015. //
  3016. ASSERT (NULL == Port->TargetNotifyHandle);
  3017. status = IoRegisterPlugPlayNotification (
  3018. EventCategoryTargetDeviceChange,
  3019. 0, // No flags
  3020. *File,
  3021. Port->Self->DriverObject,
  3022. MouseClassPlugPlayNotification,
  3023. Port,
  3024. &Port->TargetNotifyHandle);
  3025. }
  3026. } else {
  3027. //
  3028. // Getting rid of the handle is easy. Just deref the file.
  3029. //
  3030. ObDereferenceObject (*File);
  3031. *File = NULL;
  3032. }
  3033. }
  3034. MouPrint((2,"MOUCLASS-MouEnableDisablePort: exit\n"));
  3035. return (status);
  3036. }
  3037. VOID
  3038. MouInitializeDataQueue (
  3039. IN PVOID Context
  3040. )
  3041. /*++
  3042. Routine Description:
  3043. This routine initializes the input data queue. IRQL is raised to
  3044. DISPATCH_LEVEL to synchronize with StartIo, and the device object
  3045. spinlock is acquired.
  3046. Arguments:
  3047. Context - Supplies a pointer to the device extension.
  3048. Return Value:
  3049. None.
  3050. --*/
  3051. {
  3052. KIRQL oldIrql;
  3053. PDEVICE_EXTENSION deviceExtension;
  3054. MouPrint((3,"MOUCLASS-MouInitializeDataQueue: enter\n"));
  3055. //
  3056. // Get address of device extension.
  3057. //
  3058. deviceExtension = (PDEVICE_EXTENSION)Context;
  3059. //
  3060. // Acquire the spinlock to protect the input data
  3061. // queue and associated pointers.
  3062. //
  3063. KeAcquireSpinLock(&deviceExtension->SpinLock, &oldIrql);
  3064. //
  3065. // Initialize the input data queue.
  3066. //
  3067. deviceExtension->InputCount = 0;
  3068. deviceExtension->DataIn = deviceExtension->InputData;
  3069. deviceExtension->DataOut = deviceExtension->InputData;
  3070. deviceExtension->OkayToLogOverflow = TRUE;
  3071. //
  3072. // Release the spinlock and return to the old IRQL.
  3073. //
  3074. KeReleaseSpinLock(&deviceExtension->SpinLock, oldIrql);
  3075. MouPrint((3,"MOUCLASS-MouInitializeDataQueue: exit\n"));
  3076. } // end MouInitializeDataQueue
  3077. NTSTATUS
  3078. MouSendConnectRequest(
  3079. IN PDEVICE_EXTENSION ClassData,
  3080. IN PVOID ServiceCallback
  3081. )
  3082. /*++
  3083. Routine Description:
  3084. This routine sends a connect request to the port driver.
  3085. Arguments:
  3086. DeviceObject - Pointer to class device object.
  3087. ServiceCallback - Pointer to the class service callback routine.
  3088. PortIndex - The index into the PortDeviceObjectList[] for the current
  3089. connect request.
  3090. Return Value:
  3091. Status is returned.
  3092. --*/
  3093. {
  3094. PIRP irp;
  3095. IO_STATUS_BLOCK ioStatus;
  3096. NTSTATUS status;
  3097. KEVENT event;
  3098. CONNECT_DATA connectData;
  3099. PAGED_CODE ();
  3100. MouPrint((2,"MOUCLASS-MouSendConnectRequest: enter\n"));
  3101. //
  3102. // Create notification event object to be used to signal the
  3103. // request completion.
  3104. //
  3105. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3106. //
  3107. // Build the synchronous request to be sent to the port driver
  3108. // to perform the request. Allocate an IRP to issue the port internal
  3109. // device control connect call. The connect parameters are passed in
  3110. // the input buffer.
  3111. //
  3112. //
  3113. connectData.ClassDeviceObject = ClassData->TrueClassDevice;
  3114. connectData.ClassService = ServiceCallback;
  3115. irp = IoBuildDeviceIoControlRequest(
  3116. IOCTL_INTERNAL_MOUSE_CONNECT,
  3117. ClassData->TopPort,
  3118. &connectData,
  3119. sizeof(CONNECT_DATA),
  3120. NULL,
  3121. 0,
  3122. TRUE,
  3123. &event,
  3124. &ioStatus
  3125. );
  3126. //
  3127. // Call the port driver to perform the operation. If the returned status
  3128. // is PENDING, wait for the request to complete.
  3129. //
  3130. status = IoCallDriver(ClassData->TopPort, irp);
  3131. if (status == STATUS_PENDING) {
  3132. (VOID) KeWaitForSingleObject(
  3133. &event,
  3134. Executive,
  3135. KernelMode,
  3136. FALSE,
  3137. NULL
  3138. );
  3139. status = irp->IoStatus.Status;
  3140. } else {
  3141. //
  3142. // Ensure that the proper status value gets picked up.
  3143. //
  3144. ioStatus.Status = status;
  3145. }
  3146. MouPrint((2,"MOUCLASS-MouSendConnectRequest: exit\n"));
  3147. return(ioStatus.Status);
  3148. } // end MouSendConnectRequest()
  3149. void
  3150. MouseClassRemoveDevice(
  3151. IN PDEVICE_EXTENSION Data,
  3152. BOOLEAN SurpriseRemove
  3153. )
  3154. {
  3155. PFILE_OBJECT * file;
  3156. PPORT port;
  3157. PIRP waitWakeIrp;
  3158. PVOID notifyHandle;
  3159. BOOLEAN enabled;
  3160. //
  3161. // Mark that we were surprise removed so that we do not clean up twice
  3162. //
  3163. if (SurpriseRemove) {
  3164. Data->SurpriseRemoved = TRUE;
  3165. }
  3166. //
  3167. // If this is a surprise remove or we got a remove w/out a surprise remove,
  3168. // then we need to clean up
  3169. //
  3170. if (SurpriseRemove || !Data->SurpriseRemoved) {
  3171. waitWakeIrp = (PIRP)
  3172. InterlockedExchangePointer(&Data->WaitWakeIrp, NULL);
  3173. if (waitWakeIrp) {
  3174. IoCancelIrp(waitWakeIrp);
  3175. }
  3176. IoWMIRegistrationControl (Data->Self, WMIREG_ACTION_DEREGISTER);
  3177. if (Data->Started) {
  3178. //
  3179. // Stop the device without touching the hardware.
  3180. // MouStopDevice(Data, FALSE);
  3181. //
  3182. // NB sending down the enable disable does NOT touch the hardware
  3183. // it instead sends down a close file.
  3184. //
  3185. ExAcquireFastMutex (&Globals.Mutex);
  3186. if (Globals.GrandMaster) {
  3187. if (0 < Globals.Opens) {
  3188. port = &Globals.AssocClassList[Data->UnitId];
  3189. ASSERT (port->Port == Data);
  3190. file = &(port->File);
  3191. enabled = port->Enabled;
  3192. port->Enabled = FALSE;
  3193. ExReleaseFastMutex (&Globals.Mutex);
  3194. //
  3195. // ASSERT (NULL == Data->notifyHandle);
  3196. //
  3197. // If we have a grand master, that means we did the
  3198. // creation locally and registered for notification.
  3199. // we should have closed the file during
  3200. // TARGET_DEVICE_QUERY_REMOVE, but we will have not
  3201. // gotten rid of the notify handle.
  3202. //
  3203. // Of course if we receive a surprise removal then
  3204. // we should not have received the query cancel.
  3205. // In which case we should have received a
  3206. // TARGET_DEVICE_REMOVE_COMPLETE where we would have
  3207. // both closed the file and removed cleared the
  3208. // notify handle
  3209. //
  3210. // Either way the file should be closed by now.
  3211. //
  3212. ASSERT (!enabled);
  3213. // if (enabled) {
  3214. // status = MouEnableDisablePort (FALSE, Irp, Data, file);
  3215. // ASSERTMSG ("Could not close open port", NT_SUCCESS(status));
  3216. // }
  3217. notifyHandle = InterlockedExchangePointer (
  3218. &Data->TargetNotifyHandle,
  3219. NULL);
  3220. if (NULL != notifyHandle) {
  3221. IoUnregisterPlugPlayNotification (notifyHandle);
  3222. }
  3223. }
  3224. else {
  3225. ASSERT (!Globals.AssocClassList[Data->UnitId].Enabled);
  3226. ExReleaseFastMutex (&Globals.Mutex);
  3227. }
  3228. }
  3229. else {
  3230. ExReleaseFastMutex (&Globals.Mutex);
  3231. ASSERT (Data->TrueClassDevice == Data->Self);
  3232. ASSERT (Globals.ConnectOneClassToOnePort);
  3233. //
  3234. // If add device fails, then the buffer will be NULL
  3235. //
  3236. if (Data->SymbolicLinkName.Buffer != NULL) {
  3237. IoSetDeviceInterfaceState (&Data->SymbolicLinkName, FALSE);
  3238. }
  3239. }
  3240. }
  3241. }
  3242. //
  3243. // Always drain the queue, no matter if we have received both a surprise
  3244. // remove and a remove
  3245. //
  3246. if (Data->PnP) {
  3247. //
  3248. // Empty the device I/O Queue
  3249. //
  3250. MouseClassCleanupQueue (Data->Self, Data, NULL);
  3251. }
  3252. }
  3253. NTSTATUS
  3254. MousePnP (
  3255. IN PDEVICE_OBJECT DeviceObject,
  3256. IN PIRP Irp
  3257. )
  3258. /*++
  3259. Routine Description:
  3260. The plug and play dispatch routines.
  3261. Most of these this filter driver will completely ignore.
  3262. In all cases it must pass on the IRP to the lower driver.
  3263. Arguments:
  3264. DeviceObject - pointer to a device object.
  3265. Irp - pointer to an I/O Request Packet.
  3266. Return Value:
  3267. NT status code
  3268. --*/
  3269. {
  3270. PDEVICE_EXTENSION data;
  3271. PDEVICE_EXTENSION trueClassData;
  3272. PIO_STACK_LOCATION stack;
  3273. NTSTATUS status, startStatus;
  3274. ULONG i;
  3275. PFILE_OBJECT * file;
  3276. UINT_PTR startInformation;
  3277. DEVICE_CAPABILITIES devCaps;
  3278. BOOLEAN enabled;
  3279. PPORT port;
  3280. PVOID notifyHandle;
  3281. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  3282. stack = IoGetCurrentIrpStackLocation (Irp);
  3283. if(!data->PnP) {
  3284. //
  3285. // This irp was sent to the control device object, which knows not
  3286. // how to deal with this IRP. It is therefore an error.
  3287. //
  3288. Irp->IoStatus.Information = 0;
  3289. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  3290. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  3291. return STATUS_NOT_SUPPORTED;
  3292. }
  3293. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  3294. if (!NT_SUCCESS (status)) {
  3295. //
  3296. // Someone gave us a pnp irp after a remove. Unthinkable!
  3297. //
  3298. ASSERT (FALSE);
  3299. Irp->IoStatus.Information = 0;
  3300. Irp->IoStatus.Status = status;
  3301. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  3302. return status;
  3303. }
  3304. trueClassData = (PDEVICE_EXTENSION) data->TrueClassDevice->DeviceExtension;
  3305. switch (stack->MinorFunction) {
  3306. case IRP_MN_START_DEVICE:
  3307. //
  3308. // The device is starting.
  3309. //
  3310. // We cannot touch the device (send it any non pnp irps) until a
  3311. // start device has been passed down to the lower drivers.
  3312. //
  3313. status = MouseSendIrpSynchronously (data->TopPort, Irp, TRUE);
  3314. if (NT_SUCCESS (status) && NT_SUCCESS (Irp->IoStatus.Status)) {
  3315. //
  3316. // As we are successfully now back from our start device
  3317. // we can do work.
  3318. //
  3319. // Get the caps of the device. Save off pertinent information
  3320. // before mucking about w/the irp
  3321. //
  3322. startStatus = Irp->IoStatus.Status;
  3323. startInformation = Irp->IoStatus.Information;
  3324. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  3325. Irp->IoStatus.Information = 0;
  3326. RtlZeroMemory(&devCaps, sizeof (DEVICE_CAPABILITIES));
  3327. devCaps.Size = sizeof (DEVICE_CAPABILITIES);
  3328. devCaps.Version = 1;
  3329. devCaps.Address = devCaps.UINumber = (ULONG)-1;
  3330. stack = IoGetNextIrpStackLocation (Irp);
  3331. stack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  3332. stack->Parameters.DeviceCapabilities.Capabilities = &devCaps;
  3333. status = MouseSendIrpSynchronously (data->TopPort, Irp, FALSE);
  3334. if (NT_SUCCESS (status) && NT_SUCCESS (Irp->IoStatus.Status)) {
  3335. data->MinDeviceWakeState = devCaps.DeviceWake;
  3336. data->MinSystemWakeState = devCaps.SystemWake;
  3337. RtlCopyMemory (data->SystemToDeviceState,
  3338. devCaps.DeviceState,
  3339. sizeof(DEVICE_POWER_STATE) * PowerSystemHibernate);
  3340. } else {
  3341. ASSERTMSG ("Get Device caps Failed!\n", status);
  3342. }
  3343. //
  3344. // Set everything back to the way it was and continue with the start
  3345. //
  3346. status = STATUS_SUCCESS;
  3347. Irp->IoStatus.Status = startStatus;
  3348. Irp->IoStatus.Information = startInformation;
  3349. data->Started = TRUE;
  3350. if (WAITWAKE_SUPPORTED (data)) {
  3351. //
  3352. // register for the wait wake guid as well
  3353. //
  3354. data->WmiLibInfo.GuidCount = sizeof (MouseClassWmiGuidList) /
  3355. sizeof (WMIGUIDREGINFO);
  3356. //
  3357. // See if the user has enabled wait wake for the device
  3358. //
  3359. MouseClassGetWaitWakeEnableState (data);
  3360. }
  3361. else {
  3362. data->WmiLibInfo.GuidCount = sizeof (MouseClassWmiGuidList) /
  3363. sizeof (WMIGUIDREGINFO) - 1;
  3364. }
  3365. data->WmiLibInfo.GuidList = MouseClassWmiGuidList;
  3366. data->WmiLibInfo.QueryWmiRegInfo = MouseClassQueryWmiRegInfo;
  3367. data->WmiLibInfo.QueryWmiDataBlock = MouseClassQueryWmiDataBlock;
  3368. data->WmiLibInfo.SetWmiDataBlock = MouseClassSetWmiDataBlock;
  3369. data->WmiLibInfo.SetWmiDataItem = MouseClassSetWmiDataItem;
  3370. data->WmiLibInfo.ExecuteWmiMethod = NULL;
  3371. data->WmiLibInfo.WmiFunctionControl = NULL;
  3372. IoWMIRegistrationControl(data->Self,
  3373. WMIREG_ACTION_REGISTER
  3374. );
  3375. ExAcquireFastMutex (&Globals.Mutex);
  3376. if (Globals.GrandMaster) {
  3377. if (0 < Globals.Opens) {
  3378. port = &Globals.AssocClassList[data->UnitId];
  3379. ASSERT (port->Port == data);
  3380. file = &(port->File);
  3381. enabled = port->Enabled;
  3382. port->Enabled = TRUE;
  3383. ExReleaseFastMutex (&Globals.Mutex);
  3384. if (!enabled) {
  3385. status = MouEnableDisablePort (TRUE, NULL, data, file);
  3386. if (!NT_SUCCESS (status)) {
  3387. port->Enabled = FALSE;
  3388. // ASSERT (Globals.AssocClassList[data->UnitId].Enabled);
  3389. } else {
  3390. ;
  3391. }
  3392. }
  3393. } else {
  3394. ASSERT (!Globals.AssocClassList[data->UnitId].Enabled);
  3395. ExReleaseFastMutex (&Globals.Mutex);
  3396. }
  3397. } else {
  3398. ExReleaseFastMutex (&Globals.Mutex);
  3399. ASSERT (data->Self == data->TrueClassDevice);
  3400. status=IoSetDeviceInterfaceState(&data->SymbolicLinkName, TRUE);
  3401. }
  3402. //
  3403. // Start up the Wait Wake Engine if required.
  3404. //
  3405. if (SHOULD_SEND_WAITWAKE (data)) {
  3406. MouseClassCreateWaitWakeIrp (data);
  3407. }
  3408. }
  3409. //
  3410. // We must now complete the IRP, since we stopped it in the
  3411. // completetion routine with MORE_PROCESSING_REQUIRED.
  3412. //
  3413. Irp->IoStatus.Status = status;
  3414. Irp->IoStatus.Information = 0;
  3415. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  3416. break;
  3417. case IRP_MN_STOP_DEVICE:
  3418. //
  3419. // After the start IRP has been sent to the lower driver object, the
  3420. // bus may NOT send any more IRPS down ``touch'' until another START
  3421. // has occured.
  3422. // What ever access is required must be done before the Irp is passed
  3423. // on.
  3424. //
  3425. //
  3426. // Do what ever
  3427. //
  3428. //
  3429. // Stop Device touching the hardware MouStopDevice(data, TRUE);
  3430. //
  3431. if (data->Started) {
  3432. ExAcquireFastMutex (&Globals.Mutex);
  3433. if (Globals.GrandMaster) {
  3434. if (0 < Globals.Opens) {
  3435. port = &Globals.AssocClassList[data->UnitId];
  3436. ASSERT (port->Port == data);
  3437. file = &(port->File);
  3438. enabled = port->Enabled;
  3439. port->Enabled = FALSE;
  3440. ExReleaseFastMutex (&Globals.Mutex);
  3441. if (enabled) {
  3442. notifyHandle = InterlockedExchangePointer (
  3443. &data->TargetNotifyHandle,
  3444. NULL);
  3445. if (NULL != notifyHandle) {
  3446. IoUnregisterPlugPlayNotification (notifyHandle);
  3447. }
  3448. status = MouEnableDisablePort (FALSE, NULL, data, file);
  3449. ASSERTMSG ("Could not close open port", NT_SUCCESS(status));
  3450. } else {
  3451. ASSERT (NULL == data->TargetNotifyHandle);
  3452. }
  3453. } else {
  3454. ASSERT (!Globals.AssocClassList[data->UnitId].Enabled);
  3455. ExReleaseFastMutex (&Globals.Mutex);
  3456. }
  3457. } else {
  3458. ExReleaseFastMutex (&Globals.Mutex);
  3459. }
  3460. }
  3461. data->Started = FALSE;
  3462. //
  3463. // We don't need a completion routine so fire and forget.
  3464. //
  3465. // Set the current stack location to the next stack location and
  3466. // call the next device object.
  3467. //
  3468. IoSkipCurrentIrpStackLocation (Irp);
  3469. status = IoCallDriver (data->TopPort, Irp);
  3470. break;
  3471. case IRP_MN_SURPRISE_REMOVAL:
  3472. //
  3473. // The PlugPlay system has dictacted the removal of this device.
  3474. //
  3475. MouseClassRemoveDevice (data, TRUE);
  3476. //
  3477. // We don't need a completion routine so fire and forget.
  3478. //
  3479. // Set the current stack location to the next stack location and
  3480. // call the next device object.
  3481. //
  3482. IoSkipCurrentIrpStackLocation (Irp);
  3483. status = IoCallDriver (data->TopPort, Irp);
  3484. break;
  3485. case IRP_MN_REMOVE_DEVICE:
  3486. //
  3487. // The PlugPlay system has dictacted the removal of this device. We
  3488. // have no choise but to detach and delete the device objecct.
  3489. // (If we wanted to express and interest in preventing this removal,
  3490. // we should have filtered the query remove and query stop routines.)
  3491. //
  3492. MouseClassRemoveDevice (data, FALSE);
  3493. //
  3494. // Here if we had any outstanding requests in a personal queue we should
  3495. // complete them all now.
  3496. //
  3497. // Note, the device is guarenteed stopped, so we cannot send it any non-
  3498. // PNP IRPS.
  3499. //
  3500. //
  3501. // Send on the remove IRP
  3502. //
  3503. IoCopyCurrentIrpStackLocationToNext (Irp);
  3504. status = IoCallDriver (data->TopPort, Irp);
  3505. ExAcquireFastMutex (&Globals.Mutex);
  3506. if (Globals.GrandMaster) {
  3507. ASSERT (Globals.GrandMaster->Self == data->TrueClassDevice);
  3508. //
  3509. // We must remove ourself from the Assoc List
  3510. //
  3511. if (1 < Globals.NumAssocClass) {
  3512. ASSERT (Globals.AssocClassList[data->UnitId].Port == data);
  3513. Globals.AssocClassList[data->UnitId].Free = TRUE;
  3514. Globals.AssocClassList[data->UnitId].File = NULL;
  3515. Globals.AssocClassList[data->UnitId].Port = NULL;
  3516. } else {
  3517. ASSERT (1 == Globals.NumAssocClass);
  3518. Globals.NumAssocClass = 0;
  3519. ExFreePool (Globals.AssocClassList);
  3520. Globals.AssocClassList = NULL;
  3521. }
  3522. ExReleaseFastMutex (&Globals.Mutex);
  3523. } else {
  3524. //
  3525. // We are removing the one and only port associated with this class
  3526. // device object.
  3527. //
  3528. ExReleaseFastMutex (&Globals.Mutex);
  3529. ASSERT (data->TrueClassDevice == data->Self);
  3530. ASSERT (Globals.ConnectOneClassToOnePort);
  3531. }
  3532. IoReleaseRemoveLockAndWait (&data->RemoveLock, Irp);
  3533. IoDetachDevice (data->TopPort);
  3534. //
  3535. // Clean up memory
  3536. //
  3537. RtlFreeUnicodeString (&data->SymbolicLinkName);
  3538. ExFreePool (data->InputData);
  3539. IoDeleteDevice (data->Self);
  3540. return status;
  3541. case IRP_MN_QUERY_REMOVE_DEVICE:
  3542. case IRP_MN_CANCEL_REMOVE_DEVICE:
  3543. case IRP_MN_QUERY_STOP_DEVICE:
  3544. case IRP_MN_CANCEL_STOP_DEVICE:
  3545. case IRP_MN_QUERY_DEVICE_RELATIONS:
  3546. case IRP_MN_QUERY_INTERFACE:
  3547. case IRP_MN_QUERY_CAPABILITIES:
  3548. case IRP_MN_QUERY_RESOURCES:
  3549. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  3550. case IRP_MN_READ_CONFIG:
  3551. case IRP_MN_WRITE_CONFIG:
  3552. case IRP_MN_EJECT:
  3553. case IRP_MN_SET_LOCK:
  3554. case IRP_MN_QUERY_ID:
  3555. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  3556. default:
  3557. //
  3558. // Here the filter driver might modify the behavior of these IRPS
  3559. // Please see PlugPlay documentation for use of these IRPs.
  3560. //
  3561. IoCopyCurrentIrpStackLocationToNext (Irp);
  3562. status = IoCallDriver (data->TopPort, Irp);
  3563. break;
  3564. }
  3565. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  3566. return status;
  3567. }
  3568. void
  3569. MouseClassLogError(
  3570. PVOID Object,
  3571. ULONG ErrorCode,
  3572. ULONG UniqueErrorValue,
  3573. NTSTATUS FinalStatus,
  3574. ULONG DumpCount,
  3575. ULONG *DumpData,
  3576. UCHAR MajorFunction
  3577. )
  3578. {
  3579. PIO_ERROR_LOG_PACKET errorLogEntry;
  3580. ULONG i;
  3581. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  3582. IoAllocateErrorLogEntry(
  3583. Object,
  3584. (UCHAR) (sizeof(IO_ERROR_LOG_PACKET) + (DumpCount * sizeof(ULONG)))
  3585. );
  3586. if (errorLogEntry != NULL) {
  3587. errorLogEntry->ErrorCode = ErrorCode;
  3588. errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG));
  3589. errorLogEntry->SequenceNumber = 0;
  3590. errorLogEntry->MajorFunctionCode = MajorFunction;
  3591. errorLogEntry->IoControlCode = 0;
  3592. errorLogEntry->RetryCount = 0;
  3593. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  3594. errorLogEntry->FinalStatus = FinalStatus;
  3595. for (i = 0; i < DumpCount; i++)
  3596. errorLogEntry->DumpData[i] = DumpData[i];
  3597. IoWriteErrorLogEntry(errorLogEntry);
  3598. }
  3599. }
  3600. VOID
  3601. MouseClassFindMorePorts (
  3602. PDRIVER_OBJECT DriverObject,
  3603. PVOID Context,
  3604. ULONG Count
  3605. )
  3606. /*++
  3607. Routine Description:
  3608. This routine is called from
  3609. serviced by the boot device drivers and then called again by the
  3610. IO system to find disk devices serviced by nonboot device drivers.
  3611. Arguments:
  3612. DriverObject
  3613. Context -
  3614. Count - Used to determine if this is the first or second time called.
  3615. Return Value:
  3616. None
  3617. --*/
  3618. {
  3619. NTSTATUS status;
  3620. PDEVICE_EXTENSION deviceExtension = NULL;
  3621. PDEVICE_OBJECT classDeviceObject = NULL;
  3622. ULONG dumpData[DUMP_COUNT];
  3623. ULONG i;
  3624. ULONG numPorts;
  3625. ULONG successfulCreates;
  3626. UNICODE_STRING basePortName;
  3627. UNICODE_STRING fullPortName;
  3628. WCHAR basePortBuffer[NAME_MAX];
  3629. PWCHAR fullClassName = NULL;
  3630. PFILE_OBJECT file;
  3631. PAGED_CODE ();
  3632. fullPortName.MaximumLength = 0;
  3633. RtlZeroMemory(basePortBuffer, NAME_MAX * sizeof(WCHAR));
  3634. basePortName.Buffer = basePortBuffer;
  3635. basePortName.Length = 0;
  3636. basePortName.MaximumLength = NAME_MAX * sizeof(WCHAR);
  3637. //
  3638. // Set up the base device name for the associated port device.
  3639. // It is the same as the base class name, with "Class" replaced
  3640. // by "Port".
  3641. //
  3642. RtlCopyUnicodeString(&basePortName, &Globals.BaseClassName);
  3643. basePortName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
  3644. RtlAppendUnicodeToString(&basePortName, L"Port");
  3645. //
  3646. // Set up space for the full device object name for the ports.
  3647. //
  3648. RtlInitUnicodeString(&fullPortName, NULL);
  3649. fullPortName.MaximumLength = sizeof(L"\\Device\\")
  3650. + basePortName.Length
  3651. + sizeof (UNICODE_NULL);
  3652. fullPortName.Buffer = ExAllocatePool(PagedPool,
  3653. fullPortName.MaximumLength);
  3654. if (!fullPortName.Buffer) {
  3655. MouPrint((
  3656. 1,
  3657. "MOUCLASS-MouseClassInitialize: Couldn't allocate string for port device object name\n"
  3658. ));
  3659. dumpData[0] = (ULONG) fullPortName.MaximumLength;
  3660. MouseClassLogError (DriverObject,
  3661. MOUCLASS_INSUFFICIENT_RESOURCES,
  3662. MOUSE_ERROR_VALUE_BASE + 8,
  3663. STATUS_UNSUCCESSFUL,
  3664. 1,
  3665. dumpData,
  3666. 0);
  3667. goto MouseFindMorePortsExit;
  3668. }
  3669. RtlZeroMemory(fullPortName.Buffer, fullPortName.MaximumLength);
  3670. RtlAppendUnicodeToString(&fullPortName, L"\\Device\\");
  3671. RtlAppendUnicodeToString(&fullPortName, basePortName.Buffer);
  3672. RtlAppendUnicodeToString(&fullPortName, L"0");
  3673. MouDeterminePortsServiced(&basePortName, &numPorts);
  3674. //
  3675. // Set up the class device object(s) to handle the associated
  3676. // port devices.
  3677. //
  3678. for (i = Globals.NumberLegacyPorts, successfulCreates = 0;
  3679. ((i < Globals.PortsServiced) && (i < numPorts));
  3680. i++) {
  3681. //
  3682. // Append the suffix to the device object name string. E.g., turn
  3683. // \Device\PointerClass into \Device\PointerClass0. Then attempt
  3684. // to create the device object. If the device object already
  3685. // exists increment the suffix and try again.
  3686. //
  3687. fullPortName.Buffer[(fullPortName.Length / sizeof(WCHAR)) - 1]
  3688. = L'0' + (WCHAR) i;
  3689. if (fullClassName) {
  3690. ExFreePool(fullClassName);
  3691. fullClassName = NULL;
  3692. }
  3693. //
  3694. // Create the class device object.
  3695. //
  3696. status = MouCreateClassObject(DriverObject,
  3697. &Globals.InitExtension,
  3698. &classDeviceObject,
  3699. &fullClassName,
  3700. TRUE);
  3701. if (!NT_SUCCESS(status)) {
  3702. MouseClassLogError (DriverObject,
  3703. MOUCLASS_INSUFFICIENT_RESOURCES,
  3704. MOUSE_ERROR_VALUE_BASE + 8,
  3705. status,
  3706. 0,
  3707. NULL,
  3708. 0);
  3709. continue;
  3710. }
  3711. deviceExtension = (PDEVICE_EXTENSION)classDeviceObject->DeviceExtension;
  3712. deviceExtension->PnP = FALSE;
  3713. //
  3714. // Connect to the port device.
  3715. //
  3716. status = IoGetDeviceObjectPointer (&fullPortName,
  3717. FILE_READ_ATTRIBUTES,
  3718. &file,
  3719. &deviceExtension->TopPort);
  3720. if (status != STATUS_SUCCESS) {
  3721. // ISSUE: log error
  3722. MouseClassDeleteLegacyDevice (deviceExtension);
  3723. continue;
  3724. }
  3725. classDeviceObject->StackSize = 1 + deviceExtension->TopPort->StackSize;
  3726. status = MouseAddDeviceEx (deviceExtension, fullClassName, file);
  3727. classDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  3728. if (fullClassName) {
  3729. ExFreePool (fullClassName);
  3730. fullClassName = NULL;
  3731. }
  3732. if (!NT_SUCCESS (status)) {
  3733. if (Globals.GrandMaster == NULL) {
  3734. if (deviceExtension->File) {
  3735. file = deviceExtension->File;
  3736. deviceExtension->File = NULL;
  3737. }
  3738. }
  3739. else {
  3740. PPORT port;
  3741. ExAcquireFastMutex (&Globals.Mutex);
  3742. file = Globals.AssocClassList[deviceExtension->UnitId].File;
  3743. Globals.AssocClassList[deviceExtension->UnitId].File = NULL;
  3744. Globals.AssocClassList[deviceExtension->UnitId].Free = TRUE;
  3745. Globals.AssocClassList[deviceExtension->UnitId].Port = NULL;
  3746. ExReleaseFastMutex (&Globals.Mutex);
  3747. }
  3748. if (file) {
  3749. ObDereferenceObject (file);
  3750. }
  3751. MouseClassDeleteLegacyDevice (deviceExtension);
  3752. continue;
  3753. }
  3754. //
  3755. // We want to only add it to our list if everything went alright
  3756. //
  3757. InsertTailList (&Globals.LegacyDeviceList, &deviceExtension->Link);
  3758. successfulCreates++;
  3759. } // for
  3760. Globals.NumberLegacyPorts += successfulCreates;
  3761. MouseFindMorePortsExit:
  3762. //
  3763. // Free the unicode strings.
  3764. //
  3765. if (fullPortName.MaximumLength != 0) {
  3766. ExFreePool(fullPortName.Buffer);
  3767. }
  3768. if (fullClassName) {
  3769. ExFreePool(fullClassName);
  3770. }
  3771. }
  3772. NTSTATUS
  3773. MouseClassEnableGlobalPort(
  3774. IN PDEVICE_EXTENSION Port,
  3775. IN BOOLEAN Enabled
  3776. )
  3777. {
  3778. NTSTATUS status = STATUS_SUCCESS;
  3779. PPORT globalPort = NULL;
  3780. BOOLEAN enabled;
  3781. ULONG i;
  3782. PAGED_CODE ();
  3783. ExAcquireFastMutex (&Globals.Mutex);
  3784. if (0 < Globals.Opens) {
  3785. for (i = 0; i < Globals.NumAssocClass; i++) {
  3786. if (! Globals.AssocClassList [i].Free) {
  3787. if (Globals.AssocClassList[i].Port == Port) {
  3788. globalPort = &Globals.AssocClassList [i];
  3789. break;
  3790. }
  3791. }
  3792. }
  3793. ASSERTMSG ("What shall I do now?\n", (NULL != globalPort));
  3794. //
  3795. // This should never happen, globalPort should be in our list
  3796. //
  3797. if (globalPort == NULL) {
  3798. ExReleaseFastMutex (&Globals.Mutex);
  3799. return STATUS_NO_SUCH_DEVICE;
  3800. }
  3801. enabled = globalPort->Enabled;
  3802. globalPort->Enabled = Enabled;
  3803. ExReleaseFastMutex (&Globals.Mutex);
  3804. //
  3805. // Check to see if the port should change state. If so, send the new state
  3806. // down the stack
  3807. //
  3808. if (Enabled != enabled ) {
  3809. status = MouEnableDisablePort (Enabled,
  3810. NULL,
  3811. Port,
  3812. &globalPort->File);
  3813. }
  3814. } else {
  3815. ExReleaseFastMutex (&Globals.Mutex);
  3816. }
  3817. return status;
  3818. }
  3819. NTSTATUS
  3820. MouseClassPlugPlayNotification(
  3821. IN PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationStructure,
  3822. IN PDEVICE_EXTENSION Port
  3823. )
  3824. /*++
  3825. Routine Description:
  3826. This routine is called as the result of recieving PlugPlay Notifications
  3827. as registered by the previous call to IoRegisterPlugPlayNotification.
  3828. Currently this should only occur for Target Device Notifications
  3829. Arguments:
  3830. NotificationStructure - what happened.
  3831. Port - The Fdo to which things happened.
  3832. Return Value:
  3833. --*/
  3834. {
  3835. NTSTATUS status = STATUS_SUCCESS;
  3836. PVOID notify = NULL;
  3837. PAGED_CODE ();
  3838. ASSERT (Globals.GrandMaster->Self == Port->TrueClassDevice);
  3839. if (IsEqualGUID ((LPGUID) &(NotificationStructure->Event),
  3840. (LPGUID) &GUID_TARGET_DEVICE_QUERY_REMOVE)) {
  3841. //
  3842. // Our port device object will soon be receiving a query remove.
  3843. // Before that query remove will actually be sent to the device object
  3844. // stack itself the plug and play subsystem will send those registered
  3845. // for target device notification the message first.
  3846. //
  3847. //
  3848. // What we should do is now close the handle.
  3849. // Because if we do not the query remove will fail before it ever
  3850. // gets to the IRP_MJ_PNP IRP_MN_QUERY_REMOVE stage, as the PlugPlay
  3851. // system fails before it is sent based on there being an open handle
  3852. // to the device.
  3853. //
  3854. // DbgPrint ("Mouse QUERY Remove\n");
  3855. // DbgBreakPoint();
  3856. status = MouseClassEnableGlobalPort (Port, FALSE);
  3857. } else if(IsEqualGUID ((LPGUID)&(NotificationStructure->Event),
  3858. (LPGUID)&GUID_TARGET_DEVICE_REMOVE_COMPLETE)) {
  3859. //
  3860. // Here the device has disappeared.
  3861. //
  3862. // DbgPrint ("Mouse Remove Complete\n");
  3863. // DbgBreakPoint();
  3864. notify = InterlockedExchangePointer (&Port->TargetNotifyHandle,
  3865. NULL);
  3866. if (NULL != notify) {
  3867. //
  3868. // Deregister
  3869. //
  3870. IoUnregisterPlugPlayNotification (notify);
  3871. status = MouseClassEnableGlobalPort (Port, FALSE);
  3872. }
  3873. } else if(IsEqualGUID ((LPGUID)&(NotificationStructure->Event),
  3874. (LPGUID)&GUID_TARGET_DEVICE_REMOVE_CANCELLED)) {
  3875. //
  3876. // The query remove has been revoked.
  3877. // Reopen the device.
  3878. //
  3879. // DbgPrint ("Mouse Remove Complete\n");
  3880. // DbgBreakPoint();
  3881. notify = InterlockedExchangePointer (&Port->TargetNotifyHandle,
  3882. NULL);
  3883. if (NULL != notify) {
  3884. //
  3885. // Deregister
  3886. //
  3887. IoUnregisterPlugPlayNotification (notify);
  3888. status = MouseClassEnableGlobalPort (Port, TRUE);
  3889. }
  3890. }
  3891. return status;
  3892. }
  3893. VOID
  3894. MouseClassPoRequestComplete (
  3895. IN PDEVICE_OBJECT DeviceObject,
  3896. IN UCHAR MinorFunction,
  3897. IN POWER_STATE PowerState,
  3898. IN PVOID Context,
  3899. IN PIO_STATUS_BLOCK IoStatus
  3900. );
  3901. NTSTATUS
  3902. MouseClassPowerComplete (
  3903. IN PDEVICE_OBJECT DeviceObject,
  3904. IN PIRP Irp,
  3905. IN PVOID Context
  3906. );
  3907. VOID
  3908. MouseClassWWPowerUpComplete(
  3909. IN PDEVICE_OBJECT DeviceObject,
  3910. IN UCHAR MinorFunction,
  3911. IN POWER_STATE PowerState,
  3912. IN PVOID Context,
  3913. IN PIO_STATUS_BLOCK IoStatus
  3914. )
  3915. /*++
  3916. Routine Description:
  3917. Catch the Wait wake Irp on its way back.
  3918. Return Value:
  3919. --*/
  3920. {
  3921. PDEVICE_EXTENSION data = Context;
  3922. POWER_STATE powerState;
  3923. NTSTATUS status;
  3924. PMOUSE_WORK_ITEM_DATA itemData;
  3925. ASSERT (MinorFunction == IRP_MN_SET_POWER);
  3926. if (data->WaitWakeEnabled) {
  3927. //
  3928. // We cannot call CreateWaitWake from this completion routine,
  3929. // as it is a paged function.
  3930. //
  3931. itemData = (PMOUSE_WORK_ITEM_DATA)
  3932. ExAllocatePool (NonPagedPool, sizeof (MOUSE_WORK_ITEM_DATA));
  3933. if (NULL != itemData) {
  3934. itemData->Item = IoAllocateWorkItem (data->Self);
  3935. if (itemData->Item == NULL) {
  3936. ExFreePool (itemData);
  3937. goto CreateWaitWakeWorkerError;
  3938. }
  3939. itemData->Data = data;
  3940. itemData->Irp = NULL;
  3941. status = IoAcquireRemoveLock (&data->RemoveLock, itemData);
  3942. if (NT_SUCCESS(status)) {
  3943. IoQueueWorkItem (itemData->Item,
  3944. MouseClassCreateWaitWakeIrpWorker,
  3945. DelayedWorkQueue,
  3946. itemData);
  3947. }
  3948. else {
  3949. //
  3950. // The device has been removed
  3951. //
  3952. IoFreeWorkItem (itemData->Item);
  3953. ExFreePool (itemData);
  3954. }
  3955. } else {
  3956. CreateWaitWakeWorkerError:
  3957. //
  3958. // Well, we dropped the WaitWake.
  3959. //
  3960. // Print a warning to the debugger, and log an error.
  3961. //
  3962. DbgPrint ("MouClass: WARNING: Failed alloc pool -> no WW Irp\n");
  3963. MouseClassLogError (data->Self,
  3964. MOUCLASS_NO_RESOURCES_FOR_WAITWAKE,
  3965. 1,
  3966. STATUS_INSUFFICIENT_RESOURCES,
  3967. 0,
  3968. NULL,
  3969. 0);
  3970. }
  3971. }
  3972. }
  3973. VOID
  3974. MouseClassWaitWakeComplete(
  3975. IN PDEVICE_OBJECT DeviceObject,
  3976. IN UCHAR MinorFunction,
  3977. IN POWER_STATE PowerState,
  3978. IN PVOID Context,
  3979. IN PIO_STATUS_BLOCK IoStatus
  3980. )
  3981. /*++
  3982. Routine Description:
  3983. Catch the Wait wake Irp on its way back.
  3984. Return Value:
  3985. --*/
  3986. {
  3987. PDEVICE_EXTENSION data = Context;
  3988. POWER_STATE powerState;
  3989. NTSTATUS status;
  3990. PMOUSE_WORK_ITEM_DATA itemData;
  3991. ASSERT (MinorFunction == IRP_MN_WAIT_WAKE);
  3992. //
  3993. // PowerState.SystemState is undefined when the WW irp has been completed
  3994. //
  3995. // ASSERT (PowerState.SystemState == PowerSystemWorking);
  3996. if (InterlockedExchangePointer(&data->ExtraWaitWakeIrp, NULL)) {
  3997. ASSERT(IoStatus->Status == STATUS_INVALID_DEVICE_STATE);
  3998. } else {
  3999. InterlockedExchangePointer(&data->WaitWakeIrp, NULL);
  4000. }
  4001. switch (IoStatus->Status) {
  4002. case STATUS_SUCCESS:
  4003. MouPrint((1, "MouClass: Wake irp was completed successfully.\n"));
  4004. //
  4005. // We need to request a set power to power up the device.
  4006. //
  4007. powerState.DeviceState = PowerDeviceD0;
  4008. status = PoRequestPowerIrp(
  4009. data->PDO,
  4010. IRP_MN_SET_POWER,
  4011. powerState,
  4012. MouseClassWWPowerUpComplete,
  4013. Context,
  4014. NULL);
  4015. //
  4016. // We do not notify the system that a user is present because:
  4017. // 1 Win9x doesn't do this and we must maintain compatibility with it
  4018. // 2 The USB PIX4 motherboards sends a wait wake event every time the
  4019. // machine wakes up, no matter if this device woke the machine or not
  4020. //
  4021. // If we incorrectly notify the system a user is present, the following
  4022. // will occur:
  4023. // 1 The monitor will be turned on
  4024. // 2 We will prevent the machine from transitioning from standby
  4025. // (to PowerSystemWorking) to hibernate
  4026. //
  4027. // If a user is truly present, we will receive input in the service
  4028. // callback and we will notify the system at that time.
  4029. //
  4030. // PoSetSystemState (ES_USER_PRESENT);
  4031. // fall through to the break
  4032. //
  4033. // We get a remove. We will not (obviously) send another wait wake
  4034. //
  4035. case STATUS_CANCELLED:
  4036. //
  4037. // This status code will be returned if the device is put into a power state
  4038. // in which we cannot wake the machine (hibernate is a good example). When
  4039. // the device power state is returned to D0, we will attempt to rearm wait wake
  4040. //
  4041. case STATUS_POWER_STATE_INVALID:
  4042. case STATUS_ACPI_POWER_REQUEST_FAILED:
  4043. //
  4044. // We failed the Irp because we already had one queued, or a lower driver in
  4045. // the stack failed it. Either way, don't do anything.
  4046. //
  4047. case STATUS_INVALID_DEVICE_STATE:
  4048. //
  4049. // Somehow someway we got two WWs down to the lower stack.
  4050. // Let's just don't worry about it.
  4051. //
  4052. case STATUS_DEVICE_BUSY:
  4053. break;
  4054. default:
  4055. //
  4056. // Something went wrong, disable the wait wake.
  4057. //
  4058. KdPrint(("MOUCLASS: wait wake irp failed with %x\n", IoStatus->Status));
  4059. MouseToggleWaitWake (data, FALSE);
  4060. }
  4061. }
  4062. BOOLEAN
  4063. MouseClassCheckWaitWakeEnabled(
  4064. IN PDEVICE_EXTENSION Data
  4065. )
  4066. {
  4067. KIRQL irql;
  4068. BOOLEAN enabled;
  4069. KeAcquireSpinLock (&Data->WaitWakeSpinLock, &irql);
  4070. enabled = Data->WaitWakeEnabled;
  4071. KeReleaseSpinLock (&Data->WaitWakeSpinLock, irql);
  4072. return enabled;
  4073. }
  4074. void
  4075. MouseClassCreateWaitWakeIrpWorker (
  4076. IN PDEVICE_OBJECT DeviceObject,
  4077. IN PMOUSE_WORK_ITEM_DATA ItemData
  4078. )
  4079. {
  4080. PAGED_CODE ();
  4081. MouseClassCreateWaitWakeIrp (ItemData->Data);
  4082. IoReleaseRemoveLock (&ItemData->Data->RemoveLock, ItemData);
  4083. IoFreeWorkItem (ItemData->Item);
  4084. ExFreePool (ItemData);
  4085. }
  4086. BOOLEAN
  4087. MouseClassCreateWaitWakeIrp (
  4088. IN PDEVICE_EXTENSION Data
  4089. )
  4090. /*++
  4091. Routine Description:
  4092. Catch the Wait wake Irp on its way back.
  4093. Return Value:
  4094. --*/
  4095. {
  4096. POWER_STATE powerState;
  4097. BOOLEAN success = TRUE;
  4098. NTSTATUS status;
  4099. PIRP waitWakeIrp = NULL;
  4100. PAGED_CODE ();
  4101. powerState.SystemState = Data->MinSystemWakeState;
  4102. status = PoRequestPowerIrp (Data->PDO,
  4103. IRP_MN_WAIT_WAKE,
  4104. powerState,
  4105. MouseClassWaitWakeComplete,
  4106. Data,
  4107. NULL);
  4108. if (status != STATUS_PENDING) {
  4109. success = FALSE;
  4110. }
  4111. return success;
  4112. }
  4113. VOID
  4114. MouseToggleWaitWakeWorker(
  4115. IN PDEVICE_OBJECT DeviceObject,
  4116. IN PMOUSE_WORK_ITEM_DATA ItemData
  4117. )
  4118. /*++
  4119. Routine Description:
  4120. --*/
  4121. {
  4122. PDEVICE_EXTENSION data;
  4123. PIRP waitWakeIrp = NULL;
  4124. KIRQL irql;
  4125. BOOLEAN wwState = ItemData->WaitWakeState ? TRUE : FALSE;
  4126. BOOLEAN toggled = FALSE;
  4127. //
  4128. // Can't be paged b/c we are using spin locks
  4129. //
  4130. // PAGED_CODE ();
  4131. data = ItemData->Data;
  4132. KeAcquireSpinLock (&data->WaitWakeSpinLock, &irql);
  4133. if (wwState != data->WaitWakeEnabled) {
  4134. toggled = TRUE;
  4135. if (data->WaitWakeEnabled) {
  4136. waitWakeIrp = (PIRP)
  4137. InterlockedExchangePointer (&data->WaitWakeIrp, NULL);
  4138. }
  4139. data->WaitWakeEnabled = wwState;
  4140. }
  4141. KeReleaseSpinLock (&data->WaitWakeSpinLock, irql);
  4142. if (toggled) {
  4143. UNICODE_STRING strEnable;
  4144. HANDLE devInstRegKey;
  4145. ULONG tmp = wwState;
  4146. //
  4147. // write the value out to the registry
  4148. //
  4149. if ((NT_SUCCESS(IoOpenDeviceRegistryKey (data->PDO,
  4150. PLUGPLAY_REGKEY_DEVICE,
  4151. STANDARD_RIGHTS_ALL,
  4152. &devInstRegKey)))) {
  4153. RtlInitUnicodeString (&strEnable, MOUSE_WAIT_WAKE_ENABLE);
  4154. ZwSetValueKey (devInstRegKey,
  4155. &strEnable,
  4156. 0,
  4157. REG_DWORD,
  4158. &tmp,
  4159. sizeof(tmp));
  4160. ZwClose (devInstRegKey);
  4161. }
  4162. }
  4163. if (toggled && wwState) {
  4164. //
  4165. // wwState is our new state, so WW was just turned on
  4166. //
  4167. MouseClassCreateWaitWakeIrp (data);
  4168. }
  4169. //
  4170. // If we have an IRP, then WW has been toggled off, otherwise, if toggled is
  4171. // TRUE, we need to save this in the reg and, perhaps, send down a new WW irp
  4172. //
  4173. if (waitWakeIrp) {
  4174. IoCancelIrp (waitWakeIrp);
  4175. }
  4176. IoReleaseRemoveLock (&data->RemoveLock, MouseToggleWaitWakeWorker);
  4177. IoFreeWorkItem (ItemData->Item);
  4178. ExFreePool (ItemData);
  4179. }
  4180. NTSTATUS
  4181. MouseToggleWaitWake(
  4182. PDEVICE_EXTENSION Data,
  4183. BOOLEAN WaitWakeState
  4184. )
  4185. {
  4186. NTSTATUS status;
  4187. PMOUSE_WORK_ITEM_DATA itemData;
  4188. status = IoAcquireRemoveLock (&Data->RemoveLock, MouseToggleWaitWakeWorker);
  4189. if (!NT_SUCCESS (status)) {
  4190. //
  4191. // Device has gone away, just silently exit
  4192. //
  4193. return status;
  4194. }
  4195. itemData = (PMOUSE_WORK_ITEM_DATA)
  4196. ExAllocatePool(NonPagedPool, sizeof(MOUSE_WORK_ITEM_DATA));
  4197. if (itemData) {
  4198. itemData->Item = IoAllocateWorkItem (Data->Self);
  4199. if (itemData->Item == NULL) {
  4200. IoReleaseRemoveLock (&Data->RemoveLock, MouseToggleWaitWakeWorker);
  4201. }
  4202. else {
  4203. itemData->Data = Data;
  4204. itemData->WaitWakeState = WaitWakeState;
  4205. if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
  4206. //
  4207. // We are safely at PASSIVE_LEVEL, call callback directly to perform
  4208. // this operation immediately.
  4209. //
  4210. MouseToggleWaitWakeWorker (Data->Self, itemData);
  4211. } else {
  4212. //
  4213. // We are not at PASSIVE_LEVEL, so queue a workitem to handle this
  4214. // at a later time.
  4215. //
  4216. IoQueueWorkItem (itemData->Item,
  4217. MouseToggleWaitWakeWorker,
  4218. DelayedWorkQueue,
  4219. itemData);
  4220. }
  4221. }
  4222. }
  4223. else {
  4224. IoReleaseRemoveLock (&Data->RemoveLock, MouseToggleWaitWakeWorker);
  4225. }
  4226. return STATUS_SUCCESS;
  4227. }
  4228. NTSTATUS
  4229. MouseClassPower (
  4230. IN PDEVICE_OBJECT DeviceObject,
  4231. IN PIRP Irp
  4232. )
  4233. /*++
  4234. Routine Description:
  4235. The power dispatch routine.
  4236. In all cases it must call PoStartNextPowerIrp
  4237. In all cases (except failure) it must pass on the IRP to the lower driver.
  4238. Arguments:
  4239. DeviceObject - pointer to a device object.
  4240. Irp - pointer to an I/O Request Packet.
  4241. Return Value:
  4242. NT status code
  4243. --*/
  4244. {
  4245. POWER_STATE_TYPE powerType;
  4246. PIO_STACK_LOCATION stack;
  4247. PDEVICE_EXTENSION data;
  4248. NTSTATUS status;
  4249. POWER_STATE powerState;
  4250. BOOLEAN hookit = FALSE;
  4251. BOOLEAN pendit = FALSE;
  4252. PAGED_CODE ();
  4253. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  4254. stack = IoGetCurrentIrpStackLocation (Irp);
  4255. powerType = stack->Parameters.Power.Type;
  4256. powerState = stack->Parameters.Power.State;
  4257. if (data == Globals.GrandMaster) {
  4258. //
  4259. // We should never get a power irp to the grand master.
  4260. //
  4261. ASSERT (data != Globals.GrandMaster);
  4262. PoStartNextPowerIrp (Irp);
  4263. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  4264. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  4265. return STATUS_NOT_SUPPORTED;
  4266. } else if (!data->PnP) {
  4267. //
  4268. // We should never get a power irp to a non PnP device object.
  4269. //
  4270. ASSERT (data->PnP);
  4271. PoStartNextPowerIrp (Irp);
  4272. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  4273. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  4274. return STATUS_NOT_SUPPORTED;
  4275. }
  4276. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  4277. if (!NT_SUCCESS (status)) {
  4278. PoStartNextPowerIrp (Irp);
  4279. Irp->IoStatus.Status = status;
  4280. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  4281. return status;
  4282. }
  4283. switch (stack->MinorFunction) {
  4284. case IRP_MN_SET_POWER:
  4285. MouPrint((2,"MouCLASS-PnP Setting %s state to %d\n",
  4286. ((powerType == SystemPowerState) ? "System" : "Device"),
  4287. powerState.SystemState));
  4288. switch (powerType) {
  4289. case DevicePowerState:
  4290. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  4291. if (data->DeviceState < powerState.DeviceState) {
  4292. //
  4293. // Powering down
  4294. //
  4295. PoSetPowerState (data->Self, powerType, powerState);
  4296. data->DeviceState = powerState.DeviceState;
  4297. } else if (powerState.DeviceState < data->DeviceState) {
  4298. //
  4299. // Powering Up
  4300. //
  4301. hookit = TRUE;
  4302. } // else { no change }.
  4303. break;
  4304. case SystemPowerState:
  4305. if (data->SystemState < powerState.SystemState) {
  4306. //
  4307. // Powering down
  4308. //
  4309. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  4310. if (!NT_SUCCESS(status)) {
  4311. //
  4312. // This should never happen b/c we successfully acquired
  4313. // the lock already, but we must handle this case
  4314. //
  4315. // The S irp will completed with the value in status
  4316. //
  4317. break;
  4318. }
  4319. if (WAITWAKE_ON (data) &&
  4320. powerState.SystemState < PowerSystemHibernate) {
  4321. ASSERT(powerState.SystemState >= PowerSystemWorking &&
  4322. powerState.SystemState < PowerSystemHibernate);
  4323. powerState.DeviceState =
  4324. data->SystemToDeviceState[powerState.SystemState];
  4325. }
  4326. else {
  4327. powerState.DeviceState = PowerDeviceD3;
  4328. }
  4329. IoMarkIrpPending(Irp);
  4330. status = PoRequestPowerIrp (data->Self,
  4331. IRP_MN_SET_POWER,
  4332. powerState,
  4333. MouseClassPoRequestComplete,
  4334. Irp,
  4335. NULL);
  4336. if (!NT_SUCCESS(status)) {
  4337. //
  4338. // Failure...release the inner reference we just took
  4339. //
  4340. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  4341. //
  4342. // Propagate the failure back to the S irp
  4343. //
  4344. PoStartNextPowerIrp (Irp);
  4345. Irp->IoStatus.Status = status;
  4346. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4347. //
  4348. // Release the outer reference (top of the function)
  4349. //
  4350. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  4351. //
  4352. // Must return status pending b/c we marked the irp pending
  4353. // so we special case the return here and avoid overly
  4354. // complex processing at the end of the function.
  4355. //
  4356. return STATUS_PENDING;
  4357. }
  4358. else {
  4359. pendit = TRUE;
  4360. }
  4361. }
  4362. else if (powerState.SystemState < data->SystemState) {
  4363. //
  4364. // Powering Up
  4365. //
  4366. hookit = TRUE;
  4367. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  4368. } else {
  4369. //
  4370. // No change, but we want to make sure a wait wake irp is sent.
  4371. //
  4372. if (powerState.SystemState == PowerSystemWorking &&
  4373. SHOULD_SEND_WAITWAKE (data)) {
  4374. MouseClassCreateWaitWakeIrp (data);
  4375. }
  4376. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  4377. }
  4378. break;
  4379. }
  4380. break;
  4381. case IRP_MN_QUERY_POWER:
  4382. ASSERT (SystemPowerState == powerType);
  4383. //
  4384. // Fail the query if we can't wake the machine. We do, however, want to
  4385. // let hibernate succeed no matter what (besides, it is doubtful that a
  4386. // mouse can wait wake the machine out of S4).
  4387. //
  4388. if (powerState.SystemState < PowerSystemHibernate &&
  4389. powerState.SystemState > data->MinSystemWakeState &&
  4390. WAITWAKE_ON(data)) {
  4391. status = STATUS_POWER_STATE_INVALID;
  4392. }
  4393. else {
  4394. status = STATUS_SUCCESS;
  4395. }
  4396. Irp->IoStatus.Status = status;
  4397. break;
  4398. case IRP_MN_WAIT_WAKE:
  4399. if (InterlockedCompareExchangePointer(&data->WaitWakeIrp,
  4400. Irp,
  4401. NULL) != NULL) {
  4402. /* When powering up with WW being completed at same time, there
  4403. is a race condition between PoReq completion for S Irp and
  4404. completion of WW irp. Steps to repro this:
  4405. S irp completes and does PoReq of D irp with completion
  4406. routine MouseClassPoRequestComplete
  4407. WW Irp completion fires and the following happens:
  4408. set data->WaitWakeIrp to NULL
  4409. PoReq D irp with completion routine MouseClassWWPowerUpComplete
  4410. MouseClassPoRequestComplete fires first and sees no WW queued,
  4411. so it queues one.
  4412. MouseClassWWPowerUpComplete fires second and tries to queue
  4413. WW. When the WW arrives in mouclass, it sees there's one
  4414. queued already, so it fails it with invalid device state.
  4415. The completion routine, MouseClassWaitWakeComplete, fires
  4416. and it deletes the irp from the device extension.
  4417. This results in the appearance of wake being disabled,
  4418. even though the first irp is still queued.
  4419. */
  4420. InterlockedExchangePointer(&data->ExtraWaitWakeIrp, Irp);
  4421. status = STATUS_INVALID_DEVICE_STATE;
  4422. }
  4423. else {
  4424. status = STATUS_SUCCESS;
  4425. }
  4426. break;
  4427. default:
  4428. break;
  4429. }
  4430. if (!NT_SUCCESS (status)) {
  4431. Irp->IoStatus.Status = status;
  4432. PoStartNextPowerIrp (Irp);
  4433. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  4434. } else if (hookit) {
  4435. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  4436. ASSERT (STATUS_SUCCESS == status);
  4437. IoCopyCurrentIrpStackLocationToNext (Irp);
  4438. IoSetCompletionRoutine (Irp,
  4439. MouseClassPowerComplete,
  4440. NULL,
  4441. TRUE,
  4442. TRUE,
  4443. TRUE);
  4444. IoMarkIrpPending(Irp);
  4445. PoCallDriver (data->TopPort, Irp);
  4446. //
  4447. // We are returning pending instead of the result from PoCallDriver becuase:
  4448. // 1 we are changing the status in the completion routine
  4449. // 2 we will not be completing this irp in the completion routine
  4450. //
  4451. status = STATUS_PENDING;
  4452. } else if (pendit) {
  4453. status = STATUS_PENDING;
  4454. } else {
  4455. PoStartNextPowerIrp (Irp);
  4456. IoSkipCurrentIrpStackLocation (Irp);
  4457. status = PoCallDriver (data->TopPort, Irp);
  4458. }
  4459. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  4460. return status;
  4461. }
  4462. VOID
  4463. MouseClassPoRequestComplete (
  4464. IN PDEVICE_OBJECT DeviceObject,
  4465. IN UCHAR MinorFunction,
  4466. IN POWER_STATE D_PowerState,
  4467. IN PIRP S_Irp, // The S irp that caused us to request the power.
  4468. IN PIO_STATUS_BLOCK IoStatus
  4469. )
  4470. {
  4471. PDEVICE_EXTENSION data;
  4472. PMOUSE_WORK_ITEM_DATA itemData;
  4473. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  4474. //
  4475. // If the S_Irp is present, we are powering down. We do not pass the S_Irp
  4476. // as a parameter to PoRequestPowerIrp when we are powering up
  4477. //
  4478. if (ARGUMENT_PRESENT(S_Irp)) {
  4479. //
  4480. // Powering Down
  4481. //
  4482. POWER_STATE powerState;
  4483. //
  4484. // Powering Down
  4485. //
  4486. powerState = IoGetCurrentIrpStackLocation(S_Irp)->Parameters.Power.State;
  4487. PoSetPowerState (data->Self, SystemPowerState, powerState);
  4488. data->SystemState = powerState.SystemState;
  4489. PoStartNextPowerIrp (S_Irp);
  4490. IoSkipCurrentIrpStackLocation (S_Irp);
  4491. PoCallDriver (data->TopPort, S_Irp);
  4492. //
  4493. // Finally, release the lock we acquired based on this irp
  4494. //
  4495. IoReleaseRemoveLock (&data->RemoveLock, S_Irp);
  4496. }
  4497. else {
  4498. // } else if (S_powerState.SystemState < data->SystemState) {
  4499. //
  4500. // Powering Up
  4501. //
  4502. //
  4503. // We have come back to the PowerSystemWorking state and the device is
  4504. // fully powered. If we can (and should), send a wait wake irp down
  4505. // the stack. This is necessary because we might have gone into a power
  4506. // state where the wait wake irp was invalid.
  4507. //
  4508. ASSERT(data->SystemState == PowerSystemWorking);
  4509. if (SHOULD_SEND_WAITWAKE (data)) {
  4510. //
  4511. // We cannot call CreateWaitWake from this completion routine,
  4512. // as it is a paged function.
  4513. //
  4514. itemData = (PMOUSE_WORK_ITEM_DATA)
  4515. ExAllocatePool (NonPagedPool, sizeof (MOUSE_WORK_ITEM_DATA));
  4516. if (NULL != itemData) {
  4517. NTSTATUS status;
  4518. itemData->Item = IoAllocateWorkItem (data->Self);
  4519. if (itemData->Item == NULL) {
  4520. ExFreePool (itemData);
  4521. goto CreateWaitWakeWorkerError;
  4522. }
  4523. itemData->Data = data;
  4524. itemData->Irp = NULL;
  4525. status = IoAcquireRemoveLock (&data->RemoveLock, itemData);
  4526. if (NT_SUCCESS (status)) {
  4527. IoQueueWorkItem (itemData->Item,
  4528. MouseClassCreateWaitWakeIrpWorker,
  4529. DelayedWorkQueue,
  4530. itemData);
  4531. }
  4532. else {
  4533. IoFreeWorkItem (itemData->Item);
  4534. ExFreePool (itemData);
  4535. goto CreateWaitWakeWorkerError;
  4536. }
  4537. } else {
  4538. CreateWaitWakeWorkerError:
  4539. //
  4540. // Well, we dropped the WaitWake.
  4541. //
  4542. // Print a warning to the debugger, and log an error.
  4543. //
  4544. DbgPrint ("MouClass: WARNING: Failed alloc pool -> no WW Irp\n");
  4545. MouseClassLogError (data->Self,
  4546. MOUCLASS_NO_RESOURCES_FOR_WAITWAKE,
  4547. 2,
  4548. STATUS_INSUFFICIENT_RESOURCES,
  4549. 0,
  4550. NULL,
  4551. 0);
  4552. }
  4553. }
  4554. }
  4555. }
  4556. NTSTATUS
  4557. MouseClassPowerComplete (
  4558. IN PDEVICE_OBJECT DeviceObject,
  4559. IN PIRP Irp,
  4560. IN PVOID Context
  4561. )
  4562. {
  4563. NTSTATUS status;
  4564. POWER_STATE powerState;
  4565. POWER_STATE_TYPE powerType;
  4566. PIO_STACK_LOCATION stack;
  4567. PDEVICE_EXTENSION data;
  4568. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  4569. stack = IoGetCurrentIrpStackLocation (Irp);
  4570. powerType = stack->Parameters.Power.Type;
  4571. powerState = stack->Parameters.Power.State;
  4572. ASSERT (data != Globals.GrandMaster);
  4573. ASSERT (data->PnP);
  4574. switch (stack->MinorFunction) {
  4575. case IRP_MN_SET_POWER:
  4576. switch (powerType) {
  4577. case DevicePowerState:
  4578. ASSERT (powerState.DeviceState < data->DeviceState);
  4579. data->DeviceState = powerState.DeviceState;
  4580. PoSetPowerState (data->Self, powerType, powerState);
  4581. break;
  4582. case SystemPowerState:
  4583. ASSERT (powerState.SystemState < data->SystemState);
  4584. //
  4585. // Powering up
  4586. //
  4587. // Save the system state before we overwrite it
  4588. //
  4589. PoSetPowerState (data->Self, powerType, powerState);
  4590. data->SystemState = powerState.SystemState;
  4591. powerState.DeviceState = PowerDeviceD0;
  4592. status = PoRequestPowerIrp (data->Self,
  4593. IRP_MN_SET_POWER,
  4594. powerState,
  4595. MouseClassPoRequestComplete,
  4596. NULL,
  4597. NULL);
  4598. //
  4599. // Propagate the error if one occurred
  4600. //
  4601. if (!NT_SUCCESS(status)) {
  4602. Irp->IoStatus.Status = status;
  4603. }
  4604. break;
  4605. }
  4606. break;
  4607. default:
  4608. ASSERT (0xBADBAD == stack->MinorFunction);
  4609. break;
  4610. }
  4611. PoStartNextPowerIrp (Irp);
  4612. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  4613. return STATUS_SUCCESS;
  4614. }
  4615. //
  4616. // WMI System Call back functions
  4617. //
  4618. NTSTATUS
  4619. MouseClassSystemControl (
  4620. IN PDEVICE_OBJECT DeviceObject,
  4621. IN PIRP Irp
  4622. )
  4623. /*++
  4624. Routine Description
  4625. We have just received a System Control IRP.
  4626. Assume that this is a WMI IRP and
  4627. call into the WMI system library and let it handle this IRP for us.
  4628. --*/
  4629. {
  4630. PDEVICE_EXTENSION deviceExtension;
  4631. SYSCTL_IRP_DISPOSITION disposition;
  4632. NTSTATUS status;
  4633. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  4634. status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
  4635. if (!NT_SUCCESS (status)) {
  4636. Irp->IoStatus.Status = status;
  4637. Irp->IoStatus.Information = 0;
  4638. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4639. return status;
  4640. }
  4641. status = WmiSystemControl(&deviceExtension->WmiLibInfo,
  4642. DeviceObject,
  4643. Irp,
  4644. &disposition);
  4645. switch(disposition) {
  4646. case IrpProcessed:
  4647. //
  4648. // This irp has been processed and may be completed or pending.
  4649. //
  4650. break;
  4651. case IrpNotCompleted:
  4652. //
  4653. // This irp has not been completed, but has been fully processed.
  4654. // we will complete it now
  4655. //
  4656. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4657. break;
  4658. case IrpForward:
  4659. case IrpNotWmi:
  4660. //
  4661. // This irp is either not a WMI irp or is a WMI irp targetted
  4662. // at a device lower in the stack.
  4663. //
  4664. status = MouseClassPassThrough(DeviceObject, Irp);
  4665. break;
  4666. default:
  4667. //
  4668. // We really should never get here, but if we do just forward....
  4669. //
  4670. ASSERT(FALSE);
  4671. status = MouseClassPassThrough(DeviceObject, Irp);
  4672. break;
  4673. }
  4674. IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
  4675. return status;
  4676. }
  4677. NTSTATUS
  4678. MouseClassSetWmiDataItem(
  4679. IN PDEVICE_OBJECT DeviceObject,
  4680. IN PIRP Irp,
  4681. IN ULONG GuidIndex,
  4682. IN ULONG InstanceIndex,
  4683. IN ULONG DataItemId,
  4684. IN ULONG BufferSize,
  4685. IN PUCHAR Buffer
  4686. )
  4687. /*++
  4688. Routine Description:
  4689. This routine is a callback into the driver to set for the contents of
  4690. a data block. When the driver has finished filling the data block it
  4691. must call ClassWmiCompleteRequest to complete the irp. The driver can
  4692. return STATUS_PENDING if the irp cannot be completed immediately.
  4693. Arguments:
  4694. DeviceObject is the device whose data block is being queried
  4695. Irp is the Irp that makes this request
  4696. GuidIndex is the index into the list of guids provided when the
  4697. device registered
  4698. InstanceIndex is the index that denotes which instance of the data block
  4699. is being queried.
  4700. DataItemId has the id of the data item being set
  4701. BufferSize has the size of the data item passed
  4702. Buffer has the new values for the data item
  4703. Return Value:
  4704. status
  4705. --*/
  4706. {
  4707. PDEVICE_EXTENSION data;
  4708. NTSTATUS status;
  4709. ULONG size = 0;
  4710. PAGED_CODE ();
  4711. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  4712. switch(GuidIndex) {
  4713. case WMI_CLASS_DRIVER_INFORMATION:
  4714. status = STATUS_WMI_READ_ONLY;
  4715. break;
  4716. case WMI_WAIT_WAKE:
  4717. size = sizeof(BOOLEAN);
  4718. if (BufferSize < size) {
  4719. status = STATUS_BUFFER_TOO_SMALL;
  4720. break;
  4721. } else if ((1 != DataItemId) || (0 != InstanceIndex)) {
  4722. status = STATUS_INVALID_DEVICE_REQUEST;
  4723. break;
  4724. }
  4725. status = MouseToggleWaitWake(data, *(PBOOLEAN) Buffer);
  4726. break;
  4727. default:
  4728. status = STATUS_WMI_GUID_NOT_FOUND;
  4729. }
  4730. status = WmiCompleteRequest (DeviceObject,
  4731. Irp,
  4732. status,
  4733. 0,
  4734. IO_NO_INCREMENT);
  4735. return status;
  4736. }
  4737. NTSTATUS
  4738. MouseClassSetWmiDataBlock(
  4739. IN PDEVICE_OBJECT DeviceObject,
  4740. IN PIRP Irp,
  4741. IN ULONG GuidIndex,
  4742. IN ULONG InstanceIndex,
  4743. IN ULONG BufferSize,
  4744. IN PUCHAR Buffer
  4745. )
  4746. /*++
  4747. Routine Description:
  4748. This routine is a callback into the driver to set the contents of
  4749. a data block. When the driver has finished filling the data block it
  4750. must call ClassWmiCompleteRequest to complete the irp. The driver can
  4751. return STATUS_PENDING if the irp cannot be completed immediately.
  4752. Arguments:
  4753. DeviceObject is the device whose data block is being queried
  4754. Irp is the Irp that makes this request
  4755. GuidIndex is the index into the list of guids provided when the
  4756. device registered
  4757. InstanceIndex is the index that denotes which instance of the data block
  4758. is being queried.
  4759. BufferSize has the size of the data block passed
  4760. Buffer has the new values for the data block
  4761. Return Value:
  4762. status
  4763. --*/
  4764. {
  4765. PDEVICE_EXTENSION data;
  4766. NTSTATUS status;
  4767. ULONG size = 0;
  4768. PAGED_CODE ();
  4769. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  4770. switch(GuidIndex) {
  4771. case WMI_CLASS_DRIVER_INFORMATION:
  4772. status = STATUS_WMI_READ_ONLY;
  4773. break;
  4774. case WMI_WAIT_WAKE: {
  4775. size = sizeof(BOOLEAN);
  4776. if (BufferSize < size) {
  4777. status = STATUS_BUFFER_TOO_SMALL;
  4778. break;
  4779. } else if (0 != InstanceIndex) {
  4780. status = STATUS_INVALID_DEVICE_REQUEST;
  4781. break;
  4782. }
  4783. status = MouseToggleWaitWake (data, * (PBOOLEAN) Buffer);
  4784. break;
  4785. }
  4786. default:
  4787. status = STATUS_WMI_GUID_NOT_FOUND;
  4788. }
  4789. status = WmiCompleteRequest (DeviceObject,
  4790. Irp,
  4791. status,
  4792. size,
  4793. IO_NO_INCREMENT);
  4794. return status;
  4795. }
  4796. NTSTATUS
  4797. MouseClassQueryWmiDataBlock(
  4798. IN PDEVICE_OBJECT DeviceObject,
  4799. IN PIRP Irp,
  4800. IN ULONG GuidIndex,
  4801. IN ULONG InstanceIndex,
  4802. IN ULONG InstanceCount,
  4803. IN OUT PULONG InstanceLengthArray,
  4804. IN ULONG OutBufferSize,
  4805. OUT PUCHAR Buffer
  4806. )
  4807. /*++
  4808. Routine Description:
  4809. This routine is a callback into the driver to query for the contents of
  4810. a data block. When the driver has finished filling the data block it
  4811. must call ClassWmiCompleteRequest to complete the irp. The driver can
  4812. return STATUS_PENDING if the irp cannot be completed immediately.
  4813. Arguments:
  4814. DeviceObject is the device whose data block is being queried
  4815. Irp is the Irp that makes this request
  4816. GuidIndex is the index into the list of guids provided when the
  4817. device registered
  4818. InstanceIndex is the index that denotes which instance of the data block
  4819. is being queried.
  4820. InstanceCount is the number of instnaces expected to be returned for
  4821. the data block.
  4822. InstanceLengthArray is a pointer to an array of ULONG that returns the
  4823. lengths of each instance of the data block. If this is NULL then
  4824. there was not enough space in the output buffer to fufill the request
  4825. so the irp should be completed with the buffer needed.
  4826. BufferAvail on has the maximum size available to write the data
  4827. block.
  4828. Buffer on return is filled with the returned data block
  4829. Return Value:
  4830. status
  4831. --*/
  4832. {
  4833. PDEVICE_EXTENSION data;
  4834. NTSTATUS status;
  4835. ULONG size = 0;
  4836. PMSMouse_ClassInformation classInformation;
  4837. PAGED_CODE ()
  4838. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  4839. switch (GuidIndex) {
  4840. case WMI_CLASS_DRIVER_INFORMATION:
  4841. //
  4842. // Only registers 1 instance for this guid
  4843. //
  4844. if ((0 != InstanceIndex) || (1 != InstanceCount)) {
  4845. status = STATUS_INVALID_DEVICE_REQUEST;
  4846. break;
  4847. }
  4848. size = sizeof (MSMouse_ClassInformation);
  4849. if (OutBufferSize < size) {
  4850. status = STATUS_BUFFER_TOO_SMALL;
  4851. break;
  4852. }
  4853. classInformation = (PMSMouse_ClassInformation)Buffer;
  4854. classInformation->DeviceId = (ULONGLONG) DeviceObject;
  4855. *InstanceLengthArray = size;
  4856. status = STATUS_SUCCESS;
  4857. break;
  4858. case WMI_WAIT_WAKE:
  4859. //
  4860. // Only registers 1 instance for this guid
  4861. //
  4862. if ((0 != InstanceIndex) || (1 != InstanceCount)) {
  4863. status = STATUS_INVALID_DEVICE_REQUEST;
  4864. break;
  4865. }
  4866. size = sizeof(BOOLEAN);
  4867. if (OutBufferSize < size) {
  4868. status = STATUS_BUFFER_TOO_SMALL;
  4869. break;
  4870. }
  4871. *(PBOOLEAN) Buffer = (WAITWAKE_ON (data) ? TRUE : FALSE);
  4872. *InstanceLengthArray = size;
  4873. status = STATUS_SUCCESS;
  4874. break;
  4875. default:
  4876. status = STATUS_WMI_GUID_NOT_FOUND;
  4877. }
  4878. status = WmiCompleteRequest (DeviceObject,
  4879. Irp,
  4880. status,
  4881. size,
  4882. IO_NO_INCREMENT);
  4883. return status;
  4884. }
  4885. NTSTATUS
  4886. MouseClassQueryWmiRegInfo(
  4887. IN PDEVICE_OBJECT DeviceObject,
  4888. OUT ULONG *RegFlags,
  4889. OUT PUNICODE_STRING InstanceName,
  4890. OUT PUNICODE_STRING *RegistryPath,
  4891. OUT PUNICODE_STRING MofResourceName,
  4892. OUT PDEVICE_OBJECT *Pdo
  4893. )
  4894. /*++
  4895. Routine Description:
  4896. This routine is a callback into the driver to retrieve information about
  4897. the guids being registered.
  4898. Implementations of this routine may be in paged memory
  4899. Arguments:
  4900. DeviceObject is the device whose registration information is needed
  4901. *RegFlags returns with a set of flags that describe all of the guids being
  4902. registered for this device. If the device wants enable and disable
  4903. collection callbacks before receiving queries for the registered
  4904. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  4905. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  4906. the instance name is determined from the PDO associated with the
  4907. device object. Note that the PDO must have an associated devnode. If
  4908. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  4909. name for the device. These flags are ORed into the flags specified
  4910. by the GUIDREGINFO for each guid.
  4911. InstanceName returns with the instance name for the guids if
  4912. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  4913. caller will call ExFreePool with the buffer returned.
  4914. *RegistryPath returns with the registry path of the driver. This is
  4915. required
  4916. *MofResourceName returns with the name of the MOF resource attached to
  4917. the binary file. If the driver does not have a mof resource attached
  4918. then this can be returned as NULL.
  4919. *Pdo returns with the device object for the PDO associated with this
  4920. device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in
  4921. *RegFlags.
  4922. Return Value:
  4923. status
  4924. --*/
  4925. {
  4926. PDEVICE_EXTENSION deviceExtension;
  4927. deviceExtension = DeviceObject->DeviceExtension;
  4928. *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
  4929. *RegistryPath = &Globals.RegistryPath;
  4930. *Pdo = deviceExtension->PDO;
  4931. return STATUS_SUCCESS;
  4932. }