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.

859 lines
27 KiB

  1. // @doc
  2. /*******************************************************************
  3. *
  4. * @module SWVMOUSE.cpp |
  5. *
  6. * Implementation of the SideWinder Virtual Mouse
  7. *
  8. * History
  9. * ----------------------------------------------------------
  10. * Mitchell S. Dernis Original
  11. *
  12. * (c) 1986-1999 Microsoft Corporation. All right reserved.
  13. *
  14. * @topic SWVKBD |
  15. * This module implements the SideWinder Virtual Mouse
  16. * which is used to report Joystick Axes as mouse axes.
  17. * Also is used for stuffing mouse clicks.
  18. *
  19. **********************************************************************/
  20. #define __DEBUG_MODULE_IN_USE__ GCK_SWVMOUSE_C
  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 "SWVMOUSE.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 Mouse
  51. SWVB_DEVICE_SERVICE_TABLE VMouServiceTable =
  52. {
  53. GCK_VMOU_CreateProc,
  54. GCK_VMOU_CloseProc,
  55. GCK_VMOU_ReadProc,
  56. GCK_VMOU_WriteProc,
  57. GCK_VMOU_IoctlProc,
  58. GCK_VMOU_StartProc,
  59. GCK_VMOU_StopProc,
  60. GCK_VMOU_RemoveProc
  61. };
  62. // Constants describing device
  63. #define VMOU_VERSION 0x0100
  64. #define VMOU_COUNTRY 0x0000
  65. #define VMOU_DESCRIPTOR_COUNT 0x0001
  66. #define VMOU_PRODUCT_ID 0x00FB //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 pretty much copied from the HID spec Version 1 (Need to change if adding wheel support)
  70. //
  71. static UCHAR VMOU_ReportDescriptor[] =
  72. {
  73. 0x05,0x01, //Usage Page (Generic Desktop)
  74. 0x09,0x02, //Usage (Mouse)
  75. 0xA1,0x01, //Collection (Application)
  76. 0x09,0x01, // Usage (Pointer)
  77. 0xA1,0x00, // Collection (Physical)
  78. 0x05,0x09, // Usage Page (Buttons)
  79. 0x19,0x01, // Usage Minimum (01)
  80. 0x29,0x03, // Usage Maximum (03)
  81. 0x15,0x00, // Logical Minimum (0)
  82. 0x25,0x01, // Logical Maximum (1)
  83. 0x95,0x03, // Report Count (3)
  84. 0x75,0x01, // Report Size (1)
  85. 0x81,0x02, // Input (Data, Variable, Absolute) - 3 button bits
  86. 0x95,0x01, // Report Count(1)
  87. 0x75,0x05, // Report Size (5)
  88. 0x81,0x01, // Input (Const) - 5 bit padding
  89. 0x05,0x01, // Usage Page (Generic Desktop)
  90. 0x09,0x30, // Usage(X)
  91. 0x09,0x31, // Usage(Y)
  92. 0x15,0x81, // Logical Minimum (-127)
  93. 0x25,0x7F, // Logical Maximum (127)
  94. 0x75,0x08, // Report Size (8)
  95. 0x95,0x02, // Report Count (2)
  96. 0x81,0x06, // Input (Data, Variable, Relative) - 2 Positions (X & Y)
  97. 0xC0, // End Collection
  98. 0xC0 //End Collection
  99. };
  100. static HID_DESCRIPTOR VMOU_DeviceDescriptor =
  101. {
  102. sizeof (HID_DESCRIPTOR),
  103. HID_HID_DESCRIPTOR_TYPE,
  104. VMOU_VERSION,
  105. VMOU_COUNTRY,
  106. VMOU_DESCRIPTOR_COUNT,
  107. {HID_REPORT_DESCRIPTOR_TYPE,
  108. sizeof(VMOU_ReportDescriptor)}
  109. };
  110. /***********************************************************************************
  111. **
  112. ** NTSTATUS GCK_VMOU_DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
  113. **
  114. ** @func Stows the Driver Object for later
  115. **
  116. ** @rdesc STATUS_SUCCESS if it opens.
  117. **
  118. *************************************************************************************/
  119. NTSTATUS
  120. GCK_VMOU_DriverEntry(
  121. IN PDRIVER_OBJECT pDriverObject, //@parm Driver Object
  122. IN PUNICODE_STRING pRegistryPath //@parm Registry path for this driver
  123. )
  124. {
  125. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_DriverEntry\n"));
  126. UNREFERENCED_PARAMETER(pDriverObject);
  127. UNREFERENCED_PARAMETER(pRegistryPath);
  128. // g_pDriverObject = pDriverObject;
  129. g_ulInstanceBits = 0x0;
  130. g_ulInstanceOverflow = 32; //For 33 and more devices
  131. return STATUS_SUCCESS;
  132. }
  133. /***********************************************************************************
  134. **
  135. ** NTSTATUS GCK_VMOU_Create(OUT PDEVICE_OBJECT *ppDeviceObject)
  136. **
  137. ** @func Creates a new Virtual Mouse
  138. **
  139. ** @rdesc STATUS_SUCCESS if it opens.
  140. **
  141. *************************************************************************************/
  142. NTSTATUS
  143. GCK_VMOU_Create
  144. (
  145. OUT PDEVICE_OBJECT *ppDeviceObject //@parm [out] Device Object of new virtual keyboard
  146. )
  147. {
  148. NTSTATUS NtStatus;
  149. SWVB_EXPOSE_DATA SwvbExposeData;
  150. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_Create *ppDeviceObject = 0x%0.8x\n", *ppDeviceObject));
  151. //Fill out SWVB_EXPOSE_DATA structure
  152. SwvbExposeData.pmwszDeviceId=L"SideWinderVirtualMouse\0\0";
  153. SwvbExposeData.pServiceTable = &VMouServiceTable ;
  154. SwvbExposeData.ulDeviceExtensionSize = sizeof(GCK_VMOU_EXT);
  155. SwvbExposeData.ulInitContext = (ULONG)ppDeviceObject;
  156. SwvbExposeData.pfnInitDevice = &GCK_VMOU_Init;
  157. //Get the instance ID
  158. ULONG ulBitMask;
  159. ULONG ulIndex;
  160. for(ulIndex = 0, ulBitMask = 1; ulIndex < 32; ulBitMask <<= 1, ulIndex++)
  161. {
  162. if(ulBitMask & ~g_ulInstanceBits)
  163. {
  164. g_ulInstanceBits |= ulBitMask;
  165. SwvbExposeData.ulInstanceNumber = ulIndex;
  166. break;
  167. }
  168. }
  169. if(32 == ulIndex)
  170. {
  171. SwvbExposeData.ulInstanceNumber = g_ulInstanceOverflow++;
  172. }
  173. //Call virtual bus to expose virtual mouse
  174. NtStatus=GCK_SWVB_Expose(&SwvbExposeData);
  175. return NtStatus;
  176. }
  177. /***********************************************************************************
  178. **
  179. ** NTSTATUS GCK_VMOU_Init( IN PDEVICE_OBJECT pDeviceObject, IN ULONG ulInitContext)
  180. **
  181. ** @func Callback for Initializing new device object. The ulInitContext
  182. ** is a pointer to a pointer to a device object, so that we can pass
  183. ** the pointer to the device object back to the caller of create.
  184. ** @rdesc STATUS_SUCCESS.
  185. **
  186. *************************************************************************************/
  187. NTSTATUS
  188. GCK_VMOU_Init
  189. (
  190. IN PDEVICE_OBJECT pDeviceObject,
  191. IN ULONG ulInitContext
  192. )
  193. {
  194. PGCK_VMOU_EXT pDevExt;
  195. PDEVICE_OBJECT *ppSaveDeviceObject;
  196. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_Init pDeviceObject = 0x%0.8x\n", pDeviceObject));
  197. //Create sent us a pointer to a PDEVICE_OBJECT in which to return the new device object
  198. ppSaveDeviceObject = (PDEVICE_OBJECT *)ulInitContext;
  199. *ppSaveDeviceObject = pDeviceObject;
  200. //Get out part of the device extension
  201. pDevExt = (PGCK_VMOU_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  202. //Mark device as stopped
  203. pDevExt->ucDeviceState= VMOU_STATE_STOPPED;
  204. //Mark the circular buffer as empty
  205. pDevExt->usReportBufferPos=0;
  206. pDevExt->usReportBufferCount=0;
  207. //Initialize locks
  208. GCK_InitRemoveLock(&pDevExt->RemoveLock, "SWVMOU_LOCK");
  209. //Initialize IrpQueue
  210. pDevExt->IrpQueue.Init( CGuardedIrpQueue::CANCEL_IRPS_ON_DELETE |
  211. CGuardedIrpQueue::PRESERVE_QUEUE_ORDER,
  212. (CGuardedIrpQueue::PFN_DEC_IRP_COUNT)GCK_DecRemoveLock,
  213. &pDevExt->RemoveLock);
  214. return STATUS_SUCCESS;
  215. }
  216. /***********************************************************************************
  217. *
  218. ** NTSTATUS GCK_VMOU_Close(IN PDEVICE_OBJECT pDeviceObject)
  219. **
  220. ** @func Closes the virtual mouse (removes it!)
  221. **
  222. ** @rdesc STATUS_SUCCESS on success
  223. **
  224. *************************************************************************************/
  225. NTSTATUS
  226. GCK_VMOU_Close
  227. (
  228. IN PDEVICE_OBJECT pDeviceObject
  229. )
  230. {
  231. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_Close pDeviceObject = 0x%0.8x\n", pDeviceObject));
  232. //Tell the virtual bus to kill us
  233. return GCK_SWVB_Remove(pDeviceObject);
  234. }
  235. /***********************************************************************************
  236. *
  237. ** NTSTATUS GCK_VMOU_SendReportPacket(IN PDEVICE_OBJECT pDeviceObject)
  238. **
  239. ** @func Stuff a report into the circular buffer, and completes
  240. ** an IRP if one is pending.
  241. **
  242. ** @rdesc STATUS_SUCCESS on success
  243. **
  244. *************************************************************************************/
  245. NTSTATUS
  246. GCK_VMOU_SendReportPacket
  247. (
  248. IN PDEVICE_OBJECT pDeviceObject,
  249. IN PGCK_VMOU_REPORT_PACKET pReportPacket
  250. )
  251. {
  252. GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_VMOU_SendReportPacket pDeviceObject = 0x%0.8x, pReportPacket = 0x%0.8x\n", pDeviceObject, pReportPacket));
  253. USHORT usBufferIndex;
  254. PGCK_VMOU_EXT pDevExt = (PGCK_VMOU_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  255. CShareIrpQueueSpinLock IrpQueueWithSharedSpinLock(&pDevExt->IrpQueue);
  256. //
  257. // Step 1. Stuff new packet into buffer
  258. //
  259. // Acquire Lock to work with buffer
  260. IrpQueueWithSharedSpinLock.Acquire();
  261. //Find position in buffer to stuff at
  262. usBufferIndex = (pDevExt->usReportBufferPos + pDevExt->usReportBufferCount)%GCK_VMOU_STATE_BUFFER_SIZE;
  263. //Copy data
  264. pDevExt->rgReportBuffer[usBufferIndex] = *pReportPacket;
  265. //increment buffer count
  266. if(pDevExt->usReportBufferCount < GCK_VMOU_STATE_BUFFER_SIZE)
  267. {
  268. pDevExt->usReportBufferCount++;
  269. }
  270. else
  271. {
  272. //This assertion means buffer overflow
  273. GCK_DBG_TRACE_PRINT(("Virtual Mouse buffer overflow\n"));
  274. pDevExt->usReportBufferPos++;
  275. }
  276. //
  277. // Step 2. Get Irp if there is one
  278. //
  279. PIRP pPendingIrp = IrpQueueWithSharedSpinLock.Remove();
  280. if(pPendingIrp)
  281. {
  282. // Copy the data
  283. RtlCopyMemory(
  284. pPendingIrp->UserBuffer,
  285. &pDevExt->rgReportBuffer[pDevExt->usReportBufferPos],
  286. sizeof(GCK_VMOU_REPORT_PACKET)
  287. );
  288. // Adjust buffer pos and count
  289. pDevExt->usReportBufferCount--;
  290. if(pDevExt->usReportBufferCount)
  291. {
  292. pDevExt->usReportBufferPos = (pDevExt->usReportBufferPos++)%GCK_VMOU_STATE_BUFFER_SIZE;
  293. }
  294. }
  295. //We are done with the buffer spin lock
  296. IrpQueueWithSharedSpinLock.Release();
  297. if(pPendingIrp)
  298. {
  299. // Fill out IRP status
  300. pPendingIrp->IoStatus.Information = sizeof(GCK_VMOU_REPORT_PACKET);
  301. pPendingIrp->IoStatus.Status = STATUS_SUCCESS;
  302. IoCompleteRequest(pPendingIrp, IO_NO_INCREMENT);
  303. //We just completed an IRP decrement the count
  304. GCK_DecRemoveLock(&pDevExt->RemoveLock);
  305. }
  306. //All done
  307. return STATUS_SUCCESS;
  308. }
  309. /***********************************************************************************
  310. *
  311. ** NTSTATUS GCK_VMOU_ReadReport(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
  312. **
  313. ** @func If there is data in the mouse buffer, completes the IRP
  314. ** Otherwise, queues it, and set the idle timer.
  315. **
  316. ** @rdesc STATUS_SUCCESS if read, STATUS_PENDING if waiting.
  317. **
  318. *************************************************************************************/
  319. NTSTATUS
  320. GCK_VMOU_ReadReport
  321. (
  322. IN PDEVICE_OBJECT pDeviceObject,
  323. IN PIRP pIrp
  324. )
  325. {
  326. PGCK_VMOU_EXT pDevExt;
  327. PIO_STACK_LOCATION pIrpStack;
  328. KIRQL OldIrql;
  329. GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_VMOU_ReadReport pDeviceObject = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp));
  330. //
  331. // Validate buffer size, because we do this the first time we see the IRP
  332. // we never need to worry about checking it again.
  333. //
  334. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  335. if(pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GCK_VMOU_REPORT_PACKET))
  336. {
  337. pIrp->IoStatus.Information = 0;
  338. pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  339. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  340. return STATUS_BUFFER_TOO_SMALL;
  341. }
  342. // Get device extension
  343. pDevExt = (PGCK_VMOU_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  344. //Make an IRP queue accessor to share spin lock
  345. CShareIrpQueueSpinLock IrpQueueWithSharedSpinLock(&pDevExt->IrpQueue);
  346. // Count the IRP we are working on
  347. GCK_IncRemoveLock(&pDevExt->RemoveLock);
  348. // Acquire Lock to work with mouse buffer and Irp Queue
  349. IrpQueueWithSharedSpinLock.Acquire();
  350. // If there is data, complete the IRP
  351. if( pDevExt->usReportBufferCount)
  352. {
  353. // Copy the data
  354. RtlCopyMemory(
  355. pIrp->UserBuffer,
  356. &pDevExt->rgReportBuffer[pDevExt->usReportBufferPos],
  357. sizeof(GCK_VMOU_REPORT_PACKET)
  358. );
  359. // Adjust buffer pos and count
  360. pDevExt->usReportBufferCount--;
  361. if(pDevExt->usReportBufferCount)
  362. {
  363. pDevExt->usReportBufferPos = (pDevExt->usReportBufferPos++)%GCK_VMOU_STATE_BUFFER_SIZE;
  364. }
  365. //We are done with the buffer spin lock
  366. IrpQueueWithSharedSpinLock.Release();
  367. // Fill out IRP status
  368. pIrp->IoStatus.Information = sizeof(GCK_VMOU_REPORT_PACKET);
  369. pIrp->IoStatus.Status = STATUS_SUCCESS;
  370. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  371. //We just completed an IRP decrement the count
  372. GCK_DecRemoveLock(&pDevExt->RemoveLock);
  373. }
  374. else
  375. // There is no data, so queue the IRP.
  376. {
  377. return IrpQueueWithSharedSpinLock.AddAndRelease(pIrp);
  378. }
  379. //We completed the IRP and all is fine
  380. return STATUS_SUCCESS;
  381. }
  382. /***********************************************************************************
  383. **
  384. ** NTSTATUS GCK_VMOU_CloseProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  385. **
  386. ** @func Handles the the IRP_MJ_CLOSE request sent from SWVB. We don't
  387. ** need to control anything, so we just succeed.
  388. **
  389. ** @devnote This should never actually be called with the HIDSWVD.SYS mini-driver
  390. ** in the chain. Good question for the review is if we need this.
  391. **
  392. ** @rdesc STATUS_SUCCESS
  393. **
  394. *************************************************************************************/
  395. NTSTATUS
  396. GCK_VMOU_CloseProc
  397. (
  398. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  399. IN PIRP pIrp //@parm [in\out] IRP to handle
  400. )
  401. {
  402. //We don't control open and close, so just succeed
  403. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_CloseProc\n"));
  404. UNREFERENCED_PARAMETER(pDeviceObject);
  405. pIrp->IoStatus.Status = STATUS_SUCCESS;
  406. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  407. return STATUS_SUCCESS;
  408. }
  409. /***********************************************************************************
  410. **
  411. ** NTSTATUS GCK_VMOU_CreateProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  412. **
  413. ** @func Handles the the IRP_MJ_CREATE request sent from SWVB. We don't
  414. ** need to control anything, so we just succeed.
  415. **
  416. ** @devnote This should never actually be called with the HIDSWVD.SYS mini-driver
  417. ** in the chain. Good question for the review is if we need this.
  418. **
  419. ** @rdesc STATUS_SUCCESS
  420. **
  421. *************************************************************************************/
  422. NTSTATUS
  423. GCK_VMOU_CreateProc
  424. (
  425. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  426. IN PIRP pIrp //@parm [in\out] IRP to handle
  427. )
  428. {
  429. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_CreateProc\n"));
  430. UNREFERENCED_PARAMETER(pDeviceObject);
  431. pIrp->IoStatus.Status = STATUS_SUCCESS;
  432. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  433. return STATUS_SUCCESS;
  434. }
  435. /***********************************************************************************
  436. **
  437. ** NTSTATUS GCK_VMOU_IoctlProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  438. **
  439. ** @func Handles the the IRP_MJ_INTERNAL_IOCTL and IRP_MJ_IOCTL requests sent from SWVB.
  440. ** Trivial IRPs are handle here, others are delegated.
  441. **
  442. ** @rdesc STATUS_SUCCESS, and various errors
  443. **
  444. *************************************************************************************/
  445. NTSTATUS
  446. GCK_VMOU_IoctlProc
  447. (
  448. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  449. IN PIRP pIrp //@parm [in\out] IRP to handle
  450. )
  451. {
  452. NTSTATUS NtStatus;
  453. PIO_STACK_LOCATION pIrpStack;
  454. GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_VMOU_IoctlProc\n"));
  455. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  456. pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  457. // We complete everything, so the various cases
  458. // fill out status and information, and we complete
  459. // the IRP at the bottom.
  460. switch(pIrpStack->Parameters.DeviceIoControl.IoControlCode)
  461. {
  462. case IOCTL_GET_PHYSICAL_DESCRIPTOR:
  463. pIrp->IoStatus.Information = 0;
  464. NtStatus =STATUS_NOT_SUPPORTED;
  465. break;
  466. case IOCTL_HID_ACTIVATE_DEVICE:
  467. pIrp->IoStatus.Information = 0;
  468. NtStatus = STATUS_SUCCESS;
  469. break;
  470. case IOCTL_HID_DEACTIVATE_DEVICE:
  471. pIrp->IoStatus.Information = 0;
  472. NtStatus = STATUS_SUCCESS;
  473. break;
  474. case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
  475. NtStatus = GCK_VMOU_GetDeviceAttributes(
  476. pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  477. pIrp->UserBuffer,
  478. &pIrp->IoStatus.Information
  479. );
  480. break;
  481. case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
  482. NtStatus = GCK_VMOU_GetDeviceDescriptor(
  483. pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  484. pIrp->UserBuffer,
  485. &pIrp->IoStatus.Information
  486. );
  487. break;
  488. case IOCTL_HID_GET_FEATURE:
  489. pIrp->IoStatus.Information = 0;
  490. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  491. break;
  492. case IOCTL_HID_GET_REPORT_DESCRIPTOR:
  493. NtStatus = GCK_VMOU_GetReportDescriptor(
  494. pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  495. pIrp->UserBuffer,
  496. &pIrp->IoStatus.Information
  497. );
  498. break;
  499. case IOCTL_HID_GET_STRING:
  500. pIrp->IoStatus.Information = 0;
  501. NtStatus = STATUS_NOT_SUPPORTED; //Should we support this?
  502. break;
  503. case IOCTL_HID_READ_REPORT:
  504. // Read report will complete the IRP, or queue as it sees fit, just delegate
  505. return GCK_VMOU_ReadReport(pDeviceObject, pIrp);
  506. case IOCTL_HID_SET_FEATURE:
  507. pIrp->IoStatus.Information = 0;
  508. NtStatus = STATUS_NOT_SUPPORTED;
  509. break;
  510. case IOCTL_HID_WRITE_REPORT:
  511. pIrp->IoStatus.Information = 0;
  512. NtStatus = STATUS_NOT_SUPPORTED;
  513. break;
  514. default:
  515. pIrp->IoStatus.Information = 0;
  516. NtStatus = STATUS_NOT_SUPPORTED;
  517. }
  518. pIrp->IoStatus.Status = NtStatus;
  519. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  520. return NtStatus;
  521. }
  522. /***********************************************************************************
  523. **
  524. ** NTSTATUS GCK_VMOU_ReadProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  525. **
  526. ** @func Handles the the IRP_MJ_READ request sent from SWVB. We don't support this.
  527. **
  528. ** @devnote This should never actually be called with the HIDSWVD.SYS mini-driver
  529. ** in the chain. Good question for the review is if we need this.
  530. **
  531. ** @rdesc STATUS_NOT_SUPPORTED
  532. **
  533. *************************************************************************************/
  534. NTSTATUS
  535. GCK_VMOU_ReadProc
  536. (
  537. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  538. IN PIRP pIrp //@parm [in\out] IRP to handle
  539. )
  540. {
  541. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_ReadProc\n"));
  542. UNREFERENCED_PARAMETER(pDeviceObject);
  543. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  544. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  545. return STATUS_NOT_SUPPORTED;
  546. }
  547. /***********************************************************************************
  548. **
  549. ** NTSTATUS GCK_VMOU_StartProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  550. **
  551. ** @func Handles the the IRP_MJ_PNP, IRP_MN_START_DEVICE request sent from SWVB.
  552. ** Just mark that we are started.
  553. **
  554. ** @rdesc STATUS_SUCCESS
  555. **
  556. *************************************************************************************/
  557. NTSTATUS
  558. GCK_VMOU_StartProc
  559. (
  560. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  561. IN PIRP pIrp //@parm [in\out] IRP to handle
  562. )
  563. {
  564. PGCK_VMOU_EXT pDevExt;
  565. UNREFERENCED_PARAMETER(pIrp);
  566. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_StartProc\n"));
  567. // Get device extension
  568. pDevExt = (PGCK_VMOU_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  569. // Mark as started
  570. pDevExt->ucDeviceState = VMOU_STATE_STARTED;
  571. // PnP IRPs are completed by SWVB
  572. return STATUS_SUCCESS;
  573. }
  574. /***********************************************************************************
  575. **
  576. ** NTSTATUS GCK_VMOU_StopProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  577. **
  578. ** @func Handles the the IRP_MJ_PNP, IRP_MN_STOP_DEVICE request sent from SWVB.
  579. ** Just mark that we are stopped.
  580. **
  581. ** @rdesc STATUS_SUCCESS
  582. **
  583. *************************************************************************************/
  584. NTSTATUS
  585. GCK_VMOU_StopProc
  586. (
  587. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  588. IN PIRP pIrp //@parm [in\out] IRP to handle
  589. )
  590. {
  591. PGCK_VMOU_EXT pDevExt;
  592. UNREFERENCED_PARAMETER(pIrp);
  593. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_StopProc\n"));
  594. // Get device extension
  595. pDevExt = (PGCK_VMOU_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  596. // Mark as stopped
  597. pDevExt->ucDeviceState = VMOU_STATE_STOPPED;
  598. // Cancel all I\O
  599. pDevExt->IrpQueue.CancelAll(STATUS_DELETE_PENDING);
  600. // PnP IRP are completed by SWVB
  601. return STATUS_SUCCESS;
  602. }
  603. /***********************************************************************************
  604. **
  605. ** NTSTATUS GCK_VMOU_RemoveProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  606. **
  607. ** @func Handles the the IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE request sent from SWVB.
  608. ** Wait for all outstanding IO to complete before succeeding. We don't
  609. ** delete our device object that is up to SWVB.
  610. **
  611. ** @rdesc STATUS_NOT_SUPPORTED
  612. **
  613. *************************************************************************************/
  614. NTSTATUS
  615. GCK_VMOU_RemoveProc
  616. (
  617. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  618. IN PIRP pIrp //@parm [in\out] IRP to handle
  619. )
  620. {
  621. PGCK_VMOU_EXT pDevExt;
  622. UNREFERENCED_PARAMETER(pIrp);
  623. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_RemoveProc\n"));
  624. // Get device extension
  625. pDevExt = (PGCK_VMOU_EXT)GCK_SWVB_GetVirtualDeviceExtension(pDeviceObject);
  626. // Mark as Removed
  627. pDevExt->ucDeviceState = VMOU_STATE_REMOVED;
  628. //Destroy Irp Queue
  629. pDevExt->IrpQueue.Destroy();
  630. //Clear Instance Bits
  631. ULONG ulInstance = GCK_SWVB_GetInstanceNumber(pDeviceObject);
  632. if(ulInstance < 32)
  633. {
  634. g_ulInstanceBits &= ~(1 << ulInstance);
  635. }
  636. // Remove the BIAS on the RemoveLock and wait for it to go to zero (forever)
  637. return GCK_DecRemoveLockAndWait(&pDevExt->RemoveLock, NULL);
  638. }
  639. /***********************************************************************************
  640. **
  641. ** NTSTATUS GCK_VMOU_WriteProc(IN PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
  642. **
  643. ** @func Handles the the IRP_MJ_WRITE, which we don't support. With HIDSWVD.SYS
  644. ** as the functional driver this should never get called.
  645. **
  646. ** @rdesc STATUS_NOT_SUPPORTED
  647. **
  648. *************************************************************************************/
  649. NTSTATUS
  650. GCK_VMOU_WriteProc
  651. (
  652. IN PDEVICE_OBJECT pDeviceObject, //@parm [in] Device Object to handle request
  653. IN PIRP pIrp //@parm [in\out] IRP to handle
  654. )
  655. {
  656. UNREFERENCED_PARAMETER(pDeviceObject);
  657. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_WriteProc\n"));
  658. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  659. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  660. return STATUS_NOT_SUPPORTED;
  661. }
  662. /***********************************************************************************
  663. **
  664. ** NTSTATUS GCK_VMOU_GetDeviceDescriptor(IN ULONG ulBufferLength, OUT PVOID pvUserBuffer,
  665. ** OUT PULONG pulBytesCopied)
  666. **
  667. ** @func Helps handles IOCTL_HID_GET_DEVICE_DESCRIPTOR the data is statically
  668. ** declared at the top of this file.
  669. **
  670. ** @rdesc STATUS_SUCCESS
  671. ** @rdesc STATUS_BUFFER_TOO_SMALL
  672. **
  673. *************************************************************************************/
  674. NTSTATUS
  675. GCK_VMOU_GetDeviceDescriptor
  676. (
  677. IN ULONG ulBufferLength, //@parm [in] Length of User Buffer
  678. OUT PVOID pvUserBuffer, //@parm [out] User Buffer which accepts Device Descriptor
  679. OUT PULONG pulBytesCopied //@parm [out] Size of Device Descriptor Copied
  680. )
  681. {
  682. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_GetDeviceDescriptor\n"));
  683. // Check buffer size
  684. if(ulBufferLength < sizeof(VMOU_DeviceDescriptor))
  685. {
  686. *pulBytesCopied = 0;
  687. return STATUS_BUFFER_TOO_SMALL;
  688. }
  689. // Copy bytes
  690. RtlCopyMemory(pvUserBuffer, &VMOU_DeviceDescriptor, sizeof(VMOU_DeviceDescriptor));
  691. // Record number of bytes copied
  692. *pulBytesCopied = sizeof(VMOU_DeviceDescriptor);
  693. // Return Success
  694. return STATUS_SUCCESS;
  695. }
  696. /***********************************************************************************
  697. **
  698. ** NTSTATUS GCK_VMOU_GetReportDescriptor(IN ULONG ulBufferLength, OUT PVOID pvUserBuffer,
  699. ** OUT PULONG pulBytesCopied)
  700. **
  701. ** @func Helps handles IOCTL_HID_GET_REPORT_DESCRIPTOR the data is statically
  702. ** declared at the top of this file.
  703. **
  704. ** @rdesc STATUS_SUCCESS
  705. ** @rdesc STATUS_BUFFER_TOO_SMALL
  706. **
  707. *************************************************************************************/
  708. NTSTATUS
  709. GCK_VMOU_GetReportDescriptor
  710. (
  711. IN ULONG ulBufferLength, //@parm [in] Length of User Buffer
  712. OUT PVOID pvUserBuffer, //@parm [out] User Buffer which accepts Report Descriptor
  713. OUT PULONG pulBytesCopied //@parm [out] Size of Report Descriptor Copied
  714. )
  715. {
  716. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_GetReportDescriptor\n"));
  717. // Check buffer size
  718. if(ulBufferLength < sizeof(VMOU_ReportDescriptor))
  719. {
  720. *pulBytesCopied = 0;
  721. return STATUS_BUFFER_TOO_SMALL;
  722. }
  723. // Copy bytes
  724. RtlCopyMemory(pvUserBuffer, &VMOU_ReportDescriptor, sizeof(VMOU_ReportDescriptor));
  725. // Record number of bytes copied
  726. *pulBytesCopied = sizeof(VMOU_ReportDescriptor);
  727. // Return Success
  728. return STATUS_SUCCESS;
  729. }
  730. /***********************************************************************************
  731. **
  732. ** NTSTATUS GCK_VMOU_GetDeviceAttributes(IN ULONG ulBufferLength, OUT PVOID pvUserBuffer,
  733. ** OUT PULONG pulBytesCopied)
  734. **
  735. ** @func Helps handles IOCTL_HID_GET_DEVICE_ATTRIBUTES. The data is statically
  736. ** declared at the top of this file.
  737. **
  738. ** @rdesc STATUS_SUCCESS
  739. ** @rdesc STATUS_BUFFER_TOO_SMALL
  740. **
  741. *************************************************************************************/
  742. NTSTATUS
  743. GCK_VMOU_GetDeviceAttributes
  744. (
  745. IN ULONG ulBufferLength, //@parm [in] Length of User Buffer
  746. OUT PVOID pvUserBuffer, //@parm [out] User Buffer which accepts Attributes
  747. OUT PULONG pulBytesCopied //@parm [out] Size of Attributes Copied
  748. )
  749. {
  750. PHID_DEVICE_ATTRIBUTES pDeviceAttributes = (PHID_DEVICE_ATTRIBUTES)pvUserBuffer;
  751. GCK_DBG_ENTRY_PRINT(("Entering GCK_VMOU_GetDeviceAttributes\n"));
  752. // Check buffer size
  753. if(ulBufferLength < sizeof(HID_DEVICE_ATTRIBUTES))
  754. {
  755. *pulBytesCopied = 0;
  756. return STATUS_BUFFER_TOO_SMALL;
  757. }
  758. // Fill out attributes structures
  759. pDeviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
  760. pDeviceAttributes->VendorID = MICROSOFT_VENDOR_ID;
  761. pDeviceAttributes->ProductID = VMOU_PRODUCT_ID;
  762. pDeviceAttributes->VersionNumber = VMOU_VERSION;
  763. // Record number of bytes copied
  764. *pulBytesCopied = sizeof(HID_DEVICE_ATTRIBUTES);
  765. // Return Success
  766. return STATUS_SUCCESS;
  767. }