Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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