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

6561 lines
194 KiB

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