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.

279 lines
7.6 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. MAPUSAGE.C
  5. Abstract:
  6. Code for using registry usage mapping information
  7. (for broken HID keyboards that return incorrect usages)
  8. to fix usages on the fly.
  9. INF example:
  10. ------------
  11. The following line in the device instance's AddReg section
  12. of an inf for a keyboard
  13. will create a key resulting in the usage value
  14. 0x0203 being mapped to 0x0115 :
  15. HKR,UsageMappings,0203,,0115
  16. Environment:
  17. Kernel mode
  18. Revision History:
  19. Nov-98 : created by Ervin Peretz
  20. --*/
  21. #include "kbdhid.h"
  22. #include <hidclass.h>
  23. VOID LoadKeyboardUsageMappingList(PDEVICE_EXTENSION devExt)
  24. {
  25. NTSTATUS status;
  26. HANDLE hRegDriver;
  27. UsageMappingList *mapList = NULL;
  28. KIRQL oldIrql;
  29. /*
  30. * Open the driver registry key
  31. * ( HKLM/System/CurrentControlSet/Control/Class/<GUID>/<#n> )
  32. */
  33. status = IoOpenDeviceRegistryKey( devExt->PDO,
  34. PLUGPLAY_REGKEY_DRIVER,
  35. KEY_READ,
  36. &hRegDriver);
  37. if (NT_SUCCESS(status)){
  38. UNICODE_STRING usageMappingsKeyName;
  39. HANDLE hRegUsageMappings;
  40. /*
  41. * See if the Usage Mappings subkey exists.
  42. */
  43. RtlInitUnicodeString(&usageMappingsKeyName, L"UsageMappings");
  44. status = OpenSubkey( &hRegUsageMappings,
  45. hRegDriver,
  46. &usageMappingsKeyName,
  47. KEY_READ);
  48. if (NT_SUCCESS(status)){
  49. /*
  50. * The registry DOES contain usage mappings
  51. * for this keyboard.
  52. */
  53. UsageMappingList *mapListEntry, *lastMapListEntry = NULL;
  54. ULONG keyIndex = 0;
  55. /*
  56. * The key value information struct is variable-length.
  57. * The actual length is equal to:
  58. * the length of the base PKEY_VALUE_FULL_INFORMATION struct +
  59. * the length of the name of the key (4 wide chars) +
  60. * the length of the value (4 wchars + terminator = 5 wchars).
  61. */
  62. UCHAR keyValueBytes[sizeof(KEY_VALUE_FULL_INFORMATION)+4*sizeof(WCHAR)+5*sizeof(WCHAR)];
  63. PKEY_VALUE_FULL_INFORMATION keyValueInfo = (PKEY_VALUE_FULL_INFORMATION)keyValueBytes;
  64. ULONG actualLen;
  65. do {
  66. status = ZwEnumerateValueKey(
  67. hRegUsageMappings,
  68. keyIndex,
  69. KeyValueFullInformation,
  70. keyValueInfo,
  71. sizeof(keyValueBytes),
  72. &actualLen);
  73. if (NT_SUCCESS(status)){
  74. /*
  75. * Add this usage mapping to the mapping list.
  76. */
  77. USHORT sourceUsage, mappedUsage;
  78. PWCHAR valuePtr;
  79. WCHAR nameBuf[5];
  80. WCHAR valueBuf[5];
  81. ASSERT(keyValueInfo->Type == REG_SZ);
  82. ASSERT(keyValueInfo->DataLength == (4+1)*sizeof(WCHAR));
  83. ASSERT(keyValueInfo->NameLength <= (4+1)*sizeof(WCHAR));
  84. /*
  85. * keyValueInfo->Name is not NULL-terminated.
  86. * So copy it into a buffer and null-terminate.
  87. */
  88. memcpy(nameBuf, keyValueInfo->Name, 4*sizeof(WCHAR));
  89. nameBuf[4] = L'\0';
  90. valuePtr = (PWCHAR)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset);
  91. memcpy(valueBuf, valuePtr, 4*sizeof(WCHAR));
  92. valueBuf[4] = L'\0';
  93. sourceUsage = (USHORT)LAtoX(nameBuf);
  94. mappedUsage = (USHORT)LAtoX(valueBuf);
  95. /*
  96. * Create and queue a new map list entry.
  97. */
  98. mapListEntry = ExAllocatePool(NonPagedPool, sizeof(UsageMappingList));
  99. if (mapListEntry){
  100. mapListEntry->sourceUsage = sourceUsage;
  101. mapListEntry->mappedUsage = mappedUsage;
  102. mapListEntry->next = NULL;
  103. if (lastMapListEntry){
  104. lastMapListEntry->next = mapListEntry;
  105. lastMapListEntry = mapListEntry;
  106. }
  107. else {
  108. mapList = lastMapListEntry = mapListEntry;
  109. }
  110. }
  111. else {
  112. ASSERT(!(PVOID)"mem alloc failed");
  113. break;
  114. }
  115. keyIndex++;
  116. }
  117. } while (NT_SUCCESS(status));
  118. ZwClose(hRegUsageMappings);
  119. }
  120. ZwClose(hRegDriver);
  121. }
  122. KeAcquireSpinLock(&devExt->usageMappingSpinLock, &oldIrql);
  123. devExt->usageMapping = mapList;
  124. KeReleaseSpinLock(&devExt->usageMappingSpinLock, oldIrql);
  125. }
  126. VOID FreeKeyboardUsageMappingList(PDEVICE_EXTENSION devExt)
  127. {
  128. UsageMappingList *mapList;
  129. KIRQL oldIrql;
  130. KeAcquireSpinLock(&devExt->usageMappingSpinLock, &oldIrql);
  131. mapList = devExt->usageMapping;
  132. devExt->usageMapping = NULL;
  133. KeReleaseSpinLock(&devExt->usageMappingSpinLock, oldIrql);
  134. while (mapList){
  135. UsageMappingList *thisEntry = mapList;
  136. mapList = thisEntry->next;
  137. ExFreePool(thisEntry);
  138. }
  139. }
  140. USHORT MapUsage(PDEVICE_EXTENSION devExt, USHORT kbdUsage)
  141. {
  142. UsageMappingList *mapList;
  143. KIRQL oldIrql;
  144. KeAcquireSpinLock(&devExt->usageMappingSpinLock, &oldIrql);
  145. mapList = devExt->usageMapping;
  146. while (mapList){
  147. if (mapList->sourceUsage == kbdUsage){
  148. kbdUsage = mapList->mappedUsage;
  149. break;
  150. }
  151. else {
  152. mapList = mapList->next;
  153. }
  154. }
  155. KeReleaseSpinLock(&devExt->usageMappingSpinLock, oldIrql);
  156. return kbdUsage;
  157. }
  158. NTSTATUS OpenSubkey( OUT PHANDLE Handle,
  159. IN HANDLE BaseHandle,
  160. IN PUNICODE_STRING KeyName,
  161. IN ACCESS_MASK DesiredAccess
  162. )
  163. {
  164. OBJECT_ATTRIBUTES objectAttributes;
  165. NTSTATUS status;
  166. PAGED_CODE();
  167. InitializeObjectAttributes( &objectAttributes,
  168. KeyName,
  169. OBJ_CASE_INSENSITIVE,
  170. BaseHandle,
  171. (PSECURITY_DESCRIPTOR) NULL );
  172. status = ZwOpenKey(Handle, DesiredAccess, &objectAttributes);
  173. return status;
  174. }
  175. ULONG LAtoX(PWCHAR wHexString)
  176. /*++
  177. Routine Description:
  178. Convert a hex string (without the '0x' prefix) to a ULONG.
  179. Arguments:
  180. wHexString - null-terminated wide-char hex string
  181. (with no "0x" prefix)
  182. Return Value:
  183. ULONG value
  184. --*/
  185. {
  186. ULONG i, result = 0;
  187. for (i = 0; wHexString[i]; i++){
  188. if ((wHexString[i] >= L'0') && (wHexString[i] <= L'9')){
  189. result *= 0x10;
  190. result += (wHexString[i] - L'0');
  191. }
  192. else if ((wHexString[i] >= L'a') && (wHexString[i] <= L'f')){
  193. result *= 0x10;
  194. result += (wHexString[i] - L'a' + 0x0a);
  195. }
  196. else if ((wHexString[i] >= L'A') && (wHexString[i] <= L'F')){
  197. result *= 0x10;
  198. result += (wHexString[i] - L'A' + 0x0a);
  199. }
  200. else {
  201. ASSERT(0);
  202. break;
  203. }
  204. }
  205. return result;
  206. }