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.

935 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. io.c
  5. Abstract:
  6. Contains functions that communicate to the serial driver below sermouse in
  7. the stack. This includes the read/complete loop mechanism to acquire bytes
  8. and IOCTL calls.
  9. Environment:
  10. Kernel & user mode.
  11. Revision History:
  12. --*/
  13. #include "mouser.h"
  14. #include "debug.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text (PAGE, SerialMousepIoSyncIoctl)
  17. #pragma alloc_text (PAGE, SerialMousepIoSyncIoctlEx)
  18. #endif
  19. //
  20. // Private definitions.
  21. //
  22. NTSTATUS
  23. SerialMouseReadComplete (
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN PIRP Irp,
  26. IN PDEVICE_EXTENSION DeviceExtension // (PVOID Context)
  27. )
  28. /*++
  29. Routine Description:
  30. This routine is the read IRP completion routine. It is called when the
  31. serial driver satisfies (or rejects) the IRP request we sent it. The
  32. read report is analysed, and a MOUSE_INPUT_DATA structure is built
  33. and sent to the mouse class driver via a callback routine.
  34. Arguments:
  35. DeviceObject - Pointer to the device object.
  36. Irp - Pointer to the request packet.
  37. Context - Pointer to the device context structure
  38. Return Value:
  39. NTSTATUS result code.
  40. --*/
  41. {
  42. LARGE_INTEGER li;
  43. ULONG inputDataConsumed,
  44. buttonsDelta,
  45. i;
  46. NTSTATUS status;
  47. PMOUSE_INPUT_DATA currentInput;
  48. KIRQL oldIrql;
  49. BOOLEAN startRead = TRUE;
  50. Print(DeviceExtension, DBG_READ_TRACE, ("ReadComplete enter\n"));
  51. //
  52. // Obtain the current status of the IRP.
  53. //
  54. status = Irp->IoStatus.Status;
  55. Print(DeviceExtension, DBG_SS_NOISE,
  56. ("Comp Routine: interlock was %d\n", DeviceExtension->ReadInterlock));
  57. //
  58. // If ReadInterlock is == START_READ, this func has been completed
  59. // synchronously. Place IMMEDIATE_READ into the interlock to signify this
  60. // situation; this will notify StartRead to loop when IoCallDriver returns.
  61. // Otherwise, we have been completed async and it is safe to call StartRead()
  62. //
  63. startRead =
  64. (SERIAL_MOUSE_START_READ !=
  65. InterlockedCompareExchange(&DeviceExtension->ReadInterlock,
  66. SERIAL_MOUSE_IMMEDIATE_READ,
  67. SERIAL_MOUSE_START_READ));
  68. //
  69. // Determine if the IRP request was successful.
  70. //
  71. switch (status) {
  72. case STATUS_SUCCESS:
  73. //
  74. // The buffer of the context now contains a single byte from the device.
  75. //
  76. Print(DeviceExtension, DBG_READ_NOISE,
  77. ("read, Information = %d\n",
  78. Irp->IoStatus.Information
  79. ));
  80. //
  81. // Nothing read, just start another read and return
  82. //
  83. if (Irp->IoStatus.Information == 0) {
  84. break;
  85. }
  86. ASSERT(Irp->IoStatus.Information == 1);
  87. currentInput = &DeviceExtension->InputData;
  88. Print(DeviceExtension, DBG_READ_NOISE,
  89. ("byte is 0x%x\n",
  90. (ULONG) DeviceExtension->ReadBuffer[0]
  91. ));
  92. if ((*DeviceExtension->ProtocolHandler)(
  93. DeviceExtension,
  94. currentInput,
  95. &DeviceExtension->HandlerData,
  96. DeviceExtension->ReadBuffer[0],
  97. 0
  98. )) {
  99. //
  100. // The report is complete, compute the button deltas and send it off
  101. //
  102. // Do we have a button state change?
  103. //
  104. if (DeviceExtension->HandlerData.PreviousButtons ^ currentInput->RawButtons) {
  105. //
  106. // The state of the buttons changed. Make some calculations...
  107. //
  108. buttonsDelta = DeviceExtension->HandlerData.PreviousButtons ^
  109. currentInput->RawButtons;
  110. //
  111. // Button 1.
  112. //
  113. if (buttonsDelta & MOUSE_BUTTON_1) {
  114. if (currentInput->RawButtons & MOUSE_BUTTON_1) {
  115. currentInput->ButtonFlags |= MOUSE_BUTTON_1_DOWN;
  116. }
  117. else {
  118. currentInput->ButtonFlags |= MOUSE_BUTTON_1_UP;
  119. }
  120. }
  121. //
  122. // Button 2.
  123. //
  124. if (buttonsDelta & MOUSE_BUTTON_2) {
  125. if (currentInput->RawButtons & MOUSE_BUTTON_2) {
  126. currentInput->ButtonFlags |= MOUSE_BUTTON_2_DOWN;
  127. }
  128. else {
  129. currentInput->ButtonFlags |= MOUSE_BUTTON_2_UP;
  130. }
  131. }
  132. //
  133. // Button 3.
  134. //
  135. if (buttonsDelta & MOUSE_BUTTON_3) {
  136. if (currentInput->RawButtons & MOUSE_BUTTON_3) {
  137. currentInput->ButtonFlags |= MOUSE_BUTTON_3_DOWN;
  138. }
  139. else {
  140. currentInput->ButtonFlags |= MOUSE_BUTTON_3_UP;
  141. }
  142. }
  143. DeviceExtension->HandlerData.PreviousButtons =
  144. currentInput->RawButtons;
  145. }
  146. Print(DeviceExtension, DBG_READ_NOISE,
  147. ("Buttons: %0lx\n",
  148. currentInput->Buttons
  149. ));
  150. if (DeviceExtension->EnableCount) {
  151. //
  152. // Synchronization issue - it's not a big deal if .Enabled is set
  153. // FALSE after the condition above, but before the callback below,
  154. // so long as the .MouClassCallback field is not nulled. This is
  155. // guaranteed since the disconnect IOCTL is not implemented yet.
  156. //
  157. // Mouse class callback assumes we are running at DISPATCH level,
  158. // however this IoCompletion routine can be running <= DISPATCH.
  159. // Raise the IRQL before calling the callback.
  160. //
  161. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  162. //
  163. // Call the callback.
  164. //
  165. (*(PSERVICE_CALLBACK_ROUTINE)
  166. DeviceExtension->ConnectData.ClassService) (
  167. DeviceExtension->ConnectData.ClassDeviceObject,
  168. currentInput,
  169. currentInput+1,
  170. &inputDataConsumed);
  171. //
  172. // Restore the previous IRQL right away.
  173. //
  174. KeLowerIrql(oldIrql);
  175. if (1 != inputDataConsumed) {
  176. //
  177. // oh well, the packet was not consumed, just drop it
  178. //
  179. Print(DeviceExtension, DBG_READ_ERROR,
  180. ("packet not consumed!!!\n"));
  181. }
  182. }
  183. //
  184. // Clear the button flags for the next packet
  185. //
  186. currentInput->Buttons = 0;
  187. }
  188. break;
  189. case STATUS_TIMEOUT:
  190. // The IO timed out, this shouldn't happen because we set the timeouts
  191. // to never when the device was initialized
  192. break;
  193. case STATUS_CANCELLED:
  194. // The read IRP was cancelled. Do not send any more read IRPs.
  195. //
  196. // Set the event so that the stop code can continue processing
  197. //
  198. KeSetEvent(&DeviceExtension->StopEvent, 0, FALSE);
  199. case STATUS_DELETE_PENDING:
  200. case STATUS_DEVICE_NOT_CONNECTED:
  201. //
  202. // The serial mouse object is being deleted. We will soon
  203. // receive Plug 'n Play notification of this device's removal,
  204. // if we have not received it already.
  205. //
  206. Print(DeviceExtension, DBG_READ_INFO,
  207. ("removing lock on cancel, count is 0x%x\n",
  208. DeviceExtension->EnableCount));
  209. IoReleaseRemoveLock(&DeviceExtension->RemoveLock, DeviceExtension->ReadIrp);
  210. startRead = FALSE;
  211. break;
  212. default:
  213. //
  214. // Unknown device state
  215. //
  216. Print(DeviceExtension, DBG_READ_ERROR, ("read error\n"));
  217. TRAP();
  218. }
  219. if (startRead) {
  220. Print(DeviceExtension, DBG_READ_NOISE, ("calling StartRead directly\n"));
  221. SerialMouseStartRead(DeviceExtension);
  222. }
  223. #if DBG
  224. else {
  225. Print(DeviceExtension, DBG_READ_NOISE, ("StartRead will loop\n"));
  226. }
  227. #endif
  228. return STATUS_MORE_PROCESSING_REQUIRED;
  229. }
  230. NTSTATUS
  231. SerialMouseStartRead (
  232. IN PDEVICE_EXTENSION DeviceExtension
  233. )
  234. /*++
  235. Routine Description:
  236. Initiates a read to the serial port driver.
  237. Note that the routine does not verify that the device context is in the
  238. OperationPending state, but simply assumes it.
  239. Note the IoCount must be incremented before entering into this read loop.
  240. Arguments:
  241. DeviceExtension - Device context structure
  242. Return Value:
  243. NTSTATUS result code from IoCallDriver().
  244. --*/
  245. {
  246. PIRP irp;
  247. NTSTATUS status = STATUS_SUCCESS;
  248. PIO_STACK_LOCATION stack;
  249. PDEVICE_OBJECT self;
  250. LONG oldInterlock;
  251. KIRQL irql;
  252. Print(DeviceExtension, DBG_READ_TRACE, ("Start Read: Enter\n"));
  253. irp = DeviceExtension->ReadIrp;
  254. while (1) {
  255. if ((DeviceExtension->Removed) ||
  256. (!DeviceExtension->Started) ||
  257. (DeviceExtension->EnableCount == 0)) {
  258. Print(DeviceExtension, DBG_READ_INFO | DBG_READ_ERROR,
  259. ("removing lock on start read\n"));
  260. //
  261. // Set the event so that the stop code can continue processing
  262. //
  263. KeSetEvent(&DeviceExtension->StopEvent, 0, FALSE);
  264. IoReleaseRemoveLock(&DeviceExtension->RemoveLock,
  265. DeviceExtension->ReadIrp);
  266. return STATUS_UNSUCCESSFUL;
  267. }
  268. //
  269. // Make sure we have not been stopped
  270. //
  271. KeAcquireSpinLock(&DeviceExtension->PnpStateLock, &irql);
  272. if (DeviceExtension->Stopped) {
  273. KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql);
  274. //
  275. // Set the event so that the stop code can continue processing
  276. //
  277. KeSetEvent(&DeviceExtension->StopEvent, 0, FALSE);
  278. //
  279. // Release the remove lock that we acquired when we started the read
  280. // spinner irp
  281. //
  282. IoReleaseRemoveLock(&DeviceExtension->RemoveLock,
  283. DeviceExtension->ReadIrp);
  284. return STATUS_SUCCESS;
  285. }
  286. //
  287. // It is important to only reuse the irp when we are holding onto the
  288. // spinlock, otherwise we can race
  289. //
  290. IoReuseIrp(irp, STATUS_SUCCESS);
  291. KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql);
  292. //
  293. // This is where things get interesting. We don't want to call
  294. // SerialMouseStartRead if this read was completed synchronously by the
  295. // serial provider because we can potentially run out of stack space.
  296. //
  297. // Here is how we solve this:
  298. // At the beginning of StartRead(), the interlock is set to START_READ
  299. // IoCallDriver is called...
  300. // o If the read will be completed asynchronously, then StartRead()
  301. // will continue executing and set the interlock to END_READ.
  302. // o If the request will be completed synchronously, then the
  303. // completion routine will run before StartRead() has the chance of
  304. // setting the interlock to END_READ. We note this situation by
  305. // setting the interlock to IMMEDIATE_READ in the completion function.
  306. // Furthermore, StartRead() will not be called from the completion
  307. // routine as it would be in the async case
  308. // o Upon setting the interlock to END_READ in StartReaD(), the
  309. // previous value is examined. If it is IMMEDIATE_READ, then
  310. // StartRead() loops and calls IoCallDriver from the same location
  311. // within the (call) stack frame. If the previous value was *not*
  312. // IMMEDIATE_READ, then StartRead() exits and the completion routine
  313. // will be called in another context (and, thus, another stack) and
  314. // make the next call to StartRead()
  315. //
  316. #if DBG
  317. oldInterlock =
  318. #endif
  319. InterlockedExchange(&DeviceExtension->ReadInterlock,
  320. SERIAL_MOUSE_START_READ);
  321. //
  322. // END_READ should be the only value here!!! If not, the state machine
  323. // of the interlock has been broken
  324. //
  325. ASSERT(oldInterlock == SERIAL_MOUSE_END_READ);
  326. //
  327. // start this read.
  328. //
  329. self = DeviceExtension->Self;
  330. //
  331. // Set the stack location for the serenum stack
  332. //
  333. // Remember to get the file pointer correct.
  334. // NOTE: we do not have any of the cool thread stuff set.
  335. // therefore we need to make sure that we cut this IRP off
  336. // at the knees when it returns. (STATUS_MORE_PROCESSING_REQUIRED)
  337. //
  338. // Note also that serial does buffered i/o
  339. //
  340. irp->AssociatedIrp.SystemBuffer = (PVOID) DeviceExtension->ReadBuffer;
  341. stack = IoGetNextIrpStackLocation(irp);
  342. stack->Parameters.Read.Length = 1;
  343. stack->Parameters.Read.ByteOffset.QuadPart = (LONGLONG) 0;
  344. stack->MajorFunction = IRP_MJ_READ;
  345. //
  346. // Hook a completion routine for when the device completes.
  347. //
  348. IoSetCompletionRoutine(irp,
  349. SerialMouseReadComplete,
  350. DeviceExtension,
  351. TRUE,
  352. TRUE,
  353. TRUE);
  354. status = IoCallDriver(DeviceExtension->TopOfStack, irp);
  355. if (InterlockedExchange(&DeviceExtension->ReadInterlock,
  356. SERIAL_MOUSE_END_READ) !=
  357. SERIAL_MOUSE_IMMEDIATE_READ) {
  358. //
  359. // The read is asynch, will call SerialMouseStartRead from the
  360. // completion routine
  361. //
  362. Print(DeviceExtension, DBG_READ_NOISE, ("read is pending\n"));
  363. break;
  364. }
  365. #if DBG
  366. else {
  367. //
  368. // The read was synchronous (probably bytes in the buffer). The
  369. // completion routine will not call SerialMouseStartRead, so we
  370. // just loop here. This is to prevent us from running out of stack
  371. // space if always call StartRead from the completion routine
  372. //
  373. Print(DeviceExtension, DBG_READ_NOISE, ("read is looping\n"));
  374. }
  375. #endif
  376. }
  377. return status;
  378. }
  379. //
  380. // Stripped down version of SerialMouseIoSyncIoctlEx that
  381. // doesn't use input or output buffers
  382. //
  383. NTSTATUS
  384. SerialMousepIoSyncIoctl(
  385. BOOLEAN Internal,
  386. ULONG Ioctl,
  387. PDEVICE_OBJECT DeviceObject,
  388. PKEVENT Event,
  389. PIO_STATUS_BLOCK Iosb)
  390. {
  391. return SerialMousepIoSyncIoctlEx(Internal,
  392. Ioctl,
  393. DeviceObject,
  394. Event,
  395. Iosb,
  396. NULL,
  397. 0,
  398. NULL,
  399. 0);
  400. }
  401. NTSTATUS
  402. SerialMousepIoSyncIoctlEx(
  403. BOOLEAN Internal,
  404. ULONG Ioctl, // io control code
  405. PDEVICE_OBJECT DeviceObject, // object to call
  406. PKEVENT Event, // event to wait on
  407. PIO_STATUS_BLOCK Iosb, // used inside IRP
  408. PVOID InBuffer, OPTIONAL // input buffer
  409. ULONG InBufferLen, OPTIONAL // input buffer length
  410. PVOID OutBuffer, OPTIONAL // output buffer
  411. ULONG OutBufferLen) OPTIONAL // output buffer length
  412. /*++
  413. Routine Description:
  414. Performs a synchronous IO control request by waiting on the event object
  415. passed to it. The IRP is deallocated by the IO system when finished.
  416. Return value:
  417. NTSTATUS
  418. --*/
  419. {
  420. PIRP irp;
  421. NTSTATUS status;
  422. KeClearEvent(Event);
  423. //
  424. // Allocate an IRP - No need to release
  425. // When the next-lower driver completes this IRP, the I/O Manager releases it.
  426. //
  427. if (NULL == (irp = IoBuildDeviceIoControlRequest(Ioctl,
  428. DeviceObject,
  429. InBuffer,
  430. InBufferLen,
  431. OutBuffer,
  432. OutBufferLen,
  433. Internal,
  434. Event,
  435. Iosb))) {
  436. return STATUS_INSUFFICIENT_RESOURCES;
  437. }
  438. status = IoCallDriver(DeviceObject, irp);
  439. if (STATUS_PENDING == status) {
  440. //
  441. // wait for it...
  442. //
  443. status = KeWaitForSingleObject(Event,
  444. Executive,
  445. KernelMode,
  446. FALSE, // Not alertable
  447. NULL); // No timeout structure
  448. }
  449. if (NT_SUCCESS(status)) {
  450. status = Iosb->Status;
  451. }
  452. return status;
  453. }
  454. NTSTATUS
  455. SerialMouseSetReadTimeouts(
  456. PDEVICE_EXTENSION DeviceExtension,
  457. ULONG Timeout
  458. )
  459. {
  460. NTSTATUS status;
  461. SERIAL_TIMEOUTS serialTimeouts;
  462. KEVENT event;
  463. IO_STATUS_BLOCK iosb;
  464. KeInitializeEvent(&event, NotificationEvent, FALSE);
  465. RtlZeroMemory(&serialTimeouts, sizeof(SERIAL_TIMEOUTS));
  466. if (Timeout != 0) {
  467. serialTimeouts.ReadIntervalTimeout = MAXULONG;
  468. serialTimeouts.ReadTotalTimeoutMultiplier = MAXULONG;
  469. serialTimeouts.ReadTotalTimeoutConstant = Timeout;
  470. }
  471. status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
  472. DeviceExtension->TopOfStack,
  473. &event,
  474. &iosb,
  475. &serialTimeouts,
  476. sizeof(SERIAL_TIMEOUTS),
  477. NULL,
  478. 0);
  479. return status;
  480. }
  481. NTSTATUS
  482. SerialMouseReadSerialPortComplete(
  483. IN PDEVICE_OBJECT DeviceObject,
  484. IN PIRP Irp,
  485. IN PKEVENT Event
  486. )
  487. {
  488. UNREFERENCED_PARAMETER(DeviceObject);
  489. KeSetEvent(Event, 0, FALSE);
  490. return STATUS_MORE_PROCESSING_REQUIRED;
  491. }
  492. NTSTATUS
  493. SerialMouseReadSerialPort (
  494. PDEVICE_EXTENSION DeviceExtension,
  495. PCHAR ReadBuffer,
  496. USHORT Buflen,
  497. PUSHORT ActualBytesRead
  498. )
  499. /*++
  500. Routine Description:
  501. Performs a synchronous read on the serial port. Used during setup so that
  502. the type of device can be determined.
  503. Return value:
  504. NTSTATUS - STATUS_SUCCESS if the read was successful, error code otherwise
  505. --*/
  506. {
  507. NTSTATUS status = STATUS_SUCCESS;
  508. PIRP irp;
  509. KEVENT event;
  510. IO_STATUS_BLOCK iosb;
  511. PDEVICE_OBJECT self;
  512. PIO_STACK_LOCATION stack;
  513. SERIAL_TIMEOUTS serialTimeouts;
  514. int i, numReads;
  515. KeInitializeEvent(&event, NotificationEvent, FALSE);
  516. if (!NT_SUCCESS(status)) {
  517. return status;
  518. }
  519. self = DeviceExtension->Self;
  520. irp = DeviceExtension->ReadIrp;
  521. Print(DeviceExtension, DBG_SS_TRACE, ("Read pending...\n"));
  522. *ActualBytesRead = 0;
  523. while (*ActualBytesRead < Buflen) {
  524. KeClearEvent(&event);
  525. IoReuseIrp(irp, STATUS_SUCCESS);
  526. irp->AssociatedIrp.SystemBuffer = ReadBuffer;
  527. stack = IoGetNextIrpStackLocation(irp);
  528. stack->Parameters.Read.Length = 1;
  529. stack->Parameters.Read.ByteOffset.QuadPart = (LONGLONG) 0;
  530. stack->MajorFunction = IRP_MJ_READ;
  531. //
  532. // Hook a completion routine for when the device completes.
  533. //
  534. IoSetCompletionRoutine(irp,
  535. SerialMouseReadSerialPortComplete,
  536. &event,
  537. TRUE,
  538. TRUE,
  539. TRUE);
  540. status = IoCallDriver(DeviceExtension->TopOfStack, irp);
  541. if (status == STATUS_PENDING) {
  542. //
  543. // Wait for the IRP
  544. //
  545. status = KeWaitForSingleObject(&event,
  546. Executive,
  547. KernelMode,
  548. FALSE,
  549. NULL);
  550. if (status == STATUS_SUCCESS) {
  551. status = irp->IoStatus.Status;
  552. }
  553. }
  554. if (!NT_SUCCESS(status) || status == STATUS_TIMEOUT) {
  555. Print(DeviceExtension, DBG_SS_NOISE,
  556. ("IO Call failed with status %x\n", status));
  557. return status;
  558. }
  559. *ActualBytesRead += (USHORT) irp->IoStatus.Information;
  560. ReadBuffer += (USHORT) irp->IoStatus.Information;
  561. }
  562. return status;
  563. }
  564. NTSTATUS
  565. SerialMouseWriteSerialPort (
  566. PDEVICE_EXTENSION DeviceExtension,
  567. PCHAR WriteBuffer,
  568. ULONG NumBytes,
  569. PIO_STATUS_BLOCK IoStatusBlock
  570. )
  571. /*++
  572. Routine Description:
  573. Performs a synchronous write on the serial port. Used during setup so that
  574. the device can be configured.
  575. Return value:
  576. NTSTATUS - STATUS_SUCCESS if the read was successful, error code otherwise
  577. --*/
  578. {
  579. NTSTATUS status;
  580. PIRP irp;
  581. LARGE_INTEGER startingOffset;
  582. KEVENT event;
  583. int i, numReads;
  584. startingOffset.QuadPart = (LONGLONG) 0;
  585. KeInitializeEvent(&event,
  586. NotificationEvent,
  587. FALSE);
  588. Print(DeviceExtension, DBG_SS_TRACE, ("Write pending...\n"));
  589. //
  590. // Create a new IRP because there's a chance that it might get cancelled.
  591. // Can't cancel irps that I received.
  592. // IRP_MJ_READ with completion routine
  593. //
  594. if (NULL == (irp = IoBuildSynchronousFsdRequest(
  595. IRP_MJ_WRITE,
  596. DeviceExtension->TopOfStack,
  597. WriteBuffer,
  598. NumBytes,
  599. &startingOffset,
  600. &event,
  601. IoStatusBlock
  602. ))) {
  603. Print(DeviceExtension, DBG_SS_ERROR, ("Failed to allocate IRP\n"));
  604. return STATUS_INSUFFICIENT_RESOURCES;
  605. }
  606. status = IoCallDriver(DeviceExtension->TopOfStack, irp);
  607. if (status == STATUS_PENDING) {
  608. // I don't know at this time if I can wait with the default time of
  609. // 200 ms as I'm doing. In the help file for IoBuildSynchronousFsdRequest
  610. // I think that it says I can't, but I'm not quite sure.
  611. // Presently I will. I'll cancel the Irp if it isn't done.
  612. status = KeWaitForSingleObject(
  613. &event,
  614. Executive,
  615. KernelMode,
  616. FALSE, // Not alertable
  617. NULL);
  618. }
  619. status = IoStatusBlock->Status;
  620. if (!NT_SUCCESS(status)) {
  621. Print(DeviceExtension, DBG_SS_ERROR,
  622. ("IO Call failed with status %x\n",
  623. status
  624. ));
  625. return status;
  626. }
  627. if (!NT_SUCCESS(status)) {
  628. Print(DeviceExtension, DBG_SS_ERROR,
  629. ("IO Call failed with status %x\n",
  630. status
  631. ));
  632. }
  633. return status;
  634. }
  635. NTSTATUS
  636. SerialMouseWait (
  637. IN PDEVICE_EXTENSION DeviceExtension,
  638. IN LONG Timeout
  639. )
  640. /*++
  641. Routine Description:
  642. Performs a wait for the specified time.
  643. NB: Negative time is relative to the current time. Positive time
  644. represents an absolute time to wait until.
  645. Return value:
  646. NTSTATUS
  647. --*/
  648. {
  649. LARGE_INTEGER time;
  650. time.QuadPart = (LONGLONG) Timeout;
  651. Print(DeviceExtension, DBG_READ_NOISE,
  652. ("waiting for %d micro secs\n", Timeout));
  653. if (KeSetTimer(&DeviceExtension->DelayTimer,
  654. time,
  655. NULL)) {
  656. Print(DeviceExtension, DBG_SS_INFO, ("Timer already set\n"));
  657. }
  658. return KeWaitForSingleObject(&DeviceExtension->DelayTimer,
  659. Executive,
  660. KernelMode,
  661. FALSE, // Not allertable
  662. NULL); // No timeout structure
  663. }
  664. NTSTATUS
  665. SerialMouseInitializePort(
  666. PDEVICE_EXTENSION DeviceExtension
  667. )
  668. {
  669. NTSTATUS status;
  670. KEVENT event;
  671. IO_STATUS_BLOCK iosb;
  672. SERIAL_TIMEOUTS serialTimeouts;
  673. SERIAL_HANDFLOW serialHandFlow;
  674. KeInitializeEvent(&event, NotificationEvent, FALSE);
  675. status =
  676. SerialMouseIoSyncInternalIoctlEx(IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS,
  677. DeviceExtension->TopOfStack,
  678. &event,
  679. &iosb,
  680. NULL,
  681. 0,
  682. &DeviceExtension->SerialBasicSettings,
  683. sizeof(SERIAL_BASIC_SETTINGS));
  684. //
  685. // In case we are running on a port that does not support basic settings
  686. //
  687. if (!NT_SUCCESS(status)) {
  688. SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_TIMEOUTS,
  689. DeviceExtension->TopOfStack,
  690. &event,
  691. &iosb,
  692. NULL,
  693. 0,
  694. &DeviceExtension->SerialBasicSettings.Timeouts,
  695. sizeof(SERIAL_TIMEOUTS));
  696. RtlZeroMemory(&serialTimeouts, sizeof(SERIAL_TIMEOUTS));
  697. SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
  698. DeviceExtension->TopOfStack,
  699. &event,
  700. &iosb,
  701. &serialTimeouts,
  702. sizeof(SERIAL_TIMEOUTS),
  703. NULL,
  704. 0);
  705. SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_HANDFLOW,
  706. DeviceExtension->TopOfStack,
  707. &event,
  708. &iosb,
  709. NULL,
  710. 0,
  711. &DeviceExtension->SerialBasicSettings.HandFlow,
  712. sizeof(SERIAL_HANDFLOW));
  713. serialHandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
  714. serialHandFlow.FlowReplace = SERIAL_RTS_CONTROL;
  715. serialHandFlow.XonLimit = 0;
  716. serialHandFlow.XoffLimit = 0;
  717. status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_HANDFLOW,
  718. DeviceExtension->TopOfStack,
  719. &event,
  720. &iosb,
  721. &serialHandFlow,
  722. sizeof(SERIAL_HANDFLOW),
  723. NULL,
  724. 0);
  725. }
  726. return status;
  727. }
  728. VOID
  729. SerialMouseRestorePort(
  730. PDEVICE_EXTENSION DeviceExtension
  731. )
  732. {
  733. KEVENT event;
  734. IO_STATUS_BLOCK iosb;
  735. NTSTATUS status;
  736. KeInitializeEvent(&event, NotificationEvent, FALSE);
  737. status =
  738. SerialMouseIoSyncInternalIoctlEx(IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS,
  739. DeviceExtension->TopOfStack,
  740. &event,
  741. &iosb,
  742. &DeviceExtension->SerialBasicSettings,
  743. sizeof(SERIAL_BASIC_SETTINGS),
  744. NULL,
  745. 0);
  746. //
  747. // 4-24 Once serial.sys supports this new IOCTL, this code can be removed
  748. //
  749. if (!NT_SUCCESS(status)) {
  750. SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
  751. DeviceExtension->TopOfStack,
  752. &event,
  753. &iosb,
  754. &DeviceExtension->SerialBasicSettings.Timeouts,
  755. sizeof(SERIAL_TIMEOUTS),
  756. NULL,
  757. 0);
  758. SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_HANDFLOW,
  759. DeviceExtension->TopOfStack,
  760. &event,
  761. &iosb,
  762. &DeviceExtension->SerialBasicSettings.HandFlow,
  763. sizeof(SERIAL_HANDFLOW),
  764. NULL,
  765. 0);
  766. }
  767. }