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

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