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.

1842 lines
57 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This module contains general PnP and Power code for the i8042prt Driver.
  7. Environment:
  8. Kernel mode.
  9. Revision History:
  10. --*/
  11. #include "i8042prt.h"
  12. #include "i8042log.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, I8xAddDevice)
  15. #pragma alloc_text(PAGE, I8xFilterResourceRequirements)
  16. #pragma alloc_text(PAGE, I8xFindPortCallout)
  17. #pragma alloc_text(PAGE, I8xManuallyRemoveDevice)
  18. #pragma alloc_text(PAGE, I8xPnP)
  19. #pragma alloc_text(PAGE, I8xPower)
  20. #pragma alloc_text(PAGE, I8xRegisterDeviceInterface)
  21. #pragma alloc_text(PAGE, I8xRemovePort)
  22. #pragma alloc_text(PAGE, I8xSendIrpSynchronously)
  23. #endif
  24. NTSTATUS
  25. I8xAddDevice (
  26. IN PDRIVER_OBJECT Driver,
  27. IN PDEVICE_OBJECT PDO
  28. )
  29. /*++
  30. Routine Description:
  31. Adds a device to the stack and sets up the appropriate flags and
  32. device extension for the newly created device.
  33. Arguments:
  34. Driver - The driver object
  35. PDO - the device that we are attaching ourselves on top of
  36. Return Value:
  37. NTSTATUS result code.
  38. --*/
  39. {
  40. PCOMMON_DATA commonData;
  41. PIO_ERROR_LOG_PACKET errorLogEntry;
  42. PDEVICE_OBJECT device;
  43. NTSTATUS status = STATUS_SUCCESS;
  44. ULONG maxSize;
  45. PAGED_CODE();
  46. Print(DBG_PNP_TRACE, ("enter Add Device \n"));
  47. maxSize = sizeof(PORT_KEYBOARD_EXTENSION) > sizeof(PORT_MOUSE_EXTENSION) ?
  48. sizeof(PORT_KEYBOARD_EXTENSION) :
  49. sizeof(PORT_MOUSE_EXTENSION);
  50. status = IoCreateDevice(Driver, // driver
  51. maxSize, // size of extension
  52. NULL, // device name
  53. FILE_DEVICE_8042_PORT, // device type ?? unknown at this time!!!
  54. 0, // device characteristics
  55. FALSE, // exclusive
  56. &device // new device
  57. );
  58. if (!NT_SUCCESS(status)) {
  59. return (status);
  60. }
  61. RtlZeroMemory(device->DeviceExtension, maxSize);
  62. commonData = GET_COMMON_DATA(device->DeviceExtension);
  63. commonData->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);
  64. if (commonData->TopOfStack == NULL) {
  65. //
  66. // Not good; in only extreme cases will this fail
  67. //
  68. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  69. IoAllocateErrorLogEntry(Driver, (UCHAR)sizeof(IO_ERROR_LOG_PACKET));
  70. if (errorLogEntry) {
  71. errorLogEntry->ErrorCode = I8042_ATTACH_DEVICE_FAILED;
  72. errorLogEntry->DumpDataSize = 0;
  73. errorLogEntry->SequenceNumber = 0;
  74. errorLogEntry->MajorFunctionCode = 0;
  75. errorLogEntry->IoControlCode = 0;
  76. errorLogEntry->RetryCount = 0;
  77. errorLogEntry->UniqueErrorValue = 0;
  78. errorLogEntry->FinalStatus = STATUS_DEVICE_NOT_CONNECTED;
  79. IoWriteErrorLogEntry (errorLogEntry);
  80. }
  81. IoDeleteDevice (device);
  82. return STATUS_DEVICE_NOT_CONNECTED;
  83. }
  84. ASSERT(commonData->TopOfStack);
  85. commonData->Self = device;
  86. commonData->PDO = PDO;
  87. commonData->PowerState = PowerDeviceD0;
  88. KeInitializeSpinLock(&commonData->InterruptSpinLock);
  89. //
  90. // Initialize the data consumption timer
  91. //
  92. KeInitializeTimer(&commonData->DataConsumptionTimer);
  93. //
  94. // Initialize the port DPC queue to log overrun and internal
  95. // device errors.
  96. //
  97. KeInitializeDpc(
  98. &commonData->ErrorLogDpc,
  99. (PKDEFERRED_ROUTINE) I8042ErrorLogDpc,
  100. device
  101. );
  102. //
  103. // Initialize the device completion DPC for requests that exceed the
  104. // maximum number of retries.
  105. //
  106. KeInitializeDpc(
  107. &commonData->RetriesExceededDpc,
  108. (PKDEFERRED_ROUTINE) I8042RetriesExceededDpc,
  109. device
  110. );
  111. //
  112. // Initialize the device completion DPC for requests that have timed out
  113. //
  114. KeInitializeDpc(
  115. &commonData->TimeOutDpc,
  116. (PKDEFERRED_ROUTINE) I8042TimeOutDpc,
  117. device
  118. );
  119. //
  120. // Initialize the port completion DPC object in the device extension.
  121. // This DPC routine handles the completion of successful set requests.
  122. //
  123. IoInitializeDpcRequest(device, I8042CompletionDpc);
  124. IoInitializeRemoveLock(&commonData->RemoveLock,
  125. I8042_POOL_TAG,
  126. 0,
  127. 0);
  128. device->Flags |= DO_BUFFERED_IO;
  129. device->Flags |= DO_POWER_PAGABLE;
  130. device->Flags &= ~DO_DEVICE_INITIALIZING;
  131. Print(DBG_PNP_TRACE, ("Add Device (0x%x)\n", status));
  132. return status;
  133. }
  134. NTSTATUS
  135. I8xSendIrpSynchronously (
  136. IN PDEVICE_OBJECT DeviceObject,
  137. IN PIRP Irp,
  138. IN BOOLEAN Strict
  139. )
  140. /*++
  141. Routine Description:
  142. Generic routine to send an irp DeviceObject and wait for its return up the
  143. device stack.
  144. Arguments:
  145. DeviceObject - The device object to which we want to send the Irp
  146. Irp - The Irp we want to send
  147. Return Value:
  148. return code from the Irp
  149. --*/
  150. {
  151. KEVENT event;
  152. NTSTATUS status;
  153. PAGED_CODE();
  154. KeInitializeEvent(&event,
  155. SynchronizationEvent,
  156. FALSE
  157. );
  158. IoCopyCurrentIrpStackLocationToNext(Irp);
  159. IoSetCompletionRoutine(Irp,
  160. I8xPnPComplete,
  161. &event,
  162. TRUE,
  163. TRUE,
  164. TRUE
  165. );
  166. status = IoCallDriver(DeviceObject, Irp);
  167. //
  168. // Wait for lower drivers to be done with the Irp
  169. //
  170. if (status == STATUS_PENDING) {
  171. KeWaitForSingleObject(&event,
  172. Executive,
  173. KernelMode,
  174. FALSE,
  175. NULL
  176. );
  177. status = Irp->IoStatus.Status;
  178. }
  179. if (!Strict &&
  180. (status == STATUS_NOT_SUPPORTED ||
  181. status == STATUS_INVALID_DEVICE_REQUEST)) {
  182. status = STATUS_SUCCESS;
  183. }
  184. return status;
  185. }
  186. NTSTATUS
  187. I8xPnPComplete (
  188. IN PDEVICE_OBJECT DeviceObject,
  189. IN PIRP Irp,
  190. IN PKEVENT Event
  191. )
  192. /*++
  193. Routine Description:
  194. Completion routine for all PnP IRPs
  195. Arguments:
  196. DeviceObject - Pointer to the DeviceObject
  197. Irp - Pointer to the request packet
  198. Event - The event to set once processing is complete
  199. Return Value:
  200. STATUS_MORE_PROCESSING_REQUIRED
  201. --*/
  202. {
  203. UNREFERENCED_PARAMETER (DeviceObject);
  204. UNREFERENCED_PARAMETER (Irp);
  205. //
  206. // Since this completion routines sole purpose in life is to synchronize
  207. // Irp, we know that unless something else happens that the IoCallDriver
  208. // will unwind AFTER the we have complete this Irp. Therefore we should
  209. // NOT bubble up the pending bit.
  210. //
  211. // if (Irp->PendingReturned) {
  212. // IoMarkIrpPending(Irp);
  213. // }
  214. //
  215. KeSetEvent(Event, 0, FALSE);
  216. return STATUS_MORE_PROCESSING_REQUIRED;
  217. }
  218. NTSTATUS
  219. I8xPnP (
  220. IN PDEVICE_OBJECT DeviceObject,
  221. IN PIRP Irp
  222. )
  223. /*++
  224. Routine Description:
  225. This is the dispatch routine for PnP requests
  226. Arguments:
  227. DeviceObject - Pointer to the device object
  228. Irp - Pointer to the request packet
  229. Return Value:
  230. STATUS_SUCCESSFUL if successful,
  231. an valid NTSTATUS error code otherwise
  232. --*/
  233. {
  234. PPORT_KEYBOARD_EXTENSION kbExtension;
  235. PPORT_MOUSE_EXTENSION mouseExtension;
  236. PCOMMON_DATA commonData;
  237. PIO_STACK_LOCATION stack;
  238. NTSTATUS status = STATUS_SUCCESS;
  239. KIRQL oldIrql;
  240. PAGED_CODE();
  241. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  242. stack = IoGetCurrentIrpStackLocation(Irp);
  243. status = IoAcquireRemoveLock(&commonData->RemoveLock, Irp);
  244. if (!NT_SUCCESS(status)) {
  245. Irp->IoStatus.Status = status;
  246. Irp->IoStatus.Information = 0;
  247. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  248. return status;
  249. }
  250. Print(DBG_PNP_TRACE,
  251. ("I8xPnP (%s), enter (min func=0x%x)\n",
  252. commonData->IsKeyboard ? "kb" : "mou",
  253. (ULONG) stack->MinorFunction
  254. ));
  255. switch (stack->MinorFunction) {
  256. case IRP_MN_START_DEVICE:
  257. //
  258. // The device is starting.
  259. //
  260. // We cannot touch the device (send it any non pnp irps) until a
  261. // start device has been passed down to the lower drivers.
  262. //
  263. status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, TRUE);
  264. if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) {
  265. //
  266. // As we are successfully now back from our start device
  267. // we can do work.
  268. ExAcquireFastMutexUnsafe(&Globals.DispatchMutex);
  269. if (commonData->Started) {
  270. Print(DBG_PNP_ERROR,
  271. ("received 1+ starts on %s\n",
  272. commonData->IsKeyboard ? "kb" : "mouse"
  273. ));
  274. }
  275. else {
  276. //
  277. // commonData->IsKeyboard is set during
  278. // IOCTL_INTERNAL_KEYBOARD_CONNECT to TRUE and
  279. // IOCTL_INTERNAL_MOUSE_CONNECT to FALSE
  280. //
  281. if (IS_KEYBOARD(commonData)) {
  282. status = I8xKeyboardStartDevice(
  283. (PPORT_KEYBOARD_EXTENSION) DeviceObject->DeviceExtension,
  284. stack->Parameters.StartDevice.AllocatedResourcesTranslated
  285. );
  286. }
  287. else {
  288. status = I8xMouseStartDevice(
  289. (PPORT_MOUSE_EXTENSION) DeviceObject->DeviceExtension,
  290. stack->Parameters.StartDevice.AllocatedResourcesTranslated
  291. );
  292. }
  293. if (NT_SUCCESS(status)) {
  294. InterlockedIncrement(&Globals.StartedDevices);
  295. commonData->Started = TRUE;
  296. }
  297. }
  298. ExReleaseFastMutexUnsafe(&Globals.DispatchMutex);
  299. }
  300. //
  301. // We must now complete the IRP, since we stopped it in the
  302. // completetion routine with MORE_PROCESSING_REQUIRED.
  303. //
  304. Irp->IoStatus.Status = status;
  305. Irp->IoStatus.Information = 0;
  306. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  307. break;
  308. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  309. //
  310. // The general rule of thumb for handling this minor code is this:
  311. // add resources when the irp is going down the stack and
  312. // remove resources when the irp is coming back up the stack
  313. //
  314. // The irp has the original resources on the way down.
  315. //
  316. status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, FALSE);
  317. if (NT_SUCCESS(status)) {
  318. status = I8xFilterResourceRequirements(DeviceObject,
  319. Irp
  320. );
  321. }
  322. else {
  323. Print(DBG_PNP_ERROR,
  324. ("error pending filter res req event (0x%x)\n",
  325. status
  326. ));
  327. }
  328. //
  329. // Irp->IoStatus.Information will contain the new i/o resource
  330. // requirements list so leave it alone
  331. //
  332. Irp->IoStatus.Status = status;
  333. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  334. break;
  335. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  336. status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, FALSE);
  337. if (NT_SUCCESS(status)) {
  338. (PNP_DEVICE_STATE) Irp->IoStatus.Information |=
  339. commonData->PnpDeviceState;
  340. }
  341. else {
  342. Print(DBG_PNP_ERROR,
  343. ("error pending query pnp device state event (0x%x)\n",
  344. status
  345. ));
  346. }
  347. //
  348. // Irp->IoStatus.Information will contain the new i/o resource
  349. // requirements list so leave it alone
  350. //
  351. Irp->IoStatus.Status = status;
  352. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  353. break;
  354. //
  355. // Don't let either of the requests succeed, otherwise the kb/mouse
  356. // might be rendered useless.
  357. //
  358. // NOTE: this behavior is particular to i8042prt. Any other driver,
  359. // especially any other keyboard or port driver, should
  360. // succeed the query remove or stop. i8042prt has this different
  361. // behavior because of the shared I/O ports but independent interrupts.
  362. //
  363. // FURTHERMORE, if you allow the query to succeed, it should be sent
  364. // down the stack (see sermouse.sys for an example of how to do this)
  365. //
  366. case IRP_MN_QUERY_REMOVE_DEVICE:
  367. case IRP_MN_QUERY_STOP_DEVICE:
  368. status = (MANUALLY_REMOVED(commonData) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  369. //
  370. // If we succeed the irp, we must send it down the stack
  371. //
  372. if (NT_SUCCESS(status)) {
  373. IoSkipCurrentIrpStackLocation(Irp);
  374. status = IoCallDriver(commonData->TopOfStack, Irp);
  375. }
  376. else {
  377. Irp->IoStatus.Status = status;
  378. Irp->IoStatus.Information = 0;
  379. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  380. }
  381. break;
  382. //
  383. // PnP rules dictate we send the IRP down to the PDO first
  384. //
  385. case IRP_MN_CANCEL_REMOVE_DEVICE:
  386. case IRP_MN_CANCEL_STOP_DEVICE:
  387. status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, FALSE);
  388. Irp->IoStatus.Status = status;
  389. Irp->IoStatus.Information = 0;
  390. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  391. break;
  392. // case IRP_MN_SURPRISE_REMOVAL:
  393. case IRP_MN_REMOVE_DEVICE:
  394. Print(DBG_PNP_INFO,
  395. ("(surprise) remove device (0x%x function 0x%x)\n",
  396. commonData->Self,
  397. (ULONG) stack->MinorFunction));
  398. if (commonData->Initialized) {
  399. IoWMIRegistrationControl(commonData->Self,
  400. WMIREG_ACTION_DEREGISTER
  401. );
  402. }
  403. if (commonData->Started) {
  404. InterlockedDecrement(&Globals.StartedDevices);
  405. }
  406. //
  407. // Wait for any pending I/O to drain
  408. //
  409. IoReleaseRemoveLockAndWait(&commonData->RemoveLock, Irp);
  410. ExAcquireFastMutexUnsafe(&Globals.DispatchMutex);
  411. if (IS_KEYBOARD(commonData)) {
  412. I8xKeyboardRemoveDevice(DeviceObject);
  413. }
  414. else {
  415. I8xMouseRemoveDevice(DeviceObject);
  416. }
  417. ExReleaseFastMutexUnsafe(&Globals.DispatchMutex);
  418. //
  419. // Set these flags so that when a surprise remove is sent, it will be
  420. // handled just like a remove, and when the remove comes, no other
  421. // removal type actions will occur.
  422. //
  423. commonData->Started = FALSE;
  424. commonData->Initialized = FALSE;
  425. Irp->IoStatus.Status = STATUS_SUCCESS;
  426. IoSkipCurrentIrpStackLocation(Irp);
  427. status = IoCallDriver(commonData->TopOfStack, Irp);
  428. IoDetachDevice(commonData->TopOfStack);
  429. IoDeleteDevice(DeviceObject);
  430. return status;
  431. case IRP_MN_QUERY_CAPABILITIES:
  432. //
  433. // Change the device caps to not allow wait wake requests on level
  434. // triggered interrupts for mice because when an errant mouse movement
  435. // occurs while we are going to sleep, the interrupt will remain
  436. // triggered indefinitely.
  437. //
  438. // If the mouse does not have a level triggered interrupt, just let the
  439. // irp go by...
  440. //
  441. if (commonData->Started &&
  442. IS_MOUSE(commonData) && IS_LEVEL_TRIGGERED(commonData)) {
  443. Print(DBG_PNP_NOISE, ("query caps, mouse is level triggered\n"));
  444. status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, TRUE);
  445. if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) {
  446. PDEVICE_CAPABILITIES devCaps;
  447. Print(DBG_PNP_INFO, ("query caps, removing wake caps\n"));
  448. stack = IoGetCurrentIrpStackLocation(Irp);
  449. devCaps = stack->Parameters.DeviceCapabilities.Capabilities;
  450. ASSERT(devCaps);
  451. if (devCaps) {
  452. Print(DBG_PNP_NOISE,
  453. ("old DeviceWake was D%d and SystemWake was S%d.\n",
  454. devCaps->DeviceWake-1, devCaps->SystemWake-1
  455. )) ;
  456. devCaps->DeviceWake = PowerDeviceUnspecified;
  457. devCaps->SystemWake = PowerSystemUnspecified;
  458. }
  459. }
  460. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  461. break;
  462. }
  463. case IRP_MN_STOP_DEVICE:
  464. case IRP_MN_QUERY_DEVICE_RELATIONS:
  465. case IRP_MN_QUERY_INTERFACE:
  466. case IRP_MN_QUERY_DEVICE_TEXT:
  467. case IRP_MN_QUERY_RESOURCES:
  468. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  469. case IRP_MN_READ_CONFIG:
  470. case IRP_MN_WRITE_CONFIG:
  471. case IRP_MN_EJECT:
  472. case IRP_MN_SET_LOCK:
  473. case IRP_MN_QUERY_ID:
  474. default:
  475. //
  476. // Here the driver below i8042prt might modify the behavior of these IRPS
  477. // Please see PlugPlay documentation for use of these IRPs.
  478. //
  479. IoSkipCurrentIrpStackLocation(Irp);
  480. status = IoCallDriver(commonData->TopOfStack, Irp);
  481. break;
  482. }
  483. Print(DBG_PNP_TRACE,
  484. ("I8xPnP (%s) exit (status=0x%x)\n",
  485. commonData->IsKeyboard ? "kb" : "mou",
  486. status
  487. ));
  488. IoReleaseRemoveLock(&commonData->RemoveLock, Irp);
  489. return status;
  490. }
  491. LONG
  492. I8xManuallyRemoveDevice(
  493. PCOMMON_DATA CommonData
  494. )
  495. /*++
  496. Routine Description:
  497. Invalidates CommonData->PDO's device state and sets the manually removed
  498. flag
  499. Arguments:
  500. CommonData - represent either the keyboard or mouse
  501. Return Value:
  502. new device count for that particular type of device
  503. --*/
  504. {
  505. LONG deviceCount;
  506. PAGED_CODE();
  507. if (IS_KEYBOARD(CommonData)) {
  508. deviceCount = InterlockedDecrement(&Globals.AddedKeyboards);
  509. if (deviceCount < 1) {
  510. Print(DBG_PNP_INFO, ("clear kb (manually remove)\n"));
  511. CLEAR_KEYBOARD_PRESENT();
  512. }
  513. } else {
  514. deviceCount = InterlockedDecrement(&Globals.AddedMice);
  515. if (deviceCount < 1) {
  516. Print(DBG_PNP_INFO, ("clear mou (manually remove)\n"));
  517. CLEAR_MOUSE_PRESENT();
  518. }
  519. }
  520. CommonData->PnpDeviceState |= PNP_DEVICE_REMOVED | PNP_DEVICE_DONT_DISPLAY_IN_UI;
  521. IoInvalidateDeviceState(CommonData->PDO);
  522. return deviceCount;
  523. }
  524. #define PhysAddrCmp(a,b) ( (a).LowPart == (b).LowPart && (a).HighPart == (b).HighPart )
  525. BOOLEAN
  526. I8xRemovePort(
  527. IN PIO_RESOURCE_DESCRIPTOR ResDesc
  528. )
  529. /*++
  530. Routine Description:
  531. If the physical address contained in the ResDesc is not in the list of
  532. previously seen physicall addresses, it is placed within the list.
  533. Arguments:
  534. ResDesc - contains the physical address
  535. Return Value:
  536. TRUE - if the physical address was found in the list
  537. FALSE - if the physical address was not found in the list (and thus inserted
  538. into it)
  539. --*/
  540. {
  541. ULONG i;
  542. PHYSICAL_ADDRESS address;
  543. PAGED_CODE();
  544. if (Globals.ControllerData->KnownPortsCount == -1) {
  545. return FALSE;
  546. }
  547. address = ResDesc->u.Port.MinimumAddress;
  548. for (i = 0; i < Globals.ControllerData->KnownPortsCount; i++) {
  549. if (PhysAddrCmp(address, Globals.ControllerData->KnownPorts[i])) {
  550. return TRUE;
  551. }
  552. }
  553. if (Globals.ControllerData->KnownPortsCount < MaximumPortCount) {
  554. Globals.ControllerData->KnownPorts[
  555. Globals.ControllerData->KnownPortsCount++] = address;
  556. }
  557. Print(DBG_PNP_INFO,
  558. ("Saw port [0x%08x %08x] - [0x%08x %08x]\n",
  559. address.HighPart,
  560. address.LowPart,
  561. ResDesc->u.Port.MaximumAddress.HighPart,
  562. ResDesc->u.Port.MaximumAddress.LowPart
  563. ));
  564. return FALSE;
  565. }
  566. NTSTATUS
  567. I8xFindPortCallout(
  568. IN PVOID Context,
  569. IN PUNICODE_STRING PathName,
  570. IN INTERFACE_TYPE BusType,
  571. IN ULONG BusNumber,
  572. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  573. IN CONFIGURATION_TYPE ControllerType,
  574. IN ULONG ControllerNumber,
  575. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  576. IN CONFIGURATION_TYPE PeripheralType,
  577. IN ULONG PeripheralNumber,
  578. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  579. )
  580. /*++
  581. Routine Description:
  582. This is the callout routine sent as a parameter to
  583. IoQueryDeviceDescription. It grabs the keyboard controller and
  584. peripheral configuration information.
  585. Arguments:
  586. Context - Context parameter that was passed in by the routine
  587. that called IoQueryDeviceDescription.
  588. PathName - The full pathname for the registry key.
  589. BusType - Bus interface type (Isa, Eisa, Mca, etc.).
  590. BusNumber - The bus sub-key (0, 1, etc.).
  591. BusInformation - Pointer to the array of pointers to the full value
  592. information for the bus.
  593. ControllerType - The controller type (should be KeyboardController).
  594. ControllerNumber - The controller sub-key (0, 1, etc.).
  595. ControllerInformation - Pointer to the array of pointers to the full
  596. value information for the controller key.
  597. PeripheralType - The peripheral type (should be KeyboardPeripheral).
  598. PeripheralNumber - The peripheral sub-key.
  599. PeripheralInformation - Pointer to the array of pointers to the full
  600. value information for the peripheral key.
  601. Return Value:
  602. None. If successful, will have the following side-effects:
  603. - Sets DeviceObject->DeviceExtension->HardwarePresent.
  604. - Sets configuration fields in
  605. DeviceObject->DeviceExtension->Configuration.
  606. --*/
  607. {
  608. PUCHAR controllerData;
  609. NTSTATUS status = STATUS_UNSUCCESSFUL;
  610. ULONG i,
  611. listCount,
  612. portCount = 0;
  613. PIO_RESOURCE_LIST pResList = (PIO_RESOURCE_LIST) Context;
  614. PIO_RESOURCE_DESCRIPTOR pResDesc;
  615. PKEY_VALUE_FULL_INFORMATION controllerInfo = NULL;
  616. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
  617. PAGED_CODE();
  618. UNREFERENCED_PARAMETER(PathName);
  619. UNREFERENCED_PARAMETER(BusType);
  620. UNREFERENCED_PARAMETER(BusNumber);
  621. UNREFERENCED_PARAMETER(BusInformation);
  622. UNREFERENCED_PARAMETER(ControllerType);
  623. UNREFERENCED_PARAMETER(ControllerNumber);
  624. UNREFERENCED_PARAMETER(PeripheralType);
  625. UNREFERENCED_PARAMETER(PeripheralNumber);
  626. UNREFERENCED_PARAMETER(PeripheralInformation);
  627. pResDesc = pResList->Descriptors + pResList->Count;
  628. controllerInfo = ControllerInformation[IoQueryDeviceConfigurationData];
  629. Print(DBG_PNP_TRACE, ("I8xFindPortCallout enter\n"));
  630. if (controllerInfo->DataLength != 0) {
  631. controllerData = ((PUCHAR) controllerInfo) + controllerInfo->DataOffset;
  632. controllerData += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  633. PartialResourceList);
  634. listCount = ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->Count;
  635. resourceDescriptor =
  636. ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->PartialDescriptors;
  637. for (i = 0; i < listCount; i++, resourceDescriptor++) {
  638. switch(resourceDescriptor->Type) {
  639. case CmResourceTypePort:
  640. if (portCount < 2) {
  641. Print(DBG_PNP_INFO,
  642. ("found port [0x%x 0x%x] with length %d\n",
  643. resourceDescriptor->u.Port.Start.HighPart,
  644. resourceDescriptor->u.Port.Start.LowPart,
  645. resourceDescriptor->u.Port.Length
  646. ));
  647. pResDesc->Type = resourceDescriptor->Type;
  648. pResDesc->Flags = resourceDescriptor->Flags;
  649. pResDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  650. pResDesc->u.Port.Alignment = 1;
  651. pResDesc->u.Port.Length =
  652. resourceDescriptor->u.Port.Length;
  653. pResDesc->u.Port.MinimumAddress.QuadPart =
  654. resourceDescriptor->u.Port.Start.QuadPart;
  655. pResDesc->u.Port.MaximumAddress.QuadPart =
  656. pResDesc->u.Port.MinimumAddress.QuadPart +
  657. pResDesc->u.Port.Length - 1;
  658. pResList->Count++;
  659. //
  660. // We want to record the ports we stole from the kb as seen
  661. // so that if the keyboard is started later, we can trim
  662. // its resources and not have a resource conflict...
  663. //
  664. // ...we are getting too smart for ourselves here :]
  665. //
  666. I8xRemovePort(pResDesc);
  667. pResDesc++;
  668. }
  669. status = STATUS_SUCCESS;
  670. break;
  671. default:
  672. Print(DBG_PNP_NOISE, ("type 0x%x found\n",
  673. (LONG) resourceDescriptor->Type));
  674. break;
  675. }
  676. }
  677. }
  678. Print(DBG_PNP_TRACE, ("I8xFindPortCallout exit (0x%x)\n", status));
  679. return status;
  680. }
  681. NTSTATUS
  682. I8xFilterResourceRequirements(
  683. IN PDEVICE_OBJECT DeviceObject,
  684. IN PIRP Irp
  685. )
  686. /*++
  687. Routine Description:
  688. Iterates through the resource requirements list contained in the IRP and removes
  689. any duplicate requests for I/O ports. (This is a common problem on the Alphas.)
  690. No removal is performed if more than one resource requirements list is present.
  691. Arguments:
  692. DeviceObject - A pointer to the device object
  693. Irp - A pointer to the request packet which contains the resource req. list.
  694. Return Value:
  695. None.
  696. --*/
  697. {
  698. PIO_RESOURCE_REQUIREMENTS_LIST pReqList = NULL,
  699. pNewReqList = NULL;
  700. PIO_RESOURCE_LIST pResList = NULL,
  701. pNewResList = NULL;
  702. PIO_RESOURCE_DESCRIPTOR pResDesc = NULL,
  703. pNewResDesc = NULL;
  704. ULONG i = 0, j = 0,
  705. removeCount,
  706. reqCount,
  707. size;
  708. BOOLEAN foundInt = FALSE,
  709. foundPorts = FALSE;
  710. PIO_STACK_LOCATION stack;
  711. PAGED_CODE();
  712. ASSERT(DeviceObject);
  713. ASSERT(DeviceObject->DeviceExtension);
  714. Print(DBG_PNP_NOISE,
  715. ("Received IRP_MN_FILTER_RESOURCE_REQUIREMENTS for %s\n",
  716. (GET_COMMON_DATA(DeviceObject->DeviceExtension))->IsKeyboard ? "kb" : "mouse"
  717. ));
  718. stack = IoGetCurrentIrpStackLocation(Irp);
  719. //
  720. // The list can be in either the information field, or in the current
  721. // stack location. The Information field has a higher precedence over
  722. // the stack location.
  723. //
  724. if (Irp->IoStatus.Information == 0) {
  725. pReqList =
  726. stack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  727. Irp->IoStatus.Information = (ULONG_PTR) pReqList;
  728. }
  729. else {
  730. pReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information;
  731. }
  732. if (!pReqList) {
  733. //
  734. // Not much can be done here except return
  735. //
  736. Print(DBG_PNP_MASK & ~ DBG_PNP_TRACE,
  737. ("(%s) NULL resource list in I8xFilterResourceRequirements\n",
  738. (GET_COMMON_DATA(DeviceObject->DeviceExtension))->IsKeyboard ?
  739. "kb" : "mou"
  740. ));
  741. return STATUS_SUCCESS;
  742. }
  743. ASSERT(Irp->IoStatus.Information != 0);
  744. ASSERT(pReqList != 0);
  745. reqCount = pReqList->AlternativeLists;
  746. //
  747. // Only one AlternativeList is supported. If there is more than one list,
  748. // then there is now way of knowing which list will be chosen. Also, if
  749. // there are multiple lists, then chances are that a list with no i/o port
  750. // conflicts will be chosen.
  751. //
  752. if (reqCount > 1) {
  753. return STATUS_SUCCESS;
  754. }
  755. pResList = pReqList->List;
  756. removeCount = 0;
  757. for (j = 0; j < pResList->Count; j++) {
  758. pResDesc = &pResList->Descriptors[j];
  759. switch (pResDesc->Type) {
  760. case CmResourceTypePort:
  761. Print(DBG_PNP_INFO,
  762. ("option = 0x%x, flags = 0x%x\n",
  763. (LONG) pResDesc->Option,
  764. (LONG) pResDesc->Flags
  765. ));
  766. if (I8xRemovePort(pResDesc)) {
  767. //
  768. // Increment the remove count and tag this resource as
  769. // one that we don't want to copy to the new list
  770. //
  771. removeCount++;
  772. pResDesc->Type = I8X_REMOVE_RESOURCE;
  773. }
  774. foundPorts = TRUE;
  775. break;
  776. case CmResourceTypeInterrupt:
  777. if (Globals.ControllerData->Configuration.SharedInterrupts) {
  778. if (pResDesc->ShareDisposition != CmResourceShareShared) {
  779. Print(DBG_PNP_INFO, ("forcing non shared int to shared\n"));
  780. }
  781. pResDesc->ShareDisposition = CmResourceShareShared;
  782. }
  783. foundInt = TRUE;
  784. break;
  785. default:
  786. break;
  787. }
  788. }
  789. if (removeCount) {
  790. size = pReqList->ListSize;
  791. //
  792. // One element of the array is already allocated (via the struct
  793. // definition) so make sure that we are allocating at least that
  794. // much memory.
  795. //
  796. ASSERT(pResList->Count >= removeCount);
  797. if (pResList->Count > 1) {
  798. size -= removeCount * sizeof(IO_RESOURCE_DESCRIPTOR);
  799. }
  800. pNewReqList =
  801. (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
  802. if (!pNewReqList) {
  803. //
  804. // This is not good, but the system doesn't really need to know about
  805. // this, so just fix up our munging and return the original list
  806. //
  807. pReqList = stack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  808. reqCount = pReqList->AlternativeLists;
  809. removeCount = 0;
  810. for (i = 0; i < reqCount; i++) {
  811. pResList = &pReqList->List[i];
  812. for (j = 0; j < pResList->Count; j++) {
  813. pResDesc = &pResList->Descriptors[j];
  814. if (pResDesc->Type == I8X_REMOVE_RESOURCE) {
  815. pResDesc->Type = CmResourceTypePort;
  816. }
  817. }
  818. }
  819. return STATUS_SUCCESS;
  820. }
  821. //
  822. // Clear out the newly allocated list
  823. //
  824. RtlZeroMemory(pNewReqList,
  825. size
  826. );
  827. //
  828. // Copy the list header information except for the IO resource list
  829. // itself
  830. //
  831. RtlCopyMemory(pNewReqList,
  832. pReqList,
  833. sizeof(IO_RESOURCE_REQUIREMENTS_LIST) -
  834. sizeof(IO_RESOURCE_LIST)
  835. );
  836. pNewReqList->ListSize = size;
  837. pResList = pReqList->List;
  838. pNewResList = pNewReqList->List;
  839. //
  840. // Copy the list header information except for the IO resource
  841. // descriptor list itself
  842. //
  843. RtlCopyMemory(pNewResList,
  844. pResList,
  845. sizeof(IO_RESOURCE_LIST) -
  846. sizeof(IO_RESOURCE_DESCRIPTOR)
  847. );
  848. pNewResList->Count = 0;
  849. pNewResDesc = pNewResList->Descriptors;
  850. for (j = 0; j < pResList->Count; j++) {
  851. pResDesc = &pResList->Descriptors[j];
  852. if (pResDesc->Type != I8X_REMOVE_RESOURCE) {
  853. //
  854. // Keep this resource, so copy it into the new list and
  855. // incement the count and the location for the next
  856. // IO resource descriptor
  857. //
  858. *pNewResDesc = *pResDesc;
  859. pNewResDesc++;
  860. pNewResList->Count++;
  861. Print(DBG_PNP_INFO,
  862. ("List #%d, Descriptor #%d ... keeping res type %d\n",
  863. i, j,
  864. (ULONG) pResDesc->Type
  865. ));
  866. }
  867. else {
  868. //
  869. // Decrement the remove count so we can assert it is
  870. // zero once we are done
  871. //
  872. Print(DBG_PNP_INFO,
  873. ("Removing port [0x%08x %08x] - [0x%#08x %08x]\n",
  874. pResDesc->u.Port.MinimumAddress.HighPart,
  875. pResDesc->u.Port.MinimumAddress.LowPart,
  876. pResDesc->u.Port.MaximumAddress.HighPart,
  877. pResDesc->u.Port.MaximumAddress.LowPart
  878. ));
  879. removeCount--;
  880. }
  881. }
  882. ASSERT(removeCount == 0);
  883. //
  884. // There have been bugs where the old list was being used. Zero it out to
  885. // make sure that no conflicts arise. (Not to mention the fact that some
  886. // other code is accessing freed memory
  887. //
  888. RtlZeroMemory(pReqList,
  889. pReqList->ListSize
  890. );
  891. //
  892. // Free the old list and place the new one in its place
  893. //
  894. ExFreePool(pReqList);
  895. stack->Parameters.FilterResourceRequirements.IoResourceRequirementList =
  896. pNewReqList;
  897. Irp->IoStatus.Information = (ULONG_PTR) pNewReqList;
  898. }
  899. else if (!KEYBOARD_PRESENT() && !foundPorts && foundInt) {
  900. INTERFACE_TYPE interfaceType;
  901. NTSTATUS status;
  902. ULONG prevCount;
  903. CONFIGURATION_TYPE controllerType = KeyboardController;
  904. CONFIGURATION_TYPE peripheralType = KeyboardPeripheral;
  905. ASSERT( MOUSE_PRESENT() );
  906. Print(DBG_PNP_INFO, ("Adding ports to res list!\n"));
  907. //
  908. // We will now yank the resources from the keyboard to start the mouse
  909. // solo
  910. //
  911. size = pReqList->ListSize + 2 * sizeof(IO_RESOURCE_DESCRIPTOR);
  912. pNewReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)
  913. ExAllocatePool(
  914. PagedPool,
  915. size
  916. );
  917. if (!pNewReqList) {
  918. return STATUS_SUCCESS;
  919. }
  920. //
  921. // Clear out the newly allocated list
  922. //
  923. RtlZeroMemory(pNewReqList,
  924. size
  925. );
  926. //
  927. // Copy the entire old list
  928. //
  929. RtlCopyMemory(pNewReqList,
  930. pReqList,
  931. pReqList->ListSize
  932. );
  933. pResList = pReqList->List;
  934. pNewResList = pNewReqList->List;
  935. prevCount = pNewResList->Count;
  936. for (i = 0; i < MaximumInterfaceType; i++) {
  937. //
  938. // Get the registry information for this device.
  939. //
  940. interfaceType = i;
  941. status = IoQueryDeviceDescription(
  942. &interfaceType,
  943. NULL,
  944. &controllerType,
  945. NULL,
  946. &peripheralType,
  947. NULL,
  948. I8xFindPortCallout,
  949. (PVOID) pNewResList
  950. );
  951. if (NT_SUCCESS(status) || prevCount != pNewResList->Count) {
  952. break;
  953. }
  954. }
  955. if (NT_SUCCESS(status) || prevCount != pNewResList->Count) {
  956. pNewReqList->ListSize = size - (2 - (pNewResList->Count - prevCount));
  957. //
  958. // Free the old list and place the new one in its place
  959. //
  960. ExFreePool(pReqList);
  961. stack->Parameters.FilterResourceRequirements.IoResourceRequirementList =
  962. pNewReqList;
  963. Irp->IoStatus.Information = (ULONG_PTR) pNewReqList;
  964. }
  965. else {
  966. ExFreePool(pNewReqList);
  967. }
  968. }
  969. return STATUS_SUCCESS;
  970. }
  971. NTSTATUS
  972. I8xRegisterDeviceInterface(
  973. PDEVICE_OBJECT PDO,
  974. CONST GUID * Guid,
  975. PUNICODE_STRING SymbolicName
  976. )
  977. {
  978. NTSTATUS status;
  979. PAGED_CODE();
  980. status = IoRegisterDeviceInterface(
  981. PDO,
  982. Guid,
  983. NULL,
  984. SymbolicName
  985. );
  986. if (NT_SUCCESS(status)) {
  987. status = IoSetDeviceInterfaceState(SymbolicName,
  988. TRUE
  989. );
  990. }
  991. return status;
  992. }
  993. void
  994. I8xSetPowerFlag(
  995. IN ULONG Flag,
  996. IN BOOLEAN Set
  997. )
  998. {
  999. KIRQL irql;
  1000. KeAcquireSpinLock(&Globals.ControllerData->PowerSpinLock, &irql);
  1001. if (Set) {
  1002. Globals.PowerFlags |= Flag;
  1003. }
  1004. else {
  1005. Globals.PowerFlags &= ~Flag;
  1006. }
  1007. KeReleaseSpinLock(&Globals.ControllerData->PowerSpinLock, irql);
  1008. }
  1009. BOOLEAN
  1010. I8xCheckPowerFlag(
  1011. ULONG Flag
  1012. )
  1013. {
  1014. KIRQL irql;
  1015. BOOLEAN rVal = FALSE;
  1016. KeAcquireSpinLock(&Globals.ControllerData->PowerSpinLock, &irql);
  1017. if (Globals.PowerFlags & Flag) {
  1018. rVal = TRUE;
  1019. }
  1020. KeReleaseSpinLock(&Globals.ControllerData->PowerSpinLock, irql);
  1021. return rVal;
  1022. }
  1023. NTSTATUS
  1024. I8xPower (
  1025. IN PDEVICE_OBJECT DeviceObject,
  1026. IN PIRP Irp
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. This is the dispatch routine for power requests.
  1031. Arguments:
  1032. DeviceObject - Pointer to the device object.
  1033. Irp - Pointer to the request packet.
  1034. Return Value:
  1035. STATUS_SUCCESSFUL if successful,
  1036. an valid NTSTATUS error code otherwise
  1037. --*/
  1038. {
  1039. PCOMMON_DATA commonData;
  1040. PIO_STACK_LOCATION stack;
  1041. NTSTATUS status = STATUS_SUCCESS;
  1042. PAGED_CODE();
  1043. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  1044. stack = IoGetCurrentIrpStackLocation(Irp);
  1045. Print(DBG_POWER_TRACE,
  1046. ("Power (%s), enter\n",
  1047. commonData->IsKeyboard ? "keyboard" :
  1048. "mouse"
  1049. ));
  1050. //
  1051. // A power irp can be sent to the device before we have been started or
  1052. // initialized. Since the code below relies on StartDevice() to have
  1053. // executed, just fire and forget the irp
  1054. //
  1055. if (!commonData->Started || !commonData->Initialized) {
  1056. PoStartNextPowerIrp(Irp);
  1057. Irp->IoStatus.Status = STATUS_SUCCESS;
  1058. IoSkipCurrentIrpStackLocation(Irp);
  1059. return PoCallDriver(commonData->TopOfStack, Irp);
  1060. }
  1061. switch(stack->MinorFunction) {
  1062. case IRP_MN_WAIT_WAKE:
  1063. Print(DBG_POWER_NOISE, ("Got IRP_MN_WAIT_WAKE\n" ));
  1064. //
  1065. // Fail all wait wake requests on level triggered interrupts for mice
  1066. // because when an errant mouse movement occurs while we are going to
  1067. // sleep, it will keep the interrupt triggered indefinitely.
  1068. //
  1069. // We should not even get into this situation because the caps of the
  1070. // mouse should have been altered to not report wait wake
  1071. //
  1072. if (IS_MOUSE(commonData) && IS_LEVEL_TRIGGERED(commonData)) {
  1073. PoStartNextPowerIrp(Irp);
  1074. status = Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  1075. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1076. Print(DBG_POWER_INFO | DBG_POWER_ERROR,
  1077. ("failing a wait wake request on a level triggered mouse\n"));
  1078. return status;
  1079. }
  1080. break;
  1081. case IRP_MN_POWER_SEQUENCE:
  1082. Print(DBG_POWER_NOISE, ("Got IRP_MN_POWER_SEQUENCE\n" ));
  1083. break;
  1084. case IRP_MN_SET_POWER:
  1085. Print(DBG_POWER_NOISE, ("Got IRP_MN_SET_POWER\n" ));
  1086. //
  1087. // Don't handle anything but DevicePowerState changes
  1088. //
  1089. if (stack->Parameters.Power.Type != DevicePowerState) {
  1090. commonData->SystemState = stack->Parameters.Power.State.SystemState;
  1091. Print(DBG_POWER_INFO, ("system power irp, S%d\n", commonData->SystemState-1));
  1092. break;
  1093. }
  1094. //
  1095. // Check for no change in state, and if none, do nothing. This state
  1096. // can occur when the device is armed for wake. We will get a D0 in
  1097. // response to the WW irp completing and then another D0 corresponding
  1098. // to the S0 irp sent to the stack.
  1099. //
  1100. if (stack->Parameters.Power.State.DeviceState ==
  1101. commonData->PowerState) {
  1102. Print(DBG_POWER_INFO,
  1103. ("no change in state (PowerDeviceD%d)\n",
  1104. commonData->PowerState-1
  1105. ));
  1106. break;
  1107. }
  1108. switch (stack->Parameters.Power.State.DeviceState) {
  1109. case PowerDeviceD0:
  1110. Print(DBG_POWER_INFO, ("Powering up to PowerDeviceD0\n"));
  1111. IoAcquireRemoveLock(&commonData->RemoveLock, Irp);
  1112. if (IS_KEYBOARD(commonData)) {
  1113. I8xSetPowerFlag(KBD_POWERED_UP_STARTED, TRUE);
  1114. }
  1115. else {
  1116. I8xSetPowerFlag(MOU_POWERED_UP_STARTED, TRUE);
  1117. }
  1118. //
  1119. // PoSetPowerState will be called in I8xReinitalizeHardware for each
  1120. // device once all the devices have powered back up
  1121. //
  1122. IoCopyCurrentIrpStackLocationToNext(Irp);
  1123. IoSetCompletionRoutine(Irp,
  1124. I8xPowerUpToD0Complete,
  1125. NULL,
  1126. TRUE, // on success
  1127. TRUE, // on error
  1128. TRUE // on cancel
  1129. );
  1130. //
  1131. // PoStartNextPowerIrp() gets called when the irp gets completed
  1132. // in either the completion routine or the resulting work item
  1133. //
  1134. // It is OK to call PoCallDriver and return pending b/c we are
  1135. // pending the irp in the completion routine and we may change
  1136. // the completion status if we can't alloc pool. If we return the
  1137. // value from PoCallDriver, we are tied to that status value on the
  1138. // way back up.
  1139. //
  1140. IoMarkIrpPending(Irp);
  1141. PoCallDriver(commonData->TopOfStack, Irp);
  1142. return STATUS_PENDING;
  1143. case PowerDeviceD1:
  1144. case PowerDeviceD2:
  1145. case PowerDeviceD3:
  1146. Print(DBG_POWER_INFO,
  1147. ("Powering down to PowerDeviceD%d\n",
  1148. stack->Parameters.Power.State.DeviceState-1
  1149. ));
  1150. //
  1151. // If WORK_ITEM_QUEUED is set, that means that a work item is
  1152. // either queued to be run, or running now so we don't want to yank
  1153. // any devices underneath from the work item
  1154. //
  1155. if (I8xCheckPowerFlag(WORK_ITEM_QUEUED)) {
  1156. Print(DBG_POWER_INFO | DBG_POWER_ERROR,
  1157. ("denying power down request because work item is running\n"
  1158. ));
  1159. PoStartNextPowerIrp(Irp);
  1160. status = Irp->IoStatus.Status = STATUS_POWER_STATE_INVALID;
  1161. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1162. return status;
  1163. }
  1164. if (IS_KEYBOARD(commonData)) {
  1165. I8xSetPowerFlag(KBD_POWERED_DOWN, TRUE);
  1166. }
  1167. else {
  1168. I8xSetPowerFlag(MOU_POWERED_DOWN, TRUE);
  1169. }
  1170. PoSetPowerState(DeviceObject,
  1171. stack->Parameters.Power.Type,
  1172. stack->Parameters.Power.State
  1173. );
  1174. //
  1175. // Disconnect level triggered interupts on mice when we go into
  1176. // low power so errant mouse movement doesn't leave the interrupt
  1177. // signalled for long periods of time
  1178. //
  1179. if (IS_MOUSE(commonData) && IS_LEVEL_TRIGGERED(commonData)) {
  1180. PKINTERRUPT interrupt = commonData->InterruptObject;
  1181. Print(DBG_POWER_NOISE,
  1182. ("disconnecting interrupt on level triggered mouse\n")
  1183. );
  1184. commonData->InterruptObject = NULL;
  1185. if (interrupt) {
  1186. IoDisconnectInterrupt(interrupt);
  1187. }
  1188. }
  1189. commonData->PowerState = stack->Parameters.Power.State.DeviceState;
  1190. commonData->ShutdownType = stack->Parameters.Power.ShutdownType;
  1191. //
  1192. // For what we are doing, we don't need a completion routine
  1193. // since we don't race on the power requests.
  1194. //
  1195. Irp->IoStatus.Status = STATUS_SUCCESS;
  1196. PoStartNextPowerIrp(Irp);
  1197. IoSkipCurrentIrpStackLocation(Irp);
  1198. return PoCallDriver(commonData->TopOfStack, Irp);
  1199. default:
  1200. Print(DBG_POWER_INFO, ("unknown state\n"));
  1201. break;
  1202. }
  1203. break;
  1204. case IRP_MN_QUERY_POWER:
  1205. Print(DBG_POWER_NOISE, ("Got IRP_MN_QUERY_POWER\n" ));
  1206. break;
  1207. default:
  1208. Print(DBG_POWER_NOISE,
  1209. ("Got unhandled minor function (%d)\n",
  1210. stack->MinorFunction
  1211. ));
  1212. break;
  1213. }
  1214. Print(DBG_POWER_TRACE, ("Power, exit\n"));
  1215. PoStartNextPowerIrp(Irp);
  1216. IoSkipCurrentIrpStackLocation(Irp);
  1217. return PoCallDriver(commonData->TopOfStack, Irp);
  1218. }
  1219. NTSTATUS
  1220. I8xPowerUpToD0Complete(
  1221. IN PDEVICE_OBJECT DeviceObject,
  1222. IN PIRP Irp,
  1223. IN PVOID Context
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. Reinitializes the i8042 haardware after any type of hibernation/sleep.
  1228. Arguments:
  1229. DeviceObject - Pointer to the device object
  1230. Irp - Pointer to the request
  1231. Context - Context passed in from the funciton that set the completion
  1232. routine. UNUSED.
  1233. Return Value:
  1234. STATUS_SUCCESSFUL if successful,
  1235. an valid NTSTATUS error code otherwise
  1236. --*/
  1237. {
  1238. NTSTATUS status = STATUS_SUCCESS;
  1239. PCOMMON_DATA commonData;
  1240. PPOWER_UP_WORK_ITEM item;
  1241. KIRQL irql;
  1242. UCHAR poweredDownDevices = 0,
  1243. poweredUpDevices = 0,
  1244. failedDevices = 0;
  1245. BOOLEAN queueItem = FALSE,
  1246. clearFlags = FALSE,
  1247. failMouIrp = FALSE;
  1248. PIRP mouIrp = NULL,
  1249. kbdIrp = NULL;
  1250. UNREFERENCED_PARAMETER(Context);
  1251. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  1252. Print(DBG_POWER_TRACE,
  1253. ("PowerUpToD0Complete (%s), Enter\n",
  1254. commonData->IsKeyboard ? "kb" : "mouse"
  1255. ));
  1256. //
  1257. // We can use a regular work item because we have a non completed power irp
  1258. // which has an outstanding reference to this stack.
  1259. //
  1260. item = (PPOWER_UP_WORK_ITEM) ExAllocatePool(NonPagedPool,
  1261. sizeof(POWER_UP_WORK_ITEM));
  1262. KeAcquireSpinLock(&Globals.ControllerData->PowerSpinLock, &irql);
  1263. Print(DBG_POWER_TRACE,
  1264. ("Power up to D0 completion enter, power flags 0x%x\n",
  1265. Globals.PowerFlags));
  1266. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  1267. commonData->OutstandingPowerIrp = Irp;
  1268. status = STATUS_MORE_PROCESSING_REQUIRED;
  1269. if (IS_KEYBOARD(commonData)) {
  1270. KEYBOARD_POWERED_UP_SUCCESSFULLY();
  1271. }
  1272. else {
  1273. MOUSE_POWERED_UP_SUCCESSFULLY();
  1274. }
  1275. }
  1276. else {
  1277. if (IS_KEYBOARD(commonData)) {
  1278. KEYBOARD_POWERED_UP_FAILURE();
  1279. }
  1280. else {
  1281. MOUSE_POWERED_UP_FAILURE();
  1282. }
  1283. }
  1284. if (KEYBOARD_POWERED_DOWN_SUCCESS()) {
  1285. Print(DBG_POWER_NOISE, ("--kbd powered down successfully\n"));
  1286. poweredDownDevices++;
  1287. }
  1288. if (MOUSE_POWERED_DOWN_SUCCESS()) {
  1289. Print(DBG_POWER_NOISE, ("--mou powered down successfully\n"));
  1290. poweredDownDevices++;
  1291. }
  1292. if (KEYBOARD_POWERED_UP_SUCCESS()) {
  1293. Print(DBG_POWER_NOISE, ("++kbd powered up successfully\n"));
  1294. poweredUpDevices++;
  1295. }
  1296. if (MOUSE_POWERED_UP_SUCCESS()) {
  1297. Print(DBG_POWER_NOISE, ("++mou powered up successfully\n"));
  1298. poweredUpDevices++;
  1299. }
  1300. if (KEYBOARD_POWERED_UP_FAILED()) {
  1301. Print(DBG_POWER_NOISE|DBG_POWER_ERROR, (">>kbd powered down failed\n"));
  1302. failedDevices++;
  1303. }
  1304. if (MOUSE_POWERED_UP_FAILED()) {
  1305. Print(DBG_POWER_NOISE|DBG_POWER_ERROR, (">>mou powered down failed\n"));
  1306. failedDevices++;
  1307. }
  1308. Print(DBG_POWER_INFO,
  1309. ("up %d, down %d, failed %d, flags 0x%x\n",
  1310. (ULONG) poweredUpDevices,
  1311. (ULONG) poweredDownDevices,
  1312. (ULONG) failedDevices,
  1313. Globals.PowerFlags));
  1314. if ((poweredUpDevices + failedDevices) == poweredDownDevices) {
  1315. if (poweredUpDevices > 0) {
  1316. //
  1317. // The ports are associated with the keyboard. If it has failed to
  1318. // power up while the mouse succeeded, we still need to fail the
  1319. // mouse b/c there is no hardware to talk to
  1320. //
  1321. if (failedDevices > 0 && KEYBOARD_POWERED_UP_FAILED()) {
  1322. ASSERT(MOUSE_POWERED_UP_SUCCESS());
  1323. ASSERT(Globals.KeyboardExtension->OutstandingPowerIrp == NULL);
  1324. mouIrp = Globals.MouseExtension->OutstandingPowerIrp;
  1325. Globals.MouseExtension->OutstandingPowerIrp = NULL;
  1326. Globals.PowerFlags &= ~MOU_POWER_FLAGS;
  1327. clearFlags = TRUE;
  1328. if (mouIrp != Irp) {
  1329. //
  1330. // we have queued the irp, complete it later in this
  1331. // function under a special case
  1332. //
  1333. failMouIrp = TRUE;
  1334. }
  1335. else {
  1336. //
  1337. // The mouse irp is the current irp. We have already
  1338. // completed the kbd irp in our previous processing. Set
  1339. // the irp status to some unsuccessful value so that we will
  1340. // call PoStartNextPowerIrp later in this function. Also
  1341. // set status to != STATUS_MORE_PROCESSING_REQUIRED so the
  1342. // irp will be completed when the function exits.
  1343. //
  1344. status = mouIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1345. }
  1346. }
  1347. else {
  1348. Print(DBG_POWER_INFO, ("at least one device powered up!\n"));
  1349. queueItem = TRUE;
  1350. }
  1351. }
  1352. else {
  1353. Print(DBG_POWER_INFO,
  1354. ("all devices failed power up, 0x%x\n",
  1355. Globals.PowerFlags));
  1356. clearFlags = TRUE;
  1357. }
  1358. }
  1359. else {
  1360. //
  1361. // the other device is still powered down, wait for it to power back
  1362. // up before processing power states
  1363. //
  1364. Print(DBG_POWER_INFO,
  1365. ("queueing, waiting for 2nd dev obj to power cycle\n"));
  1366. }
  1367. if (queueItem || clearFlags) {
  1368. //
  1369. // Extract the irp from each successfully started device and clear the
  1370. // associated power flags for the device
  1371. //
  1372. if (MOUSE_POWERED_UP_SUCCESS()) {
  1373. mouIrp = Globals.MouseExtension->OutstandingPowerIrp;
  1374. Globals.MouseExtension->OutstandingPowerIrp = NULL;
  1375. ASSERT(!TEST_PWR_FLAGS(MOU_POWERED_UP_FAILURE));
  1376. Globals.PowerFlags &= ~MOU_POWER_FLAGS;
  1377. }
  1378. else {
  1379. Globals.PowerFlags &= ~(MOU_POWERED_UP_FAILURE);
  1380. }
  1381. if (KEYBOARD_POWERED_UP_SUCCESS()) {
  1382. kbdIrp = Globals.KeyboardExtension->OutstandingPowerIrp;
  1383. Globals.KeyboardExtension->OutstandingPowerIrp = NULL;
  1384. ASSERT(!TEST_PWR_FLAGS(KBD_POWERED_UP_FAILURE));
  1385. Globals.PowerFlags &= ~(KBD_POWER_FLAGS);
  1386. }
  1387. else {
  1388. Globals.PowerFlags &= ~(KBD_POWERED_UP_FAILURE);
  1389. }
  1390. //
  1391. // Mark that the work item is queued. This is used to make sure that 2
  1392. // work items are not queued concucrrently
  1393. //
  1394. if (item && queueItem) {
  1395. Print(DBG_POWER_INFO, ("setting work item queued flag\n"));
  1396. Globals.PowerFlags |= WORK_ITEM_QUEUED;
  1397. }
  1398. }
  1399. KeReleaseSpinLock(&Globals.ControllerData->PowerSpinLock, irql);
  1400. if (queueItem) {
  1401. if (item == NULL) {
  1402. //
  1403. // complete any queued power irps
  1404. //
  1405. Print(DBG_POWER_INFO | DBG_POWER_ERROR,
  1406. ("failed to alloc work item\n"));
  1407. //
  1408. // what about PoSetPowerState?
  1409. //
  1410. if (mouIrp != NULL) {
  1411. Print(DBG_POWER_ERROR | DBG_POWER_INFO,
  1412. ("completing mouse power irp 0x%x", mouIrp));
  1413. mouIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1414. mouIrp->IoStatus.Information = 0x0;
  1415. PoStartNextPowerIrp(mouIrp);
  1416. IoCompleteRequest(mouIrp, IO_NO_INCREMENT);
  1417. IoReleaseRemoveLock(&Globals.MouseExtension->RemoveLock,
  1418. mouIrp);
  1419. mouIrp = NULL;
  1420. }
  1421. if (kbdIrp != NULL) {
  1422. Print(DBG_POWER_ERROR | DBG_POWER_INFO,
  1423. ("completing kbd power irp 0x%x", kbdIrp));
  1424. kbdIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1425. kbdIrp->IoStatus.Information = 0x0;
  1426. PoStartNextPowerIrp(kbdIrp);
  1427. IoCompleteRequest(kbdIrp, IO_NO_INCREMENT);
  1428. IoReleaseRemoveLock(&Globals.KeyboardExtension->RemoveLock,
  1429. kbdIrp);
  1430. kbdIrp = NULL;
  1431. }
  1432. //
  1433. // The passed in Irp has just been completed; by returning more
  1434. // processing required, it will not be double completed
  1435. //
  1436. return STATUS_MORE_PROCESSING_REQUIRED;
  1437. }
  1438. else {
  1439. RtlZeroMemory(item, sizeof(*item));
  1440. if (MOUSE_STARTED()) {
  1441. SET_RECORD_STATE(Globals.MouseExtension,
  1442. RECORD_RESUME_FROM_POWER);
  1443. }
  1444. Print(DBG_POWER_INFO, ("queueing work item for init\n"));
  1445. item->KeyboardPowerIrp = kbdIrp;
  1446. item->MousePowerIrp = mouIrp;
  1447. ExInitializeWorkItem(&item->Item, I8xReinitializeHardware, item);
  1448. ExQueueWorkItem(&item->Item, DelayedWorkQueue);
  1449. }
  1450. }
  1451. else if (item != NULL) {
  1452. Print(DBG_POWER_NOISE,("freeing unused item %p\n", item));
  1453. ExFreePool(item);
  1454. item = NULL;
  1455. }
  1456. if (failMouIrp) {
  1457. Print(DBG_POWER_INFO | DBG_POWER_ERROR,
  1458. ("failing successful mouse irp %p because kbd failed power up\n",
  1459. mouIrp));
  1460. PoStartNextPowerIrp(mouIrp);
  1461. IoCompleteRequest(mouIrp, IO_NO_INCREMENT);
  1462. IoReleaseRemoveLock(&Globals.MouseExtension->RemoveLock, mouIrp);
  1463. mouIrp = NULL;
  1464. }
  1465. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  1466. Print(DBG_POWER_INFO | DBG_POWER_ERROR,
  1467. ("irp %p failed, starting next\n", Irp));
  1468. PoStartNextPowerIrp(Irp);
  1469. Irp = NULL;
  1470. ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED);
  1471. }
  1472. return status;
  1473. }