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

371 lines
10 KiB

  1. /*++
  2. Copyright (c) 1990-1999 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. ptdrvkbd.c
  5. Abstract:
  6. Keyboard specific parts of the RDP remote port driver.
  7. Environment:
  8. Kernel mode only.
  9. Revision History:
  10. 02/12/99 - Initial Revision based on pnpi8042 driver
  11. --*/
  12. #include <precomp.h>
  13. #pragma hdrstop
  14. #include "ptdrvcom.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, PtKeyboardConfiguration)
  17. #pragma alloc_text(PAGE, PtKeyboardStartDevice)
  18. #pragma alloc_text(PAGE, PtKeyboardRemoveDevice)
  19. #endif
  20. VOID
  21. PtSendCurrentKeyboardInput(
  22. IN PDEVICE_OBJECT DeviceObject,
  23. IN PKEYBOARD_INPUT_DATA pInput,
  24. IN ULONG ulEntries
  25. )
  26. /*++
  27. Routine Description:
  28. This routine calls the keyboard class driver until all the data has been
  29. queued.
  30. Arguments:
  31. DeviceObject - Pointer to the device object
  32. Return Value:
  33. None
  34. --*/
  35. {
  36. PPORT_KEYBOARD_EXTENSION deviceExtension;
  37. LARGE_INTEGER SleepTime;
  38. NTSTATUS Status;
  39. PUCHAR pEnd;
  40. Print(DBG_DPC_NOISE, ("PtSendCurrentKeyboardInput: enter\n"));
  41. if (DeviceObject != NULL) {
  42. deviceExtension = DeviceObject->DeviceExtension;
  43. if (deviceExtension->EnableCount) {
  44. PVOID classService;
  45. PVOID classDeviceObject;
  46. ULONG dataNotConsumed = 0;
  47. ULONG inputDataConsumed = 0;
  48. //
  49. // Call the connected class driver's callback ISR
  50. //
  51. classDeviceObject = deviceExtension->ConnectData.ClassDeviceObject;
  52. classService = deviceExtension->ConnectData.ClassService;
  53. ASSERT(classService != NULL);
  54. Print(DBG_DPC_NOISE,
  55. ("PtSendCurrentKeyboardInput: calling class callback (%p, %ld)\n",
  56. pInput, ulEntries));
  57. dataNotConsumed = ulEntries;
  58. pEnd = (PUCHAR)pInput + (ulEntries * sizeof(KEYBOARD_INPUT_DATA));
  59. while (dataNotConsumed)
  60. {
  61. KIRQL oldIrql;
  62. inputDataConsumed = 0;
  63. //
  64. // Class Service Callback routines need to be execusted at
  65. // DISPATCH_LEVEL, so raise IRQL before calling the callback.
  66. //
  67. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql);
  68. (*(PSERVICE_CALLBACK_ROUTINE) classService)(
  69. classDeviceObject,
  70. pInput,
  71. pEnd,
  72. &inputDataConsumed);
  73. //
  74. // reset the IRQL.
  75. //
  76. KeLowerIrql( oldIrql );
  77. dataNotConsumed = ((ULONG)(pEnd - (PUCHAR)pInput)
  78. /sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
  79. Print(DBG_DPC_INFO,
  80. ("PtSendCurrentKeyboardInput: Call callback consumed %d items, left %d\n",
  81. inputDataConsumed,
  82. dataNotConsumed));
  83. if (dataNotConsumed)
  84. {
  85. //
  86. // update the input pointer
  87. //
  88. pInput = (PKEYBOARD_INPUT_DATA)((PUCHAR)pInput +
  89. inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
  90. //
  91. // sleep for 1 ms
  92. //
  93. SleepTime = RtlEnlargedIntegerMultiply( 1, -10000 );
  94. Status = KeDelayExecutionThread( KernelMode, TRUE, &SleepTime );
  95. }
  96. }
  97. }
  98. } else {
  99. Print(DBG_DPC_ERROR, ("PtSendCurrentKeyboardInput called with NULL Keyboard Device Object\n"));
  100. }
  101. Print(DBG_DPC_NOISE, ("PtSendCurrentKeyboardInput: exit\n"));
  102. }
  103. NTSTATUS
  104. PtKeyboardConfiguration(
  105. IN PPORT_KEYBOARD_EXTENSION KeyboardExtension,
  106. IN PCM_RESOURCE_LIST ResourceList
  107. )
  108. /*++
  109. Routine Description:
  110. This routine retrieves the configuration information for the keyboard.
  111. Arguments:
  112. KeyboardExtension - Keyboard extension
  113. ResourceList - Translated resource list give to us via the start IRP
  114. Return Value:
  115. STATUS_SUCCESS if all the resources required are presented
  116. --*/
  117. {
  118. NTSTATUS status = STATUS_SUCCESS;
  119. PCM_PARTIAL_RESOURCE_LIST partialResList = NULL;
  120. PCM_PARTIAL_RESOURCE_DESCRIPTOR firstResDesc = NULL,
  121. currentResDesc = NULL;
  122. PCM_FULL_RESOURCE_DESCRIPTOR fullResDesc = NULL;
  123. PI8042_CONFIGURATION_INFORMATION configuration;
  124. PKEYBOARD_ID keyboardId;
  125. ULONG count,
  126. i;
  127. PAGED_CODE();
  128. if (ResourceList) {
  129. fullResDesc = ResourceList->List;
  130. if (!fullResDesc) {
  131. //
  132. // this should never happen
  133. //
  134. ASSERT(fullResDesc != NULL);
  135. return STATUS_INSUFFICIENT_RESOURCES;
  136. }
  137. configuration = &Globals.ControllerData->Configuration;
  138. partialResList = &fullResDesc->PartialResourceList;
  139. currentResDesc = firstResDesc = partialResList->PartialDescriptors;
  140. count = partialResList->Count;
  141. for (i = 0; i < count; i++, currentResDesc++) {
  142. switch (currentResDesc->Type) {
  143. case CmResourceTypePort:
  144. //
  145. // Copy the port information. We will sort the port list
  146. // into ascending order based on the starting port address
  147. // later (note that we *know* there are a max of two port
  148. // ranges for the i8042).
  149. //
  150. Print(DBG_SS_NOISE,
  151. ("port is %s\n",
  152. currentResDesc->Flags == CM_RESOURCE_PORT_MEMORY ?
  153. "memory" :
  154. "an io port"
  155. ));
  156. if (configuration->PortListCount < MaximumPortCount) {
  157. configuration->PortList[configuration->PortListCount] =
  158. *currentResDesc;
  159. configuration->PortListCount += 1;
  160. }
  161. else {
  162. Print(DBG_SS_INFO | DBG_SS_ERROR,
  163. ("KB::PortListCount already at max (%d)\n",
  164. configuration->PortListCount
  165. )
  166. );
  167. }
  168. break;
  169. default:
  170. Print(DBG_ALWAYS,
  171. ("resource type 0x%x unhandled...\n",
  172. (LONG) currentResDesc->Type
  173. ));
  174. break;
  175. }
  176. }
  177. }
  178. else
  179. Print(DBG_SS_INFO | DBG_SS_TRACE, ("keyboard with null resources\n"));
  180. return status;
  181. }
  182. NTSTATUS
  183. PtKeyboardStartDevice(
  184. IN OUT PPORT_KEYBOARD_EXTENSION KeyboardExtension,
  185. IN PCM_RESOURCE_LIST ResourceList
  186. )
  187. /*++
  188. Routine Description:
  189. Configures the keyboard's device extension (ie allocation of pool,
  190. initialization of DPCs, etc). If the keyboard is the last device to start,
  191. it will also initialize the hardware and connect all the interrupts.
  192. Arguments:
  193. KeyboardExtension - Keyboard extesnion
  194. ResourceList - Translated resource list for this device
  195. Return Value:
  196. STATUS_SUCCESSFUL if successful,
  197. --*/
  198. {
  199. ULONG dumpData[1];
  200. NTSTATUS status = STATUS_SUCCESS;
  201. PAGED_CODE();
  202. Print(DBG_SS_TRACE, ("PtKeyboardStartDevice, enter\n"));
  203. //
  204. // Check to see if kb has been started. If so, fail this start
  205. //
  206. if (KEYBOARD_INITIALIZED()) {
  207. Print(DBG_SS_ERROR, ("too many kbs!\n"));
  208. //
  209. // This is not really necessary because the value won't ever be checked
  210. // in the context of seeing if all the keyboards were bogus, but it is
  211. // done so that Globals.AddedKeyboards == # of actual started keyboards
  212. //
  213. InterlockedDecrement(&Globals.AddedKeyboards);
  214. status = STATUS_NO_SUCH_DEVICE;
  215. goto PtKeyboardStartDeviceExit;
  216. }
  217. else if (KeyboardExtension->ConnectData.ClassService == NULL) {
  218. //
  219. // We are never really going to get here because if we don't have the
  220. // class driver on top of us, extension->IsKeyboard will be false and
  221. // we will think that the device is a mouse, but for completeness
  222. //
  223. // No class driver on top of us == BAD BAD BAD
  224. //
  225. // Fail the start of this device in the hope that there is another stack
  226. // that is correctly formed. Another side affect of having no class
  227. // driver is that the AddedKeyboards count is not incremented for this
  228. // device
  229. //
  230. Print(DBG_SS_ERROR, ("Keyboard started with out a service cb!\n"));
  231. return STATUS_INVALID_DEVICE_STATE;
  232. }
  233. status = PtKeyboardConfiguration(KeyboardExtension,
  234. ResourceList
  235. );
  236. if (!NT_SUCCESS(status)) {
  237. goto PtKeyboardStartDeviceExit;
  238. }
  239. ASSERT( KEYBOARD_PRESENT() );
  240. Globals.KeyboardExtension = KeyboardExtension;
  241. PtInitWmi(GET_COMMON_DATA(KeyboardExtension));
  242. KeyboardExtension->Initialized = TRUE;
  243. PtKeyboardStartDeviceExit:
  244. Print(DBG_SS_INFO,
  245. ("PtKeyboardStartDevice %s\n",
  246. NT_SUCCESS(status) ? "successful" : "unsuccessful"
  247. ));
  248. Print(DBG_SS_TRACE, ("PtKeyboardStartDevice exit (0x%x)\n", status));
  249. return status;
  250. }
  251. VOID
  252. PtKeyboardRemoveDevice(
  253. PDEVICE_OBJECT DeviceObject
  254. )
  255. /*++
  256. Routine Description:
  257. Removes the device. This will only occur if the device removed itself.
  258. Disconnects the interrupt, removes the synchronization flag for the mouse if
  259. present, and frees any memory associated with the device.
  260. Arguments:
  261. DeviceObject - The device object for the keyboard
  262. Return Value:
  263. STATUS_SUCCESSFUL if successful,
  264. --*/
  265. {
  266. PPORT_KEYBOARD_EXTENSION keyboardExtension = DeviceObject->DeviceExtension;
  267. PIRP irp;
  268. Print(DBG_PNP_INFO, ("PtKeyboardRemoveDevice enter\n"));
  269. PAGED_CODE();
  270. if (Globals.KeyboardExtension == keyboardExtension && keyboardExtension) {
  271. Globals.KeyboardExtension = NULL;
  272. }
  273. }