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.

1315 lines
37 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. parmode.c
  5. Abstract:
  6. This is the main module for Extended Parallel Port (ECP) and
  7. Enhanced Parallel Port (EPP) detection. This module
  8. will detect for invalid chipshets and do ECR detection
  9. for ECP and EPP hardware support if the invalid chipset
  10. is not found.
  11. Author:
  12. Don Redford (v-donred) 4-Mar-1998
  13. Environment:
  14. Kernel mode
  15. Revision History :
  16. --*/
  17. #include "pch.h"
  18. #define USE_PARCHIP_ECRCONTROLLER 1
  19. NTSTATUS
  20. PptDetectChipFilter(
  21. IN PFDO_EXTENSION Fdx
  22. )
  23. /*++
  24. Routine Description:
  25. This routine is called once per DeviceObject to see if the filter driver
  26. for detecting parallel chip capabilities is there and to get the chip
  27. capabilities if there of the port in question.
  28. Arguments:
  29. Fdx - Supplies the device extension.
  30. Return Value:
  31. STATUS_SUCCESS - if we were able detect the chip and modes possible.
  32. !STATUS_SUCCESS - otherwise.
  33. --*/
  34. {
  35. NTSTATUS Status = STATUS_NO_SUCH_DEVICE;
  36. PIRP Irp;
  37. KEVENT Event;
  38. IO_STATUS_BLOCK IoStatus;
  39. UCHAR ecrLast;
  40. PUCHAR Controller, EcpController;
  41. Controller = Fdx->PortInfo.Controller;
  42. EcpController = Fdx->PnpInfo.EcpController;
  43. // Setting variable to FALSE to make sure we do not acidentally succeed
  44. Fdx->ChipInfo.success = FALSE;
  45. // Setting the Address to send to the filter driver to check the chips
  46. Fdx->ChipInfo.Controller = Controller;
  47. // Setting the Address to send to the filter driver to check the chips
  48. Fdx->ChipInfo.EcrController = EcpController;
  49. #ifndef USE_PARCHIP_ECRCONTROLLER
  50. // if there is not value in the ECR controller then PARCHIP and PARPORT
  51. // will conflict and PARCHIP will not work with PARPORT unless we
  52. // use the ECR controller found by PARCHIP.
  53. if ( !EcpController ) {
  54. return Status;
  55. }
  56. #endif
  57. //
  58. // Initialize
  59. //
  60. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  61. // Send a Pointer to the ChipInfo structure to and from the filter
  62. Irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_PARCHIP_CONNECT,
  63. Fdx->ParentDeviceObject,
  64. &Fdx->ChipInfo,
  65. sizeof(PARALLEL_PARCHIP_INFO),
  66. &Fdx->ChipInfo,
  67. sizeof(PARALLEL_PARCHIP_INFO),
  68. TRUE, &Event, &IoStatus);
  69. if (!Irp) {
  70. // couldn't create an IRP
  71. return STATUS_INSUFFICIENT_RESOURCES;
  72. }
  73. //
  74. // Call down to our parent and see if Filter is present
  75. //
  76. Status = IoCallDriver(Fdx->ParentDeviceObject, Irp);
  77. if (Status == STATUS_PENDING) {
  78. KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
  79. Status = Irp->IoStatus.Status;
  80. }
  81. //
  82. // If successful then we have a filter driver and we need to get the modes supported
  83. //
  84. if ( NT_SUCCESS(Status) ) {
  85. //
  86. // check to see if the filter driver was able to determine the I/O chip
  87. //
  88. if ( Fdx->ChipInfo.success ) {
  89. Fdx->PnpInfo.HardwareCapabilities = Fdx->ChipInfo.HardwareModes;
  90. #ifdef USE_PARCHIP_ECRCONTROLLER
  91. // only replace it if defined
  92. if ( Fdx->PnpInfo.EcpController != Fdx->ChipInfo.EcrController ) {
  93. Fdx->PnpInfo.EcpController = Fdx->ChipInfo.EcrController;
  94. EcpController = Fdx->PnpInfo.EcpController;
  95. }
  96. #endif
  97. // Set variable to say we have a filter driver
  98. Fdx->FilterMode = TRUE;
  99. }
  100. }
  101. // if there is a filter and ECP capable we need to get the Fifo Size
  102. if ( Fdx->FilterMode && Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT ) {
  103. Status = Fdx->ChipInfo.ParChipSetMode ( Fdx->ChipInfo.Context, ECR_ECP_MODE );
  104. // if able to set ECP mode
  105. if ( NT_SUCCESS( Status ) ) {
  106. PUCHAR wPortECR;
  107. wPortECR = EcpController + ECR_OFFSET;
  108. // get value from ECR reg & save it
  109. ecrLast = P5ReadPortUchar( wPortECR );
  110. // Determining Fifo Size
  111. PptDetermineFifoWidth(Fdx);
  112. PptDetermineFifoDepth(Fdx);
  113. // return ecr to original
  114. P5WritePortUchar( wPortECR, ecrLast);
  115. Status = Fdx->ChipInfo.ParChipClearMode ( Fdx->ChipInfo.Context, ECR_ECP_MODE );
  116. }
  117. }
  118. return Status;
  119. }
  120. NTSTATUS
  121. PptDetectPortType(
  122. IN PFDO_EXTENSION Fdx
  123. )
  124. /*++
  125. Routine Description:
  126. This routine is called once per DeviceObject to detect the type of
  127. parallel chip capabilities of the port in question.
  128. Arguments:
  129. Fdx - Supplies the device extension.
  130. Return Value:
  131. STATUS_SUCCESS - if we were able detect the chip and modes possible.
  132. !STATUS_SUCCESS - otherwise.
  133. --*/
  134. {
  135. NTSTATUS Status;
  136. UNICODE_STRING ParportPath;
  137. RTL_QUERY_REGISTRY_TABLE RegTable[2];
  138. ULONG IdentifierHex = 12169;
  139. ULONG zero = 0;
  140. //
  141. // -- May want to get detection order from Registry.
  142. // -- May also want to store/retrieve last known good configuration in/from registry.
  143. // -- Finally we should set a registry flag during dection so that we'll know
  144. // if we crashed while attempting to detect and not try it again.
  145. //
  146. RtlInitUnicodeString(&ParportPath, (PWSTR)L"Parport");
  147. // Setting up to get the Parport info
  148. RtlZeroMemory( RegTable, sizeof(RegTable) );
  149. RegTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
  150. RegTable[0].Name = (PWSTR)L"ModeCheckedStalled";
  151. RegTable[0].EntryContext = &IdentifierHex;
  152. RegTable[0].DefaultType = REG_DWORD;
  153. RegTable[0].DefaultData = &zero;
  154. RegTable[0].DefaultLength = sizeof(ULONG);
  155. //
  156. // Querying the registry for Parport to see if we tried to go check mode and we crashed
  157. // the registry key would still be there
  158. //
  159. Status = RtlQueryRegistryValues(
  160. RTL_REGISTRY_SERVICES,
  161. ParportPath.Buffer,
  162. RegTable,
  163. NULL,
  164. NULL );
  165. //
  166. // if registry key is there then we will just check ECP and Byte
  167. //
  168. if ( !(NT_SUCCESS( Status ) && IdentifierHex == 0) && (Status != STATUS_OBJECT_NAME_NOT_FOUND) ) {
  169. // dvtw, Check for ECP anyway! We just won't turn it on
  170. PptDetectEcpPort(Fdx);
  171. PptDetectBytePort(Fdx);
  172. if( Fdx->PnpInfo.HardwareCapabilities & (PPT_ECP_PRESENT | PPT_BYTE_PRESENT) ) {
  173. return STATUS_SUCCESS;
  174. } else {
  175. return STATUS_NO_SUCH_DEVICE;
  176. }
  177. }
  178. IdentifierHex = 12169;
  179. // Write the registry key out there just in case we crash
  180. Status = RtlWriteRegistryValue(
  181. RTL_REGISTRY_SERVICES,
  182. ParportPath.Buffer,
  183. (PWSTR)L"ModeCheckedStalled",
  184. REG_DWORD,
  185. &IdentifierHex,
  186. sizeof(ULONG) );
  187. //
  188. // Now we can start detecting the parallel port chip capabilities
  189. //
  190. Status = PptDetectPortCapabilities( Fdx );
  191. // Delete the registry key out there since we finished
  192. Status = RtlDeleteRegistryValue( RTL_REGISTRY_SERVICES, ParportPath.Buffer, (PWSTR)L"ModeCheckedStalled" );
  193. return Status;
  194. }
  195. NTSTATUS
  196. PptDetectPortCapabilities(
  197. IN PFDO_EXTENSION Fdx
  198. )
  199. /*++
  200. Routine Description:
  201. This is the "default" detection code, which looks for an ECR. If the ECR
  202. is present it tries to set mode 100b in <7:5>. If it sticks we'll call it
  203. EPP.
  204. Arguments:
  205. Fdx - Supplies the device extension.
  206. Return Value:
  207. STATUS_SUCCESS - if the port type was detected.
  208. !STATUS_SUCCESS - otherwise.
  209. --*/
  210. {
  211. NTSTATUS Status;
  212. PptDetectEcpPort( Fdx );
  213. // dvdr
  214. //
  215. // if we did not detect an ECR for ECP mode and ECP mode failed
  216. // EPP mode would fail also
  217. // Also cannot have EPP mode at an address that ends with a "C"
  218. //
  219. if ( (Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT) &&
  220. (((ULONG_PTR)Fdx->PortInfo.Controller & 0x0F) != 0x0C) ) {
  221. // Need to check for National chipsets before trying EPP mode
  222. // dvdr - need to add detection for old Winbond
  223. Status = PptFindNatChip( Fdx );
  224. if ( NT_SUCCESS( Status ) ) {
  225. if ( !Fdx->NationalChipFound ) {
  226. // National chipset was NOT found so we can see if generic EPP is supported
  227. PptDetectEppPortIfDot3DevicePresent( Fdx );
  228. if( !Fdx->CheckedForGenericEpp ) {
  229. // we didn't have a dot3 device to use for screening, do check anyway
  230. // if user has explicitly requested EPP detection
  231. PptDetectEppPortIfUserRequested( Fdx );
  232. }
  233. } else {
  234. // National chipset was found so can't do generic EPP
  235. Fdx->CheckedForGenericEpp = TRUE; // check is complete - generic EPP is unsafe
  236. }
  237. }
  238. } else {
  239. // ECP failed no check for Generic EPP
  240. Fdx->CheckedForGenericEpp = TRUE; // check is complete - generic EPP is unsafe
  241. }
  242. PptDetectBytePort( Fdx );
  243. if (Fdx->PnpInfo.HardwareCapabilities & (PPT_ECP_PRESENT | PPT_EPP_PRESENT | PPT_BYTE_PRESENT) ) {
  244. return STATUS_SUCCESS;
  245. }
  246. return STATUS_NO_SUCH_DEVICE;
  247. }
  248. VOID
  249. PptDetectEcpPort(
  250. IN PFDO_EXTENSION Fdx
  251. )
  252. /*++
  253. Routine Description:
  254. This routine looks for the presence of an ECR register to determine that
  255. it has ECP.
  256. Arguments:
  257. Fdx - Supplies the device extension of the device we are
  258. reporting resources for.
  259. Return Value:
  260. None.
  261. --*/
  262. {
  263. PUCHAR Controller;
  264. PUCHAR wPortDCR; // IO address of Device Control Register (DCR)
  265. PUCHAR wPortECR; // IO address of Extended Control Register (ECR)
  266. UCHAR ecrLast, ecr, dcr;
  267. Controller = Fdx->PortInfo.Controller;
  268. wPortDCR = Controller + DCR_OFFSET;
  269. if( 0 == Fdx->PnpInfo.EcpController ) {
  270. // PnP didn't give us an ECP Register set - we're done here
  271. return;
  272. }
  273. wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
  274. ecrLast = ecr = P5ReadPortUchar(wPortECR);
  275. // Initialize the DCR's nAutoFeed and nStrobe to a harmless combination
  276. // that could be returned by the ECR, but is not likely to be returned if
  277. // the ECR isn't present. Depending on the host's address decode logic,
  278. // reading a non-existant ECR could have one of two results: the ECR address
  279. // could decode on top of the DCR, so we'll read the value we are about to set.
  280. // Alternately, we might just read a floating bus and get a random value.
  281. dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, INACTIVE, ACTIVE );
  282. P5WritePortUchar( wPortDCR, dcr );
  283. ecrLast = ecr = P5ReadPortUchar(wPortECR);
  284. // Attempt to read the ECR. If ECP hardware is present, the ECR register's
  285. // bit 1 and bit 0 should read a 00 (some data in the FIFO), 01 (FIFO empty),
  286. // or 10 (FIFO full). If we read a 11 (illegal combination) then we know for
  287. // sure that no ECP hardware is present. Also, a valid ECR should never return
  288. // 0xFF (but a nonexistant register probably would), so we'll test for that
  289. // specific value also.
  290. if ( ( TEST_ECR_FIFO( ecr, ECR_FIFO_MASK ) ) || ( ecrLast == 0xFF ) ) {
  291. // ECR[1:0] returned a value of 11, so this can't be hardware ECP.
  292. DD((PCE)Fdx,DDT,"ParMode::PptDetectEcpPort: illegal FIFO status\n");
  293. // Restore the DCR so that all lines are inactive.
  294. dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
  295. P5WritePortUchar( wPortDCR, dcr );
  296. return;
  297. }
  298. // OK, so we got either a 00, 01, or 10 for ECR[1:0]. If it was 10, the
  299. if( TEST_ECR_FIFO( ecr, ECR_FIFO_FULL ) ) { // Looking for ECR[1:0] of 10...
  300. // The ECR[1:0] returned 10. This is a legal value, but possibly the
  301. // hardware might have just decoded the DCR and we merely read back the
  302. // DCR value we set earlier. Or, we might have just read back a value
  303. // that was hanging on the bus due to bus capacitance. So, we'll change
  304. // the DCR, read the ECR again, and see if the two registers continue to
  305. // track each other. If they do track, we'll conclude that there is no
  306. // ECP hardware.
  307. // Put the DCR's nAutoFeed and nStrobe register bits back to zero.
  308. dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
  309. P5WritePortUchar( wPortDCR, dcr );
  310. // Read the ECR again
  311. ecr = P5ReadPortUchar( wPortECR );
  312. if ( TEST_ECR_FIFO( ecr, ECR_FIFO_SOME_DATA ) ) {
  313. // ECR[1:0] is tracking DCR[1:0], so this can't be hardware ECP.
  314. // Restore the DCR so that all lines are inactive.
  315. dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
  316. P5WritePortUchar( wPortDCR, dcr );
  317. return;
  318. }
  319. }
  320. // If we get this far, then the ECR appears to be returning something valid that
  321. // doesn't track the DCR. It is beginning to look promising. We're going
  322. // to take a chance, and write the ECR to put the chip in compatiblity
  323. // mode. Doing so will reset the FIFO, so when we read FIFO status it should
  324. // come back empty. However, if we're wrong and this isn't ECP hardware, the
  325. // value we're about to write will turn on 1284Active (nSelectIn) and this might
  326. // cause headaches for the peripheral.
  327. P5WritePortUchar( wPortECR, DEFAULT_ECR_COMPATIBILITY );
  328. // Read the ECR again
  329. ecr = P5ReadPortUchar( wPortECR );
  330. // Now test the ECR snapshot to see if the FIFO status is correct. The FIFO
  331. // should test empty.
  332. if (!TEST_ECR_FIFO( ecr, ECR_FIFO_EMPTY ) )
  333. {
  334. // Restore the DCR so that all lines are inactive.
  335. dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
  336. P5WritePortUchar( wPortDCR, dcr );
  337. return;
  338. }
  339. // OK, it looks very promising. Perform a couple of additional tests that
  340. // will give us a lot of confidence, as well as providing some information
  341. // we need about the ECP chip.
  342. // return ecr to original
  343. P5WritePortUchar(wPortECR, ecrLast);
  344. //
  345. // Test here for ECP capable
  346. //
  347. // get value from ECR reg & save it
  348. ecrLast = P5ReadPortUchar( wPortECR );
  349. ecr = (UCHAR)(ecrLast & ECR_MODE_MASK);
  350. // Put the chip into test mode; the FIFO should start out empty
  351. P5WritePortUchar(wPortECR, (UCHAR)(ecr | ECR_TEST_MODE) );
  352. PptDetermineFifoWidth(Fdx);
  353. if( 0 != Fdx->PnpInfo.FifoWidth) {
  354. Fdx->PnpInfo.HardwareCapabilities |= PPT_ECP_PRESENT;
  355. PptDetermineFifoDepth( Fdx );
  356. if( 0 == Fdx->PnpInfo.FifoDepth ) {
  357. // Probe for FIFO depth failed - mark ECP as bad chip mode
  358. Fdx->PnpInfo.HardwareCapabilities &= ~(PPT_ECP_PRESENT);
  359. }
  360. }
  361. // return ecr to original
  362. P5WritePortUchar( wPortECR, ecrLast );
  363. return;
  364. }
  365. VOID
  366. PptDetectEppPortIfDot3DevicePresent(
  367. IN PFDO_EXTENSION Fdx
  368. )
  369. /*++
  370. Routine Description:
  371. If a 1284.3 daisy chain device is present, use the dot3 device to screen
  372. any printer from signal leakage while doing EPP detection. Otherwise
  373. abort detection.
  374. Arguments:
  375. Fdx - Supplies the device extension of the device we are
  376. reporting resources for.
  377. Return Value:
  378. None.
  379. --*/
  380. {
  381. NTSTATUS status;
  382. PUCHAR Controller = Fdx->PortInfo.Controller;
  383. PARALLEL_1284_COMMAND Command;
  384. if( 0 == Fdx->PnpInfo.Ieee1284_3DeviceCount ) {
  385. // No dot3 DC device present - aborting - unsafe for some printers if we check for EPP here
  386. return;
  387. }
  388. //
  389. // 1284.3 daisy chain device is present. Use device to screen printer from
  390. // possible signal leakage.
  391. //
  392. //
  393. // Select 1284.3 daisy chain device
  394. //
  395. Command.ID = 0;
  396. Command.Port = 0;
  397. Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
  398. status = PptTrySelectDevice( Fdx, &Command );
  399. if( !NT_SUCCESS( status ) ) {
  400. // unable to select device - something is wrong - just bail out
  401. return;
  402. }
  403. //
  404. // do the detection for chipset EPP capability
  405. //
  406. // DOT3 Device Present and selected
  407. PptDetectEppPort( Fdx );
  408. //
  409. // Deselect 1284.3 daisy chain device
  410. //
  411. Command.ID = 0;
  412. Command.Port = 0;
  413. Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
  414. status = PptDeselectDevice( Fdx, &Command );
  415. if( !NT_SUCCESS( status ) ) {
  416. // deselect failed??? - this shouldn't happen - our daisy chain interface is likely hung
  417. DD((PCE)Fdx,DDE,"PptDetectEppPort - deselect of 1284.3 device FAILED - Controller=%x\n", Controller);
  418. }
  419. return;
  420. }
  421. VOID
  422. PptDetectEppPortIfUserRequested(
  423. IN PFDO_EXTENSION Fdx
  424. )
  425. /*++
  426. Routine Description:
  427. If user explicitly requested Generic EPP detection then do the check.
  428. Arguments:
  429. Fdx - Supplies the device extension of the device we are
  430. reporting resources for.
  431. Return Value:
  432. None.
  433. --*/
  434. {
  435. ULONG RequestEppTest = 0;
  436. PptRegGetDeviceParameterDword( Fdx->PhysicalDeviceObject, (PWSTR)L"RequestEppTest", &RequestEppTest );
  437. if( RequestEppTest ) {
  438. DD((PCE)Fdx,DDT,"-- User Requested EPP detection - %x\n", RequestEppTest);
  439. PptDetectEppPort( Fdx );
  440. } else {
  441. DD((PCE)Fdx,DDT,"-- User did not request EPP detection\n");
  442. }
  443. return;
  444. }
  445. VOID
  446. PptDetectEppPort(
  447. IN PFDO_EXTENSION Fdx
  448. )
  449. /*++
  450. Routine Description:
  451. This routine checks for EPP capable port after ECP was found.
  452. Arguments:
  453. Fdx - Supplies the device extension of the device we are
  454. reporting resources for.
  455. Return Value:
  456. None.
  457. --*/
  458. {
  459. PUCHAR Controller;
  460. UCHAR dcr, i;
  461. UCHAR Reverse = (UCHAR)(DCR_DIRECTION | DCR_NOT_INIT | DCR_AUTOFEED | DCR_DSTRB);
  462. UCHAR Forward = (UCHAR)(DCR_NOT_INIT | DCR_AUTOFEED | DCR_DSTRB);
  463. ASSERTMSG(FALSE, "PptDetectEppPort shouldn't be called in current driver version");
  464. DD((PCE)Fdx,DDT,"-- PptDetectEppPort - Enter\n");
  465. DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: Enter\n");
  466. Controller = Fdx->PortInfo.Controller;
  467. // Get current DCR
  468. dcr = P5ReadPortUchar( Controller + DCR_OFFSET );
  469. //
  470. // Temporarily set capability to true to bypass PptEcrSetMode validity
  471. // check. We'll clear the flag before we return if EPP test fails.
  472. //
  473. Fdx->PnpInfo.HardwareCapabilities |= PPT_EPP_PRESENT;
  474. // Setting EPP mode
  475. DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: Setting EPP Mode\n");
  476. PptEcrSetMode( Fdx, ECR_EPP_PIO_MODE );
  477. //
  478. // Testing the hardware for EPP capable
  479. //
  480. for ( i = 0x01; i <= 0x02; i++ ) {
  481. // Put it into reverse phase so it doesn't talk to a device
  482. P5WritePortUchar( Controller + DCR_OFFSET, Reverse );
  483. KeStallExecutionProcessor( 5 );
  484. P5WritePortUchar( Controller + EPP_OFFSET, (UCHAR)i );
  485. // put it back into forward phase to read the byte we put out there
  486. P5WritePortUchar( Controller + DCR_OFFSET, Forward );
  487. KeStallExecutionProcessor( 5 );
  488. if ( P5ReadPortUchar( Controller ) != i ) {
  489. // failure so clear EPP flag
  490. Fdx->PnpInfo.HardwareCapabilities &= ~PPT_EPP_PRESENT;
  491. break;
  492. }
  493. }
  494. // Clearing EPP Mode
  495. PptEcrClearMode( Fdx );
  496. // Restore DCR
  497. P5WritePortUchar( Controller + DCR_OFFSET, dcr );
  498. Fdx->CheckedForGenericEpp = TRUE; // check is complete
  499. if( Fdx->PnpInfo.HardwareCapabilities & PPT_EPP_PRESENT ) {
  500. DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: EPP present - Controller=%x\n", Controller);
  501. DD((PCE)Fdx,DDT,"-- PptDetectEppPort - HAVE Generic EPP\n");
  502. } else {
  503. DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: EPP NOT present - Controller=%x\n", Controller);
  504. DD((PCE)Fdx,DDT,"-- PptDetectEppPort - DON'T HAVE Generic EPP\n");
  505. }
  506. DD((PCE)Fdx,DDT,"-- PptDetectEppPort - Exit\n");
  507. return;
  508. }
  509. VOID
  510. PptDetectBytePort(
  511. IN PFDO_EXTENSION Fdx
  512. )
  513. /*++
  514. Routine Description:
  515. This routine check to see if the port is Byte capable.
  516. Arguments:
  517. Fdx - Supplies the device extension of the device we are
  518. reporting resources for.
  519. Return Value:
  520. None.
  521. --*/
  522. {
  523. NTSTATUS Status = STATUS_SUCCESS;
  524. DD((PCE)Fdx,DDT,"ParMode::PptDetectBytePort Enter.\n" );
  525. Status = PptSetByteMode( Fdx, ECR_BYTE_PIO_MODE );
  526. if ( NT_SUCCESS(Status) ) {
  527. // Byte Mode found
  528. DD((PCE)Fdx,DDT,"ParMode::PptDetectBytePort: Byte Found\n");
  529. Fdx->PnpInfo.HardwareCapabilities |= PPT_BYTE_PRESENT;
  530. } else {
  531. // Byte Mode Not Found
  532. DD((PCE)Fdx,DDT,"ParMode::PptDetectBytePort: Byte Not Found\n");
  533. }
  534. (VOID)PptClearByteMode( Fdx );
  535. }
  536. VOID PptDetermineFifoDepth(
  537. IN PFDO_EXTENSION Fdx
  538. )
  539. {
  540. PUCHAR Controller;
  541. PUCHAR wPortECR; // IO address of Extended Control Register (ECR)
  542. PUCHAR wPortDFIFO;
  543. UCHAR ecr, ecrLast;
  544. ULONG wFifoDepth;
  545. UCHAR writeFifoDepth; // Depth calculated while writing FIFO
  546. UCHAR readFifoDepth; // Depth calculated while reading FIFO
  547. ULONG limitCount; // Prevents infinite looping on FIFO status
  548. UCHAR testData;
  549. Controller = Fdx->PortInfo.Controller;
  550. wPortECR = Fdx->PnpInfo.EcpController+ ECR_OFFSET;
  551. wPortDFIFO = Fdx->PnpInfo.EcpController;
  552. wFifoDepth = 0;
  553. ecrLast = P5ReadPortUchar(wPortECR );
  554. P5WritePortUchar(wPortECR, DEFAULT_ECR_TEST );
  555. ecr = P5ReadPortUchar(wPortECR );
  556. if ( TEST_ECR_FIFO( ecr, ECR_FIFO_EMPTY ) ) {
  557. // Write bytes into the FIFO until it indicates full.
  558. writeFifoDepth = 0;
  559. limitCount = 0;
  560. while (((P5ReadPortUchar (wPortECR) & ECR_FIFO_MASK) != ECR_FIFO_FULL ) &&
  561. (limitCount <= ECP_MAX_FIFO_DEPTH)) {
  562. P5WritePortUchar( wPortDFIFO, (UCHAR)(writeFifoDepth & 0xFF) );
  563. writeFifoDepth++;
  564. limitCount++;
  565. }
  566. DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth:: write fifo depth = %d\r\n", writeFifoDepth);
  567. // Now read the bytes back, comparing what comes back.
  568. readFifoDepth = 0;
  569. limitCount = 0;
  570. while (((P5ReadPortUchar( wPortECR ) & ECR_FIFO_MASK ) != ECR_FIFO_EMPTY ) &&
  571. (limitCount <= ECP_MAX_FIFO_DEPTH)) {
  572. testData = P5ReadPortUchar( wPortDFIFO );
  573. if ( testData != (readFifoDepth & (UCHAR)0xFF )) {
  574. // Data mismatch indicates problems...
  575. // FIFO status didn't pan out, may not be an ECP chip after all
  576. P5WritePortUchar( wPortECR, ecrLast);
  577. DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth::: data mismatch\n");
  578. return;
  579. }
  580. readFifoDepth++;
  581. limitCount++;
  582. }
  583. DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth::: read fifo depth = %d\r\n", readFifoDepth);
  584. // The write depth should match the read depth...
  585. if ( writeFifoDepth == readFifoDepth ) {
  586. wFifoDepth = readFifoDepth;
  587. } else {
  588. // Assume no FIFO
  589. P5WritePortUchar( wPortECR, ecrLast);
  590. DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth::: No Fifo\n");
  591. return;
  592. }
  593. } else {
  594. // FIFO status didn't pan out, may not be an ECP chip after all
  595. DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth:: Bad Fifo\n");
  596. P5WritePortUchar(wPortECR, ecrLast);
  597. return;
  598. }
  599. // put chip into spp mode
  600. P5WritePortUchar( wPortECR, ecrLast );
  601. Fdx->PnpInfo.FifoDepth = wFifoDepth;
  602. }
  603. VOID
  604. PptDetermineFifoWidth(
  605. IN PFDO_EXTENSION Fdx
  606. )
  607. {
  608. PUCHAR Controller;
  609. UCHAR bConfigA;
  610. PUCHAR wPortECR;
  611. DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoWidth: Start\n");
  612. Controller = Fdx->PortInfo.Controller;
  613. wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
  614. // Put chip into configuration mode so we can access the ConfigA register
  615. P5WritePortUchar( wPortECR, DEFAULT_ECR_CONFIGURATION );
  616. // The FIFO width is bits <6:4> of the ConfigA register.
  617. bConfigA = P5ReadPortUchar( Fdx->PnpInfo.EcpController );
  618. Fdx->PnpInfo.FifoWidth = (ULONG)(( bConfigA & CNFGA_IMPID_MASK ) >> CNFGA_IMPID_SHIFT);
  619. // Put the chip back in compatibility mode.
  620. P5WritePortUchar(wPortECR, DEFAULT_ECR_COMPATIBILITY );
  621. return;
  622. }
  623. NTSTATUS
  624. PptSetChipMode (
  625. IN PFDO_EXTENSION Fdx,
  626. IN UCHAR ChipMode
  627. )
  628. /*++
  629. Routine Description:
  630. This function will put the current parallel chip into the
  631. given mode if supported. The determination of supported mode
  632. was in the PptDetectPortType function.
  633. Arguments:
  634. Fdx - Supplies the device extension.
  635. Return Value:
  636. STATUS_SUCCESS - if the port type was detected.
  637. !STATUS_SUCCESS - otherwise.
  638. --*/
  639. {
  640. NTSTATUS Status = STATUS_SUCCESS;
  641. UCHAR EcrMode = (UCHAR)( ChipMode & ~ECR_MODE_MASK );
  642. // Also allow PptSetChipMode from PS/2 mode - we need this for HWECP
  643. // bus flip from Forward to Reverse in order to meet the required
  644. // sequence specified in the Microsoft ECP Port Spec version 1.06,
  645. // July 14, 1993, to switch directly from PS/2 mode with output
  646. // drivers disabled (direction bit set to "read") to HWECP via
  647. // the ECR. Changed 2000-02-11.
  648. if ( Fdx->PnpInfo.CurrentMode != INITIAL_MODE && Fdx->PnpInfo.CurrentMode != ECR_BYTE_MODE ) {
  649. DD((PCE)Fdx,DDW,"PptSetChipMode - CurrentMode invalid\n");
  650. // Current mode is not valid to put in EPP or ECP mode
  651. Status = STATUS_INVALID_DEVICE_STATE;
  652. goto ExitSetChipModeNoChange;
  653. }
  654. // need to find out what mode it was and try to take it out of it
  655. // Check to see if we need to use the filter to set the mode
  656. if ( Fdx->FilterMode ) {
  657. Status = Fdx->ChipInfo.ParChipSetMode ( Fdx->ChipInfo.Context, ChipMode );
  658. } else {
  659. // If asked for ECP check to see if we can do it
  660. if ( EcrMode == ECR_ECP_MODE ) {
  661. if ((Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT) ^ PPT_ECP_PRESENT) {
  662. // ECP Not Present
  663. return STATUS_NO_SUCH_DEVICE;
  664. }
  665. Status = PptEcrSetMode ( Fdx, ChipMode );
  666. goto ExitSetChipModeWithChanges;
  667. }
  668. // If asked for EPP check to see if we can do it
  669. if ( EcrMode == ECR_EPP_MODE ) {
  670. if ((Fdx->PnpInfo.HardwareCapabilities & PPT_EPP_PRESENT) ^ PPT_EPP_PRESENT) {
  671. // EPP Not Present
  672. return STATUS_NO_SUCH_DEVICE;
  673. }
  674. Status = PptEcrSetMode ( Fdx, ChipMode );
  675. goto ExitSetChipModeWithChanges;
  676. }
  677. // If asked for Byte Mode check to see if it is still enabled
  678. if ( EcrMode == ECR_BYTE_MODE ) {
  679. if ((Fdx->PnpInfo.HardwareCapabilities & PPT_BYTE_PRESENT) ^ PPT_BYTE_PRESENT) {
  680. // BYTE Not Present
  681. return STATUS_NO_SUCH_DEVICE;
  682. }
  683. Status = PptSetByteMode ( Fdx, ChipMode );
  684. goto ExitSetChipModeWithChanges;
  685. }
  686. }
  687. ExitSetChipModeWithChanges:
  688. if ( NT_SUCCESS(Status) ) {
  689. Fdx->PnpInfo.CurrentMode = EcrMode;
  690. } else {
  691. DD((PCE)Fdx,DDW,"PptSetChipMode - failed w/status = %x\n",Status);
  692. }
  693. ExitSetChipModeNoChange:
  694. return Status;
  695. }
  696. NTSTATUS
  697. PptClearChipMode (
  698. IN PFDO_EXTENSION Fdx,
  699. IN UCHAR ChipMode
  700. )
  701. /*++
  702. Routine Description:
  703. This routine Clears the Given chip mode.
  704. Arguments:
  705. Fdx - Supplies the device extension.
  706. ChipMode - The given mode to clear from the Chip
  707. Return Value:
  708. STATUS_SUCCESS - if the port type was detected.
  709. !STATUS_SUCCESS - otherwise.
  710. --*/
  711. {
  712. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  713. ULONG EcrMode = ChipMode & ~ECR_MODE_MASK;
  714. // make sure we have a mode to clear
  715. if ( EcrMode != Fdx->PnpInfo.CurrentMode ) {
  716. DD((PCE)Fdx,DDW,"ParMode::PptClearChipMode: Mode to Clear != CurrentModen");
  717. // Current mode is not the same as requested to take it out of
  718. Status = STATUS_INVALID_DEVICE_STATE;
  719. goto ExitClearChipModeNoChange;
  720. }
  721. // need to find out what mode it was and try to take it out of it
  722. // check to see if we used the filter to set the mode
  723. if ( Fdx->FilterMode ) {
  724. Status = Fdx->ChipInfo.ParChipClearMode ( Fdx->ChipInfo.Context, ChipMode );
  725. } else {
  726. // If ECP mode check to see if we can clear it
  727. if ( EcrMode == ECR_ECP_MODE ) {
  728. Status = PptEcrClearMode( Fdx );
  729. goto ExitClearChipModeWithChanges;
  730. }
  731. // If EPP mode check to see if we can clear it
  732. if ( EcrMode == ECR_EPP_MODE ) {
  733. Status = PptEcrClearMode( Fdx );
  734. goto ExitClearChipModeWithChanges;
  735. }
  736. // If BYTE mode clear it if use ECR register
  737. if ( EcrMode == ECR_BYTE_MODE ) {
  738. Status = PptClearByteMode( Fdx );
  739. goto ExitClearChipModeWithChanges;
  740. }
  741. }
  742. ExitClearChipModeWithChanges:
  743. if( NT_SUCCESS(Status) ) {
  744. Fdx->PnpInfo.CurrentMode = INITIAL_MODE;
  745. }
  746. ExitClearChipModeNoChange:
  747. return Status;
  748. }
  749. NTSTATUS
  750. PptEcrSetMode(
  751. IN PFDO_EXTENSION Fdx,
  752. IN UCHAR ChipMode
  753. )
  754. /*++
  755. Routine Description:
  756. This routine enables EPP mode through the ECR register.
  757. Arguments:
  758. Fdx - Supplies the device extension.
  759. Return Value:
  760. STATUS_SUCCESS - if the port type was detected.
  761. !STATUS_SUCCESS - otherwise.
  762. --*/
  763. {
  764. UCHAR ecr;
  765. PUCHAR Controller;
  766. PUCHAR wPortECR;
  767. Controller = Fdx->PortInfo.Controller;
  768. //
  769. // Store the prior mode.
  770. //
  771. wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
  772. ecr = P5ReadPortUchar( wPortECR );
  773. Fdx->EcrPortData = ecr;
  774. // get rid of prior mode which is the top three bits
  775. ecr &= ECR_MODE_MASK;
  776. // Write out SPP mode first to the chip
  777. P5WritePortUchar( wPortECR, (UCHAR)(ecr | ECR_BYTE_MODE) );
  778. // Write new mode to ECR register
  779. P5WritePortUchar( wPortECR, ChipMode );
  780. return STATUS_SUCCESS;
  781. }
  782. NTSTATUS
  783. PptSetByteMode(
  784. IN PFDO_EXTENSION Fdx,
  785. IN UCHAR ChipMode
  786. )
  787. /*++
  788. Routine Description:
  789. This routine enables Byte mode either through the ECR register
  790. (if available). Or just checks it to see if it works
  791. Arguments:
  792. Fdx - Supplies the device extension.
  793. Return Value:
  794. STATUS_SUCCESS - if the port type was detected.
  795. !STATUS_SUCCESS - otherwise.
  796. --*/
  797. {
  798. NTSTATUS Status;
  799. // Checking to see if ECR register is there and if there use it
  800. if ( Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT ) {
  801. Status = PptEcrSetMode( Fdx, ChipMode );
  802. }
  803. Status = PptCheckByteMode( Fdx );
  804. return Status;
  805. }
  806. NTSTATUS
  807. PptClearByteMode(
  808. IN PFDO_EXTENSION Fdx
  809. )
  810. /*++
  811. Routine Description:
  812. This routine Clears Byte mode through the ECR register if there otherwise
  813. just returns success because nothing needs to be done.
  814. Arguments:
  815. Fdx - Supplies the device extension.
  816. Return Value:
  817. STATUS_SUCCESS - if the port type was detected.
  818. !STATUS_SUCCESS - otherwise.
  819. --*/
  820. {
  821. NTSTATUS Status = STATUS_SUCCESS;
  822. // Put ECR register back to original if it was there
  823. if ( Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT ) {
  824. Status = PptEcrClearMode( Fdx );
  825. }
  826. return Status;
  827. }
  828. NTSTATUS
  829. PptCheckByteMode(
  830. IN PFDO_EXTENSION Fdx
  831. )
  832. /*++
  833. Routine Description:
  834. This routine checks to make sure we are still Byte capable before doing
  835. any transfering of data.
  836. Arguments:
  837. Fdx - Supplies the device extension of the device we are
  838. reporting resources for.
  839. Return Value:
  840. None.
  841. --*/
  842. {
  843. PUCHAR Controller;
  844. UCHAR dcr;
  845. Controller = Fdx->PortInfo.Controller;
  846. //
  847. // run the test again to make sure somebody didn't take us out of a
  848. // bi-directional capable port.
  849. //
  850. // 1. put in extended read mode.
  851. // 2. write data pattern
  852. // 3. read data pattern
  853. // 4. if bi-directional capable, then data patterns will be different.
  854. // 5. if patterns are the same, then check one more pattern.
  855. // 6. if patterns are still the same, then port is NOT bi-directional.
  856. //
  857. // get the current control port value for later restoration
  858. dcr = P5ReadPortUchar( Controller + DCR_OFFSET );
  859. // put port into extended read mode
  860. P5WritePortUchar( Controller + DCR_OFFSET, (UCHAR)(dcr | DCR_DIRECTION) );
  861. // write the first pattern to the port
  862. P5WritePortUchar( Controller, (UCHAR)0x55 );
  863. if ( P5ReadPortUchar( Controller ) == (UCHAR)0x55 ) {
  864. // same pattern, try the second pattern
  865. P5WritePortUchar( Controller, (UCHAR)0xaa );
  866. if ( P5ReadPortUchar( Controller ) == (UCHAR)0xaa ) {
  867. // the port is NOT bi-directional capable
  868. return STATUS_UNSUCCESSFUL;
  869. }
  870. }
  871. // restore the control port to its original value
  872. P5WritePortUchar( Controller + DCR_OFFSET, (UCHAR)dcr );
  873. return STATUS_SUCCESS;
  874. }
  875. NTSTATUS
  876. PptEcrClearMode(
  877. IN PFDO_EXTENSION Fdx
  878. )
  879. /*++
  880. Routine Description:
  881. This routine disables EPP or ECP mode whichever one the chip
  882. was in through the ECR register.
  883. Arguments:
  884. Fdx - Supplies the device extension.
  885. Return Value:
  886. STATUS_SUCCESS - if it was successful.
  887. !STATUS_SUCCESS - otherwise.
  888. --*/
  889. {
  890. UCHAR ecr;
  891. PUCHAR Controller;
  892. PUCHAR wPortECR;
  893. Controller = Fdx->PortInfo.Controller;
  894. //
  895. // Restore the prior mode.
  896. //
  897. // Get original ECR register
  898. ecr = Fdx->EcrPortData;
  899. Fdx->EcrPortData = 0;
  900. // some chips require to change modes only after
  901. // you put it into spp mode
  902. wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
  903. P5WritePortUchar( wPortECR, (UCHAR)(ecr & ECR_MODE_MASK) );
  904. // Back to original mode
  905. P5WritePortUchar( wPortECR, ecr );
  906. return STATUS_SUCCESS;
  907. }
  908. NTSTATUS
  909. PptBuildResourceList(
  910. IN PFDO_EXTENSION Fdx,
  911. IN ULONG Partial,
  912. IN PUCHAR *Addresses,
  913. OUT PCM_RESOURCE_LIST Resources
  914. )
  915. /*++
  916. Routine Description:
  917. This routine Builds a CM_RESOURCE_LIST with 1 Full Resource
  918. Descriptor and as many Partial resource descriptors as you want
  919. with the same parameters for the Full. No Interrupts or anything
  920. else just IO addresses.
  921. Arguments:
  922. Fdx - Supplies the device extension.
  923. Partial - Number (array size) of partial descriptors in Addresses[]
  924. Addresses - Pointer to an Array of addresses of the partial descriptors
  925. Resources - The returned CM_RESOURCE_LIST
  926. Return Value:
  927. STATUS_SUCCESS - if the building of the list was successful.
  928. STATUS_UNSUCCESSFUL - otherwise.
  929. --*/
  930. {
  931. UCHAR i;
  932. //
  933. // Number of Full Resource descriptors
  934. //
  935. Resources->Count = 1;
  936. Resources->List[0].InterfaceType = Fdx->InterfaceType;
  937. Resources->List[0].BusNumber = Fdx->BusNumber;
  938. Resources->List[0].PartialResourceList.Version = 0;
  939. Resources->List[0].PartialResourceList.Revision = 0;
  940. Resources->List[0].PartialResourceList.Count = Partial;
  941. //
  942. // Going through the loop for each partial descriptor
  943. //
  944. for ( i = 0; i < Partial ; i++ ) {
  945. //
  946. // Setup port
  947. //
  948. Resources->List[0].PartialResourceList.PartialDescriptors[i].Type = CmResourceTypePort;
  949. Resources->List[0].PartialResourceList.PartialDescriptors[i].ShareDisposition = CmResourceShareDriverExclusive;
  950. Resources->List[0].PartialResourceList.PartialDescriptors[i].Flags = CM_RESOURCE_PORT_IO;
  951. Resources->List[0].PartialResourceList.PartialDescriptors[i].u.Port.Start.QuadPart = (ULONG_PTR)Addresses[i];
  952. Resources->List[0].PartialResourceList.PartialDescriptors[i].u.Port.Length = (ULONG)2;
  953. }
  954. return ( STATUS_SUCCESS );
  955. }