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.

1291 lines
42 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. par12843.c
  5. Abstract:
  6. This is the main module for 1284.3 functionality. These
  7. function enable the selection and deselection of 1284.3
  8. compatable devices on the parallel port.
  9. The devices can be selected and deselected IRQL <= DISPATCH_LEVEL
  10. by calling IOCTL_INTERNAL_SELECT_DEVICE, or 'TrySelectDevice'.
  11. The first call is the simplest: the IRP will be queued in the
  12. parallel port driver until the port is free and then it will
  13. try to select the device with the given ID from the structure
  14. PARALLEL_1284_COMMAND. If successful it will with a successful
  15. status, otherwise it will return with an unsuccessful status.
  16. The class driver may cancel this IRP at any time which serves
  17. as a mechanism to timeout an allocate request.
  18. The 'TrySelectDevice' call returns immediately from the port
  19. driver with a TRUE status if the port was allocated and the
  20. device was able to be selected or a FALSE status if the port
  21. was either busy or the device was not able to be selected.
  22. Once the device is selected, the port is owned by the selecting class
  23. driver until a 'DeselectDevice' call is made. This deselects the
  24. device and also releases the port and wakes up the next caller.
  25. Author:
  26. Don E. Redford 3-Mar-1998
  27. Environment:
  28. Kernel mode
  29. Revision History :
  30. --*/
  31. #include "pch.h"
  32. ULONG
  33. PptInitiate1284_3(
  34. IN PVOID Extension
  35. );
  36. NTSTATUS
  37. PptTrySelectDevice(
  38. IN PVOID Context,
  39. IN PVOID TrySelectCommand
  40. );
  41. NTSTATUS
  42. PptDeselectDevice(
  43. IN PVOID Context,
  44. IN PVOID DeselectCommand
  45. );
  46. ULONG
  47. Ppt1284_3AssignAddress(
  48. IN PFDO_EXTENSION DeviceExtension
  49. );
  50. BOOLEAN
  51. PptSend1284_3Command(
  52. IN PUCHAR CurrentPort,
  53. IN UCHAR Command
  54. );
  55. BOOLEAN
  56. PptCheckIfStl1284_3(
  57. IN PFDO_EXTENSION DeviceExtension,
  58. IN ULONG ulDaisyIndex,
  59. IN BOOLEAN bNoStrobe
  60. );
  61. BOOLEAN
  62. PptCheckIfNon1284_3Present(
  63. IN PFDO_EXTENSION Extension
  64. );
  65. BOOLEAN
  66. PptCheckIfStlProductId(
  67. IN PFDO_EXTENSION Extension,
  68. IN ULONG ulDaisyIndex
  69. );
  70. //
  71. // Beginning of functions
  72. //
  73. ULONG
  74. PptInitiate1284_3(
  75. IN PVOID Extension
  76. )
  77. /*++
  78. Routine Description:
  79. This routine initializes all of the 1284.3 devices out on the
  80. given parallel port. It does this by assigning 1284.3 addresses to
  81. each device on the port.
  82. Arguments:
  83. Extensioon - Device extension structure.
  84. Return Value:
  85. None.
  86. --*/
  87. {
  88. ULONG deviceCount1 = 0;
  89. ULONG deviceCount2 = 0;
  90. ULONG loopCount = 0;
  91. ULONG maxTries = 3; // picked 3 out of thin air as a "reasonable" value
  92. // Send command to assign addresses and count number of 1284.3 daisy chain devices
  93. // Try multiple times to make sure we get the same count
  94. do {
  95. KeStallExecutionProcessor( 5 );
  96. deviceCount1 = Ppt1284_3AssignAddress( Extension );
  97. KeStallExecutionProcessor( 5 );
  98. deviceCount2 = Ppt1284_3AssignAddress( Extension );
  99. if( deviceCount1 != deviceCount2 ) {
  100. DD((PCE)Extension,DDW,"PptInitiate1284_3 - count unstable\n");
  101. PptAssert(deviceCount1 == deviceCount2);
  102. }
  103. } while( (deviceCount1 != deviceCount2) && (++loopCount < maxTries) );
  104. return deviceCount2;
  105. }
  106. NTSTATUS
  107. PptTrySelectDevice(
  108. IN PVOID Context,
  109. IN PVOID TrySelectCommand
  110. )
  111. /*++
  112. Routine Description:
  113. This routine first tries to allocate the port. If successful
  114. it will then try to select the device with the ID given.
  115. Arguments:
  116. Extension - Driver extension.
  117. Device - 1284.3 Device Id.
  118. Command - Command to know whether to allocate the port
  119. Return Value:
  120. TRUE - Able to allocate the port and select the device
  121. FALSE - 1: Invalid ID 2: Not able to allocate port 3: Not able to select device
  122. --*/
  123. {
  124. NTSTATUS Status = STATUS_SUCCESS;
  125. PFDO_EXTENSION Extension = Context;
  126. PPARALLEL_1284_COMMAND Command = TrySelectCommand;
  127. BOOLEAN success = FALSE;
  128. SYNCHRONIZED_COUNT_CONTEXT SyncContext;
  129. KIRQL CancelIrql;
  130. UCHAR i, DeviceID;
  131. if( ( Command->CommandFlags & PAR_LEGACY_ZIP_DRIVE ) ||
  132. ( Command->ID == DOT3_LEGACY_ZIP_ID )) {
  133. Status = PptTrySelectLegacyZip(Context, TrySelectCommand);
  134. DD((PCE)Extension,DDT,"PptTrySelectDevice - LegacyZip - status=%x\n",Status);
  135. return Status;
  136. }
  137. // get device ID to select
  138. DeviceID = Command->ID;
  139. // validate parameters - we will accept:
  140. // - a Dot3 device with a valid DeviceID
  141. // - an End-of-Chain device indicated by the PAR_END_OF_CHAIN_DEVICE flag, or
  142. // - an End-of-Chain device indicated by a DeviceID value one past the last Dot3 device
  143. if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) && DeviceID > Extension->PnpInfo.Ieee1284_3DeviceCount ) {
  144. // Requested device is not flagged as End-of-Chain device and DeviceID
  145. // is more than one past the end of the Dot3 Devices, so FAIL the IRP
  146. DD((PCE)Extension,DDE,"PptTrySelectDevice - FAIL - invalid DeviceID parameter\n",DeviceID);
  147. PptAssertMsg("PptTrySelectDevice - FAIL - invalid DeviceID parameter",FALSE);
  148. Status = STATUS_INVALID_PARAMETER;
  149. } else {
  150. //
  151. // Request appears valid
  152. //
  153. // test to see if we need to grab port
  154. if( Command->CommandFlags & PAR_HAVE_PORT_KEEP_PORT ) {
  155. //
  156. // requester has already acquired port, just do a SELECT
  157. //
  158. if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) &&
  159. DeviceID < Extension->PnpInfo.Ieee1284_3DeviceCount ) {
  160. // SELECT the device
  161. for ( i = 0; i < PptDot3Retries && !success; i++ ) {
  162. // Send command to to select device in compatability mode
  163. success = PptSend1284_3Command( Extension->PortInfo.Controller, (UCHAR)(CPP_SELECT | DeviceID) );
  164. // Stall a little in case we have to retry
  165. KeStallExecutionProcessor( 5 );
  166. }
  167. if ( success ) {
  168. DD((PCE)Extension,DDT,"PptTrySelectDevice - had port - SUCCESS\n");
  169. Status = STATUS_SUCCESS;
  170. } else {
  171. DD((PCE)Extension,DDW,"PptTrySelectDevice - FAIL\n");
  172. Status = STATUS_UNSUCCESSFUL;
  173. }
  174. } else {
  175. // End-of-Chain device, no SELECT required, SUCCEED the request
  176. DD((PCE)Extension,DDT,"PptTrySelectDevice - EOC\n");
  177. Status = STATUS_SUCCESS;
  178. }
  179. } else {
  180. // Don't have the port
  181. //
  182. // Try to acquire port and select device
  183. //
  184. IoAcquireCancelSpinLock(&CancelIrql);
  185. SyncContext.Count = &Extension->WorkQueueCount;
  186. if (Extension->InterruptRefCount) {
  187. KeSynchronizeExecution(Extension->InterruptObject, PptSynchronizedIncrement, &SyncContext);
  188. } else {
  189. PptSynchronizedIncrement(&SyncContext);
  190. }
  191. if (SyncContext.NewCount) {
  192. // Port is busy, queue request
  193. DD((PCE)Extension,DDT,"PptTrySelectDevice - Port Busy - Request Queued\n");
  194. IoReleaseCancelSpinLock(CancelIrql);
  195. Status = STATUS_PENDING;
  196. } else {
  197. IoReleaseCancelSpinLock(CancelIrql);
  198. // Port is acquired
  199. DD((PCE)Extension,DDT,"PptTrySelectDevice - Port Acquired\n");
  200. Extension->WmiPortAllocFreeCounts.PortAllocates++;
  201. if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) && DeviceID < Extension->PnpInfo.Ieee1284_3DeviceCount ) {
  202. // SELECT the device
  203. for ( i = 0; i < PptDot3Retries && !success; i++ ) {
  204. // Send command to to select device in compatability mode
  205. success = PptSend1284_3Command( Extension->PortInfo.Controller, (UCHAR)(CPP_SELECT | DeviceID) );
  206. // Stall a little in case we have to retry
  207. KeStallExecutionProcessor( 5 );
  208. }
  209. if ( success ) {
  210. DD((PCE)Extension,DDT,"PptTrySelectDevice - SUCCESS\n");
  211. Status = STATUS_SUCCESS;
  212. } else {
  213. DD((PCE)Extension,DDW,"PptTrySelectDevice - FAILED\n");
  214. // RMT - 000831 - do we still have the port locked!?! - did we hang the port?
  215. Status = STATUS_UNSUCCESSFUL;
  216. }
  217. } else {
  218. // End-of-Chain device, no SELECT required, SUCCEED the request
  219. DD((PCE)Extension,DDT,"PptTrySelectDevice - EOC2\n");
  220. Status = STATUS_SUCCESS;
  221. }
  222. } // endif - test for port busy
  223. } // endif - test if already have port
  224. } // endif - test for valid parameters
  225. return Status;
  226. }
  227. NTSTATUS
  228. PptDeselectDevice(
  229. IN PVOID Context,
  230. IN PVOID DeselectCommand
  231. )
  232. /*++
  233. Routine Description:
  234. This routine deselects the current device and then frees the port
  235. Arguments:
  236. Return Value:
  237. TRUE - Able to deselect the device and free the port
  238. FALSE - 1: Invalid ID 2: Not able to deselect the drive
  239. --*/
  240. {
  241. NTSTATUS Status = STATUS_SUCCESS;
  242. PFDO_EXTENSION fdx = Context;
  243. PPARALLEL_1284_COMMAND Command = DeselectCommand;
  244. BOOLEAN success = FALSE;
  245. UCHAR i, DeviceID;
  246. if( ( Command->CommandFlags & PAR_LEGACY_ZIP_DRIVE ) ||
  247. ( Command->ID == DOT3_LEGACY_ZIP_ID ) ) {
  248. return PptDeselectLegacyZip( Context, DeselectCommand );
  249. }
  250. // get device ID to deselect
  251. DeviceID = Command->ID;
  252. // validate ID
  253. if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) && DeviceID > fdx->PnpInfo.Ieee1284_3DeviceCount ) {
  254. // not End-of-Chain device and Dot3 DeviceID is invalid
  255. DD((PCE)fdx,DDE,"PptDeselectDevice - ID=%d - FAIL - invalid parameter\n",DeviceID);
  256. Status = STATUS_INVALID_PARAMETER;
  257. } else {
  258. // Check for End-of-Chain device
  259. if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) &&
  260. DeviceID < fdx->PnpInfo.Ieee1284_3DeviceCount ) {
  261. // first deselect the device
  262. for ( i = 0; i < PptDot3Retries && !success; i++ ) {
  263. success = PptSend1284_3Command( fdx->PortInfo.Controller, (UCHAR)CPP_DESELECT );
  264. // Stall a little in case we have to retry
  265. KeStallExecutionProcessor( 5 );
  266. }
  267. if ( success ) {
  268. // Deselecting device was a success
  269. DD((PCE)fdx,DDT,"PptDeselectDevice\n");
  270. // check if requester wants to keep port or free port
  271. if( !(Command->CommandFlags & PAR_HAVE_PORT_KEEP_PORT) ) {
  272. PptFreePort( fdx );
  273. }
  274. Status = STATUS_SUCCESS;
  275. } else {
  276. // Unable to deselect device, something went very wrong,
  277. // port is now in an unknown/blocked state
  278. DD((PCE)fdx,DDE,"PptDeselectDevice - ID=%d - FAIL\n",DeviceID);
  279. PptAssertMsg("PptDeselectDevice - FAIL - port in unknown state",FALSE);
  280. Status = STATUS_UNSUCCESSFUL;
  281. }
  282. } else {
  283. // this is End-of-Chain device so no deselect neccessary
  284. DD((PCE)fdx,DDT,"PptDeselectDevice - End-of-Chain - SUCCESS\n",DeviceID);
  285. // check if requester wants to keep port or free port
  286. if( !(Command->CommandFlags & PAR_HAVE_PORT_KEEP_PORT) ) {
  287. PptFreePort( fdx );
  288. }
  289. Status = STATUS_SUCCESS;
  290. } // endif - Check if End Of Chain
  291. } // endif - Validate ID
  292. return Status;
  293. }
  294. ULONG
  295. Ppt1284_3AssignAddress(
  296. IN PFDO_EXTENSION DeviceExtension
  297. )
  298. /*++
  299. Routine Description:
  300. This routine initializes the 1284_3 bus.
  301. Arguments:
  302. DeviceExtension - Supplies Device Extension structure of the driver.
  303. Return Value:
  304. Number of 1284.3 devices out there at the given address.
  305. --*/
  306. {
  307. //UCHAR i, ii, value, newvalue, status;
  308. UCHAR i, value, newvalue, status;
  309. PUCHAR CurrentPort, CurrentStatus, CurrentControl;
  310. ULONG Delay = 5;
  311. UCHAR number = 0;
  312. BOOLEAN lastdevice = FALSE;
  313. UCHAR idx;
  314. CurrentPort = DeviceExtension->PortInfo.Controller;
  315. CurrentStatus = CurrentPort + 1;
  316. CurrentControl = CurrentPort + 2;
  317. // get current ctl reg
  318. value = P5ReadPortUchar( CurrentControl );
  319. // make sure 1284.3 devices do not get reseted
  320. newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
  321. // make sure we can write
  322. newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
  323. P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
  324. // bring nStrobe high
  325. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  326. // send first four bytes of the 1284.3 mode qualifier sequence out
  327. for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
  328. P5WritePortUchar( CurrentPort, ModeQualifier[i] );
  329. KeStallExecutionProcessor( Delay );
  330. }
  331. // check for correct status
  332. status = P5ReadPortUchar( CurrentStatus );
  333. if ( (status & (UCHAR)0xb8 )
  334. == ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
  335. // continue with fifth byte of mode qualifier
  336. P5WritePortUchar( CurrentPort, ModeQualifier[4] );
  337. KeStallExecutionProcessor( Delay );
  338. // check for correct status
  339. status = P5ReadPortUchar( CurrentStatus );
  340. // note busy is high too but is opposite so we see it as a low
  341. if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
  342. // continue with sixth byte
  343. P5WritePortUchar( CurrentPort, ModeQualifier[5] );
  344. KeStallExecutionProcessor( Delay );
  345. // check for correct status
  346. status = P5ReadPortUchar( CurrentStatus );
  347. // if status is valid there is a device out there responding
  348. if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
  349. // Device is out there
  350. KeStallExecutionProcessor( Delay );
  351. while ( number < 4 && !lastdevice ) {
  352. // Asssign address byte
  353. P5WritePortUchar( CurrentPort, number );
  354. number = (UCHAR)(number + 1);
  355. KeStallExecutionProcessor( Delay ); // wait a bit
  356. if ( (P5ReadPortUchar( CurrentStatus ) & (UCHAR)DSR_NOT_BUSY ) == 0 ) {
  357. // we saw last device
  358. lastdevice = TRUE;
  359. }
  360. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  361. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
  362. KeStallExecutionProcessor( Delay ); // wait a bit
  363. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  364. KeStallExecutionProcessor( Delay ); // wait a bit
  365. }
  366. // last byte
  367. P5WritePortUchar( CurrentPort, ModeQualifier[6] );
  368. if ( number ) {
  369. BOOLEAN bStlNon1284_3Found ;
  370. BOOLEAN bStlNon1284_3Valid ;
  371. bStlNon1284_3Found = PptCheckIfNon1284_3Present(DeviceExtension);
  372. bStlNon1284_3Valid = FALSE ;
  373. // as the earlier 1284 spec does not give the
  374. // lastdevice status is BSY, number needs to
  375. // be corrected in such cases
  376. for ( idx = 0 ; idx < number ; idx++ ) {
  377. if ( TRUE == PptCheckIfStl1284_3(DeviceExtension, idx, bStlNon1284_3Found ) ) {
  378. continue ;
  379. }
  380. if ( TRUE == bStlNon1284_3Found ) {
  381. if ( TRUE == PptCheckIfStlProductId(DeviceExtension, idx) ) {
  382. bStlNon1284_3Valid = TRUE ;
  383. continue ;
  384. }
  385. }
  386. break ;
  387. }
  388. if ( TRUE == bStlNon1284_3Valid ) {
  389. // we alter the count only if old adapters
  390. // are in the chain
  391. number = idx;
  392. }
  393. }
  394. } // Third status
  395. } // Second status
  396. } // First status
  397. P5WritePortUchar( CurrentControl, value ); // restore everything
  398. // returns last device ID + 1 or number of devices out there
  399. return ( (ULONG)number );
  400. }
  401. BOOLEAN
  402. PptCheckIfNon1284_3Present(
  403. IN PFDO_EXTENSION Extension
  404. )
  405. /*++
  406. Routine Description:
  407. Indicates whether one of the devices of the earlier
  408. specification is present in the chain.
  409. Arguments:
  410. Extension - Device Extension structure
  411. Return Value:
  412. TRUE : Atleast one of the adapters are of earlier spec.
  413. FALSE : None of the adapters of the earlier spec.
  414. --*/
  415. {
  416. BOOLEAN bReturnValue = FALSE ;
  417. UCHAR i, value, newvalue, status;
  418. ULONG Delay = 3;
  419. PUCHAR CurrentPort, CurrentStatus, CurrentControl;
  420. UCHAR ucAckStatus ;
  421. CurrentPort = Extension->PortInfo.Controller;
  422. CurrentStatus = CurrentPort + 1;
  423. CurrentControl = CurrentPort + 2;
  424. // get current ctl reg
  425. value = P5ReadPortUchar( CurrentControl );
  426. // make sure 1284.3 devices do not get reseted
  427. newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
  428. // make sure we can write
  429. newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
  430. P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
  431. // bring nStrobe high
  432. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  433. // send first four bytes of the 1284.3 mode qualifier sequence out
  434. for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
  435. P5WritePortUchar( CurrentPort, ModeQualifier[i] );
  436. KeStallExecutionProcessor( Delay );
  437. }
  438. // check for correct status
  439. status = P5ReadPortUchar( CurrentStatus );
  440. if ( (status & (UCHAR)0xb8 )
  441. == ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
  442. ucAckStatus = status & 0x40 ;
  443. // continue with fifth byte of mode qualifier
  444. P5WritePortUchar( CurrentPort, ModeQualifier[4] );
  445. KeStallExecutionProcessor( Delay );
  446. // check for correct status
  447. status = P5ReadPortUchar( CurrentStatus );
  448. // note busy is high too but is opposite so we see it as a low
  449. if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
  450. if ( ucAckStatus != ( status & 0x40 ) ) {
  451. // save current ack status
  452. ucAckStatus = status & 0x40 ;
  453. // continue with sixth byte
  454. P5WritePortUchar( CurrentPort, ModeQualifier[5] );
  455. KeStallExecutionProcessor( Delay );
  456. // check for correct status
  457. status = P5ReadPortUchar( CurrentStatus );
  458. // if status is valid there is a device out there responding
  459. if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
  460. bReturnValue = TRUE ;
  461. } // Third status
  462. } // ack of earlier adapters not seen
  463. // last byte
  464. P5WritePortUchar( CurrentPort, ModeQualifier[6] );
  465. } // Second status
  466. } // First status
  467. P5WritePortUchar( CurrentControl, value ); // restore everything
  468. return bReturnValue ;
  469. } // PptCheckIfNon1284_3Present
  470. // Define 1284 Commands
  471. #define CPP_QUERY_PRODID 0x10
  472. // 1284 related SHTL prod id equates
  473. #define SHTL_EPAT_PRODID 0xAAFF
  474. #define SHTL_EPST_PRODID 0xA8FF
  475. BOOLEAN
  476. PptCheckIfStl1284_3(
  477. IN PFDO_EXTENSION DeviceExtension,
  478. IN ULONG ulDaisyIndex,
  479. IN BOOLEAN bNoStrobe
  480. )
  481. /*++
  482. Routine Description:
  483. This function checks to see whether the device indicated
  484. is a Shuttle 1284_3 type of device.
  485. Arguments:
  486. Extension - Device extension structure.
  487. ulDaisyIndex - The daisy chain id of the device that
  488. this function will check on.
  489. bNoStrobe - If set, indicates that the query
  490. Ep1284 command issued by this function
  491. need not assert strobe to latch the
  492. command.
  493. Return Value:
  494. TRUE - Yes. Device is Shuttle 1284_3 type of device.
  495. FALSE - No. This may mean that this device is either
  496. non-shuttle or Shuttle non-1284_3 type of
  497. device.
  498. --*/
  499. {
  500. BOOLEAN bReturnValue = FALSE ;
  501. UCHAR i, value, newvalue, status;
  502. ULONG Delay = 3;
  503. UCHAR ucExpectedPattern ;
  504. UCHAR ucReadValue, ucReadPattern;
  505. PUCHAR CurrentPort, CurrentStatus, CurrentControl;
  506. CurrentPort = DeviceExtension->PortInfo.Controller;
  507. CurrentStatus = CurrentPort + 1;
  508. CurrentControl = CurrentPort + 2;
  509. // get current ctl reg
  510. value = P5ReadPortUchar( CurrentControl );
  511. // make sure 1284.3 devices do not get reseted
  512. newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
  513. // make sure we can write
  514. newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
  515. P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
  516. // bring nStrobe high
  517. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  518. // send first four bytes of the 1284.3 mode qualifier sequence out
  519. for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
  520. P5WritePortUchar( CurrentPort, ModeQualifier[i] );
  521. KeStallExecutionProcessor( Delay );
  522. }
  523. // check for correct status
  524. status = P5ReadPortUchar( CurrentStatus );
  525. if ( (status & (UCHAR)0xb8 )
  526. == ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
  527. // continue with fifth byte of mode qualifier
  528. P5WritePortUchar( CurrentPort, ModeQualifier[4] );
  529. KeStallExecutionProcessor( Delay );
  530. // check for correct status
  531. status = P5ReadPortUchar( CurrentStatus );
  532. // note busy is high too but is opposite so we see it as a low
  533. if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
  534. // continue with sixth byte
  535. P5WritePortUchar( CurrentPort, ModeQualifier[5] );
  536. KeStallExecutionProcessor( Delay );
  537. // check for correct status
  538. status = P5ReadPortUchar( CurrentStatus );
  539. // if status is valid there is a device out there responding
  540. if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
  541. // Device is out there
  542. KeStallExecutionProcessor( Delay );
  543. // issue shuttle specific CPP command
  544. P5WritePortUchar( CurrentPort, (UCHAR) ( 0x88 | ulDaisyIndex ) );
  545. KeStallExecutionProcessor( Delay ); // wait a bit
  546. if ( ulDaisyIndex && ( bNoStrobe == FALSE ) ) {
  547. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  548. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
  549. KeStallExecutionProcessor( Delay ); // wait a bit
  550. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  551. KeStallExecutionProcessor( Delay ); // wait a bit
  552. }
  553. ucExpectedPattern = 0xF0 ;
  554. bReturnValue = TRUE ;
  555. while ( ucExpectedPattern ) {
  556. KeStallExecutionProcessor( Delay ); // wait a bit
  557. P5WritePortUchar( CurrentPort, (UCHAR) (0x80 | ulDaisyIndex )) ;
  558. KeStallExecutionProcessor( Delay ); // wait a bit
  559. P5WritePortUchar( CurrentPort, (UCHAR) (0x88 | ulDaisyIndex )) ;
  560. KeStallExecutionProcessor( Delay ); // wait a bit
  561. ucReadValue = P5ReadPortUchar( CurrentStatus ) ;
  562. ucReadPattern = ( ucReadValue << 1 ) & 0x70 ;
  563. ucReadPattern |= ( ucReadValue & 0x80 ) ;
  564. if ( ucReadPattern != ucExpectedPattern ) {
  565. // not Shuttle 1284_3 behaviour
  566. bReturnValue = FALSE ;
  567. break ;
  568. }
  569. ucExpectedPattern -= 0x10 ;
  570. }
  571. // last byte
  572. P5WritePortUchar( CurrentPort, ModeQualifier[6] );
  573. } // Third status
  574. } // Second status
  575. } // First status
  576. P5WritePortUchar( CurrentControl, value ); // restore everything
  577. return bReturnValue ;
  578. } // end PptCheckIfStl1284_3()
  579. BOOLEAN
  580. PptCheckIfStlProductId(
  581. IN PFDO_EXTENSION DeviceExtension,
  582. IN ULONG ulDaisyIndex
  583. )
  584. /*++
  585. Routine Description:
  586. This function checks to see whether the device indicated
  587. is a Shuttle non-1284_3 type of device.
  588. Arguments:
  589. Extension - Device extension structure.
  590. ulDaisyIndex - The daisy chain id of the device that
  591. this function will check on.
  592. Return Value:
  593. TRUE - Yes. Device is Shuttle non-1284_3 type of device.
  594. FALSE - No. This may mean that this device is
  595. non-shuttle.
  596. --*/
  597. {
  598. BOOLEAN bReturnValue = FALSE ;
  599. UCHAR i, value, newvalue, status;
  600. ULONG Delay = 3;
  601. UCHAR ucProdIdHiByteHiNibble, ucProdIdHiByteLoNibble ;
  602. UCHAR ucProdIdLoByteHiNibble, ucProdIdLoByteLoNibble ;
  603. UCHAR ucProdIdHiByte, ucProdIdLoByte ;
  604. USHORT usProdId ;
  605. PUCHAR CurrentPort, CurrentStatus, CurrentControl;
  606. CurrentPort = DeviceExtension->PortInfo.Controller;
  607. CurrentStatus = CurrentPort + 1;
  608. CurrentControl = CurrentPort + 2;
  609. // get current ctl reg
  610. value = P5ReadPortUchar( CurrentControl );
  611. // make sure 1284.3 devices do not get reseted
  612. newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
  613. // make sure we can write
  614. newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
  615. P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
  616. // bring nStrobe high
  617. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  618. // send first four bytes of the 1284.3 mode qualifier sequence out
  619. for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
  620. P5WritePortUchar( CurrentPort, ModeQualifier[i] );
  621. KeStallExecutionProcessor( Delay );
  622. }
  623. // check for correct status
  624. status = P5ReadPortUchar( CurrentStatus );
  625. if ( (status & (UCHAR)0xb8 )
  626. == ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
  627. // continue with fifth byte of mode qualifier
  628. P5WritePortUchar( CurrentPort, ModeQualifier[4] );
  629. KeStallExecutionProcessor( Delay );
  630. // check for correct status
  631. status = P5ReadPortUchar( CurrentStatus );
  632. // note busy is high too but is opposite so we see it as a low
  633. if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
  634. // continue with sixth byte
  635. P5WritePortUchar( CurrentPort, ModeQualifier[5] );
  636. KeStallExecutionProcessor( Delay );
  637. // check for correct status
  638. status = P5ReadPortUchar( CurrentStatus );
  639. // if status is valid there is a device out there responding
  640. if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
  641. P5WritePortUchar ( CurrentPort, (UCHAR) (CPP_QUERY_PRODID | ulDaisyIndex )) ;
  642. KeStallExecutionProcessor( Delay );
  643. // Device is out there
  644. KeStallExecutionProcessor( Delay );
  645. ucProdIdLoByteHiNibble = P5ReadPortUchar( CurrentStatus ) ;
  646. ucProdIdLoByteHiNibble &= 0xF0 ;
  647. KeStallExecutionProcessor( Delay );
  648. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  649. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
  650. KeStallExecutionProcessor( Delay ); // wait a bit
  651. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  652. KeStallExecutionProcessor( Delay ); // wait a bit
  653. ucProdIdLoByteLoNibble = P5ReadPortUchar( CurrentStatus ) ;
  654. ucProdIdLoByteLoNibble >>= 4 ;
  655. ucProdIdLoByte = ucProdIdLoByteHiNibble | ucProdIdLoByteLoNibble ;
  656. KeStallExecutionProcessor( Delay );
  657. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  658. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
  659. KeStallExecutionProcessor( Delay ); // wait a bit
  660. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  661. KeStallExecutionProcessor( Delay ); // wait a bit
  662. ucProdIdHiByteHiNibble = P5ReadPortUchar( CurrentStatus ) ;
  663. ucProdIdHiByteHiNibble &= 0xF0 ;
  664. KeStallExecutionProcessor( Delay );
  665. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  666. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
  667. KeStallExecutionProcessor( Delay ); // wait a bit
  668. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  669. KeStallExecutionProcessor( Delay ); // wait a bit
  670. ucProdIdHiByteLoNibble = P5ReadPortUchar( CurrentStatus ) ;
  671. ucProdIdHiByteLoNibble >>= 4 ;
  672. ucProdIdHiByte = ucProdIdHiByteHiNibble | ucProdIdHiByteLoNibble ;
  673. // issue the last strobe
  674. KeStallExecutionProcessor( Delay );
  675. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  676. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
  677. KeStallExecutionProcessor( Delay ); // wait a bit
  678. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  679. KeStallExecutionProcessor( Delay ); // wait a bit
  680. usProdId = ( ucProdIdHiByte << 8 ) | ucProdIdLoByte ;
  681. if ( ( SHTL_EPAT_PRODID == usProdId ) ||\
  682. ( SHTL_EPST_PRODID == usProdId ) ) {
  683. // one of the devices that conform to the earlier
  684. // draft is found
  685. bReturnValue = TRUE ;
  686. }
  687. // last byte
  688. P5WritePortUchar( CurrentPort, ModeQualifier[6] );
  689. } // Third status
  690. } // Second status
  691. } // First status
  692. P5WritePortUchar( CurrentControl, value ); // restore everything
  693. return bReturnValue ;
  694. } // end PptCheckIfStlProductId()
  695. BOOLEAN
  696. PptSend1284_3Command(
  697. IN PUCHAR CurrentPort,
  698. IN UCHAR Command
  699. )
  700. /*++
  701. Routine Description:
  702. This routine sends the 1284_3 Command given to it
  703. down the parallel bus.
  704. Arguments:
  705. Return Value:
  706. None.
  707. --*/
  708. {
  709. UCHAR i, value, newvalue, test;//, status;
  710. ULONG ii;
  711. PUCHAR CurrentStatus, CurrentControl;
  712. ULONG Delay = 3;
  713. BOOLEAN success = FALSE;
  714. CurrentStatus = CurrentPort + 1;
  715. CurrentControl = CurrentPort + 2;
  716. // Get Upper 4 bits to see what Command it is
  717. test = (UCHAR)(Command & (UCHAR)CPP_COMMAND_FILTER);
  718. // get current ctl reg
  719. value = P5ReadPortUchar( CurrentControl );
  720. // make sure 1284.3 devices do not get reseted
  721. newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
  722. // make sure we can write
  723. newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
  724. P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
  725. // bring nStrobe high
  726. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
  727. KeStallExecutionProcessor( Delay );
  728. // send first four bytes of the 1284.3 mode qualifier sequence out
  729. for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
  730. P5WritePortUchar( CurrentPort, ModeQualifier[i] );
  731. KeStallExecutionProcessor( Delay );
  732. }
  733. // wait up to 5 us : Spec says about 2 but we will be lienient
  734. if (CHECK_DSR(CurrentPort, INACTIVE, DONT_CARE, ACTIVE, ACTIVE, ACTIVE, 5 )) {
  735. // continue with fifth byte of mode qualifier
  736. P5WritePortUchar( CurrentPort, ModeQualifier[4] );
  737. KeStallExecutionProcessor( Delay );
  738. // wait up to 5 us : Spec says about 2 but we will be lienient
  739. if (CHECK_DSR(CurrentPort, ACTIVE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE, 5 )) {
  740. // continue with sixth byte
  741. P5WritePortUchar( CurrentPort, ModeQualifier[5] );
  742. KeStallExecutionProcessor( Delay );
  743. // wait up to 5 us : Spec says about 2 but we will be lienient
  744. if (CHECK_DSR(CurrentPort, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, 5 )) {
  745. // Device is out there
  746. KeStallExecutionProcessor( Delay );
  747. // Command byte
  748. P5WritePortUchar( CurrentPort, Command );
  749. KeStallExecutionProcessor( Delay ); // wait a bit
  750. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  751. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
  752. KeStallExecutionProcessor( Delay ); // wait a bit
  753. // NOTE NOTE NOTE
  754. // Assertion of strobe to be done ONLY after checking for the
  755. // FAULT feedback, as per the 1284_3 specification.
  756. // Selection does not work correctly yet to be able to check for lines
  757. switch ( test ) {
  758. case CPP_SELECT:
  759. // Check to make sure we are selected
  760. // wait for upto 250 micro Secs for for selection time out.
  761. for ( ii = 25000; ii > 0; ii-- ) {
  762. if ( ( P5ReadPortUchar( CurrentStatus ) & DSR_NOT_FAULT ) == DSR_NOT_FAULT ) {
  763. // selection...
  764. success = TRUE;
  765. break;
  766. }
  767. }
  768. break;
  769. case CPP_DESELECT:
  770. // Check to make sure we are deselected
  771. // wait for upto 250 micro Secs for for deselection time out.
  772. for ( ii = 25000; ii > 0; ii-- ) {
  773. if ( (P5ReadPortUchar( CurrentStatus ) & DSR_NOT_FAULT) != DSR_NOT_FAULT ) {
  774. // deselection...
  775. success = TRUE;
  776. break;
  777. }
  778. }
  779. break;
  780. default :
  781. // there is a device out there and Command completed sucessfully
  782. KeStallExecutionProcessor( Delay ); // wait a bit
  783. success = TRUE;
  784. break;
  785. } // End Switch
  786. // NOTE NOTE NOTE
  787. // the strobe is de-asserted now and the command is completed here
  788. P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
  789. KeStallExecutionProcessor( Delay ); // wait a bit
  790. // last byte
  791. P5WritePortUchar( CurrentPort, ModeQualifier[6] );
  792. } // Third status
  793. } // Second status
  794. } // First status
  795. P5WritePortUchar( CurrentControl, value ); // restore everything
  796. // return TRUE if command succeeded, FALSE otherwise
  797. return success;
  798. }
  799. BOOLEAN
  800. ParSelectDevice(
  801. IN PPDO_EXTENSION Pdx,
  802. IN BOOLEAN HavePort
  803. )
  804. /*++
  805. Routine Description:
  806. This routine acquires the ParPort and selects a 1284.3 device
  807. Arguments:
  808. Pdx - Supplies the device extension.
  809. HavePort - TRUE indicates that caller has already acquired port
  810. so we should only do a SELECT_DEVICE
  811. - FALSE indicates that caller has not already acquired port
  812. so we should do a combination ACQUIRE_PORT/SELECT_DEVICE
  813. Return Value:
  814. TRUE - success - the device was selected (and port acquired if needed)
  815. FALSE - failure
  816. --*/
  817. {
  818. NTSTATUS status;
  819. PDEVICE_OBJECT pPortDeviceObject;
  820. PARALLEL_1284_COMMAND par1284Command;
  821. LARGE_INTEGER timeOut;
  822. enum _PdoType pdoType;
  823. //
  824. // Initialize command structure and extract parameters from the DeviceExtension
  825. //
  826. // reserved - always set to 0
  827. par1284Command.Port = 0;
  828. if( HavePort ) {
  829. par1284Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
  830. } else {
  831. par1284Command.CommandFlags = 0;
  832. }
  833. pdoType = Pdx->PdoType;
  834. switch( pdoType ) {
  835. case PdoTypeRawPort:
  836. case PdoTypeEndOfChain:
  837. par1284Command.ID = 0; // ignored, but set anyway
  838. par1284Command.CommandFlags |= PAR_END_OF_CHAIN_DEVICE;
  839. break;
  840. case PdoTypeLegacyZip:
  841. par1284Command.ID = DOT3_LEGACY_ZIP_ID;
  842. break;
  843. case PdoTypeDaisyChain:
  844. par1284Command.ID = Pdx->Ieee1284_3DeviceId;
  845. break;
  846. default:
  847. DD((PCE)Pdx,DDE,"Invalid pdoType = %x\n",pdoType);
  848. PptAssert(FALSE);
  849. break;
  850. }
  851. pPortDeviceObject = Pdx->PortDeviceObject;
  852. //
  853. // Send the request
  854. //
  855. timeOut.QuadPart = -(10*1000*500); // 500ms ( 100ns units )
  856. status = ParBuildSendInternalIoctl(IOCTL_INTERNAL_SELECT_DEVICE,
  857. pPortDeviceObject,
  858. &par1284Command, sizeof(PARALLEL_1284_COMMAND),
  859. NULL, 0,
  860. &timeOut);
  861. if( NT_SUCCESS( status ) ) {
  862. // SELECT succeeded
  863. DD((PCE)Pdx,DDT,"ParSelectDevice - SUCCESS\n");
  864. if( !HavePort ) {
  865. // note in the device extension that we have the port
  866. Pdx->bAllocated = TRUE;
  867. }
  868. return TRUE;
  869. } else {
  870. // SELECT failed
  871. DD((PCE)Pdx,DDT,"ParSelectDevice - FAIL\n");
  872. return FALSE;
  873. }
  874. }
  875. BOOLEAN
  876. ParDeselectDevice(
  877. IN PPDO_EXTENSION Pdx,
  878. IN BOOLEAN KeepPort
  879. )
  880. /*++
  881. Routine Description:
  882. This routine deselects a 1284.3 or Legacy Zip device and optionally
  883. releases the ParPort
  884. Arguments:
  885. Pdx - Supplies the device extension.
  886. KeepPort - TRUE indicates that we should keep the port acquired,
  887. so we should only do a DESELECT_DEVICE
  888. - FALSE indicates that we should not keep the port acquired,
  889. so we should do a combination DESELECT_DEVICE/FREE_PORT
  890. Return Value:
  891. TRUE - The device was deselected (and the port released if requested)
  892. --*/
  893. {
  894. PARALLEL_1284_COMMAND par1284Command;
  895. NTSTATUS status;
  896. enum _PdoType pdoType;
  897. PDEVICE_OBJECT fdo = Pdx->Fdo;
  898. PFDO_EXTENSION fdx = fdo->DeviceExtension;
  899. //
  900. // If we don't have the port, succeed and return
  901. //
  902. if( !Pdx->bAllocated ) {
  903. DD((PCE)Pdx,DDW,"ParDeselectDevice - we do not have the port\n");
  904. return TRUE;
  905. }
  906. //
  907. // Initialize command structure and extract parameters from the DeviceExtension
  908. //
  909. // reserved - always set to 0
  910. par1284Command.Port = 0;
  911. if( KeepPort ) {
  912. par1284Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
  913. } else {
  914. par1284Command.CommandFlags = 0;
  915. }
  916. pdoType = Pdx->PdoType;
  917. switch( pdoType ) {
  918. case PdoTypeRawPort:
  919. case PdoTypeEndOfChain:
  920. par1284Command.ID = 0; // ignored, but set anyway
  921. par1284Command.CommandFlags |= PAR_END_OF_CHAIN_DEVICE;
  922. break;
  923. case PdoTypeLegacyZip:
  924. par1284Command.ID = DOT3_LEGACY_ZIP_ID;
  925. break;
  926. case PdoTypeDaisyChain:
  927. par1284Command.ID = Pdx->Ieee1284_3DeviceId;
  928. break;
  929. default:
  930. DD((PCE)Pdx,DDE,"Invalid pdoType = %x\n",pdoType);
  931. par1284Command.ID = 0; // choose a 1284.3 type deselect since this is harmless
  932. PptAssert(FALSE);
  933. break;
  934. }
  935. status = PptDeselectDevice( fdx, &par1284Command );
  936. if( status != STATUS_SUCCESS ) {
  937. // DESELECT failed?!? - there isn't anything that we can do
  938. DD((PCE)Pdx,DDE,"ParDeselectDevice - FAILED - nothing we can do - status=%x\n", status);
  939. } else {
  940. DD((PCE)Pdx,DDT,"ParDeselectDevice - SUCCESS\n", status);
  941. }
  942. if( !KeepPort ) {
  943. // note in the device extension that we gave up the port
  944. DD((PCE)Pdx,DDT,"ParDeselectDevice - gave up port\n");
  945. Pdx->bAllocated = FALSE;
  946. }
  947. return TRUE;
  948. }