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.

1726 lines
61 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. hwecp.c
  5. Abstract:
  6. This module contains code for the host to utilize HardwareECP if it has been
  7. detected and successfully enabled.
  8. Author:
  9. Robbie Harris (Hewlett-Packard) 21-May-1998
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "pch.h"
  15. #include "hwecp.h"
  16. VOID ParCleanupHwEcpPort(IN PDEVICE_EXTENSION Extension)
  17. /*++
  18. Routine Description:
  19. Cleans up prior to a normal termination from ECP mode. Puts the
  20. port HW back into Compatibility mode.
  21. Arguments:
  22. Controller - Supplies the parallel port's controller address.
  23. Return Value:
  24. None.
  25. --*/
  26. {
  27. PUCHAR Controller;
  28. NTSTATUS nError = STATUS_SUCCESS;
  29. // UCHAR bDCR; // Contents of DCR
  30. Controller = Extension->Controller;
  31. //----------------------------------------------------------------------
  32. // Set the ECR to mode 001 (PS2 Mode).
  33. //----------------------------------------------------------------------
  34. #if (1 == PARCHIP_ECR_ARBITRATOR)
  35. Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
  36. #else
  37. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  38. WRITE_PORT_UCHAR(Controller + ECR_OFFSET, DEFAULT_ECR_PS2);
  39. #else
  40. WRITE_PORT_UCHAR(Extension->EcrController + ECR_OFFSET, DEFAULT_ECR_PS2);
  41. #endif
  42. #endif
  43. Extension->PortHWMode = HW_MODE_PS2;
  44. ParCleanupSwEcpPort(Extension);
  45. //----------------------------------------------------------------------
  46. // Set the ECR to mode 000 (Compatibility Mode).
  47. //----------------------------------------------------------------------
  48. #if (1 == PARCHIP_ECR_ARBITRATOR)
  49. // Nothing to do!
  50. #else
  51. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  52. WRITE_PORT_UCHAR(Controller + ECR_OFFSET, DEFAULT_ECR_COMPATIBILITY);
  53. #else
  54. WRITE_PORT_UCHAR(Extension->EcrController + ECR_OFFSET, DEFAULT_ECR_COMPATIBILITY);
  55. #endif
  56. #endif
  57. Extension->PortHWMode = HW_MODE_COMPATIBILITY;
  58. }
  59. VOID ParEcpHwDrainShadowBuffer(
  60. IN Queue *pShadowBuffer,
  61. IN PUCHAR lpsBufPtr,
  62. IN ULONG dCount,
  63. OUT ULONG *fifoCount)
  64. {
  65. *fifoCount = 0;
  66. if (Queue_IsEmpty(pShadowBuffer)) {
  67. ParDump2(PARINFO,("ParEcpHwDrainShadowBuffer: No data in Shadow\r\n"));
  68. return;
  69. }
  70. while ( dCount > 0 ) {
  71. // LAC FRAME 13Jan98
  72. // Break out the Queue_Dequeue from the pointer increment so we can
  73. // observe the data if needed.
  74. if (FALSE == Queue_Dequeue(pShadowBuffer, lpsBufPtr)) { // Get byte from queue.
  75. ParDump2(PARERRORS,("ParEcpHwDrainShadowBuffer: ShadowBuffer Bad\r\n"));
  76. return;
  77. }
  78. ParDump2(PARINFO,("ParEcpHwDrainShadowBuffer: read data byte %02x\r\n",(int)*lpsBufPtr));
  79. lpsBufPtr++;
  80. dCount--; // Decrement count.
  81. (*fifoCount)++;
  82. }
  83. #if DBG
  84. if (*fifoCount) {
  85. ParTimerCheck(("ParEcpHwDrainShadowBuffer: read %d bytes from shadow\r\n", *fifoCount ));
  86. }
  87. #endif
  88. ParDump2( PARINFO, ("ParEcpHwDrainShadowBuffer: read %d bytes from shadow\r\n", *fifoCount ));
  89. }
  90. //============================================================================
  91. // NAME: HardwareECP::EmptyFIFO()
  92. //
  93. // Empties HW FIFO into a shadow buffer. This must be done before
  94. // turning the direction from reverse to forward, if the printer has
  95. // stuffed data in that no one has read yet.
  96. //
  97. // PARAMETERS:
  98. // Controller - Supplies the base address of the parallel port.
  99. //
  100. // RETURNS: STATUS_SUCCESS or ....
  101. //
  102. // NOTES:
  103. // Called ZIP_EmptyFIFO in the original 16 bit code.
  104. //
  105. //============================================================================
  106. NTSTATUS ParEcpHwEmptyFIFO(IN PDEVICE_EXTENSION Extension)
  107. {
  108. NTSTATUS nError = STATUS_SUCCESS;
  109. Queue *pShadowBuffer;
  110. UCHAR bData;
  111. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  112. PUCHAR wPortDFIFO = Extension->Controller + ECP_DFIFO_OFFSET; // IO address of ECP Data FIFO
  113. PUCHAR wPortECR = Extension->Controller + ECR_OFFSET; // IO address of Extended Control Register (ECR)
  114. #else
  115. PUCHAR wPortDFIFO = Extension->EcrController; // IO address of ECP Data FIFO
  116. PUCHAR wPortECR = Extension->EcrController + ECR_OFFSET; // IO address of Extended Control Register (ECR)
  117. #endif
  118. // While data exists in the FIFO, read it and put it into shadow buffer.
  119. // If the shadow buffer fills up before the FIFO is exhausted, an
  120. // error condition exists.
  121. pShadowBuffer = &(Extension->ShadowBuffer);
  122. while ((READ_PORT_UCHAR(wPortECR) & ECR_FIFO_EMPTY) == 0 )
  123. {
  124. // LAC FRAME 13Jan98
  125. // Break out the Port Read so we can observe the data if needed
  126. bData = READ_PORT_UCHAR(wPortDFIFO);
  127. if (FALSE == Queue_Enqueue(pShadowBuffer, bData)) // Put byte in queue.
  128. {
  129. ParDump2(PARERRORS, ( "ParEcpHwEmptyFIFO: Shadow buffer full, FIFO not empty\r\n" ));
  130. nError = STATUS_BUFFER_OVERFLOW;
  131. goto ParEcpHwEmptyFIFO_ExitLabel;
  132. }
  133. ParDump2(PARINFO,("ParEcpHwEmptyFIFO: Enqueue data %02x\r\n",(int)bData));
  134. }
  135. if( ( !Queue_IsEmpty(pShadowBuffer) && (Extension->P12843DL.bEventActive) )) {
  136. KeSetEvent(Extension->P12843DL.Event, 0, FALSE);
  137. }
  138. ParEcpHwEmptyFIFO_ExitLabel:
  139. return nError;
  140. } // ParEcpHwEmptyFIFO
  141. // LAC ENTEREXIT 5Dec97
  142. //=========================================================
  143. // HardwareECP::ExitForwardPhase
  144. //
  145. // Description : Exit from HWECP Forward Phase to the common phase
  146. // (FWD IDLE, PS/2)
  147. //
  148. // Input Parameters : Controller, pPortInfoStruct
  149. //
  150. // Modifies :
  151. //
  152. // Pre-conditions :
  153. //
  154. // Post-conditions :
  155. //
  156. // Returns :
  157. //
  158. //=========================================================
  159. NTSTATUS ParEcpHwExitForwardPhase( IN PDEVICE_EXTENSION Extension )
  160. {
  161. NTSTATUS status;
  162. PUCHAR wPortECR; // I/O address of ECR
  163. ParDump2( PARENTRY, ("ParEcpHwExitForwardPhase: Entry\r\n") );
  164. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  165. wPortECR = Extension->Controller + ECR_OFFSET;
  166. #else
  167. wPortECR = Extension->EcrController + ECR_OFFSET;
  168. #endif
  169. // First, there could be data in the FIFO. Wait for it to empty
  170. // and then put the bus in the common state (PHASE_FORWARD_IDLE with
  171. // ECRMode set to PS/2
  172. status = ParEcpHwWaitForEmptyFIFO( Extension );
  173. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  174. ParDumpReg(PAREXIT, ("ParEcpHwExitForwardPhase: Exit[%d]", NT_SUCCESS(status)),
  175. wPortECR,
  176. Extension->Controller + OFFSET_DCR,
  177. Extension->Controller + OFFSET_DSR);
  178. return( status );
  179. }
  180. // LAC ENTEREXIT 5Dec97
  181. //=========================================================
  182. // HardwareECP::EnterReversePhase
  183. //
  184. // Description : Go from the common phase to HWECP Reverse Phase
  185. //
  186. // Input Parameters : Controller, pPortInfoStruct
  187. //
  188. // Modifies :
  189. //
  190. // Pre-conditions :
  191. //
  192. // Post-conditions :
  193. //
  194. // Returns :
  195. //
  196. //=========================================================
  197. NTSTATUS ParEcpHwEnterReversePhase( IN PDEVICE_EXTENSION Extension )
  198. {
  199. NTSTATUS status;
  200. PUCHAR Controller;
  201. PUCHAR wPortECR; // I/O address of Extended Control Register
  202. PUCHAR wPortDCR; // I/O address of Device Control Register
  203. UCHAR dcr;
  204. // ParTimerCheck(("ParEcpHwEnterReversePhase: Start\r\n"));
  205. Controller = Extension->Controller;
  206. #if (0 == PARCHIP_ECR_ARBITRATOR)
  207. wPortECR = Controller + ECR_OFFSET;
  208. #else
  209. wPortECR = Extension->EcrController + ECR_OFFSET;
  210. #endif
  211. wPortDCR = Controller + OFFSET_DCR;
  212. ParDumpReg(PARENTRY, ("ParEcpHwEnterReversePhase: Enter"),
  213. wPortECR,
  214. wPortDCR,
  215. Controller + OFFSET_DSR);
  216. // EnterReversePhase assumes that we are in PHASE_FORWARD_IDLE,
  217. // and that the ECPMode is set to PS/2 mode at entry.
  218. //volatile UCHAR ecr = READ_PORT_UCHAR( Controller + ECR_OFFSET ) & 0xe0;
  219. //HPKAssert( ((PHASE_FORWARD_IDLE == pPortInfoStruct->CurrentPhase) && (0x20 == ecr)),
  220. // ("HardwareECP::EnterReversePhase: Bad initial state (%d/%x)\r\n",(int)pPortInfoStruct->CurrentPhase,(int)ecr) );
  221. //----------------------------------------------------------------------
  222. // Set the ECR to mode 001 (PS2 Mode).
  223. //----------------------------------------------------------------------
  224. #if (1 == PARCHIP_ECR_ARBITRATOR)
  225. Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
  226. #else
  227. WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_PS2);
  228. #endif
  229. Extension->PortHWMode = HW_MODE_PS2;
  230. if ( Extension->ModeSafety == SAFE_MODE ) {
  231. // Reverse the bus first (using ECP::EnterReversePhase)
  232. status = ParEcpEnterReversePhase(Extension);
  233. if ( NT_SUCCESS(status) )
  234. {
  235. //----------------------------------------------------------------------
  236. // Wait for nAckReverse low (ECP State 40)
  237. //----------------------------------------------------------------------
  238. if ( !CHECK_DSR(Controller, DONT_CARE, DONT_CARE, INACTIVE, ACTIVE, DONT_CARE,
  239. IEEE_MAXTIME_TL) )
  240. {
  241. ParDump2(PARERRORS,("ParEcpHwEnterReversePhase: State 40 failed\r\n"));
  242. status = ParEcpHwRecoverPort( Extension, RECOVER_28 );
  243. if ( NT_SUCCESS(status))
  244. status = STATUS_LINK_FAILED;
  245. goto ParEcpHwEnterReversePhase_ExitLabel;
  246. }
  247. else
  248. {
  249. ParDump2(PARECPTRACE, ("ParEcpHwEnterReversePhase: Phase_RevIdle. Setup HW ECR\r\n"));
  250. Extension->CurrentPhase = PHASE_REVERSE_IDLE;
  251. }
  252. }
  253. } else {
  254. //----------------------------------------------------------------------
  255. // Set Dir=1 in DCR for reading.
  256. //----------------------------------------------------------------------
  257. dcr = READ_PORT_UCHAR( wPortDCR ); // Get content of DCR.
  258. dcr = UPDATE_DCR( dcr, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
  259. WRITE_PORT_UCHAR(wPortDCR, dcr);
  260. }
  261. //----------------------------------------------------------------------
  262. // Set the ECR to mode 011 (ECP Mode). DmaEnable=0.
  263. //----------------------------------------------------------------------
  264. ParDump2(PARECPTRACE,("ParEcpHwEnterReversePhase: Before Setting Harware DCR - %x.\n", READ_PORT_UCHAR(wPortDCR) ));
  265. #if (1 == PARCHIP_ECR_ARBITRATOR)
  266. status = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
  267. if ( !NT_SUCCESS(status) )
  268. {
  269. ParDump2(PARERRORS,("ParEcpHwEnterReversePhase: TrySetChipMode failed\r\n"));
  270. }
  271. #else
  272. WRITE_PORT_UCHAR( wPortECR, DEFAULT_ECR_ECP );
  273. #endif
  274. Extension->PortHWMode = HW_MODE_ECP;
  275. ParDump2(PARECPTRACE,("ParEcpHwEnterReversePhase: After Setting Harware Before nStrobe and nAutoFd DCR - %x.\n", READ_PORT_UCHAR(wPortDCR) ));
  276. //----------------------------------------------------------------------
  277. // Set nStrobe=0 and nAutoFd=0 in DCR, so that ECP HW can control.
  278. //----------------------------------------------------------------------
  279. dcr = READ_PORT_UCHAR( wPortDCR ); // Get content of DCR.
  280. dcr = UPDATE_DCR( dcr, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE);
  281. WRITE_PORT_UCHAR( wPortDCR, dcr );
  282. ParDump2(PARECPTRACE,("ParEcpHwEnterReversePhase: After nStrobe and nAutoFd DCR - %x.\n", READ_PORT_UCHAR(wPortDCR) ));
  283. // Set the phase variable to ReverseIdle
  284. Extension->CurrentPhase = PHASE_REVERSE_IDLE;
  285. ParEcpHwEnterReversePhase_ExitLabel:
  286. // ParTimerCheck(("ParEcpHwEnterReversePhase: End\r\n"));
  287. ParDumpReg(PAREXIT, ("ParEcpHwEnterReversePhase: Exit[%d]", NT_SUCCESS(status)),
  288. wPortECR,
  289. wPortDCR,
  290. Controller + OFFSET_DSR);
  291. return( status );
  292. }
  293. //=========================================================
  294. // HardwareECP::ExitReversePhase
  295. //
  296. // Description : Get out of HWECP Reverse Phase to the common state
  297. //
  298. // Input Parameters : Controller, pPortInfoStruct
  299. //
  300. // Modifies :
  301. //
  302. // Pre-conditions :
  303. //
  304. // Post-conditions :
  305. //
  306. // Returns :
  307. //
  308. //=========================================================
  309. NTSTATUS ParEcpHwExitReversePhase( IN PDEVICE_EXTENSION Extension )
  310. {
  311. NTSTATUS nError = STATUS_SUCCESS;
  312. UCHAR bDCR;
  313. UCHAR bECR;
  314. PUCHAR wPortECR;
  315. PUCHAR wPortDCR;
  316. PUCHAR Controller;
  317. ParDump2( PARENTRY, ("ParEcpHwExitReversePhase: Entry\r\n") );
  318. // ParTimerCheck(("ParEcpHwExitReversePhase: Start\r\n"));
  319. Controller = Extension->Controller;
  320. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  321. wPortECR = Controller + ECR_OFFSET;
  322. #else
  323. wPortECR = Extension->EcrController + ECR_OFFSET;
  324. #endif
  325. wPortDCR = Controller + OFFSET_DCR;
  326. //----------------------------------------------------------------------
  327. // Set status byte to indicate Reverse To Forward Mode.
  328. //----------------------------------------------------------------------
  329. Extension->CurrentPhase = PHASE_REV_TO_FWD;
  330. if ( Extension->ModeSafety == SAFE_MODE ) {
  331. //----------------------------------------------------------------------
  332. // Assert nReverseRequest high. This should stop further data transfer
  333. // into the FIFO. [[REVISIT: does the chip handle this correctly
  334. // if it occurs in the middle of a byte transfer (states 43-46)??
  335. // Answer (10/9/95) no, it doesn't!!]]
  336. //----------------------------------------------------------------------
  337. bDCR = READ_PORT_UCHAR(wPortDCR); // Get content of DCR.
  338. bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, DONT_CARE, DONT_CARE );
  339. WRITE_PORT_UCHAR(wPortDCR, bDCR );
  340. //----------------------------------------------------------------------
  341. // Wait for PeriphAck low and PeriphClk high (ECP state 48) together
  342. // with nAckReverse high (ECP state 49).
  343. //----------------------------------------------------------------------
  344. if ( ! CHECK_DSR(Controller,
  345. INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
  346. DEFAULT_RECEIVE_TIMEOUT ) )
  347. {
  348. ParDump2( PARERRORS, ("ParEcpHwExitReversePhase: Periph failed state 48/49.\r\n"));
  349. nError = ParEcpHwRecoverPort( Extension, RECOVER_37 ); // Reset port.
  350. if (NT_SUCCESS(nError))
  351. {
  352. ParDump2( PARERRORS, ("ParEcpHwExitReversePhase: State 48/49 Failure. RecoverPort Invoked.\r\n"));
  353. return STATUS_LINK_FAILED;
  354. }
  355. return nError;
  356. }
  357. //-----------------------------------------------------------------------
  358. // Empty the HW FIFO of any bytes that may have already come in.
  359. // This must be done before changing ECR modes because the FIFO is reset
  360. // when that occurs.
  361. //-----------------------------------------------------------------------
  362. bECR = READ_PORT_UCHAR(wPortECR); // Get content of ECR.
  363. if ((bECR & ECR_FIFO_EMPTY) == 0) // Check if FIFO is not empty.
  364. {
  365. if ((nError = ParEcpHwEmptyFIFO(Extension)) != STATUS_SUCCESS)
  366. {
  367. ParDump2( PARERRORS, ("ParEcpHwExitReversePhase: Attempt to empty ECP chip failed.\r\n"));
  368. return nError;
  369. }
  370. }
  371. //----------------------------------------------------------------------
  372. // Assert HostAck and HostClk high. [[REVISIT: is this necessary?
  373. // should already be high...]]
  374. //----------------------------------------------------------------------
  375. bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
  376. WRITE_PORT_UCHAR(wPortDCR, bDCR );
  377. } // SAFE_MODE
  378. //----------------------------------------------------------------------
  379. // Set the ECR to PS2 Mode so we can change bus direction.
  380. //----------------------------------------------------------------------
  381. #if (1 == PARCHIP_ECR_ARBITRATOR)
  382. Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
  383. #else
  384. WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_PS2);
  385. #endif
  386. Extension->PortHWMode = HW_MODE_PS2;
  387. //----------------------------------------------------------------------
  388. // Set Dir=0 (Write) in DCR.
  389. //----------------------------------------------------------------------
  390. bDCR = READ_PORT_UCHAR(wPortDCR);
  391. bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
  392. WRITE_PORT_UCHAR(wPortDCR, bDCR );
  393. //----------------------------------------------------------------------
  394. // Set the ECR back to ECP Mode. DmaEnable=0.
  395. //----------------------------------------------------------------------
  396. #if (1 == PARCHIP_ECR_ARBITRATOR)
  397. nError = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
  398. #else
  399. WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_ECP);
  400. #endif
  401. Extension->PortHWMode = HW_MODE_ECP;
  402. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  403. // ParTimerCheck(("ParEcpHwExitReversePhase: End\r\n"));
  404. ParDumpReg(PAREXIT, ("ParEcpHwExitReversePhase: Exit[%d]", NT_SUCCESS(nError)),
  405. wPortECR,
  406. wPortDCR,
  407. Extension->Controller + OFFSET_DSR);
  408. return(nError);
  409. }
  410. BOOLEAN
  411. ParEcpHwHaveReadData (
  412. IN PDEVICE_EXTENSION Extension
  413. )
  414. {
  415. Queue *pQueue;
  416. // check shadow buffer
  417. pQueue = &(Extension->ShadowBuffer);
  418. if (!Queue_IsEmpty(pQueue)) {
  419. return TRUE;
  420. }
  421. // check periph
  422. if (ParEcpHaveReadData(Extension))
  423. return TRUE;
  424. // Check if FIFO is not empty.
  425. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  426. return (BOOLEAN)( (UCHAR)0 == (READ_PORT_UCHAR(Extension->Controller + ECR_OFFSET) & ECR_FIFO_EMPTY) );
  427. #else
  428. return (BOOLEAN)( (UCHAR)0 == (READ_PORT_UCHAR(Extension->EcrController + ECR_OFFSET) & ECR_FIFO_EMPTY) );
  429. #endif
  430. }
  431. NTSTATUS
  432. ParEcpHwHostRecoveryPhase(
  433. IN PDEVICE_EXTENSION Extension
  434. )
  435. {
  436. NTSTATUS nError = STATUS_SUCCESS;
  437. PUCHAR pPortDCR; // I/O address of Device Control Register
  438. PUCHAR pPortDSR; // I/O address of Device Status Register
  439. PUCHAR pPortECR; // I/O address of Extended Control Register
  440. UCHAR bDCR; // Contents of DCR
  441. UCHAR bDSR; // Contents of DSR
  442. if (!Extension->bIsHostRecoverSupported)
  443. {
  444. ParDump2( PARENTRY, ( "ParEcpHwHostRecoveryPhase: Host Recovery not supported\r\n"));
  445. return STATUS_SUCCESS;
  446. }
  447. ParDump2( PARENTRY, ( "ParEcpHwHostRecoveryPhase: Host Recovery Start\r\n"));
  448. // Calculate I/O port addresses for common registers
  449. pPortDCR = Extension->Controller + OFFSET_DCR;
  450. pPortDSR = Extension->Controller + OFFSET_DSR;
  451. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  452. pPortECR = Controller + OFFSET_ECR;
  453. #else
  454. pPortECR = Extension->EcrController + ECR_OFFSET;
  455. #endif
  456. // Set the ECR to mode 001 (PS2 Mode)
  457. #if (1 == PARCHIP_ECR_ARBITRATOR)
  458. // Don't need to flip to Byte mode. The ECR arbitrator will handle this.
  459. #else
  460. WRITE_PORT_UCHAR(pPortECR, DEFAULT_ECR_PS2);
  461. #endif
  462. Extension->PortHWMode = HW_MODE_PS2;
  463. // Set Dir=1 in DCR to disable host bus drive, because the peripheral may
  464. // try to drive the bus during host recovery phase. We are not really going
  465. // to let any data handshake across, because we don't set HostAck low, and
  466. // we don't enable the ECP chip during this phase.
  467. bDCR = READ_PORT_UCHAR(pPortDCR); // Get content of DCR.
  468. bDCR = UPDATE_DCR( bDCR, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
  469. WRITE_PORT_UCHAR(pPortDCR, bDCR );
  470. // Check the DCR to see if it has been stomped on
  471. bDCR = READ_PORT_UCHAR( pPortDCR );
  472. if ( TEST_DCR( bDCR, DIR_WRITE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE ) )
  473. {
  474. // DCR ok, now test DSR for valid state, ignoring PeriphAck since it could change
  475. bDSR = READ_PORT_UCHAR( pPortDSR );
  476. // 11/21/95 LLL, CGM: change test to look for XFlag high
  477. if ( TEST_DSR( bDSR, DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) )
  478. {
  479. // Drop ReverseRequest to initiate host recovery
  480. bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE, DONT_CARE );
  481. WRITE_PORT_UCHAR( pPortDCR, bDCR );
  482. // Wait for nAckReverse response
  483. // 11/21/95 LLL, CGM: tightened test to include PeriphClk and XFlag.
  484. // "ZIP_HRP: state 73, DSR"
  485. if ( CHECK_DSR( Extension->Controller,
  486. DONT_CARE, ACTIVE, INACTIVE, ACTIVE, DONT_CARE,
  487. IEEE_MAXTIME_TL))
  488. {
  489. // Yes, raise nReverseRequest, HostClk and HostAck (HostAck high so HW can drive)
  490. bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, ACTIVE );
  491. WRITE_PORT_UCHAR( pPortDCR, bDCR );
  492. // Wait for nAckReverse response
  493. // 11/21/95 LLL, CGM: tightened test to include XFlag and PeriphClk.
  494. // "ZIP_HRP: state 75, DSR"
  495. if ( CHECK_DSR( Extension->Controller,
  496. DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
  497. IEEE_MAXTIME_TL))
  498. {
  499. // Let the host drive the bus again.
  500. bDCR = READ_PORT_UCHAR(pPortDCR); // Get content of DCR.
  501. bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
  502. WRITE_PORT_UCHAR(pPortDCR, bDCR );
  503. // Recovery is complete, let the caller decide what to do now
  504. nError = STATUS_SUCCESS;
  505. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  506. }
  507. else
  508. {
  509. nError = STATUS_IO_TIMEOUT;
  510. ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: Error prior to state 75 \r\n"));
  511. }
  512. }
  513. else
  514. {
  515. nError = STATUS_IO_TIMEOUT;
  516. ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: Error prior to state 73 \r\n"));
  517. }
  518. }
  519. else
  520. {
  521. #if DVRH_BUS_RESET_ON_ERROR
  522. BusReset(pPortDCR); // Pass in the dcr address
  523. #endif
  524. ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: VE_LINK_FAILURE \r\n"));
  525. nError = STATUS_LINK_FAILED;
  526. }
  527. }
  528. else
  529. {
  530. ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: VE_PORT_STOMPED \r\n"));
  531. nError = STATUS_DEVICE_PROTOCOL_ERROR;
  532. }
  533. if (!NT_SUCCESS(nError))
  534. {
  535. // Make sure both HostAck and HostClk are high before leaving
  536. // Also let the host drive the bus again.
  537. bDCR = READ_PORT_UCHAR( pPortDCR );
  538. bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
  539. WRITE_PORT_UCHAR( pPortDCR, bDCR );
  540. // [[REVISIT]] pSDCB->wCurrentPhase = PHASE_UNKNOWN;
  541. }
  542. // Set the ECR to ECP mode, disable DMA
  543. #if (1 == PARCHIP_ECR_ARBITRATOR)
  544. nError = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
  545. #else
  546. WRITE_PORT_UCHAR(pPortECR, DEFAULT_ECR_ECP);
  547. #endif
  548. Extension->PortHWMode = HW_MODE_ECP;
  549. ParDump2( PAREXIT, ( "ParEcpHwHostRecoveryPhase:: Exit %d\r\n", NT_SUCCESS(nError)));
  550. return(nError);
  551. }
  552. NTSTATUS
  553. ParEcpHwRead(
  554. IN PDEVICE_EXTENSION Extension,
  555. IN PVOID Buffer,
  556. IN ULONG BufferSize,
  557. OUT PULONG BytesTransferred
  558. )
  559. /*++
  560. Routine Description:
  561. This routine performs a 1284 ECP mode read under Hardware control
  562. into the given buffer for no more than 'BufferSize' bytes.
  563. Arguments:
  564. Extension - Supplies the device extension.
  565. Buffer - Supplies the buffer to read into.
  566. BufferSize - Supplies the number of bytes in the buffer.
  567. BytesTransferred - Returns the number of bytes transferred.
  568. --*/
  569. {
  570. NTSTATUS nError = STATUS_SUCCESS;
  571. PUCHAR lpsBufPtr = (PUCHAR)Buffer; // Pointer to buffer cast to desired data type
  572. ULONG dCount = BufferSize; // Working copy of caller's original request count
  573. UCHAR bDSR; // Contents of DSR
  574. UCHAR bPeriphRequest; // Calculated state of nPeriphReq signal, used in loop
  575. ULONG dFifoCount = 0; // Amount of data pulled from FIFO shadow at start of read
  576. PUCHAR wPortDSR = Extension->Controller + DSR_OFFSET;
  577. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  578. PUCHAR wPortECR = Extension->Controller + ECR_OFFSET;
  579. PUCHAR wPortDFIFO = Extension->Controller + ECP_DFIFO_OFFSET;
  580. #else
  581. PUCHAR wPortECR = Extension->EcrController + ECR_OFFSET;
  582. PUCHAR wPortDFIFO = Extension->EcrController;
  583. #endif
  584. #if (1 == DVRH_USE_HW_MAXTIME)
  585. LARGE_INTEGER WaitOverallTimer;
  586. LARGE_INTEGER StartOverallTimer;
  587. LARGE_INTEGER EndOverallTimer;
  588. #else
  589. LARGE_INTEGER WaitPerByteTimer;
  590. LARGE_INTEGER StartPerByteTimer;
  591. LARGE_INTEGER EndPerByteTimer;
  592. BOOLEAN bResetTimer = TRUE;
  593. #endif
  594. ULONG wBurstCount; // Calculated amount of data in FIFO
  595. UCHAR ecrFIFO;
  596. ParTimerCheck(("ParEcpHwRead: Start BufferSize[%d]\r\n", BufferSize));
  597. #if (1 == DVRH_USE_HW_MAXTIME)
  598. // Look for limit to overall time spent in this routine. If bytes are just barely
  599. // trickling in, we don't want to stay here forever.
  600. WaitOverallTimer.QuadPart = (990 * 10 * 1000) + KeQueryTimeIncrement();
  601. // WaitOverallTimer.QuadPart = (DEFAULT_RECEIVE_TIMEOUT * 10 * 1000) + KeQueryTimeIncrement();
  602. #else
  603. WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement();
  604. #endif
  605. //----------------------------------------------------------------------
  606. // Set status byte to indicate Reverse Transfer Phase.
  607. //----------------------------------------------------------------------
  608. Extension->CurrentPhase = PHASE_REVERSE_XFER;
  609. //----------------------------------------------------------------------
  610. // We've already checked the shadow in ParRead. So go right to the
  611. // Hardware FIFO and pull more data across.
  612. //----------------------------------------------------------------------
  613. #if (1 == DVRH_USE_HW_MAXTIME)
  614. KeQueryTickCount(&StartOverallTimer); // Start the timer
  615. #else
  616. KeQueryTickCount(&StartPerByteTimer); // Start the timer
  617. #endif
  618. ParEcpHwRead_ReadLoopStart:
  619. //------------------------------------------------------------------
  620. // Determine whether the FIFO has any data and respond accordingly
  621. //------------------------------------------------------------------
  622. ecrFIFO = (UCHAR)(READ_PORT_UCHAR(wPortECR) & (UCHAR)ECR_FIFO_MASK);
  623. if (ECR_FIFO_FULL == ecrFIFO)
  624. {
  625. ParDump2(PARINFO, ("ParEcpHwRead: ECR_FIFO_FULL\r\n"));
  626. wBurstCount = ( dCount > Extension->FifoDepth ? Extension->FifoDepth : dCount );
  627. dCount -= wBurstCount;
  628. #if (1 == PAR_USE_BUFFER_READ_WRITE)
  629. READ_PORT_BUFFER_UCHAR(wPortDFIFO, lpsBufPtr, wBurstCount);
  630. lpsBufPtr += wBurstCount;
  631. ParDump2(PARINFO,("ParEcpHwRead: Read FIFOBurst\r\n"));
  632. #else
  633. while ( wBurstCount-- )
  634. {
  635. *lpsBufPtr = READ_PORT_UCHAR(wPortDFIFO);
  636. ParDump2(PARINFO,("ParEcpHwRead: Full FIFO: Read byte value %02x\r\n",(int)*lpsBufPtr));
  637. lpsBufPtr++;
  638. }
  639. #endif
  640. #if (0 == DVRH_USE_HW_MAXTIME)
  641. bResetTimer = TRUE;
  642. #endif
  643. }
  644. else if (ECR_FIFO_SOME_DATA == ecrFIFO)
  645. {
  646. // Read just one byte at a time, since we don't know exactly how much is
  647. // in the FIFO.
  648. *lpsBufPtr = READ_PORT_UCHAR(wPortDFIFO);
  649. lpsBufPtr++;
  650. dCount--;
  651. #if (0 == DVRH_USE_HW_MAXTIME)
  652. bResetTimer = TRUE;
  653. #endif
  654. }
  655. else // ECR_FIFO_EMPTY
  656. {
  657. ParDump2(PARINFO, ("ParEcpHwRead: ECR_FIFO_EMPTY\r\n"));
  658. // Nothing to do. We either have a slow peripheral or a bad peripheral.
  659. // We don't have a good way to figure out if its bad. Let's chew up our
  660. // time and hope for the best.
  661. #if (0 == DVRH_USE_HW_MAXTIME)
  662. bResetTimer = FALSE;
  663. #endif
  664. } // ECR_FIFO_EMPTY a.k.a. else clause of (ECR_FIFO_FULL == ecrFIFO)
  665. if (dCount == 0)
  666. goto ParEcpHwRead_ReadLoopEnd;
  667. else
  668. {
  669. #if (1 == DVRH_USE_HW_MAXTIME)
  670. // Limit the overall time we spend in this loop.
  671. KeQueryTickCount(&EndOverallTimer);
  672. if (((EndOverallTimer.QuadPart - StartOverallTimer.QuadPart) * KeQueryTimeIncrement()) > WaitOverallTimer.QuadPart)
  673. goto ParEcpHwRead_ReadLoopEnd;
  674. #else
  675. // Limit the overall time we spend in this loop.
  676. if (bResetTimer)
  677. {
  678. bResetTimer = FALSE;
  679. KeQueryTickCount(&StartPerByteTimer); // Restart the timer
  680. }
  681. else
  682. {
  683. KeQueryTickCount(&EndPerByteTimer);
  684. if (((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement()) > WaitPerByteTimer.QuadPart)
  685. goto ParEcpHwRead_ReadLoopEnd;
  686. }
  687. #endif
  688. }
  689. goto ParEcpHwRead_ReadLoopStart;
  690. ParEcpHwRead_ReadLoopEnd:
  691. ParDump2(PARECPTRACE,("ParEcpHwRead: Phase_RevIdle\r\n"));
  692. Extension->CurrentPhase = PHASE_REVERSE_IDLE;
  693. *BytesTransferred = BufferSize - dCount; // Set current count.
  694. Extension->log.HwEcpReadCount += *BytesTransferred;
  695. if (0 == *BytesTransferred)
  696. {
  697. bDSR = READ_PORT_UCHAR(wPortDSR);
  698. bPeriphRequest = (UCHAR)TEST_DSR( bDSR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE );
  699. // Only flag a timeout error if the device still said it had data to send.
  700. if ( bPeriphRequest )
  701. {
  702. //
  703. // Periph still says that it has data, but we timed out trying to read the data.
  704. //
  705. ParDump2(PARERRORS, ("ParEcpHwRead: read timout with nPeriphRequest asserted and no data read\r\n"));
  706. nError = STATUS_IO_TIMEOUT;
  707. if ((TRUE == Extension->P12843DL.bEventActive) ) {
  708. //
  709. // Signal transport that it should try another read
  710. //
  711. KeSetEvent(Extension->P12843DL.Event, 0, FALSE);
  712. }
  713. }
  714. }
  715. ParTimerCheck(("ParEcpHwRead: Exit[%d] BytesTransferred[%d]\r\n", NT_SUCCESS(nError), *BytesTransferred));
  716. ParDumpReg(PAREXIT, ("ParEcpHwRead: Exit[%d] BytesTransferred[%d]", NT_SUCCESS(nError), *BytesTransferred),
  717. wPortECR,
  718. Extension->Controller + OFFSET_DCR,
  719. Extension->Controller + OFFSET_DSR);
  720. return nError;
  721. } // ParEcpHwRead
  722. NTSTATUS
  723. ParEcpHwRecoverPort(
  724. PDEVICE_EXTENSION Extension,
  725. UCHAR bRecoverCode
  726. )
  727. {
  728. NTSTATUS nError = STATUS_SUCCESS;
  729. PUCHAR wPortDCR; // IO address of Device Control Register (DCR)
  730. PUCHAR wPortDSR; // IO address of Device Status Register (DSR)
  731. PUCHAR wPortECR; // IO address of Extended Control Register (ECR)
  732. PUCHAR wPortData; // IO address of Data Register
  733. UCHAR bDCR; // Contents of DCR
  734. UCHAR bDSR; // Contents of DSR
  735. UCHAR bDSRmasked; // DSR after masking low order bits
  736. ParDump2( PARENTRY, ( "ParEcpHwRecoverPort: enter %d\r\n", bRecoverCode ));
  737. // Calculate I/O port addresses for common registers
  738. wPortDCR = Extension->Controller + OFFSET_DCR;
  739. wPortDSR = Extension->Controller + OFFSET_DSR;
  740. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  741. wPortECR = Extension->Controller + ECR_OFFSET;
  742. #else
  743. wPortECR = Extension->EcrController + ECR_OFFSET;
  744. #endif
  745. wPortData = Extension->Controller + OFFSET_DATA;
  746. //----------------------------------------------------------------------
  747. // Check if port is stomped.
  748. //----------------------------------------------------------------------
  749. bDCR = READ_PORT_UCHAR(wPortDCR); // Get content of DCR.
  750. if ( ! TEST_DCR( bDCR, DONT_CARE, DONT_CARE, ACTIVE, DONT_CARE, DONT_CARE, DONT_CARE ) )
  751. {
  752. #if DVRH_BUS_RESET_ON_ERROR
  753. BusReset(wPortDCR); // Pass in the dcr address
  754. #endif
  755. ParDump2( PARERRORS, ( "!ParEcpHwRecoverPort: port stomped.\r\n"));
  756. nError = STATUS_DEVICE_PROTOCOL_ERROR;
  757. }
  758. //----------------------------------------------------------------------
  759. // Attempt a termination phase to get the peripheral recovered.
  760. // Ignore the error return, we've already got that figured out.
  761. //----------------------------------------------------------------------
  762. IeeeTerminate1284Mode(Extension );
  763. //----------------------------------------------------------------------
  764. // Set the ECR to PS2 Mode so we can change bus direction.
  765. //----------------------------------------------------------------------
  766. #if (1 == PARCHIP_ECR_ARBITRATOR)
  767. Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
  768. #else
  769. WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_PS2);
  770. #endif
  771. Extension->PortHWMode = HW_MODE_PS2;
  772. //----------------------------------------------------------------------
  773. // Assert nSelectIn low, nInit high, nStrobe high, and nAutoFd high.
  774. //----------------------------------------------------------------------
  775. bDCR = READ_PORT_UCHAR(wPortDCR); // Get content of DCR.
  776. bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
  777. WRITE_PORT_UCHAR(wPortDCR, bDCR);
  778. WRITE_PORT_UCHAR(wPortData, bRecoverCode); // Output the error ID
  779. KeStallExecutionProcessor(100); // Hold long enough to capture
  780. WRITE_PORT_UCHAR(wPortData, 0); // Now clear the data lines.
  781. //----------------------------------------------------------------------
  782. // Set the ECR to mode 000 (Compatibility Mode).
  783. //----------------------------------------------------------------------
  784. #if (1 == PARCHIP_ECR_ARBITRATOR)
  785. // Nothing needs to be done here.
  786. #else
  787. WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_COMPATIBILITY);
  788. #endif
  789. Extension->PortHWMode = HW_MODE_COMPATIBILITY;
  790. //----------------------------------------------------------------------
  791. // Check for any link errors if nothing bad found yet.
  792. //----------------------------------------------------------------------
  793. bDSR = READ_PORT_UCHAR(wPortDSR); // Get content of DSR.
  794. bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
  795. if (NT_SUCCESS(nError))
  796. {
  797. if (bDSRmasked != 0xDF)
  798. {
  799. ParDump2( PARERRORS, ("!ParEcpHwRecoverPort: DSR Exp value: 0xDF, Act value: 0x%X\r\n", bDSRmasked));
  800. // Get DSR again just to make sure...
  801. bDSR = READ_PORT_UCHAR(wPortDSR); // Get content of DSR.
  802. bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
  803. if ( (bDSRmasked == CHKPRNOFF1) || (bDSRmasked == CHKPRNOFF2) ) // Check for printer off.
  804. {
  805. ParDump2( PARERRORS, ("!ParEcpHwRecoverPort: DSR value: 0x%X, Printer Off.\r\n", bDSRmasked));
  806. nError = STATUS_DEVICE_POWERED_OFF;
  807. }
  808. else
  809. {
  810. if (bDSRmasked == CHKNOCABLE) // Check for cable unplugged.
  811. {
  812. ParDump2( PARERRORS, ("!ParEcpHwRecoverPort: DSR value: 0x%X, Cable Unplugged.\r\n", bDSRmasked));
  813. nError = STATUS_DEVICE_NOT_CONNECTED;
  814. }
  815. else
  816. {
  817. nError = STATUS_LINK_FAILED;
  818. }
  819. }
  820. }
  821. }
  822. //----------------------------------------------------------------------
  823. // Set status byte to indicate Compatibility Mode.
  824. //----------------------------------------------------------------------
  825. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  826. ParDump2( PAREXIT, ( "ParEcpHwRecoverPort: exit, return = 0x%X\r\n", NT_SUCCESS(nError) ));
  827. return nError;
  828. } // ParEcpHwRecoverPort
  829. NTSTATUS
  830. ParEcpHwSetAddress(
  831. IN PDEVICE_EXTENSION Extension,
  832. IN UCHAR Address
  833. )
  834. /*++
  835. Routine Description:
  836. Sets the ECP Address.
  837. Arguments:
  838. Extension - Supplies the device extension.
  839. Address - The bus address to be set.
  840. Return Value:
  841. None.
  842. --*/
  843. {
  844. NTSTATUS nError = STATUS_SUCCESS;
  845. PUCHAR wPortDSR; // IO address of Device Status Register
  846. PUCHAR wPortECR; // IO address of Extended Control Register
  847. PUCHAR wPortAFIFO; // IO address of ECP Address FIFO
  848. UCHAR bDSR; // Contents of DSR
  849. UCHAR bECR; // Contents of ECR
  850. BOOLEAN bDone;
  851. ParDump2( PARENTRY, ("ParEcpHwSetAddress, Start\r\n"));
  852. // Calculate I/O port addresses for common registers
  853. wPortDSR = Extension->Controller + DSR_OFFSET;
  854. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  855. wPortECR = Extension->Controller + ECR_OFFSET;
  856. #else
  857. wPortECR = Extension->EcrController + ECR_OFFSET;
  858. #endif
  859. wPortAFIFO = Extension->Controller + AFIFO_OFFSET;
  860. //----------------------------------------------------------------------
  861. // Check for any link errors.
  862. //----------------------------------------------------------------------
  863. //ZIP_CHECK_PORT( DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE,
  864. // "ZIP_SCA: init DCR", RECOVER_40, errorExit );
  865. //ZIP_CHECK_LINK( DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
  866. // "ZIP_SCA: init DSR", RECOVER_41, errorExit );
  867. // Set state to indicate ECP forward transfer phase
  868. Extension->CurrentPhase = PHASE_FORWARD_XFER;
  869. //----------------------------------------------------------------------
  870. // Send ECP channel address to AFIFO.
  871. //----------------------------------------------------------------------
  872. if ( ! ( TEST_ECR_FIFO( READ_PORT_UCHAR( wPortECR), ECR_FIFO_EMPTY ) ? TRUE :
  873. CheckPort( wPortECR, ECR_FIFO_MASK, ECR_FIFO_EMPTY,
  874. IEEE_MAXTIME_TL ) ) )
  875. {
  876. nError = ParEcpHwHostRecoveryPhase(Extension);
  877. ParDump2(PARERRORS, ("ParEcpHwSetAddress: FIFO full, timeout sending ECP channel address\r\n"));
  878. nError = STATUS_IO_DEVICE_ERROR;
  879. }
  880. else
  881. {
  882. // Send the address byte. The most significant bit must be set to distinquish
  883. // it as an address (as opposed to a run-length compression count).
  884. WRITE_PORT_UCHAR(wPortAFIFO, (UCHAR)(Address | 0x80));
  885. }
  886. if ( NT_SUCCESS(nError) )
  887. {
  888. // If there have been no previous errors, and synchronous writes
  889. // have been requested, wait for the FIFO to empty and the device to
  890. // complete the last PeriphAck handshake before returning success.
  891. if ( Extension->bSynchWrites )
  892. {
  893. LARGE_INTEGER Wait;
  894. LARGE_INTEGER Start;
  895. LARGE_INTEGER End;
  896. // we wait up to 35 milliseconds.
  897. Wait.QuadPart = (IEEE_MAXTIME_TL * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
  898. KeQueryTickCount(&Start);
  899. bDone = FALSE;
  900. while ( ! bDone )
  901. {
  902. bECR = READ_PORT_UCHAR( wPortECR );
  903. bDSR = READ_PORT_UCHAR( wPortDSR );
  904. // LLL/CGM 10/9/95: Tighten up link test - PeriphClk high
  905. if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) &&
  906. TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) )
  907. {
  908. bDone = TRUE;
  909. }
  910. else
  911. {
  912. KeQueryTickCount(&End);
  913. if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart)
  914. {
  915. ParDump2( PARERRORS, ("ParEcpHwSetAddress, timeout during synch\r\n"));
  916. bDone = TRUE;
  917. nError = ParEcpHwHostRecoveryPhase(Extension);
  918. nError = STATUS_IO_DEVICE_ERROR;
  919. }
  920. }
  921. } // of while...
  922. } // if bSynchWrites...
  923. }
  924. if ( NT_SUCCESS(nError) )
  925. {
  926. // Update the state to reflect that we are back in an idle phase
  927. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  928. }
  929. else if ( nError == STATUS_IO_DEVICE_ERROR )
  930. {
  931. // Update the state to reflect that we are back in an idle phase
  932. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  933. }
  934. ParDumpReg(PAREXIT, ("ParEcpHwSetAddress: Exit[%d]", NT_SUCCESS(nError)),
  935. wPortECR,
  936. Extension->Controller + OFFSET_DCR,
  937. wPortDSR);
  938. return nError;
  939. }
  940. NTSTATUS
  941. ParEcpHwSetupPhase(
  942. IN PDEVICE_EXTENSION Extension
  943. )
  944. /*++
  945. Routine Description:
  946. This routine performs 1284 Setup Phase.
  947. Arguments:
  948. Controller - Supplies the port address.
  949. Return Value:
  950. STATUS_SUCCESS - Successful negotiation.
  951. otherwise - Unsuccessful negotiation.
  952. --*/
  953. {
  954. NTSTATUS Status = STATUS_SUCCESS;
  955. PUCHAR pPortDCR; // IO address of Device Control Register (DCR)
  956. PUCHAR pPortDSR; // IO address of Device Status Register (DSR)
  957. PUCHAR pPortECR; // IO address of Extended Control Register (ECR)
  958. UCHAR bDCR; // Contents of DCR
  959. ParDump2(PARENTRY,("HardwareECP::SetupPhase: Start\r\n"));
  960. // Calculate I/O port addresses for common registers
  961. pPortDCR = Extension->Controller + OFFSET_DCR;
  962. pPortDSR = Extension->Controller + OFFSET_DSR;
  963. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  964. pPortECR = Extension->Controller + ECR_OFFSET;
  965. #else
  966. pPortECR = Extension->EcrController + ECR_OFFSET;
  967. #endif
  968. // Get the DCR and make sure port hasn't been stomped
  969. //ZIP_CHECK_PORT( DIR_WRITE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE,
  970. // "ZIP_SP: init DCR", RECOVER_44, exit1 );
  971. // Set HostAck low
  972. bDCR = READ_PORT_UCHAR(pPortDCR); // Get content of DCR.
  973. bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE );
  974. WRITE_PORT_UCHAR( pPortDCR, bDCR );
  975. // for some reason dvdr doesn't want an extra check in UNSAFE_MODE
  976. if ( Extension->ModeSafety == SAFE_MODE ) {
  977. // Wait for nAckReverse to go high
  978. // LLL/CGM 10/9/95: look for PeriphAck low, PeriphClk high as per 1284 spec.
  979. if ( !CHECK_DSR(Extension->Controller, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
  980. IEEE_MAXTIME_TL ) )
  981. {
  982. // Any failure leaves us in an unknown state to recover from.
  983. Extension->CurrentPhase = PHASE_UNKNOWN;
  984. Status = STATUS_IO_DEVICE_ERROR;
  985. goto HWECP_SetupPhaseExitLabel;
  986. }
  987. }
  988. //----------------------------------------------------------------------
  989. // Set the ECR to mode 001 (PS2 Mode).
  990. //----------------------------------------------------------------------
  991. #if (1 == PARCHIP_ECR_ARBITRATOR)
  992. Status = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
  993. #else
  994. WRITE_PORT_UCHAR(pPortECR, DEFAULT_ECR_PS2);
  995. #endif
  996. // Set DCR: DIR=0 for output, HostAck and HostClk high so HW can drive
  997. bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
  998. WRITE_PORT_UCHAR( pPortDCR, bDCR );
  999. // Set the ECR to ECP mode, disable DMA
  1000. #if (1 == PARCHIP_ECR_ARBITRATOR)
  1001. // Nothing needs to be done here
  1002. #else
  1003. WRITE_PORT_UCHAR( pPortECR, DEFAULT_ECR_ECP );
  1004. #endif
  1005. Extension->PortHWMode = HW_MODE_ECP;
  1006. // If setup was successful, mark the new ECP phase.
  1007. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  1008. Status = STATUS_SUCCESS;
  1009. HWECP_SetupPhaseExitLabel:
  1010. ParDump2(PARENTRY,("HardwareECP::SetupPhase: End [%d]\r\n", NT_SUCCESS(Status)));
  1011. return Status;
  1012. }
  1013. NTSTATUS ParEcpHwWaitForEmptyFIFO(IN PDEVICE_EXTENSION Extension)
  1014. /*++
  1015. Routine Description:
  1016. This routine will babysit the Fifo.
  1017. Arguments:
  1018. Extension - The device extension.
  1019. Return Value:
  1020. NTSTATUS.
  1021. --*/
  1022. {
  1023. UCHAR bDSR; // Contents of DSR
  1024. UCHAR bECR; // Contents of ECR
  1025. UCHAR bDCR; // Contents of ECR
  1026. BOOLEAN bDone = FALSE;
  1027. PUCHAR wPortDSR;
  1028. PUCHAR wPortECR;
  1029. PUCHAR wPortDCR;
  1030. LARGE_INTEGER Wait;
  1031. LARGE_INTEGER Start;
  1032. LARGE_INTEGER End;
  1033. NTSTATUS status = STATUS_SUCCESS;
  1034. // Calculate I/O port addresses for common registers
  1035. wPortDSR = Extension->Controller + OFFSET_DSR;
  1036. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  1037. wPortECR = Extension->Controller + ECR_OFFSET;
  1038. #else
  1039. wPortECR = Extension->EcrController + ECR_OFFSET;
  1040. #endif
  1041. wPortDCR = Extension->Controller + OFFSET_DCR;
  1042. Wait.QuadPart = (330 * 10 * 1000) + KeQueryTimeIncrement(); // 330ms
  1043. KeQueryTickCount(&Start);
  1044. //--------------------------------------------------------------------
  1045. // wait for the FIFO to empty and the last
  1046. // handshake of PeriphAck to complete before returning success.
  1047. //--------------------------------------------------------------------
  1048. while ( ! bDone )
  1049. {
  1050. bECR = READ_PORT_UCHAR(wPortECR);
  1051. bDSR = READ_PORT_UCHAR(wPortDSR);
  1052. bDCR = READ_PORT_UCHAR(wPortDCR);
  1053. #if 0
  1054. if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) &&
  1055. TEST_DCR( bDCR, INACTIVE, INACTIVE, ACTIVE, ACTIVE, DONT_CARE, ACTIVE ) &&
  1056. TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
  1057. #else
  1058. if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) &&
  1059. TEST_DCR( bDCR, INACTIVE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, ACTIVE ) &&
  1060. TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
  1061. #endif
  1062. // FIFO is empty, exit without error.
  1063. bDone = TRUE;
  1064. } else {
  1065. KeQueryTickCount(&End);
  1066. if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart) {
  1067. // FIFO not empty, timeout occurred, exit with error.
  1068. // NOTE: There is not a good way to determine how many bytes
  1069. // are stuck in the fifo
  1070. ParDump2( PARERRORS, ("ParEcpHwWaitForEmptyFIFO: timeout during synch\r\n"));
  1071. status = STATUS_IO_TIMEOUT;
  1072. bDone = TRUE;
  1073. }
  1074. }
  1075. } // of while...
  1076. return status;
  1077. }
  1078. NTSTATUS
  1079. ParEcpHwWrite(
  1080. IN PDEVICE_EXTENSION Extension,
  1081. IN PVOID Buffer,
  1082. IN ULONG BufferSize,
  1083. OUT PULONG BytesTransferred
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. Writes data to the peripheral using the ECP protocol under hardware
  1088. control.
  1089. Arguments:
  1090. Extension - Supplies the device extension.
  1091. Buffer - Supplies the buffer to write from.
  1092. BufferSize - Supplies the number of bytes in the buffer.
  1093. BytesTransferred - Returns the number of bytes transferred.
  1094. Return Value:
  1095. None.
  1096. --*/
  1097. {
  1098. PUCHAR wPortDSR;
  1099. PUCHAR wPortECR;
  1100. PUCHAR wPortDFIFO;
  1101. ULONG bytesToWrite = BufferSize;
  1102. // ULONG i;
  1103. // UCHAR dcr;
  1104. UCHAR dsr, ecr;
  1105. UCHAR ecrFIFO;
  1106. LARGE_INTEGER WaitPerByteTimer;
  1107. LARGE_INTEGER StartPerByteTimer;
  1108. LARGE_INTEGER EndPerByteTimer;
  1109. #if (1 == DVRH_USE_HW_MAXTIME)
  1110. LARGE_INTEGER WaitOverallTimer;
  1111. LARGE_INTEGER StartOverallTimer;
  1112. LARGE_INTEGER EndOverallTimer;
  1113. #endif
  1114. BOOLEAN bResetTimer = TRUE;
  1115. ULONG wBurstCount; // Length of burst to write when FIFO empty
  1116. PUCHAR pBuffer;
  1117. NTSTATUS Status = STATUS_SUCCESS;
  1118. wPortDSR = Extension->Controller + DSR_OFFSET;
  1119. #if (0 == DVRH_USE_PARPORT_ECP_ADDR)
  1120. wPortECR = Extension->Controller+ ECR_OFFSET;
  1121. wPortDFIFO = Extension->Controller + ECP_DFIFO_OFFSET;
  1122. #else
  1123. wPortECR = Extension->EcrController + ECR_OFFSET;
  1124. wPortDFIFO = Extension->EcrController;
  1125. #endif
  1126. pBuffer = Buffer;
  1127. ParTimerCheck(("ParEcpHwWrite: Start bytesToWrite[%d]\r\n", bytesToWrite));
  1128. Status = ParTestEcpWrite(Extension);
  1129. if (!NT_SUCCESS(Status))
  1130. {
  1131. Extension->CurrentPhase = PHASE_UNKNOWN;
  1132. Extension->Connected = FALSE;
  1133. ParDump2(PARERRORS,("ParEcpHwWrite: Invalid Entry State\r\n"));
  1134. goto ParEcpHwWrite_ExitLabel; // Use a goto so we can see Debug info located at the end of proc!
  1135. }
  1136. Extension->CurrentPhase = PHASE_FORWARD_XFER;
  1137. //----------------------------------------------------------------------
  1138. // Setup Timer Stuff.
  1139. //----------------------------------------------------------------------
  1140. // we wait up to 35 milliseconds.
  1141. WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
  1142. #if (1 == DVRH_USE_HW_MAXTIME)
  1143. WaitOverallTimer.QuadPart = (330 * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
  1144. //WaitOverallTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
  1145. #endif
  1146. // Set up the overall timer that limits how much time is spent per call
  1147. // to this function.
  1148. #if (1 == DVRH_USE_HW_MAXTIME)
  1149. KeQueryTickCount(&StartOverallTimer);
  1150. #endif
  1151. // Set up the timer that limits the time allowed for per-byte handshakes.
  1152. KeQueryTickCount(&StartPerByteTimer);
  1153. //----------------------------------------------------------------------
  1154. // Send the data to the DFIFO.
  1155. //----------------------------------------------------------------------
  1156. HWECP_WriteLoop_Start:
  1157. //------------------------------------------------------------------
  1158. // Determine whether the FIFO has space and respond accordingly.
  1159. //------------------------------------------------------------------
  1160. ecrFIFO = (UCHAR)(READ_PORT_UCHAR(wPortECR) & ECR_FIFO_MASK);
  1161. if ( ECR_FIFO_EMPTY == ecrFIFO )
  1162. {
  1163. wBurstCount = (bytesToWrite > Extension->FifoDepth) ? Extension->FifoDepth : bytesToWrite;
  1164. bytesToWrite -= wBurstCount;
  1165. #if (PAR_USE_BUFFER_READ_WRITE == 1)
  1166. ParDump2(PARINFO,("ParEcpHwWrite: FIFOBurst\r\n"));
  1167. WRITE_PORT_BUFFER_UCHAR(wPortDFIFO, pBuffer, wBurstCount);
  1168. pBuffer += wBurstCount;
  1169. #else
  1170. while ( wBurstCount-- )
  1171. {
  1172. ParDump2(PARINFO,("ParEcpHwWrite: FIFOBurst: %02x\r\n",(int)*pBuffer));
  1173. WRITE_PORT_UCHAR(wPortDFIFO, *pBuffer++);
  1174. }
  1175. #endif
  1176. bResetTimer = TRUE;
  1177. }
  1178. else if (ECR_FIFO_SOME_DATA == ecrFIFO)
  1179. {
  1180. // Write just one byte at a time, since we don't know exactly how much
  1181. // room there is.
  1182. ParDump2(PARINFO,("ParEcpHwWrite: OneByte: %02x\r\n",(int)*pBuffer));
  1183. WRITE_PORT_UCHAR(wPortDFIFO, *pBuffer++);
  1184. bytesToWrite--;
  1185. bResetTimer = TRUE;
  1186. }
  1187. else { // ECR_FIFO_FULL
  1188. ParDump2(PARINFO,("ParEcpHwWrite: ECR_FIFO_FULL ecr=%02x\r\n",(int)READ_PORT_UCHAR(wPortECR)));
  1189. // Need to figure out whether to keep attempting to send, or to quit
  1190. // with a timeout status.
  1191. // Reset the per-byte timer if a byte was received since the last
  1192. // timer check.
  1193. if ( bResetTimer )
  1194. {
  1195. ParDump2(PARINFO,("ParEcpHwWrite: ECR_FIFO_FULL Reset Timer\r\n"));
  1196. KeQueryTickCount(&StartPerByteTimer);
  1197. bResetTimer = FALSE;
  1198. }
  1199. KeQueryTickCount(&EndPerByteTimer);
  1200. if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart)
  1201. {
  1202. ParDump2(PARERRORS,("ParEcpHwWrite: ECR_FIFO_FULL Timeout ecr=%02x\r\n",(int)READ_PORT_UCHAR(wPortECR)));
  1203. Status = STATUS_TIMEOUT;
  1204. // Peripheral is either busy or stalled. If the peripheral
  1205. // is busy then they should be using SWECP to allow for
  1206. // relaxed timings. Let's punt!
  1207. goto HWECP_WriteLoop_End;
  1208. }
  1209. }
  1210. if (bytesToWrite == 0)
  1211. {
  1212. goto HWECP_WriteLoop_End; // Transfer completed.
  1213. }
  1214. #if (1 == DVRH_USE_HW_MAXTIME)
  1215. // Limit the overall time we spend in this loop, in case the
  1216. // peripheral is taking data at a slow overall rate.
  1217. KeQueryTickCount(&EndOverallTimer);
  1218. if ((EndOverallTimer.QuadPart - StartOverallTimer.QuadPart) * KeQueryTimeIncrement() > WaitOverallTimer.QuadPart)
  1219. {
  1220. ParDump2(PARERRORS,("ParEcpHwWrite: OverAll Timer expired!\r\n"));
  1221. Status = STATUS_TIMEOUT;
  1222. goto HWECP_WriteLoop_End;
  1223. }
  1224. #endif
  1225. goto HWECP_WriteLoop_Start; // Start over
  1226. HWECP_WriteLoop_End:
  1227. if ( NT_SUCCESS(Status) )
  1228. {
  1229. // If there have been no previous errors, and synchronous writes
  1230. // have been requested, wait for the FIFO to empty and the last
  1231. // handshake of PeriphAck to complete before returning success.
  1232. if (Extension->bSynchWrites )
  1233. {
  1234. BOOLEAN bDone = FALSE;
  1235. ParDump2(PARINFO,("ParEcpHwWrite: Waiting for FIFO to empty\r\n"));
  1236. #if (0 == DVRH_USE_HW_MAXTIME)
  1237. KeQueryTickCount(&StartPerByteTimer);
  1238. #endif
  1239. while ( ! bDone )
  1240. {
  1241. ecr = READ_PORT_UCHAR(wPortECR);
  1242. dsr = READ_PORT_UCHAR(wPortDSR);
  1243. // LLL/CGM 10/9/95: tighten up DSR test - PeriphClk should be high
  1244. if ( TEST_ECR_FIFO( ecr, ECR_FIFO_EMPTY ) &&
  1245. TEST_DSR( dsr, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) )
  1246. {
  1247. ParDump2(PARINFO,("ParEcpHwWrite: FIFO is now empty\r\n"));
  1248. // FIFO is empty, exit without error.
  1249. bDone = TRUE;
  1250. }
  1251. else
  1252. {
  1253. #if (1 == DVRH_USE_HW_MAXTIME)
  1254. KeQueryTickCount(&EndOverallTimer);
  1255. if ((EndOverallTimer.QuadPart - StartOverallTimer.QuadPart) * KeQueryTimeIncrement() > WaitOverallTimer.QuadPart)
  1256. #else
  1257. KeQueryTickCount(&EndPerByteTimer);
  1258. if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart)
  1259. #endif
  1260. {
  1261. ParDump2(PARERRORS,("ParEcpHwWrite: FIFO didn't empty. dsr[%x] ecr[%x]\r\n", dsr, ecr));
  1262. // FIFO not empty, timeout occurred, exit with error.
  1263. Status = STATUS_TIMEOUT;
  1264. bDone = TRUE;
  1265. //HPKAssertOnError(0, ("ZIP_FTP, timeout during synch\r\n"));
  1266. }
  1267. }
  1268. } // of while...
  1269. }
  1270. }
  1271. Extension->CurrentPhase = PHASE_FORWARD_IDLE;
  1272. ParEcpHwWrite_ExitLabel:
  1273. *BytesTransferred = BufferSize - bytesToWrite;
  1274. Extension->log.HwEcpWriteCount += *BytesTransferred;
  1275. ParTimerCheck(("ParEcpHwWrite: Exit[%d] BytesTransferred[%d]\r\n", NT_SUCCESS(Status), (long)*BytesTransferred));
  1276. // ParDumpReg(PAREXIT | PARECPTRACE, ("ParEcpHwWrite: Exit[%d] BytesTransferred[%d]", NT_SUCCESS(Status), (long)*BytesTransferred),
  1277. ParDumpReg(PAREXIT, ("ParEcpHwWrite: Exit[%d] BytesTransferred[%d]", NT_SUCCESS(Status), (long)*BytesTransferred),
  1278. wPortECR,
  1279. Extension->Controller + OFFSET_DCR,
  1280. wPortDSR);
  1281. return Status;
  1282. }
  1283. NTSTATUS
  1284. ParEnterEcpHwMode(
  1285. IN PDEVICE_EXTENSION Extension,
  1286. IN BOOLEAN DeviceIdRequest
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. This routine performs 1284 negotiation with the peripheral to the
  1291. ECP mode protocol.
  1292. Arguments:
  1293. Controller - Supplies the port address.
  1294. DeviceIdRequest - Supplies whether or not this is a request for a device
  1295. id.
  1296. Return Value:
  1297. STATUS_SUCCESS - Successful negotiation.
  1298. otherwise - Unsuccessful negotiation.
  1299. --*/
  1300. {
  1301. NTSTATUS Status = STATUS_SUCCESS;
  1302. PUCHAR Controller;
  1303. ParDump2(PARENTRY,("ParEnterEcpHwMode: Start EcrController %x\n", Extension->EcrController));
  1304. Controller = Extension->Controller;
  1305. if ( Extension->ModeSafety == SAFE_MODE ) {
  1306. if (DeviceIdRequest) {
  1307. Status = IeeeEnter1284Mode (Extension, ECP_EXTENSIBILITY | DEVICE_ID_REQ);
  1308. } else {
  1309. Status = IeeeEnter1284Mode (Extension, ECP_EXTENSIBILITY);
  1310. }
  1311. } else {
  1312. ParDump2(PARINFO, ("ParEnterEcpHwMode:: UNSAFE_MODE.\n"));
  1313. Extension->Connected = TRUE;
  1314. }
  1315. // LAC ENTEREXIT 5Dec97
  1316. // Make sure that the ECR is in PS/2 mode, and that wPortHWMode
  1317. // has the correct value. (This is the common entry mode);
  1318. #if (0 == PARCHIP_ECR_ARBITRATOR)
  1319. WRITE_PORT_UCHAR( Controller + ECR_OFFSET, DEFAULT_ECR_PS2 );
  1320. #endif
  1321. Extension->PortHWMode = HW_MODE_PS2;
  1322. if (NT_SUCCESS(Status)) {
  1323. Status = ParEcpHwSetupPhase(Extension);
  1324. Extension->bSynchWrites = TRUE; // NOTE this is a temp hack!!! dvrh
  1325. if (!Extension->bShadowBuffer)
  1326. {
  1327. Queue_Create(&(Extension->ShadowBuffer), Extension->FifoDepth * 2);
  1328. Extension->bShadowBuffer = TRUE;
  1329. }
  1330. Extension->IsIeeeTerminateOk = TRUE;
  1331. }
  1332. return Status;
  1333. }
  1334. BOOLEAN
  1335. ParIsEcpHwSupported(
  1336. IN PDEVICE_EXTENSION Extension
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. This routine determines whether or not ECP mode is suported
  1341. in the write direction by trying to negotiate when asked.
  1342. Arguments:
  1343. Extension - The device extension.
  1344. Return Value:
  1345. BOOLEAN.
  1346. --*/
  1347. {
  1348. NTSTATUS Status;
  1349. if (Extension->BadProtocolModes & ECP_HW_NOIRQ)
  1350. return FALSE;
  1351. if (Extension->ProtocolModesSupported & ECP_HW_NOIRQ)
  1352. return TRUE;
  1353. if (!(Extension->HardwareCapabilities & PPT_ECP_PRESENT))
  1354. return FALSE;
  1355. if (0 == Extension->FifoWidth)
  1356. return FALSE;
  1357. if (Extension->ProtocolModesSupported & ECP_SW)
  1358. return TRUE;
  1359. // Must use HWECP Enter and Terminate for this test.
  1360. // Internel state machines will fail otherwise. --dvrh
  1361. Status = ParEnterEcpHwMode (Extension, FALSE);
  1362. ParTerminateHwEcpMode (Extension);
  1363. if (NT_SUCCESS(Status)) {
  1364. Extension->ProtocolModesSupported |= ECP_HW_NOIRQ;
  1365. return TRUE;
  1366. }
  1367. return FALSE;
  1368. }
  1369. VOID
  1370. ParTerminateHwEcpMode(
  1371. IN PDEVICE_EXTENSION Extension
  1372. )
  1373. /*++
  1374. Routine Description:
  1375. This routine terminates the interface back to compatibility mode.
  1376. Arguments:
  1377. Controller - Supplies the parallel port's controller address.
  1378. Return Value:
  1379. None.
  1380. --*/
  1381. {
  1382. ParDump2( PARENTRY, ("HWECP::Terminate Entry CurrentPhase %d\r\n", Extension->CurrentPhase));
  1383. // Need to check current phase -- if its reverse, need to flip bus
  1384. // If its not forward -- its an incorrect phase and termination will fail.
  1385. if ( Extension->ModeSafety == SAFE_MODE ) {
  1386. switch (Extension->CurrentPhase)
  1387. {
  1388. case PHASE_FORWARD_IDLE: // Legal state to terminate
  1389. {
  1390. break;
  1391. }
  1392. case PHASE_REVERSE_IDLE: // Flip the bus so we can terminate
  1393. {
  1394. NTSTATUS status = ParEcpHwExitReversePhase( Extension );
  1395. if ( STATUS_SUCCESS == status )
  1396. {
  1397. status = ParEcpEnterForwardPhase(Extension );
  1398. }
  1399. else
  1400. {
  1401. ParDump2( PARERRORS, ("HWECP::Terminate Couldn't flip the bus\r\n"));
  1402. }
  1403. break;
  1404. }
  1405. case PHASE_FORWARD_XFER:
  1406. case PHASE_REVERSE_XFER:
  1407. {
  1408. ParDump2( PARERRORS, ("HWECP::Terminate invalid wCurrentPhase (XFer in progress) \r\n"));
  1409. //status = VE_BUSY;
  1410. // Dunno what to do here. We probably will confuse the peripheral.
  1411. break;
  1412. }
  1413. // LAC TERMINATED 13Jan98
  1414. // Included PHASE_TERMINATE in the switch so we won't return an
  1415. // error if we are already terminated.
  1416. case PHASE_TERMINATE:
  1417. {
  1418. // We are already terminated, nothing to do
  1419. break;
  1420. }
  1421. default:
  1422. {
  1423. ParDump2( PARERRORS, ("ECP::Terminate VE_CORRUPT: invalid CurrentPhase %d\r\n", Extension->CurrentPhase));
  1424. //status = VE_CORRUPT;
  1425. // Dunno what to do here. We're lost and don't have a map to figure
  1426. // out where we are!
  1427. break;
  1428. }
  1429. }
  1430. ParDump2(PARINFO, ("HWECP::Terminate - Test ECPChanAddr\r\n"));
  1431. ParEcpHwWaitForEmptyFIFO(Extension);
  1432. ParCleanupHwEcpPort(Extension);
  1433. IeeeTerminate1284Mode (Extension);
  1434. } else {
  1435. ParCleanupHwEcpPort(Extension);
  1436. ParDump2(PARINFO, ("HWECP::Terminate - UNSAFE_MODE\r\n"));
  1437. Extension->Connected = FALSE;
  1438. }
  1439. return;
  1440. }