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

915 lines
29 KiB

  1. // @doc
  2. /*******************************************************************
  3. *
  4. * @module SWVKBD.cpp |
  5. *
  6. * Implementation of the SideWinder Virtual Keyboard
  7. *
  8. * History
  9. * ----------------------------------------------------------
  10. * Mitchell S. Dernis Original
  11. *
  12. * (c) 1986-1998 Microsoft Corporation. All right reserved.
  13. *
  14. * @topic SWVKBD |
  15. * This module implements the SideWinder Virtual Keyboard
  16. * which is used to stuff keystrokes from Kernel Mode.
  17. *
  18. **********************************************************************/
  19. #define __DEBUG_MODULE_IN_USE__ GCK_SWVKBD_C
  20. //#pragma message (DDK_LIB_PATH)
  21. extern "C" {
  22. #include <WDM.H>
  23. #include "GckShell.h"
  24. #include "debug.h"
  25. #include "hidtoken.h"
  26. #include "hidusage.h"
  27. #include "hidport.h"
  28. #include "remlock.h"
  29. DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL));
  30. }
  31. #include "SWVBENUM.h"
  32. #include "SWVKBD.h"
  33. #include <stdio.h>
  34. // PDRIVER_OBJECT g_pDriverObject;
  35. //
  36. // These keep track of the next instance number
  37. // g_ulInstanceBits is a bit field. A device holds an instance number
  38. // by setting a bit, and clearing when it is destroyed. This only works
  39. // for the first 32 devices (i.e. 99.99% of the time). The 33rd device
  40. // goes into the overflow. Instance numbers in the overflow are not recovered.
  41. // With 33 devices plugged in, plugging and unplugging the 33rd device will cause
  42. // the instances of devices in the registry to profilerate. No real harm is done,
  43. // it is just ugly, but this is a highly unlikely scenario.
  44. //
  45. static ULONG g_ulInstanceBits;
  46. static ULONG g_ulInstanceOverflow;
  47. //---------------------------------------------------------------------
  48. // Tables that define device characteristics and/or entry points
  49. //---------------------------------------------------------------------
  50. // Service table used by Virtual Bus Module to call into Virtual Keyboard
  51. SWVB_DEVICE_SERVICE_TABLE VKbdServiceTable =
  52. {
  53. &GCK_VKBD_CreateProc,
  54. &GCK_VKBD_CloseProc,
  55. &GCK_VKBD_ReadProc,
  56. &GCK_VKBD_WriteProc,
  57. &GCK_VKBD_IoctlProc,
  58. &GCK_VKBD_StartProc,
  59. &GCK_VKBD_StopProc,
  60. &GCK_VKBD_RemoveProc
  61. };
  62. // Constants describing device
  63. #define VKBD_VERSION 0x0100
  64. #define VKBD_COUNTRY 0x0000
  65. #define VKBD_DESCRIPTOR_COUNT 0x0001
  66. #define VKBD_PRODUCT_ID 0x00FA //BUGBUGBUG I made this up, I need to request through Rob Walker
  67. //BUGBUGBUG to permanently allocate one for this purpose.
  68. //
  69. // This is more or less copied from the HID spec Version 1 - Final, except that
  70. // we left off the reserved byte and the LED's , why should a virtual keyboard
  71. // need to have virtual LED's. I can conceive of a real one without them.
  72. //
  73. static UCHAR VKBD_ReportDescriptor[] =
  74. {
  75. 0x05,0x01, //Usage Page (Generic Desktop)
  76. 0x09,0x06, //Usage (Keyboard)
  77. 0xA1,0x01, //Collection (Application)
  78. 0x05,0x07, //Usage Page (Key Codes)
  79. 0x19,0xE0, //Usage Minimum (224) - from Left Control
  80. 0x29,0xE7, //Usage Maximum (231) - to Right GUI
  81. 0x15,0x00, //Logical Minimum (0)
  82. 0x25,0x01, //Logical Maximum (1)
  83. 0x75,0x01, //Report Size (1)
  84. 0x95,0x08, //Report Count (8)
  85. 0x81,0x02, //Input (Data, Variable, Absolute) - Modifier Byte
  86. 0x95,0x05, //Report Count(5)
  87. 0x75,0x01, //Report Size (1)
  88. 0x05,0x08, //Usage Page (LEDs)
  89. 0x19,0x01, //Usage Minimum (1)
  90. 0x29,0x05, //Usage Maximum (5)
  91. 0x91,0x02, //Output (Data, Vartiable, Absolute) - LED Indicator lights
  92. 0x95,0x01, //Report Count(1)
  93. 0x75,0x03, //Report Size (3)
  94. 0x91,0x01, //Output (Constant) - Padding for LED output report, to bring it up to a byte.
  95. 0x75,0x08, //Report Size (8)
  96. 0x95, GCK_VKBD_MAX_KEYSTROKES, //Report Count (GCK_VKBD_MAX_KEYSTROKES)
  97. 0x15,0x00, //Logical Minimum (0)
  98. 0x25,0xFF, //Logical Maximum (1)
  99. 0x05,0x07, //Usage Page (Key Codes)
  100. 0x19,0x00, //Usage Minimum (0) - from '1' ???
  101. 0x29,0xFF, //Usage Maximum (255) - ???
  102. 0x81,0x00, //Input (Data, Array) - Key arrays
  103. 0xC0 //End Collection
  104. };
  105. static HID_DESCRIPTOR VKBD_DeviceDescriptor =
  106. {
  107. sizeof (HID_DESCRIPTOR),
  108. HID_HID_DESCRIPTOR_TYPE,
  109. VKBD_VERSION,
  110. VKBD_COUNTRY,
  111. VKBD_DESCRIPTOR_COUNT,
  112. {HID_REPORT_DESCRIPTOR_TYPE,
  113. sizeof(VKBD_ReportDescriptor)}
  114. };
  115. /***********************************************************************************
  116. **
  117. ** NTSTATUS GCK_VKBD_DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
  118. **
  119. ** @func Stows the Driver Object for later
  120. **
  121. ** @rdesc STATUS_SUCCESS if it opens.
  122. **
  123. *************************************************************************************/
  124. NTSTATUS
  125. GCK_VKBD_DriverEntry(
  126. IN PDRIVER_OBJECT pDriverObject, //@parm Driver Object
  127. IN PUNICODE_STRING pRegistryPath //@parm Registry path for this driver
  128. )
  129. {
  130. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_DriverEntry\n"));
  131. UNREFERENCED_PARAMETER(pDriverObject);
  132. UNREFERENCED_PARAMETER(pRegistryPath);
  133. // g_pDriverObject = pDriverObject;
  134. g_ulInstanceBits = 0x0;
  135. g_ulInstanceOverflow = 32; //For 33 and more devices
  136. return STATUS_SUCCESS;
  137. }
  138. /***********************************************************************************
  139. **
  140. ** NTSTATUS GCK_VKBD_Create(OUT PDEVICE_OBJECT *ppDeviceObject)
  141. **
  142. ** @func Creates a new Virtual Keyboard
  143. **
  144. ** @rdesc STATUS_SUCCESS if it opens.
  145. **
  146. *************************************************************************************/
  147. NTSTATUS
  148. GCK_VKBD_Create
  149. (
  150. OUT PDEVICE_OBJECT *ppDeviceObject //@parm [out] Device Object of new virtual keyboard
  151. )
  152. {
  153. NTSTATUS NtStatus;
  154. SWVB_EXPOSE_DATA SwvbExposeData;
  155. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_Create *ppDeviceObject = 0x%0.8x\n", *ppDeviceObject));
  156. //Fill out SWVB_EXPOSE_DATA structure
  157. SwvbExposeData.pmwszDeviceId=L"SideWinderVirtualKeyboard\0\0";
  158. SwvbExposeData.pServiceTable = &VKbdServiceTable;
  159. SwvbExposeData.ulDeviceExtensionSize = sizeof(GCK_VKBD_EXT);
  160. SwvbExposeData.ulInitContext = (ULONG)ppDeviceObject;
  161. SwvbExposeData.pfnInitDevice = &GCK_VKBD_Init;
  162. //Get the instance ID
  163. ULONG ulBitMask;
  164. ULONG ulIndex;
  165. for(ulIndex = 0, ulBitMask = 1; ulIndex < 32; ulBitMask <<= 1, ulIndex++)
  166. {
  167. if(ulBitMask & ~g_ulInstanceBits)
  168. {
  169. g_ulInstanceBits |= ulBitMask;
  170. SwvbExposeData.ulInstanceNumber = ulIndex;
  171. break;
  172. }
  173. }
  174. if(32 == ulIndex)
  175. {
  176. SwvbExposeData.ulInstanceNumber = g_ulInstanceOverflow++;
  177. }
  178. //Call virtual bus to expose virtual keyboard
  179. NtStatus=GCK_SWVB_Expose(&SwvbExposeData);
  180. return NtStatus;
  181. }
  182. /***********************************************************************************
  183. **
  184. ** NTSTATUS GCK_VKBD_Init( IN PDEVICE_OBJECT pDeviceObject, IN ULONG ulInitContext)
  185. **
  186. ** @func Callback for Initializing new device object. The ulInitContext
  187. ** is a pointer to a pointer to a device object, so that we can pass
  188. ** the pointer to the device object back to the caller of create.
  189. ** @rdesc STATUS_SUCCESS.
  190. **
  191. *************************************************************************************/
  192. NTSTATUS
  193. GCK_VKBD_Init
  194. (
  195. IN PDEVICE_OBJECT pDeviceObject,
  196. IN ULONG ulInitContext
  197. )
  198. {
  199. PGCK_VKBD_EXT pDevExt;
  200. PDEVICE_OBJECT *ppSaveDeviceObject;
  201. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_Init pDeviceObject = 0x%0.8x\n", pDeviceObject));
  202. //Create sent us a pointer to a PDEVICE_OBJECT in which to return the new device object
  203. ppSaveDeviceObject = (PDEVICE_OBJECT *)ulInitContext;
  204. *ppSaveDeviceObject = pDeviceObject;
  205. //Get out part of the device extension
  206. pDevExt = (PGCK_VKBD_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  207. //Mark device as stopped
  208. pDevExt->ucDeviceState= VKBD_STATE_STOPPED;
  209. //Mark the circular buffer as empty
  210. pDevExt->usReportBufferPos=0;
  211. pDevExt->usReportBufferCount=0;
  212. //Initialize locks
  213. GCK_InitRemoveLock(&pDevExt->RemoveLock, "SWVKBD_LOCK");
  214. //Initialize IrpQueue
  215. pDevExt->IrpQueue.Init( CGuardedIrpQueue::CANCEL_IRPS_ON_DELETE |
  216. CGuardedIrpQueue::PRESERVE_QUEUE_ORDER,
  217. (CGuardedIrpQueue::PFN_DEC_IRP_COUNT)GCK_DecRemoveLock,
  218. &pDevExt->RemoveLock);
  219. return STATUS_SUCCESS;
  220. }
  221. /***********************************************************************************
  222. *
  223. ** NTSTATUS GCK_VKBD_Close(IN PDEVICE_OBJECT pDeviceObject)
  224. **
  225. ** @func Closes the virtual keyboard (removes it!)
  226. **
  227. ** @rdesc STATUS_SUCCESS on success
  228. **
  229. *************************************************************************************/
  230. NTSTATUS
  231. GCK_VKBD_Close
  232. (
  233. IN PDEVICE_OBJECT pDeviceObject
  234. )
  235. {
  236. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_Close pDeviceObject = 0x%0.8x\n", pDeviceObject));
  237. //Tell the virtual bus to kill us
  238. return GCK_SWVB_Remove(pDeviceObject);
  239. }
  240. /***********************************************************************************
  241. *
  242. ** NTSTATUS GCK_VKBD_SendReportPacket(IN PDEVICE_OBJECT pDeviceObject)
  243. **
  244. ** @func Stuff a report into the circular buffer, and completes
  245. ** an IRP if one is pending.
  246. **
  247. ** @rdesc STATUS_SUCCESS on success
  248. **
  249. *************************************************************************************/
  250. NTSTATUS
  251. GCK_VKBD_SendReportPacket
  252. (
  253. IN PDEVICE_OBJECT pDeviceObject,
  254. IN PGCK_VKBD_REPORT_PACKET pReportPacket
  255. )
  256. {
  257. USHORT usBufferIndex;
  258. PGCK_VKBD_EXT pDevExt = (PGCK_VKBD_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  259. CShareIrpQueueSpinLock IrpQueueWithSharedSpinLock(&pDevExt->IrpQueue);
  260. //
  261. // Step 1. Stuff new packet into buffer
  262. //
  263. // Acquire Lock to work with buffer
  264. IrpQueueWithSharedSpinLock.Acquire();
  265. //Find position in buffer to stuff at
  266. usBufferIndex = (pDevExt->usReportBufferPos + pDevExt->usReportBufferCount)%GCK_VKBD_STATE_BUFFER_SIZE;
  267. //Copy data
  268. pDevExt->rgReportBuffer[usBufferIndex] = *pReportPacket;
  269. //increment buffer count
  270. if(pDevExt->usReportBufferCount < GCK_VKBD_STATE_BUFFER_SIZE)
  271. {
  272. pDevExt->usReportBufferCount++;
  273. }
  274. else
  275. {
  276. //This assertion means buffer overflow
  277. ASSERT(FALSE);
  278. pDevExt->usReportBufferPos++;
  279. }
  280. //
  281. // Step 2. Get Irp if there is one
  282. //
  283. PIRP pPendingIrp = IrpQueueWithSharedSpinLock.Remove();
  284. if(pPendingIrp)
  285. {
  286. // Copy the data
  287. RtlCopyMemory(
  288. pPendingIrp->UserBuffer,
  289. &pDevExt->rgReportBuffer[pDevExt->usReportBufferPos],
  290. sizeof(GCK_VKBD_REPORT_PACKET)
  291. );
  292. // Adjust buffer pos and count
  293. pDevExt->usReportBufferCount--;
  294. if(pDevExt->usReportBufferCount)
  295. {
  296. pDevExt->usReportBufferPos = (pDevExt->usReportBufferPos++)%GCK_VKBD_STATE_BUFFER_SIZE;
  297. }
  298. }
  299. //We are done with the buffer spin lock
  300. IrpQueueWithSharedSpinLock.Release();
  301. if(pPendingIrp)
  302. {
  303. // Fill out IRP status
  304. pPendingIrp->IoStatus.Information = sizeof(GCK_VKBD_REPORT_PACKET);
  305. pPendingIrp->IoStatus.Status = STATUS_SUCCESS;
  306. IoCompleteRequest(pPendingIrp, IO_NO_INCREMENT);
  307. //We just completed an IRP decrement the count
  308. GCK_DecRemoveLock(&pDevExt->RemoveLock);
  309. }
  310. //All done
  311. return STATUS_SUCCESS;
  312. }
  313. /***********************************************************************************
  314. *
  315. ** NTSTATUS GCK_VKBD_ReadReport(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
  316. **
  317. ** @func If there is data in the keyboard buffer, completes the IRP
  318. ** Otherwise, queues it, and set the idle timer.
  319. **
  320. ** @rdesc STATUS_SUCCESS if read, STATUS_PENDING if waiting.
  321. **
  322. *************************************************************************************/
  323. NTSTATUS
  324. GCK_VKBD_ReadReport
  325. (
  326. IN PDEVICE_OBJECT pDeviceObject,
  327. IN PIRP pIrp
  328. )
  329. {
  330. PGCK_VKBD_EXT pDevExt;
  331. PIO_STACK_LOCATION pIrpStack;
  332. KIRQL OldIrql;
  333. GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_VKBD_ReadReport pDeviceObject = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp));
  334. //
  335. // Validate buffer size, because we do this the first time we see the IRP
  336. // we never need to worry about checking it again.
  337. //
  338. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  339. if(pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GCK_VKBD_REPORT_PACKET))
  340. {
  341. pIrp->IoStatus.Information = 0;
  342. pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  343. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  344. return STATUS_BUFFER_TOO_SMALL;
  345. }
  346. // Get device extension
  347. pDevExt = (PGCK_VKBD_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  348. //Make an IRP queue accessor to share spin lock
  349. CShareIrpQueueSpinLock IrpQueueWithSharedSpinLock(&pDevExt->IrpQueue);
  350. // Count the IRP we are working on
  351. GCK_IncRemoveLock(&pDevExt->RemoveLock);
  352. // Acquire Lock to work with mouse buffer and Irp Queue
  353. IrpQueueWithSharedSpinLock.Acquire();
  354. // If there is data, complete the IRP
  355. if( pDevExt->usReportBufferCount)
  356. {
  357. // Copy the data
  358. RtlCopyMemory(
  359. pIrp->UserBuffer,
  360. &pDevExt->rgReportBuffer[pDevExt->usReportBufferPos],
  361. sizeof(GCK_VKBD_REPORT_PACKET)
  362. );
  363. // Adjust buffer pos and count
  364. pDevExt->usReportBufferCount--;
  365. if(pDevExt->usReportBufferCount)
  366. {
  367. pDevExt->usReportBufferPos = (pDevExt->usReportBufferPos++)%GCK_VKBD_STATE_BUFFER_SIZE;
  368. }
  369. //We are done with the buffer spin lock
  370. IrpQueueWithSharedSpinLock.Release();
  371. // Fill out IRP status
  372. pIrp->IoStatus.Information = sizeof(GCK_VKBD_REPORT_PACKET);
  373. pIrp->IoStatus.Status = STATUS_SUCCESS;
  374. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  375. //We just completed an IRP decrement the count
  376. GCK_DecRemoveLock(&pDevExt->RemoveLock);
  377. }
  378. else
  379. // There is no data, so queue the IRP.
  380. {
  381. return IrpQueueWithSharedSpinLock.AddAndRelease(pIrp);
  382. }
  383. //We completed the IRP and all is fine
  384. return STATUS_SUCCESS;
  385. }
  386. /***********************************************************************************
  387. *
  388. ** NTSTATUS GCK_VKBD_WriteToFakeLEDs(IN PIRP pIrp)
  389. **
  390. ** @func In the context of any device object (hence not input parameter),
  391. ** this function handle IOCTL_HID_WRITE_REPORT. The only output
  392. ** that virtual keyboards support is report ID 0 (the LED indicators)
  393. ** and one byte of data is expected. We verify this set the
  394. ** IoStatus.Information and return the correct error code. The IOCTL
  395. ** dispatch set IoStatus.Status and completes the IRP.
  396. **
  397. ** @rdesc STATUS_SUCCESS if OK, STATUS_INVALID_DEVICE_REQUEST if not Report ID 0
  398. ** STATUS_INVALID_PARAMETER if the buffer is the wrong size.
  399. **
  400. *************************************************************************************/
  401. NTSTATUS GCK_VKBD_WriteToFakeLEDs
  402. (
  403. IN PIRP pIrp // @parm [in/out] IRP for IOCTL_HID_WRITE_REPORT
  404. )
  405. {
  406. HID_XFER_PACKET *pHidXferPacket;
  407. //We haven't copied anything yet
  408. pIrp->IoStatus.Information = 0;
  409. // Cast UserBuffer to an XferPacket (this is what it is supposed to be.
  410. // We don't verify the IOCTL code, because a good and trusted friend (GCK_VKBD_Ioctl)
  411. // sent this IRP here, and is inefficient, not to mention painful, to check again.
  412. pHidXferPacket = (PHID_XFER_PACKET)pIrp->UserBuffer;
  413. //Verify Report ID
  414. if(0 /* Report ID of LED report */ != pHidXferPacket->reportId)
  415. {
  416. return STATUS_INVALID_DEVICE_REQUEST;
  417. }
  418. //Verify Repot Buffer Length
  419. if(1 /*1 byte - size of LED report*/ != pHidXferPacket->reportBufferLen)
  420. {
  421. return STATUS_INVALID_PARAMETER;
  422. }
  423. //Report that we received the one byte and set the virtual LED's accordingly
  424. pIrp->IoStatus.Information = 1;
  425. return STATUS_SUCCESS;
  426. }
  427. /***********************************************************************************
  428. **
  429. ** NTSTATUS GCK_VKBD_CloseProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  430. **
  431. ** @func Handles the the IRP_MJ_CLOSE request sent from SWVB. We don't
  432. ** need to control anything, so we just succeed.
  433. **
  434. ** @devnote This should never actually be called with the HIDSWVD.SYS mini-driver
  435. ** in the chain. Good question for the review is if we need this.
  436. **
  437. ** @rdesc STATUS_SUCCESS
  438. **
  439. *************************************************************************************/
  440. NTSTATUS
  441. GCK_VKBD_CloseProc
  442. (
  443. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  444. IN PIRP pIrp //@parm [in\out] IRP to handle
  445. )
  446. {
  447. //We don't control open and close, so just succeed
  448. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_CloseProc\n"));
  449. UNREFERENCED_PARAMETER(pDeviceObject);
  450. pIrp->IoStatus.Status = STATUS_SUCCESS;
  451. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  452. return STATUS_SUCCESS;
  453. }
  454. /***********************************************************************************
  455. **
  456. ** NTSTATUS GCK_VKBD_CreateProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  457. **
  458. ** @func Handles the the IRP_MJ_CREATE request sent from SWVB. We don't
  459. ** need to control anything, so we just succeed.
  460. **
  461. ** @devnote This should never actually be called with the HIDSWVD.SYS mini-driver
  462. ** in the chain. Good question for the review is if we need this.
  463. **
  464. ** @rdesc STATUS_SUCCESS
  465. **
  466. *************************************************************************************/
  467. NTSTATUS
  468. GCK_VKBD_CreateProc
  469. (
  470. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  471. IN PIRP pIrp //@parm [in\out] IRP to handle
  472. )
  473. {
  474. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_CreateProc\n"));
  475. UNREFERENCED_PARAMETER(pDeviceObject);
  476. pIrp->IoStatus.Status = STATUS_SUCCESS;
  477. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  478. return STATUS_SUCCESS;
  479. }
  480. /***********************************************************************************
  481. **
  482. ** NTSTATUS GCK_VKBD_IoctlProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  483. **
  484. ** @func Handles the the IRP_MJ_INTERNAL_IOCTL and IRP_MJ_IOCTL requests sent from SWVB.
  485. ** Trivial IRPs are handle here, others are delegated.
  486. **
  487. ** @rdesc STATUS_SUCCESS, and various errors
  488. **
  489. *************************************************************************************/
  490. NTSTATUS
  491. GCK_VKBD_IoctlProc
  492. (
  493. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  494. IN PIRP pIrp //@parm [in\out] IRP to handle
  495. )
  496. {
  497. NTSTATUS NtStatus;
  498. PIO_STACK_LOCATION pIrpStack;
  499. GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_VKBD_IoctlProc\n"));
  500. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  501. pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  502. // We complete everything, so the various cases
  503. // fill out status and information, and we complete
  504. // the IRP at the bottom.
  505. switch(pIrpStack->Parameters.DeviceIoControl.IoControlCode)
  506. {
  507. case IOCTL_GET_PHYSICAL_DESCRIPTOR:
  508. pIrp->IoStatus.Information = 0;
  509. NtStatus =STATUS_NOT_SUPPORTED;
  510. break;
  511. case IOCTL_HID_ACTIVATE_DEVICE:
  512. pIrp->IoStatus.Information = 0;
  513. NtStatus = STATUS_SUCCESS;
  514. break;
  515. case IOCTL_HID_DEACTIVATE_DEVICE:
  516. pIrp->IoStatus.Information = 0;
  517. NtStatus = STATUS_SUCCESS;
  518. break;
  519. case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
  520. NtStatus = GCK_VKBD_GetDeviceAttributes(
  521. pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  522. pIrp->UserBuffer,
  523. &pIrp->IoStatus.Information
  524. );
  525. break;
  526. case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
  527. NtStatus = GCK_VKBD_GetDeviceDescriptor(
  528. pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  529. pIrp->UserBuffer,
  530. &pIrp->IoStatus.Information
  531. );
  532. break;
  533. case IOCTL_HID_GET_FEATURE:
  534. pIrp->IoStatus.Information = 0;
  535. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  536. break;
  537. case IOCTL_HID_GET_REPORT_DESCRIPTOR:
  538. NtStatus = GCK_VKBD_GetReportDescriptor(
  539. pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  540. pIrp->UserBuffer,
  541. &pIrp->IoStatus.Information
  542. );
  543. break;
  544. case IOCTL_HID_GET_STRING:
  545. pIrp->IoStatus.Information = 0;
  546. NtStatus = STATUS_NOT_SUPPORTED; //Should we support this?
  547. break;
  548. case IOCTL_HID_READ_REPORT:
  549. // Read report will complete the IRP, or queue as it sees fit, just delegate
  550. return GCK_VKBD_ReadReport(pDeviceObject, pIrp);
  551. case IOCTL_HID_SET_FEATURE:
  552. pIrp->IoStatus.Information = 0;
  553. NtStatus = STATUS_NOT_SUPPORTED;
  554. break;
  555. case IOCTL_HID_WRITE_REPORT:
  556. //
  557. // Fake LED's are the only output we support. The routine verifies that
  558. // this is what is being written to, and that the buffer size is correct
  559. // If this is true, the routine will mark IoStatus.Information to say that
  560. // got the new state and return STATUS_SUCCESS. Otherwise, it will return
  561. // STATUS_INVALID_DEVICE_REQUEST
  562. //
  563. NtStatus = GCK_VKBD_WriteToFakeLEDs(pIrp);
  564. break;
  565. default:
  566. pIrp->IoStatus.Information = 0;
  567. NtStatus = STATUS_NOT_SUPPORTED;
  568. }
  569. pIrp->IoStatus.Status = NtStatus;
  570. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  571. return NtStatus;
  572. }
  573. /***********************************************************************************
  574. **
  575. ** NTSTATUS GCK_VKBD_ReadProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  576. **
  577. ** @func Handles the the IRP_MJ_READ request sent from SWVB. We don't support this.
  578. **
  579. ** @devnote This should never actually be called with the HIDSWVD.SYS mini-driver
  580. ** in the chain. Good question for the review is if we need this.
  581. **
  582. ** @rdesc STATUS_NOT_SUPPORTED
  583. **
  584. *************************************************************************************/
  585. NTSTATUS
  586. GCK_VKBD_ReadProc
  587. (
  588. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  589. IN PIRP pIrp //@parm [in\out] IRP to handle
  590. )
  591. {
  592. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_ReadProc\n"));
  593. UNREFERENCED_PARAMETER(pDeviceObject);
  594. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  595. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  596. return STATUS_NOT_SUPPORTED;
  597. }
  598. /***********************************************************************************
  599. **
  600. ** NTSTATUS GCK_VKBD_StartProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  601. **
  602. ** @func Handles the the IRP_MJ_PNP, IRP_MN_START_DEVICE request sent from SWVB.
  603. ** Just mark that we are started.
  604. **
  605. ** @rdesc STATUS_SUCCESS
  606. **
  607. *************************************************************************************/
  608. NTSTATUS
  609. GCK_VKBD_StartProc
  610. (
  611. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  612. IN PIRP pIrp //@parm [in\out] IRP to handle
  613. )
  614. {
  615. PGCK_VKBD_EXT pDevExt;
  616. UNREFERENCED_PARAMETER(pIrp);
  617. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_StartProc\n"));
  618. // Get device extension
  619. pDevExt = (PGCK_VKBD_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  620. // Mark as started
  621. pDevExt->ucDeviceState = VKBD_STATE_STARTED;
  622. // PnP IRPs are completed by SWVB
  623. return STATUS_SUCCESS;
  624. }
  625. /***********************************************************************************
  626. **
  627. ** NTSTATUS GCK_VKBD_StopProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  628. **
  629. ** @func Handles the the IRP_MJ_PNP, IRP_MN_STOP_DEVICE request sent from SWVB.
  630. ** Just mark that we are stopped.
  631. **
  632. ** @rdesc STATUS_SUCCESS
  633. **
  634. *************************************************************************************/
  635. NTSTATUS
  636. GCK_VKBD_StopProc
  637. (
  638. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  639. IN PIRP pIrp //@parm [in\out] IRP to handle
  640. )
  641. {
  642. PGCK_VKBD_EXT pDevExt;
  643. UNREFERENCED_PARAMETER(pIrp);
  644. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_StopProc\n"));
  645. // Get device extension
  646. pDevExt = (PGCK_VKBD_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  647. // Mark as stopped
  648. pDevExt->ucDeviceState = VKBD_STATE_STOPPED;
  649. // Cancel all I\O
  650. pDevExt->IrpQueue.CancelAll(STATUS_DELETE_PENDING);
  651. // PnP IRP are completed by SWVB
  652. return STATUS_SUCCESS;
  653. }
  654. /***********************************************************************************
  655. **
  656. ** NTSTATUS GCK_VKBD_RemoveProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  657. **
  658. ** @func Handles the the IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE request sent from SWVB.
  659. ** Wait for all outstanding IO to complete before succeeding. We don't
  660. ** delete our device object that is up to SWVB.
  661. **
  662. ** @rdesc STATUS_NOT_SUPPORTED
  663. **
  664. *************************************************************************************/
  665. NTSTATUS
  666. GCK_VKBD_RemoveProc
  667. (
  668. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  669. IN PIRP pIrp //@parm [in\out] IRP to handle
  670. )
  671. {
  672. PGCK_VKBD_EXT pDevExt;
  673. UNREFERENCED_PARAMETER(pIrp);
  674. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_RemoveProc\n"));
  675. // Get device extension
  676. pDevExt = (PGCK_VKBD_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  677. // Mark as Removed
  678. pDevExt->ucDeviceState = VKBD_STATE_REMOVED;
  679. //Clear Instance Bits
  680. ULONG ulInstance = GCK_SWVB_GetInstanceNumber(pDeviceObject);
  681. if(ulInstance < 32)
  682. {
  683. g_ulInstanceBits &= ~(1 << ulInstance);
  684. }
  685. // Remove the BIAS on the RemoveLock and wait for it to go to zero (forever)
  686. return GCK_DecRemoveLockAndWait(&pDevExt->RemoveLock, NULL);
  687. }
  688. /***********************************************************************************
  689. **
  690. ** NTSTATUS GCK_VKBD_WriteProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  691. **
  692. ** @func Handles the the IRP_MJ_WRITE, which we don't support. With HIDSWVD.SYS
  693. ** as the functional driver this should never get called.
  694. **
  695. ** @rdesc STATUS_NOT_SUPPORTED
  696. **
  697. *************************************************************************************/
  698. NTSTATUS
  699. GCK_VKBD_WriteProc
  700. (
  701. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  702. IN PIRP pIrp //@parm [in\out] IRP to handle
  703. )
  704. {
  705. UNREFERENCED_PARAMETER(pDeviceObject);
  706. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_WriteProc\n"));
  707. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  708. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  709. return STATUS_NOT_SUPPORTED;
  710. }
  711. /***********************************************************************************
  712. **
  713. ** NTSTATUS GCK_VKBD_GetDeviceDescriptor(IN ULONG ulBufferLength, OUT PVOID pvUserBuffer,
  714. ** OUT PULONG pulBytesCopied)
  715. **
  716. ** @func Helps handles IOCTL_HID_GET_DEVICE_DESCRIPTOR the data is statically
  717. ** declared at the top of this file.
  718. **
  719. ** @rdesc STATUS_SUCCESS
  720. ** @rdesc STATUS_BUFFER_TOO_SMALL
  721. **
  722. *************************************************************************************/
  723. NTSTATUS
  724. GCK_VKBD_GetDeviceDescriptor
  725. (
  726. IN ULONG ulBufferLength, //@parm [in] Length of User Buffer
  727. OUT PVOID pvUserBuffer, //@parm [out] User Buffer which accepts Device Descriptor
  728. OUT PULONG pulBytesCopied //@parm [out] Size of Device Descriptor Copied
  729. )
  730. {
  731. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_GetDeviceDescriptor\n"));
  732. // Check buffer size
  733. if(ulBufferLength < sizeof(VKBD_DeviceDescriptor))
  734. {
  735. *pulBytesCopied = 0;
  736. return STATUS_BUFFER_TOO_SMALL;
  737. }
  738. // Copy bytes
  739. RtlCopyMemory(pvUserBuffer, &VKBD_DeviceDescriptor, sizeof(VKBD_DeviceDescriptor));
  740. // Record number of bytes copied
  741. *pulBytesCopied = sizeof(VKBD_DeviceDescriptor);
  742. // Return Success
  743. return STATUS_SUCCESS;
  744. }
  745. /***********************************************************************************
  746. **
  747. ** NTSTATUS GCK_VKBD_GetReportDescriptor(IN ULONG ulBufferLength, OUT PVOID pvUserBuffer,
  748. ** OUT PULONG pulBytesCopied)
  749. **
  750. ** @func Helps handles IOCTL_HID_GET_REPORT_DESCRIPTOR the data is statically
  751. ** declared at the top of this file.
  752. **
  753. ** @rdesc STATUS_SUCCESS
  754. ** @rdesc STATUS_BUFFER_TOO_SMALL
  755. **
  756. *************************************************************************************/
  757. NTSTATUS
  758. GCK_VKBD_GetReportDescriptor
  759. (
  760. IN ULONG ulBufferLength, //@parm [in] Length of User Buffer
  761. OUT PVOID pvUserBuffer, //@parm [out] User Buffer which accepts Report Descriptor
  762. OUT PULONG pulBytesCopied //@parm [out] Size of Report Descriptor Copied
  763. )
  764. {
  765. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_GetReportDescriptor\n"));
  766. // Check buffer size
  767. if(ulBufferLength < sizeof(VKBD_ReportDescriptor))
  768. {
  769. *pulBytesCopied = 0;
  770. return STATUS_BUFFER_TOO_SMALL;
  771. }
  772. // Copy bytes
  773. RtlCopyMemory(pvUserBuffer, &VKBD_ReportDescriptor, sizeof(VKBD_ReportDescriptor));
  774. // Record number of bytes copied
  775. *pulBytesCopied = sizeof(VKBD_ReportDescriptor);
  776. // Return Success
  777. return STATUS_SUCCESS;
  778. }
  779. /***********************************************************************************
  780. **
  781. ** NTSTATUS GCK_VKBD_GetDeviceAttributes(IN ULONG ulBufferLength, OUT PVOID pvUserBuffer,
  782. ** OUT PULONG pulBytesCopied)
  783. **
  784. ** @func Helps handles IOCTL_HID_GET_DEVICE_ATTRIBUTES. The data is statically
  785. ** declared at the top of this file.
  786. **
  787. ** @rdesc STATUS_SUCCESS
  788. ** @rdesc STATUS_BUFFER_TOO_SMALL
  789. **
  790. *************************************************************************************/
  791. NTSTATUS
  792. GCK_VKBD_GetDeviceAttributes
  793. (
  794. IN ULONG ulBufferLength, //@parm [in] Length of User Buffer
  795. OUT PVOID pvUserBuffer, //@parm [out] User Buffer which accepts Attributes
  796. OUT PULONG pulBytesCopied //@parm [out] Size of Attributes Copied
  797. )
  798. {
  799. PHID_DEVICE_ATTRIBUTES pDeviceAttributes = (PHID_DEVICE_ATTRIBUTES)pvUserBuffer;
  800. GCK_DBG_ENTRY_PRINT(("Entering GCK_VKBD_GetDeviceAttributes\n"));
  801. // Check buffer size
  802. if(ulBufferLength < sizeof(HID_DEVICE_ATTRIBUTES))
  803. {
  804. *pulBytesCopied = 0;
  805. return STATUS_BUFFER_TOO_SMALL;
  806. }
  807. // Fill out attributes structures
  808. pDeviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
  809. pDeviceAttributes->VendorID = MICROSOFT_VENDOR_ID;
  810. pDeviceAttributes->ProductID = VKBD_PRODUCT_ID;
  811. pDeviceAttributes->VersionNumber = VKBD_VERSION;
  812. // Record number of bytes copied
  813. *pulBytesCopied = sizeof(HID_DEVICE_ATTRIBUTES);
  814. // Return Success
  815. return STATUS_SUCCESS;
  816. }