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.

905 lines
23 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 2000
  3. Module Name:
  4. swecp.c
  5. Abstract:
  6. Enhanced Capabilities Port (ECP)
  7. This module contains the code to perform all ECP related tasks (including
  8. ECP Software and ECP Hardware modes.)
  9. Author:
  10. Tim Wells (WESTTEK) - April 16, 1997
  11. Environment:
  12. Kernel mode
  13. Revision History :
  14. --*/
  15. #include "pch.h"
  16. BOOLEAN
  17. ParIsEcpSwWriteSupported(
  18. IN PPDO_EXTENSION Pdx
  19. )
  20. /*++
  21. Routine Description:
  22. This routine determines whether or not ECP mode is suported
  23. in the write direction by trying to negotiate when asked.
  24. Arguments:
  25. Pdx - The device extension.
  26. Return Value:
  27. BOOLEAN.
  28. --*/
  29. {
  30. NTSTATUS Status;
  31. //
  32. // Has a client driver or user mode app told us to avoid this mode
  33. // for this device via IOCTL_PAR_GET_DEVICE_CAPS?
  34. //
  35. if( Pdx->BadProtocolModes & ECP_SW ) {
  36. return FALSE;
  37. }
  38. //
  39. // Have we previously checked for and found that this mode is
  40. // supported with this device?
  41. //
  42. if( Pdx->ProtocolModesSupported & ECP_SW ) {
  43. return TRUE;
  44. }
  45. //
  46. // Determine if the mode is supported by trying to negotiate the
  47. // device the device into the requested mode.
  48. //
  49. // RMT - DVDF - 000709 - the following 2 lines really handle two distinct operations
  50. // each: (1) negotiating the peripheral into ECP, and (2) setting/clearing our
  51. // driver state machine. Consider breaking these operations out into two
  52. // distinct functions each.
  53. Status = ParEnterEcpSwMode( Pdx, FALSE );
  54. ParTerminateEcpMode( Pdx );
  55. if( NT_SUCCESS(Status) ) {
  56. Pdx->ProtocolModesSupported |= ECP_SW;
  57. return TRUE;
  58. } else {
  59. return FALSE;
  60. }
  61. }
  62. BOOLEAN
  63. ParIsEcpSwReadSupported(
  64. IN PPDO_EXTENSION Pdx
  65. )
  66. /*++
  67. Routine Description:
  68. This routine determines whether or not ECP mode is suported
  69. in the read direction (need to be able to float the data register
  70. drivers in order to do byte wide reads) by trying negotiate when asked.
  71. Arguments:
  72. Pdx - The device extension.
  73. Return Value:
  74. BOOLEAN.
  75. --*/
  76. {
  77. NTSTATUS Status;
  78. if( !(Pdx->HardwareCapabilities & PPT_ECP_PRESENT) &&
  79. !(Pdx->HardwareCapabilities & PPT_BYTE_PRESENT) ) {
  80. // Only use ECP Software in the reverse direction if an
  81. // ECR is present or we know that we can put the data register into Byte mode.
  82. return FALSE;
  83. }
  84. if (Pdx->BadProtocolModes & ECP_SW)
  85. return FALSE;
  86. if (Pdx->ProtocolModesSupported & ECP_SW)
  87. return TRUE;
  88. // Must use SWECP Enter and Terminate for this test.
  89. // Internel state machines will fail otherwise. --dvrh
  90. Status = ParEnterEcpSwMode (Pdx, FALSE);
  91. ParTerminateEcpMode (Pdx);
  92. if (NT_SUCCESS(Status)) {
  93. Pdx->ProtocolModesSupported |= ECP_SW;
  94. return TRUE;
  95. }
  96. return FALSE;
  97. }
  98. NTSTATUS
  99. ParEnterEcpSwMode(
  100. IN PPDO_EXTENSION Pdx,
  101. IN BOOLEAN DeviceIdRequest
  102. )
  103. /*++
  104. Routine Description:
  105. This routine performs 1284 negotiation with the peripheral to the
  106. ECP mode protocol.
  107. Arguments:
  108. Controller - Supplies the port address.
  109. DeviceIdRequest - Supplies whether or not this is a request for a device id.
  110. Return Value:
  111. STATUS_SUCCESS - Successful negotiation.
  112. otherwise - Unsuccessful negotiation.
  113. --*/
  114. {
  115. NTSTATUS status = STATUS_SUCCESS;
  116. if( Pdx->ModeSafety == SAFE_MODE ) {
  117. if( DeviceIdRequest ) {
  118. status = IeeeEnter1284Mode( Pdx, ECP_EXTENSIBILITY | DEVICE_ID_REQ );
  119. } else {
  120. status = IeeeEnter1284Mode( Pdx, ECP_EXTENSIBILITY );
  121. }
  122. } else {
  123. DD((PCE)Pdx,DDT,"ParEnterEcpSwMode: In UNSAFE_MODE\n");
  124. Pdx->Connected = TRUE;
  125. }
  126. if( NT_SUCCESS(status) ) {
  127. status = ParEcpSetupPhase( Pdx );
  128. }
  129. return status;
  130. }
  131. VOID
  132. ParCleanupSwEcpPort(
  133. IN PPDO_EXTENSION Pdx
  134. )
  135. /*++
  136. Routine Description:
  137. Cleans up prior to a normal termination from ECP mode. Puts the
  138. port HW back into Compatibility mode.
  139. Arguments:
  140. Controller - Supplies the parallel port's controller address.
  141. Return Value:
  142. None.
  143. --*/
  144. {
  145. PUCHAR Controller;
  146. UCHAR dcr; // Contents of DCR
  147. Controller = Pdx->Controller;
  148. //----------------------------------------------------------------------
  149. // Set data bus for output
  150. //----------------------------------------------------------------------
  151. dcr = P5ReadPortUchar(Controller + OFFSET_DCR); // Get content of DCR
  152. dcr = UPDATE_DCR( dcr, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
  153. P5WritePortUchar( Controller + OFFSET_DCR, dcr );
  154. return;
  155. }
  156. VOID
  157. ParTerminateEcpMode(
  158. IN PPDO_EXTENSION Pdx
  159. )
  160. /*++
  161. Routine Description:
  162. This routine terminates the interface back to compatibility mode.
  163. Arguments:
  164. Controller - Supplies the parallel port's controller address.
  165. Return Value:
  166. None.
  167. --*/
  168. {
  169. ParCleanupSwEcpPort(Pdx);
  170. if ( Pdx->ModeSafety == SAFE_MODE ) {
  171. IeeeTerminate1284Mode (Pdx);
  172. } else {
  173. DD((PCE)Pdx,DDT,"ParTerminateEcpMode: In UNSAFE_MODE\n");
  174. Pdx->Connected = FALSE;
  175. }
  176. return;
  177. }
  178. NTSTATUS
  179. ParEcpSetAddress(
  180. IN PPDO_EXTENSION Pdx,
  181. IN UCHAR Address
  182. )
  183. /*++
  184. Routine Description:
  185. Sets the ECP Address.
  186. Arguments:
  187. Pdx - Supplies the device extension.
  188. Address - The bus address to be set.
  189. Return Value:
  190. None.
  191. --*/
  192. {
  193. PUCHAR Controller;
  194. PUCHAR DCRController;
  195. UCHAR dcr;
  196. DD((PCE)Pdx,DDT,"ParEcpSetAddress: Start: Channel [%x]\n", Address);
  197. Controller = Pdx->Controller;
  198. DCRController = Controller + OFFSET_DCR;
  199. //
  200. // Event 34
  201. //
  202. // HostAck low indicates a command byte
  203. Pdx->CurrentEvent = 34;
  204. dcr = P5ReadPortUchar(DCRController);
  205. dcr = UPDATE_DCR( dcr, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE );
  206. P5WritePortUchar(DCRController, dcr);
  207. // Place the channel address on the bus
  208. // Bit 7 of the byte sent must be 1 to indicate that this is an address
  209. // instead of run length count.
  210. //
  211. P5WritePortUchar(Controller + DATA_OFFSET, (UCHAR)(Address | 0x80));
  212. //
  213. // Event 35
  214. //
  215. // Start handshake by dropping HostClk
  216. Pdx->CurrentEvent = 35;
  217. dcr = UPDATE_DCR( dcr, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE );
  218. P5WritePortUchar(DCRController, dcr);
  219. // =============== Periph State 36 ===============8
  220. // PeriphAck/PtrBusy = High (signals state 36)
  221. // PeriphClk/PtrClk = Don't Care
  222. // nAckReverse/AckDataReq = Don't Care
  223. // XFlag = Don't Care
  224. // nPeriphReq/nDataAvail = Don't Care
  225. Pdx->CurrentEvent = 35;
  226. if (!CHECK_DSR(Controller,
  227. ACTIVE, DONT_CARE, DONT_CARE,
  228. DONT_CARE, DONT_CARE,
  229. DEFAULT_RECEIVE_TIMEOUT))
  230. {
  231. DD((PCE)Pdx,DDE,"ECP::SendChannelAddress:State 36 Failed: Controller %x\n", Controller);
  232. // Make sure both HostAck and HostClk are high before leaving
  233. // HostClk should be high in forward transfer except when handshaking
  234. // HostAck should be high to indicate that what follows is data (not commands)
  235. //
  236. dcr = UPDATE_DCR( dcr, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
  237. P5WritePortUchar(DCRController, dcr);
  238. return STATUS_IO_DEVICE_ERROR;
  239. }
  240. //
  241. // Event 37
  242. //
  243. // Finish handshake by raising HostClk
  244. // HostClk is high when it's 0
  245. //
  246. Pdx->CurrentEvent = 37;
  247. dcr = UPDATE_DCR( dcr, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE );
  248. P5WritePortUchar(DCRController, dcr);
  249. // =============== Periph State 32 ===============8
  250. // PeriphAck/PtrBusy = Low (signals state 32)
  251. // PeriphClk/PtrClk = Don't Care
  252. // nAckReverse/AckDataReq = Don't Care
  253. // XFlag = Don't Care
  254. // nPeriphReq/nDataAvail = Don't Care
  255. Pdx->CurrentEvent = 32;
  256. if (!CHECK_DSR(Controller,
  257. INACTIVE, DONT_CARE, DONT_CARE,
  258. DONT_CARE, DONT_CARE,
  259. DEFAULT_RECEIVE_TIMEOUT))
  260. {
  261. DD((PCE)Pdx,DDE,"ECP::SendChannelAddress:State 32 Failed: Controller %x\n", Controller);
  262. // Make sure both HostAck and HostClk are high before leaving
  263. // HostClk should be high in forward transfer except when handshaking
  264. // HostAck should be high to indicate that what follows is data (not commands)
  265. //
  266. dcr = UPDATE_DCR( dcr, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
  267. P5WritePortUchar(DCRController, dcr);
  268. return STATUS_IO_DEVICE_ERROR;
  269. }
  270. // Make sure both HostAck and HostClk are high before leaving
  271. // HostClk should be high in forward transfer except when handshaking
  272. // HostAck should be high to indicate that what follows is data (not commands)
  273. //
  274. dcr = UPDATE_DCR( dcr, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
  275. P5WritePortUchar(DCRController, dcr);
  276. DD((PCE)Pdx,DDT,"ParEcpSetAddress, Exit [%d]\n", NT_SUCCESS(STATUS_SUCCESS));
  277. return STATUS_SUCCESS;
  278. }
  279. NTSTATUS
  280. ParEcpSwWrite(
  281. IN PPDO_EXTENSION Pdx,
  282. IN PVOID Buffer,
  283. IN ULONG BufferSize,
  284. OUT PULONG BytesTransferred
  285. )
  286. /*++
  287. Routine Description:
  288. Writes data to the peripheral using the ECP protocol under software
  289. control.
  290. Arguments:
  291. Pdx - Supplies the device extension.
  292. Buffer - Supplies the buffer to write from.
  293. BufferSize - Supplies the number of bytes in the buffer.
  294. BytesTransferred - Returns the number of bytes transferred.
  295. Return Value:
  296. None.
  297. --*/
  298. {
  299. PUCHAR Controller;
  300. NTSTATUS Status = STATUS_SUCCESS;
  301. PUCHAR pBuffer;
  302. LARGE_INTEGER Timeout;
  303. LARGE_INTEGER StartWrite;
  304. LARGE_INTEGER Wait;
  305. LARGE_INTEGER Start;
  306. LARGE_INTEGER End;
  307. UCHAR dsr;
  308. UCHAR dcr;
  309. ULONG i = 0;
  310. Controller = Pdx->Controller;
  311. pBuffer = Buffer;
  312. Status = ParTestEcpWrite(Pdx);
  313. if( !NT_SUCCESS(Status) ) {
  314. P5SetPhase( Pdx, PHASE_UNKNOWN );
  315. Pdx->Connected = FALSE;
  316. DD((PCE)Pdx,DDE,"ParEcpSwWrite: Invalid Entry State\n");
  317. goto ParEcpSwWrite_ExitLabel;
  318. }
  319. Wait.QuadPart = DEFAULT_RECEIVE_TIMEOUT * 10 * 1000 + KeQueryTimeIncrement();
  320. Timeout.QuadPart = Pdx->AbsoluteOneSecond.QuadPart * Pdx->TimerStart;
  321. KeQueryTickCount(&StartWrite);
  322. dcr = GetControl (Controller);
  323. // clear direction bit - enable output
  324. dcr &= ~(DCR_DIRECTION);
  325. StoreControl(Controller, dcr);
  326. KeStallExecutionProcessor(1);
  327. for (i = 0; i < BufferSize; i++) {
  328. //
  329. // Event 34
  330. //
  331. Pdx->CurrentEvent = 34;
  332. P5WritePortUchar(Controller + DATA_OFFSET, *pBuffer++);
  333. //
  334. // Event 35
  335. //
  336. Pdx->CurrentEvent = 35;
  337. dcr &= ~DCR_AUTOFEED;
  338. dcr |= DCR_STROBE;
  339. StoreControl (Controller, dcr);
  340. //
  341. // Waiting for Event 36
  342. //
  343. Pdx->CurrentEvent = 36;
  344. while (TRUE) {
  345. KeQueryTickCount(&End);
  346. dsr = GetStatus(Controller);
  347. if (!(dsr & DSR_NOT_BUSY)) {
  348. break;
  349. }
  350. if ((End.QuadPart - StartWrite.QuadPart) *
  351. KeQueryTimeIncrement() > Timeout.QuadPart) {
  352. dsr = GetStatus(Controller);
  353. if (!(dsr & DSR_NOT_BUSY)) {
  354. break;
  355. }
  356. //
  357. // Return the device to Idle.
  358. //
  359. dcr &= ~(DCR_STROBE);
  360. StoreControl (Controller, dcr);
  361. *BytesTransferred = i;
  362. Pdx->log.SwEcpWriteCount += *BytesTransferred;
  363. return STATUS_DEVICE_BUSY;
  364. }
  365. }
  366. //
  367. // Event 37
  368. //
  369. Pdx->CurrentEvent = 37;
  370. dcr &= ~DCR_STROBE;
  371. StoreControl (Controller, dcr);
  372. //
  373. // Waiting for Event 32
  374. //
  375. Pdx->CurrentEvent = 32;
  376. KeQueryTickCount(&Start);
  377. while (TRUE) {
  378. KeQueryTickCount(&End);
  379. dsr = GetStatus(Controller);
  380. if (dsr & DSR_NOT_BUSY) {
  381. break;
  382. }
  383. if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() >
  384. Wait.QuadPart) {
  385. dsr = GetStatus(Controller);
  386. if (dsr & DSR_NOT_BUSY) {
  387. break;
  388. }
  389. #if DVRH_BUS_RESET_ON_ERROR
  390. BusReset(Controller+OFFSET_DCR); // Pass in the dcr address
  391. #endif
  392. *BytesTransferred = i;
  393. Pdx->log.SwEcpWriteCount += *BytesTransferred;
  394. return STATUS_IO_DEVICE_ERROR;
  395. }
  396. }
  397. }
  398. ParEcpSwWrite_ExitLabel:
  399. *BytesTransferred = i;
  400. Pdx->log.SwEcpWriteCount += *BytesTransferred;
  401. return Status;
  402. }
  403. NTSTATUS
  404. ParEcpSwRead(
  405. IN PPDO_EXTENSION Pdx,
  406. IN PVOID Buffer,
  407. IN ULONG BufferSize,
  408. OUT PULONG BytesTransferred
  409. )
  410. /*++
  411. Routine Description:
  412. This routine performs a 1284 ECP mode read under software control
  413. into the given buffer for no more than 'BufferSize' bytes.
  414. Arguments:
  415. Pdx - Supplies the device extension.
  416. Buffer - Supplies the buffer to read into.
  417. BufferSize - Supplies the number of bytes in the buffer.
  418. BytesTransferred - Returns the number of bytes transferred.
  419. --*/
  420. {
  421. PUCHAR Controller;
  422. PUCHAR pBuffer;
  423. USHORT usTime;
  424. UCHAR dcr;
  425. ULONG i;
  426. UCHAR ecr = 0;
  427. Controller = Pdx->Controller;
  428. pBuffer = Buffer;
  429. dcr = GetControl (Controller);
  430. P5SetPhase( Pdx, PHASE_REVERSE_XFER );
  431. //
  432. // Put ECR into PS/2 mode and float the drivers.
  433. //
  434. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  435. // Save off the ECR register
  436. ecr = P5ReadPortUchar(Controller + ECR_OFFSET);
  437. }
  438. dcr |= DCR_DIRECTION;
  439. StoreControl (Controller, dcr);
  440. KeStallExecutionProcessor(1);
  441. for (i = 0; i < BufferSize; i++) {
  442. // dvtw - READ TIMEOUTS
  443. //
  444. // If it is the first byte then give it more time
  445. //
  446. if (!(GetStatus (Controller) & DSR_NOT_FAULT) || i == 0) {
  447. usTime = DEFAULT_RECEIVE_TIMEOUT;
  448. } else {
  449. usTime = IEEE_MAXTIME_TL;
  450. }
  451. // *************** State 43 Reverse Phase ***************8
  452. // PeriphAck/PtrBusy = DONT CARE
  453. // PeriphClk/PtrClk = LOW ( State 43 )
  454. // nAckReverse/AckDataReq = LOW
  455. // XFlag = HIGH
  456. // nPeriphReq/nDataAvail = DONT CARE
  457. Pdx->CurrentEvent = 43;
  458. if (!CHECK_DSR(Controller, DONT_CARE, INACTIVE, INACTIVE, ACTIVE, DONT_CARE,
  459. usTime)) {
  460. P5SetPhase( Pdx, PHASE_UNKNOWN );
  461. dcr &= ~DCR_DIRECTION;
  462. StoreControl (Controller, dcr);
  463. // restore ecr register
  464. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  465. P5WritePortUchar(Controller + ECR_OFFSET, ecr);
  466. }
  467. *BytesTransferred = i;
  468. Pdx->log.SwEcpReadCount += *BytesTransferred;
  469. return STATUS_IO_DEVICE_ERROR;
  470. }
  471. // *************** State 44 Setup Phase ***************8
  472. // DIR = DONT CARE
  473. // IRQEN = DONT CARE
  474. // 1284/SelectIn = DONT CARE
  475. // nReverseReq/**(ECP only)= DONT CARE
  476. // HostAck/HostBusy = HIGH ( State 44 )
  477. // HostClk/nStrobe = DONT CARE
  478. //
  479. Pdx->CurrentEvent = 44;
  480. dcr = P5ReadPortUchar(Controller + OFFSET_DCR);
  481. dcr = UPDATE_DCR(dcr, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, DONT_CARE);
  482. P5WritePortUchar(Controller + OFFSET_DCR, dcr);
  483. // *************** State 45 Reverse Phase ***************8
  484. // PeriphAck/PtrBusy = DONT CARE
  485. // PeriphClk/PtrClk = HIGH ( State 45 )
  486. // nAckReverse/AckDataReq = LOW
  487. // XFlag = HIGH
  488. // nPeriphReq/nDataAvail = DONT CARE
  489. Pdx->CurrentEvent = 45;
  490. if (!CHECK_DSR(Controller, DONT_CARE, ACTIVE, INACTIVE, ACTIVE, DONT_CARE,
  491. IEEE_MAXTIME_TL)) {
  492. P5SetPhase( Pdx, PHASE_UNKNOWN );
  493. dcr &= ~DCR_DIRECTION;
  494. StoreControl (Controller, dcr);
  495. // restore ecr register
  496. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  497. P5WritePortUchar(Controller + ECR_OFFSET, ecr);
  498. }
  499. *BytesTransferred = i;
  500. Pdx->log.SwEcpReadCount += *BytesTransferred;
  501. return STATUS_IO_DEVICE_ERROR;
  502. }
  503. //
  504. // Read the data
  505. //
  506. *pBuffer = P5ReadPortUchar (Controller + DATA_OFFSET);
  507. pBuffer++;
  508. // *************** State 46 Setup Phase ***************8
  509. // DIR = DONT CARE
  510. // IRQEN = DONT CARE
  511. // 1284/SelectIn = DONT CARE
  512. // nReverseReq/**(ECP only)= DONT CARE
  513. // HostAck/HostBusy = LOW ( State 46 )
  514. // HostClk/nStrobe = DONT CARE
  515. //
  516. Pdx->CurrentEvent = 46;
  517. dcr = P5ReadPortUchar(Controller + OFFSET_DCR);
  518. dcr = UPDATE_DCR(dcr, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE);
  519. P5WritePortUchar(Controller + OFFSET_DCR, dcr);
  520. }
  521. P5SetPhase( Pdx, PHASE_REVERSE_IDLE );
  522. dcr &= ~DCR_DIRECTION;
  523. StoreControl (Controller, dcr);
  524. // restore ecr register
  525. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  526. P5WritePortUchar(Controller + ECR_OFFSET, ecr);
  527. }
  528. *BytesTransferred = i;
  529. Pdx->log.SwEcpReadCount += *BytesTransferred;
  530. return STATUS_SUCCESS;
  531. }
  532. NTSTATUS
  533. ParEcpForwardToReverse(
  534. IN PPDO_EXTENSION Pdx
  535. )
  536. /*++
  537. Routine Description:
  538. This routine reverses the channel (ECP).
  539. Arguments:
  540. Pdx - Supplies the device extension.
  541. --*/
  542. {
  543. PUCHAR Controller;
  544. LARGE_INTEGER Wait35ms;
  545. LARGE_INTEGER Start;
  546. LARGE_INTEGER End;
  547. UCHAR dsr;
  548. UCHAR dcr;
  549. UCHAR ecr;
  550. Controller = Pdx->Controller;
  551. Wait35ms.QuadPart = 10*35*1000 + KeQueryTimeIncrement();
  552. dcr = GetControl (Controller);
  553. //
  554. // Put ECR into PS/2 mode to flush the FIFO.
  555. //
  556. // Save off the ECR register
  557. // Note: Don't worry about checking to see if it's
  558. // safe to touch the ecr since we've already checked
  559. // that before we allowed this mode to be activated.
  560. ecr = P5ReadPortUchar(Controller + ECR_OFFSET);
  561. //
  562. // Event 38
  563. //
  564. Pdx->CurrentEvent = 38;
  565. dcr |= DCR_AUTOFEED;
  566. StoreControl (Controller, dcr);
  567. KeStallExecutionProcessor(1);
  568. //
  569. // Event 39
  570. //
  571. Pdx->CurrentEvent = 39;
  572. dcr &= ~DCR_NOT_INIT;
  573. StoreControl (Controller, dcr);
  574. //
  575. // Wait for Event 40
  576. //
  577. Pdx->CurrentEvent = 40;
  578. KeQueryTickCount(&Start);
  579. while (TRUE) {
  580. KeQueryTickCount(&End);
  581. dsr = GetStatus(Controller);
  582. if (!(dsr & DSR_PERROR)) {
  583. break;
  584. }
  585. if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait35ms.QuadPart) {
  586. dsr = GetStatus(Controller);
  587. if (!(dsr & DSR_PERROR)) {
  588. break;
  589. }
  590. #if DVRH_BUS_RESET_ON_ERROR
  591. BusReset(Controller+OFFSET_DCR); // Pass in the dcr address
  592. #endif
  593. // restore the ecr register
  594. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  595. P5WritePortUchar(Controller + ECR_OFFSET, ecr);
  596. }
  597. DD((PCE)Pdx,DDE,"ParEcpForwardToReverse: Failed to get State 40\n");
  598. return STATUS_IO_DEVICE_ERROR;
  599. }
  600. }
  601. // restore the ecr register
  602. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  603. P5WritePortUchar(Controller + ECR_OFFSET, ecr);
  604. }
  605. P5SetPhase( Pdx, PHASE_REVERSE_IDLE );
  606. return STATUS_SUCCESS;
  607. }
  608. NTSTATUS
  609. ParEcpReverseToForward(
  610. IN PPDO_EXTENSION Pdx
  611. )
  612. /*++
  613. Routine Description:
  614. This routine puts the channel back into forward mode (ECP).
  615. Arguments:
  616. Pdx - Supplies the device extension.
  617. --*/
  618. {
  619. PUCHAR Controller;
  620. LARGE_INTEGER Wait35ms;
  621. LARGE_INTEGER Start;
  622. LARGE_INTEGER End;
  623. UCHAR dsr;
  624. UCHAR dcr;
  625. UCHAR ecr;
  626. Controller = Pdx->Controller;
  627. Wait35ms.QuadPart = 10*35*1000 + KeQueryTimeIncrement();
  628. dcr = GetControl (Controller);
  629. //
  630. // Put ECR into PS/2 mode to flush the FIFO.
  631. //
  632. // Save off the ECR register
  633. // Note: Don't worry about checking to see if it's
  634. // safe to touch the ecr since we've already checked
  635. // that before we allowed this mode to be activated.
  636. ecr = P5ReadPortUchar(Controller + ECR_OFFSET);
  637. //
  638. // Event 47
  639. //
  640. Pdx->CurrentEvent = 47;
  641. dcr |= DCR_NOT_INIT;
  642. StoreControl (Controller, dcr);
  643. //
  644. // Wait for Event 49
  645. //
  646. Pdx->CurrentEvent = 49;
  647. KeQueryTickCount(&Start);
  648. while (TRUE) {
  649. KeQueryTickCount(&End);
  650. dsr = GetStatus(Controller);
  651. if (dsr & DSR_PERROR) {
  652. break;
  653. }
  654. if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() >
  655. Wait35ms.QuadPart) {
  656. dsr = GetStatus(Controller);
  657. if (dsr & DSR_PERROR) {
  658. break;
  659. }
  660. #if DVRH_BUS_RESET_ON_ERROR
  661. BusReset(Controller+OFFSET_DCR); // Pass in the dcr address
  662. #endif
  663. // Restore the ecr register
  664. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  665. P5WritePortUchar(Controller + ECR_OFFSET, ecr);
  666. }
  667. DD((PCE)Pdx,DDE,"ParEcpReverseToForward: Failed to get State 49\n");
  668. return STATUS_IO_DEVICE_ERROR;
  669. }
  670. }
  671. // restore the ecr register
  672. if (Pdx->HardwareCapabilities & PPT_ECP_PRESENT) {
  673. P5WritePortUchar(Controller + ECR_OFFSET, ecr);
  674. }
  675. P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
  676. return STATUS_SUCCESS;
  677. }