home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
spldapi.zip
/
pdrapi.c
Wrap
C/C++ Source or Header
|
1997-10-09
|
67KB
|
2,169 lines
/**************************************************************************
*
* SOURCE FILE NAME = pdrapi.c
*
* DESCRIPTIVE NAME = parallel port driver exported SplPd APIs
*
* Copyright : COPYRIGHT IBM CORPORATION, 1994, 1995
* LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
* REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
* RESTRICTED MATERIALS OF IBM
* IBM CONFIDENTIAL
*
* VERSION = V2.2
*
* DATE
*
* DESCRIPTION
*
*
* FUNCTIONS
*
* ENTRY POINTS:
*
* DEPENDENCIES:
*
* NOTES
*
*
* STRUCTURES
*
* EXTERNAL REFERENCES
*
* EXTERNAL FUNCTIONS
*
* CHANGE ACTIVITY =
* DATE FLAG APAR CHANGE DESCRIPTION
* -------- ---------- ----- --------------------------------------
* mm/dd/yy @Vr.mpppxx xxxxx xxxxxxx
****************************************************************************/
#include "pdrconst.h"
#include "pdrtypes.h"
#include "pdrproto.h"
#define BIDI_TEST_RESP 0x9000
/*
** SPLPD functions that can be called by ANY process, not just the spooler
*/
/****************************************************************************
*
* FUNCTION NAME = SplPdEnumPort
*
* DESCRIPTION = Return ports supported by this port driver
* Currently this will return those ports this port
* driver supports by default.
* The print object only calls this if the port
* driver does not export the extended attribute
* "DEFAULT_PORT"
*
* INPUT = hab - anchor block handle
* pBuf - buffer to get enumerated PORTNAMES structures
* cbBuf - size(in bytes) of pBuf passed in
*
* OUTPUT = *pulReturned - number of PORTNAMES structures stored in pBuf
* *pulTotal - total ports supported by this port driver
* *pcbRequired - size(in bytes) of buffer needed to store
* all enumerated PORTNAMES entries.
* pBuf - gets an array(number elements is *pulReturned) of
* PORTNAMES structures.
* Each psz in PORTNAMES structure points to a string
* copied into the end of pBuf.
*
* typedef struct _PORTNAMES {
* PSZ pszPortName; // Name of port, example: PAR1284
* PSZ pszPortDesc; // Port description
* } PORTNAMES;
*
* RETURN-NORMAL = 0 - if all portnames and descriptions fit in pBuf
*
* RETURN-ERROR = ERROR_INSUFFICIENT_BUFFER - if no PORTNAMES structs
* could fit in buffer. Caller
* uses *pcbRequired to allocate
* a buffer big enough to store all
* port names.
* ERROR_MORE_DATA - if some, but not all, PORTNAMES structs
* could fit in buffer. Caller
* uses *pcbRequired to allocate
* a buffer big enough to store all
* port names.
*
****************************************************************************/
APIRET APIENTRY SplPdEnumPort ( HAB hab,
PVOID pBuf,
ULONG cbBuf,
PULONG pulReturned,
PULONG pulTotal,
PULONG pcbRequired )
{
/*
** ensure pointers not null
*/
if (!pulReturned ||
!pulTotal ||
!pcbRequired)
{
return(ERROR_INVALID_PARAMETER);
}
/*
** if buffer length is supplied then there should be pBuf
*/
if (!pBuf && cbBuf)
{
return(ERROR_INVALID_PARAMETER);
}
/*
** check if cbBuf is 0 - then return number of ports in pulTotal
** and number of bytes required in pcbRequired
*/
if (cbBuf == 0L)
{
*pulReturned = 0;
*pcbRequired = CalcBufLength ( hab );
*pulTotal = 3 ; /* Currently support PAR1284 */
/*
** NOTE: early version of the print object checked for
** ERROR_MORE_DATA instead of ERROR_INSUFFICIENT_BUFFER
** For this reason we return ERROR_MORE_DATA here.
*/
return(ERROR_MORE_DATA);
}
/*
** check number of ports info we can fit in supplied buffer
*/
*pulTotal = 3 ; /* Currently support PAR1284 */
*pcbRequired = CalcBufLength ( hab );
*pulReturned = NumPortsCanFit ( hab, cbBuf);
/*
** return error if we can not fit one port.
*/
if (!(*pulReturned))
{
return(ERROR_INSUFFICIENT_BUFFER);
}
/*
** copy all the ports which we can store in the pBuf
*/
CopyNPorts (hab, (PCH)pBuf, *pulReturned);
/*
** copy all the ports which we can store in the pBuf
*/
if (*pulReturned < *pulTotal)
{
return(ERROR_MORE_DATA);
}
return(NO_ERROR);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdInstallPort
*
* DESCRIPTION = Install a new port for this port driver.
*
* The print object calls this when user selects to install
* a new printer port. The portname given might be the
* name from the "DEFAULT_PORT" extended attribute of
* the port driver file, in which case this port driver
* can generate a new port name to install.
* If this port driver cannot find any printer it
* can communicate with, it should return
* ERROR_PRINT_CANCELLED to make sure the print object
* does not put up "Port Installed" message.
*
* The print object will not call SplPdSetPort after
* this. Each port driver has the option to
* bring up their SplPdSetPort dialog during processing
* of this call to allow users to select the printer
* they wish to connect with(and possibly change the
* name of the print port they are installing).
*
* INPUT = hab - Anchor block handle
* pszPortName - name of port to be installed
*
* OUTPUT =
*
* RETURN-NORMAL = 0
*
* RETURN-ERROR = ERROR_INVALID_PARAMETER - if bad port name given
* ERROR_PRINT_CANCELLED - port not installed
*
****************************************************************************/
APIRET APIENTRY SplPdInstallPort ( HAB hab,
PSZ pszPortName )
{
CHAR chBuf[CCHMAXPATH];
CHAR chPortDesc[STR_LEN_PORTDESC];
PPORTDLGSTRUCT pPortDlgStruct;
ULONG rc;
BOOL fSuccess;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
/*
** Check if port name string is NULL. This is an error.
*/
if (!pszPortName)
{
return(ERROR_INVALID_PARAMETER);
}
/*
** Make Application name string "PM_Port Name"
*/
strcpy (chBuf, APPNAME_LEAD_STR);
strcat (chBuf, pszPortName);
/*
** Check for this being our default Port Name to install
** If so(pszPortName == "LPT") then generate a unique
** port name so that we can install multiple IR printers.
*/
if (!strcmp(pszPortName, DEF_PORTNAME))
{
/*
** Use chBuf to store the new portname to install
** Must first increment past "PM_" in chBuf
*/
pszPortName = chBuf + 3;
GenerateUniquePortName( pszPortName );
}
/*
** Check if we have description for port
*/
if (!GetPortDescription (hab, pszPortName, chPortDesc))
{
/*
** Port description not found, use port name
*/
strcpy( chPortDesc, pszPortName );
}
/*
** Write data for this port in ini file with new format.
*/
PrfWriteProfileString (HINI_SYSTEMPROFILE,
chBuf,
KEY_DESCRIPTION,
chPortDesc);
PrfWriteProfileString (HINI_SYSTEMPROFILE,
chBuf,
KEY_TIMEOUT_QUERY,
DEF_TIMEOUT_QUERY);
PrfWriteProfileString (HINI_SYSTEMPROFILE,
chBuf,
KEY_TIMEOUT_JOB,
DEF_TIMEOUT_JOB);
PrfWriteProfileString (HINI_SYSTEMPROFILE,
chBuf,
KEY_PORTDRIVER,
DEF_PORTDRIVER);
/*
** Write data for this port in ini file with old format.
** This call will add pszPortName as a selectable port
** from the print object "Output Port" settings page.
*/
fSuccess = PrfWriteProfileString (HINI_SYSTEMPROFILE,
APPNAME_PM_SPOOLER_PORT,
pszPortName,
DEF_OLD_INITIALIZATION);
if (!fSuccess)
{
/*
** Unable to add the new port
*/
DBPRINTF ((logbuf, "SplPdInstallPort Unable to add PM_SPOOLER_PORT(%s)", pszPortName));
return( ERROR_INVALID_PARAMETER );
}
/*
** rewrite portdriver connection - fix for old spooler
*/
PrfWriteProfileString (HINI_SYSTEMPROFILE,
chBuf,
KEY_PORTDRIVER,
DEF_PORTDRIVER);
/*
** Now that the port has been added we can
** display the settings dialog to let the user
** select the settings for this printer port.
**
** First allocate a port driver dialog structure
*/
pPortDlgStruct = NULL;
rc = DosAllocMem((PVOID)&pPortDlgStruct,
sizeof(PORTDLGSTRUCT),
PAG_READ | PAG_WRITE | PAG_COMMIT);
if (rc)
{
DBPRINTF ((logbuf, "SplPdInstallPort DosAllocMem failed rc=%d",rc));
return(rc);
}
/*
** Give user dialog to connect to a new printer
*/
memset (pPortDlgStruct, 0, sizeof (PORTDLGSTRUCT));
pPortDlgStruct->signature = PDLG_SIGNATURE;
pPortDlgStruct->hAB = hab ;
pPortDlgStruct->hModule = hPdrMod ;
pPortDlgStruct->pszPortName = pszPortName ;
/*
** Load the dialog for user to change.
*/
OpenPar1284PortDlg (hab, pPortDlgStruct);
DosFreeMem( pPortDlgStruct );
DBPRINTF ((logbuf, "SplPdInstallPort Successful(%s)", pszPortName));
return(NO_ERROR);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdGetPortIcon
*
* DESCRIPTION = Return Resource ID of icon representing this port.
* Note: only one icon will represent all ports supported
* by a port driver.
*
* INPUT = hab - Anchor block handle
* idIcon - gets Resource ID of icon bit map
*
* OUTPUT =
*
* RETURN-NORMAL = TRUE
*
* RETURN-ERROR = FALSE - if unable to return icon Resource ID
*
****************************************************************************/
BOOL APIENTRY SplPdGetPortIcon ( HAB hab,
PULONG idIcon )
{
/*
** Check for our global port icon ID(is always set)
*/
if (idIcon)
{
*idIcon = PAR1284_ICON;
}
return(TRUE);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdQueryPort
*
* DESCRIPTION = Returns textual data that describes the port configuration.
*
* INPUT = hab - Anchor block handle
* pszPortName - name of port to get configuration for
* pBufIn - pointer to buffer of returned data structures
* cbBuf - Size of pBufIn in bytes
* cItems - Count of number of strings of descriptions
* returned
*
* OUTPUT =
*
* RETURN-NORMAL = 0
*
* RETURN-ERROR = ERROR_INSUFFICIENT_BUFFER - if buffer is too small
* ERROR_INVALID_PARAMETER - if bad port name given
*
****************************************************************************/
APIRET APIENTRY SplPdQueryPort ( HAB hab,
PSZ pszPortName,
PVOID pBufIn,
ULONG cbBuf,
PULONG cItems )
{
CHAR chString[STR_LEN_DESC];
USHORT usNumLines;
USHORT usLineID;
USHORT usStrLength;
PCH pBuf = (PCH)pBufIn;
/*
** check pointer to all the return variables is not null
*/
if (!cItems)
{
return(ERROR_INVALID_PARAMETER);
}
/*
** if pBuf or cbBuf is NULL - it is an error.
*/
if (!pBuf || !cbBuf)
{
return(ERROR_INVALID_PARAMETER);
}
chString[0] = '\0' ;
/*
** get number of lines.
*/
WinLoadString(hab, hPdrMod, (USHORT)ID_NUMBER_OF_DESC_LINES, STR_LEN_DESC,
chString);
usNumLines = (USHORT)atoi (chString);
usLineID = ID_FIRST_DESC_LINES;
for (*cItems = 0; *cItems < usNumLines; *cItems++)
{
WinLoadString(hab, hPdrMod, usLineID, STR_LEN_DESC, chString);
if (cbBuf >= (usStrLength = (USHORT)(strlen (chString) + 1)))
{
strcpy (pBuf, chString);
pBuf += usStrLength;
cbBuf -= usStrLength;
}
else
{
return(ERROR_INSUFFICIENT_BUFFER);
}
}
return(NO_ERROR);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdRemovePort
*
* DESCRIPTION = Tells port driver the name of a port that needs to be removed.
* Port driver should remove its data from the INI file.
*
* INPUT = hab - Anchor block handle
* pszPortName - name of port to be removed
*
* OUTPUT =
*
* RETURN-NORMAL = 0
*
* RETURN-ERROR = ERROR_INVALID_PARAMETER - if bad port name given
*
****************************************************************************/
APIRET APIENTRY SplPdRemovePort ( HAB hab,
PSZ pszPortName )
{
CHAR chBuf[STR_LEN_PORTNAME];
CHAR chPortDriver[STR_LEN_PORTNAME];
BOOL fSuccess;
#ifdef DEBUG_ALERT
CHAR logbuf[260];
#endif
/*
** Check if port name string is NULL. This is an error.
*/
if (!pszPortName)
{
return(ERROR_INVALID_PARAMETER);
}
/*
* Remove port from port list
* Must free all threads waiting for this port @BUGBUG
*/
EnterPdrSem();
RemovePortInst ( pszPortName );
LeavePdrSem();
/*
** Make Application name string.
*/
strcpy (chBuf, APPNAME_LEAD_STR);
strcat (chBuf, pszPortName);
/*
** Check if this port is PAR1284 port.
*/
if (!(PrfQueryProfileString (HINI_SYSTEMPROFILE, chBuf,
KEY_PORTDRIVER, NULL, chPortDriver,
STR_LEN_PORTNAME)))
{
DBPRINTF ((logbuf, "SplPdRemovePort failed - no portdriver in INI(%s)", pszPortName));
return(ERROR_INVALID_PARAMETER);
}
if (strcmp (chPortDriver, DEF_PORTDRIVER))
{
DBPRINTF ((logbuf, "SplPdRemovePort failed - wrong portdriver in INI(%s)", pszPortName));
return(ERROR_INVALID_PARAMETER);
}
/*
** We found port to be removed.
** Remove INI entries for "PM_portname"
*/
PrfWriteProfileString (HINI_SYSTEMPROFILE, chBuf, NULL, NULL);
/*
** remove this port from selectable ports in the print object
*/
fSuccess = PrfWriteProfileString (HINI_SYSTEMPROFILE,
APPNAME_PM_SPOOLER_PORT,
pszPortName,
NULL);
DBPRINTF ((logbuf, "SplPdRemovePort removing %s from INI fSuccess=%d", pszPortName, fSuccess));
return(NO_ERROR);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdSetPort
*
* DESCRIPTION = Display a dialog to allow the user to browse and modify
* port configurations.
*
* INPUT = hab - Anchor block handle
* pszPortName - name of port to configure
* flModified - Flag to indicate that the configuration
* has been modified.(TRUE if modified).
*
* OUTPUT =
*
* RETURN-NORMAL = 0
*
* RETURN-ERROR = ERROR_INVALID_PARAMETER - if bad port name given
*
****************************************************************************/
APIRET APIENTRY SplPdSetPort ( HAB hab,
PSZ pszPortName,
PULONG flModified )
{
ULONG rc;
PPORTDLGSTRUCT pPortDlgStruct;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
/*
** Check if port name string is NULL. This is an error.
*/
if (!pszPortName || !flModified)
{
return(ERROR_INVALID_PARAMETER);
}
/*
** First allocate a port driver dialog structure
*/
pPortDlgStruct = NULL;
rc = DosAllocMem((PVOID)&pPortDlgStruct,
sizeof(PORTDLGSTRUCT),
PAG_READ | PAG_WRITE | PAG_COMMIT);
if (rc)
{
DBPRINTF ((logbuf, "SplPdSetPort DosAllocMem failed rc=%d",rc));
return(rc);
}
/*
** Give user dialog to connect to a new printer
*/
memset (pPortDlgStruct, 0, sizeof (PORTDLGSTRUCT));
pPortDlgStruct->signature = PDLG_SIGNATURE;
pPortDlgStruct->hAB = hab ;
pPortDlgStruct->hModule = hPdrMod ;
pPortDlgStruct->pszPortName = pszPortName ;
/*
** Load the dialog for user to change.
*/
*flModified = OpenPar1284PortDlg (hab, pPortDlgStruct);
DosFreeMem( pPortDlgStruct );
DBPRINTF ((logbuf, "SplPdSetPort flModified=%d(%s)", *flModified, pszPortName));
return(NO_ERROR);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdRemoteSetPort
*
* DESCRIPTION = Display a dialog to allow the user to browse and modify
* port configurations.
*
* INPUT = hab - Anchor block handle
* pszComputerName - Name of print server being configured.
* pszPortName - name of port to configure
* flModified - Flag to indicate that the configuration
* has been modified.(TRUE if modified).
*
* OUTPUT =
*
* RETURN-NORMAL = 0
*
* RETURN-ERROR = ERROR_INVALID_PARAMETER - if bad port name given
*
****************************************************************************/
#ifdef BIDI
APIRET APIENTRY SplPdRemoteSetPort ( HAB hab,
PSZ pszComputerName,
PSZ pszPortName,
PULONG flModified )
{
ULONG rc;
PPORTDLGSTRUCT pPortDlgStruct;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
/*
** Check if port name string is NULL. This is an error.
*/
if (!pszComputerName || !pszPortName || !flModified)
{
return(ERROR_INVALID_PARAMETER);
}
/*
** First allocate a port driver dialog structure
*/
pPortDlgStruct = NULL;
rc = DosAllocMem((PVOID)&pPortDlgStruct,
sizeof(PORTDLGSTRUCT),
PAG_READ | PAG_WRITE | PAG_COMMIT);
if (rc)
{
DBPRINTF ((logbuf, "SplPdRemoteSetPort DosAllocMem failed rc=%d",rc));
return(rc);
}
/*
** Give user dialog to connect to a new printer
*/
memset (pPortDlgStruct, 0, sizeof (PORTDLGSTRUCT));
pPortDlgStruct->signature = PDLG_SIGNATURE;
pPortDlgStruct->hAB = hab ;
pPortDlgStruct->hModule = hPdrMod ;
pPortDlgStruct->pszPortName = pszPortName ;
pPortDlgStruct->pszComputerName = pszComputerName ;
/*
** Load the dialog for user to change.
*/
*flModified = OpenPar1284PortDlg (hab, pPortDlgStruct);
DosFreeMem( pPortDlgStruct );
DBPRINTF ((logbuf, "SplPdRemoteSetPort flModified=%d(%s on %s)", *flModified, pszPortName, pszComputerName));
return(NO_ERROR);
}
#endif // ifdef BIDI
/*
** SPLPD functions that can only be called by the spooler process
*/
/****************************************************************************
*
* FUNCTION NAME = SplPdOpen - EXTERNAL API
*
* DESCRIPTION = Open a print port for output.
*
*
*
* INPUT = pszPortName - name of port to open
* phDevice - gets port driver handle
* pDeviceFlags - gets device type being opened
*
* HANDTYPE_FILE 0x0000
* HANDTYPE_DEVICE 0x0001
* HANDTYPE_PIPE 0x0002
* HANDTYPE_LPTDEVICE 0x0004
* HANDTYPE_COMDEVICE 0x0008
* HANDTYPE_PROTECTED 0x4000
* HANDTYPE_NETWORK 0x8000
*
* pPrtOpenStruct - spooler parameter structure for PrtOpen
*
* OUTPUT = 0 - successful.
* This device cannot be opened again until SplPdClose()
* is called.
*
* *phDevice = port driver handle to be used with
* SplPdWrite/SplPdAbortDoc/SplPdClose...
* *pDeviceFlags = device handle flags
*
* Other - error code, port not opened.
*
****************************************************************************/
ULONG APIENTRY SplPdOpen( PSZ pszPortName,
PHFILE phFile,
PULONG pDeviceFlags,
PVOID pPrtOpenStruct)
{
ULONG rc;
ULONG cb;
PPORTINST pPortInst;
PPDOPENINST pPdOpenInstance;
PRTSTARTJOB PrtStartJob;
PPRTOPENSTRUCT0 pPrtOpenStruct0;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
/*
* Check for valid pointers
*/
if (!phFile || !pDeviceFlags )
{
return(ERROR_INVALID_PARAMETER);
}
*phFile = NULLHANDLE;
pPdOpenInstance = NULL;
pPortInst = NULL;
rc = 0;
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
{
sprintf( logbuf,
"SplPdOpen on %s\r\n",
pszPortName);
LogCall( logbuf );
}
}
#endif /* DEBUG */
cb = sizeof(PDOPENINST) + strlen(pszPortName) + 1 ;
EnterPdrSem();
/*
** Add port to list.
** If added previously, get pointer to structure.
** If not yet opened, open the port
*/
pPortInst = AddPortInst ( pszPortName );
/*
** Set TimeLastCmd so that we don't close this
** port from our ControlThread
*/
if (pPortInst) {
pPortInst->ulTimeLastCmd = time();
}
if (pPortInst && !(pPortInst->flStatus & PF_PORT_OPEN))
{
rc = PdOpen(pPortInst);
}
if (!rc)
{
pPdOpenInstance = (PPDOPENINST) AllocPdrMem( cb );
}
LeavePdrSem();
if (!rc && !pPdOpenInstance)
{
rc = ERROR_NOT_ENOUGH_MEMORY;
}
if (!rc)
{
/*
** init instance struct
*/
memset( pPdOpenInstance, 0, sizeof(PDOPENINST) );
pPdOpenInstance->signature = PD_SIGNATURE ;
pPdOpenInstance->cb = cb ;
pPdOpenInstance->pNext = NULL;
pPdOpenInstance->pPortInst = pPortInst;
pPdOpenInstance->pszPortName = (PSZ)(pPdOpenInstance+1);
strcpy( pPdOpenInstance->pszPortName, pszPortName);
/*
* Add this pdopen instance to this driver's list
*/
EnterPdrSem();
rc = AddPdOpenInst( pPdOpenInstance );
LeavePdrSem();
if (!rc)
{
*phFile = (HFILE)( pPdOpenInstance );
*pDeviceFlags = HANDTYPE_DEVICE;
}
}
if (!rc)
{
/*
** Send start job command
*/
#ifdef BIDI
pPrtOpenStruct0 = (PPRTOPENSTRUCT0)pPrtOpenStruct;
if (pPrtOpenStruct0) {
PrtStartJob.ulSpoolerJobID = pPrtOpenStruct0->ulSpoolerJobID ;
PrtStartJob.ulInterpreterID = pPrtOpenStruct0->ulLogicalUnit ;
PrtStartJob.ulStartPage = pPrtOpenStruct0->ulStartPage ;
PrtStartJob.ulEndPage = pPrtOpenStruct0->ulEndPage ;
} else {
PrtStartJob.ulSpoolerJobID = (ULONG)-1;
PrtStartJob.ulInterpreterID = (ULONG)-1;
PrtStartJob.ulStartPage = 0;
PrtStartJob.ulEndPage = 0;
}
rc = MyPrtSet ( NULL, pszPortName, TYPE_LONG_WAIT, BIDI_STARTJOB,
&PrtStartJob, sizeof(PrtStartJob));
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
{
sprintf( logbuf,
"SplPdOpen PrtSet(BIDI_STARTJOB) rc=%d\r\n",
rc);
LogCall( logbuf );
}
}
#endif /* DEBUG */
if ( (rc == ERROR_NOT_SUPPORTED) || (rc == ERROR_TIMEOUT) )
{
/*
* You will receive ERROR_NOT_SUPPORTED from BIDI_STARTJOB
* if there is no protocol converter.
* You also could receive ERROR_TIMEOUT if the converter
* is not working properly.
*/
rc = 0;
}
#endif
/*
** Set JOB_PRINTING flag AFTER sending STARTJOB to allow sending
** the BIDI_STARTJOB sequence, and avoid sending query data
** while sending a job.
*/
if (!rc) {
EnterPdrSem();
pPortInst->ulJobPrinting = PDR_PRINTING;
LeavePdrSem();
}
} /* end if pPdOpenInstance created OK */
if (rc) {
/*
** Error occurred initializing the port
*/
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
{
sprintf( logbuf,
"SplPdOpen failed, freeing pdOpenInst=%lX\r\n",
(ULONG)pPdOpenInstance);
LogCall( logbuf );
}
}
#endif /* DEBUG */
EnterPdrSem();
if (pPortInst && !(pPortInst->flStatus & PF_Q_PORT_CALLED))
{
/*
** We close connection at end of each job ONLY if
** bidi is not enabled(never received BIDI_Q_PORT)
*/
PdClose( pPortInst );
}
if (pPdOpenInstance) {
/*
** Free PdInstance if open fails
*/
RemovePdOpenInst ( pPdOpenInstance );
FreePdrMem( (PVOID)pPdOpenInstance , pPdOpenInstance->cb );
}
LeavePdrSem();
*phFile = NULLHANDLE;
}
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
{
sprintf( logbuf,
"SplPdOpen on %s rc=%d hFile=%lX\r\n",
pszPortName, rc, *phFile);
LogCall( logbuf );
}
}
#endif /* DEBUG */
return(rc);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdWrite - EXTERNAL API
*
* DESCRIPTION = Write data to a printer port opened with SplPdOpen()
*
* INPUT = hDevice - handle from SplPdOpen
* pchData - ptr to data buffer to write
* cbData - length of data in bytes
* pcbWritten - gets count of bytes actually written
*
* OUTPUT = 0 - successful.
* *pcbWritten must be checked to ensure cbData bytes
* have been written.
* Possible to get 0 rc and 0 bytes written.
*
*
* Other - error code, write failed
* *pcbWritten contains number of bytes successfully
* written.
*
* NOTES Not in port driver semaphore on entry/exit
* Data may be buffered; PrtClose must send any buffered data.
*
****************************************************************************/
ULONG APIENTRY SplPdWrite( HFILE hFile,
PVOID pchData,
ULONG cbData,
PULONG pcbWritten )
{
ULONG rc;
PPORTINST pPortInst;
PPDOPENINST pPdOpenInstance ;
ULONG ulPortTimeout ; /* timeout for this port */
ULONG cbWritten ; /* bytes written to port so far */
ULONG ulTime ; /* time prior to issuing DosWrite call */
BOOL fMustCheckDevID; /* TRUE = call GetDeviceID */
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
#ifdef DEBUG_ALERT
{
if (flChangeDebugLog & FL_PDRDB_ENABLE_SPLPDWRITE)
{
sprintf( logbuf,
"SplPdWrite hFile=%lX pBuf=%lX cb=%d\r\n",
hFile, (ULONG)pchData, cbData );
LogCall( logbuf );
}
}
#endif /* DEBUG */
/*
* Validate file handle
*/
if (!(pPdOpenInstance = ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
return(ERROR_INVALID_HANDLE);
}
/*
* Get port structure,
*/
pPortInst = pPdOpenInstance->pPortInst;
if (!(pPortInst) ) {
return(ERROR_INVALID_HANDLE);
}
if ( (pPortInst->ulCurrentMode <= CURMODE_COMPATIBLE) &&
!(pPortInst->flStatus & PF_BIDI_CHECKED) &&
(pPortInst->ulModeSelected != PARMODE_DISABLE_BIDI) ) {
/*
** If this write is successful
** then we should try to query the deviceID for the printer.
** This is done in case the printer was not powered on
** when we initially tried to get the device ID from it.
** The result(if a bidi printer was powered off but is
** on when the first job is sent) is that the first job
** is printed in unidirectional mode, an alert is sent
** (PRTALERT_TYPE_COMM_STATUS_CHANGED) which causes the
** spooler to re-init the printer after the current job
** completes. This will put the software into bidi mode.
*/
fMustCheckDevID = TRUE;
} else {
fMustCheckDevID = FALSE;
}
/*
* Save time prior to issuing DosWrite
* If write fails before printer timeout expired
* retry the request.
* This allows us to set shorter timeout with the
* device driver
*/
ulTime = time() ;
*pcbWritten = 0 ; /* init bytes written to zero */
//
// Get write mutex sem
//
rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
while (pPortInst->fMoreCmds) {
/*
** We were in the process of sending multiple
** queries to the printer.
** Hold off the print job until the query commands
** have been sent.
*/
rc = DosReleaseMutexSem ( pPortInst->hPortSem );
DosSleep(500);
rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
}
rc = PdWrite(pPortInst, pchData, cbData, pcbWritten);
if (rc || (*pcbWritten != cbData) ) {
/*
* Check time it took to issue write
* If this is a known port
* there is a timeout for the port
* and the time it took to do the write was
* less than (PortTimeout - 1)
* then
* Retry Request
*
* If the job was aborted, ulJobPrinting would be reset.
*/
if ( (pPdOpenInstance->signature == PD_SIGNATURE) &&
(ulPortTimeout = pPortInst->ulPrintTimeOut) &&
( (time() - ulTime) < (ulPortTimeout - 1) )) {
/*
* Keep track of total bytes written
* Reset clock if DosWrite succeeded without writting all bytes
* Retry request
*/
cbWritten = *pcbWritten ;
do
{
if ( (rc == 0) && (*pcbWritten) ) {
/*
* if DosWrite successful and bytes were written
* reset timeout value
*/
ulTime = time() ;
}
/*
** Some printers allow query commands to be sent
** while still sending the print job.
** Here we release the mutex Write semaphore to allow
** the protocol converter to issue a query to the
** printer.
** It is up to the protocol converter to ensure @BUGBUG
** the printer can accept the query command in
** the middle of a print job.
*/
rc = DosReleaseMutexSem ( pPortInst->hPortSem );
/* Sleep one second to avoid hard loop on DosWrite */
DosSleep(1000) ;
rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
*pcbWritten = 0 ; /* reset bytes written */
/*
* Write buffer, taking into account bytes written so far
*/
rc = PdWrite( pPortInst,
(PVOID)((PBYTE)pchData + cbWritten),
/* index past bytes written */
cbData - cbWritten,/* only write remaining data */
pcbWritten);
cbWritten += *pcbWritten ;
} while ( (cbWritten < cbData) &&
(pPortInst->ulJobPrinting == PDR_PRINTING) &&
( (time() - ulTime) < (ulPortTimeout - 1) )) ;
/* return actual bytes written */
*pcbWritten = cbWritten ;
}
} /* end giving retry */
//
// Give up write sem
//
rc = DosReleaseMutexSem ( pPortInst->hPortSem );
if (pPortInst->flJob & PRTSW_JOB_WRAPPER_REQUIRED) {
/*
** This printer gets a bidi wrapper put around all data writes.
** Wakeup ParReadThread so we can get the acknowledgement @BUGBUG
** to the buffer we just sent, because some printers(NPAP)
** might reject data buffers when the printer is busy.
** The CNV waits for an ack that the printer accepted the
** data buffer before sending the next data buffer.
**
** Later we should allow PROTCNV to tell us whether we should
** expect an Ack for data writes(dynamically set the state
** using PrtSet).
*/
DosPostEventSem(pPortInst->hevReadThread);
}
#ifdef DEBUG_ALERT
{
if (flChangeDebugLog & FL_PDRDB_ENABLE_SPLPDWRITE)
{
sprintf( logbuf,
"SplPdWrite rc=%d cbWritten=%d\r\n",
rc, *pcbWritten );
LogCall( logbuf );
}
}
#endif /* DEBUG */
/*
** If anything was written to the printer for the first time
** then try to get the printer's device ID.
*/
if ( fMustCheckDevID && (*pcbWritten > 1) ) {
RecheckDevID( pPortInst );
}
return(rc);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdAbortDoc - EXTERNAL API
*
* DESCRIPTION = Flush all current write requests for a h SplPdOpen()
*
* INPUT = hDevice - handle from SplPdOpen
* pchData - ptr to data buffer to write
* cbData - length of data in bytes
* ulFlags - abort processing flags
*
* OUTPUT = 0 - successful.
*
* Other - error code, write failed
* *pcbWritten contains number of bytes successfully
* written.
*
* NOTES This currently does not buffer any write requests,
* so there are no buffers to flush.
*
****************************************************************************/
ULONG APIENTRY SplPdAbortDoc( HFILE hFile,
PVOID pchData,
ULONG cbData,
ULONG ulFlags )
{
ULONG rc;
ULONG ulJobPrinting;
ULONG cbWritten;
PPORTINST pPortInst;
PPDOPENINST pPdOpenInstance ;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDABORT))
{
sprintf( logbuf,
"SplPdAbortDoc hFile=%lX pBuf=%lX cb=%d Flags=%lX\r\n",
hFile, (ULONG)pchData, cbData, ulFlags );
LogCall( logbuf );
}
}
#endif /* DEBUG */
rc = 0 ;
cbWritten = 0;
/*
* Validate file handle
*/
if (!(pPdOpenInstance = ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
return(ERROR_INVALID_HANDLE);
}
/*
* Get port structure
*/
pPortInst = pPdOpenInstance->pPortInst;
if (!(pPortInst) ) {
return(ERROR_INVALID_HANDLE);
}
/*
* Issue FLUSH IOCtl to clear any data in PAR1284 kernel device driver
*
* Note: It is possible that data other than for this job could
* be flushed since the kernel device driver does not
* keep track of job boundaries, therefore the flush IOCtl
* is not sent!
*/
/*
* If any reset data, send it after flushing our buffers
*/
if (cbData) {
rc = PdWrite(pPortInst, pchData, cbData, &cbWritten);
}
/*
* Reset flag indicating job aborted
*/
EnterPdrSem();
ulJobPrinting = pPortInst->ulJobPrinting;
pPortInst->ulJobPrinting = PDR_ABORTED;
LeavePdrSem();
/*
* Only release semaphore if needed
*/
if (ulJobPrinting == PDR_PRINTING) {
rc = DosReleaseMutexSem ( pPortInst->hPortSem );
}
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDABORT))
{
sprintf( logbuf,
"SplPdAbortDoc rc=%d cbWritten=%d\r\n",
rc, cbWritten );
LogCall( logbuf );
}
}
#endif /* DEBUG */
return(rc);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdNewPage - EXTERNAL API
*
* DESCRIPTION = notify port driver that another print page is being sent to
* the printer
*
*
* INPUT = hDevice - handle from SplPdOpen
* ulPageNumber - page number to be sent next
* Starts with page 1
*
* OUTPUT = 0 - successful.
* Valid hDevice, spooler updated job with page number
*
* ERROR_INVALID_HANDLE - invalid hDevice given
*
* Other - failure from port driver.
*
****************************************************************************/
ULONG APIENTRY SplPdNewPage ( HFILE hFile, ULONG ulPageNumber )
{
/*
* Validate file handle
*/
if (!(ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
return(ERROR_INVALID_HANDLE);
}
/*
* Spooler sets job "Sent to printer" pij->page number.
* This port driver does not use pagessent value.
*/
return 0;
}
/****************************************************************************
*
* FUNCTION NAME = SplPdClose - EXTERNAL API
*
* DESCRIPTION = close a printer device opened with SplPdOpen
*
*
*
* INPUT = hDevice - handle from SplPdOpen
*
* OUTPUT = 0 - successful.
* SplPdOpen handle freed; the port may be opened again
* with SplPdOpen()
*
* Other - error code, close failed.
* If not ERROR_INVALID_HANDLE then caller should
* reissue SplPdClose().
*
* NOTES: If SplPdWrite data buffered, this outputs data before closing.
* If error outputting data, issue SplMessageBox(and retry)
*
****************************************************************************/
ULONG APIENTRY SplPdClose( HFILE hFile )
{
ULONG rc;
ULONG ulJobPrinting;
PPDOPENINST pPdOpenInstance ;
PPORTINST pPortInst;
PRTJOB PrtJob;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
{
sprintf( logbuf,
"SplPdClose hFile=%lX\r\n",
hFile);
LogCall( logbuf );
}
}
#endif /* DEBUG */
/*
* Validate file handle
*/
if (!(pPdOpenInstance = ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
return(ERROR_INVALID_HANDLE);
}
/*
* Reset flag indicating no job printing
*/
EnterPdrSem();
pPortInst = pPdOpenInstance->pPortInst;
if (!(pPortInst) || (pPortInst->signature != PT_SIGNATURE) ) {
rc = ERROR_FILE_NOT_FOUND;
pPortInst = NULL;
} else {
/*
** Clear JOB_PRINTING flag BEFORE sending ENDJOB to allow sending
** the BIDI_ENDJOB sequence.
*/
ulJobPrinting = pPortInst->ulJobPrinting;
pPortInst->ulTimeLastJob = time();
pPortInst->ulJobPrinting = PDR_NOT_PRINTING;
/*
* Only release semaphore if needed
*/
if (ulJobPrinting == PDR_PRINTING) {
rc = DosReleaseMutexSem ( pPortInst->hPortSem );
}
}
if (pPortInst && !(pPortInst->flStatus & PF_Q_PORT_CALLED))
{
/*
** We close connection at end of each job ONLY if
** bidi is not enabled(never received BIDI_Q_PORT)
*/
PdClose( pPortInst );
}
/*
* if DosClose fails @BUGBUG
* for now return 0 and assume the port can be reopened
*/
if (rc) {
rc = 0;
}
/*
* Send end job command
*/
#ifdef BIDI
if (pPortInst && (pPortInst->flStatus & PF_Q_PORT_CALLED)) {
PrtJob.ulInterpreterID = (ULONG)-1;
PrtJob.ulPrinterJobID = (ULONG)-1;
LeavePdrSem();
rc = MyPrtSet ( NULL, pPdOpenInstance->pszPortName, TYPE_LONG_WAIT, BIDI_ENDJOB,
&PrtJob, sizeof(PRTJOB));
EnterPdrSem();
/*
* Reset rc to 0 even if BIDI_ENDJOB doesn't work
*/
rc = 0;
}
#endif
RemovePdOpenInst ( pPdOpenInstance );
FreePdrMem( (PVOID)pPdOpenInstance , pPdOpenInstance->cb );
LeavePdrSem();
DosPostEventSem( hevControl );
return rc;
}
/****************************************************************************
*
* FUNCTION NAME = SplPdQuery - EXTERNAL API
*
* DESCRIPTION = Query information about a print device
*
* INPUT = pszDeviceName - name of port printer is attached
* ulFlags - query options
* ulCommand - function code for query
* pInData - command specific input data
* cbInData - length in bytes of pInData
* pOutData - returned query structure, format depends
* on ulCommand
* pcbOutData - Points to length of pOutData(in bytes)
* On entry this is set to length of buffer
* passed in.
* On exit this is updated with the length
* of available data, which may be more
* than put into pOutData
*
* OUTPUT = 0 - successful.
* *pcbOutData = length of data returned by query
* pOutData = query structure
* 234(ERROR_MORE_DATA) - partial query structure returned
* *pcbOutData = length of buffer required to store
* entire query structure
* pOutData = partial query structure
* 2123(NERR_BufTooSmall) - buffer too small to fit any data
* *pcbOutData = length of buffer required to store
* entire query structure
* pOutData = not updated, since it is much too small
* Other - error code, nothing updated
*
*
*
* NOTE Not in port driver semaphore on entry/exit
*
****************************************************************************/
ULONG APIENTRY SplPdQuery ( PSZ pszDeviceName,
ULONG ulFlags,
ULONG ulCommand,
PVOID pInData,
ULONG cbInData,
PVOID pOutData,
PULONG pcbOutData )
{
ULONG rc;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
#ifdef DEBUG_ALERT
{
PULONG pul;
pul = (PULONG)pInData;
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDQUERY))
{
sprintf( logbuf,
"SplPdQuery on %s Flags=%lX Cmd=%lX cb=%d Data=%lX %lX\r\n",
pszDeviceName, ulFlags, ulCommand, cbInData,
(cbInData >= 4) ? pul[0]:0,
(cbInData >= 8) ? pul[1]:0
);
LogCall( logbuf );
}
}
#endif /* DEBUG */
rc = 0;
#ifdef BIDI
switch (ulCommand) {
case BIDI_Q_PORT:
/*
* Add port to the list of supported ports and return
* the status of the PAR1284 connected printer.
*/
rc = HandleQPort( pszDeviceName,
ulFlags,
pOutData,
pcbOutData );
break;
case BIDI_WAIT_ALERT:
/*
* Read alert, waiting if necessary ( Assume what is returned from
* the PAR1284 kernel driver is complete )
*/
rc = HandleWaitAlert( pszDeviceName,
ulFlags,
ulCommand,
pInData,
cbInData,
pOutData,
pcbOutData );
break;
case BIDI_Q_PORTDRV:
/*
* Check for valid data
*/
if (!pOutData || !pcbOutData ) {
return(ERROR_INVALID_PARAMETER);
}
/*
* Send back PORTSETTINGS structure
*/
rc = HandleQPortDRV ( pszDeviceName,
pOutData,
pcbOutData );
break;
case BIDI_READ_PASSTHRU:
/*
* An application wants to read passthru data from the printer and there
* is no protocol converter used on this port(CNV would get called
* with this command instead of the port driver).
*/
rc = ReadPassthru ( pszDeviceName,
ulFlags,
ulCommand,
pInData,
cbInData,
pOutData,
pcbOutData );
break;
default:
/*
** Let protocol converter handle all other queries.
*/
rc = MySplProtSendCmd ( pszDeviceName,
ulFlags,
ulCommand,
(PFN) SplPdSendCmd,
(PFN) NULL,
pInData,
cbInData,
pOutData,
pcbOutData );
}
#else
rc = ERROR_NOT_SUPPORTED;
#endif // ifdef BIDI
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDQUERY))
{
sprintf( logbuf,
"SplPdQuery on %s rc=%d\r\n",
pszDeviceName,
rc );
LogCall( logbuf );
}
}
#endif /* DEBUG */
return(rc);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdSet - EXTERNAL API
*
* DESCRIPTION = Set printer device information
*
* INPUT = pszDeviceName - name of port printer is attached
* ulFlags - set options
* ulCommand - function code for set command
* pInData - command specific input data
* cbInData - length in bytes of pInData
*
* OUTPUT = 0 - successful.
* Other - error code
*
* NOTE Not in port driver semaphore on entry/exit
*
****************************************************************************/
ULONG APIENTRY SplPdSet ( PSZ pszDeviceName,
ULONG ulFlags,
ULONG ulCommand,
PVOID pInData,
ULONG cbInData )
{
ULONG rc = 0;
PPORTINST pPortInst = NULL;
PPRTSW pPrtSw;
ULONG ulcbOutBuf;
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
#ifdef DEBUG_ALERT
{
PULONG pul;
pul = (PULONG)pInData;
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSET))
{
sprintf( logbuf,
"SplPdSet on %s Flags=%lX Cmd=%lX cb=%d Data=%lX %lX\r\n",
pszDeviceName, ulFlags, ulCommand, cbInData,
(cbInData >= 4) ? pul[0]:0,
(cbInData >= 8) ? pul[1]:0
);
LogCall( logbuf );
}
}
#endif /* DEBUG */
/*
* Check for valid set command
*/
if (ulCommand >= BIDI_READ_PASSTHRU) {
return(ERROR_INVALID_FUNCTION);
}
rc = 0;
pPortInst = NULL;
switch (ulCommand) {
case BIDI_INIT_PORTDRV:
/*
* Create thread to control all LPT ports.
* Move DllInit mem init routine here @BUGBUG
*/
CreateControlThread();
break;
#ifdef BIDI
case BIDI_RESET:
//
// Reset printer - done by protocol converter
//
break;
case BIDI_SHUTDOWN:
/*
** Wake up control thread to begin termination
*/
fShutdownInProgress = TRUE;
DosPostEventSem(hevControl);
/*
** This should wait until all threads are shutdown
** because the spooler process will terminate when
** this returns.
** If this does not return within 25 seconds, the spooler
** process will terminate anyway without letting us
** complete our shutdown.
*/
break;
case BIDI_INIT:
//
// Change printer from Uni to Bidirectional - currently not needed
//
break;
case BIDI_TERM:
//
// Change printer from Bidirectional to Uni - currently not needed
//
break;
case BIDI_RESPONSE_FMT:
/*
* Set format of printer-to-host response = currently not used
*/
break;
case BIDI_PACKET_SIZE:
/*
* Set printer-to-host max packet size = currently not used
*/
break;
case BIDI_SET_SW:
/*
* Gives software capabilities of attached bidi printer
*/
if (!pInData || cbInData < sizeof(PRTSW)) {
return(ERROR_INVALID_PARAMETER);
}
/*
* Find port instance
*/
EnterPdrSem();
pPortInst = FindPortInst ( pszDeviceName );
if (pPortInst) {
/*
* Set Port Driver variables
*/
pPrtSw = (PPRTSW) pInData;
pPortInst->flJob = pPrtSw->flJob;
pPortInst->flDevice = pPrtSw->flDevice;
} else {
rc = ERROR_FILE_NOT_FOUND;
}
LeavePdrSem();
break;
case BIDI_SET_PORTDRV:
/*
* Save port settings
*/
if (!pInData || cbInData < sizeof(PPORTSETTINGS)) {
return(ERROR_INVALID_PARAMETER);
}
/*
* Save PORTSETTINGS structure
*/
rc = HandleSetPortDRV ( pszDeviceName,
pInData,
cbInData );
break;
case BIDI_NOTIFY_ENDJOBCONNECT:
/*
* Spooler no longer waiting for any job confirmations from port
* This could be used to drop a job-based connection quicker
* than the timeouts used in ControlThread.
*/
break;
case BIDI_NOTIFY_PORT_SELECTED:
/*
* Spooler tells port driver that this port is connected to a print queue
* We could pay more attention to this output port than
* one not connected to a print queue.
*/
break;
case BIDI_NOTIFY_PORT_RELEASED:
/*
* Spooler tells port driver this port is no longer connected
* to a print queue. We could pay less attention to this
* output port now that it is not connected to a queue.
*/
break;
case BIDI_ADD_VIRTUAL_PORT:
/*
* An application requested a virtual port to get information from
* this port driver. This is useful if an App wants the
* port driver to enumerate or find printers on the network wire.
* The buffer passed in is port-driver specific.
* The PAR1284 port driver does not support this.
*/
rc = ERROR_NOT_SUPPORTED;
break;
case BIDI_DEL_VIRTUAL_PORT:
/*
* An application wants to delete a virtual port it has previously
* created. This is done in response to SplDeletePort() for
* a virtual port.
* The PAR1284 port driver does not support virtual ports.
*/
rc = ERROR_NOT_SUPPORTED;
case BIDI_DEL_PORT:
/*
* A port belonging to this port driver was removed from the System INI.
* It may have been this port driver that removed it( SplPdRemovePort ).
* We can free our instance data for this port now.
* Be certain that any reference to the PORTINST structures
* allow for deleting a PORTINST.
* Since we only support LPT1-3, we don't actually remove any
* port from our instance list.
*/
break;
case BIDI_START_PASSTHRU:
/*
* An application wants a passthru session and there is no
* protocol converter used on this port(CNV would get called
* with this command instead of the port driver).
*/
rc = StartPassthru( pszDeviceName,
ulFlags,
ulCommand,
pInData,
cbInData );
break;
case BIDI_SEND_PASSTHRU:
/*
* An application wants to send passthru data to the printer and there
* is no protocol converter used on this port(CNV would get called
* with this command instead of the port driver).
*/
rc = SendPassthru( pszDeviceName,
ulFlags,
ulCommand,
pInData,
cbInData );
break;
case BIDI_END_PASSTHRU:
/*
* An application wants to end a passthru session with the printer and
* there is no protocol converter used on this port(CNV would get
* called with this command instead of the port driver).
*/
rc = EndPassthru( pszDeviceName,
ulFlags,
ulCommand,
pInData,
cbInData );
break;
#endif // #ifdef BIDI
default:
#ifdef BIDI
/*
** Let protocol converter handle any other set command
*/
ulcbOutBuf = 0;
rc = MySplProtSendCmd ( pszDeviceName,
ulFlags,
ulCommand,
(PFN) SplPdSendCmd,
(PFN) NULL,
pInData,
cbInData,
NULL,
&ulcbOutBuf );
#else
rc = ERROR_NOT_SUPPORTED;
#endif // #ifdef BIDI
}
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSET))
{
sprintf( logbuf,
"SplPdSet on %s rc=%d\r\n",
pszDeviceName,
rc );
LogCall( logbuf );
}
}
#endif /* DEBUG */
return(rc);
}
/****************************************************************************
*
* FUNCTION NAME = SplPdSendCmd - EXTERNAL API
*
* DESCRIPTION = Send protocol specific commands to the printer
*
*
* INPUT = pszDeviceName - name of port printer is attached
* ulFlags - query/set options
* Only channel currently for the PAR1284 port is data
* ulCommand - function code for query/set
* pInData - command specific input data
* cbInData - length in bytes of pInData
*
* OUTPUT = 0 - successful.
* Other - error code, nothing updated
*
* NOTE Not in port driver semaphore on entry/exit
* If cbInData is 0, just check ulCommand value
*
****************************************************************************/
#ifdef BIDI
ULONG APIENTRY SplPdSendCmd( PSZ pszDeviceName,
ULONG ulFlags,
ULONG ulCommand,
PVOID pInData,
ULONG cbInData )
{
ULONG rc;
PPORTINST pPortInst;
PBYTE pBufToSend; /* -> buffer to give to PdWrite */
ULONG cbWritten;
ULONG cbWrite;
ULONG ulPortTimeout ; /* timeout for this port */
ULONG ulTime ; /* time prior to issuing DosWrite call */
#ifdef DEBUG_ALERT
char logbuf[260];
#endif
#ifdef DEBUG_ALERT
{
PULONG pul;
pul = (PULONG)pInData;
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
{
sprintf( logbuf,
"SplPdSendCmd on %s Flags=%lX Cmd=%lX cb=%d Data=%lX %lX\r\n",
pszDeviceName, ulFlags, ulCommand, cbInData,
(cbInData >= 4) ? pul[0]:0,
(cbInData >= 8) ? pul[1]:0
);
LogCall( logbuf );
/*
* Dump out the Bidi commands we are going to send to
* the printer when in debug mode
*/
DumpHex( (PBYTE)pInData, cbInData );
}
}
#endif /* DEBUG */
rc = 0;
/*
* Get port instance
*/
EnterPdrSem();
pPortInst = AddPortInst ( pszDeviceName );
if (!pPortInst) {
rc = ERROR_FILE_NOT_FOUND;
} else {
/*
* Here we could check for whether a job is printing or not @BUGBUG
* For now, we allow commands to be sent to the printer
* while sending a print job because some protocol converters
* packetize job data writes.
* For those protocol converters that do not allow sending commands
* to the printer while in the middle of sending a print job, the
* converter must ensure it does not try to send a command
* use SplPdSendCmd().
*/
//if (pPortInst->ulJobPrinting == PDR_PRINTING ) {
// //
// // Since there is only one channel to the printer
// // we cannot send commands while in the middle of sending
// // a print job
// // We handle BIDI_STARTJOB and BIDI_ENDJOB by not setting
// // the port status to PDR_PRINTING until AFTER STARTJOB
// // and clearing it BEFORE ENDJOB.
// //
// if (!(ulFlags & FLG_SYNCH) || !(ulFlags & FLG_MUSTCOMPLETE)) {
// rc = ERROR_INFO_NOT_AVAIL;
// }
//}
}
LeavePdrSem();
if (rc) {
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
{
sprintf( logbuf,
"SplPdSendCmd on %s rc=%d %lX\r\n",
pszDeviceName, rc );
LogCall( logbuf );
}
}
#endif /* DEBUG */
return(rc);
}
rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
/*
* If we wanted to hold the caller until the current job data was @BUGBUG
* sent to the printer, the following bit of code would do it:
*/
// /*
// * Loop until there is no job data being sent to the printer
// * variable is reset.
// */
// while (pPortInst->ulJobPrinting == PDR_PRINTING) {
// rc = DosReleaseMutexSem ( pPortInst->hPortSem );
// DosSleep(500);
// rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
// }
EnterPdrSem();
/*
** Set TimeLastCmd so that we don't close this
** port from our ControlThread
*/
pPortInst->ulTimeLastCmd = time();
/*
** open PAR1284 device if not yet opened
*/
if ( !rc && !(pPortInst->flStatus & PF_PORT_OPEN) ) {
rc = PdOpen(pPortInst);
}
LeavePdrSem();
if (rc) {
DosReleaseMutexSem ( pPortInst->hPortSem );
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
{
sprintf( logbuf,
"SplPdSendCmd on %s rc=%d %lX\r\n",
pszDeviceName, rc );
LogCall( logbuf );
}
}
#endif /* DEBUG */
return(rc);
}
/*
* Save time prior to issuing DosWrite
* If write fails before printer timeout expired
* retry the request.
*/
cbWrite = 0;
cbWritten = 0;
ulTime = time() ;
/*
** Some 32-bit linear addresses are not handled well by DosWrite
** (all pages have to be able to be locked by the filesystem).
** To ensure we do not get rc=5(ACCESS_DENIED) from DosWrite
** we copy the data out to a separately allocated buffer,
** and pass this buffer to DosWrite.
** We only do this for SplPdSendCmd() because our 32-bit print
** drivers(callers of SplPdWrite) already handle this.
**/
if ((cbInData <= DEFAULT_BUFSIZE) && pPortInst->pbWriteBuf) {
memcpy( pPortInst->pbWriteBuf, pInData, cbInData );
pBufToSend = pPortInst->pbWriteBuf;
} else {
pBufToSend = pInData;
}
rc = PdWrite( pPortInst, pBufToSend, cbInData, &cbWrite );
if (rc || ( cbWrite != cbInData ) ) {
/*
* Check time it took to issue write
* If this is a known port
* there is a timeout for the port
* and the time it took to do the DosWrite was
* less than (PortTimeout - 1)
* then
* Retry Request
*/
if ( (ulPortTimeout = pPortInst->ulPrintTimeOut) &&
( (time() - ulTime) < (ulPortTimeout - 1) )) {
/*
* Keep track of total bytes written
* Reset clock if DosWrite succeeded without writting all bytes
* Retry request
*/
cbWritten = cbWrite ;
do
{
if ( (rc == 0) && ( cbWrite ) ) {
/*
* if DosWrite successful and bytes were written
* reset timeout value
*/
ulTime = time() ;
}
/* Sleep one second to avoid hard loop on DosWrite */
DosSleep(1000) ;
cbWrite = 0 ; /* reset bytes written */
/*
* Write buffer, taking into account bytes written so far
*/
rc = PdWrite( pPortInst,
(PVOID)((PBYTE)pBufToSend + cbWritten),
/* index past bytes written */
cbInData - cbWritten,/* only write remaining data */
&cbWrite );
cbWritten += cbWrite ;
} while ( (cbWritten < cbInData) &&
( (time() - ulTime) < (ulPortTimeout - 1) )) ;
}
} /* end giving retry */
/*
** Set TimeLastCmd so that we don't close this
** port from our ControlThread until necessary.
** Wakeup control thread if it is waiting indefinitely.
** This is done to ensure we close the port
** when only query commands are sent to it.
** The control thread will just check this port,
** then reset its eventSem timeout to the next time
** it should check this port.
** This is done because we never know when the last
** query buffer for a port is coming.
*/
pPortInst->ulTimeLastCmd = time();
if (!fControlWakeupPending)
{
DosPostEventSem(hevControl);
}
DosReleaseMutexSem ( pPortInst->hPortSem );
/*
** Wakeup ParReadThread so we can get the response
** to the command we just sent.
*/
DosPostEventSem(pPortInst->hevReadThread);
#ifdef DEBUG_ALERT
{
if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
{
sprintf( logbuf,
"SplPdSendCmd on %s rc=%d %lX\r\n",
pszDeviceName, rc );
LogCall( logbuf );
}
}
#endif /* DEBUG */
return(rc);
}
#endif // ifdef BIDI