📄 spp.c
字号:
// We never want to be at raised irql form more than
// 200 microseconds, so we will do no more than 100
// bytes at a time.
//
LoopNumber = 512;
if (LoopNumber > BytesToWrite) {
LoopNumber = BytesToWrite;
}
//
// Enter the write loop
//
if (!Pdx->BusyDelayDetermined) {
DD((PCE)Pdx,DDT,"SppWrite: Calling SppCheckBusyDelay\n");
NumBytesWritten = SppCheckBusyDelay(Pdx, IrpBuffer, LoopNumber);
if (Pdx->BusyDelayDetermined) {
if (Pdx->BusyDelay > MaxBusyDelay) {
MaxBusyDelay = Pdx->BusyDelay;
NumberOfBusyChecks = 10;
}
if (NumberOfBusyChecks) {
NumberOfBusyChecks--;
Pdx->BusyDelayDetermined = FALSE;
} else {
Pdx->BusyDelay = MaxBusyDelay + 1;
}
}
} else if( Pdx->UsePIWriteLoop ) {
NumBytesWritten = SppWriteLoopPI( Pdx->Controller, IrpBuffer, LoopNumber, Pdx->BusyDelay );
} else {
NumBytesWritten = SppWriteLoopPI( Pdx->Controller, IrpBuffer, LoopNumber, 1 );
}
if (NumBytesWritten) {
CountDown = TimerStart;
IrpBuffer += NumBytesWritten;
BytesToWrite -= NumBytesWritten;
}
//
// Check to see if the io is done. If it is then call the
// code to complete the request.
//
if (!BytesToWrite) {
*BytesTransferred = MaxBytes;
status = STATUS_SUCCESS;
goto returnTarget;
} else if ((Pdx->CurrentOpIrp)->Cancel) {
//
// See if the IO has been canceled. The cancel routine
// has been removed already (when this became the
// current irp). Simply check the bit. We don't even
// need to capture the lock. If we miss a round
// it won't be that bad.
//
*BytesTransferred = MaxBytes - BytesToWrite;
status = STATUS_CANCELLED;
goto returnTarget;
} else {
//
// We've taken care of the reasons that the irp "itself"
// might want to be completed.
// printer to see if it is in a state that might
// cause us to complete the irp.
//
// First let's check if the device status is
// ok and online. If it is then simply go back
// to the byte pusher.
//
DeviceStatus = GetStatus(Pdx->Controller);
if (PAR_ONLINE(DeviceStatus)) {
goto PushSomeBytes;
}
//
// Perhaps the operator took the device off line,
// or forgot to put in enough paper. If so, then
// let's hang out here for the until the timeout
// period has expired waiting for them to make things
// all better.
//
if (PAR_PAPER_EMPTY(DeviceStatus) ||
PAR_OFF_LINE(DeviceStatus)) {
if (CountDown > 0) {
//
// We'll wait 1 second increments.
//
DD((PCE)Pdx,DDT,"decrementing countdown for PAPER_EMPTY/OFF_LINE - countDown: %d status: 0x%x\n", CountDown, DeviceStatus);
CountDown--;
// If anyone is waiting for the port then let them have it,
// since the printer is busy.
ParFreePort(Pdx);
KeDelayExecutionThread(
KernelMode,
FALSE,
&Pdx->OneSecond
);
if (!ParAllocPort(Pdx)) {
*BytesTransferred = MaxBytes - BytesToWrite;
DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_BUSY\n");
status = STATUS_DEVICE_BUSY;
goto returnTarget;
}
goto PushSomeBytes;
} else {
//
// Timer has expired. Complete the request.
//
*BytesTransferred = MaxBytes - BytesToWrite;
DD((PCE)Pdx,DDT,"In SppWrite(...): Timer expired - DeviceStatus = %08x\n", DeviceStatus);
if (PAR_OFF_LINE(DeviceStatus)) {
DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_OFF_LINE\n");
status = STATUS_DEVICE_OFF_LINE;
goto returnTarget;
} else if (PAR_NO_CABLE(DeviceStatus)) {
DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_NOT_CONNECTED\n");
status = STATUS_DEVICE_NOT_CONNECTED;
goto returnTarget;
} else {
DD((PCE)Pdx,DDT,"In SppWrite(...): returning STATUS_DEVICE_PAPER_EMPTY\n");
status = STATUS_DEVICE_PAPER_EMPTY;
goto returnTarget;
}
}
} else if (PAR_POWERED_OFF(DeviceStatus) ||
PAR_NOT_CONNECTED(DeviceStatus) ||
PAR_NO_CABLE(DeviceStatus)) {
//
// We are in a "bad" state. Is what
// happened to the printer (power off, not connected, or
// the cable being pulled) something that will require us
// to reinitialize the printer? If we need to
// reinitialize the printer then we should complete
// this IO so that the driving application can
// choose what is the best thing to do about it's
// io.
//
DD((PCE)Pdx,DDT,"In SppWrite(...): \"bad\" state - need to reinitialize printer?");
*BytesTransferred = MaxBytes - BytesToWrite;
if (PAR_POWERED_OFF(DeviceStatus)) {
DD((PCE)Pdx,DDT,"SppWrite: returning STATUS_DEVICE_POWERED_OFF\n");
status = STATUS_DEVICE_POWERED_OFF;
goto returnTarget;
} else if (PAR_NOT_CONNECTED(DeviceStatus) ||
PAR_NO_CABLE(DeviceStatus)) {
DD((PCE)Pdx,DDT,"SppWrite: STATUS_DEVICE_NOT_CONNECTED\n");
status = STATUS_DEVICE_NOT_CONNECTED;
goto returnTarget;
}
}
//
// The device could simply be busy at this point. Simply spin
// here waiting for the device to be in a state that we
// care about.
//
// As we spin, get the system ticks. Every time that it looks
// like a second has passed, decrement the countdown. If
// it ever goes to zero, then timeout the request.
//
KeQueryTickCount(&StartOfSpin);
DoDelays = FALSE;
do {
//
// After about a second of spinning, let the rest of the
// machine have time for a second.
//
if (DoDelays) {
ParFreePort(Pdx);
PortFree = TRUE;
DD((PCE)Pdx,DDT,"Before delay thread of one second, dsr=%x DCR[%x]\n",
P5ReadPortUchar(Pdx->Controller + OFFSET_DSR),
P5ReadPortUchar(Pdx->Controller + OFFSET_DCR));
KeDelayExecutionThread(KernelMode, FALSE, &Pdx->OneSecond);
DD((PCE)Pdx,DDT,"Did delay thread of one second, CountDown=%d\n", CountDown);
CountDown--;
} else {
if (Pdx->QueryNumWaiters(Pdx->PortContext)) {
ParFreePort(Pdx);
PortFree = TRUE;
} else {
PortFree = FALSE;
}
KeQueryTickCount(&NextQuery);
Difference.QuadPart = NextQuery.QuadPart - StartOfSpin.QuadPart;
if (Difference.QuadPart*KeQueryTimeIncrement() >=
Pdx->AbsoluteOneSecond.QuadPart) {
DD((PCE)Pdx,DDT,"Countdown: %d - device Status: %x lowpart: %x highpart: %x\n",
CountDown, DeviceStatus, Difference.LowPart, Difference.HighPart);
CountDown--;
DoDelays = TRUE;
}
}
if (CountDown <= 0) {
*BytesTransferred = MaxBytes - BytesToWrite;
status = STATUS_DEVICE_BUSY;
goto returnTarget;
}
if (PortFree && !ParAllocPort(Pdx)) {
*BytesTransferred = MaxBytes - BytesToWrite;
status = STATUS_DEVICE_BUSY;
goto returnTarget;
}
DeviceStatus = GetStatus(Pdx->Controller);
} while ((!PAR_ONLINE(DeviceStatus)) &&
(!PAR_PAPER_EMPTY(DeviceStatus)) &&
(!PAR_POWERED_OFF(DeviceStatus)) &&
(!PAR_NOT_CONNECTED(DeviceStatus)) &&
(!PAR_NO_CABLE(DeviceStatus)) &&
!(Pdx->CurrentOpIrp)->Cancel);
if (CountDown != (LONG)TimerStart) {
DD((PCE)Pdx,DDT,"Leaving busy loop - countdown %d status %x\n", CountDown, DeviceStatus);
}
goto PushSomeBytes;
}
returnTarget:
// added single return point so we can save log of bytes transferred
Pdx->log.SppWriteCount += *BytesTransferred;
DD((PCE)Pdx,DDT,"SppWrite - exit, BytesTransferred = %d\n",*BytesTransferred);
return status;
}
NTSTATUS
SppQueryDeviceId(
IN PPDO_EXTENSION Pdx,
OUT PCHAR DeviceIdBuffer,
IN ULONG BufferSize,
OUT PULONG DeviceIdSize,
IN BOOLEAN bReturnRawString
)
/*++
Routine Description:
This routine is now a wrapper function around Par3QueryDeviceId that
preserves the interface of the original SppQueryDeviceId function.
Clients of this function should consider switching to Par3QueryDeviceId
if possible because Par3QueryDeviceId will allocate and return a pointer
to a buffer if the caller supplied buffer is too small to hold the
device ID.
Arguments:
Pdx - DeviceExtension/Legacy - used to get controller.
DeviceIdBuffer - Buffer used to return ID.
BufferSize - Size of supplied buffer.
DeviceIdSize - Size of returned ID.
bReturnRawString - Should the 2 byte size prefix be included? (TRUE==Yes)
Return Value:
STATUS_SUCCESS - ID query was successful
STATUS_BUFFER_TOO_SMALL - We were able to read an ID from the device but the caller
supplied buffer was not large enough to hold the ID. The
size required to hold the ID is returned in DeviceIdSize.
STATUS_UNSUCCESSFUL - ID query failed - Possibly interface or device is hung, missed
timeouts during the handshake, or device may not be connected.
--*/
{
PCHAR idBuffer;
DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: Enter - buffersize=%d\n", BufferSize);
if ( Pdx->Ieee1284Flags & ( 1 << Pdx->Ieee1284_3DeviceId ) ) {
idBuffer = Par3QueryDeviceId( Pdx, DeviceIdBuffer, BufferSize, DeviceIdSize, bReturnRawString, TRUE );
}
else {
idBuffer = Par3QueryDeviceId( Pdx, DeviceIdBuffer, BufferSize, DeviceIdSize, bReturnRawString, FALSE );
}
if( idBuffer == NULL ) {
//
// Error at lower level - FAIL query
//
DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: call to Par3QueryDeviceId hard FAIL\n");
return STATUS_UNSUCCESSFUL;
} else if( idBuffer != DeviceIdBuffer ) {
//
// We got a deviceId from the device, but caller's buffer was too small to hold it.
// Free the buffer and tell the caller that the supplied buffer was too small.
//
DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: buffer too small - have buffer size=%d, need buffer size=%d\n", BufferSize, *DeviceIdSize);
ExFreePool( idBuffer );
return STATUS_BUFFER_TOO_SMALL;
} else {
//
// Query succeeded using caller's buffer (idBuffer == DeviceIdBuffer)
//
DD((PCE)Pdx,DDT,"spp::SppQueryDeviceId: SUCCESS - deviceId=<%s>\n", idBuffer);
return STATUS_SUCCESS;
}
}
VOID
ParTerminateSppMode(
IN PPDO_EXTENSION Pdx
)
{
DD((PCE)Pdx,DDT,"ParTerminateSppMode\n");
Pdx->Connected = FALSE;
P5SetPhase( Pdx, PHASE_TERMINATE );
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -