PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/sourcecode/queryattr/moufiltr.c

https://github.com/martinb3/windows_driver_model_tutorial
C | 970 lines | 460 code | 135 blank | 375 comment | 34 complexity | 5338d9ec2cb85776702d51ff445b2467 MD5 | raw file
Possible License(s): Apache-2.0
  1. /*++
  2. This filter driver was adopted from the MouFiltr example in the
  3. Windows DDK version 3790.1830.
  4. File: moufiltr.c
  5. Last Modified: 2005-September-20
  6. --*/
  7. #include "moufiltr.h"
  8. NTSTATUS DriverEntry (PDRIVER_OBJECT, PUNICODE_STRING);
  9. // Suggest to the compiler different memory allocation
  10. // settings for different driver functions
  11. #ifdef ALLOC_PRAGMA
  12. #pragma alloc_text (PAGE, MouFilter_AddDevice)
  13. #pragma alloc_text (PAGE, MouFilter_CreateClose)
  14. #pragma alloc_text (PAGE, MouFilter_IoCtl)
  15. #pragma alloc_text (PAGE, MouFilter_InternIoCtl)
  16. #pragma alloc_text (PAGE, MouFilter_PnP)
  17. #pragma alloc_text (PAGE, MouFilter_Power)
  18. #pragma alloc_text (PAGE, MouFilter_Unload)
  19. #pragma alloc_text (PAGE, MouFilter_MakeSynchronousIoctl)
  20. #pragma alloc_text (PAGE, MouFilter_QueryMouseAttributes)
  21. #endif
  22. NTSTATUS
  23. DriverEntry (
  24. IN PDRIVER_OBJECT DriverObject,
  25. IN PUNICODE_STRING RegistryPath
  26. )
  27. /*++
  28. Routine Description:
  29. Initialize the entry points of the driver.
  30. --*/
  31. {
  32. ULONG i;
  33. UNREFERENCED_PARAMETER (RegistryPath);
  34. DbgPrint(("MouFilter_DriverEntry() called\n"));
  35. //
  36. // Fill in all the dispatch entry points with the pass through function
  37. // and the explicitly fill in the functions we are going to intercept
  38. //
  39. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  40. DriverObject->MajorFunction[i] = MouFilter_DispatchPassThrough;
  41. }
  42. DriverObject->MajorFunction [IRP_MJ_CREATE] = MouFilter_CreateClose;
  43. DriverObject->MajorFunction [IRP_MJ_CLOSE] = MouFilter_CreateClose;
  44. DriverObject->MajorFunction [IRP_MJ_PNP] = MouFilter_PnP;
  45. DriverObject->MajorFunction [IRP_MJ_POWER] = MouFilter_Power;
  46. DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouFilter_InternIoCtl;
  47. DriverObject->DriverUnload = MouFilter_Unload;
  48. DriverObject->DriverExtension->AddDevice = MouFilter_AddDevice;
  49. return STATUS_SUCCESS;
  50. }
  51. NTSTATUS
  52. MouFilter_AddDevice(
  53. IN PDRIVER_OBJECT Driver,
  54. IN PDEVICE_OBJECT PDO
  55. )
  56. {
  57. PDEVICE_EXTENSION devExt;
  58. IO_ERROR_LOG_PACKET errorLogEntry;
  59. PDEVICE_OBJECT device;
  60. NTSTATUS status = STATUS_SUCCESS;
  61. PAGED_CODE();
  62. DbgPrint(("MouFilter_AddDevice() called\n"));
  63. status = IoCreateDevice(Driver,
  64. sizeof(DEVICE_EXTENSION),
  65. NULL,
  66. FILE_DEVICE_MOUSE,
  67. 0,
  68. FALSE,
  69. &device
  70. );
  71. if (!NT_SUCCESS(status)) {
  72. return (status);
  73. }
  74. RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION));
  75. devExt = (PDEVICE_EXTENSION) device->DeviceExtension;
  76. devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);
  77. if (devExt->TopOfStack == NULL) {
  78. IoDeleteDevice(device);
  79. return STATUS_DEVICE_NOT_CONNECTED;
  80. }
  81. ASSERT(devExt->TopOfStack);
  82. devExt->Self = device;
  83. devExt->PDO = PDO;
  84. devExt->DeviceState = PowerDeviceD0;
  85. devExt->SurpriseRemoved = FALSE;
  86. devExt->Removed = FALSE;
  87. devExt->Started = FALSE;
  88. device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
  89. device->Flags &= ~DO_DEVICE_INITIALIZING;
  90. MouFilter_QueryMouseAttributes(devExt->TopOfStack);
  91. return status;
  92. }
  93. NTSTATUS
  94. MouFilter_Complete(
  95. IN PDEVICE_OBJECT DeviceObject,
  96. IN PIRP Irp,
  97. IN PVOID Context
  98. )
  99. /*++
  100. Routine Description:
  101. Generic completion routine that allows the driver to send the irp down the
  102. stack, catch it on the way up, and do more processing at the original IRQL.
  103. --*/
  104. {
  105. PKEVENT event;
  106. event = (PKEVENT) Context;
  107. // this is a unique way to "reference" a parameter
  108. // to avoid compile-time warnings, but still avoid using it
  109. //
  110. //It's defined as: #define UNREFERENCED_PARAMETER(P) (P)
  111. UNREFERENCED_PARAMETER(DeviceObject);
  112. UNREFERENCED_PARAMETER(Irp);
  113. DbgPrint(("MouFilter_Complete() called\n"));
  114. //
  115. // We could switch on the major and minor functions of the IRP to perform
  116. // different functions, but we know that Context is an event that needs
  117. // to be set.
  118. //
  119. // Wake this event. We set it previously.
  120. KeSetEvent(event, 0, FALSE);
  121. //
  122. // Allows the event we just woke to do something to the IRP
  123. // before it gets sent on its way
  124. //
  125. return STATUS_MORE_PROCESSING_REQUIRED;
  126. }
  127. NTSTATUS
  128. MouFilter_CreateClose (
  129. IN PDEVICE_OBJECT DeviceObject,
  130. IN PIRP Irp
  131. )
  132. /*++
  133. Routine Description:
  134. Maintain a simple count of the creates and closes sent against this device
  135. --*/
  136. {
  137. PIO_STACK_LOCATION irpStack;
  138. NTSTATUS status;
  139. PDEVICE_EXTENSION devExt;
  140. PAGED_CODE();
  141. DbgPrint(("MouFilter_CreateClose() called\n"));
  142. irpStack = IoGetCurrentIrpStackLocation(Irp);
  143. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  144. status = Irp->IoStatus.Status;
  145. switch (irpStack->MajorFunction) {
  146. case IRP_MJ_CREATE:
  147. if (NULL == devExt->UpperConnectData.ClassService) {
  148. //
  149. // No Connection yet. How can we be enabled?
  150. //
  151. status = STATUS_INVALID_DEVICE_STATE;
  152. }
  153. else if ( 1 >= InterlockedIncrement(&devExt->EnableCount)) {
  154. //
  155. // First time enable here
  156. //
  157. }
  158. else {
  159. //
  160. // More than one create was sent down (ignore the rest?)
  161. //
  162. }
  163. break;
  164. case IRP_MJ_CLOSE:
  165. ASSERT(0 < devExt->EnableCount);
  166. if (0 >= InterlockedDecrement(&devExt->EnableCount)) {
  167. //
  168. // successfully closed the device, do any appropriate work here
  169. // this would be place to free any resources allocated earlier
  170. // that are still pointed to in the devExt device extension
  171. //
  172. }
  173. break;
  174. }
  175. Irp->IoStatus.Status = status;
  176. //
  177. // Pass on the create and the close
  178. //
  179. return MouFilter_DispatchPassThrough(DeviceObject, Irp);
  180. }
  181. NTSTATUS
  182. MouFilter_DispatchPassThrough(
  183. IN PDEVICE_OBJECT DeviceObject,
  184. IN PIRP Irp
  185. )
  186. /*++
  187. Routine Description:
  188. Passes a request on to the lower driver.
  189. --*/
  190. {
  191. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  192. DbgPrint(("MouFilter_DispatchPassThrough() called -- "));
  193. switch(irpStack->MajorFunction) {
  194. case IRP_MJ_CREATE:
  195. DbgPrint(("MouFiltr.sys saw IRP_MJ_CREATE\n"));
  196. break;
  197. case IRP_MJ_PNP:
  198. DbgPrint(("MouFiltr.sys saw IRP_MJ_PNP\n"));
  199. break;
  200. case IRP_MJ_POWER:
  201. DbgPrint(("MouFiltr.sys saw IRP_MJ_POWER\n"));
  202. break;
  203. case IRP_MJ_READ:
  204. DbgPrint(("MouFiltr.sys saw IRP_MJ_READ\n"));
  205. break;
  206. case IRP_MJ_WRITE:
  207. DbgPrint(("MouFiltr.sys saw IRP_MJ_WRITE\n"));
  208. break;
  209. case IRP_MJ_FLUSH_BUFFERS:
  210. DbgPrint(("MouFiltr.sys saw IRP_MJ_FLUSH_BUFFERS\n"));
  211. break;
  212. case IRP_MJ_QUERY_INFORMATION:
  213. DbgPrint(("MouFiltr.sys saw IRP_MJ_QUERY_INFORMATION\n"));
  214. break;
  215. case IRP_MJ_SET_INFORMATION:
  216. DbgPrint(("MouFiltr.sys saw IRP_MJ_SET_INFORMATION\n"));
  217. break;
  218. case IRP_MJ_DEVICE_CONTROL:
  219. DbgPrint(("MouFiltr.sys saw IRP_MJ_DEVICE_CONTROL\n"));
  220. break;
  221. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  222. DbgPrint(("MouFiltr.sys saw IRP_MJ_INTERNAL_DEVICE_CONTROL\n"));
  223. break;
  224. case IRP_MJ_SYSTEM_CONTROL:
  225. DbgPrint(("MouFiltr.sys saw IRP_MJ_SYSTEM_CONTROL\n"));
  226. break;
  227. case IRP_MJ_CLEANUP:
  228. DbgPrint(("MouFiltr.sys saw IRP_MJ_CLEANUP\n"));
  229. break;
  230. case IRP_MJ_CLOSE:
  231. DbgPrint(("MouFiltr.sys saw IRP_MJ_CLOSE\n"));
  232. break;
  233. case IRP_MJ_SHUTDOWN:
  234. DbgPrint(("MouFiltr.sys saw IRP_MJ_SHUTDOWN\n"));
  235. break;
  236. default:
  237. DbgPrint(("MouFiltr.sys saw an unknown IRP Major Function Code\n"));
  238. }
  239. //
  240. // Pass the IRP to the target
  241. //
  242. IoSkipCurrentIrpStackLocation(Irp);
  243. return IoCallDriver(((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->TopOfStack, Irp);
  244. }
  245. NTSTATUS
  246. MouFilter_InternIoCtl(
  247. IN PDEVICE_OBJECT DeviceObject,
  248. IN PIRP Irp
  249. )
  250. /*++
  251. Routine Description:
  252. This routine is the dispatch routine for internal device control requests.
  253. There are two specific control codes that are of interest:
  254. IOCTL_INTERNAL_MOUSE_CONNECT:
  255. Store the old context and function pointer and replace it with our own.
  256. This makes life much simpler than intercepting IRPs sent by the RIT and
  257. modifying them on the way back up.
  258. RIT = Raw Input Thread that sends IRPs like IRP_MJ_READ
  259. Arguments:
  260. DeviceObject - Pointer to the device object.
  261. Irp - Pointer to the request packet.
  262. Return Value:
  263. Status is returned.
  264. --*/
  265. {
  266. PIO_STACK_LOCATION irpStack;
  267. PDEVICE_EXTENSION devExt;
  268. KEVENT event;
  269. PCONNECT_DATA connectData;
  270. NTSTATUS status = STATUS_SUCCESS;
  271. DbgPrint(("MouFilter_InternIoCtl() called\n"));
  272. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  273. Irp->IoStatus.Information = 0;
  274. irpStack = IoGetCurrentIrpStackLocation(Irp);
  275. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  276. //
  277. // Connect a mouse class device driver to the port driver.
  278. //
  279. case IOCTL_INTERNAL_MOUSE_CONNECT:
  280. //
  281. // Only allow one connection. Check for already-used function pointer.
  282. //
  283. if (devExt->UpperConnectData.ClassService != NULL) {
  284. status = STATUS_SHARING_VIOLATION;
  285. break;
  286. }
  287. else if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  288. sizeof(CONNECT_DATA)) {
  289. //
  290. // invalid buffer, it must not really be a CONNECT_DATA
  291. //
  292. status = STATUS_INVALID_PARAMETER;
  293. break;
  294. }
  295. //
  296. // Store the original function pointer in the device extension.
  297. //
  298. connectData = ((PCONNECT_DATA)
  299. (irpStack->Parameters.DeviceIoControl.Type3InputBuffer));
  300. devExt->UpperConnectData = *connectData;
  301. //
  302. // Hook into the report chain. Everytime a mouse packet is reported to
  303. // the system, MouFilter_ServiceCallback will be called
  304. //
  305. connectData->ClassDeviceObject = devExt->Self;
  306. connectData->ClassService = MouFilter_ServiceCallback;
  307. break;
  308. //
  309. // Disconnect a mouse class device driver from the port driver.
  310. //
  311. case IOCTL_INTERNAL_MOUSE_DISCONNECT:
  312. //
  313. // Clear the connection parameters in the device extension.
  314. //
  315. // devExt->UpperConnectData.ClassDeviceObject = NULL;
  316. // devExt->UpperConnectData.ClassService = NULL;
  317. //
  318. // As the DDK uses this example, it should hopefully not be
  319. // neccessary for our use. At least we return "not-implemented"...
  320. status = STATUS_NOT_IMPLEMENTED;
  321. break;
  322. //
  323. // Might want to capture this in the future. For now, then pass it down
  324. // the stack. These queries must be successful for the RIT to communicate
  325. // with the mouse.
  326. //
  327. case IOCTL_MOUSE_QUERY_ATTRIBUTES:
  328. default:
  329. break;
  330. }
  331. if (!NT_SUCCESS(status)) {
  332. Irp->IoStatus.Status = status;
  333. Irp->IoStatus.Information = 0;
  334. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  335. return status;
  336. }
  337. return MouFilter_DispatchPassThrough(DeviceObject, Irp);
  338. }
  339. NTSTATUS
  340. MouFilter_PnP(
  341. IN PDEVICE_OBJECT DeviceObject,
  342. IN PIRP Irp
  343. )
  344. /*++
  345. Routine Description:
  346. This routine is the dispatch routine for plug and play irps
  347. Arguments:
  348. DeviceObject - Pointer to the device object.
  349. Irp - Pointer to the request packet.
  350. Return Value:
  351. Status is returned.
  352. --*/
  353. {
  354. PDEVICE_EXTENSION devExt;
  355. PIO_STACK_LOCATION irpStack;
  356. NTSTATUS status = STATUS_SUCCESS;
  357. KIRQL oldIrql;
  358. KEVENT event;
  359. PAGED_CODE();
  360. DbgPrint(("MouFilter_PnP() called\n"));
  361. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  362. irpStack = IoGetCurrentIrpStackLocation(Irp);
  363. switch (irpStack->MinorFunction) {
  364. case IRP_MN_START_DEVICE: {
  365. //
  366. // The device is starting.
  367. //
  368. // We cannot touch the device (send it any non pnp irps) until a
  369. // start device has been passed down to the lower drivers.
  370. //
  371. // prepare to pass this irp to the next stack location for processing
  372. IoCopyCurrentIrpStackLocationToNext(Irp);
  373. // set a kernel wait "event" so that this driver doesn't run off
  374. KeInitializeEvent(&event,
  375. NotificationEvent,
  376. FALSE
  377. );
  378. // when this IRP is completed, call MouFilter_Complete
  379. IoSetCompletionRoutine(Irp,
  380. (PIO_COMPLETION_ROUTINE) MouFilter_Complete,
  381. &event,
  382. TRUE,
  383. TRUE,
  384. TRUE); // No need for Cancel
  385. // if the driver below us completes the IRP, we'll get a success
  386. // otherwise, it will pend the IRP and we'll wait
  387. status = IoCallDriver(devExt->TopOfStack, Irp);
  388. if (STATUS_PENDING == status) {
  389. KeWaitForSingleObject(
  390. &event,
  391. Executive, // Waiting for reason of a driver
  392. KernelMode, // Waiting in kernel mode
  393. FALSE, // No allert
  394. NULL); // No timeout
  395. }
  396. if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) {
  397. //
  398. // As we are successfully now back from our start device
  399. // we can do work.
  400. //
  401. devExt->Started = TRUE;
  402. devExt->Removed = FALSE;
  403. devExt->SurpriseRemoved = FALSE;
  404. }
  405. //
  406. // We must now complete the IRP, since we stopped it in the
  407. // completetion routine with MORE_PROCESSING_REQUIRED.
  408. //
  409. Irp->IoStatus.Status = status;
  410. Irp->IoStatus.Information = 0;
  411. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  412. break;
  413. }
  414. case IRP_MN_SURPRISE_REMOVAL:
  415. //
  416. // Same as a remove device, but don't call IoDetach or IoDeleteDevice
  417. //
  418. devExt->SurpriseRemoved = TRUE;
  419. // Remove code here
  420. IoSkipCurrentIrpStackLocation(Irp);
  421. status = IoCallDriver(devExt->TopOfStack, Irp);
  422. break;
  423. case IRP_MN_REMOVE_DEVICE:
  424. devExt->Removed = TRUE;
  425. // remove code here
  426. Irp->IoStatus.Status = STATUS_SUCCESS;
  427. IoSkipCurrentIrpStackLocation(Irp);
  428. status = IoCallDriver(devExt->TopOfStack, Irp);
  429. // we must release the device since it wasn't surprise_removal
  430. IoDetachDevice(devExt->TopOfStack);
  431. IoDeleteDevice(DeviceObject);
  432. break;
  433. case IRP_MN_QUERY_REMOVE_DEVICE:
  434. case IRP_MN_QUERY_STOP_DEVICE:
  435. case IRP_MN_CANCEL_REMOVE_DEVICE:
  436. case IRP_MN_CANCEL_STOP_DEVICE:
  437. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  438. case IRP_MN_STOP_DEVICE:
  439. case IRP_MN_QUERY_DEVICE_RELATIONS:
  440. case IRP_MN_QUERY_INTERFACE:
  441. case IRP_MN_QUERY_CAPABILITIES:
  442. case IRP_MN_QUERY_DEVICE_TEXT:
  443. case IRP_MN_QUERY_RESOURCES:
  444. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  445. case IRP_MN_READ_CONFIG:
  446. case IRP_MN_WRITE_CONFIG:
  447. case IRP_MN_EJECT:
  448. case IRP_MN_SET_LOCK:
  449. case IRP_MN_QUERY_ID:
  450. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  451. default:
  452. //
  453. // Here the filter driver might modify the behavior of these IRPS
  454. // Please see PlugPlay DDK Example's documentation for use of these IRPs.
  455. //
  456. // this would be place to add new "virtual" functionality or something.
  457. IoSkipCurrentIrpStackLocation(Irp);
  458. status = IoCallDriver(devExt->TopOfStack, Irp);
  459. break;
  460. }
  461. return status;
  462. }
  463. NTSTATUS
  464. MouFilter_Power(
  465. IN PDEVICE_OBJECT DeviceObject,
  466. IN PIRP Irp
  467. )
  468. /*++
  469. Routine Description:
  470. This routine is the dispatch routine for power irps Does nothing except
  471. record the state of the device.
  472. Arguments:
  473. DeviceObject - Pointer to the device object.
  474. Irp - Pointer to the request packet.
  475. Return Value:
  476. Status is returned.
  477. --*/
  478. {
  479. PIO_STACK_LOCATION irpStack;
  480. PDEVICE_EXTENSION devExt;
  481. POWER_STATE powerState;
  482. POWER_STATE_TYPE powerType;
  483. PAGED_CODE();
  484. DbgPrint(("MouFilter_Power() called\n"));
  485. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  486. irpStack = IoGetCurrentIrpStackLocation(Irp);
  487. powerType = irpStack->Parameters.Power.Type;
  488. powerState = irpStack->Parameters.Power.State;
  489. switch (irpStack->MinorFunction) {
  490. case IRP_MN_SET_POWER:
  491. if (powerType == DevicePowerState) {
  492. devExt->DeviceState = powerState.DeviceState;
  493. }
  494. case IRP_MN_QUERY_POWER:
  495. case IRP_MN_WAIT_WAKE:
  496. case IRP_MN_POWER_SEQUENCE:
  497. default:
  498. break;
  499. }
  500. // The PoStartNextPowerIrp routine signals the power manager that the driver is ready to handle the next power IRP.
  501. // This routine must be called by every driver in the device stack - from the April 2005 MSDN Library
  502. PoStartNextPowerIrp(Irp);
  503. IoSkipCurrentIrpStackLocation(Irp);
  504. return PoCallDriver(devExt->TopOfStack, Irp);
  505. }
  506. VOID
  507. MouFilter_ServiceCallback(
  508. IN PDEVICE_OBJECT DeviceObject,
  509. IN PMOUSE_INPUT_DATA InputDataStart,
  510. IN PMOUSE_INPUT_DATA InputDataEnd,
  511. IN OUT PULONG InputDataConsumed
  512. )
  513. /*++
  514. Routine Description:
  515. Called when there are mouse packets to report to the RIT. You can do
  516. anything you like to the packets. For instance:
  517. o Drop a packet altogether
  518. o Mutate the contents of a packet
  519. o Insert packets into the stream
  520. Arguments:
  521. DeviceObject - Context passed during the connect IOCTL
  522. InputDataStart - First packet to be reported
  523. InputDataEnd - One past the last packet to be reported. Total number of
  524. packets is equal to InputDataEnd - InputDataStart
  525. InputDataConsumed - Set to the total number of packets consumed by the RIT
  526. (via the function pointer we replaced in the connect
  527. IOCTL)
  528. Return Value:
  529. Status is returned.
  530. For reference:
  531. ----------------------------------------
  532. typedef struct MOUSE_INPUT_DATA {
  533. USHORT UnitId;
  534. USHORT Flags;
  535. union {
  536. ULONG Buttons;
  537. struct {
  538. USHORT ButtonFlags;
  539. USHORT ButtonData;
  540. };
  541. };
  542. ULONG RawButtons;
  543. LONG LastX;
  544. LONG LastY;
  545. ULONG ExtraInformation;
  546. } MOUSE_INPUT_DATA, *PMOUSE_INPUT_DATA;
  547. Flags:
  548. MOUSE_MOVE_RELATIVE The LastX and LastY are set relative to the previous location.
  549. MOUSE_MOVE_ABSOLUTE The LastX and LastY values are set to absolute values.
  550. MOUSE_VIRTUAL_DESKTOP The mouse coordinates are mapped to the virtual desktop.
  551. MOUSE_ATTRIBUTES_CHANGED The mouse attributes have changed. The other data in the structure is not used.
  552. ButtonFlags:
  553. MOUSE_LEFT_BUTTON_DOWN The left mouse button changed to down.
  554. MOUSE_LEFT_BUTTON_UP The left mouse button changed to up.
  555. MOUSE_RIGHT_BUTTON_DOWN The right mouse button changed to down.
  556. MOUSE_RIGHT_BUTTON_UP The right mouse button changed to up.
  557. MOUSE_MIDDLE_BUTTON_DOWN The middle mouse button changed to down.
  558. MOUSE_MIDDLE_BUTTON_UP The middle mouse button changed to up.
  559. MOUSE_BUTTON_4_DOWN The fourth mouse button changed to down.
  560. MOUSE_BUTTON_4_UP The fourth mouse button changed to up.
  561. MOUSE_BUTTON_5_DOWN The fifth mouse button changed to down.
  562. MOUSE_BUTTON_5_UP The fifth mouse button changed to up.
  563. MOUSE_WHEEL Mouse wheel data is present.
  564. ----------------------------------------
  565. --*/
  566. {
  567. PDEVICE_EXTENSION devExt;
  568. PMOUSE_INPUT_DATA pCursor; // cursor for looping
  569. // if there's at least one input packet, this pointer is good. trust the executive's pointers!
  570. DbgPrint("MouFilter_ServiceCallback() called for UnitId %hu\n", InputDataStart->UnitId);
  571. devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  572. // this is where we can mangle/delete/add packets
  573. for (pCursor = InputDataStart; pCursor < InputDataEnd; pCursor++) {
  574. // do something with the current MOUSE_INPUT_DATA
  575. DbgPrint("Mouse moved X = %li and Y = %li\n", pCursor->LastX, pCursor->LastY);
  576. }
  577. // Here we stop playing with the data!
  578. // UpperConnectData must be called at DISPATCH
  579. //
  580. (*(PSERVICE_CALLBACK_ROUTINE) devExt->UpperConnectData.ClassService)(
  581. devExt->UpperConnectData.ClassDeviceObject,
  582. InputDataStart,
  583. InputDataEnd,
  584. InputDataConsumed
  585. );
  586. }
  587. VOID
  588. MouFilter_Unload(
  589. IN PDRIVER_OBJECT Driver
  590. )
  591. /*++
  592. Routine Description:
  593. Free all the allocated resources associated with this driver.
  594. Arguments:
  595. DriverObject - Pointer to the driver object.
  596. Return Value:
  597. None.
  598. --*/
  599. {
  600. DbgPrint(("MouFiltr_Unload() called\n"));
  601. PAGED_CODE();
  602. UNREFERENCED_PARAMETER(Driver);
  603. ASSERT(NULL == Driver->DeviceObject);
  604. }
  605. NTSTATUS
  606. MouFilter_MakeSynchronousIoctl(
  607. IN PDEVICE_OBJECT TopOfDeviceStack,
  608. IN ULONG IoctlControlCode,
  609. PVOID InputBuffer,
  610. ULONG InputBufferLength,
  611. PVOID OutputBuffer,
  612. ULONG OutputBufferLength
  613. )
  614. /*++
  615. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmarch/hh/kmarch/k104_dca88c92-682a-437e-963b-6fac4e9c39bf.xml.asp
  616. describes basically this function
  617. Arguments:
  618. TopOfDeviceStack-
  619. IoctlControlCode - Value of the IOCTL request
  620. InputBuffer - Buffer to be sent to the TopOfDeviceStack
  621. InputBufferLength - Size of buffer to be sent to the TopOfDeviceStack
  622. OutputBuffer - Buffer for received data from the TopOfDeviceStack
  623. OutputBufferLength - Size of receive buffer from the TopOfDeviceStack
  624. Return Value:
  625. NT status code
  626. --*/
  627. {
  628. KEVENT event;
  629. PIRP irp;
  630. IO_STATUS_BLOCK ioStatus;
  631. NTSTATUS status;
  632. PAGED_CODE();
  633. //
  634. // Creating Device control IRP and send it to the another
  635. // driver without setting a completion routine.
  636. //
  637. KeInitializeEvent(&event, NotificationEvent, FALSE);
  638. irp = IoBuildDeviceIoControlRequest (
  639. IoctlControlCode,
  640. TopOfDeviceStack,
  641. InputBuffer,
  642. InputBufferLength,
  643. OutputBuffer,
  644. OutputBufferLength,
  645. TRUE, // If TRUE, the routine sets the IRP's major function code
  646. // to IRP_MJ_INTERNAL_DEVICE_CONTROL. Otherwise, the routine
  647. // sets the IRP's major function code to IRP_MJ_DEVICE_CONTROL.
  648. &event,
  649. &ioStatus);
  650. if (NULL == irp) {
  651. return STATUS_INSUFFICIENT_RESOURCES;
  652. }
  653. status = IoCallDriver(TopOfDeviceStack, irp);
  654. if (status == STATUS_PENDING) {
  655. //
  656. // You must wait here for the IRP to be completed because:
  657. // 1) The IoBuildDeviceIoControlRequest associates the IRP with the
  658. // thread and if the thread exits for any reason, it would cause the IRP
  659. // to be canceled.
  660. // 2) The Event and IoStatus block memory is from the stack and we
  661. // cannot go out of scope.
  662. // This event will be signaled by the I/O manager when the
  663. // IRP is completed.
  664. //
  665. status = KeWaitForSingleObject(
  666. &event,
  667. Executive, // wait reason
  668. KernelMode, // To prevent stack from being paged out.
  669. FALSE, // You are not alertable
  670. NULL); // No time out !!!!
  671. status = ioStatus.Status;
  672. }
  673. // Must not call any other functions on the IRP -- the I/O Manager frees synchronus irps
  674. // when a lower driver completes them with IoCompleteRequest(). We simply return a status
  675. // value, and the supplied buffer now is filled!
  676. return status;
  677. }
  678. VOID
  679. MouFilter_QueryMouseAttributes(
  680. IN PDEVICE_OBJECT TopOfDeviceStack
  681. )
  682. /*
  683. This calls the MakeSynchronusIoctl function above. Since that function uses IoBuildDeviceIoControlRequest,
  684. it MUST be called at IRQL=Passive Level. Plus, the functions are set to be paged, so... you need the pages ;).
  685. This function requests from MakeSynchronousIoctl() the results of IOCTL_MOUSE_QUERY_ATTRIBUTES in a specific buffer.
  686. Here is the struct returned:
  687. typedef struct _MOUSE_ATTRIBUTES {
  688. USHORT MouseIdentifier;
  689. USHORT NumberOfButtons;
  690. USHORT SampleRate;
  691. ULONG InputDataQueueLength;
  692. } MOUSE_ATTRIBUTES, *PMOUSE_ATTRIBUTES;
  693. From MSDN, about these fields:
  694. MouseIdentifier
  695. Specifies one of the following types of mouse devices.
  696. Mouse type Meaning
  697. BALLPOINT_I8042_HARDWARE i8042 port ballpoint mouse
  698. BALLPOINT_SERIAL_HARDWARE Serial port ballpoint mouse
  699. MOUSE_HID_HARDWARE HIDClass mouse
  700. MOUSE_I8042_HARDWARE i8042 port mouse
  701. MOUSE_INPORT_HARDWARE Inport (bus) mouse
  702. MOUSE_SERIAL_HARDWARE Serial port mouse
  703. WHEELMOUSE_HID_HARDWARE HIDClass wheel mouse
  704. WHEELMOUSE_I8042_HARDWARE i8042 port wheel mouse
  705. WHEELMOUSE_SERIAL_HARDWARE Serial port wheel mouse
  706. NumberOfButtons
  707. Specifies the number of buttons supported by a mouse. A mouse can have from two to five buttons.
  708. The default value is MOUSE_NUMBER_OF_BUTTONS.
  709. SampleRate
  710. Specifies the rate, in reports per second, at which input from a PS/2 mouse is sampled. The default value
  711. is MOUSE_SAMPLE_RATE. This value is not used for USB devices.
  712. InputDataQueueLength
  713. Specifies the size, in bytes, of the input data queue used by the port driver for a mouse device.
  714. */
  715. {
  716. NTSTATUS status;
  717. MOUSE_ATTRIBUTES m;
  718. PAGED_CODE();
  719. if(KeGetCurrentIrql() != PASSIVE_LEVEL) {
  720. DbgPrint(("MouFiltr_QueryMouseAtttributes was called at != PASSIVE_LEVEL, exiting.\n"));
  721. return;
  722. }
  723. status = MouFilter_MakeSynchronousIoctl(TopOfDeviceStack, IOCTL_MOUSE_QUERY_ATTRIBUTES, NULL, 0, &m, sizeof(MOUSE_ATTRIBUTES));
  724. if(NT_SUCCESS(status)) {
  725. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES was STATUS_SUCCESS\n"));
  726. switch(m.MouseIdentifier) {
  727. case BALLPOINT_I8042_HARDWARE:
  728. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported i8042 port ballpoint mouse MouseIdentifier\n")); break;
  729. case BALLPOINT_SERIAL_HARDWARE:
  730. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported Serial port ballpoint mouse MouseIdentifier\n")); break;
  731. case MOUSE_HID_HARDWARE:
  732. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported HIDClass mouse MouseIdentifier\n")); break;
  733. case MOUSE_I8042_HARDWARE:
  734. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported i8042 port mouse MouseIdentifier\n")); break;
  735. case MOUSE_INPORT_HARDWARE:
  736. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported Inport (bus) mouse MouseIdentifier\n")); break;
  737. case MOUSE_SERIAL_HARDWARE:
  738. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported Serial port mouse MouseIdentifier\n")); break;
  739. case WHEELMOUSE_HID_HARDWARE:
  740. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported HIDClass wheel mouse MouseIdentifier\n")); break;
  741. case WHEELMOUSE_I8042_HARDWARE:
  742. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported i8042 port wheel mouse MouseIdentifier\n")); break;
  743. case WHEELMOUSE_SERIAL_HARDWARE:
  744. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported Serial port wheel mouse MouseIdentifier\n")); break;
  745. default:
  746. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES reported unknown MouseIdentifier\n"));
  747. }
  748. }
  749. else
  750. {
  751. DbgPrint(("IOCTL_MOUSE_QUERY_ATTRIBUTES was NOT!!! STATUS_SUCCESS\n"));
  752. }
  753. }