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.

804 lines
22 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. spp.c
  5. Abstract:
  6. This module contains the code for standard parallel ports
  7. (centronics mode).
  8. Author:
  9. Anthony V. Ercolano 1-Aug-1992
  10. Norbert P. Kusters 22-Oct-1993
  11. Environment:
  12. Kernel mode
  13. Revision History :
  14. --*/
  15. #include "pch.h"
  16. ULONG
  17. SppWriteLoopPI(
  18. IN PUCHAR Controller,
  19. IN PUCHAR WriteBuffer,
  20. IN ULONG NumBytesToWrite,
  21. IN ULONG BusyDelay
  22. );
  23. ULONG
  24. SppCheckBusyDelay(
  25. IN PPDO_EXTENSION Pdx,
  26. IN PUCHAR WriteBuffer,
  27. IN ULONG NumBytesToWrite
  28. );
  29. NTSTATUS
  30. ParEnterSppMode(
  31. IN PPDO_EXTENSION Pdx,
  32. IN BOOLEAN DeviceIdRequest
  33. )
  34. {
  35. UNREFERENCED_PARAMETER( DeviceIdRequest );
  36. DD((PCE)Pdx,DDT,"ParEnterSppMode: Enter!\n");
  37. P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
  38. Pdx->Connected = TRUE;
  39. return STATUS_SUCCESS;
  40. }
  41. ULONG
  42. SppWriteLoopPI(
  43. IN PUCHAR Controller,
  44. IN PUCHAR WriteBuffer,
  45. IN ULONG NumBytesToWrite,
  46. IN ULONG BusyDelay
  47. )
  48. /*++
  49. Routine Description:
  50. This routine outputs the given write buffer to the parallel port
  51. using the standard centronics protocol.
  52. Arguments:
  53. Controller - Supplies the base address of the parallel port.
  54. WriteBuffer - Supplies the buffer to write to the port.
  55. NumBytesToWrite - Supplies the number of bytes to write out to the port.
  56. BusyDelay - Supplies the number of microseconds to delay before
  57. checking the busy bit.
  58. Return Value:
  59. The number of bytes successfully written out to the parallel port.
  60. --*/
  61. {
  62. ULONG i;
  63. UCHAR DeviceStatus;
  64. BOOLEAN atPassiveIrql = FALSE;
  65. if( KeGetCurrentIrql() == PASSIVE_LEVEL ) {
  66. atPassiveIrql = TRUE;
  67. }
  68. if (!BusyDelay) {
  69. BusyDelay = 1;
  70. }
  71. for (i = 0; i < NumBytesToWrite; i++) {
  72. DeviceStatus = GetStatus(Controller);
  73. if (PAR_ONLINE(DeviceStatus)) {
  74. //
  75. // Anytime we write out a character we will restart
  76. // the count down timer.
  77. //
  78. P5WritePortUchar(Controller + PARALLEL_DATA_OFFSET, *WriteBuffer++);
  79. KeStallExecutionProcessor(1);
  80. StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
  81. PAR_CONTROL_SLIN |
  82. PAR_CONTROL_NOT_INIT |
  83. PAR_CONTROL_STROBE));
  84. KeStallExecutionProcessor(1);
  85. StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
  86. PAR_CONTROL_SLIN |
  87. PAR_CONTROL_NOT_INIT));
  88. KeStallExecutionProcessor(BusyDelay);
  89. } else {
  90. DD(NULL,DDT,"spp::SppWriteLoopPI - DeviceStatus = %x - NOT ONLINE\n", DeviceStatus);
  91. break;
  92. }
  93. }
  94. DD(NULL,DDT,"SppWriteLoopPI - exit - bytes written = %ld\n",i);
  95. return i;
  96. }
  97. ULONG
  98. SppCheckBusyDelay(
  99. IN PPDO_EXTENSION Pdx,
  100. IN PUCHAR WriteBuffer,
  101. IN ULONG NumBytesToWrite
  102. )
  103. /*++
  104. Routine Description:
  105. This routine determines if the current busy delay setting is
  106. adequate for this printer.
  107. Arguments:
  108. Pdx - Supplies the device extension.
  109. WriteBuffer - Supplies the write buffer.
  110. NumBytesToWrite - Supplies the size of the write buffer.
  111. Return Value:
  112. The number of bytes strobed out to the printer.
  113. --*/
  114. {
  115. PUCHAR Controller;
  116. ULONG BusyDelay;
  117. LARGE_INTEGER Start;
  118. LARGE_INTEGER PerfFreq;
  119. LARGE_INTEGER End;
  120. LARGE_INTEGER GetStatusTime;
  121. LARGE_INTEGER CallOverhead;
  122. UCHAR DeviceStatus;
  123. ULONG i;
  124. ULONG NumberOfCalls;
  125. ULONG maxTries;
  126. KIRQL OldIrql = PASSIVE_LEVEL;
  127. UNREFERENCED_PARAMETER( NumBytesToWrite );
  128. Controller = Pdx->Controller;
  129. BusyDelay = Pdx->BusyDelay;
  130. // If the current busy delay value is 10 or greater then something
  131. // is weird and settle for 10.
  132. if (Pdx->BusyDelay >= 10) {
  133. Pdx->BusyDelayDetermined = TRUE;
  134. return 0;
  135. }
  136. // Take some performance measurements.
  137. if (0 == SppNoRaiseIrql)
  138. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  139. Start = KeQueryPerformanceCounter(&PerfFreq);
  140. DeviceStatus = GetStatus(Controller);
  141. End = KeQueryPerformanceCounter(&PerfFreq);
  142. GetStatusTime.QuadPart = End.QuadPart - Start.QuadPart;
  143. Start = KeQueryPerformanceCounter(&PerfFreq);
  144. End = KeQueryPerformanceCounter(&PerfFreq);
  145. if (0 == SppNoRaiseIrql)
  146. KeLowerIrql(OldIrql);
  147. CallOverhead.QuadPart = End.QuadPart - Start.QuadPart;
  148. GetStatusTime.QuadPart -= CallOverhead.QuadPart;
  149. if (GetStatusTime.QuadPart <= 0) {
  150. GetStatusTime.QuadPart = 1;
  151. }
  152. // Figure out how many calls to 'GetStatus' can be made in 20 us.
  153. NumberOfCalls = (ULONG) (PerfFreq.QuadPart*20/GetStatusTime.QuadPart/1000000) + 1;
  154. //
  155. // - check to make sure the device is ready to receive a byte before we start clocking
  156. // data out
  157. //
  158. // DVDF - 25Jan99 - added check
  159. //
  160. //
  161. // - nothing magic about 25 - just catch the case where NumberOfCalls may be bogus
  162. // and try something reasonable - empirically NumberOfCalls has ranged from 8-24
  163. //
  164. maxTries = (NumberOfCalls > 25) ? 25 : NumberOfCalls;
  165. for( i = 0 ; i < maxTries ; i++ ) {
  166. // spin for slow device to get ready to receive data - roughly 20us max
  167. DeviceStatus = GetStatus( Controller );
  168. if( PAR_ONLINE( DeviceStatus ) ) {
  169. // break out of loop as soon as device is ready
  170. break;
  171. }
  172. }
  173. if( !PAR_ONLINE( DeviceStatus ) ) {
  174. // device is still not online - bail out
  175. return 0;
  176. }
  177. // The printer is ready to accept a byte. Strobe one out
  178. // and check out the reaction time for BUSY.
  179. if (BusyDelay) {
  180. if (0 == SppNoRaiseIrql)
  181. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  182. P5WritePortUchar(Controller + PARALLEL_DATA_OFFSET, *WriteBuffer++);
  183. KeStallExecutionProcessor(1);
  184. StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
  185. PAR_CONTROL_SLIN |
  186. PAR_CONTROL_NOT_INIT |
  187. PAR_CONTROL_STROBE));
  188. KeStallExecutionProcessor(1);
  189. StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
  190. PAR_CONTROL_SLIN |
  191. PAR_CONTROL_NOT_INIT));
  192. KeStallExecutionProcessor(BusyDelay);
  193. for (i = 0; i < NumberOfCalls; i++) {
  194. DeviceStatus = GetStatus(Controller);
  195. if (!(DeviceStatus & PAR_STATUS_NOT_BUSY)) {
  196. break;
  197. }
  198. }
  199. if (0 == SppNoRaiseIrql)
  200. KeLowerIrql(OldIrql);
  201. } else {
  202. if (0 == SppNoRaiseIrql)
  203. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  204. P5WritePortUchar(Controller + PARALLEL_DATA_OFFSET, *WriteBuffer++);
  205. KeStallExecutionProcessor(1);
  206. StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
  207. PAR_CONTROL_SLIN |
  208. PAR_CONTROL_NOT_INIT |
  209. PAR_CONTROL_STROBE));
  210. KeStallExecutionProcessor(1);
  211. StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
  212. PAR_CONTROL_SLIN |
  213. PAR_CONTROL_NOT_INIT));
  214. for (i = 0; i < NumberOfCalls; i++) {
  215. DeviceStatus = GetStatus(Controller);
  216. if (!(DeviceStatus & PAR_STATUS_NOT_BUSY)) {
  217. break;
  218. }
  219. }
  220. if (0 == SppNoRaiseIrql)
  221. KeLowerIrql(OldIrql);
  222. }
  223. if (i == 0) {
  224. // In this case the BUSY was set as soon as we checked it.
  225. // Use this busyDelay with the PI code.
  226. Pdx->UsePIWriteLoop = TRUE;
  227. Pdx->BusyDelayDetermined = TRUE;
  228. } else if (i == NumberOfCalls) {
  229. // In this case the BUSY was never seen. This is a very fast
  230. // printer so use the fastest code possible.
  231. Pdx->BusyDelayDetermined = TRUE;
  232. } else {
  233. // The test failed. The lines showed not BUSY and then BUSY
  234. // without strobing a byte in between.
  235. Pdx->UsePIWriteLoop = TRUE;
  236. Pdx->BusyDelay++;
  237. }
  238. return 1;
  239. }
  240. NTSTATUS
  241. SppWrite(
  242. IN PPDO_EXTENSION Pdx,
  243. IN PVOID Buffer,
  244. IN ULONG BytesToWrite,
  245. OUT PULONG BytesTransferred
  246. )
  247. /*++
  248. Routine Description:
  249. Arguments:
  250. Pdx - Supplies the device extension.
  251. Return Value:
  252. None.
  253. --*/
  254. {
  255. NTSTATUS status;
  256. UCHAR DeviceStatus;
  257. ULONG TimerStart;
  258. LONG CountDown;
  259. PUCHAR IrpBuffer;
  260. LARGE_INTEGER StartOfSpin;
  261. LARGE_INTEGER NextQuery;
  262. LARGE_INTEGER Difference;
  263. BOOLEAN DoDelays;
  264. BOOLEAN PortFree;
  265. ULONG NumBytesWritten;
  266. ULONG LoopNumber;
  267. ULONG NumberOfBusyChecks;
  268. ULONG MaxBusyDelay;
  269. ULONG MaxBytes;
  270. DD((PCE)Pdx,DDT,"SppWrite - enter, BytesToWrite = %d\n",BytesToWrite);
  271. *BytesTransferred = 0; // initialize to none
  272. IrpBuffer = (PUCHAR)Buffer;
  273. MaxBytes = BytesToWrite;
  274. TimerStart = Pdx->TimerStart;
  275. CountDown = (LONG)TimerStart;
  276. NumberOfBusyChecks = 9;
  277. MaxBusyDelay = 0;
  278. // Turn off the strobe in case it was left on by some other device sharing the port.
  279. StoreControl(Pdx->Controller, (PAR_CONTROL_WR_CONTROL |
  280. PAR_CONTROL_SLIN |
  281. PAR_CONTROL_NOT_INIT));
  282. PushSomeBytes:
  283. //
  284. // While we are strobing data we don't want to get context
  285. // switched away. Raise up to dispatch level to prevent that.
  286. //
  287. // The reason we can't afford the context switch is that
  288. // the device can't have the data strobe line on for more
  289. // than 500 microseconds.
  290. //
  291. // We never want to be at raised irql form more than
  292. // 200 microseconds, so we will do no more than 100
  293. // bytes at a time.
  294. //
  295. LoopNumber = 512;
  296. if (LoopNumber > BytesToWrite) {
  297. LoopNumber = BytesToWrite;
  298. }
  299. //
  300. // Enter the write loop
  301. //
  302. if (!Pdx->BusyDelayDetermined) {
  303. DD((PCE)Pdx,DDT,"SppWrite: Calling SppCheckBusyDelay\n");
  304. NumBytesWritten = SppCheckBusyDelay(Pdx, IrpBuffer, LoopNumber);
  305. if (Pdx->BusyDelayDetermined) {
  306. if (Pdx->BusyDelay > MaxBusyDelay) {
  307. MaxBusyDelay = Pdx->BusyDelay;
  308. NumberOfBusyChecks = 10;
  309. }
  310. if (NumberOfBusyChecks) {
  311. NumberOfBusyChecks--;
  312. Pdx->BusyDelayDetermined = FALSE;
  313. } else {
  314. Pdx->BusyDelay = MaxBusyDelay + 1;
  315. }
  316. }
  317. } else if( Pdx->UsePIWriteLoop ) {
  318. NumBytesWritten = SppWriteLoopPI( Pdx->Controller, IrpBuffer, LoopNumber, Pdx->BusyDelay );
  319. } else {
  320. NumBytesWritten = SppWriteLoopPI( Pdx->Controller, IrpBuffer, LoopNumber, 1 );
  321. }
  322. if (NumBytesWritten) {
  323. CountDown = TimerStart;
  324. IrpBuffer += NumBytesWritten;
  325. BytesToWrite -= NumBytesWritten;
  326. }
  327. //
  328. // Check to see if the io is done. If it is then call the
  329. // code to complete the request.
  330. //
  331. if (!BytesToWrite) {
  332. *BytesTransferred = MaxBytes;
  333. status = STATUS_SUCCESS;
  334. goto returnTarget;
  335. } else if ((Pdx->CurrentOpIrp)->Cancel) {
  336. //
  337. // See if the IO has been canceled. The cancel routine
  338. // has been removed already (when this became the
  339. // current irp). Simply check the bit. We don't even
  340. // need to capture the lock. If we miss a round
  341. // it won't be that bad.
  342. //
  343. *BytesTransferred = MaxBytes - BytesToWrite;
  344. status = STATUS_CANCELLED;
  345. goto returnTarget;
  346. } else {
  347. //
  348. // We've taken care of the reasons that the irp "itself"
  349. // might want to be completed.
  350. // printer to see if it is in a state that might
  351. // cause us to complete the irp.
  352. //
  353. // First let's check if the device status is
  354. // ok and online. If it is then simply go back
  355. // to the byte pusher.
  356. //
  357. DeviceStatus = GetStatus(Pdx->Controller);
  358. if (PAR_ONLINE(DeviceStatus)) {
  359. goto PushSomeBytes;
  360. }
  361. //
  362. // Perhaps the operator took the device off line,
  363. // or forgot to put in enough paper. If so, then
  364. // let's hang out here for the until the timeout
  365. // period has expired waiting for them to make things
  366. // all better.
  367. //
  368. if (PAR_PAPER_EMPTY(DeviceStatus) ||
  369. PAR_OFF_LINE(DeviceStatus)) {
  370. if (CountDown > 0) {
  371. //
  372. // We'll wait 1 second increments.
  373. //
  374. DD((PCE)Pdx,DDT,"decrementing countdown for PAPER_EMPTY/OFF_LINE - countDown: %d status: 0x%x\n", CountDown, DeviceStatus);
  375. CountDown--;
  376. // If anyone is waiting for the port then let them have it,
  377. // since the printer is busy.
  378. ParFreePort(Pdx);
  379. KeDelayExecutionThread(
  380. KernelMode,
  381. FALSE,
  382. &Pdx->OneSecond
  383. );
  384. if (!ParAllocPort(Pdx)) {
  385. *BytesTransferred = MaxBytes - BytesToWrite;
  386. DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_BUSY\n");
  387. status = STATUS_DEVICE_BUSY;
  388. goto returnTarget;
  389. }
  390. goto PushSomeBytes;
  391. } else {
  392. //
  393. // Timer has expired. Complete the request.
  394. //
  395. *BytesTransferred = MaxBytes - BytesToWrite;
  396. DD((PCE)Pdx,DDT,"In SppWrite(...): Timer expired - DeviceStatus = %08x\n", DeviceStatus);
  397. if (PAR_OFF_LINE(DeviceStatus)) {
  398. DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_OFF_LINE\n");
  399. status = STATUS_DEVICE_OFF_LINE;
  400. goto returnTarget;
  401. } else if (PAR_NO_CABLE(DeviceStatus)) {
  402. DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_NOT_CONNECTED\n");
  403. status = STATUS_DEVICE_NOT_CONNECTED;
  404. goto returnTarget;
  405. } else {
  406. DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_PAPER_EMPTY\n");
  407. status = STATUS_DEVICE_PAPER_EMPTY;
  408. goto returnTarget;
  409. }
  410. }
  411. } else if (PAR_POWERED_OFF(DeviceStatus) ||
  412. PAR_NOT_CONNECTED(DeviceStatus) ||
  413. PAR_NO_CABLE(DeviceStatus)) {
  414. //
  415. // We are in a "bad" state. Is what
  416. // happened to the printer (power off, not connected, or
  417. // the cable being pulled) something that will require us
  418. // to reinitialize the printer? If we need to
  419. // reinitialize the printer then we should complete
  420. // this IO so that the driving application can
  421. // choose what is the best thing to do about it's
  422. // io.
  423. //
  424. DD((PCE)Pdx,DDT,"In SppWrite(...): \"bad\" state - need to reinitialize printer?");
  425. *BytesTransferred = MaxBytes - BytesToWrite;
  426. if (PAR_POWERED_OFF(DeviceStatus)) {
  427. DD((PCE)Pdx,DDT,"SppWrite: returning STATUS_DEVICE_POWERED_OFF\n");
  428. status = STATUS_DEVICE_POWERED_OFF;
  429. goto returnTarget;
  430. } else if (PAR_NOT_CONNECTED(DeviceStatus) ||
  431. PAR_NO_CABLE(DeviceStatus)) {
  432. DD((PCE)Pdx,DDT,"SppWrite: STATUS_DEVICE_NOT_CONNECTED\n");
  433. status = STATUS_DEVICE_NOT_CONNECTED;
  434. goto returnTarget;
  435. }
  436. }
  437. //
  438. // The device could simply be busy at this point. Simply spin
  439. // here waiting for the device to be in a state that we
  440. // care about.
  441. //
  442. // As we spin, get the system ticks. Every time that it looks
  443. // like a second has passed, decrement the countdown. If
  444. // it ever goes to zero, then timeout the request.
  445. //
  446. KeQueryTickCount(&StartOfSpin);
  447. DoDelays = FALSE;
  448. do {
  449. //
  450. // After about a second of spinning, let the rest of the
  451. // machine have time for a second.
  452. //
  453. if (DoDelays) {
  454. ParFreePort(Pdx);
  455. PortFree = TRUE;
  456. DD((PCE)Pdx,DDT,"Before delay thread of one second, dsr=%x DCR[%x]\n",
  457. P5ReadPortUchar(Pdx->Controller + OFFSET_DSR),
  458. P5ReadPortUchar(Pdx->Controller + OFFSET_DCR));
  459. KeDelayExecutionThread(KernelMode, FALSE, &Pdx->OneSecond);
  460. DD((PCE)Pdx,DDT,"Did delay thread of one second, CountDown=%d\n", CountDown);
  461. CountDown--;
  462. } else {
  463. if (Pdx->QueryNumWaiters(Pdx->PortContext)) {
  464. ParFreePort(Pdx);
  465. PortFree = TRUE;
  466. } else {
  467. PortFree = FALSE;
  468. }
  469. KeQueryTickCount(&NextQuery);
  470. Difference.QuadPart = NextQuery.QuadPart - StartOfSpin.QuadPart;
  471. if (Difference.QuadPart*KeQueryTimeIncrement() >=
  472. Pdx->AbsoluteOneSecond.QuadPart) {
  473. DD((PCE)Pdx,DDT,"Countdown: %d - device Status: %x lowpart: %x highpart: %x\n",
  474. CountDown, DeviceStatus, Difference.LowPart, Difference.HighPart);
  475. CountDown--;
  476. DoDelays = TRUE;
  477. }
  478. }
  479. if (CountDown <= 0) {
  480. *BytesTransferred = MaxBytes - BytesToWrite;
  481. status = STATUS_DEVICE_BUSY;
  482. goto returnTarget;
  483. }
  484. if (PortFree && !ParAllocPort(Pdx)) {
  485. *BytesTransferred = MaxBytes - BytesToWrite;
  486. status = STATUS_DEVICE_BUSY;
  487. goto returnTarget;
  488. }
  489. DeviceStatus = GetStatus(Pdx->Controller);
  490. } while ((!PAR_ONLINE(DeviceStatus)) &&
  491. (!PAR_PAPER_EMPTY(DeviceStatus)) &&
  492. (!PAR_POWERED_OFF(DeviceStatus)) &&
  493. (!PAR_NOT_CONNECTED(DeviceStatus)) &&
  494. (!PAR_NO_CABLE(DeviceStatus)) &&
  495. !(Pdx->CurrentOpIrp)->Cancel);
  496. if (CountDown != (LONG)TimerStart) {
  497. DD((PCE)Pdx,DDT,"Leaving busy loop - countdown %d status %x\n", CountDown, DeviceStatus);
  498. }
  499. goto PushSomeBytes;
  500. }
  501. returnTarget:
  502. // added single return point so we can save log of bytes transferred
  503. Pdx->log.SppWriteCount += *BytesTransferred;
  504. DD((PCE)Pdx,DDT,"SppWrite - exit, BytesTransferred = %d\n",*BytesTransferred);
  505. return status;
  506. }
  507. NTSTATUS
  508. SppQueryDeviceId(
  509. IN PPDO_EXTENSION Pdx,
  510. OUT PCHAR DeviceIdBuffer,
  511. IN ULONG BufferSize,
  512. OUT PULONG DeviceIdSize,
  513. IN BOOLEAN bReturnRawString
  514. )
  515. /*++
  516. Routine Description:
  517. This routine is now a wrapper function around Par3QueryDeviceId that
  518. preserves the interface of the original SppQueryDeviceId function.
  519. Clients of this function should consider switching to Par3QueryDeviceId
  520. if possible because Par3QueryDeviceId will allocate and return a pointer
  521. to a buffer if the caller supplied buffer is too small to hold the
  522. device ID.
  523. Arguments:
  524. Pdx - DeviceExtension/Legacy - used to get controller.
  525. DeviceIdBuffer - Buffer used to return ID.
  526. BufferSize - Size of supplied buffer.
  527. DeviceIdSize - Size of returned ID.
  528. bReturnRawString - Should the 2 byte size prefix be included? (TRUE==Yes)
  529. Return Value:
  530. STATUS_SUCCESS - ID query was successful
  531. STATUS_BUFFER_TOO_SMALL - We were able to read an ID from the device but the caller
  532. supplied buffer was not large enough to hold the ID. The
  533. size required to hold the ID is returned in DeviceIdSize.
  534. STATUS_UNSUCCESSFUL - ID query failed - Possibly interface or device is hung, missed
  535. timeouts during the handshake, or device may not be connected.
  536. --*/
  537. {
  538. PCHAR idBuffer;
  539. DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: Enter - buffersize=%d\n", BufferSize);
  540. if ( Pdx->Ieee1284Flags & ( 1 << Pdx->Ieee1284_3DeviceId ) ) {
  541. idBuffer = Par3QueryDeviceId( Pdx, DeviceIdBuffer, BufferSize, DeviceIdSize, bReturnRawString, TRUE );
  542. }
  543. else {
  544. idBuffer = Par3QueryDeviceId( Pdx, DeviceIdBuffer, BufferSize, DeviceIdSize, bReturnRawString, FALSE );
  545. }
  546. if( idBuffer == NULL ) {
  547. //
  548. // Error at lower level - FAIL query
  549. //
  550. DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: call to Par3QueryDeviceId hard FAIL\n");
  551. return STATUS_UNSUCCESSFUL;
  552. } else if( idBuffer != DeviceIdBuffer ) {
  553. //
  554. // We got a deviceId from the device, but caller's buffer was too small to hold it.
  555. // Free the buffer and tell the caller that the supplied buffer was too small.
  556. //
  557. DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: buffer too small - have buffer size=%d, need buffer size=%d\n", BufferSize, *DeviceIdSize);
  558. ExFreePool( idBuffer );
  559. return STATUS_BUFFER_TOO_SMALL;
  560. } else {
  561. //
  562. // Query succeeded using caller's buffer (idBuffer == DeviceIdBuffer)
  563. //
  564. DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: SUCCESS - deviceId=<%s>\n", idBuffer);
  565. return STATUS_SUCCESS;
  566. }
  567. }
  568. VOID
  569. ParTerminateSppMode(
  570. IN PPDO_EXTENSION Pdx
  571. )
  572. {
  573. DD((PCE)Pdx,DDT,"ParTerminateSppMode\n");
  574. Pdx->Connected = FALSE;
  575. P5SetPhase( Pdx, PHASE_TERMINATE );
  576. return;
  577. }