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.

2518 lines
79 KiB

  1. /*--
  2. Copyright (c) 1998. 1999 Microsoft Corporation
  3. Module Name:
  4. dinput.c
  5. Abstract:
  6. Environment:
  7. Kernel mode only.
  8. Notes:
  9. --*/
  10. #define INITGUID
  11. //#define UNICODE
  12. //#define _UNICODE
  13. #include <wdm.h>
  14. #include <ntdef.h>
  15. #include <stdio.h>
  16. #include <tchar.h>
  17. #include <devguid.h>
  18. typedef ULONG DWORD;
  19. typedef void *HWND;
  20. typedef struct DIDEVICEOBJECTDATA_DX3 {
  21. DWORD dwOfs;
  22. DWORD dwData;
  23. DWORD dwTimeStamp;
  24. DWORD dwSequence;
  25. } DIDEVICEOBJECTDATA_DX3, *LPDIDEVICEOBJECTDATA_DX3;
  26. typedef const DIDEVICEOBJECTDATA_DX3 *LPCDIDEVICEOBJECTDATA_DX;
  27. typedef struct DIDEVICEOBJECTDATA {
  28. DWORD dwOfs;
  29. DWORD dwData;
  30. DWORD dwTimeStamp;
  31. DWORD dwSequence;
  32. #if(DIRECTINPUT_VERSION >= 0x0701)
  33. UINT_PTR uAppData;
  34. #endif /* DIRECTINPUT_VERSION >= 0x0701 */
  35. } DIDEVICEOBJECTDATA, *LPDIDEVICEOBJECTDATA;
  36. typedef const DIDEVICEOBJECTDATA *LPCDIDEVICEOBJECTDATA;
  37. typedef struct _DIOBJECTDATAFORMAT {
  38. const GUID *pguid;
  39. DWORD dwOfs;
  40. DWORD dwType;
  41. DWORD dwFlags;
  42. } DIOBJECTDATAFORMAT, *LPDIOBJECTDATAFORMAT;
  43. typedef const DIOBJECTDATAFORMAT *LPCDIOBJECTDATAFORMAT;
  44. typedef struct _DIMOUSESTATE2 {
  45. LONG lX;
  46. LONG lY;
  47. LONG lZ;
  48. UCHAR rgbButtons[8];
  49. } DIMOUSESTATE2, *LPDIMOUSESTATE2;
  50. #define DIMOUSESTATE_INT DIMOUSESTATE2 //
  51. #define LPDIMOUSESTATE_INT LPDIMOUSESTATE2 //
  52. #define DIMOFS_X FIELD_OFFSET(DIMOUSESTATE2, lX)
  53. #define DIMOFS_Y FIELD_OFFSET(DIMOUSESTATE2, lY)
  54. #define DIMOFS_Z FIELD_OFFSET(DIMOUSESTATE2, lZ)
  55. #define DIMOFS_BUTTON0 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 0)
  56. #define DIMOFS_BUTTON1 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 1)
  57. #define DIMOFS_BUTTON2 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 2)
  58. #define DIMOFS_BUTTON3 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 3)
  59. #define DIMOFS_BUTTON4 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 4)
  60. #define DIMOFS_BUTTON5 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 5)
  61. #define DIMOFS_BUTTON6 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 6)
  62. #define DIMOFS_BUTTON7 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 7)
  63. #include "..\\dx8\\dll\\dinputv.h"
  64. #include "dinputs.h"
  65. #include "disysdef.h"
  66. #define DIK_LCONTROL 0x1D
  67. #define DIK_LMENU 0x38 /* left Alt */
  68. #define DIK_DECIMAL 0x53 /* . on numeric keypad */
  69. #define DIK_RCONTROL 0x9D
  70. #define DIK_RMENU 0xB8 /* right Alt */
  71. #define DIK_PAUSE 0xC5 /* Pause */
  72. #define DIK_DELETE 0xD3 /* Delete on arrow keypad */
  73. #define DIK_LWIN 0xDB /* Left Windows key */
  74. #define DIK_RWIN 0xDC /* Right Windows key */
  75. #define DIK_APPS 0xDD /* AppMenu key */
  76. #define PVOIDATOFFSET(buffer, ofs) (*(PVOID*)(((UCHAR*)(buffer)) + (ofs)))
  77. #define ULONGATOFFSET(buffer, ofs) (*(ULONG*)(((UCHAR*)(buffer)) + (ofs)))
  78. #define DI_ExAllocatePool(PoolType, Size) \
  79. ExAllocatePoolWithTag(PoolType, Size, 'PNID'); \
  80. ReportError(_T("Allocating %u bytes\n"), Size)
  81. enum DI_DeviceType {DI_DeviceKeyboard, DI_DeviceMouse};
  82. NTSTATUS DriverEntry (PDRIVER_OBJECT, PUNICODE_STRING);
  83. void DI_AddDevice(PDRIVER_OBJECT pDriver);
  84. void DI_RemoveDevice();
  85. NTSTATUS DI_AddToList(PDEVICE_OBJECT pDev);
  86. NTSTATUS DI_RemoveFromList(PDEVICE_OBJECT pDev);
  87. // IOCTL functions
  88. NTSTATUS DI_DestroyInstance(PVXDINSTANCE pVI);
  89. NTSTATUS DI_AcquireInstance(LPDI_DEVINSTANCE pDevInst);
  90. NTSTATUS DI_UnacquireInstance(LPDI_DEVINSTANCE pDevInst);
  91. NTSTATUS DI_SetBufferSize(LPDI_DEVINSTANCE pDevInst, ULONG ulSize);
  92. NTSTATUS DI_SetNotifyHandle(LPDI_DEVINSTANCE pDevInst, PVOID pEvent);
  93. NTSTATUS DI_CreateInstanceHelper(PSYSDEVICEFORMAT pSysDevFormat, void **ppInstanceHandle, enum DI_DeviceType DeviceType);
  94. NTSTATUS DI_CreateKeyboardInstance(PSYSDEVICEFORMAT pSysDevFormat, UCHAR *pbTranslationTable, void **ppInstanceHandle);
  95. NTSTATUS DI_CreateMouseInstance(PSYSDEVICEFORMAT pSysDevFormat, void **ppInstanceHandle);
  96. NTSTATUS DI_SetDataFormat(LPDI_DEVINSTANCE pDevInst, ULONG ulSize, ULONG *pulDataFormat);
  97. #ifdef ALLOC_PRAGMA
  98. #pragma alloc_text (INIT, DriverEntry)
  99. #pragma alloc_text (PAGE, KbdMou_AddDevice)
  100. #pragma alloc_text (PAGE, KbdMou_CreateClose)
  101. #pragma alloc_text (PAGE, KbdMou_IoCtl)
  102. #pragma alloc_text (PAGE, KbdMou_InternIoCtl)
  103. #pragma alloc_text (PAGE, KbdMou_Unload)
  104. #pragma alloc_text (PAGE, KbdMou_DispatchPassThrough)
  105. #pragma alloc_text (PAGE, KbdMou_PnP)
  106. #pragma alloc_text (PAGE, KbdMou_Power)
  107. #pragma alloc_text (PAGE, DI_AddDevice)
  108. #pragma alloc_text (PAGE, DI_RemoveDevice)
  109. #pragma alloc_text (PAGE, DI_AddToList)
  110. #pragma alloc_text (PAGE, DI_RemoveFromList)
  111. #pragma alloc_text (PAGE, DI_DestroyInstance)
  112. #pragma alloc_text (PAGE, DI_AcquireInstance)
  113. #pragma alloc_text (PAGE, DI_UnacquireInstance)
  114. #pragma alloc_text (PAGE, DI_SetBufferSize)
  115. #pragma alloc_text (PAGE, DI_SetNotifyHandle)
  116. #pragma alloc_text (PAGE, DI_CreateInstanceHelper)
  117. #pragma alloc_text (PAGE, DI_CreateKeyboardInstance)
  118. #pragma alloc_text (PAGE, DI_CreateMouseInstance)
  119. #pragma alloc_text (PAGE, DI_SetDataFormat)
  120. #endif
  121. // Globals
  122. BOOLEAN g_bDebugLog = TRUE;
  123. WCHAR g_wszKbdClassGuid[] = L"{4D36E96B-E325-11CE-BFC1-08002BE10318}";
  124. WCHAR g_wszMouClassGuid[] = L"{4D36E96F-E325-11CE-BFC1-08002BE10318}";
  125. PDEVICE_OBJECT g_pUserDevObj = NULL; // Device that communicates with user mode app (DINPUT)
  126. BOOLEAN g_bKbExclusive = FALSE; // Whether a device holds exclusive access to keyboard
  127. UNICODE_STRING g_SymbolicName;
  128. WCHAR g_wszSymbolicNameBuffer[260] = L"\\DosDevices\\DINPUT.SYS"; // Buffer used by g_SymbolicName
  129. ULONG g_ulNumOpenedDevices = 0; // Number of opened devices
  130. DI_DEVINSTANCE *g_pKbdDevInstList = NULL; // list of keyboard device instances
  131. DI_DEVINSTANCE *g_pMouDevInstList = NULL; // list of mouse device instances
  132. PDEVICE_OBJECT g_pKbdDevList = NULL; // A list of PDEVICE_OBJECT for all keyboard devices
  133. PDEVICE_OBJECT g_pMouDevList = NULL; // A list of PDEVICE_OBJECT for all mouse devices
  134. KEYBOARD_INPUT_DATA g_rgCtrlAltDelSequence[6] =
  135. {{0, 0x1D, 0, 0, 0},
  136. {0, 0x38, 0, 0, 0},
  137. {0, 0x53, 0, 0, 0},
  138. {0, 0x53, KEY_BREAK, 0, 0},
  139. {0, 0x38, KEY_BREAK, 0, 0},
  140. {0, 0x1D, KEY_BREAK, 0, 0}};
  141. /*void TRACE(LPCTSTR szFmt, ...)
  142. {
  143. va_list argptr;
  144. TCHAR szBuf[1024];
  145. UNICODE_STRING Unicode;
  146. ANSI_STRING Ansi;
  147. // CHAR szAnsi[1024];
  148. // CHAR *pcPtr = szAnsi;
  149. // TCHAR *ptcPtr;
  150. // Print the identation first
  151. // for (DWORD i = 0; i < s_dwLevels; ++i)
  152. // {
  153. // OutputDebugString(_T(" "));
  154. // if (s_pLogFile)
  155. // _ftprintf(s_pLogFile, _T(" "));
  156. // }
  157. // Then print the content
  158. va_start(argptr, szFmt);
  159. #ifdef WIN95
  160. {
  161. char *psz = NULL;
  162. char szDfs[1024]={0};
  163. strcpy(szDfs,szFmt); // make a local copy of format string
  164. while (psz = strstr(szDfs,"%p")) // find each %p
  165. *(psz+1) = 'x'; // replace %p with %x
  166. _vstprintf(szBuf, szDfs, argptr); // use the local format string
  167. }
  168. #else
  169. {
  170. _vstprintf(szBuf, szFmt, argptr);
  171. }
  172. #endif
  173. // Convert string to ANSI
  174. #ifdef UNICODE
  175. Unicode.Length = _tcslen(szBuf);
  176. Unicode.MaximumLength = 1023;
  177. Unicode.Buffer = szBuf;
  178. RtlUnicodeStringToAnsiString(&Ansi, &Unicode, TRUE);
  179. DebugPrint((Ansi.Buffer));
  180. RtlFreeAnsiString(&Ansi);
  181. #else
  182. DebugPrint((szBuf));
  183. #endif
  184. // ptcPtr = szBuf;
  185. // while (*ptcPtr)
  186. // {
  187. // if (*ptcPtr & 0xFF00) DebugPrint(("UNICODE\n"));
  188. // *pcPtr = *(CHAR*)ptcPtr;
  189. // ++pcPtr;
  190. // ++ptcPtr;
  191. // }
  192. // *pcPtr = '\0';
  193. va_end(argptr);
  194. }
  195. */
  196. #ifdef DBG
  197. #define TRACE DebugOut
  198. #else
  199. #define TRACE 1 ? 0 :
  200. #endif
  201. void DebugOut(LPTSTR tszDbgMsg)
  202. {
  203. CHAR szAnsi[260];
  204. CHAR *pcPtr = szAnsi;
  205. TCHAR *ptcPtr = tszDbgMsg;
  206. ANSI_STRING Ansi;
  207. UNICODE_STRING Unicode;
  208. NTSTATUS Ret;
  209. // Convert string to ANSI
  210. #ifdef UNICODE
  211. Unicode.Length = _tcslen(tszDbgMsg);
  212. Unicode.MaximumLength = Unicode.Length;
  213. Unicode.Buffer = tszDbgMsg;
  214. Ret = RtlUnicodeStringToAnsiString(&Ansi, &Unicode, TRUE);
  215. if (Ret != STATUS_SUCCESS)
  216. DebugPrint(("Convertion failed\n"));
  217. DebugPrint((Ansi.Buffer));
  218. RtlFreeAnsiString(&Ansi);
  219. #else
  220. DebugPrint((tszDbgMsg));
  221. #endif
  222. /* while (*ptcPtr)
  223. {
  224. if (*ptcPtr & 0xFF00) DebugPrint(("UNICODE\n"));
  225. *pcPtr = *(CHAR*)ptcPtr;
  226. ++pcPtr;
  227. ++ptcPtr;
  228. }
  229. *pcPtr = '\0';
  230. */
  231. }
  232. #ifdef DBG
  233. #define ReportError DebugOut1
  234. #else
  235. #define ReportError 1 ? 0 :
  236. #endif
  237. void DebugOut1(LPTSTR tszMsg, long dwCode)
  238. {
  239. TCHAR tszBuffer[1024];
  240. if (g_bDebugLog)
  241. #ifdef WIN95
  242. {
  243. char *psz = NULL;
  244. char szDfs[1024]={0};
  245. strcpy(szDfs,tszMsg); // make a local copy of format string
  246. while (psz = strstr(szDfs,"%p")) // find each %p
  247. *(psz+1) = 'x'; // replace %p with %x
  248. _stprintf(tszBuffer, szDfs, dwCode); // use the local format string
  249. TRACE(tszBuffer);
  250. }
  251. #else
  252. {
  253. _stprintf(tszBuffer, tszMsg, dwCode);
  254. TRACE(tszBuffer);
  255. }
  256. #endif
  257. }
  258. void UnicodeToAnsi(LPSTR szAnsi, LPWSTR wszUnicode)
  259. {
  260. CHAR *pcPtr = szAnsi;
  261. USHORT *pwcPtr = wszUnicode;
  262. while (*pwcPtr)
  263. {
  264. *pcPtr = *(CHAR*)pwcPtr;
  265. ++pcPtr;
  266. ++pwcPtr;
  267. }
  268. *pcPtr = '\0';
  269. }
  270. NTSTATUS DI_AddToList(PDEVICE_OBJECT pDev)
  271. {
  272. PDEVICE_EXTENSION pExt = pDev->DeviceExtension;
  273. PDEVICE_OBJECT pDevList;
  274. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  275. ReportError(_T("DI_AddToList(0x%P)\n"), pDev);
  276. ReportError(_T("DeviceType = 0x%X\n"), pDev->DeviceType);
  277. switch(pDev->DeviceType)
  278. {
  279. case FILE_DEVICE_KEYBOARD:
  280. pExt->pLink = g_pKbdDevList;
  281. pExt->pPrevLink = NULL;
  282. InterlockedExchangePointer(&g_pKbdDevList, pDev); // Insert ourselves to beginning of list
  283. if (pExt->pLink)
  284. InterlockedExchangePointer(&((PDEVICE_EXTENSION)pExt->pLink->DeviceExtension)->pPrevLink, pDev); // Make the next obj backpoint to us
  285. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  286. ReportError(_T("g_pKbdDevList = 0x%P\n"), g_pKbdDevList);
  287. break;
  288. case FILE_DEVICE_MOUSE:
  289. pExt->pLink = g_pMouDevList;
  290. pExt->pPrevLink = NULL;
  291. InterlockedExchangePointer(&g_pMouDevList, pDev); // Insert ourselves to beginning of list
  292. if (pExt->pLink)
  293. InterlockedExchangePointer(&((PDEVICE_EXTENSION)pExt->pLink->DeviceExtension)->pPrevLink, pDev); // Make the next obj backpoint to us
  294. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  295. ReportError(_T("g_pMouDevList = 0x%P\n"), g_pMouDevList);
  296. break;
  297. }
  298. return STATUS_SUCCESS;
  299. }
  300. NTSTATUS DI_RemoveFromList(PDEVICE_OBJECT pDev)
  301. {
  302. PDEVICE_EXTENSION pExt = pDev->DeviceExtension;
  303. if (pExt->pLink)
  304. ((PDEVICE_EXTENSION)pExt->pLink->DeviceExtension)->pPrevLink = pExt->pPrevLink;
  305. if (pExt->pPrevLink)
  306. ((PDEVICE_EXTENSION)pExt->pPrevLink->DeviceExtension)->pLink = pExt->pLink;
  307. // If we are the first device, make the head pointer point to the next device.
  308. switch(pDev->DeviceType)
  309. {
  310. case FILE_DEVICE_KEYBOARD:
  311. if (pDev == g_pKbdDevList)
  312. InterlockedExchangePointer(&g_pKbdDevList, pExt->pLink);
  313. break;
  314. case FILE_DEVICE_MOUSE:
  315. if (pDev == g_pMouDevList)
  316. InterlockedExchangePointer(&g_pMouDevList, pExt->pLink);
  317. break;
  318. }
  319. return STATUS_SUCCESS;
  320. }
  321. // GetDevInstFromUserVxdInst searches the global device instance list for the instance
  322. // that has the specified user mode Vxd instance, then returns a pointer to the dev instance.
  323. // If none is found, it returns NULL.
  324. LPDI_DEVINSTANCE GetDevInstFromUserVxdInst(PVXDINSTANCE pVIUser)
  325. {
  326. LPDI_DEVINSTANCE pDevInst = g_pKbdDevInstList;
  327. // Search through keyboard list
  328. while (pDevInst)
  329. {
  330. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  331. ReportError(_T("Searching 0x%P\n"), pDevInst);
  332. if (pDevInst->pVIUser == pVIUser)
  333. return pDevInst;
  334. pDevInst = pDevInst->pLink;
  335. }
  336. // Not found in keyboard list. Now search through mouse list.
  337. pDevInst = g_pMouDevInstList;
  338. while (pDevInst)
  339. {
  340. if (pDevInst->pVIUser == pVIUser)
  341. return pDevInst;
  342. pDevInst = pDevInst->pLink;
  343. }
  344. return NULL;
  345. }
  346. NTSTATUS
  347. DriverEntry (
  348. IN PDRIVER_OBJECT DriverObject,
  349. IN PUNICODE_STRING RegistryPath
  350. )
  351. /*++
  352. Routine Description:
  353. Initialize the entry points of the driver.
  354. --*/
  355. {
  356. ULONG i;
  357. CHAR DriverNameAnsi[260];
  358. BOOLEAN bDebugLog = g_bDebugLog;
  359. UNREFERENCED_PARAMETER (RegistryPath);
  360. g_bDebugLog = TRUE;
  361. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  362. ReportError(_T("g_bDebugLog located at 0x%P\n"), &g_bDebugLog);
  363. g_bDebugLog = bDebugLog;
  364. //
  365. // Fill in all the dispatch entry points with the pass through function
  366. // and the explicitly fill in the functions we are going to intercept
  367. //
  368. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  369. DriverObject->MajorFunction[i] = KbdMou_DispatchPassThrough;
  370. }
  371. DriverObject->MajorFunction [IRP_MJ_CREATE] =
  372. DriverObject->MajorFunction [IRP_MJ_CLOSE] = KbdMou_CreateClose;
  373. DriverObject->MajorFunction [IRP_MJ_PNP] = KbdMou_PnP;
  374. DriverObject->MajorFunction [IRP_MJ_POWER] = KbdMou_Power;
  375. DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  376. KbdMou_InternIoCtl;
  377. //
  378. // If you are planning on using this function, you must create another
  379. // device object to send the requests to. Please see the considerations
  380. // comments for KbdMou_DispatchPassThrough for implementation details.
  381. //
  382. DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = KbdMou_IoCtl;
  383. DriverObject->DriverUnload = KbdMou_Unload;
  384. DriverObject->DriverExtension->AddDevice = KbdMou_AddDevice;
  385. UnicodeToAnsi(DriverNameAnsi, DriverObject->DriverName.Buffer);
  386. TRACE(DriverNameAnsi);
  387. DI_AddDevice(DriverObject);
  388. ReportError(_T("First IOCTL = %u\n"), IOCTL_INPUTLOST);
  389. ReportError(_T("Last IOCTL = %u\n"), IOCTL_JOY_CONFIGCHANGED);
  390. return STATUS_SUCCESS;
  391. }
  392. NTSTATUS
  393. KbdMou_AddDevice(
  394. IN PDRIVER_OBJECT Driver,
  395. IN PDEVICE_OBJECT PDO
  396. )
  397. {
  398. PDEVICE_EXTENSION devExt;
  399. IO_ERROR_LOG_PACKET errorLogEntry;
  400. PDEVICE_OBJECT device = NULL;
  401. NTSTATUS status = STATUS_SUCCESS;
  402. UNICODE_STRING KbdClassGuid;
  403. UNICODE_STRING MouClassGuid;
  404. UNICODE_STRING PDOClassGuid;
  405. WCHAR wszPDOClassGuid[260];
  406. ULONG ulGuidLength;
  407. CHAR szSymName[260];
  408. PAGED_CODE();
  409. IoGetDeviceProperty(PDO, DevicePropertyClassGuid, sizeof(WCHAR) * 260, wszPDOClassGuid, &ulGuidLength);
  410. RtlInitUnicodeString(&PDOClassGuid, wszPDOClassGuid);
  411. RtlInitUnicodeString(&KbdClassGuid, g_wszKbdClassGuid); // Initialize Keyboard GUID string
  412. RtlInitUnicodeString(&MouClassGuid, g_wszMouClassGuid); // Initialize Mouse GUID string
  413. #ifdef DBG
  414. {
  415. CHAR szPDOClassGuid[260];
  416. UnicodeToAnsi(szPDOClassGuid, wszPDOClassGuid);
  417. #ifdef UNICODE
  418. TRACE(wszPDOClassGuid);
  419. #else
  420. TRACE(szPDOClassGuid);
  421. #endif
  422. TRACE(_T("\n"));
  423. }
  424. #endif
  425. if (!RtlCompareUnicodeString(&KbdClassGuid, &PDOClassGuid, TRUE))
  426. {
  427. // Keyboard device
  428. TRACE(_T("Adding keyboard device...\n"));
  429. status = IoCreateDevice(Driver,
  430. sizeof(DEVICE_EXTENSION),
  431. NULL,
  432. FILE_DEVICE_KEYBOARD,
  433. 0,
  434. FALSE,
  435. &device
  436. );
  437. if (!status)
  438. device->DeviceType = FILE_DEVICE_KEYBOARD;
  439. } else
  440. if (!RtlCompareUnicodeString(&MouClassGuid, &PDOClassGuid, TRUE))
  441. {
  442. // Mouse device
  443. TRACE(_T("Adding mouse device...\n"));
  444. status = IoCreateDevice(Driver,
  445. sizeof(DEVICE_EXTENSION),
  446. NULL,
  447. FILE_DEVICE_MOUSE,
  448. 0,
  449. FALSE,
  450. &device
  451. );
  452. if (!status)
  453. device->DeviceType = FILE_DEVICE_MOUSE;
  454. } else
  455. {
  456. ReportError(_T("IoCreateDevice() failed: 0x%08X\n"), status);
  457. // return STATUS_SUCCESS; // This is a device that we don't care about. Simply return success.
  458. }
  459. if (!NT_SUCCESS(status)) {
  460. return (status);
  461. }
  462. RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION));
  463. devExt = (PDEVICE_EXTENSION) device->DeviceExtension;
  464. devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);
  465. ASSERT(devExt->TopOfStack);
  466. devExt->Self = device;
  467. devExt->PDO = PDO;
  468. devExt->DeviceState = PowerDeviceD0;
  469. devExt->SurpriseRemoved = FALSE;
  470. devExt->Removed = FALSE;
  471. devExt->Started = FALSE;
  472. device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
  473. device->Flags &= ~DO_DEVICE_INITIALIZING;
  474. TRACE(_T("AddDevice successful\n"));
  475. return status;
  476. }
  477. NTSTATUS
  478. KbdMou_Complete(
  479. IN PDEVICE_OBJECT DeviceObject,
  480. IN PIRP Irp,
  481. IN PVOID Context
  482. )
  483. /*++
  484. Routine Description:
  485. Generic completion routine that allows the driver to send the irp down the
  486. stack, catch it on the way up, and do more processing at the original IRQL.
  487. --*/
  488. {
  489. PKEVENT event;
  490. DebugPrint(("KbdMou_Complete()\n"));
  491. event = (PKEVENT) Context;
  492. UNREFERENCED_PARAMETER(DeviceObject);
  493. UNREFERENCED_PARAMETER(Irp);
  494. //
  495. // We could switch on the major and minor functions of the IRP to perform
  496. // different functions, but we know that Context is an event that needs
  497. // to be set.
  498. //
  499. KeSetEvent(event, 0, FALSE);
  500. //
  501. // Allows the caller to use the IRP after it is completed
  502. //
  503. return STATUS_MORE_PROCESSING_REQUIRED;
  504. }
  505. NTSTATUS
  506. KbdMou_CreateClose (
  507. IN PDEVICE_OBJECT DeviceObject,
  508. IN PIRP Irp
  509. )
  510. /*++
  511. Routine Description:
  512. Maintain a simple count of the creates and closes sent against this device
  513. --*/
  514. {
  515. PIO_STACK_LOCATION irpStack;
  516. NTSTATUS status;
  517. PDEVICE_EXTENSION devExt;
  518. PAGED_CODE();
  519. DebugPrint(("KbdMou_CreateClose\n"));
  520. irpStack = IoGetCurrentIrpStackLocation(Irp);
  521. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  522. status = Irp->IoStatus.Status;
  523. switch (irpStack->MajorFunction) {
  524. case IRP_MJ_CREATE:
  525. DebugPrint(("IRP_MJ_CREATE\n"));
  526. if (NULL == devExt->UpperConnectData.ClassService) {
  527. //
  528. // No Connection yet. How can we be enabled?
  529. //
  530. if (DeviceObject != g_pUserDevObj)
  531. status = STATUS_INVALID_DEVICE_STATE;
  532. }
  533. else if ( 1 == InterlockedIncrement(&devExt->EnableCount)) {
  534. //
  535. // first time enable here
  536. //
  537. }
  538. else {
  539. //
  540. // More than one create was sent down
  541. //
  542. }
  543. break;
  544. case IRP_MJ_CLOSE:
  545. DebugPrint(("IRP_MJ_CLOSE\n"));
  546. if (0 == InterlockedDecrement(&devExt->EnableCount)) {
  547. //
  548. // successfully closed the device, do any appropriate work here
  549. //
  550. }
  551. break;
  552. }
  553. Irp->IoStatus.Status = status;
  554. //
  555. // Pass on the create and the close
  556. //
  557. return KbdMou_DispatchPassThrough(DeviceObject, Irp);
  558. }
  559. NTSTATUS
  560. KbdMou_DispatchPassThrough(
  561. IN PDEVICE_OBJECT DeviceObject,
  562. IN PIRP Irp
  563. )
  564. /*++
  565. Routine Description:
  566. Passes a request on to the lower driver.
  567. Considerations:
  568. If you are creating another device object (to communicate with user mode
  569. via IOCTLs), then this function must act differently based on the intended
  570. device object. If the IRP is being sent to the solitary device object, then
  571. this function should just complete the IRP (becuase there is no more stack
  572. locations below it). If the IRP is being sent to the PnP built stack, then
  573. the IRP should be passed down the stack.
  574. These changes must also be propagated to all the other IRP_MJ dispatch
  575. functions (create, close, cleanup, etc) as well!
  576. --*/
  577. {
  578. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  579. // ReportError(_T("DispatchPassThrough(0x%P)\n"), DeviceObject);
  580. if (DeviceObject == g_pUserDevObj)
  581. {
  582. NTSTATUS status = Irp->IoStatus.Status;
  583. // Secondary device
  584. // ReportError(_T("DispatchPassThrough completed with status 0x%08X\n"), Irp->IoStatus.Status);
  585. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  586. return status; // Must use a local to save the return value as IoCompleteRequest frees the IRP.
  587. }
  588. else
  589. {
  590. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  591. //
  592. // Pass the IRP to the target
  593. //
  594. IoSkipCurrentIrpStackLocation(Irp);
  595. return IoCallDriver(((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->TopOfStack, Irp);
  596. }
  597. }
  598. NTSTATUS
  599. KbdMou_InternIoCtl(
  600. IN PDEVICE_OBJECT DeviceObject,
  601. IN PIRP Irp
  602. )
  603. /*++
  604. Routine Description:
  605. This routine is the dispatch routine for internal device control requests.
  606. There are two specific control codes that are of interest:
  607. IOCTL_INTERNAL_KEYBOARD_CONNECT:
  608. Store the old context and function pointer and replace it with our own.
  609. This makes life much simpler than intercepting IRPs sent by the RIT and
  610. modifying them on the way back up.
  611. IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
  612. Add in the necessary function pointers and context values so that we can
  613. alter how the ps/2 keyboard is initialized.
  614. NOTE: Handling IOCTL_INTERNAL_I8042_HOOK_KEYBOARD is *NOT* necessary if
  615. all you want to do is filter KEYBOARD_INPUT_DATAs. You can remove
  616. the handling code and all related device extension fields and
  617. functions to conserve space.
  618. Arguments:
  619. DeviceObject - Pointer to the device object.
  620. Irp - Pointer to the request packet.
  621. Return Value:
  622. Status is returned.
  623. --*/
  624. {
  625. PIO_STACK_LOCATION irpStack;
  626. PDEVICE_EXTENSION devExt;
  627. PINTERNAL_I8042_HOOK_KEYBOARD hookKeyboard;
  628. PINTERNAL_I8042_HOOK_MOUSE hookMouse;
  629. KEVENT event;
  630. PCONNECT_DATA connectData;
  631. NTSTATUS status = STATUS_SUCCESS;
  632. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  633. ReportError(_T("KbdMou_InternIoCtl(0x%P)\n"), DeviceObject);
  634. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  635. Irp->IoStatus.Information = 0;
  636. irpStack = IoGetCurrentIrpStackLocation(Irp);
  637. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  638. //
  639. // Connect a keyboard class device driver to the port driver.
  640. //
  641. case IOCTL_INTERNAL_KEYBOARD_CONNECT:
  642. case IOCTL_INTERNAL_MOUSE_CONNECT:
  643. if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_CONNECT)
  644. TRACE(_T(" IOCTL_INTERNAL_KEYBOARD_CONNECT\n"));
  645. else
  646. TRACE(_T(" IOCTL_INTERNAL_MOUSE_CONNECT\n"));
  647. //
  648. // Only allow one connection.
  649. //
  650. if (devExt->UpperConnectData.ClassService != NULL) {
  651. status = STATUS_SHARING_VIOLATION;
  652. break;
  653. }
  654. else if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  655. sizeof(CONNECT_DATA)) {
  656. //
  657. // invalid buffer
  658. //
  659. status = STATUS_INVALID_PARAMETER;
  660. break;
  661. }
  662. //
  663. // Copy the connection parameters to the device extension.
  664. //
  665. connectData = ((PCONNECT_DATA)
  666. (irpStack->Parameters.DeviceIoControl.Type3InputBuffer));
  667. devExt->UpperConnectData = *connectData;
  668. //
  669. // Hook into the report chain. Everytime a keyboard packet is reported
  670. // to the system, Kbd_ServiceCallback will be called
  671. //
  672. connectData->ClassDeviceObject = devExt->Self;
  673. if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_CONNECT)
  674. connectData->ClassService = Kbd_ServiceCallback;
  675. else
  676. connectData->ClassService = Mou_ServiceCallback;
  677. break;
  678. //
  679. // Disconnect a keyboard class device driver from the port driver.
  680. //
  681. case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
  682. case IOCTL_INTERNAL_MOUSE_DISCONNECT:
  683. if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_DISCONNECT)
  684. TRACE(_T(" IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n"));
  685. else
  686. TRACE(_T(" IOCTL_INTERNAL_MOUSE_DISCONNECT\n"));
  687. //
  688. // Clear the connection parameters in the device extension.
  689. //
  690. // devExt->UpperConnectData.ClassDeviceObject = NULL;
  691. // devExt->UpperConnectData.ClassService = NULL;
  692. status = STATUS_NOT_IMPLEMENTED;
  693. break;
  694. //
  695. // Attach this driver to the initialization and byte processing of the
  696. // i8042 (ie PS/2) keyboard. This is only necessary if you want to do PS/2
  697. // specific functions, otherwise hooking the CONNECT_DATA is sufficient
  698. //
  699. case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
  700. case IOCTL_INTERNAL_I8042_HOOK_MOUSE:
  701. {
  702. ULONG ulCorrectSize;
  703. if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_I8042_HOOK_KEYBOARD)
  704. TRACE(_T(" IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n"));
  705. else
  706. TRACE(_T(" IOCTL_INTERNAL_I8042_HOOK_MOUSE\n"));
  707. if (IOCTL_INTERNAL_I8042_HOOK_KEYBOARD == irpStack->Parameters.DeviceIoControl.IoControlCode)
  708. {
  709. // ******* KEYBOARD CASE *******
  710. TRACE(_T("hook keyboard received!\n"));
  711. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(INTERNAL_I8042_HOOK_KEYBOARD))
  712. {
  713. TRACE(_T("InternalIoctl error - invalid buffer length\n"));
  714. status = STATUS_INVALID_PARAMETER;
  715. break;
  716. }
  717. hookKeyboard = (PINTERNAL_I8042_HOOK_KEYBOARD)
  718. irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
  719. //
  720. // Enter our own initialization routine and record any Init routine
  721. // that may be above us. Repeat for the isr hook
  722. //
  723. devExt->UpperContext = hookKeyboard->Context;
  724. //
  725. // replace old Context with our own
  726. //
  727. hookKeyboard->Context = (PVOID) DeviceObject;
  728. if (hookKeyboard->InitializationRoutine) {
  729. devExt->UpperInitializationRoutine =
  730. hookKeyboard->InitializationRoutine;
  731. }
  732. hookKeyboard->InitializationRoutine =
  733. (PI8042_KEYBOARD_INITIALIZATION_ROUTINE)
  734. Kbd_InitializationRoutine;
  735. if (hookKeyboard->IsrRoutine) {
  736. devExt->UpperKbdIsrHook = hookKeyboard->IsrRoutine;
  737. }
  738. hookKeyboard->IsrRoutine = (PI8042_KEYBOARD_ISR) Kbd_IsrHook;
  739. //
  740. // Store all of the other important stuff
  741. //
  742. devExt->IsrWritePort = hookKeyboard->IsrWritePort;
  743. devExt->QueuePacket = hookKeyboard->QueueKeyboardPacket;
  744. devExt->CallContext = hookKeyboard->CallContext;
  745. } else
  746. {
  747. // ******* MOUSE CASE *******
  748. TRACE(_T("hook mouse received!\n"));
  749. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  750. sizeof(INTERNAL_I8042_HOOK_MOUSE)) {
  751. //
  752. // invalid buffer
  753. //
  754. status = STATUS_INVALID_PARAMETER;
  755. break;
  756. }
  757. //
  758. // Copy the connection parameters to the device extension.
  759. //
  760. hookMouse = (PINTERNAL_I8042_HOOK_MOUSE)
  761. (irpStack->Parameters.DeviceIoControl.Type3InputBuffer);
  762. //
  763. // Set isr routine and context and record any values from above this driver
  764. //
  765. devExt->UpperContext = hookMouse->Context;
  766. hookMouse->Context = (PVOID) DeviceObject;
  767. if (hookMouse->IsrRoutine) {
  768. devExt->UpperMouIsrHook = hookMouse->IsrRoutine;
  769. }
  770. hookMouse->IsrRoutine = (PI8042_MOUSE_ISR) Mou_IsrHook;
  771. //
  772. // Store all of the other functions we might need in the future
  773. //
  774. devExt->IsrWritePort = hookMouse->IsrWritePort;
  775. devExt->CallContext = hookMouse->CallContext;
  776. devExt->QueuePacket = hookMouse->QueueMousePacket;
  777. }
  778. status = STATUS_SUCCESS;
  779. break;
  780. }
  781. //
  782. // These internal ioctls are not supported by the new PnP model.
  783. //
  784. #if 0 // obsolete
  785. case IOCTL_INTERNAL_KEYBOARD_ENABLE:
  786. case IOCTL_INTERNAL_KEYBOARD_DISABLE:
  787. case IOCTL_INTERNAL_MOUSE_ENABLE:
  788. case IOCTL_INTERNAL_MOUSE_DISABLE:
  789. status = STATUS_NOT_SUPPORTED;
  790. break;
  791. #endif // obsolete
  792. //
  793. // Might want to capture these in the future. For now, then pass them down
  794. // the stack. These queries must be successful for the RIT to communicate
  795. // with the keyboard/mouse.
  796. //
  797. case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
  798. case IOCTL_MOUSE_QUERY_ATTRIBUTES:
  799. case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
  800. case IOCTL_KEYBOARD_QUERY_INDICATORS:
  801. case IOCTL_KEYBOARD_SET_INDICATORS:
  802. case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
  803. case IOCTL_KEYBOARD_SET_TYPEMATIC:
  804. break;
  805. }
  806. if (!NT_SUCCESS(status))
  807. {
  808. Irp->IoStatus.Status = status;
  809. Irp->IoStatus.Information = 0;
  810. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  811. return status;
  812. }
  813. return KbdMou_DispatchPassThrough(DeviceObject, Irp);
  814. }
  815. NTSTATUS
  816. KbdMou_PnP(
  817. IN PDEVICE_OBJECT DeviceObject,
  818. IN PIRP Irp
  819. )
  820. /*++
  821. Routine Description:
  822. This routine is the dispatch routine for plug and play irps
  823. Arguments:
  824. DeviceObject - Pointer to the device object.
  825. Irp - Pointer to the request packet.
  826. Return Value:
  827. Status is returned.
  828. --*/
  829. {
  830. PDEVICE_EXTENSION devExt;
  831. PIO_STACK_LOCATION irpStack;
  832. NTSTATUS status = STATUS_SUCCESS;
  833. KIRQL oldIrql;
  834. KEVENT event;
  835. PAGED_CODE();
  836. DebugPrint(("KbdMou_PnP\n"));
  837. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  838. irpStack = IoGetCurrentIrpStackLocation(Irp);
  839. switch (irpStack->MinorFunction) {
  840. case IRP_MN_START_DEVICE: {
  841. DebugPrint(("IRP_MN_START_DEVICE\n"));
  842. //
  843. // The device is starting.
  844. //
  845. // We cannot touch the device (send it any non pnp irps) until a
  846. // start device has been passed down to the lower drivers.
  847. //
  848. IoCopyCurrentIrpStackLocationToNext(Irp);
  849. KeInitializeEvent(&event,
  850. NotificationEvent,
  851. FALSE
  852. );
  853. IoSetCompletionRoutine(Irp,
  854. (PIO_COMPLETION_ROUTINE) KbdMou_Complete,
  855. &event,
  856. TRUE,
  857. TRUE,
  858. TRUE); // No need for Cancel
  859. status = IoCallDriver(devExt->TopOfStack, Irp);
  860. if (STATUS_PENDING == status) {
  861. KeWaitForSingleObject(
  862. &event,
  863. Executive, // Waiting for reason of a driver
  864. KernelMode, // Waiting in kernel mode
  865. FALSE, // No allert
  866. NULL); // No timeout
  867. }
  868. if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status))
  869. {
  870. //
  871. // As we are successfully now back from our start device
  872. // we can do work.
  873. //
  874. devExt->Started = TRUE;
  875. devExt->Removed = FALSE;
  876. devExt->SurpriseRemoved = FALSE;
  877. // Add ourselves to the global device list
  878. DI_AddToList(DeviceObject);
  879. // Enable the interface
  880. // IoSetDeviceInterfaceState(&g_SymbolicName, TRUE);
  881. }
  882. //
  883. // We must now complete the IRP, since we stopped it in the
  884. // completetion routine with MORE_PROCESSING_REQUIRED.
  885. //
  886. Irp->IoStatus.Status = status;
  887. Irp->IoStatus.Information = 0;
  888. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  889. break;
  890. }
  891. case IRP_MN_SURPRISE_REMOVAL:
  892. DebugPrint(("IRP_MN_SURPRISE_REMOVAL\n"));
  893. //
  894. // Same as a remove device, but don't call IoDetach or IoDeleteDevice
  895. //
  896. devExt->SurpriseRemoved = TRUE;
  897. // Remove code here
  898. // Remove ourselves from the global device list
  899. DI_RemoveFromList(DeviceObject);
  900. // IoSetDeviceInterfaceState(&g_SymbolicName, FALSE); // Enable the interface
  901. // DI_RemoveDevice();
  902. IoSkipCurrentIrpStackLocation(Irp);
  903. status = IoCallDriver(devExt->TopOfStack, Irp);
  904. break;
  905. case IRP_MN_REMOVE_DEVICE:
  906. DebugPrint(("IRP_MN_REMOVE_DEVICE\n"));
  907. devExt->Removed = TRUE;
  908. // remove code here
  909. // Remove ourselves from the global device list
  910. DI_RemoveFromList(DeviceObject);
  911. // IoSetDeviceInterfaceState(&g_SymbolicName, FALSE); // Enable the interface
  912. // DI_RemoveDevice();
  913. IoSkipCurrentIrpStackLocation(Irp);
  914. IoCallDriver(devExt->TopOfStack, Irp);
  915. IoDetachDevice(devExt->TopOfStack);
  916. IoDeleteDevice(DeviceObject);
  917. status = STATUS_SUCCESS;
  918. break;
  919. case IRP_MN_QUERY_REMOVE_DEVICE:
  920. case IRP_MN_QUERY_STOP_DEVICE:
  921. case IRP_MN_CANCEL_REMOVE_DEVICE:
  922. case IRP_MN_CANCEL_STOP_DEVICE:
  923. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  924. case IRP_MN_STOP_DEVICE:
  925. case IRP_MN_QUERY_DEVICE_RELATIONS:
  926. case IRP_MN_QUERY_INTERFACE:
  927. case IRP_MN_QUERY_CAPABILITIES:
  928. case IRP_MN_QUERY_DEVICE_TEXT:
  929. case IRP_MN_QUERY_RESOURCES:
  930. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  931. case IRP_MN_READ_CONFIG:
  932. case IRP_MN_WRITE_CONFIG:
  933. case IRP_MN_EJECT:
  934. case IRP_MN_SET_LOCK:
  935. case IRP_MN_QUERY_ID:
  936. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  937. default:
  938. //
  939. // Here the filter driver might modify the behavior of these IRPS
  940. // Please see PlugPlay documentation for use of these IRPs.
  941. //
  942. IoSkipCurrentIrpStackLocation(Irp);
  943. status = IoCallDriver(devExt->TopOfStack, Irp);
  944. break;
  945. }
  946. return status;
  947. }
  948. NTSTATUS
  949. KbdMou_Power(
  950. IN PDEVICE_OBJECT DeviceObject,
  951. IN PIRP Irp
  952. )
  953. /*++
  954. Routine Description:
  955. This routine is the dispatch routine for power irps Does nothing except
  956. record the state of the device.
  957. Arguments:
  958. DeviceObject - Pointer to the device object.
  959. Irp - Pointer to the request packet.
  960. Return Value:
  961. Status is returned.
  962. --*/
  963. {
  964. PIO_STACK_LOCATION irpStack;
  965. PDEVICE_EXTENSION devExt;
  966. POWER_STATE powerState;
  967. POWER_STATE_TYPE powerType;
  968. PAGED_CODE();
  969. DebugPrint(("KbdMou_Power\n"));
  970. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  971. irpStack = IoGetCurrentIrpStackLocation(Irp);
  972. powerType = irpStack->Parameters.Power.Type;
  973. powerState = irpStack->Parameters.Power.State;
  974. switch (irpStack->MinorFunction) {
  975. case IRP_MN_SET_POWER:
  976. if (powerType == DevicePowerState) {
  977. devExt->DeviceState = powerState.DeviceState;
  978. }
  979. case IRP_MN_POWER_SEQUENCE:
  980. case IRP_MN_WAIT_WAKE:
  981. case IRP_MN_QUERY_POWER:
  982. default:
  983. break;
  984. }
  985. PoStartNextPowerIrp(Irp);
  986. IoSkipCurrentIrpStackLocation(Irp);
  987. return PoCallDriver(devExt->TopOfStack, Irp);
  988. }
  989. NTSTATUS
  990. Kbd_InitializationRoutine(
  991. IN PDEVICE_OBJECT DeviceObject,
  992. IN PVOID SynchFuncContext,
  993. IN PI8042_SYNCH_READ_PORT ReadPort,
  994. IN PI8042_SYNCH_WRITE_PORT WritePort,
  995. OUT PBOOLEAN TurnTranslationOn
  996. )
  997. /*++
  998. Routine Description:
  999. This routine gets called after the following has been performed on the kb
  1000. 1) a reset
  1001. 2) set the typematic
  1002. 3) set the LEDs
  1003. i8042prt specific code, if you are writing a packet only filter driver, you
  1004. can remove this function
  1005. Arguments:
  1006. DeviceObject - Context passed during IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
  1007. SynchFuncContext - Context to pass when calling Read/WritePort
  1008. Read/WritePort - Functions to synchronoulsy read and write to the kb
  1009. TurnTranslationOn - If TRUE when this function returns, i8042prt will not
  1010. turn on translation on the keyboard
  1011. Return Value:
  1012. Status is returned.
  1013. --*/
  1014. {
  1015. PDEVICE_EXTENSION devExt;
  1016. NTSTATUS status = STATUS_SUCCESS;
  1017. DebugPrint(("Kbd_InitializationRoutine\n"));
  1018. devExt = DeviceObject->DeviceExtension;
  1019. //
  1020. // Do any interesting processing here. We just call any other drivers
  1021. // in the chain if they exist. Make Translation is turned on as well
  1022. //
  1023. if (devExt->UpperInitializationRoutine) {
  1024. status = (*devExt->UpperInitializationRoutine) (
  1025. devExt->UpperContext,
  1026. SynchFuncContext,
  1027. ReadPort,
  1028. WritePort,
  1029. TurnTranslationOn
  1030. );
  1031. if (!NT_SUCCESS(status)) {
  1032. return status;
  1033. }
  1034. }
  1035. *TurnTranslationOn = TRUE;
  1036. return status;
  1037. }
  1038. BOOLEAN
  1039. Kbd_IsrHook(
  1040. PDEVICE_OBJECT DeviceObject,
  1041. PKEYBOARD_INPUT_DATA CurrentInput,
  1042. POUTPUT_PACKET CurrentOutput,
  1043. UCHAR StatusByte,
  1044. PUCHAR DataByte,
  1045. PBOOLEAN ContinueProcessing,
  1046. PKEYBOARD_SCAN_STATE ScanState
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. This routine gets called at the beginning of processing of the kb interrupt.
  1051. i8042prt specific code, if you are writing a packet only filter driver, you
  1052. can remove this function
  1053. Arguments:
  1054. DeviceObject - Our context passed during IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
  1055. CurrentInput - Current input packet being formulated by processing all the
  1056. interrupts
  1057. CurrentOutput - Current list of bytes being written to the keyboard or the
  1058. i8042 port.
  1059. StatusByte - Byte read from I/O port 60 when the interrupt occurred
  1060. DataByte - Byte read from I/O port 64 when the interrupt occurred.
  1061. This value can be modified and i8042prt will use this value
  1062. if ContinueProcessing is TRUE
  1063. ContinueProcessing - If TRUE, i8042prt will proceed with normal processing of
  1064. the interrupt. If FALSE, i8042prt will return from the
  1065. interrupt after this function returns. Also, if FALSE,
  1066. it is this functions responsibilityt to report the input
  1067. packet via the function provided in the hook IOCTL or via
  1068. queueing a DPC within this driver and calling the
  1069. service callback function acquired from the connect IOCTL
  1070. Return Value:
  1071. Status is returned.
  1072. --*/
  1073. {
  1074. PDEVICE_EXTENSION devExt;
  1075. BOOLEAN retVal = TRUE;
  1076. // ReportError(_T("ISR(0x%02X)\n"), *DataByte);
  1077. devExt = DeviceObject->DeviceExtension;
  1078. if (devExt->UpperKbdIsrHook) {
  1079. retVal = (*devExt->UpperKbdIsrHook) (
  1080. devExt->UpperContext,
  1081. CurrentInput,
  1082. CurrentOutput,
  1083. StatusByte,
  1084. DataByte,
  1085. ContinueProcessing,
  1086. ScanState
  1087. );
  1088. if (!retVal || !(*ContinueProcessing))
  1089. return retVal;
  1090. }
  1091. *ContinueProcessing = TRUE;
  1092. return retVal;
  1093. }
  1094. BOOLEAN
  1095. Mou_IsrHook (
  1096. PDEVICE_OBJECT DeviceObject,
  1097. PMOUSE_INPUT_DATA CurrentInput,
  1098. POUTPUT_PACKET CurrentOutput,
  1099. UCHAR StatusByte,
  1100. PUCHAR DataByte,
  1101. PBOOLEAN ContinueProcessing,
  1102. PMOUSE_STATE MouseState,
  1103. PMOUSE_RESET_SUBSTATE ResetSubState
  1104. )
  1105. /*++
  1106. Remarks:
  1107. i8042prt specific code, if you are writing a packet only filter driver, you
  1108. can remove this function
  1109. Arguments:
  1110. DeviceObject - Our context passed during IOCTL_INTERNAL_I8042_HOOK_MOUSE
  1111. CurrentInput - Current input packet being formulated by processing all the
  1112. interrupts
  1113. CurrentOutput - Current list of bytes being written to the mouse or the
  1114. i8042 port.
  1115. StatusByte - Byte read from I/O port 60 when the interrupt occurred
  1116. DataByte - Byte read from I/O port 64 when the interrupt occurred.
  1117. This value can be modified and i8042prt will use this value
  1118. if ContinueProcessing is TRUE
  1119. ContinueProcessing - If TRUE, i8042prt will proceed with normal processing of
  1120. the interrupt. If FALSE, i8042prt will return from the
  1121. interrupt after this function returns. Also, if FALSE,
  1122. it is this functions responsibilityt to report the input
  1123. packet via the function provided in the hook IOCTL or via
  1124. queueing a DPC within this driver and calling the
  1125. service callback function acquired from the connect IOCTL
  1126. Return Value:
  1127. Status is returned.
  1128. --+*/
  1129. {
  1130. PDEVICE_EXTENSION devExt;
  1131. BOOLEAN retVal = TRUE;
  1132. devExt = DeviceObject->DeviceExtension;
  1133. if (devExt->UpperMouIsrHook) {
  1134. retVal = (*devExt->UpperMouIsrHook) (
  1135. devExt->UpperContext,
  1136. CurrentInput,
  1137. CurrentOutput,
  1138. StatusByte,
  1139. DataByte,
  1140. ContinueProcessing,
  1141. MouseState,
  1142. ResetSubState
  1143. );
  1144. if (!retVal || !(*ContinueProcessing)) {
  1145. return retVal;
  1146. }
  1147. }
  1148. *ContinueProcessing = TRUE;
  1149. return retVal;
  1150. }
  1151. #define IsDeleteDown() \
  1152. (devExt->arbKbdState[DIK_DELETE] || devExt->arbKbdState[DIK_DECIMAL])
  1153. #define IsCtrlDown() \
  1154. (devExt->arbKbdState[DIK_LCONTROL] || devExt->arbKbdState[DIK_RCONTROL])
  1155. #define IsAltDown() \
  1156. (devExt->arbKbdState[DIK_LMENU] || devExt->arbKbdState[DIK_RMENU])
  1157. VOID
  1158. Kbd_ServiceCallback(
  1159. IN PDEVICE_OBJECT DeviceObject,
  1160. IN PKEYBOARD_INPUT_DATA InputDataStart,
  1161. IN PKEYBOARD_INPUT_DATA InputDataEnd,
  1162. IN OUT PULONG InputDataConsumed
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. Called when there are keyboard packets to report to the RIT. You can do
  1167. anything you like to the packets. For instance:
  1168. o Drop a packet altogether
  1169. o Mutate the contents of a packet
  1170. o Insert packets into the stream
  1171. Arguments:
  1172. DeviceObject - Context passed during the connect IOCTL
  1173. InputDataStart - First packet to be reported
  1174. InputDataEnd - One past the last packet to be reported. Total number of
  1175. packets is equal to InputDataEnd - InputDataStart
  1176. InputDataConsumed - Set to the total number of packets consumed by the RIT
  1177. (via the function pointer we replaced in the connect
  1178. IOCTL)
  1179. Return Value:
  1180. Status is returned.
  1181. Remark:
  1182. This routine filters out packets with contents as follows:
  1183. It drops packets with MakeCode 0x2A and E0 flag on.
  1184. It drops packets with MakeCode 0x45 that immediately follows an E1 packet.
  1185. --*/
  1186. {
  1187. PDEVICE_EXTENSION devExt;
  1188. PKEYBOARD_INPUT_DATA pKid = InputDataStart;
  1189. KEYBOARD_INPUT_DATA CurrPacket;
  1190. BOOLEAN bEatPacket = FALSE;
  1191. static BOOLEAN bE1Set; // Static flag that indicates whether the previous packet is an E1 packet.
  1192. BOOLEAN bCtrlAltDel = FALSE; // We set this flag when we detect that Ctrl + Alt + Del is issued.
  1193. LPDI_DEVINSTANCE pInst;
  1194. LARGE_INTEGER TickCount;
  1195. ULONG ulTimeStamp;
  1196. KeQueryTickCount(&TickCount);
  1197. ulTimeStamp = (ULONG)(TickCount.QuadPart * KeQueryTimeIncrement() / 1000000); // KeQueryIncrement() returns time in nanosecond
  1198. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1199. while (pKid != InputDataEnd)
  1200. {
  1201. // TCHAR tszMsg[255];
  1202. // _stprintf(tszMsg, _T("In callback (%hu:0x%02hX:%s) La La La!\n"), pKid->UnitId, pKid->MakeCode, pKid->Flags & KEY_BREAK ? _T("Up") : _T("Down"));
  1203. // TRACE(tszMsg);
  1204. CurrPacket = *pKid; // Get our own copy so we don't tamper packets sent to RIT
  1205. // First check if current packet needs to be dropped. This is true if a previous packet set the E1 flag.
  1206. if (!bE1Set)
  1207. {
  1208. // Check for E1 flag
  1209. if (CurrPacket.Flags & KEY_E1)
  1210. {
  1211. // E1 flag set. This is a pause key packet.
  1212. CurrPacket.MakeCode = DIK_PAUSE;
  1213. bE1Set = TRUE; // Set E1 flag to true so the next packet will be dropped.
  1214. } else
  1215. // Check for E0 flag
  1216. if (CurrPacket.Flags & KEY_E0)
  1217. {
  1218. // E0 flag set
  1219. // If MakeCode == 0x2A, drop the packet
  1220. if (CurrPacket.MakeCode == 0x2A)
  1221. {
  1222. ++pKid; // Next packet is to be processed
  1223. continue;
  1224. }
  1225. // Set the high bit of MakeCode then continue as normal.
  1226. CurrPacket.MakeCode |= 0x80;
  1227. }
  1228. // Now CurrPacket.MakeCode contains DIK_ code
  1229. // Check if this is a repeat call
  1230. if (((CurrPacket.Flags & KEY_BREAK) && devExt->arbKbdState[CurrPacket.MakeCode]) ||
  1231. (!(CurrPacket.Flags & KEY_BREAK) && !devExt->arbKbdState[CurrPacket.MakeCode]))
  1232. {
  1233. // Not a repeat interrupt. Continue processing.
  1234. // TCHAR tszMsg[255];
  1235. // _stprintf(tszMsg, _T("Kb(%hu:0x%02hX:%s:0x%X)\n"), CurrPacket.UnitId, CurrPacket.MakeCode, CurrPacket.Flags & KEY_BREAK ? _T("Up") : _T("Down"), (ULONG)CurrPacket.Flags);
  1236. // TRACE(tszMsg);
  1237. // Normal processing
  1238. // ReportError(_T(" DI sees 0x%02X "), CurrPacket.MakeCode);
  1239. // TRACE(CurrPacket.Flags & KEY_BREAK ? _T("Up\n") : _T("Dn\n"));
  1240. devExt->arbKbdState[CurrPacket.MakeCode] = !(CurrPacket.Flags & KEY_BREAK) ? 0x80 : 0x00; // Record the new state (0x00 if key is up; 0x80 if key is down)
  1241. // Now check if this is a Delete with Ctrl and Alt down.
  1242. if (IsCtrlDown() && IsAltDown() &&
  1243. (CurrPacket.MakeCode == DIK_DELETE || CurrPacket.MakeCode == DIK_DECIMAL) && !(CurrPacket.Flags & KEY_BREAK))
  1244. {
  1245. // Ctrl + Alt + Delete sequenced started.
  1246. bCtrlAltDel = TRUE;
  1247. }
  1248. // Now put the event to all instances' buffers
  1249. // Note: If an instance has non-exclusive access before another device claims exclusive access, the
  1250. // first instance should be fed data even though exclusive access is claimed. However, if yet
  1251. // another instance tries to claim exclusive access after it's already claimed, the attempt will
  1252. // fail. In other words, non-exclusive instances acquired before exclusive access takes effect
  1253. // will continue to get data, while non-exclusive instances acquired after exclusive access
  1254. // takes effect will not get data.
  1255. // What this means is we still have to traverse the list of instances even if an instance has
  1256. // exclusive access. Only the SIFL_ACQUIRED flag determines if the instance receives data.
  1257. //
  1258. // Now we iterate thru the instances and do our work.
  1259. //
  1260. pInst = g_pKbdDevInstList;
  1261. while (pInst &&
  1262. pInst->pVI->fl & VIFL_ACQUIRED)
  1263. {
  1264. // Check for NOWINKEY and CAPTURED flag
  1265. if ((pInst->pVI->fl & VIFL_CAPTURED) ||
  1266. ((pInst->pVI->fl & VIFL_NOWINKEY) &&
  1267. (CurrPacket.MakeCode == DIK_LWIN || CurrPacket.MakeCode == DIK_RWIN)))
  1268. bEatPacket = TRUE;
  1269. // Update the instance's state buffer
  1270. ((UCHAR*)pInst->pState)[CurrPacket.MakeCode] = devExt->arbKbdState[CurrPacket.MakeCode];
  1271. // Synchronize pTail with user mode version.
  1272. pInst->pTail = pInst->pBuffer + (pInst->pVI->pTail - pInst->pVI->pBuffer);
  1273. // Queue the packet only if the instance is buffered.
  1274. if (pInst->pBuffer &&
  1275. pInst->pTail != pInst->pHead + 1 && // full condition
  1276. pInst->pHead != pInst->pTail + pInst->ulBufferSize - 1) // full condition with wrapping
  1277. {
  1278. ULONG dwOfs = CurrPacket.MakeCode;;
  1279. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1280. // ReportError(_T("Inst 0x%P "), pInst);
  1281. // ReportError(_T("pHead at 0x%P "), &pInst->pHead);
  1282. // ReportError(_T("pHead -> 0x%P\n"), pInst->pHead);
  1283. if (pInst->pExtra) // If there is a xlat table, use the table to translate scancode to DIK constant
  1284. dwOfs = ((UCHAR*)pInst->pExtra)[dwOfs];
  1285. if (pInst->pulOffsets) // If there is a data format, use it to translate.
  1286. dwOfs = pInst->pulOffsets[dwOfs];
  1287. pInst->pHead->dwOfs = dwOfs;
  1288. pInst->pHead->dwData = !(CurrPacket.Flags & KEY_BREAK) << 7; // High bit of low byte is 1 if key is down; 0 if up
  1289. pInst->pHead->dwTimeStamp = ulTimeStamp;
  1290. pInst->pHead->dwSequence = pInst->ulSequence++;
  1291. ++pInst->ulEventCount;
  1292. if (++pInst->pVI->pHead, ++pInst->pHead == pInst->pEnd)
  1293. {
  1294. pInst->pVI->pHead = pInst->pVI->pBuffer;
  1295. pInst->pHead = pInst->pBuffer;
  1296. }
  1297. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1298. // ReportError(_T("Inst 0x%P now has "), pInst);
  1299. // ReportError(_T("%u events\n"), pInst->ulEventCount);
  1300. }
  1301. // Set the event for this instance if one exists.
  1302. if (pInst->pEvent)
  1303. {
  1304. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1305. // ReportError(_T("Setting event 0x%P\n"), pInst->pEvent);
  1306. KeSetEvent(pInst->pEvent, 0, FALSE);
  1307. // TRACE(_T("Event set\n"));
  1308. }
  1309. pInst = pInst->pLink; // Next instance
  1310. } // while (instance iterator)
  1311. } else // End of non-repeat packet
  1312. {
  1313. // Repeat packet. We still need to check for NOWINKEY and CAPTURED flag
  1314. pInst = g_pKbdDevInstList;
  1315. while (pInst &&
  1316. pInst->pVI->fl & VIFL_ACQUIRED)
  1317. {
  1318. // Check for NOWINKEY flag
  1319. if ((pInst->pVI->fl & VIFL_CAPTURED) ||
  1320. ((pInst->pVI->fl & VIFL_NOWINKEY) &&
  1321. (CurrPacket.MakeCode == DIK_LWIN || CurrPacket.MakeCode == DIK_RWIN)))
  1322. bEatPacket = TRUE;
  1323. pInst = pInst->pLink; // Next instance
  1324. }
  1325. } // End of repeat packet
  1326. } // if (!bE1Set)
  1327. else
  1328. bE1Set = FALSE; // Clear the E1 flag to avoid incorrectly dropping more than one packet.
  1329. ++pKid;
  1330. }
  1331. if (!bEatPacket)
  1332. (*(PSERVICE_CALLBACK_ROUTINE)devExt->UpperConnectData.ClassService)(
  1333. devExt->UpperConnectData.ClassDeviceObject,
  1334. InputDataStart,
  1335. InputDataEnd,
  1336. InputDataConsumed);
  1337. else
  1338. {
  1339. // We don't send anything to RIT, but we must send Ctrl + Alt + Delete if issued.
  1340. if (bCtrlAltDel)
  1341. {
  1342. (*(PSERVICE_CALLBACK_ROUTINE)devExt->UpperConnectData.ClassService)(
  1343. devExt->UpperConnectData.ClassDeviceObject,
  1344. g_rgCtrlAltDelSequence,
  1345. g_rgCtrlAltDelSequence + 6,
  1346. InputDataConsumed);
  1347. // // Now reset the state for LCtrl, RCtrl, LAlt, RAlt, Delete, and Decimal because when
  1348. // // issued the sequence to Windows, input is lost and the break code of these keys
  1349. // // were not received by us.
  1350. }
  1351. }
  1352. // ReportError(_T("RIT consumed %u packets\n"), *InputDataConsumed);
  1353. *InputDataConsumed = InputDataEnd - InputDataStart;
  1354. }
  1355. // AddMouseEvent adds a mouse event to the instance passed to it. It checks for full condition and
  1356. // update the buffer pointers appropriately.
  1357. #define AddMouseEvent(pInst, Ofs, Data, TimeStamp) \
  1358. do { \
  1359. /* Queue the packet only if the instance is buffered. */ \
  1360. if (pInst->pBuffer && \
  1361. pInst->pTail != pInst->pHead + 1 && /* full condition */ \
  1362. pInst->pHead != pInst->pTail + pInst->ulBufferSize - 1) /* full condition with wrapping */ \
  1363. { \
  1364. pInst->pHead->dwOfs = Ofs; \
  1365. pInst->pHead->dwData = Data; \
  1366. pInst->pHead->dwTimeStamp = TimeStamp; \
  1367. pInst->pHead->dwSequence = pInst->ulSequence++; \
  1368. ++pInst->ulEventCount; \
  1369. /* Advance head pointer */ \
  1370. if (++pInst->pVI->pHead, ++pInst->pHead == pInst->pEnd) \
  1371. { \
  1372. pInst->pVI->pHead = pInst->pVI->pBuffer; \
  1373. pInst->pHead = pInst->pBuffer; \
  1374. } \
  1375. } \
  1376. } while (0)
  1377. VOID
  1378. Mou_ServiceCallback(
  1379. IN PDEVICE_OBJECT DeviceObject,
  1380. IN PMOUSE_INPUT_DATA InputDataStart,
  1381. IN PMOUSE_INPUT_DATA InputDataEnd,
  1382. IN OUT PULONG InputDataConsumed
  1383. )
  1384. /*++
  1385. Routine Description:
  1386. Called when there are mouse packets to report to the RIT. You can do
  1387. anything you like to the packets. For instance:
  1388. o Drop a packet altogether
  1389. o Mutate the contents of a packet
  1390. o Insert packets into the stream
  1391. Arguments:
  1392. DeviceObject - Context passed during the connect IOCTL
  1393. InputDataStart - First packet to be reported
  1394. InputDataEnd - One past the last packet to be reported. Total number of
  1395. packets is equal to InputDataEnd - InputDataStart
  1396. InputDataConsumed - Set to the total number of packets consumed by the RIT
  1397. (via the function pointer we replaced in the connect
  1398. IOCTL)
  1399. Return Value:
  1400. Status is returned.
  1401. --*/
  1402. {
  1403. PDEVICE_EXTENSION devExt;
  1404. PMOUSE_INPUT_DATA pMid;
  1405. LPDI_DEVINSTANCE pInst;
  1406. LPDIMOUSESTATE_INT pState = &((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->MouseState;
  1407. LARGE_INTEGER TickCount;
  1408. ULONG ulTimeStamp;
  1409. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1410. KeQueryTickCount(&TickCount);
  1411. ulTimeStamp = (ULONG)(TickCount.QuadPart * KeQueryTimeIncrement() / 1000000); // KeQueryIncrement() returns time in nanosecond
  1412. pMid = InputDataStart;
  1413. while (pMid != InputDataEnd)
  1414. {
  1415. /* ReportError(_T("%u["), pMid->UnitId);
  1416. ReportError(_T("%d,"), pMid->LastX);
  1417. ReportError(_T("%d]"), pMid->LastY);
  1418. ReportError(_T("%X "), pMid->RawButtons);
  1419. ReportError(_T("%X "), pMid->ButtonData);
  1420. ReportError(_T("%X\n"), pMid->ButtonFlags);*/
  1421. // Update the state of the device object
  1422. pState->lX += pMid->LastX;
  1423. pState->lY += pMid->LastY;
  1424. if (pMid->ButtonFlags & MOUSE_WHEEL)
  1425. pState->lZ += (SHORT)pMid->ButtonData;
  1426. if ((MOUSE_BUTTON_1_DOWN|MOUSE_BUTTON_1_UP) & pMid->ButtonFlags)
  1427. pState->rgbButtons[0] = MOUSE_BUTTON_1_DOWN & pMid->ButtonFlags ? 0x80 : 0;
  1428. if ((MOUSE_BUTTON_2_DOWN|MOUSE_BUTTON_2_UP) & pMid->ButtonFlags)
  1429. pState->rgbButtons[1] = MOUSE_BUTTON_2_DOWN & pMid->ButtonFlags ? 0x80 : 0;
  1430. if ((MOUSE_BUTTON_3_DOWN|MOUSE_BUTTON_3_UP) & pMid->ButtonFlags)
  1431. pState->rgbButtons[2] = MOUSE_BUTTON_3_DOWN & pMid->ButtonFlags ? 0x80 : 0;
  1432. if ((MOUSE_BUTTON_4_DOWN|MOUSE_BUTTON_4_UP) & pMid->ButtonFlags)
  1433. pState->rgbButtons[3] = MOUSE_BUTTON_4_DOWN & pMid->ButtonFlags ? 0x80 : 0;
  1434. if ((MOUSE_BUTTON_5_DOWN|MOUSE_BUTTON_5_UP) & pMid->ButtonFlags)
  1435. pState->rgbButtons[4] = MOUSE_BUTTON_5_DOWN & pMid->ButtonFlags ? 0x80 : 0;
  1436. // Now we inspect the input packet and fill in the instance buffers.
  1437. pInst = g_pMouDevInstList;
  1438. while (pInst && pInst->pVI->fl & VIFL_ACQUIRED)
  1439. {
  1440. // Synchronize pTail with user mode version.
  1441. pInst->pTail = pInst->pBuffer + (pInst->pVI->pTail - pInst->pVI->pBuffer);
  1442. // Queue the axes movement
  1443. if (pMid->LastX)
  1444. {
  1445. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_X], pState->lX - ((LPDIMOUSESTATE_INT)pInst->pState)->lX, ulTimeStamp);
  1446. ((LPDIMOUSESTATE_INT)pInst->pState)->lX = pState->lX;
  1447. }
  1448. if (pMid->LastY)
  1449. {
  1450. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_Y], pState->lY - ((LPDIMOUSESTATE_INT)pInst->pState)->lY, ulTimeStamp);
  1451. ((LPDIMOUSESTATE_INT)pInst->pState)->lY = pState->lY;
  1452. }
  1453. if (pMid->ButtonFlags & MOUSE_WHEEL)
  1454. {
  1455. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_Z], pState->lZ - ((LPDIMOUSESTATE_INT)pInst->pState)->lZ, ulTimeStamp);
  1456. ((LPDIMOUSESTATE_INT)pInst->pState)->lZ = pState->lZ;
  1457. }
  1458. // Queue the button changes
  1459. if ((MOUSE_BUTTON_1_DOWN|MOUSE_BUTTON_1_UP) & pMid->ButtonFlags)
  1460. {
  1461. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_BUTTON0], pState->rgbButtons[0], ulTimeStamp);
  1462. ((LPDIMOUSESTATE_INT)pInst->pState)->rgbButtons[0] = pState->rgbButtons[0];
  1463. }
  1464. if ((MOUSE_BUTTON_2_DOWN|MOUSE_BUTTON_2_UP) & pMid->ButtonFlags)
  1465. {
  1466. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_BUTTON1], pState->rgbButtons[1], ulTimeStamp);
  1467. ((LPDIMOUSESTATE_INT)pInst->pState)->rgbButtons[1] = pState->rgbButtons[1];
  1468. }
  1469. if ((MOUSE_BUTTON_3_DOWN|MOUSE_BUTTON_3_UP) & pMid->ButtonFlags)
  1470. {
  1471. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_BUTTON2], pState->rgbButtons[2], ulTimeStamp);
  1472. ((LPDIMOUSESTATE_INT)pInst->pState)->rgbButtons[2] = pState->rgbButtons[2];
  1473. }
  1474. if ((MOUSE_BUTTON_4_DOWN|MOUSE_BUTTON_4_UP) & pMid->ButtonFlags)
  1475. {
  1476. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_BUTTON3], pState->rgbButtons[3], ulTimeStamp);
  1477. ((LPDIMOUSESTATE_INT)pInst->pState)->rgbButtons[3] = pState->rgbButtons[3];
  1478. }
  1479. if ((MOUSE_BUTTON_5_DOWN|MOUSE_BUTTON_5_UP) & pMid->ButtonFlags)
  1480. {
  1481. AddMouseEvent(pInst, pInst->pulOffsets[DIMOFS_BUTTON4], pState->rgbButtons[4], ulTimeStamp);
  1482. ((LPDIMOUSESTATE_INT)pInst->pState)->rgbButtons[4] = pState->rgbButtons[4];
  1483. }
  1484. // Set event if one is given
  1485. if (pInst->pEvent)
  1486. KeSetEvent(pInst->pEvent, 0, FALSE);
  1487. pInst = pInst->pLink;
  1488. }
  1489. ++pMid;
  1490. }
  1491. //
  1492. // UpperConnectData must be called at DISPATCH
  1493. //
  1494. (*(PSERVICE_CALLBACK_ROUTINE) devExt->UpperConnectData.ClassService)(
  1495. devExt->UpperConnectData.ClassDeviceObject,
  1496. InputDataStart,
  1497. InputDataEnd,
  1498. InputDataConsumed
  1499. );
  1500. }
  1501. VOID
  1502. KbdMou_Unload(
  1503. IN PDRIVER_OBJECT Driver
  1504. )
  1505. /*++
  1506. Routine Description:
  1507. Free all the allocated resources associated with this driver.
  1508. Arguments:
  1509. DriverObject - Pointer to the driver object.
  1510. Return Value:
  1511. None.
  1512. --*/
  1513. {
  1514. PAGED_CODE();
  1515. DebugPrint(("KbdMou_Unload\n"));
  1516. DI_RemoveDevice();
  1517. UNREFERENCED_PARAMETER(Driver);
  1518. ASSERT(NULL == Driver->DeviceObject);
  1519. }
  1520. ///////////////////////////////////////////////////////////////
  1521. // DINPUT Specific
  1522. ///////////////////////////////////////////////////////////////
  1523. // All IOCTLs that takes an instance handle as input actually takes a pointer to a
  1524. // VXDINSTANCE structure. We then find the corresponding device instance pointer
  1525. // by calling GetDevInstFromUserVxdInst.
  1526. NTSTATUS
  1527. KbdMou_IoCtl(
  1528. IN PDEVICE_OBJECT DeviceObject,
  1529. IN PIRP Irp
  1530. )
  1531. {
  1532. LPDI_DEVINSTANCE hInst = NULL;
  1533. NTSTATUS Status = STATUS_SUCCESS;
  1534. PIO_STACK_LOCATION irpStack;
  1535. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1536. ReportError(_T("KbdMou_IoCtl(0x%P)\n"), DeviceObject);
  1537. // If this is not the secondary device object, we just pass it down to the next driver.
  1538. if (DeviceObject != g_pUserDevObj)
  1539. return KbdMou_DispatchPassThrough(DeviceObject, Irp);
  1540. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1541. switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
  1542. {
  1543. case IOCTL_GETVERSION:
  1544. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1545. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1546. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1547. /* ReportError(_T("About to write to user buffer at 0x%P\n"), Irp->AssociatedIrp.SystemBuffer);
  1548. ReportError(_T(" Currently 0x%P"), *Irp->AssociatedIrp.SystemBuffer);
  1549. ReportError(_T(" Input Buffer length = %u\n"), irpStack->Parameters.DeviceIoControl.InputBufferLength);
  1550. ReportError(_T(" Output Buffer length = %u\n"), irpStack->Parameters.DeviceIoControl.OutputBufferLength);*/
  1551. *(ULONG*)Irp->AssociatedIrp.SystemBuffer = 0x12345678;
  1552. Irp->IoStatus.Information = sizeof(ULONG);
  1553. TRACE(_T("Written to user buffer.\n"));
  1554. break;
  1555. case IOCTL_DESTROYINSTANCE:
  1556. // Input is a buffer containing a pointer to VXDINSTANCE
  1557. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1558. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1559. if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(void*))
  1560. { Status = STATUS_INVALID_PARAMETER; break; }
  1561. if (!*(PVOID*)Irp->AssociatedIrp.SystemBuffer)
  1562. { Status = STATUS_INVALID_PARAMETER; break; }
  1563. hInst = GetDevInstFromUserVxdInst(*(VXDINSTANCE**)Irp->AssociatedIrp.SystemBuffer);
  1564. if (!hInst)
  1565. { Status = STATUS_INVALID_PARAMETER; break; }
  1566. Status = DI_DestroyInstance(*(VXDINSTANCE**)Irp->AssociatedIrp.SystemBuffer);
  1567. break;
  1568. case IOCTL_SETDATAFORMAT:
  1569. // Input is a buffer containing the instance handle followed by a DWORD indicating number of elements
  1570. // in the data format, followed by the address of the array of DWORDs defining the data format.
  1571. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1572. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1573. if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(void*) + sizeof(ULONG) + sizeof(void*))
  1574. { Status = STATUS_INVALID_PARAMETER; break; }
  1575. if (!*(PVOID*)Irp->AssociatedIrp.SystemBuffer)
  1576. { Status = STATUS_INVALID_PARAMETER; break; }
  1577. hInst = GetDevInstFromUserVxdInst(*(VXDINSTANCE**)Irp->AssociatedIrp.SystemBuffer);
  1578. if (!hInst)
  1579. { Status = STATUS_INVALID_PARAMETER; break; }
  1580. if (!PVOIDATOFFSET(Irp->AssociatedIrp.SystemBuffer, sizeof(PVOID) + sizeof(ULONG)))
  1581. { Status = STATUS_INVALID_PARAMETER; break; }
  1582. Status = DI_SetDataFormat(hInst,
  1583. ULONGATOFFSET(Irp->AssociatedIrp.SystemBuffer, sizeof(PVOID)),
  1584. PVOIDATOFFSET(Irp->AssociatedIrp.SystemBuffer, sizeof(PVOID) + sizeof(ULONG)));
  1585. break;
  1586. case IOCTL_ACQUIREINSTANCE:
  1587. // Input is a buffer containing the instance handle
  1588. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1589. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1590. if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(void*))
  1591. { Status = STATUS_INVALID_PARAMETER; break; }
  1592. if (!*(PVOID*)Irp->AssociatedIrp.SystemBuffer)
  1593. { Status = STATUS_INVALID_PARAMETER; break; }
  1594. hInst = GetDevInstFromUserVxdInst(*(VXDINSTANCE**)Irp->AssociatedIrp.SystemBuffer);
  1595. if (!hInst)
  1596. { Status = STATUS_INVALID_PARAMETER; break; }
  1597. Status = DI_AcquireInstance(hInst);
  1598. break;
  1599. case IOCTL_UNACQUIREINSTANCE:
  1600. // Input is a buffer containing the instance handle
  1601. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1602. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1603. if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(void*))
  1604. { Status = STATUS_INVALID_PARAMETER; break; }
  1605. if (!*(PVOID*)Irp->AssociatedIrp.SystemBuffer)
  1606. { Status = STATUS_INVALID_PARAMETER; break; }
  1607. hInst = GetDevInstFromUserVxdInst(*(VXDINSTANCE**)Irp->AssociatedIrp.SystemBuffer);
  1608. if (!hInst)
  1609. { Status = STATUS_INVALID_PARAMETER; break; }
  1610. Status = DI_UnacquireInstance(hInst);
  1611. break;
  1612. case IOCTL_SETNOTIFYHANDLE:
  1613. // Input is a buffer containing the instance handle followed by an event object.
  1614. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1615. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1616. if (!*(PVOID*)Irp->AssociatedIrp.SystemBuffer)
  1617. { Status = STATUS_INVALID_PARAMETER; break; }
  1618. hInst = GetDevInstFromUserVxdInst(*(VXDINSTANCE**)Irp->AssociatedIrp.SystemBuffer);
  1619. if (!hInst)
  1620. { Status = STATUS_INVALID_PARAMETER; break; }
  1621. Status = DI_SetNotifyHandle(hInst,
  1622. PVOIDATOFFSET(Irp->AssociatedIrp.SystemBuffer, sizeof(PVOID)));
  1623. break;
  1624. case IOCTL_SETBUFFERSIZE:
  1625. // Input is a buffer containing the instance handle followed by the size (DWORD) in element.
  1626. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1627. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1628. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(PVOID) + sizeof(DWORD))
  1629. { Status = STATUS_INVALID_PARAMETER; break; }
  1630. if (!*(PVOID*)Irp->AssociatedIrp.SystemBuffer)
  1631. { Status = STATUS_INVALID_PARAMETER; break; }
  1632. hInst = GetDevInstFromUserVxdInst(*(VXDINSTANCE**)Irp->AssociatedIrp.SystemBuffer);
  1633. if (!hInst)
  1634. { Status = STATUS_INVALID_PARAMETER; break; }
  1635. DI_SetBufferSize(hInst, *(ULONG*)((UCHAR*)Irp->AssociatedIrp.SystemBuffer + sizeof(PVOID)));
  1636. break;
  1637. case IOCTL_KBD_CREATEINSTANCE:
  1638. case IOCTL_MOUSE_CREATEINSTANCE:
  1639. {
  1640. // Input is a buffer containing a SYSDEVICEFORMAT structure
  1641. void *pInstanceHandle;
  1642. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1643. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1644. if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(SYSDEVICEFORMAT))
  1645. { Status = STATUS_INVALID_PARAMETER; break; }
  1646. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(void*))
  1647. { Status = STATUS_INVALID_PARAMETER; break; }
  1648. if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KBD_CREATEINSTANCE)
  1649. Status = DI_CreateKeyboardInstance(Irp->AssociatedIrp.SystemBuffer,
  1650. ((PSYSDEVICEFORMAT)Irp->AssociatedIrp.SystemBuffer)->pExtra,
  1651. &pInstanceHandle);
  1652. else
  1653. Status = DI_CreateMouseInstance(Irp->AssociatedIrp.SystemBuffer, &pInstanceHandle);
  1654. *(void **)Irp->AssociatedIrp.SystemBuffer = pInstanceHandle;
  1655. Irp->IoStatus.Information = sizeof(PVOID);
  1656. break;
  1657. }
  1658. case IOCTL_KBD_INITKEYS:
  1659. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1660. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1661. break;
  1662. case IOCTL_MOUSE_INITBUTTONS:
  1663. if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  1664. TRACE(_T("WARNING WARNING WARNING: IOCTL called at IRQL > PASSIVE_LEVEL\n"));
  1665. break;
  1666. default:
  1667. ReportError(_T("Unsupported IOCTL (0x%08X) called\n"), irpStack->Parameters.DeviceIoControl.IoControlCode);
  1668. Status = STATUS_INVALID_PARAMETER;
  1669. break;
  1670. }
  1671. if (Status) Irp->IoStatus.Status = Status;
  1672. return KbdMou_DispatchPassThrough(DeviceObject, Irp);
  1673. }
  1674. void DI_AddDevice(PDRIVER_OBJECT pDriver)
  1675. {
  1676. NTSTATUS status;
  1677. if (g_ulNumOpenedDevices++ == 0)
  1678. {
  1679. // Create the secondary device object
  1680. USHORT wszDevNameString[] = L"\\Device\\DINPUT1";
  1681. UNICODE_STRING DevName;
  1682. RtlInitUnicodeString(&DevName, wszDevNameString);
  1683. status = IoCreateDevice(pDriver,
  1684. sizeof(DEVICE_EXTENSION),
  1685. &DevName,
  1686. FILE_DEVICE_UNKNOWN,
  1687. 0,
  1688. FALSE,
  1689. &g_pUserDevObj
  1690. );
  1691. if (status)
  1692. {
  1693. ReportError(_T("IoCreateDevice on second device failed: 0x%08X\n"), status);
  1694. }
  1695. ReportError(_T("User Device Object at 0x%P\n"), g_pUserDevObj);
  1696. // Register device interface
  1697. // IoRegisterDeviceInterface(PDO, &DINPUT_INTERFACE_GUID, NULL, &g_SymbolicName);
  1698. // Correct 2nd and 3rd characters in the name returned.
  1699. // g_SymbolicName.Buffer[1] = _T('\\');
  1700. // g_SymbolicName.Buffer[2] = _T('.');
  1701. // UnicodeToAnsi(szSymName, g_SymbolicName.Buffer);
  1702. // TRACE(szSymName);
  1703. // TRACE(_T("\n"));
  1704. if (!status)
  1705. {
  1706. ANSI_STRING AnsiName;
  1707. // Create a symbolic link
  1708. // NTSTATUS ret;
  1709. // USHORT wszBuffer[260] = L"\\DosDevices\\DINPUT1";
  1710. // UNICODE_STRING NewName;
  1711. g_pUserDevObj->DeviceType = FILE_DEVICE_UNKNOWN;
  1712. RtlInitUnicodeString(&g_SymbolicName, g_wszSymbolicNameBuffer);
  1713. RtlUnicodeStringToAnsiString(&AnsiName, &g_SymbolicName, TRUE);
  1714. ReportError(_T("Symbolic name used: \"%s\"\n"), (ULONG)AnsiName.Buffer);
  1715. status = IoCreateSymbolicLink(&g_SymbolicName, &DevName);
  1716. if (status)
  1717. {
  1718. ReportError(_T("IoCreateSymbolicLink failed: 0x%08X\n"), status);
  1719. // ReportError(_T(" 2nd character is 0x%02X\n"), (char)g_SymbolicName.Buffer[1]);
  1720. // ReportError(_T(" 3rd character is 0x%02X\n"), (char)g_SymbolicName.Buffer[2]);
  1721. }
  1722. else
  1723. TRACE(_T("IoCreateSymbolicLink successful\n"));
  1724. /* else
  1725. {
  1726. status = IoDeleteSymbolicLink(&g_SymbolicName);
  1727. if (status)
  1728. ReportError(_T("IoDeleteSymbolicLink() failed: 0x%08X\n"), status);
  1729. }*/
  1730. // IoDeleteDevice(g_pUserDevObj);
  1731. }
  1732. }
  1733. }
  1734. void DI_RemoveDevice()
  1735. {
  1736. DebugPrint(("DI_RemoveDevice()\n"));
  1737. if (--g_ulNumOpenedDevices == 0)
  1738. {
  1739. // Delete the secondary device object
  1740. IoSetDeviceInterfaceState(&g_SymbolicName, FALSE);
  1741. IoDeleteDevice(g_pUserDevObj);
  1742. }
  1743. }
  1744. // DI_CreateInstanceHelper does the following:
  1745. // 1. Allocate memory for VXDINSTANCE and makes it user mode accessible.
  1746. // 2. Allocate memory for device instance structure.
  1747. // 3. Allocate memory for device state and makes it user mode accessible.
  1748. // 4. Insert the instance to the appropriate instance list.
  1749. // 5. Initialize ppInstanceHandle with the user mode address of VXDINSTANCE.
  1750. NTSTATUS DI_CreateInstanceHelper(PSYSDEVICEFORMAT pSysDevFormat, void **ppInstanceHandle, enum DI_DeviceType DeviceType)
  1751. {
  1752. PVXDINSTANCE pVI;
  1753. PVXDINSTANCE pVIUser;
  1754. PMDL pMdlForVI;
  1755. LPDI_DEVINSTANCE pDevInst;
  1756. BOOLEAN bFailed = FALSE;
  1757. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1758. ReportError(_T("DI_CreateInstanceHelper(0x%P, "), pSysDevFormat);
  1759. ReportError(_T("0x%P)\n"), ppInstanceHandle);
  1760. // First thing we do is allocate memory for VXDINSTANCE and make it usermode accessible
  1761. pVI = DI_ExAllocatePool(PagedPool, sizeof(VXDINSTANCE));
  1762. if (!pVI)
  1763. return STATUS_INSUFFICIENT_RESOURCES;
  1764. RtlZeroMemory(pVI, sizeof(VXDINSTANCE));
  1765. pMdlForVI = IoAllocateMdl(pVI, sizeof(VXDINSTANCE), FALSE, FALSE, NULL);
  1766. __try
  1767. {
  1768. MmProbeAndLockPages(pMdlForVI, KernelMode, IoReadAccess);
  1769. }
  1770. __except(EXCEPTION_EXECUTE_HANDLER)
  1771. {
  1772. // Cannot lock pages. Free Mdl and pool, then bail out.
  1773. IoFreeMdl(pMdlForVI);
  1774. ExFreePool(pVI);
  1775. return STATUS_INSUFFICIENT_RESOURCES;
  1776. }
  1777. pVIUser = MmMapLockedPages(pMdlForVI, UserMode);
  1778. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1779. ReportError(_T("User VI at 0x%P\n"), pVIUser);
  1780. // Now allocate and initialize DI_DEVINSTANCE
  1781. pDevInst = DI_ExAllocatePool(PagedPool, sizeof(DI_DEVINSTANCE));
  1782. if (!pDevInst)
  1783. return STATUS_INSUFFICIENT_RESOURCES;
  1784. // NOTE: Right now, make all instances use the first keyboard. Later, caller will supply a parameter
  1785. // telling us which keyboard it's interested in.
  1786. RtlZeroMemory(pDevInst, sizeof(DI_DEVINSTANCE));
  1787. pDevInst->pDev = DeviceType == DI_DeviceKeyboard ? g_pKbdDevList : g_pMouDevList;
  1788. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1789. ReportError(_T("pDev = 0x%P\n"), pDevInst->pDev);
  1790. pDevInst->pBuffer = pDevInst->pEnd = pDevInst->pHead = pDevInst->pTail = NULL;
  1791. pDevInst->pVIUser = pVIUser; // Save the user mode VI address
  1792. pDevInst->pVI = pVI; // Save the kernel mode address of our VI
  1793. pDevInst->pMdlForVI = pMdlForVI; // Save the Mdl for use by DestroyInstance
  1794. // pVI->hInst = pDevInst; // Make VI point to the device instance struct
  1795. __try
  1796. {
  1797. __try
  1798. {
  1799. // Allocate memory to hold the state information
  1800. ULONG ulStateSize = DeviceType == DI_DeviceKeyboard ? sizeof(UCHAR) * 256 : sizeof(DIMOUSESTATE_INT);
  1801. pDevInst->pState = DI_ExAllocatePool(PagedPool, ulStateSize);
  1802. if (!pDevInst->pState)
  1803. {
  1804. bFailed = TRUE;
  1805. return STATUS_INSUFFICIENT_RESOURCES;
  1806. }
  1807. RtlZeroMemory(pDevInst->pState, ulStateSize);
  1808. // Lock the state buffer for sharing with the DLL
  1809. pDevInst->pMdlForState = IoAllocateMdl(pDevInst->pState, ulStateSize, FALSE, FALSE, NULL);
  1810. MmProbeAndLockPages(pDevInst->pMdlForState, KernelMode, IoReadAccess);
  1811. pVI->pState = MmMapLockedPages(pDevInst->pMdlForState, UserMode);
  1812. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1813. ReportError(_T("Usermode state buffer at 0x%P\n"), pVI->pState);
  1814. // Insert the intance to the keyboard list
  1815. if (DeviceType == DI_DeviceKeyboard)
  1816. {
  1817. if (!g_pKbdDevInstList)
  1818. {
  1819. // This is the first instance
  1820. pDevInst->pLink = NULL;
  1821. pDevInst->pPrevLink = NULL;
  1822. InterlockedExchangePointer(&g_pKbdDevInstList, pDevInst);
  1823. } else
  1824. {
  1825. // Insert this instance to the beginning of the list
  1826. pDevInst->pPrevLink = NULL;
  1827. pDevInst->pLink = g_pKbdDevInstList;
  1828. InterlockedExchangePointer(&g_pKbdDevInstList->pPrevLink, pDevInst);
  1829. InterlockedExchangePointer(&g_pKbdDevInstList, pDevInst);
  1830. }
  1831. } else
  1832. {
  1833. // Insert this instance to the mouse list
  1834. if (!g_pMouDevInstList)
  1835. {
  1836. // This is the first instance
  1837. pDevInst->pLink = NULL;
  1838. pDevInst->pPrevLink = NULL;
  1839. InterlockedExchangePointer(&g_pMouDevInstList, pDevInst);
  1840. } else
  1841. {
  1842. // Insert this instance to the beginning of the list
  1843. pDevInst->pPrevLink = NULL;
  1844. pDevInst->pLink = g_pMouDevInstList;
  1845. InterlockedExchangePointer(&g_pMouDevInstList->pPrevLink, pDevInst);
  1846. InterlockedExchangePointer(&g_pMouDevInstList, pDevInst);
  1847. }
  1848. }
  1849. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1850. ReportError(_T("New instance = 0x%P\n"), pDevInst);
  1851. *ppInstanceHandle = pVIUser;
  1852. }
  1853. __except(EXCEPTION_EXECUTE_HANDLER)
  1854. {
  1855. // MmProbeAndLockPages failed
  1856. bFailed = TRUE;
  1857. IoFreeMdl(pDevInst->pMdlForState);
  1858. return STATUS_INSUFFICIENT_RESOURCES;
  1859. }
  1860. }
  1861. __finally
  1862. {
  1863. if (bFailed)
  1864. {
  1865. TRACE(_T("Create failed\n"));
  1866. if (pDevInst->pState)
  1867. {
  1868. TRACE(_T("Freeing pState"));
  1869. ExFreePool(pDevInst->pState);
  1870. }
  1871. if (pDevInst->pExtra)
  1872. {
  1873. TRACE(_T("Freeing pExtra"));
  1874. ExFreePool(pDevInst->pExtra);
  1875. }
  1876. // Free instance memory
  1877. ExFreePool(pDevInst);
  1878. }
  1879. }
  1880. return STATUS_SUCCESS;
  1881. }
  1882. NTSTATUS DI_CreateKeyboardInstance(PSYSDEVICEFORMAT pSysDevFormat, UCHAR *pbTranslationTable, void **ppInstanceHandle)
  1883. {
  1884. NTSTATUS status;
  1885. BOOLEAN bFailed = FALSE;
  1886. LPDI_DEVINSTANCE pDevInst;
  1887. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1888. ReportError(_T("DI_CreateKeyboardInstance(0x%P, "), pSysDevFormat);
  1889. ReportError(_T("0x%P, "), pbTranslationTable);
  1890. ReportError(_T("0x%P)\n"), ppInstanceHandle);
  1891. status = DI_CreateInstanceHelper(pSysDevFormat, ppInstanceHandle, DI_DeviceKeyboard);
  1892. if (status) return status;
  1893. pDevInst = GetDevInstFromUserVxdInst(*ppInstanceHandle);
  1894. __try
  1895. {
  1896. // Allocate memory to hold the translation table
  1897. if (pbTranslationTable)
  1898. {
  1899. pDevInst->pExtra = DI_ExAllocatePool(PagedPool, sizeof(UCHAR) * 256);
  1900. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1901. ReportError(_T("Translation table at 0x%P\n"), pDevInst->pExtra);
  1902. if (!pDevInst->pExtra)
  1903. {
  1904. bFailed = TRUE;
  1905. return STATUS_INSUFFICIENT_RESOURCES;
  1906. }
  1907. RtlMoveMemory(pDevInst->pExtra, pbTranslationTable, sizeof(UCHAR) * 256);
  1908. }
  1909. }
  1910. __finally
  1911. {
  1912. if (bFailed)
  1913. DI_DestroyInstance(*ppInstanceHandle);
  1914. }
  1915. return STATUS_SUCCESS;
  1916. }
  1917. NTSTATUS DI_CreateMouseInstance(PSYSDEVICEFORMAT pSysDevFormat, void **ppInstanceHandle)
  1918. {
  1919. NTSTATUS status;
  1920. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1921. ReportError(_T("DI_CreateMouseInstance(0x%P, "), pSysDevFormat);
  1922. ReportError(_T("0x%P)\n"), ppInstanceHandle);
  1923. status = DI_CreateInstanceHelper(pSysDevFormat, ppInstanceHandle, DI_DeviceMouse);
  1924. if (status) return status;
  1925. return STATUS_SUCCESS;
  1926. }
  1927. NTSTATUS DI_DestroyInstance(PVXDINSTANCE pVI)
  1928. {
  1929. LPDI_DEVINSTANCE pDevInst = GetDevInstFromUserVxdInst(pVI);
  1930. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1931. ReportError(_T("DI_DestroyInstance(0x%P)\n"), pVI);
  1932. ReportError(_T(" DEVINSTANCE at 0x%P\n"), pDevInst);
  1933. // Dereference the event pointer so the resource can be freed.
  1934. if (pDevInst->pEvent)
  1935. {
  1936. ObDereferenceObject(pDevInst->pEvent);
  1937. pDevInst->pEvent = NULL;
  1938. }
  1939. // If there is a data format, destroy it.
  1940. if (pDevInst->pulOffsets)
  1941. ExFreePool(pDevInst->pulOffsets);
  1942. // Remove it from the global list
  1943. if (pDevInst->pLink)
  1944. pDevInst->pLink->pPrevLink = pDevInst->pPrevLink;
  1945. if (pDevInst->pPrevLink)
  1946. pDevInst->pPrevLink->pLink = pDevInst->pLink;
  1947. // If we are the first instance, the global list will now begin at the next instance.
  1948. // Note that we check for both the keyboard and mouse lists anyway, but only one of these IFs
  1949. // will satisfy since an instance cannot be in both lists.
  1950. if (g_pKbdDevInstList == pDevInst)
  1951. g_pKbdDevInstList = pDevInst->pLink;
  1952. if (g_pMouDevInstList == pDevInst)
  1953. g_pMouDevInstList = pDevInst->pLink;
  1954. // Clean up for state buffer
  1955. if (pDevInst->pState)
  1956. {
  1957. MmUnmapLockedPages(pDevInst->pVI->pState, pDevInst->pMdlForState);
  1958. IoFreeMdl(pDevInst->pMdlForState);
  1959. ExFreePool(pDevInst->pState);
  1960. }
  1961. if (pDevInst->pBuffer) ExFreePool(pDevInst->pBuffer);
  1962. if (pDevInst->pExtra) ExFreePool(pDevInst->pExtra);
  1963. // Now unlock the memory for VI
  1964. MmUnmapLockedPages(pVI, pDevInst->pMdlForVI);
  1965. IoFreeMdl(pDevInst->pMdlForVI);
  1966. ExFreePool(pDevInst->pVI);
  1967. ExFreePool(pDevInst);
  1968. return STATUS_SUCCESS;
  1969. }
  1970. NTSTATUS DI_AcquireInstance(LPDI_DEVINSTANCE pDevInst)
  1971. {
  1972. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1973. ReportError(_T("DI_AcquireInstance(0x%P)\n"), pDevInst);
  1974. // Synchronize with the current key state
  1975. if (pDevInst->pDev->DeviceType == FILE_DEVICE_KEYBOARD)
  1976. {
  1977. ReportError(_T("Copying %u bytes\n"), sizeof(UCHAR) * 256);
  1978. RtlCopyMemory(pDevInst->pState, ((PDEVICE_EXTENSION)pDevInst->pDev->DeviceExtension)->arbKbdState, sizeof(UCHAR) * 256);
  1979. }
  1980. else
  1981. {
  1982. ReportError(_T("Copying %u bytes\n"), sizeof(DIMOUSESTATE_INT));
  1983. RtlCopyMemory(pDevInst->pState, &((PDEVICE_EXTENSION)pDevInst->pDev->DeviceExtension)->MouseState, sizeof(DIMOUSESTATE_INT));
  1984. }
  1985. pDevInst->pVI->fl |= VIFL_ACQUIRED;
  1986. return STATUS_SUCCESS;
  1987. }
  1988. NTSTATUS DI_UnacquireInstance(LPDI_DEVINSTANCE pDevInst)
  1989. {
  1990. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1991. ReportError(_T("DI_UnaquireInstance(0x%P)\n"), pDevInst);
  1992. pDevInst->pVI->fl &= ~VIFL_ACQUIRED;
  1993. return STATUS_SUCCESS;
  1994. }
  1995. NTSTATUS DI_SetBufferSize(LPDI_DEVINSTANCE pDevInst, ULONG ulSize)
  1996. {
  1997. DIDEVICEOBJECTDATA_DX3 *pNewBuffer;
  1998. PVOID pOldBuffer;
  1999. PMDL pOldMdlForBuffer;
  2000. PVOID pOldUserBuffer;
  2001. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  2002. ReportError(_T("DI_SetBufferSize(0x%P, "), pDevInst);
  2003. ReportError(_T("%u)\n"), ulSize);
  2004. if (!ulSize)
  2005. {
  2006. // If there is a buffer, free it.
  2007. if (pDevInst->pBuffer)
  2008. {
  2009. pOldBuffer = pDevInst->pBuffer;
  2010. MmUnmapLockedPages(pDevInst->pVI->pBuffer, pDevInst->pMdlForBuffer);
  2011. IoFreeMdl(pDevInst->pMdlForBuffer);
  2012. pDevInst->pMdlForBuffer = NULL;
  2013. pDevInst->pVI->pBuffer = // User mode pointers
  2014. pDevInst->pVI->pEnd =
  2015. pDevInst->pVI->pHead =
  2016. pDevInst->pVI->pTail = NULL;
  2017. InterlockedExchangePointer(&pDevInst->pBuffer, NULL); // Kernel mode pointers
  2018. InterlockedExchangePointer(&pDevInst->pEnd, NULL);
  2019. InterlockedExchangePointer(&pDevInst->pHead, NULL);
  2020. InterlockedExchangePointer(&pDevInst->pTail, NULL);
  2021. ExFreePool(pOldBuffer);
  2022. }
  2023. pDevInst->ulBufferSize = 0;
  2024. return STATUS_SUCCESS;
  2025. }
  2026. // First thing we do is see if we can get the new buffer
  2027. pNewBuffer = DI_ExAllocatePool(PagedPool, sizeof(DIDEVICEOBJECTDATA_DX3) * ulSize);
  2028. if (!pNewBuffer)
  2029. return STATUS_INSUFFICIENT_RESOURCES; // If we can't, exit without changing anything.
  2030. // Lock and map the buffer for DLL's access
  2031. pDevInst->pMdlForBuffer = IoAllocateMdl(pNewBuffer, sizeof(DIDEVICEOBJECTDATA_DX3) * ulSize, FALSE, FALSE, NULL);
  2032. __try
  2033. {
  2034. MmProbeAndLockPages(pDevInst->pMdlForBuffer, KernelMode, IoReadAccess);
  2035. }
  2036. __except(EXCEPTION_EXECUTE_HANDLER)
  2037. {
  2038. // MmProbeAndLockPages failed
  2039. IoFreeMdl(pDevInst->pMdlForBuffer);
  2040. ExFreePool(pNewBuffer);
  2041. return STATUS_INSUFFICIENT_RESOURCES;
  2042. }
  2043. // These don't need to be protected by InterlockedXXX since only user mode code accesses them.
  2044. pOldUserBuffer = pDevInst->pVI->pBuffer;
  2045. pDevInst->pVI->pBuffer = MmMapLockedPages(pDevInst->pMdlForBuffer, UserMode);
  2046. pDevInst->pVI->pEnd = pDevInst->pVI->pBuffer + ulSize;
  2047. pDevInst->pVI->pHead = pDevInst->pVI->pTail = pDevInst->pVI->pBuffer;
  2048. RtlZeroMemory(pNewBuffer, sizeof(DIDEVICEOBJECTDATA_DX3) * ulSize); // Initialize the buffer with 0s
  2049. pOldBuffer = pDevInst->pBuffer;
  2050. pOldMdlForBuffer = pDevInst->pMdlForBuffer;
  2051. // Initialize the pointers
  2052. InterlockedExchange(&pDevInst->ulBufferSize, ulSize);
  2053. InterlockedExchangePointer(&pDevInst->pEnd, pNewBuffer + ulSize);
  2054. InterlockedExchangePointer(&pDevInst->pTail, pNewBuffer);
  2055. InterlockedExchangePointer(&pDevInst->pHead, pNewBuffer);
  2056. InterlockedExchangePointer(&pDevInst->pBuffer, pNewBuffer);
  2057. // If there is already a buffer, free it.
  2058. if (pOldBuffer)
  2059. {
  2060. MmUnmapLockedPages(pOldUserBuffer, pOldMdlForBuffer);
  2061. IoFreeMdl(pOldMdlForBuffer);
  2062. ExFreePool(pOldBuffer);
  2063. }
  2064. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  2065. // ReportError(_T("pBuffer at 0x%P\n"), pDevInst->pBuffer);
  2066. // ReportError(_T("pEnd at 0x%P\n"), pDevInst->pEnd);
  2067. // ReportError(_T("pHead at 0x%P\n"), pDevInst->pHead);
  2068. // ReportError(_T("pTail at 0x%P\n"), pDevInst->pTail);
  2069. // ReportError(_T("User pBuffer at 0x%P\n"), pDevInst->pVI->pBuffer);
  2070. // ReportError(_T("User pEnd at 0x%P\n"), pDevInst->pVI->pEnd);
  2071. // ReportError(_T("User pHead at 0x%P\n"), pDevInst->pVI->pHead);
  2072. // ReportError(_T("User pTail at 0x%P\n"), pDevInst->pVI->pTail);
  2073. return STATUS_SUCCESS;
  2074. }
  2075. NTSTATUS DI_SetNotifyHandle(LPDI_DEVINSTANCE pDevInst, PVOID pEvent)
  2076. {
  2077. NTSTATUS status;
  2078. PVOID pNewPointer = NULL;
  2079. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  2080. ReportError(_T("DI_SetNotifyHandle(0x%P, "), pDevInst);
  2081. ReportError(_T("0x%P)\n"), pEvent);
  2082. // Obtain a kernel mode pointer to the passed event and save it.
  2083. if (pEvent)
  2084. {
  2085. status = ObReferenceObjectByHandle(pEvent, STANDARD_RIGHTS_WRITE, *ExEventObjectType,
  2086. KernelMode, &pNewPointer, NULL);
  2087. if (status != STATUS_SUCCESS)
  2088. return status;
  2089. }
  2090. // If a previous handle is passed to us, we must dereference it first.
  2091. if (pDevInst->pEvent)
  2092. ObDereferenceObject(pDevInst->pEvent);
  2093. pDevInst->pEvent = pNewPointer;
  2094. return STATUS_SUCCESS;
  2095. }
  2096. NTSTATUS DI_SetDataFormat(LPDI_DEVINSTANCE pDevInst, ULONG ulSize, ULONG *pulDataFormat)
  2097. {
  2098. ULONG *pulNewFormat = NULL;
  2099. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  2100. ReportError(_T("DI_SetDataFormat(0x%P, "), pDevInst);
  2101. ReportError(_T("%u, "), ulSize);
  2102. ReportError(_T("0x%P)\n"), pulDataFormat);
  2103. // Allocate memory to store the new format
  2104. if (pulDataFormat)
  2105. {
  2106. pulNewFormat = DI_ExAllocatePool(PagedPool, ulSize * sizeof(ULONG));
  2107. if (!pulNewFormat)
  2108. return STATUS_INSUFFICIENT_RESOURCES;
  2109. RtlMoveMemory(pulNewFormat, pulDataFormat, ulSize * sizeof(ULONG));
  2110. }
  2111. #ifdef DBG
  2112. {
  2113. ULONG i;
  2114. TRACE(_T("******************\n"));
  2115. for (i = 0; i < ulSize; ++i)
  2116. ReportError(_T("*** %10d ***\n"), pulDataFormat[i]);
  2117. TRACE(_T("******************\n"));
  2118. }
  2119. #endif
  2120. // If there is an existing data format, destroy it.
  2121. if (pDevInst->pulOffsets)
  2122. ExFreePool(pDevInst->pulOffsets);
  2123. pDevInst->pulOffsets = pulNewFormat;
  2124. pDevInst->ulDataFormatSize = ulSize;
  2125. return STATUS_SUCCESS;
  2126. }