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.

1362 lines
36 KiB

  1. #if defined(i386)
  2. /*++
  3. Copyright (c) 1989, 1990, 1991, 1992, 1993 Microsoft Corporation
  4. Module Name:
  5. inpcmn.c
  6. Abstract:
  7. The common portions of the Microsoft InPort mouse port driver.
  8. This file should not require modification to support new mice
  9. that are similar to the InPort mouse.
  10. Environment:
  11. Kernel mode only.
  12. Notes:
  13. NOTES: (Future/outstanding issues)
  14. - Powerfail not implemented.
  15. - IOCTL_INTERNAL_MOUSE_DISCONNECT has not been implemented. It's not
  16. needed until the class unload routine is implemented. Right now,
  17. we don't want to allow the mouse class driver to unload.
  18. - Consolidate duplicate code, where possible and appropriate.
  19. Revision History:
  20. --*/
  21. #include "stdarg.h"
  22. #include "stdio.h"
  23. #include "string.h"
  24. #include "ntddk.h"
  25. #include "inport.h"
  26. #include "inplog.h"
  27. //
  28. // Declare the global debug flag for this driver.
  29. //
  30. #if DBG
  31. ULONG InportDebug = 2;
  32. #endif
  33. VOID
  34. InportErrorLogDpc(
  35. IN PKDPC Dpc,
  36. IN PDEVICE_OBJECT DeviceObject,
  37. IN PIRP Irp,
  38. IN PVOID Context
  39. )
  40. /*++
  41. Routine Description:
  42. This routine runs at DISPATCH_LEVEL IRQL to log errors that are
  43. discovered at IRQL > DISPATCH_LEVEL (e.g., in the ISR routine or
  44. in a routine that is executed via KeSynchronizeExecution). There
  45. is not necessarily a current request associated with this condition.
  46. Arguments:
  47. Dpc - Pointer to the DPC object.
  48. DeviceObject - Pointer to the device object.
  49. Irp - Not used.
  50. Context - Indicates type of error to log.
  51. Return Value:
  52. None.
  53. --*/
  54. {
  55. PDEVICE_EXTENSION deviceExtension;
  56. PIO_ERROR_LOG_PACKET errorLogEntry;
  57. UNREFERENCED_PARAMETER(Dpc);
  58. UNREFERENCED_PARAMETER(Irp);
  59. InpPrint((2, "INPORT-InportErrorLogDpc: enter\n"));
  60. deviceExtension = DeviceObject->DeviceExtension;
  61. //
  62. // Log an error packet.
  63. //
  64. errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
  65. DeviceObject,
  66. sizeof(IO_ERROR_LOG_PACKET)
  67. + (2 * sizeof(ULONG))
  68. );
  69. if (errorLogEntry != NULL) {
  70. errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
  71. if ((ULONG) Context == INPORT_MOU_BUFFER_OVERFLOW) {
  72. errorLogEntry->UniqueErrorValue = INPORT_ERROR_VALUE_BASE + 210;
  73. errorLogEntry->DumpData[0] = sizeof(MOUSE_INPUT_DATA);
  74. errorLogEntry->DumpData[1] =
  75. deviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
  76. } else {
  77. errorLogEntry->UniqueErrorValue = INPORT_ERROR_VALUE_BASE + 220;
  78. errorLogEntry->DumpData[0] = 0;
  79. errorLogEntry->DumpData[1] = 0;
  80. }
  81. errorLogEntry->ErrorCode = (ULONG) Context;
  82. errorLogEntry->SequenceNumber = 0;
  83. errorLogEntry->MajorFunctionCode = 0;
  84. errorLogEntry->IoControlCode = 0;
  85. errorLogEntry->RetryCount = 0;
  86. errorLogEntry->FinalStatus = 0;
  87. IoWriteErrorLogEntry(errorLogEntry);
  88. }
  89. InpPrint((2, "INPORT-InportErrorLogDpc: exit\n"));
  90. }
  91. NTSTATUS
  92. InportFlush(
  93. IN PDEVICE_OBJECT DeviceObject,
  94. IN PIRP Irp
  95. )
  96. {
  97. UNREFERENCED_PARAMETER(DeviceObject);
  98. UNREFERENCED_PARAMETER(Irp);
  99. InpPrint((2,"INPORT-InportFlush: enter\n"));
  100. InpPrint((2,"INPORT-InportFlush: exit\n"));
  101. return(STATUS_NOT_IMPLEMENTED);
  102. }
  103. NTSTATUS
  104. InportInternalDeviceControl(
  105. IN PDEVICE_OBJECT DeviceObject,
  106. IN PIRP Irp
  107. )
  108. /*++
  109. Routine Description:
  110. This routine is the dispatch routine for internal device control requests.
  111. Arguments:
  112. DeviceObject - Pointer to the device object.
  113. Irp - Pointer to the request packet.
  114. Return Value:
  115. Status is returned.
  116. --*/
  117. {
  118. PIO_STACK_LOCATION irpSp;
  119. PDEVICE_EXTENSION deviceExtension;
  120. NTSTATUS status;
  121. InpPrint((2,"INPORT-InportInternalDeviceControl: enter\n"));
  122. //
  123. // Get a pointer to the device extension.
  124. //
  125. deviceExtension = DeviceObject->DeviceExtension;
  126. //
  127. // Initialize the returned Information field.
  128. //
  129. Irp->IoStatus.Information = 0;
  130. //
  131. // Get a pointer to the current parameters for this request. The
  132. // information is contained in the current stack location.
  133. //
  134. irpSp = IoGetCurrentIrpStackLocation(Irp);
  135. //
  136. // Case on the device control subfunction that is being performed by the
  137. // requestor.
  138. //
  139. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  140. //
  141. // Connect a mouse class device driver to the port driver.
  142. //
  143. case IOCTL_INTERNAL_MOUSE_CONNECT:
  144. InpPrint((
  145. 2,
  146. "INPORT-InportInternalDeviceControl: mouse connect\n"
  147. ));
  148. //
  149. // Only allow one connection.
  150. //
  151. //
  152. if (deviceExtension->ConnectData.ClassService != NULL) {
  153. InpPrint((
  154. 2,
  155. "INPORT-InportInternalDeviceControl: error - already connected\n"
  156. ));
  157. status = STATUS_SHARING_VIOLATION;
  158. break;
  159. }
  160. else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  161. sizeof(CONNECT_DATA)) {
  162. InpPrint((
  163. 2,
  164. "INPORT-InportInternalDeviceControl: error - invalid buffer length\n"
  165. ));
  166. status = STATUS_INVALID_PARAMETER;
  167. break;
  168. }
  169. //
  170. // Copy the connection parameters to the device extension.
  171. //
  172. deviceExtension->ConnectData =
  173. *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
  174. //
  175. // Set the completion status.
  176. //
  177. status = STATUS_SUCCESS;
  178. break;
  179. //
  180. // Disconnect a mouse class device driver from the port driver.
  181. //
  182. // NOTE: Not implemented.
  183. //
  184. case IOCTL_INTERNAL_MOUSE_DISCONNECT:
  185. InpPrint((
  186. 2,
  187. "INPORT-InportInternalDeviceControl: mouse disconnect\n"
  188. ));
  189. //
  190. // Perform a mouse interrupt disable call.
  191. //
  192. //
  193. // Clear the connection parameters in the device extension.
  194. // NOTE: Must synchronize this with the mouse ISR.
  195. //
  196. //
  197. //deviceExtension->ConnectData.ClassDeviceObject =
  198. // Null;
  199. //deviceExtension->ConnectData.ClassService =
  200. // Null;
  201. //
  202. // Set the completion status.
  203. //
  204. status = STATUS_NOT_IMPLEMENTED;
  205. break;
  206. // obsolete ioctls
  207. #if 0
  208. //
  209. // Enable mouse interrupts (mark the request pending and handle
  210. // it in StartIo).
  211. //
  212. case IOCTL_INTERNAL_MOUSE_ENABLE:
  213. InpPrint((
  214. 2,
  215. "INPORT-InportInternalDeviceControl: mouse enable\n"
  216. ));
  217. status = STATUS_PENDING;
  218. break;
  219. //
  220. // Disable mouse interrupts (mark the request pending and handle
  221. // it in StartIo).
  222. //
  223. case IOCTL_INTERNAL_MOUSE_DISABLE:
  224. InpPrint((
  225. 2,
  226. "INPORT-InportInternalDeviceControl: mouse disable\n"
  227. ));
  228. status = STATUS_PENDING;
  229. break;
  230. #endif
  231. //
  232. // Query the mouse attributes. First check for adequate buffer
  233. // length. Then, copy the mouse attributes from the device
  234. // extension to the output buffer.
  235. //
  236. case IOCTL_MOUSE_QUERY_ATTRIBUTES:
  237. InpPrint((
  238. 2,
  239. "INPORT-InportInternalDeviceControl: mouse query attributes\n"
  240. ));
  241. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  242. sizeof(MOUSE_ATTRIBUTES)) {
  243. status = STATUS_BUFFER_TOO_SMALL;
  244. } else {
  245. //
  246. // Copy the attributes from the DeviceExtension to the
  247. // buffer.
  248. //
  249. *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
  250. deviceExtension->Configuration.MouseAttributes;
  251. Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
  252. status = STATUS_SUCCESS;
  253. }
  254. break;
  255. default:
  256. InpPrint((
  257. 2,
  258. "INPORT-InportInternalDeviceControl: INVALID REQUEST\n"
  259. ));
  260. status = STATUS_INVALID_DEVICE_REQUEST;
  261. break;
  262. }
  263. Irp->IoStatus.Status = status;
  264. if (status == STATUS_PENDING) {
  265. IoMarkIrpPending(Irp);
  266. IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
  267. } else {
  268. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  269. }
  270. InpPrint((2,"INPORT-InportInternalDeviceControl: exit\n"));
  271. return(status);
  272. }
  273. VOID
  274. InportIsrDpc(
  275. IN PKDPC Dpc,
  276. IN PDEVICE_OBJECT DeviceObject,
  277. IN PIRP Irp,
  278. IN PVOID Context
  279. )
  280. /*++
  281. Routine Description:
  282. This routine runs at DISPATCH_LEVEL IRQL to finish processing
  283. mouse interrupts. It is queued in the mouse ISR. The real
  284. work is done via a callback to the connected mouse class driver.
  285. Arguments:
  286. Dpc - Pointer to the DPC object.
  287. DeviceObject - Pointer to the device object.
  288. Irp - Pointer to the Irp.
  289. Context - Not used.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. PDEVICE_EXTENSION deviceExtension;
  295. GET_DATA_POINTER_CONTEXT getPointerContext;
  296. SET_DATA_POINTER_CONTEXT setPointerContext;
  297. VARIABLE_OPERATION_CONTEXT operationContext;
  298. PVOID classService;
  299. PVOID classDeviceObject;
  300. LONG interlockedResult;
  301. BOOLEAN moreDpcProcessing;
  302. ULONG dataNotConsumed = 0;
  303. ULONG inputDataConsumed = 0;
  304. LARGE_INTEGER deltaTime;
  305. UNREFERENCED_PARAMETER(Dpc);
  306. UNREFERENCED_PARAMETER(Irp);
  307. UNREFERENCED_PARAMETER(Context);
  308. InpPrint((3, "INPORT-InportIsrDpc: enter\n"));
  309. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  310. //
  311. // Use DpcInterlockVariable to determine whether the DPC is running
  312. // concurrently on another processor. We only want one instantiation
  313. // of the DPC to actually do any work. DpcInterlockVariable is -1
  314. // when no DPC is executing. We increment it, and if the result is
  315. // zero then the current instantiation is the only one executing, and it
  316. // is okay to proceed. Otherwise, we just return.
  317. //
  318. //
  319. operationContext.VariableAddress =
  320. &deviceExtension->DpcInterlockVariable;
  321. operationContext.Operation = IncrementOperation;
  322. operationContext.NewValue = &interlockedResult;
  323. KeSynchronizeExecution(
  324. deviceExtension->InterruptObject,
  325. (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
  326. (PVOID) &operationContext
  327. );
  328. moreDpcProcessing = (interlockedResult == 0)? TRUE:FALSE;
  329. while (moreDpcProcessing) {
  330. dataNotConsumed = 0;
  331. inputDataConsumed = 0;
  332. //
  333. // Get the port InputData queue pointers synchronously.
  334. //
  335. getPointerContext.DeviceExtension = deviceExtension;
  336. setPointerContext.DeviceExtension = deviceExtension;
  337. setPointerContext.InputCount = 0;
  338. KeSynchronizeExecution(
  339. deviceExtension->InterruptObject,
  340. (PKSYNCHRONIZE_ROUTINE) InpGetDataQueuePointer,
  341. (PVOID) &getPointerContext
  342. );
  343. if (getPointerContext.InputCount != 0) {
  344. //
  345. // Call the connected class driver's callback ISR with the
  346. // port InputData queue pointers. If we have to wrap the queue,
  347. // break the operation into two pieces, and call the class callback
  348. // ISR once for each piece.
  349. //
  350. classDeviceObject =
  351. deviceExtension->ConnectData.ClassDeviceObject;
  352. classService =
  353. deviceExtension->ConnectData.ClassService;
  354. ASSERT(classService != NULL);
  355. if (getPointerContext.DataOut >= getPointerContext.DataIn) {
  356. //
  357. // We'll have to wrap the InputData circular buffer. Call
  358. // the class callback ISR with the chunk of data starting at
  359. // DataOut and ending at the end of the queue.
  360. //
  361. InpPrint((
  362. 3,
  363. "INPORT-InportIsrDpc: calling class callback\n"
  364. ));
  365. InpPrint((
  366. 3,
  367. "INPORT-InportIsrDpc: with Start 0x%x and End 0x%x\n",
  368. getPointerContext.DataOut,
  369. deviceExtension->DataEnd
  370. ));
  371. (*(PSERVICE_CALLBACK_ROUTINE) classService)(
  372. classDeviceObject,
  373. getPointerContext.DataOut,
  374. deviceExtension->DataEnd,
  375. &inputDataConsumed
  376. );
  377. dataNotConsumed = (((PUCHAR)
  378. deviceExtension->DataEnd -
  379. (PUCHAR) getPointerContext.DataOut)
  380. / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
  381. InpPrint((
  382. 3,
  383. "INPORT-InportIsrDpc: (Wrap) Call callback consumed %d items, left %d\n",
  384. inputDataConsumed,
  385. dataNotConsumed
  386. ));
  387. setPointerContext.InputCount += inputDataConsumed;
  388. if (dataNotConsumed) {
  389. setPointerContext.DataOut =
  390. ((PUCHAR)getPointerContext.DataOut) +
  391. (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
  392. } else {
  393. setPointerContext.DataOut =
  394. deviceExtension->InputData;
  395. getPointerContext.DataOut = setPointerContext.DataOut;
  396. }
  397. }
  398. //
  399. // Call the class callback ISR with data remaining in the queue.
  400. //
  401. if ((dataNotConsumed == 0) &&
  402. (inputDataConsumed < getPointerContext.InputCount)){
  403. InpPrint((
  404. 3,
  405. "INPORT-InportIsrDpc: calling class callback\n"
  406. ));
  407. InpPrint((
  408. 3,
  409. "INPORT-InportIsrDpc: with Start 0x%x and End 0x%x\n",
  410. getPointerContext.DataOut,
  411. getPointerContext.DataIn
  412. ));
  413. (*(PSERVICE_CALLBACK_ROUTINE) classService)(
  414. classDeviceObject,
  415. getPointerContext.DataOut,
  416. getPointerContext.DataIn,
  417. &inputDataConsumed
  418. );
  419. dataNotConsumed = (((PUCHAR) getPointerContext.DataIn -
  420. (PUCHAR) getPointerContext.DataOut)
  421. / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
  422. InpPrint((
  423. 3,
  424. "INPORT-InportIsrDpc: Call callback consumed %d items, left %d\n",
  425. inputDataConsumed,
  426. dataNotConsumed
  427. ));
  428. setPointerContext.DataOut =
  429. ((PUCHAR)getPointerContext.DataOut) +
  430. (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
  431. setPointerContext.InputCount += inputDataConsumed;
  432. }
  433. //
  434. // Update the port InputData queue DataOut pointer and InputCount
  435. // synchronously.
  436. //
  437. KeSynchronizeExecution(
  438. deviceExtension->InterruptObject,
  439. (PKSYNCHRONIZE_ROUTINE) InpSetDataQueuePointer,
  440. (PVOID) &setPointerContext
  441. );
  442. }
  443. if (dataNotConsumed) {
  444. //
  445. // The class driver was unable to consume all the data.
  446. // Reset the interlocked variable to -1. We do not want
  447. // to attempt to move more data to the class driver at this
  448. // point, because it is already overloaded. Need to wait a
  449. // while to give the Raw Input Thread a chance to read some
  450. // of the data out of the class driver's queue. We accomplish
  451. // this "wait" via a timer.
  452. //
  453. InpPrint((3, "INPORT-InportIsrDpc: set timer in DPC\n"));
  454. operationContext.Operation = WriteOperation;
  455. interlockedResult = -1;
  456. operationContext.NewValue = &interlockedResult;
  457. KeSynchronizeExecution(
  458. deviceExtension->InterruptObject,
  459. (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
  460. (PVOID) &operationContext
  461. );
  462. deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
  463. deltaTime.HighPart = -1;
  464. (VOID) KeSetTimer(
  465. &deviceExtension->DataConsumptionTimer,
  466. deltaTime,
  467. &deviceExtension->IsrDpcRetry
  468. );
  469. moreDpcProcessing = FALSE;
  470. } else {
  471. //
  472. // Decrement DpcInterlockVariable. If the result goes negative,
  473. // then we're all finished processing the DPC. Otherwise, either
  474. // the ISR incremented DpcInterlockVariable because it has more
  475. // work for the ISR DPC to do, or a concurrent DPC executed on
  476. // some processor while the current DPC was running (the
  477. // concurrent DPC wouldn't have done any work). Make sure that
  478. // the current DPC handles any extra work that is ready to be
  479. // done.
  480. //
  481. operationContext.Operation = DecrementOperation;
  482. operationContext.NewValue = &interlockedResult;
  483. KeSynchronizeExecution(
  484. deviceExtension->InterruptObject,
  485. (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
  486. (PVOID) &operationContext
  487. );
  488. if (interlockedResult != -1) {
  489. //
  490. // The interlocked variable is still greater than or equal to
  491. // zero. Reset it to zero, so that we execute the loop one
  492. // more time (assuming no more DPCs execute and bump the
  493. // variable up again).
  494. //
  495. operationContext.Operation = WriteOperation;
  496. interlockedResult = 0;
  497. operationContext.NewValue = &interlockedResult;
  498. KeSynchronizeExecution(
  499. deviceExtension->InterruptObject,
  500. (PKSYNCHRONIZE_ROUTINE) InpDpcVariableOperation,
  501. (PVOID) &operationContext
  502. );
  503. InpPrint((3, "INPORT-InportIsrDpc: loop in DPC\n"));
  504. } else {
  505. moreDpcProcessing = FALSE;
  506. }
  507. }
  508. }
  509. InpPrint((3, "INPORT-InportIsrDpc: exit\n"));
  510. }
  511. NTSTATUS
  512. InportCreate(
  513. IN PDEVICE_OBJECT DeviceObject,
  514. IN PIRP Irp
  515. )
  516. {
  517. NTSTATUS status = STATUS_SUCCESS;
  518. PDEVICE_EXTENSION deviceExtension;
  519. InpPrint((2, "INPORT-InportCreate: enter\n"));
  520. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  521. if (NULL == deviceExtension->ConnectData.ClassService) {
  522. //
  523. // No Connection yet. How can we be enabled?
  524. //
  525. InpPrint((3,"INPORT-InportCreate: not enabled!\n"));
  526. status = STATUS_INVALID_DEVICE_STATE;
  527. }
  528. else {
  529. InpEnableInterrupts(deviceExtension);
  530. }
  531. //
  532. // No need to call the lower driver (the root bus) because it only handles
  533. // Power and PnP Irps
  534. //
  535. Irp->IoStatus.Status = status;
  536. Irp->IoStatus.Information = 0;
  537. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  538. InpPrint((2, "INPORT-InportCreate: exit\n"));
  539. return status;
  540. }
  541. NTSTATUS
  542. InportClose(
  543. IN PDEVICE_OBJECT DeviceObject,
  544. IN PIRP Irp
  545. )
  546. /*++
  547. Routine Description:
  548. This is the dispatch routine for create/open and close requests.
  549. These requests complete successfully.
  550. Arguments:
  551. DeviceObject - Pointer to the device object.
  552. Irp - Pointer to the request packet.
  553. Return Value:
  554. Status is returned.
  555. --*/
  556. {
  557. UNREFERENCED_PARAMETER(DeviceObject);
  558. InpPrint((2,"INPORT-InportClose: enter\n"));
  559. Irp->IoStatus.Status = STATUS_SUCCESS;
  560. Irp->IoStatus.Information = 0;
  561. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  562. InpPrint((2,"INPORT-InportClose: exit\n"));
  563. return STATUS_SUCCESS;
  564. }
  565. VOID
  566. InportStartIo(
  567. IN PDEVICE_OBJECT DeviceObject,
  568. IN PIRP Irp
  569. )
  570. /*++
  571. Routine Description:
  572. This routine starts an I/O operation for the device.
  573. Arguments:
  574. DeviceObject - Pointer to the device object.
  575. Irp - Pointer to the request packet.
  576. Return Value:
  577. None.
  578. --*/
  579. {
  580. PDEVICE_EXTENSION deviceExtension;
  581. PIO_STACK_LOCATION irpSp;
  582. InpPrint((2, "INPORT-InportStartIo: enter\n"));
  583. deviceExtension = DeviceObject->DeviceExtension;
  584. //
  585. // Bump the error log sequence number.
  586. //
  587. deviceExtension->SequenceNumber += 1;
  588. //
  589. // Get a pointer to the current parameters for this request. The
  590. // information is contained in the current stack location.
  591. //
  592. irpSp = IoGetCurrentIrpStackLocation(Irp);
  593. //
  594. // We know we got here with an internal device control request. Switch
  595. // on IoControlCode.
  596. //
  597. switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
  598. //
  599. // Enable mouse interrupts, by calling InpEnableInterrupts
  600. // synchronously.
  601. //
  602. case IOCTL_INTERNAL_MOUSE_ENABLE:
  603. KeSynchronizeExecution(
  604. deviceExtension->InterruptObject,
  605. (PKSYNCHRONIZE_ROUTINE) InpEnableInterrupts,
  606. (PVOID) deviceExtension
  607. );
  608. InpPrint((
  609. 2,
  610. "INPORT-InportStartIo: mouse enable (count %d)\n",
  611. deviceExtension->MouseEnableCount
  612. ));
  613. Irp->IoStatus.Status = STATUS_SUCCESS;
  614. //
  615. // Complete the request.
  616. //
  617. IoStartNextPacket(DeviceObject, FALSE);
  618. IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
  619. break;
  620. //
  621. // Disable mouse interrupts, by calling InpDisableInterrupts
  622. // synchronously.
  623. //
  624. case IOCTL_INTERNAL_MOUSE_DISABLE:
  625. InpPrint((2, "INPORT-InportStartIo: mouse disable"));
  626. if (deviceExtension->MouseEnableCount == 0) {
  627. //
  628. // Mouse already disabled.
  629. //
  630. InpPrint((2, " - error\n"));
  631. Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
  632. } else {
  633. //
  634. // Disable mouse by calling InpDisableInterrupts.
  635. //
  636. KeSynchronizeExecution(
  637. deviceExtension->InterruptObject,
  638. (PKSYNCHRONIZE_ROUTINE) InpDisableInterrupts,
  639. (PVOID) deviceExtension
  640. );
  641. InpPrint((
  642. 2,
  643. " (count %d)\n",
  644. deviceExtension->MouseEnableCount
  645. ));
  646. Irp->IoStatus.Status = STATUS_SUCCESS;
  647. }
  648. //
  649. // Complete the request.
  650. //
  651. IoStartNextPacket(DeviceObject, FALSE);
  652. IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
  653. break;
  654. default:
  655. InpPrint((2, "INPORT-InportStartIo: INVALID REQUEST\n"));
  656. //
  657. // Log an internal error. Note that we're calling the
  658. // error log DPC routine directly, rather than duplicating
  659. // code.
  660. //
  661. InportErrorLogDpc(
  662. (PKDPC) NULL,
  663. DeviceObject,
  664. Irp,
  665. (PVOID) (ULONG) INPORT_INVALID_STARTIO_REQUEST
  666. );
  667. ASSERT(FALSE);
  668. break;
  669. }
  670. InpPrint((2, "INPORT-InportStartIo: exit\n"));
  671. return;
  672. }
  673. #if DBG
  674. VOID
  675. InpDebugPrint(
  676. ULONG DebugPrintLevel,
  677. PCCHAR DebugMessage,
  678. ...
  679. )
  680. /*++
  681. Routine Description:
  682. Debug print routine.
  683. Arguments:
  684. Debug print level between 0 and 3, with 3 being the most verbose.
  685. Return Value:
  686. None.
  687. --*/
  688. {
  689. va_list ap;
  690. va_start(ap, DebugMessage);
  691. if (DebugPrintLevel <= InportDebug) {
  692. char buffer[128];
  693. (VOID) vsprintf(buffer, DebugMessage, ap);
  694. DbgPrint(buffer);
  695. }
  696. va_end(ap);
  697. }
  698. #endif
  699. VOID
  700. InpDpcVariableOperation(
  701. IN PVOID Context
  702. )
  703. /*++
  704. Routine Description:
  705. This routine is called synchronously by the ISR DPC to perform an
  706. operation on the InterlockedDpcVariable. The operations that can be
  707. performed include increment, decrement, write, and read. The ISR
  708. itself reads and writes the InterlockedDpcVariable without calling this
  709. routine.
  710. Arguments:
  711. Context - Pointer to a structure containing the address of the variable
  712. to be operated on, the operation to perform, and the address at
  713. which to copy the resulting value of the variable (the latter is also
  714. used to pass in the value to write to the variable, on a write
  715. operation).
  716. Return Value:
  717. None.
  718. --*/
  719. {
  720. PVARIABLE_OPERATION_CONTEXT operationContext = Context;
  721. InpPrint((3,"INPORT-InpDpcVariableOperation: enter\n"));
  722. InpPrint((
  723. 3,
  724. "\tPerforming %s at 0x%x (current value 0x%x)\n",
  725. (operationContext->Operation == IncrementOperation)? "increment":
  726. (operationContext->Operation == DecrementOperation)? "decrement":
  727. (operationContext->Operation == WriteOperation)? "write":
  728. (operationContext->Operation == ReadOperation)? "read":"",
  729. operationContext->VariableAddress,
  730. *(operationContext->VariableAddress)
  731. ));
  732. //
  733. // Perform the specified operation at the specified address.
  734. //
  735. switch(operationContext->Operation) {
  736. case IncrementOperation:
  737. *(operationContext->VariableAddress) += 1;
  738. break;
  739. case DecrementOperation:
  740. *(operationContext->VariableAddress) -= 1;
  741. break;
  742. case ReadOperation:
  743. break;
  744. case WriteOperation:
  745. InpPrint((
  746. 3,
  747. "\tWriting 0x%x\n",
  748. *(operationContext->NewValue)
  749. ));
  750. *(operationContext->VariableAddress) =
  751. *(operationContext->NewValue);
  752. break;
  753. default:
  754. ASSERT(FALSE);
  755. break;
  756. }
  757. *(operationContext->NewValue) = *(operationContext->VariableAddress);
  758. InpPrint((
  759. 3,
  760. "INPORT-InpDpcVariableOperation: exit with value 0x%x\n",
  761. *(operationContext->NewValue)
  762. ));
  763. }
  764. VOID
  765. InpGetDataQueuePointer(
  766. IN PVOID Context
  767. )
  768. /*++
  769. Routine Description:
  770. This routine is called synchronously to get the current DataIn and DataOut
  771. pointers for the port InputData queue.
  772. Arguments:
  773. Context - Pointer to a structure containing the device extension,
  774. address at which to store the current DataIn pointer, and the
  775. address at which to store the current DataOut pointer.
  776. Return Value:
  777. None.
  778. --*/
  779. {
  780. PDEVICE_EXTENSION deviceExtension;
  781. InpPrint((3,"INPORT-InpGetDataQueuePointer: enter\n"));
  782. //
  783. // Get address of device extension.
  784. //
  785. deviceExtension = (PDEVICE_EXTENSION)
  786. ((PGET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
  787. //
  788. // Get the DataIn and DataOut pointers.
  789. //
  790. InpPrint((
  791. 3,
  792. "INPORT-InpGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
  793. deviceExtension->DataIn,
  794. deviceExtension->DataOut
  795. ));
  796. ((PGET_DATA_POINTER_CONTEXT) Context)->DataIn = deviceExtension->DataIn;
  797. ((PGET_DATA_POINTER_CONTEXT) Context)->DataOut = deviceExtension->DataOut;
  798. ((PGET_DATA_POINTER_CONTEXT) Context)->InputCount =
  799. deviceExtension->InputCount;
  800. InpPrint((3,"INPORT-InpGetDataQueuePointer: exit\n"));
  801. }
  802. VOID
  803. InpInitializeDataQueue (
  804. IN PVOID Context
  805. )
  806. /*++
  807. Routine Description:
  808. This routine initializes the input data queue. It is called
  809. via KeSynchronization, except when called from the initialization routine.
  810. Arguments:
  811. Context - Pointer to the device extension.
  812. Return Value:
  813. None.
  814. --*/
  815. {
  816. PDEVICE_EXTENSION deviceExtension;
  817. InpPrint((3,"INPORT-InpInitializeDataQueue: enter\n"));
  818. //
  819. // Get address of device extension.
  820. //
  821. deviceExtension = (PDEVICE_EXTENSION) Context;
  822. //
  823. // Initialize the input data queue.
  824. //
  825. deviceExtension->InputCount = 0;
  826. deviceExtension->DataIn = deviceExtension->InputData;
  827. deviceExtension->DataOut = deviceExtension->InputData;
  828. deviceExtension->OkayToLogOverflow = TRUE;
  829. InpPrint((3,"INPORT-InpInitializeDataQueue: exit\n"));
  830. }
  831. VOID
  832. InpSetDataQueuePointer(
  833. IN PVOID Context
  834. )
  835. /*++
  836. Routine Description:
  837. This routine is called synchronously to set the DataOut pointer
  838. and InputCount for the port InputData queue.
  839. Arguments:
  840. Context - Pointer to a structure containing the device extension
  841. and the new DataOut value for the port InputData queue.
  842. Return Value:
  843. None.
  844. --*/
  845. {
  846. PDEVICE_EXTENSION deviceExtension;
  847. InpPrint((3,"INPORT-InpSetDataQueuePointer: enter\n"));
  848. //
  849. // Get address of device extension.
  850. //
  851. deviceExtension = (PDEVICE_EXTENSION)
  852. ((PSET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
  853. //
  854. // Set the DataOut pointer.
  855. //
  856. InpPrint((
  857. 3,
  858. "INPORT-InpSetDataQueuePointer: old mouse DataOut 0x%x, InputCount %d\n",
  859. deviceExtension->DataOut,
  860. deviceExtension->InputCount
  861. ));
  862. deviceExtension->DataOut = ((PSET_DATA_POINTER_CONTEXT) Context)->DataOut;
  863. deviceExtension->InputCount -=
  864. ((PSET_DATA_POINTER_CONTEXT) Context)->InputCount;
  865. if (deviceExtension->InputCount == 0) {
  866. //
  867. // Reset the flag that determines whether it is time to log
  868. // queue overflow errors. We don't want to log errors too often.
  869. // Instead, log an error on the first overflow that occurs after
  870. // the ring buffer has been emptied, and then stop logging errors
  871. // until it gets cleared out and overflows again.
  872. //
  873. InpPrint((
  874. 4,
  875. "INPORT-InpSetDataQueuePointer: Okay to log overflow\n"
  876. ));
  877. deviceExtension->OkayToLogOverflow = TRUE;
  878. }
  879. InpPrint((
  880. 3,
  881. "INPORT-InpSetDataQueuePointer: new mouse DataOut 0x%x, InputCount %d\n",
  882. deviceExtension->DataOut,
  883. deviceExtension->InputCount
  884. ));
  885. InpPrint((3,"INPORT-InpSetDataQueuePointer: exit\n"));
  886. }
  887. BOOLEAN
  888. InpWriteDataToQueue(
  889. PDEVICE_EXTENSION DeviceExtension,
  890. IN PMOUSE_INPUT_DATA InputData
  891. )
  892. /*++
  893. Routine Description:
  894. This routine adds input data from the mouse to the InputData queue.
  895. Arguments:
  896. DeviceExtension - Pointer to the device extension.
  897. InputData - Pointer to the data to add to the InputData queue.
  898. Return Value:
  899. Returns TRUE if the data was added, otherwise FALSE.
  900. --*/
  901. {
  902. InpPrint((3,"INPORT-InpWriteDataToQueue: enter\n"));
  903. InpPrint((
  904. 3,
  905. "INPORT-InpWriteDataToQueue: DataIn 0x%x, DataOut 0x%x\n",
  906. DeviceExtension->DataIn,
  907. DeviceExtension->DataOut
  908. ));
  909. InpPrint((
  910. 3,
  911. "INPORT-InpWriteDataToQueue: InputCount %d\n",
  912. DeviceExtension->InputCount
  913. ));
  914. //
  915. // Check for full input data queue.
  916. //
  917. if ((DeviceExtension->DataIn == DeviceExtension->DataOut) &&
  918. (DeviceExtension->InputCount != 0)) {
  919. //
  920. // The input data queue is full. Intentionally ignore
  921. // the new data.
  922. //
  923. InpPrint((1,"INPORT-InpWriteDataToQueue: OVERFLOW\n"));
  924. return(FALSE);
  925. } else {
  926. *(DeviceExtension->DataIn) = *InputData;
  927. DeviceExtension->InputCount += 1;
  928. DeviceExtension->DataIn++;
  929. InpPrint((
  930. 3,
  931. "INPORT-InpWriteDataToQueue: new InputCount %d\n",
  932. DeviceExtension->InputCount
  933. ));
  934. if (DeviceExtension->DataIn ==
  935. DeviceExtension->DataEnd) {
  936. InpPrint((3,"INPORT-InpWriteDataToQueue: wrap buffer\n"));
  937. DeviceExtension->DataIn = DeviceExtension->InputData;
  938. }
  939. }
  940. InpPrint((3,"INPORT-InpWriteDataToQueue: exit\n"));
  941. return(TRUE);
  942. }
  943. VOID
  944. InpLogError(
  945. IN PDEVICE_OBJECT DeviceObject,
  946. IN NTSTATUS ErrorCode,
  947. IN ULONG UniqueErrorValue,
  948. IN NTSTATUS FinalStatus,
  949. IN PULONG DumpData,
  950. IN ULONG DumpCount
  951. )
  952. /*++
  953. Routine Description:
  954. This routine contains common code to write an error log entry. It is
  955. called from other routines, to avoid
  956. duplication of code. Note that some routines continue to have their
  957. own error logging code (especially in the case where the error logging
  958. can be localized and/or the routine has more data because there is
  959. and IRP).
  960. Arguments:
  961. DeviceObject - Pointer to the device object.
  962. ErrorCode - The error code for the error log packet.
  963. UniqueErrorValue - The unique error value for the error log packet.
  964. FinalStatus - The final status of the operation for the error log packet.
  965. DumpData - Pointer to an array of dump data for the error log packet.
  966. DumpCount - The number of entries in the dump data array.
  967. Return Value:
  968. None.
  969. --*/
  970. {
  971. PIO_ERROR_LOG_PACKET errorLogEntry;
  972. ULONG i;
  973. errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
  974. DeviceObject,
  975. (UCHAR)
  976. (sizeof(IO_ERROR_LOG_PACKET)
  977. + (DumpCount * sizeof(ULONG)))
  978. );
  979. if (errorLogEntry != NULL) {
  980. errorLogEntry->ErrorCode = ErrorCode;
  981. errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG));
  982. errorLogEntry->SequenceNumber = 0;
  983. errorLogEntry->MajorFunctionCode = 0;
  984. errorLogEntry->IoControlCode = 0;
  985. errorLogEntry->RetryCount = 0;
  986. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  987. errorLogEntry->FinalStatus = FinalStatus;
  988. for (i = 0; i < DumpCount; i++)
  989. errorLogEntry->DumpData[i] = DumpData[i];
  990. IoWriteErrorLogEntry(errorLogEntry);
  991. }
  992. }
  993. #endif