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.

374 lines
11 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. becp.c
  5. Abstract:
  6. This module contains code for the host to utilize BoundedECP if it has been
  7. detected and successfully enabled.
  8. Author:
  9. Robbie Harris (Hewlett-Packard) 27-May-1998
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "pch.h"
  15. #include "readwrit.h"
  16. #include "hwecp.h"
  17. // The following error codes were added to reflect errors that are unique to
  18. // Bounded ECP
  19. #define VE_FRAME_NO_DATA -74 // attempt to enter FrameRev w/o nPerReq
  20. #define VE_FRAME_CANT_EXIT_REVERSE -75 // attempt to exit FrameRev w/ nPerReq
  21. //=========================================================
  22. // BECP::ExitReversePhase
  23. //
  24. // Description : Get out of BECP Reverse Phase to the common state
  25. //
  26. // Input Parameters : Controller, pPortInfoStruct
  27. //
  28. // Modifies :
  29. //
  30. // Pre-conditions :
  31. //
  32. // Post-conditions :
  33. //
  34. // Returns :
  35. //
  36. //=========================================================
  37. NTSTATUS ParBecpExitReversePhase( IN PDEVICE_EXTENSION Extension )
  38. {
  39. // When using BECP, test nPeriphRequest prior to negotiation
  40. // from reverse phase to forward phase. Do not negotiate unless the
  41. // peripheral indicates it is finished sending. If using any other
  42. // mode, negotiate immediately.
  43. if ( Extension->ModeSafety == SAFE_MODE ) {
  44. if (Extension->CurrentPhase == PHASE_REVERSE_IDLE)
  45. {
  46. if (!CHECK_DSR( Extension->Controller,
  47. DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE,
  48. IEEE_MAXTIME_TL) )
  49. {
  50. ParDump2(PARERRORS, ("ParBecpExitReversePhase: Periph Stuck. Can't Flip Bus\n"));
  51. return STATUS_IO_TIMEOUT;
  52. }
  53. }
  54. }
  55. return ParEcpHwExitReversePhase(Extension);
  56. }
  57. //============================================================================
  58. // NAME: ECPFrame::Read()
  59. //
  60. //
  61. // LAC FRAME 12Dec97
  62. // This function is used for two different kinds of reads:
  63. // 1) continuing read - where we don't expect to exit reverse mode afterwards
  64. // 2) non-continuing read - where we expect to exit reverse mode afterwards
  65. // The problem is that we have no way of knowing which is which. I can
  66. // either wait after each read for nPeriphRequest to drop, or I can
  67. // check to see if it has dropped when I enter and handle it then.
  68. //
  69. // The other problem is that we have no way of communicating the fact that
  70. // we have done this to the PortTuple. It uses the last_direction member
  71. // to decide whether it should even look at entering or exiting some phase.
  72. //
  73. // Lets face it, we are on our own with this. It is safer to leave it
  74. // connected and then try to straighten things out when we come back. I
  75. // know that this wastes some time, but so does waiting at the end of
  76. // every read when only half of them are going to drop the nPeriphRequest.
  77. //
  78. // This routine performs a 1284 ECP mode read into the given
  79. // buffer for no more than 'BufferSize' bytes.
  80. //
  81. // This routine runs at DISPATCH_LEVEL.
  82. //
  83. // PARAMETERS:
  84. // Controller - Supplies the base address of the parallel port.
  85. // pPortInfoStruct - Supplies port information as defined in p1284.h
  86. // Buffer - Supplies the buffer to read into.
  87. // BufferSize - Supplies the number of bytes in the buffer.
  88. // BytesTransferred - Returns the number of bytes transferred.
  89. //
  90. // RETURNS:
  91. // NTSTATUS STATUS_SUCCESS or...
  92. // The number of bytes successfully read from the port is
  93. // returned via one of the arguments passed into this method.
  94. //
  95. // NOTES:
  96. // - Called ECP_PatchReverseTransfer in the original 16 bit code.
  97. //
  98. //============================================================================
  99. NTSTATUS
  100. ParBecpRead(
  101. IN PDEVICE_EXTENSION Extension,
  102. IN PVOID Buffer,
  103. IN ULONG BufferSize,
  104. OUT PULONG BytesTransferred
  105. )
  106. {
  107. NTSTATUS status = STATUS_SUCCESS;
  108. ParDump2(PARENTRY,("ParBecpRead: Enter BufferSize[%d]\n", BufferSize));
  109. status = ParEcpHwRead( Extension, Buffer, BufferSize, BytesTransferred );
  110. if (NT_SUCCESS(status)) {
  111. PUCHAR Controller;
  112. Controller = Extension->Controller;
  113. if ( CHECK_DSR_WITH_FIFO( Controller, DONT_CARE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE,
  114. ECR_FIFO_EMPTY, ECR_FIFO_SOME_DATA,
  115. DEFAULT_RECEIVE_TIMEOUT) ) {
  116. ParDump2(PARINFO,("ParBecpRead: No more data. Flipping to Fwd.\n"));
  117. //
  118. // Bounded ECP rule - no more data from periph - flip bus to forward
  119. //
  120. status = ParReverseToForward( Extension );
  121. ParDump2(PARINFO,("ParBecpRead: We have flipped to Fwd.\n"));
  122. } else {
  123. UCHAR bDSR = READ_PORT_UCHAR( Controller + OFFSET_DSR );
  124. //
  125. // Periph still has data, check for valid state
  126. //
  127. ParDump2(PARINFO,("ParBecpRead: Periph says there is more data. Checking for stall.\n"));
  128. // It's OK for the device to continue asserting nPeriphReq,
  129. // it may have more data to send. However, nAckReverse and
  130. // XFlag should be in a known state, so double check them.
  131. if ( ! TEST_DSR( bDSR, DONT_CARE, DONT_CARE, INACTIVE, ACTIVE, DONT_CARE ) ) {
  132. #if DVRH_BUS_RESET_ON_ERROR
  133. BusReset(Controller + OFFSET_DCR); // Pass in the dcr address
  134. #endif
  135. status = STATUS_LINK_FAILED;
  136. ParDump2(PARERRORS,("ParBecpRead: nAckReverse and XFlag are bad.\n"));
  137. } else {
  138. //
  139. // Periph has correctly acknowledged that it has data (state valid)
  140. //
  141. if ( (TRUE == Extension->P12843DL.bEventActive) ) {
  142. //
  143. // Signal transport (e.g., dot4) that data is avail
  144. //
  145. KeSetEvent(Extension->P12843DL.Event, 0, FALSE);
  146. }
  147. }
  148. }
  149. }
  150. ParDump2(PAREXIT, ("ParBecpRead: Exit[%d] BytesTransferred[%d]\r\n", NT_SUCCESS(status), *BytesTransferred));
  151. return status;
  152. }
  153. NTSTATUS
  154. ParEnterBecpMode(
  155. IN PDEVICE_EXTENSION Extension,
  156. IN BOOLEAN DeviceIdRequest
  157. )
  158. /*++
  159. Routine Description:
  160. This routine performs 1284 negotiation with the peripheral to the
  161. BECP mode protocol.
  162. Arguments:
  163. Controller - Supplies the port address.
  164. DeviceIdRequest - Supplies whether or not this is a request for a device
  165. id.
  166. Return Value:
  167. STATUS_SUCCESS - Successful negotiation.
  168. otherwise - Unsuccessful negotiation.
  169. --*/
  170. {
  171. NTSTATUS Status = STATUS_SUCCESS;
  172. if ( Extension->ModeSafety == SAFE_MODE ) {
  173. if (DeviceIdRequest) {
  174. Status = IeeeEnter1284Mode (Extension, BECP_EXTENSIBILITY | DEVICE_ID_REQ);
  175. } else {
  176. Status = IeeeEnter1284Mode (Extension, BECP_EXTENSIBILITY);
  177. }
  178. } else {
  179. Extension->Connected = TRUE;
  180. }
  181. if (NT_SUCCESS(Status)) {
  182. Status = ParEcpHwSetupPhase(Extension);
  183. Extension->bSynchWrites = TRUE; // NOTE this is a temp hack!!! dvrh
  184. if (!Extension->bShadowBuffer)
  185. {
  186. Queue_Create(&(Extension->ShadowBuffer), Extension->FifoDepth * 2);
  187. Extension->bShadowBuffer = TRUE;
  188. }
  189. Extension->IsIeeeTerminateOk = TRUE;
  190. }
  191. ParDump2(PARENTRY,("ParEnterBecpMode: End [%d]\n", NT_SUCCESS(Status)));
  192. return Status;
  193. }
  194. BOOLEAN
  195. ParIsBecpSupported(
  196. IN PDEVICE_EXTENSION Extension
  197. )
  198. /*++
  199. Routine Description:
  200. This routine determines whether or not ECP mode is suported
  201. in the write direction by trying to negotiate when asked.
  202. Arguments:
  203. Extension - The device extension.
  204. Return Value:
  205. BOOLEAN.
  206. --*/
  207. {
  208. NTSTATUS Status;
  209. if (Extension->BadProtocolModes & BOUNDED_ECP)
  210. {
  211. ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: BOUNDED_ECP has been marked as BadProtocolModes\n"));
  212. return FALSE;
  213. }
  214. if (Extension->ProtocolModesSupported & BOUNDED_ECP)
  215. {
  216. ParDump2(PARINFO, ("ParIsBecpSupported: PASSED: BOUNDED_ECP has already been cheacked\n"));
  217. return TRUE;
  218. }
  219. if (!(Extension->HardwareCapabilities & PPT_ECP_PRESENT))
  220. {
  221. ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: No HWECP\n"));
  222. return FALSE;
  223. }
  224. if (0 == Extension->FifoWidth)
  225. {
  226. ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: No FifoWidth\n"));
  227. return FALSE;
  228. }
  229. // Must use BECP Enter and Terminate for this test.
  230. // Internel state machines will fail otherwise. --dvrh
  231. Status = ParEnterBecpMode (Extension, FALSE);
  232. ParTerminateBecpMode (Extension);
  233. if (NT_SUCCESS(Status)) {
  234. Extension->ProtocolModesSupported |= BOUNDED_ECP;
  235. ParDump2(PARINFO, ("ParIsBecpSupported: PASSED:\n"));
  236. return TRUE;
  237. }
  238. ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: BOUNDED_ECP didn't negotiate\n"));
  239. return FALSE;
  240. }
  241. VOID
  242. ParTerminateBecpMode(
  243. IN PDEVICE_EXTENSION Extension
  244. )
  245. /*++
  246. Routine Description:
  247. This routine terminates the interface back to compatibility mode.
  248. Arguments:
  249. Controller - Supplies the parallel port's controller address.
  250. Return Value:
  251. None.
  252. --*/
  253. {
  254. ParDump2( PARENTRY, ("ParTerminateBecpMode: Entry CurrentPhase %d\r\n", Extension->CurrentPhase));
  255. // Need to check current phase -- if its reverse, need to flip bus
  256. // If its not forward -- its an incorrect phase and termination will fail.
  257. switch (Extension->CurrentPhase)
  258. {
  259. case PHASE_FORWARD_IDLE: // Legal state to terminate
  260. {
  261. break;
  262. }
  263. case PHASE_REVERSE_IDLE: // Flip the bus so we can terminate
  264. {
  265. NTSTATUS status = ParEcpHwExitReversePhase( Extension );
  266. if ( STATUS_SUCCESS == status )
  267. {
  268. status = ParEcpEnterForwardPhase(Extension );
  269. }
  270. else
  271. {
  272. ParDump2( PARERRORS, ("ParTerminateBecpMode: Couldn't flip the bus\n"));
  273. }
  274. break;
  275. }
  276. case PHASE_FORWARD_XFER:
  277. case PHASE_REVERSE_XFER:
  278. {
  279. ParDump2( PARERRORS, ("ParTerminateBecpMode: invalid wCurrentPhase (XFer in progress) \r\n"));
  280. //status = VE_BUSY;
  281. // Dunno what to do here. We probably will confuse the peripheral.
  282. break;
  283. }
  284. // LAC TERMINATED 13Jan98
  285. // Included PHASE_TERMINATE in the switch so we won't return an
  286. // error if we are already terminated.
  287. case PHASE_TERMINATE:
  288. {
  289. // We are already terminated, nothing to do
  290. break;
  291. }
  292. default:
  293. {
  294. ParDump2( PARERRORS, ("ParTerminateBecpMode: VE_CORRUPT: invalid CurrentPhase %d\r\n", Extension->CurrentPhase));
  295. //status = VE_CORRUPT;
  296. // Dunno what to do here. We're lost and don't have a map to figure
  297. // out where we are!
  298. break;
  299. }
  300. }
  301. ParEcpHwWaitForEmptyFIFO(Extension);
  302. ParCleanupHwEcpPort(Extension);
  303. if ( Extension->ModeSafety == SAFE_MODE ) {
  304. IeeeTerminate1284Mode (Extension);
  305. } else {
  306. ParDump2(PARINFO, ("ParTerminateBecpMode: In UNSAFE_MODE.\n"));
  307. Extension->Connected = FALSE;
  308. }
  309. return;
  310. }