Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1280 lines
32 KiB

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