home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / spldapi.zip / pdrapi.c
C/C++ Source or Header  |  1997-10-09  |  67KB  |  2,169 lines

  1. /**************************************************************************
  2.  *
  3.  * SOURCE FILE NAME = pdrapi.c
  4.  *
  5.  * DESCRIPTIVE NAME = parallel port driver exported SplPd APIs
  6.  *
  7.  * Copyright : COPYRIGHT IBM CORPORATION, 1994, 1995
  8.  *             LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
  9.  *             REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
  10.  *             RESTRICTED MATERIALS OF IBM
  11.  *             IBM CONFIDENTIAL
  12.  *
  13.  * VERSION = V2.2
  14.  *
  15.  * DATE
  16.  *
  17.  * DESCRIPTION
  18.  *
  19.  *
  20.  * FUNCTIONS
  21.  *
  22.  * ENTRY POINTS:
  23.  *
  24.  * DEPENDENCIES:
  25.  *
  26.  * NOTES
  27.  *
  28.  *
  29.  * STRUCTURES
  30.  *
  31.  * EXTERNAL REFERENCES
  32.  *
  33.  * EXTERNAL FUNCTIONS
  34.  *
  35.  * CHANGE ACTIVITY =
  36.  *  DATE      FLAG        APAR   CHANGE DESCRIPTION
  37.  *  --------  ----------  -----  --------------------------------------
  38.  *  mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
  39.  ****************************************************************************/
  40.  
  41. #include    "pdrconst.h"
  42. #include    "pdrtypes.h"
  43. #include    "pdrproto.h"
  44.  
  45. #define     BIDI_TEST_RESP      0x9000
  46.  
  47. /*
  48. ** SPLPD functions that can be called by ANY process, not just the spooler
  49. */
  50. /****************************************************************************
  51.  *
  52.  * FUNCTION NAME = SplPdEnumPort
  53.  *
  54.  * DESCRIPTION   = Return ports supported by this port driver
  55.  *                 Currently this will return those ports this port
  56.  *                  driver supports by default.
  57.  *                 The print object only calls this if the port
  58.  *                  driver does not export the extended attribute
  59.  *                  "DEFAULT_PORT"
  60.  *
  61.  * INPUT         = hab - anchor block handle
  62.  *                 pBuf - buffer to get enumerated PORTNAMES structures
  63.  *                 cbBuf - size(in bytes) of pBuf passed in
  64.  *
  65.  * OUTPUT        = *pulReturned - number of PORTNAMES structures stored in pBuf
  66.  *                 *pulTotal    - total ports supported by this port driver
  67.  *                 *pcbRequired - size(in bytes) of buffer needed to store
  68.  *                                all enumerated PORTNAMES entries.
  69.  *                 pBuf - gets an array(number elements is *pulReturned) of
  70.  *                        PORTNAMES structures.
  71.  *                        Each psz in PORTNAMES structure points to a string
  72.  *                        copied into the end of pBuf.
  73.  *
  74.  *                 typedef struct _PORTNAMES {
  75.  *                         PSZ pszPortName;  // Name of port, example: PAR1284
  76.  *                         PSZ pszPortDesc;  // Port description
  77.  *                 } PORTNAMES;
  78.  *
  79.  * RETURN-NORMAL = 0 - if all portnames and descriptions fit in pBuf
  80.  *
  81.  * RETURN-ERROR  = ERROR_INSUFFICIENT_BUFFER - if no PORTNAMES structs
  82.  *                                             could fit in buffer.  Caller
  83.  *                                             uses *pcbRequired to allocate
  84.  *                                             a buffer big enough to store all
  85.  *                                             port names.
  86.  *                 ERROR_MORE_DATA - if some, but not all, PORTNAMES structs
  87.  *                                   could fit in buffer.  Caller
  88.  *                                   uses *pcbRequired to allocate
  89.  *                                   a buffer big enough to store all
  90.  *                                   port names.
  91.  *
  92.  ****************************************************************************/
  93.  
  94. APIRET APIENTRY SplPdEnumPort ( HAB hab,
  95.                                 PVOID pBuf,
  96.                                 ULONG cbBuf,
  97.                                 PULONG pulReturned,
  98.                                 PULONG pulTotal,
  99.                                 PULONG pcbRequired )
  100.  
  101. {
  102.       /*
  103.       ** ensure pointers not null
  104.       */
  105.    if (!pulReturned ||
  106.        !pulTotal ||
  107.        !pcbRequired)
  108.    {
  109.       return(ERROR_INVALID_PARAMETER);
  110.    }
  111.  
  112.       /*
  113.       ** if buffer length is supplied then there should be pBuf
  114.       */
  115.    if (!pBuf && cbBuf)
  116.    {
  117.       return(ERROR_INVALID_PARAMETER);
  118.    }
  119.  
  120.       /*
  121.       ** check if cbBuf is 0 - then return number of ports in pulTotal
  122.       ** and number of bytes required in pcbRequired
  123.       */
  124.    if (cbBuf == 0L)
  125.    {
  126.       *pulReturned = 0;
  127.       *pcbRequired = CalcBufLength ( hab );
  128.       *pulTotal    = 3 ;            /* Currently support PAR1284 */
  129.            /*
  130.            ** NOTE: early version of the print object checked for
  131.            **       ERROR_MORE_DATA instead of ERROR_INSUFFICIENT_BUFFER
  132.            **       For this reason we return ERROR_MORE_DATA here.
  133.            */
  134.         return(ERROR_MORE_DATA);
  135.    }
  136.  
  137.       /*
  138.       ** check number of ports info we can fit in supplied buffer
  139.       */
  140.    *pulTotal    = 3 ; /* Currently support PAR1284 */
  141.    *pcbRequired = CalcBufLength ( hab );
  142.    *pulReturned = NumPortsCanFit ( hab, cbBuf);
  143.  
  144.       /*
  145.       ** return error if we can not fit one port.
  146.       */
  147.    if (!(*pulReturned))
  148.    {
  149.       return(ERROR_INSUFFICIENT_BUFFER);
  150.    }
  151.  
  152.       /*
  153.       ** copy all the ports which we can store in the pBuf
  154.       */
  155.    CopyNPorts (hab, (PCH)pBuf, *pulReturned);
  156.  
  157.       /*
  158.       ** copy all the ports which we can store in the pBuf
  159.       */
  160.    if (*pulReturned < *pulTotal)
  161.    {
  162.       return(ERROR_MORE_DATA);
  163.    }
  164.  
  165.    return(NO_ERROR);
  166. }
  167.  
  168. /****************************************************************************
  169.  *
  170.  * FUNCTION NAME = SplPdInstallPort
  171.  *
  172.  * DESCRIPTION   = Install a new port for this port driver.
  173.  *
  174.  *                 The print object calls this when user selects to install
  175.  *                   a new printer port.  The portname given might be the
  176.  *                   name from the "DEFAULT_PORT" extended attribute of
  177.  *                   the port driver file, in which case this port driver
  178.  *                   can generate a new port name to install.
  179.  *                 If this port driver cannot find any printer it
  180.  *                   can communicate with, it should return
  181.  *                   ERROR_PRINT_CANCELLED to make sure the print object
  182.  *                   does not put up "Port Installed" message.
  183.  *
  184.  *                 The print object will not call SplPdSetPort after
  185.  *                   this.  Each port driver has the option to
  186.  *                   bring up their SplPdSetPort dialog during processing
  187.  *                   of this call to allow users to select the printer
  188.  *                   they wish to connect with(and possibly change the
  189.  *                   name of the print port they are installing).
  190.  *
  191.  * INPUT         = hab         - Anchor block handle
  192.  *                 pszPortName - name of port to be installed
  193.  *
  194.  * OUTPUT        =
  195.  *
  196.  * RETURN-NORMAL = 0
  197.  *
  198.  * RETURN-ERROR  = ERROR_INVALID_PARAMETER - if bad port name given
  199.  *                 ERROR_PRINT_CANCELLED - port not installed
  200.  *
  201.  ****************************************************************************/
  202.  
  203. APIRET APIENTRY SplPdInstallPort ( HAB hab,
  204.                                    PSZ pszPortName )
  205. {
  206.    CHAR           chBuf[CCHMAXPATH];
  207.    CHAR           chPortDesc[STR_LEN_PORTDESC];
  208.    PPORTDLGSTRUCT pPortDlgStruct;
  209.    ULONG          rc;
  210.    BOOL           fSuccess;
  211.    #ifdef DEBUG_ALERT
  212.      char logbuf[260];
  213.    #endif
  214.  
  215.  
  216.    /*
  217.    ** Check if port name string is NULL. This is an error.
  218.    */
  219.    if (!pszPortName)
  220.    {
  221.       return(ERROR_INVALID_PARAMETER);
  222.    }
  223.  
  224.    /*
  225.    ** Make Application name string "PM_Port Name"
  226.    */
  227.    strcpy (chBuf, APPNAME_LEAD_STR);
  228.    strcat (chBuf, pszPortName);
  229.  
  230.    /*
  231.    ** Check for this being our default Port Name to install
  232.    ** If so(pszPortName == "LPT") then generate a unique
  233.    **   port name so that we can install multiple IR printers.
  234.    */
  235.    if (!strcmp(pszPortName, DEF_PORTNAME))
  236.    {
  237.       /*
  238.       ** Use chBuf to store the new portname to install
  239.       ** Must first increment past "PM_" in chBuf
  240.       */
  241.       pszPortName = chBuf + 3;
  242.       GenerateUniquePortName( pszPortName );
  243.    }
  244.  
  245.    /*
  246.    ** Check if we have description for port
  247.    */
  248.    if (!GetPortDescription (hab, pszPortName, chPortDesc))
  249.    {
  250.       /*
  251.       ** Port description not found, use port name
  252.       */
  253.       strcpy( chPortDesc, pszPortName );
  254.    }
  255.  
  256.    /*
  257.    ** Write data for this port in ini file with new format.
  258.    */
  259.    PrfWriteProfileString (HINI_SYSTEMPROFILE,
  260.                           chBuf,
  261.                           KEY_DESCRIPTION,
  262.                           chPortDesc);
  263.  
  264.    PrfWriteProfileString (HINI_SYSTEMPROFILE,
  265.                           chBuf,
  266.                           KEY_TIMEOUT_QUERY,
  267.                           DEF_TIMEOUT_QUERY);
  268.  
  269.    PrfWriteProfileString (HINI_SYSTEMPROFILE,
  270.                           chBuf,
  271.                           KEY_TIMEOUT_JOB,
  272.                           DEF_TIMEOUT_JOB);
  273.  
  274.    PrfWriteProfileString (HINI_SYSTEMPROFILE,
  275.                           chBuf,
  276.                           KEY_PORTDRIVER,
  277.                           DEF_PORTDRIVER);
  278.  
  279.    /*
  280.    ** Write data for this port in ini file with old format.
  281.    ** This call will add pszPortName as a selectable port
  282.    **   from the print object "Output Port" settings page.
  283.    */
  284.    fSuccess = PrfWriteProfileString (HINI_SYSTEMPROFILE,
  285.                                      APPNAME_PM_SPOOLER_PORT,
  286.                                      pszPortName,
  287.                                      DEF_OLD_INITIALIZATION);
  288.    if (!fSuccess)
  289.    {
  290.       /*
  291.       ** Unable to add the new port
  292.       */
  293.       DBPRINTF ((logbuf, "SplPdInstallPort Unable to add PM_SPOOLER_PORT(%s)", pszPortName));
  294.       return( ERROR_INVALID_PARAMETER );
  295.    }
  296.    /*
  297.    ** rewrite portdriver connection - fix for old spooler
  298.    */
  299.    PrfWriteProfileString (HINI_SYSTEMPROFILE,
  300.                           chBuf,
  301.                           KEY_PORTDRIVER,
  302.                           DEF_PORTDRIVER);
  303.  
  304.    /*
  305.    ** Now that the port has been added we can
  306.    **   display the settings dialog to let the user
  307.    **   select the settings for this printer port.
  308.    **
  309.    ** First allocate a port driver dialog structure
  310.    */
  311.    pPortDlgStruct = NULL;
  312.    rc = DosAllocMem((PVOID)&pPortDlgStruct,
  313.                     sizeof(PORTDLGSTRUCT),
  314.                     PAG_READ | PAG_WRITE | PAG_COMMIT);
  315.    if (rc)
  316.    {
  317.       DBPRINTF ((logbuf, "SplPdInstallPort DosAllocMem failed rc=%d",rc));
  318.       return(rc);
  319.    }
  320.    /*
  321.    ** Give user dialog to connect to a new printer
  322.    */
  323.    memset (pPortDlgStruct, 0, sizeof (PORTDLGSTRUCT));
  324.    pPortDlgStruct->signature = PDLG_SIGNATURE;
  325.    pPortDlgStruct->hAB = hab ;
  326.    pPortDlgStruct->hModule = hPdrMod ;
  327.    pPortDlgStruct->pszPortName = pszPortName ;
  328.  
  329.    /*
  330.    ** Load the dialog for user to change.
  331.    */
  332.    OpenPar1284PortDlg (hab, pPortDlgStruct);
  333.  
  334.    DosFreeMem( pPortDlgStruct );
  335.    DBPRINTF ((logbuf, "SplPdInstallPort Successful(%s)", pszPortName));
  336.  
  337.    return(NO_ERROR);
  338. }
  339.  
  340. /****************************************************************************
  341.  *
  342.  * FUNCTION NAME = SplPdGetPortIcon
  343.  *
  344.  * DESCRIPTION   = Return Resource ID of icon representing this port.
  345.  *                 Note: only one icon will represent all ports supported
  346.  *                       by a port driver.
  347.  *
  348.  * INPUT         = hab         - Anchor block handle
  349.  *                 idIcon      - gets Resource ID of icon bit map
  350.  *
  351.  * OUTPUT        =
  352.  *
  353.  * RETURN-NORMAL = TRUE
  354.  *
  355.  * RETURN-ERROR  = FALSE - if unable to return icon Resource ID
  356.  *
  357.  ****************************************************************************/
  358.  
  359. BOOL   APIENTRY SplPdGetPortIcon ( HAB hab,
  360.                                    PULONG idIcon )
  361. {
  362.       /*
  363.       ** Check for our global port icon ID(is always set)
  364.       */
  365.    if (idIcon)
  366.    {
  367.       *idIcon = PAR1284_ICON;
  368.    }
  369.    return(TRUE);
  370. }
  371.  
  372. /****************************************************************************
  373.  *
  374.  * FUNCTION NAME = SplPdQueryPort
  375.  *
  376.  * DESCRIPTION   = Returns textual data that describes the port configuration.
  377.  *
  378.  * INPUT         = hab         - Anchor block handle
  379.  *                 pszPortName - name of port to get configuration for
  380.  *                 pBufIn      - pointer to buffer of returned data structures
  381.  *                 cbBuf       - Size of pBufIn in bytes
  382.  *                 cItems      - Count of number of strings of descriptions
  383.  *                               returned
  384.  *
  385.  * OUTPUT        =
  386.  *
  387.  * RETURN-NORMAL = 0
  388.  *
  389.  * RETURN-ERROR  = ERROR_INSUFFICIENT_BUFFER - if buffer is too small
  390.  *                 ERROR_INVALID_PARAMETER - if bad port name given
  391.  *
  392.  ****************************************************************************/
  393.  
  394. APIRET APIENTRY SplPdQueryPort ( HAB hab,
  395.                                  PSZ pszPortName,
  396.                                  PVOID pBufIn,
  397.                                  ULONG cbBuf,
  398.                                  PULONG cItems )
  399. {
  400.    CHAR chString[STR_LEN_DESC];
  401.    USHORT usNumLines;
  402.    USHORT usLineID;
  403.    USHORT usStrLength;
  404.    PCH    pBuf = (PCH)pBufIn;
  405.  
  406.       /*
  407.       ** check pointer to all the return variables is not null
  408.       */
  409.    if (!cItems)
  410.    {
  411.       return(ERROR_INVALID_PARAMETER);
  412.    }
  413.  
  414.       /*
  415.       ** if pBuf or cbBuf is NULL - it is an error.
  416.       */
  417.    if (!pBuf || !cbBuf)
  418.    {
  419.       return(ERROR_INVALID_PARAMETER);
  420.    }
  421.  
  422.    chString[0] = '\0' ;
  423.  
  424.       /*
  425.       ** get number of lines.
  426.       */
  427.    WinLoadString(hab, hPdrMod, (USHORT)ID_NUMBER_OF_DESC_LINES, STR_LEN_DESC,
  428.                  chString);
  429.    usNumLines = (USHORT)atoi (chString);
  430.    usLineID = ID_FIRST_DESC_LINES;
  431.    for (*cItems = 0; *cItems < usNumLines; *cItems++)
  432.    {
  433.       WinLoadString(hab, hPdrMod, usLineID, STR_LEN_DESC, chString);
  434.       if (cbBuf >= (usStrLength = (USHORT)(strlen (chString) + 1)))
  435.       {
  436.          strcpy (pBuf, chString);
  437.          pBuf += usStrLength;
  438.          cbBuf -= usStrLength;
  439.       }
  440.       else
  441.       {
  442.          return(ERROR_INSUFFICIENT_BUFFER);
  443.       }
  444.    }
  445.    return(NO_ERROR);
  446.  
  447. }
  448.  
  449. /****************************************************************************
  450.  *
  451.  * FUNCTION NAME = SplPdRemovePort
  452.  *
  453.  * DESCRIPTION   = Tells port driver the name of a port that needs to be removed.
  454.  *                 Port driver should remove its data from the INI file.
  455.  *
  456.  * INPUT         = hab         - Anchor block handle
  457.  *                 pszPortName - name of port to be removed
  458.  *
  459.  * OUTPUT        =
  460.  *
  461.  * RETURN-NORMAL = 0
  462.  *
  463.  * RETURN-ERROR  = ERROR_INVALID_PARAMETER - if bad port name given
  464.  *
  465.  ****************************************************************************/
  466.  
  467. APIRET APIENTRY SplPdRemovePort ( HAB hab,
  468.                                   PSZ pszPortName )
  469. {
  470.     CHAR chBuf[STR_LEN_PORTNAME];
  471.     CHAR chPortDriver[STR_LEN_PORTNAME];
  472.     BOOL fSuccess;
  473.     #ifdef DEBUG_ALERT
  474.       CHAR logbuf[260];
  475.     #endif
  476.  
  477.       /*
  478.       ** Check if port name string is NULL. This is an error.
  479.       */
  480.    if (!pszPortName)
  481.    {
  482.       return(ERROR_INVALID_PARAMETER);
  483.    }
  484.  
  485.    /*
  486.     * Remove port from port list
  487.     * Must free all threads waiting for this port @BUGBUG
  488.     */
  489.   EnterPdrSem();
  490.     RemovePortInst ( pszPortName );
  491.   LeavePdrSem();
  492.  
  493.       /*
  494.       ** Make Application name string.
  495.       */
  496.    strcpy (chBuf, APPNAME_LEAD_STR);
  497.    strcat (chBuf, pszPortName);
  498.  
  499.       /*
  500.       ** Check if this port is PAR1284 port.
  501.       */
  502.    if (!(PrfQueryProfileString (HINI_SYSTEMPROFILE, chBuf,
  503.                                 KEY_PORTDRIVER, NULL, chPortDriver,
  504.                                 STR_LEN_PORTNAME)))
  505.    {
  506.       DBPRINTF ((logbuf, "SplPdRemovePort failed - no portdriver in INI(%s)", pszPortName));
  507.       return(ERROR_INVALID_PARAMETER);
  508.    }
  509.  
  510.    if (strcmp (chPortDriver, DEF_PORTDRIVER))
  511.    {
  512.       DBPRINTF ((logbuf, "SplPdRemovePort failed - wrong portdriver in INI(%s)", pszPortName));
  513.       return(ERROR_INVALID_PARAMETER);
  514.    }
  515.  
  516.       /*
  517.       ** We found port to be removed.
  518.       ** Remove INI entries for "PM_portname"
  519.       */
  520.    PrfWriteProfileString (HINI_SYSTEMPROFILE, chBuf, NULL, NULL);
  521.  
  522.       /*
  523.       ** remove this port from selectable ports in the print object
  524.       */
  525.    fSuccess = PrfWriteProfileString (HINI_SYSTEMPROFILE,
  526.                                      APPNAME_PM_SPOOLER_PORT,
  527.                                      pszPortName,
  528.                                      NULL);
  529.    DBPRINTF ((logbuf, "SplPdRemovePort removing %s from INI fSuccess=%d", pszPortName, fSuccess));
  530.  
  531.    return(NO_ERROR);
  532.  
  533. }
  534.  
  535. /****************************************************************************
  536.  *
  537.  * FUNCTION NAME = SplPdSetPort
  538.  *
  539.  * DESCRIPTION   = Display a dialog to allow the user to browse and modify
  540.  *                 port configurations.
  541.  *
  542.  * INPUT         = hab         - Anchor block handle
  543.  *                 pszPortName - name of port to configure
  544.  *                 flModified  - Flag to indicate that the configuration
  545.  *                               has been modified.(TRUE if modified).
  546.  *
  547.  * OUTPUT        =
  548.  *
  549.  * RETURN-NORMAL = 0
  550.  *
  551.  * RETURN-ERROR  = ERROR_INVALID_PARAMETER - if bad port name given
  552.  *
  553.  ****************************************************************************/
  554.  
  555. APIRET APIENTRY SplPdSetPort ( HAB hab,
  556.                                PSZ pszPortName,
  557.                                PULONG flModified )
  558. {
  559.    ULONG          rc;
  560.    PPORTDLGSTRUCT pPortDlgStruct;
  561.    #ifdef DEBUG_ALERT
  562.      char logbuf[260];
  563.    #endif
  564.  
  565.  
  566.       /*
  567.       ** Check if port name string is NULL. This is an error.
  568.       */
  569.    if (!pszPortName || !flModified)
  570.    {
  571.       return(ERROR_INVALID_PARAMETER);
  572.    }
  573.  
  574.  
  575.    /*
  576.    ** First allocate a port driver dialog structure
  577.    */
  578.    pPortDlgStruct = NULL;
  579.    rc = DosAllocMem((PVOID)&pPortDlgStruct,
  580.                     sizeof(PORTDLGSTRUCT),
  581.                     PAG_READ | PAG_WRITE | PAG_COMMIT);
  582.    if (rc)
  583.    {
  584.       DBPRINTF ((logbuf, "SplPdSetPort DosAllocMem failed rc=%d",rc));
  585.       return(rc);
  586.    }
  587.    /*
  588.    ** Give user dialog to connect to a new printer
  589.    */
  590.    memset (pPortDlgStruct, 0, sizeof (PORTDLGSTRUCT));
  591.    pPortDlgStruct->signature = PDLG_SIGNATURE;
  592.    pPortDlgStruct->hAB = hab ;
  593.    pPortDlgStruct->hModule = hPdrMod ;
  594.    pPortDlgStruct->pszPortName = pszPortName ;
  595.  
  596.    /*
  597.    ** Load the dialog for user to change.
  598.    */
  599.    *flModified = OpenPar1284PortDlg (hab, pPortDlgStruct);
  600.  
  601.    DosFreeMem( pPortDlgStruct );
  602.    DBPRINTF ((logbuf, "SplPdSetPort flModified=%d(%s)", *flModified, pszPortName));
  603.  
  604.    return(NO_ERROR);
  605. }
  606.  
  607. /****************************************************************************
  608.  *
  609.  * FUNCTION NAME = SplPdRemoteSetPort
  610.  *
  611.  * DESCRIPTION   = Display a dialog to allow the user to browse and modify
  612.  *                 port configurations.
  613.  *
  614.  * INPUT         = hab         - Anchor block handle
  615.  *                 pszComputerName - Name of print server being configured.
  616.  *                 pszPortName - name of port to configure
  617.  *                 flModified  - Flag to indicate that the configuration
  618.  *                               has been modified.(TRUE if modified).
  619.  *
  620.  * OUTPUT        =
  621.  *
  622.  * RETURN-NORMAL = 0
  623.  *
  624.  * RETURN-ERROR  = ERROR_INVALID_PARAMETER - if bad port name given
  625.  *
  626.  ****************************************************************************/
  627.  
  628. #ifdef BIDI
  629.  
  630. APIRET APIENTRY SplPdRemoteSetPort ( HAB hab,
  631.                                      PSZ pszComputerName,
  632.                                      PSZ pszPortName,
  633.                                      PULONG flModified )
  634. {
  635.  
  636.    ULONG          rc;
  637.    PPORTDLGSTRUCT pPortDlgStruct;
  638.    #ifdef DEBUG_ALERT
  639.      char logbuf[260];
  640.    #endif
  641.  
  642.  
  643.       /*
  644.       ** Check if port name string is NULL. This is an error.
  645.       */
  646.    if (!pszComputerName || !pszPortName || !flModified)
  647.    {
  648.       return(ERROR_INVALID_PARAMETER);
  649.    }
  650.  
  651.  
  652.    /*
  653.    ** First allocate a port driver dialog structure
  654.    */
  655.    pPortDlgStruct = NULL;
  656.    rc = DosAllocMem((PVOID)&pPortDlgStruct,
  657.                     sizeof(PORTDLGSTRUCT),
  658.                     PAG_READ | PAG_WRITE | PAG_COMMIT);
  659.    if (rc)
  660.    {
  661.       DBPRINTF ((logbuf, "SplPdRemoteSetPort DosAllocMem failed rc=%d",rc));
  662.       return(rc);
  663.    }
  664.    /*
  665.    ** Give user dialog to connect to a new printer
  666.    */
  667.    memset (pPortDlgStruct, 0, sizeof (PORTDLGSTRUCT));
  668.    pPortDlgStruct->signature = PDLG_SIGNATURE;
  669.    pPortDlgStruct->hAB = hab ;
  670.    pPortDlgStruct->hModule = hPdrMod ;
  671.    pPortDlgStruct->pszPortName = pszPortName ;
  672.    pPortDlgStruct->pszComputerName = pszComputerName ;
  673.  
  674.    /*
  675.    ** Load the dialog for user to change.
  676.    */
  677.    *flModified = OpenPar1284PortDlg (hab, pPortDlgStruct);
  678.  
  679.    DosFreeMem( pPortDlgStruct );
  680.    DBPRINTF ((logbuf, "SplPdRemoteSetPort flModified=%d(%s on %s)", *flModified, pszPortName, pszComputerName));
  681.  
  682.    return(NO_ERROR);
  683.  
  684. }
  685. #endif  // ifdef BIDI
  686.  
  687.  
  688.  
  689. /*
  690. ** SPLPD functions that can only be called by the spooler process
  691. */
  692. /****************************************************************************
  693.  *
  694.  * FUNCTION NAME = SplPdOpen - EXTERNAL API
  695.  *
  696.  * DESCRIPTION   = Open a print port for output.
  697.  *
  698.  *
  699.  *
  700.  * INPUT         = pszPortName     - name of port to open
  701.  *                 phDevice        - gets port driver handle
  702.  *                 pDeviceFlags    - gets device type being opened
  703.  *
  704.  *                                   HANDTYPE_FILE      0x0000
  705.  *                                   HANDTYPE_DEVICE    0x0001
  706.  *                                   HANDTYPE_PIPE      0x0002
  707.  *                                   HANDTYPE_LPTDEVICE 0x0004
  708.  *                                   HANDTYPE_COMDEVICE 0x0008
  709.  *                                   HANDTYPE_PROTECTED 0x4000
  710.  *                                   HANDTYPE_NETWORK   0x8000
  711.  *
  712.  *                 pPrtOpenStruct  - spooler parameter structure for PrtOpen
  713.  *
  714.  * OUTPUT        = 0  - successful.
  715.  *                      This device cannot be opened again until SplPdClose()
  716.  *                      is called.
  717.  *
  718.  *                      *phDevice   = port driver handle to be used with
  719.  *                                    SplPdWrite/SplPdAbortDoc/SplPdClose...
  720.  *                      *pDeviceFlags = device handle flags
  721.  *
  722.  *                 Other - error code, port not opened.
  723.  *
  724.  ****************************************************************************/
  725.  
  726. ULONG APIENTRY SplPdOpen( PSZ     pszPortName,
  727.                           PHFILE  phFile,
  728.                           PULONG  pDeviceFlags,
  729.                           PVOID   pPrtOpenStruct)
  730. {
  731.   ULONG           rc;
  732.   ULONG           cb;
  733.   PPORTINST       pPortInst;
  734.   PPDOPENINST     pPdOpenInstance;
  735.   PRTSTARTJOB     PrtStartJob;
  736.   PPRTOPENSTRUCT0 pPrtOpenStruct0;
  737.   #ifdef DEBUG_ALERT
  738.     char logbuf[260];
  739.   #endif
  740.  
  741.  
  742.  
  743.   /*
  744.    * Check for valid pointers
  745.    */
  746.   if (!phFile || !pDeviceFlags )
  747.   {
  748.       return(ERROR_INVALID_PARAMETER);
  749.   }
  750.  
  751.   *phFile         = NULLHANDLE;
  752.   pPdOpenInstance = NULL;
  753.   pPortInst       = NULL;
  754.   rc              = 0;
  755.  
  756.   #ifdef DEBUG_ALERT
  757.    {
  758.      if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
  759.      {
  760.        sprintf( logbuf,
  761.                 "SplPdOpen on %s\r\n",
  762.                 pszPortName);
  763.        LogCall( logbuf );
  764.      }
  765.    }
  766.   #endif /* DEBUG */
  767.  
  768.   cb = sizeof(PDOPENINST) + strlen(pszPortName) + 1 ;
  769.  EnterPdrSem();
  770.   /*
  771.   ** Add port to list.
  772.   ** If added previously, get pointer to structure.
  773.   ** If not yet opened, open the port
  774.   */
  775.   pPortInst = AddPortInst ( pszPortName );
  776.  
  777.   /*
  778.   ** Set TimeLastCmd so that we don't close this
  779.   **   port from our ControlThread
  780.   */
  781.   if (pPortInst) {
  782.      pPortInst->ulTimeLastCmd = time();
  783.   }
  784.  
  785.   if (pPortInst && !(pPortInst->flStatus & PF_PORT_OPEN))
  786.   {
  787.      rc = PdOpen(pPortInst);
  788.   }
  789.   if (!rc)
  790.   {
  791.     pPdOpenInstance = (PPDOPENINST) AllocPdrMem( cb );
  792.   }
  793.  
  794.  LeavePdrSem();
  795.   if (!rc && !pPdOpenInstance)
  796.   {
  797.      rc = ERROR_NOT_ENOUGH_MEMORY;
  798.   }
  799.  
  800.   if (!rc)
  801.   {
  802.      /*
  803.      ** init instance struct
  804.      */
  805.      memset( pPdOpenInstance, 0, sizeof(PDOPENINST) );
  806.      pPdOpenInstance->signature   = PD_SIGNATURE ;
  807.      pPdOpenInstance->cb          = cb ;
  808.      pPdOpenInstance->pNext       = NULL;
  809.      pPdOpenInstance->pPortInst   = pPortInst;
  810.      pPdOpenInstance->pszPortName = (PSZ)(pPdOpenInstance+1);
  811.      strcpy( pPdOpenInstance->pszPortName, pszPortName);
  812.      /*
  813.       * Add this pdopen instance to this driver's list
  814.       */
  815.     EnterPdrSem();
  816.      rc = AddPdOpenInst( pPdOpenInstance );
  817.     LeavePdrSem();
  818.      if (!rc)
  819.      {
  820.         *phFile       = (HFILE)( pPdOpenInstance );
  821.         *pDeviceFlags = HANDTYPE_DEVICE;
  822.      }
  823.   }
  824.  
  825.   if (!rc)
  826.   {
  827.      /*
  828.      ** Send start job command
  829.      */
  830. #ifdef BIDI
  831.      pPrtOpenStruct0 = (PPRTOPENSTRUCT0)pPrtOpenStruct;
  832.      if (pPrtOpenStruct0) {
  833.         PrtStartJob.ulSpoolerJobID  = pPrtOpenStruct0->ulSpoolerJobID ;
  834.         PrtStartJob.ulInterpreterID = pPrtOpenStruct0->ulLogicalUnit ;
  835.         PrtStartJob.ulStartPage     = pPrtOpenStruct0->ulStartPage ;
  836.         PrtStartJob.ulEndPage       = pPrtOpenStruct0->ulEndPage ;
  837.      } else {
  838.         PrtStartJob.ulSpoolerJobID  = (ULONG)-1;
  839.         PrtStartJob.ulInterpreterID = (ULONG)-1;
  840.         PrtStartJob.ulStartPage     = 0;
  841.         PrtStartJob.ulEndPage       = 0;
  842.      }
  843.  
  844.      rc = MyPrtSet ( NULL, pszPortName, TYPE_LONG_WAIT, BIDI_STARTJOB,
  845.                      &PrtStartJob, sizeof(PrtStartJob));
  846.      #ifdef DEBUG_ALERT
  847.       {
  848.        if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
  849.        {
  850.          sprintf( logbuf,
  851.                   "SplPdOpen PrtSet(BIDI_STARTJOB) rc=%d\r\n",
  852.                   rc);
  853.          LogCall( logbuf );
  854.        }
  855.       }
  856.      #endif /* DEBUG */
  857.      if ( (rc == ERROR_NOT_SUPPORTED) || (rc == ERROR_TIMEOUT) )
  858.      {
  859.         /*
  860.          * You will receive ERROR_NOT_SUPPORTED from BIDI_STARTJOB
  861.          *   if there is no protocol converter.
  862.          * You also could receive ERROR_TIMEOUT if the converter
  863.          *   is not working properly.
  864.          */
  865.         rc = 0;
  866.      }
  867. #endif
  868.      /*
  869.      ** Set JOB_PRINTING flag AFTER sending STARTJOB to allow sending
  870.      **   the BIDI_STARTJOB sequence, and avoid sending query data
  871.      **   while sending a job.
  872.      */
  873.      if (!rc) {
  874.         EnterPdrSem();
  875.           pPortInst->ulJobPrinting = PDR_PRINTING;
  876.         LeavePdrSem();
  877.      }
  878.  
  879.   } /* end if pPdOpenInstance created OK */
  880.  
  881.   if (rc) {
  882.      /*
  883.      ** Error occurred initializing the port
  884.      */
  885.      #ifdef DEBUG_ALERT
  886.       {
  887.        if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
  888.        {
  889.          sprintf( logbuf,
  890.                   "SplPdOpen failed, freeing pdOpenInst=%lX\r\n",
  891.                   (ULONG)pPdOpenInstance);
  892.          LogCall( logbuf );
  893.        }
  894.       }
  895.      #endif /* DEBUG */
  896.     EnterPdrSem();
  897.      if (pPortInst && !(pPortInst->flStatus & PF_Q_PORT_CALLED))
  898.      {
  899.        /*
  900.        ** We close connection at end of each job ONLY if
  901.        **   bidi is not enabled(never received BIDI_Q_PORT)
  902.        */
  903.        PdClose( pPortInst );
  904.      }
  905.      if (pPdOpenInstance) {
  906.        /*
  907.        ** Free PdInstance if open fails
  908.        */
  909.        RemovePdOpenInst ( pPdOpenInstance );
  910.        FreePdrMem( (PVOID)pPdOpenInstance , pPdOpenInstance->cb );
  911.      }
  912.     LeavePdrSem();
  913.      *phFile         = NULLHANDLE;
  914.   }
  915.  
  916.   #ifdef DEBUG_ALERT
  917.    {
  918.     if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
  919.     {
  920.        sprintf( logbuf,
  921.                 "SplPdOpen on %s rc=%d hFile=%lX\r\n",
  922.                 pszPortName, rc, *phFile);
  923.        LogCall( logbuf );
  924.     }
  925.    }
  926.   #endif /* DEBUG */
  927.  
  928.   return(rc);
  929. }
  930.  
  931.  
  932. /****************************************************************************
  933.  *
  934.  * FUNCTION NAME = SplPdWrite - EXTERNAL API
  935.  *
  936.  * DESCRIPTION   = Write data to a printer port opened with SplPdOpen()
  937.  *
  938.  * INPUT         = hDevice         - handle from SplPdOpen
  939.  *                 pchData         - ptr to data buffer to write
  940.  *                 cbData          - length of data in bytes
  941.  *                 pcbWritten      - gets count of bytes actually written
  942.  *
  943.  * OUTPUT        = 0  - successful.
  944.  *                      *pcbWritten must be checked to ensure cbData bytes
  945.  *                                  have been written.
  946.  *                                  Possible to get 0 rc and 0 bytes written.
  947.  *
  948.  *
  949.  *                 Other - error code, write failed
  950.  *                      *pcbWritten contains number of bytes successfully
  951.  *                                  written.
  952.  *
  953.  * NOTES           Not in port driver semaphore on entry/exit
  954.  *                 Data may be buffered; PrtClose must send any buffered data.
  955.  *
  956.  ****************************************************************************/
  957.  
  958. ULONG APIENTRY SplPdWrite( HFILE   hFile,
  959.                            PVOID   pchData,
  960.                            ULONG   cbData,
  961.                            PULONG  pcbWritten )
  962. {
  963.     ULONG   rc;
  964.     PPORTINST pPortInst;
  965.     PPDOPENINST pPdOpenInstance ;
  966.     ULONG  ulPortTimeout ;  /* timeout for this port          */
  967.     ULONG  cbWritten ;  /* bytes written to port so far       */
  968.     ULONG  ulTime ;  /* time prior to issuing DosWrite call   */
  969.     BOOL   fMustCheckDevID; /* TRUE = call GetDeviceID        */
  970.     #ifdef DEBUG_ALERT
  971.       char logbuf[260];
  972.     #endif
  973.  
  974.  
  975.     #ifdef DEBUG_ALERT
  976.      {
  977.       if (flChangeDebugLog & FL_PDRDB_ENABLE_SPLPDWRITE)
  978.       {
  979.          sprintf( logbuf,
  980.                   "SplPdWrite hFile=%lX pBuf=%lX cb=%d\r\n",
  981.                   hFile, (ULONG)pchData, cbData );
  982.          LogCall( logbuf );
  983.       }
  984.      }
  985.     #endif /* DEBUG */
  986.  
  987.     /*
  988.      * Validate file handle
  989.      */
  990.     if (!(pPdOpenInstance = ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
  991.         return(ERROR_INVALID_HANDLE);
  992.     }
  993.  
  994.     /*
  995.      * Get port structure,
  996.      */
  997.     pPortInst = pPdOpenInstance->pPortInst;
  998.  
  999.     if (!(pPortInst) ) {
  1000.        return(ERROR_INVALID_HANDLE);
  1001.     }
  1002.  
  1003.     if ( (pPortInst->ulCurrentMode <= CURMODE_COMPATIBLE) &&
  1004.          !(pPortInst->flStatus & PF_BIDI_CHECKED) &&
  1005.          (pPortInst->ulModeSelected != PARMODE_DISABLE_BIDI) ) {
  1006.        /*
  1007.        ** If this write is successful
  1008.        **  then we should try to query the deviceID for the printer.
  1009.        ** This is done in case the printer was not powered on
  1010.        **  when we initially tried to get the device ID from it.
  1011.        ** The result(if a bidi printer was powered off but is
  1012.        **  on when the first job is sent) is that the first job
  1013.        **  is printed in unidirectional mode, an alert is sent
  1014.        **  (PRTALERT_TYPE_COMM_STATUS_CHANGED) which causes the
  1015.        **  spooler to re-init the printer after the current job
  1016.        **  completes.  This will put the software into bidi mode.
  1017.        */
  1018.        fMustCheckDevID = TRUE;
  1019.     } else {
  1020.        fMustCheckDevID = FALSE;
  1021.     }
  1022.     /*
  1023.      * Save time prior to issuing DosWrite
  1024.      * If write fails before printer timeout expired
  1025.      *   retry the request.
  1026.      * This allows us to set shorter timeout with the
  1027.      *   device driver
  1028.      */
  1029.     ulTime      = time() ;
  1030.     *pcbWritten = 0 ;                    /* init bytes written to zero   */
  1031.     //
  1032.     // Get write mutex sem
  1033.     //
  1034.     rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
  1035.     while (pPortInst->fMoreCmds) {
  1036.         /*
  1037.         ** We were in the process of sending multiple
  1038.         **   queries to the printer.
  1039.         ** Hold off the print job until the query commands
  1040.         **   have been sent.
  1041.         */
  1042.         rc = DosReleaseMutexSem ( pPortInst->hPortSem );
  1043.         DosSleep(500);
  1044.         rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
  1045.     }
  1046.  
  1047.     rc = PdWrite(pPortInst, pchData, cbData, pcbWritten);
  1048.  
  1049.     if (rc || (*pcbWritten != cbData) ) {
  1050.        /*
  1051.         * Check time it took to issue write
  1052.         * If this is a known port
  1053.         *    there is a timeout for the port
  1054.         *    and the time it took to do the write was
  1055.         *    less than (PortTimeout - 1)
  1056.         * then
  1057.         *   Retry Request
  1058.         *
  1059.         * If the job was aborted, ulJobPrinting would be reset.
  1060.         */
  1061.        if ( (pPdOpenInstance->signature == PD_SIGNATURE) &&
  1062.             (ulPortTimeout = pPortInst->ulPrintTimeOut) &&
  1063.             ( (time() - ulTime) < (ulPortTimeout - 1) )) {
  1064.  
  1065.            /*
  1066.             * Keep track of total bytes written
  1067.             * Reset clock if DosWrite succeeded without writting all bytes
  1068.             * Retry request
  1069.             */
  1070.            cbWritten = *pcbWritten ;
  1071.            do
  1072.            {
  1073.               if ( (rc == 0) && (*pcbWritten) ) {
  1074.                  /*
  1075.                   * if DosWrite successful and bytes were written
  1076.                   *    reset timeout value
  1077.                   */
  1078.                  ulTime  = time() ;
  1079.               }
  1080.  
  1081.               /*
  1082.               ** Some printers allow query commands to be sent
  1083.               **  while still sending the print job.
  1084.               ** Here we release the mutex Write semaphore to allow
  1085.               **  the protocol converter to issue a query to the
  1086.               **  printer.
  1087.               ** It is up to the protocol converter to ensure @BUGBUG
  1088.               **  the printer can accept the query command in
  1089.               **  the middle of a print job.
  1090.               */
  1091.               rc = DosReleaseMutexSem ( pPortInst->hPortSem );
  1092.               /* Sleep one second to avoid hard loop on DosWrite */
  1093.               DosSleep(1000) ;
  1094.               rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
  1095.  
  1096.               *pcbWritten = 0 ; /* reset bytes written */
  1097.  
  1098.               /*
  1099.                * Write buffer, taking into account bytes written so far
  1100.                */
  1101.               rc = PdWrite( pPortInst,
  1102.                             (PVOID)((PBYTE)pchData + cbWritten),
  1103.                                      /* index past bytes written */
  1104.                             cbData - cbWritten,/* only write remaining data */
  1105.                             pcbWritten);
  1106.  
  1107.               cbWritten += *pcbWritten ;
  1108.  
  1109.            } while ( (cbWritten < cbData) &&
  1110.                      (pPortInst->ulJobPrinting == PDR_PRINTING) &&
  1111.                      ( (time() - ulTime) < (ulPortTimeout - 1) )) ;
  1112.  
  1113.            /* return actual bytes written */
  1114.            *pcbWritten = cbWritten ;
  1115.        }
  1116.  
  1117.     } /* end giving retry */
  1118.  
  1119.     //
  1120.     // Give up write sem
  1121.     //
  1122.     rc = DosReleaseMutexSem ( pPortInst->hPortSem );
  1123.  
  1124.     if (pPortInst->flJob & PRTSW_JOB_WRAPPER_REQUIRED) {
  1125.        /*
  1126.        ** This printer gets a bidi wrapper put around all data writes.
  1127.        ** Wakeup ParReadThread so we can get the acknowledgement @BUGBUG
  1128.        **   to the buffer we just sent, because some printers(NPAP)
  1129.        **   might reject data buffers when the printer is busy.
  1130.        **   The CNV waits for an ack that the printer accepted the
  1131.        **   data buffer before sending the next data buffer.
  1132.        **
  1133.        ** Later we should allow PROTCNV to tell us whether we should
  1134.        **   expect an Ack for data writes(dynamically set the state
  1135.        **   using PrtSet).
  1136.        */
  1137.        DosPostEventSem(pPortInst->hevReadThread);
  1138.     }
  1139.  
  1140.     #ifdef DEBUG_ALERT
  1141.      {
  1142.       if (flChangeDebugLog & FL_PDRDB_ENABLE_SPLPDWRITE)
  1143.       {
  1144.          sprintf( logbuf,
  1145.                   "SplPdWrite rc=%d cbWritten=%d\r\n",
  1146.                   rc, *pcbWritten );
  1147.          LogCall( logbuf );
  1148.       }
  1149.      }
  1150.     #endif /* DEBUG */
  1151.     /*
  1152.     ** If anything was written to the printer for the first time
  1153.     ** then try to get the printer's device ID.
  1154.     */
  1155.     if ( fMustCheckDevID && (*pcbWritten > 1) ) {
  1156.        RecheckDevID( pPortInst );
  1157.     }
  1158.  
  1159.     return(rc);
  1160.  
  1161. }
  1162.  
  1163.  
  1164. /****************************************************************************
  1165.  *
  1166.  * FUNCTION NAME = SplPdAbortDoc - EXTERNAL API
  1167.  *
  1168.  * DESCRIPTION   = Flush all current write requests for a h SplPdOpen()
  1169.  *
  1170.  * INPUT         = hDevice         - handle from SplPdOpen
  1171.  *                 pchData         - ptr to data buffer to write
  1172.  *                 cbData          - length of data in bytes
  1173.  *                 ulFlags         - abort processing flags
  1174.  *
  1175.  * OUTPUT        = 0  - successful.
  1176.  *
  1177.  *                 Other - error code, write failed
  1178.  *                      *pcbWritten contains number of bytes successfully
  1179.  *                                  written.
  1180.  *
  1181.  * NOTES           This currently does not buffer any write requests,
  1182.  *                 so there are no buffers to flush.
  1183.  *
  1184.  ****************************************************************************/
  1185.  
  1186. ULONG APIENTRY SplPdAbortDoc( HFILE   hFile,
  1187.                               PVOID   pchData,
  1188.                               ULONG   cbData,
  1189.                               ULONG   ulFlags )
  1190. {
  1191.   ULONG   rc;
  1192.   ULONG   ulJobPrinting;
  1193.   ULONG   cbWritten;
  1194.   PPORTINST pPortInst;
  1195.   PPDOPENINST pPdOpenInstance ;
  1196.   #ifdef DEBUG_ALERT
  1197.     char logbuf[260];
  1198.   #endif
  1199.  
  1200.  
  1201.  
  1202.   #ifdef DEBUG_ALERT
  1203.    {
  1204.     if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDABORT))
  1205.     {
  1206.        sprintf( logbuf,
  1207.                 "SplPdAbortDoc hFile=%lX pBuf=%lX cb=%d Flags=%lX\r\n",
  1208.                 hFile, (ULONG)pchData, cbData, ulFlags );
  1209.        LogCall( logbuf );
  1210.     }
  1211.    }
  1212.   #endif /* DEBUG */
  1213.  
  1214.   rc = 0 ;
  1215.   cbWritten = 0;
  1216.  
  1217.   /*
  1218.    * Validate file handle
  1219.    */
  1220.   if (!(pPdOpenInstance = ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
  1221.       return(ERROR_INVALID_HANDLE);
  1222.   }
  1223.   /*
  1224.    * Get port structure
  1225.    */
  1226.   pPortInst = pPdOpenInstance->pPortInst;
  1227.  
  1228.   if (!(pPortInst) ) {
  1229.      return(ERROR_INVALID_HANDLE);
  1230.   }
  1231.  
  1232.   /*
  1233.    * Issue FLUSH IOCtl to clear any data in PAR1284 kernel device driver
  1234.    *
  1235.    * Note: It is possible that data other than for this job could
  1236.    *       be flushed since the kernel device driver does not
  1237.    *       keep track of job boundaries, therefore the flush IOCtl
  1238.    *       is not sent!
  1239.    */
  1240.  
  1241.   /*
  1242.    * If any reset data, send it after flushing our buffers
  1243.    */
  1244.   if (cbData) {
  1245.     rc = PdWrite(pPortInst, pchData, cbData, &cbWritten);
  1246.   }
  1247.   /*
  1248.    * Reset flag indicating job aborted
  1249.    */
  1250.  EnterPdrSem();
  1251.    ulJobPrinting = pPortInst->ulJobPrinting;
  1252.    pPortInst->ulJobPrinting = PDR_ABORTED;
  1253.  LeavePdrSem();
  1254.    /*
  1255.     * Only release semaphore if needed
  1256.     */
  1257.    if (ulJobPrinting == PDR_PRINTING) {
  1258.       rc = DosReleaseMutexSem ( pPortInst->hPortSem );
  1259.    }
  1260.  
  1261.   #ifdef DEBUG_ALERT
  1262.    {
  1263.     if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDABORT))
  1264.     {
  1265.        sprintf( logbuf,
  1266.                 "SplPdAbortDoc rc=%d cbWritten=%d\r\n",
  1267.                 rc, cbWritten );
  1268.        LogCall( logbuf );
  1269.     }
  1270.    }
  1271.   #endif /* DEBUG */
  1272.  
  1273.   return(rc);
  1274. }
  1275.  
  1276.  
  1277. /****************************************************************************
  1278.  *
  1279.  * FUNCTION NAME = SplPdNewPage - EXTERNAL API
  1280.  *
  1281.  * DESCRIPTION   = notify port driver that another print page is being sent to
  1282.  *                 the printer
  1283.  *
  1284.  *
  1285.  * INPUT         = hDevice         - handle from SplPdOpen
  1286.  *                 ulPageNumber    - page number to be sent next
  1287.  *                                   Starts with page 1
  1288.  *
  1289.  * OUTPUT        = 0  - successful.
  1290.  *                      Valid hDevice, spooler updated job with page number
  1291.  *
  1292.  *                 ERROR_INVALID_HANDLE - invalid hDevice given
  1293.  *
  1294.  *                 Other - failure from port driver.
  1295.  *
  1296.  ****************************************************************************/
  1297.  
  1298. ULONG  APIENTRY SplPdNewPage ( HFILE  hFile, ULONG ulPageNumber )
  1299. {
  1300.  
  1301.     /*
  1302.      * Validate file handle
  1303.      */
  1304.     if (!(ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
  1305.         return(ERROR_INVALID_HANDLE);
  1306.     }
  1307.  
  1308.     /*
  1309.      * Spooler sets job "Sent to printer" pij->page number.
  1310.      * This port driver does not use pagessent value.
  1311.      */
  1312.  
  1313.     return 0;
  1314. }
  1315.  
  1316.  
  1317. /****************************************************************************
  1318.  *
  1319.  * FUNCTION NAME = SplPdClose - EXTERNAL API
  1320.  *
  1321.  * DESCRIPTION   = close a printer device opened with SplPdOpen
  1322.  *
  1323.  *
  1324.  *
  1325.  * INPUT         = hDevice         - handle from SplPdOpen
  1326.  *
  1327.  * OUTPUT        = 0  - successful.
  1328.  *                      SplPdOpen handle freed; the port may be opened again
  1329.  *                      with SplPdOpen()
  1330.  *
  1331.  *                 Other - error code, close failed.
  1332.  *                         If not ERROR_INVALID_HANDLE then caller should
  1333.  *                         reissue SplPdClose().
  1334.  *
  1335.  * NOTES:        If SplPdWrite data buffered, this outputs data before closing.
  1336.  *               If error outputting data, issue SplMessageBox(and retry)
  1337.  *
  1338.  ****************************************************************************/
  1339.  
  1340. ULONG  APIENTRY SplPdClose( HFILE  hFile )
  1341. {
  1342.   ULONG   rc;
  1343.   ULONG   ulJobPrinting;
  1344.   PPDOPENINST pPdOpenInstance ;
  1345.   PPORTINST pPortInst;
  1346.   PRTJOB  PrtJob;
  1347.   #ifdef DEBUG_ALERT
  1348.     char logbuf[260];
  1349.   #endif
  1350.  
  1351.  
  1352.  
  1353.   #ifdef DEBUG_ALERT
  1354.    {
  1355.     if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDOPEN))
  1356.     {
  1357.        sprintf( logbuf,
  1358.                 "SplPdClose hFile=%lX\r\n",
  1359.                 hFile);
  1360.        LogCall( logbuf );
  1361.     }
  1362.    }
  1363.   #endif /* DEBUG */
  1364.  
  1365.   /*
  1366.    * Validate file handle
  1367.    */
  1368.   if (!(pPdOpenInstance = ValidatePdOpenInst((PPDOPENINST)hFile)) ) {
  1369.       return(ERROR_INVALID_HANDLE);
  1370.   }
  1371.  
  1372.   /*
  1373.    * Reset flag indicating no job printing
  1374.    */
  1375.  EnterPdrSem();
  1376.   pPortInst = pPdOpenInstance->pPortInst;
  1377.   if (!(pPortInst) || (pPortInst->signature != PT_SIGNATURE) ) {
  1378.       rc = ERROR_FILE_NOT_FOUND;
  1379.       pPortInst = NULL;
  1380.   } else {
  1381.      /*
  1382.      ** Clear JOB_PRINTING flag BEFORE sending ENDJOB to allow sending
  1383.      **   the BIDI_ENDJOB sequence.
  1384.      */
  1385.       ulJobPrinting = pPortInst->ulJobPrinting;
  1386.       pPortInst->ulTimeLastJob = time();
  1387.       pPortInst->ulJobPrinting = PDR_NOT_PRINTING;
  1388.       /*
  1389.        * Only release semaphore if needed
  1390.        */
  1391.       if (ulJobPrinting == PDR_PRINTING) {
  1392.           rc = DosReleaseMutexSem ( pPortInst->hPortSem );
  1393.       }
  1394.   }
  1395.  
  1396.   if (pPortInst && !(pPortInst->flStatus & PF_Q_PORT_CALLED))
  1397.   {
  1398.     /*
  1399.     ** We close connection at end of each job ONLY if
  1400.     **   bidi is not enabled(never received BIDI_Q_PORT)
  1401.     */
  1402.     PdClose( pPortInst );
  1403.   }
  1404.   /*
  1405.    * if DosClose fails                                   @BUGBUG
  1406.    *    for now return 0 and assume the port can be reopened
  1407.    */
  1408.   if (rc) {
  1409.      rc = 0;
  1410.   }
  1411.  
  1412.   /*
  1413.    * Send end job command
  1414.    */
  1415. #ifdef BIDI
  1416.  
  1417.   if (pPortInst && (pPortInst->flStatus & PF_Q_PORT_CALLED)) {
  1418.      PrtJob.ulInterpreterID  = (ULONG)-1;
  1419.      PrtJob.ulPrinterJobID = (ULONG)-1;
  1420.     LeavePdrSem();
  1421.      rc = MyPrtSet ( NULL, pPdOpenInstance->pszPortName, TYPE_LONG_WAIT, BIDI_ENDJOB,
  1422.                      &PrtJob, sizeof(PRTJOB));
  1423.     EnterPdrSem();
  1424.      /*
  1425.       * Reset rc to 0 even if BIDI_ENDJOB doesn't work
  1426.       */
  1427.      rc = 0;
  1428.   }
  1429. #endif
  1430.  
  1431.   RemovePdOpenInst ( pPdOpenInstance );
  1432.  
  1433.   FreePdrMem( (PVOID)pPdOpenInstance , pPdOpenInstance->cb );
  1434.  LeavePdrSem();
  1435.  
  1436.   DosPostEventSem( hevControl );
  1437.  
  1438.   return rc;
  1439. }
  1440.  
  1441.  
  1442. /****************************************************************************
  1443.  *
  1444.  * FUNCTION NAME = SplPdQuery - EXTERNAL API
  1445.  *
  1446.  * DESCRIPTION   = Query information about a print device
  1447.  *
  1448.  * INPUT         = pszDeviceName   - name of port printer is attached
  1449.  *                 ulFlags         - query options
  1450.  *                 ulCommand       - function code for query
  1451.  *                 pInData         - command specific input data
  1452.  *                 cbInData        - length in bytes of pInData
  1453.  *                 pOutData        - returned query structure, format depends
  1454.  *                                   on ulCommand
  1455.  *                 pcbOutData      - Points to length of pOutData(in bytes)
  1456.  *                                   On entry this is set to length of buffer
  1457.  *                                    passed in.
  1458.  *                                   On exit this is updated with the length
  1459.  *                                    of available data, which may be more
  1460.  *                                    than put into pOutData
  1461.  *
  1462.  * OUTPUT        = 0  - successful.
  1463.  *                      *pcbOutData = length of data returned by query
  1464.  *                      pOutData    = query structure
  1465.  *                 234(ERROR_MORE_DATA) - partial query structure returned
  1466.  *                      *pcbOutData = length of buffer required to store
  1467.  *                                    entire query structure
  1468.  *                      pOutData    = partial query structure
  1469.  *                 2123(NERR_BufTooSmall) - buffer too small to fit any data
  1470.  *                      *pcbOutData = length of buffer required to store
  1471.  *                                    entire query structure
  1472.  *                      pOutData    = not updated, since it is much too small
  1473.  *                 Other - error code, nothing updated
  1474.  *
  1475.  *
  1476.  *
  1477.  * NOTE            Not in port driver semaphore on entry/exit
  1478.  *
  1479.  ****************************************************************************/
  1480.  
  1481.  
  1482. ULONG  APIENTRY SplPdQuery ( PSZ    pszDeviceName,
  1483.                              ULONG  ulFlags,
  1484.                              ULONG  ulCommand,
  1485.                              PVOID  pInData,
  1486.                              ULONG  cbInData,
  1487.                              PVOID  pOutData,
  1488.                              PULONG pcbOutData )
  1489. {
  1490.     ULONG       rc;
  1491.     #ifdef DEBUG_ALERT
  1492.       char logbuf[260];
  1493.     #endif
  1494.  
  1495.  
  1496.     #ifdef DEBUG_ALERT
  1497.      {
  1498.       PULONG pul;
  1499.       pul = (PULONG)pInData;
  1500.       if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDQUERY))
  1501.       {
  1502.          sprintf( logbuf,
  1503.                   "SplPdQuery on %s Flags=%lX Cmd=%lX cb=%d Data=%lX %lX\r\n",
  1504.                   pszDeviceName, ulFlags, ulCommand, cbInData,
  1505.                   (cbInData >= 4) ? pul[0]:0,
  1506.                   (cbInData >= 8) ? pul[1]:0
  1507.                   );
  1508.          LogCall( logbuf );
  1509.       }
  1510.      }
  1511.     #endif /* DEBUG */
  1512.  
  1513.     rc = 0;
  1514.  
  1515. #ifdef BIDI
  1516.     switch (ulCommand) {
  1517.     case BIDI_Q_PORT:
  1518.       /*
  1519.        * Add port to the list of supported ports and return
  1520.        *   the status of the PAR1284 connected printer.
  1521.        */
  1522.       rc = HandleQPort( pszDeviceName,
  1523.                          ulFlags,
  1524.                          pOutData,
  1525.                          pcbOutData );
  1526.       break;
  1527.  
  1528.     case BIDI_WAIT_ALERT:
  1529.       /*
  1530.        * Read alert, waiting if necessary ( Assume what is returned from
  1531.        *  the PAR1284 kernel driver is complete )
  1532.        */
  1533.       rc = HandleWaitAlert( pszDeviceName,
  1534.                              ulFlags,
  1535.                              ulCommand,
  1536.                              pInData,
  1537.                              cbInData,
  1538.                              pOutData,
  1539.                              pcbOutData );
  1540.       break;
  1541.  
  1542.     case BIDI_Q_PORTDRV:
  1543.       /*
  1544.        * Check for valid data
  1545.        */
  1546.       if (!pOutData || !pcbOutData ) {
  1547.           return(ERROR_INVALID_PARAMETER);
  1548.       }
  1549.       /*
  1550.        * Send back PORTSETTINGS structure
  1551.        */
  1552.       rc = HandleQPortDRV ( pszDeviceName,
  1553.                             pOutData,
  1554.                             pcbOutData );
  1555.       break;
  1556.  
  1557.     case BIDI_READ_PASSTHRU:
  1558.       /*
  1559.        * An application wants to read passthru data from the printer and there
  1560.        *   is no protocol converter used on this port(CNV would get called
  1561.        *   with this command instead of the port driver).
  1562.        */
  1563.       rc = ReadPassthru  ( pszDeviceName,
  1564.                              ulFlags,
  1565.                              ulCommand,
  1566.                              pInData,
  1567.                              cbInData,
  1568.                              pOutData,
  1569.                              pcbOutData );
  1570.       break;
  1571.  
  1572.  
  1573.     default:
  1574.       /*
  1575.       ** Let protocol converter handle all other queries.
  1576.       */
  1577.       rc = MySplProtSendCmd ( pszDeviceName,
  1578.                               ulFlags,
  1579.                               ulCommand,
  1580.                               (PFN) SplPdSendCmd,
  1581.                               (PFN) NULL,
  1582.                               pInData,
  1583.                               cbInData,
  1584.                               pOutData,
  1585.                               pcbOutData );
  1586.      }
  1587. #else
  1588.      rc = ERROR_NOT_SUPPORTED;
  1589. #endif  // ifdef BIDI
  1590.  
  1591.     #ifdef DEBUG_ALERT
  1592.      {
  1593.       if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDQUERY))
  1594.       {
  1595.          sprintf( logbuf,
  1596.                   "SplPdQuery on %s rc=%d\r\n",
  1597.                   pszDeviceName,
  1598.                   rc );
  1599.          LogCall( logbuf );
  1600.       }
  1601.      }
  1602.     #endif /* DEBUG */
  1603.  
  1604.     return(rc);
  1605. }
  1606.  
  1607.  
  1608.  
  1609. /****************************************************************************
  1610.  *
  1611.  * FUNCTION NAME = SplPdSet - EXTERNAL API
  1612.  *
  1613.  * DESCRIPTION   = Set printer device information
  1614.  *
  1615.  * INPUT         = pszDeviceName   - name of port printer is attached
  1616.  *                 ulFlags         - set options
  1617.  *                 ulCommand       - function code for set command
  1618.  *                 pInData         - command specific input data
  1619.  *                 cbInData        - length in bytes of pInData
  1620.  *
  1621.  * OUTPUT        = 0  - successful.
  1622.  *                 Other - error code
  1623.  *
  1624.  * NOTE            Not in port driver semaphore on entry/exit
  1625.  *
  1626.  ****************************************************************************/
  1627. ULONG  APIENTRY SplPdSet   ( PSZ    pszDeviceName,
  1628.                              ULONG  ulFlags,
  1629.                              ULONG  ulCommand,
  1630.                              PVOID  pInData,
  1631.                              ULONG  cbInData )
  1632. {
  1633.     ULONG         rc = 0;
  1634.     PPORTINST     pPortInst = NULL;
  1635.     PPRTSW        pPrtSw;
  1636.     ULONG         ulcbOutBuf;
  1637.     #ifdef DEBUG_ALERT
  1638.       char logbuf[260];
  1639.     #endif
  1640.  
  1641.  
  1642.     #ifdef DEBUG_ALERT
  1643.      {
  1644.       PULONG pul;
  1645.       pul = (PULONG)pInData;
  1646.       if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSET))
  1647.       {
  1648.          sprintf( logbuf,
  1649.                   "SplPdSet on %s Flags=%lX Cmd=%lX cb=%d Data=%lX %lX\r\n",
  1650.                   pszDeviceName, ulFlags, ulCommand, cbInData,
  1651.                   (cbInData >= 4) ? pul[0]:0,
  1652.                   (cbInData >= 8) ? pul[1]:0
  1653.                   );
  1654.          LogCall( logbuf );
  1655.       }
  1656.      }
  1657.     #endif /* DEBUG */
  1658.  
  1659.     /*
  1660.      * Check for valid set command
  1661.      */
  1662.     if (ulCommand >= BIDI_READ_PASSTHRU) {
  1663.         return(ERROR_INVALID_FUNCTION);
  1664.     }
  1665.     rc = 0;
  1666.     pPortInst = NULL;
  1667.  
  1668.     switch (ulCommand) {
  1669.     case BIDI_INIT_PORTDRV:
  1670.       /*
  1671.        * Create thread to control all LPT ports.
  1672.        * Move DllInit mem init routine here @BUGBUG
  1673.        */
  1674.       CreateControlThread();
  1675.       break;
  1676.  
  1677. #ifdef BIDI
  1678.  
  1679.     case BIDI_RESET:
  1680.       //
  1681.       // Reset printer - done by protocol converter
  1682.       //
  1683.       break;
  1684.     case BIDI_SHUTDOWN:
  1685.       /*
  1686.       ** Wake up control thread to begin termination
  1687.       */
  1688.       fShutdownInProgress = TRUE;
  1689.       DosPostEventSem(hevControl);
  1690.       /*
  1691.       ** This should wait until all threads are shutdown
  1692.       **  because the spooler process will terminate when
  1693.       **  this returns.
  1694.       ** If this does not return within 25 seconds, the spooler
  1695.       **  process will terminate anyway without letting us
  1696.       **  complete our shutdown.
  1697.       */
  1698.       break;
  1699.     case BIDI_INIT:
  1700.       //
  1701.       // Change printer from Uni to Bidirectional - currently not needed
  1702.       //
  1703.       break;
  1704.     case BIDI_TERM:
  1705.       //
  1706.       // Change printer from Bidirectional to Uni - currently not needed
  1707.       //
  1708.       break;
  1709.     case BIDI_RESPONSE_FMT:
  1710.       /*
  1711.        * Set format of printer-to-host response = currently not used
  1712.        */
  1713.       break;
  1714.     case BIDI_PACKET_SIZE:
  1715.       /*
  1716.        * Set printer-to-host max packet size = currently not used
  1717.        */
  1718.       break;
  1719.     case BIDI_SET_SW:
  1720.       /*
  1721.        * Gives software capabilities of attached bidi printer
  1722.        */
  1723.       if (!pInData || cbInData < sizeof(PRTSW)) {
  1724.           return(ERROR_INVALID_PARAMETER);
  1725.       }
  1726.       /*
  1727.        * Find port instance
  1728.        */
  1729.      EnterPdrSem();
  1730.       pPortInst = FindPortInst ( pszDeviceName );
  1731.       if (pPortInst) {
  1732.          /*
  1733.           * Set Port Driver variables
  1734.           */
  1735.          pPrtSw = (PPRTSW) pInData;
  1736.          pPortInst->flJob    = pPrtSw->flJob;
  1737.          pPortInst->flDevice = pPrtSw->flDevice;
  1738.       } else {
  1739.          rc = ERROR_FILE_NOT_FOUND;
  1740.       }
  1741.      LeavePdrSem();
  1742.       break;
  1743.  
  1744.     case BIDI_SET_PORTDRV:
  1745.       /*
  1746.        * Save port settings
  1747.        */
  1748.       if (!pInData || cbInData < sizeof(PPORTSETTINGS)) {
  1749.           return(ERROR_INVALID_PARAMETER);
  1750.       }
  1751.       /*
  1752.        * Save PORTSETTINGS structure
  1753.        */
  1754.       rc = HandleSetPortDRV ( pszDeviceName,
  1755.                               pInData,
  1756.                               cbInData );
  1757.       break;
  1758.  
  1759.     case BIDI_NOTIFY_ENDJOBCONNECT:
  1760.       /*
  1761.        * Spooler no longer waiting for any job confirmations from port
  1762.        * This could be used to drop a job-based connection quicker
  1763.        *   than the timeouts used in ControlThread.
  1764.        */
  1765.       break;
  1766.     case BIDI_NOTIFY_PORT_SELECTED:
  1767.       /*
  1768.        * Spooler tells port driver that this port is connected to a print queue
  1769.        * We could pay more attention to this output port than
  1770.        *   one not connected to a print queue.
  1771.        */
  1772.       break;
  1773.     case BIDI_NOTIFY_PORT_RELEASED:
  1774.       /*
  1775.        * Spooler tells port driver this port is no longer connected
  1776.        *   to a print queue.  We could pay less attention to this
  1777.        *   output port now that it is not connected to a queue.
  1778.        */
  1779.       break;
  1780.     case BIDI_ADD_VIRTUAL_PORT:
  1781.       /*
  1782.        * An application requested a virtual port to get information from
  1783.        *   this port driver.  This is useful if an App wants the
  1784.        *   port driver to enumerate or find printers on the network wire.
  1785.        * The buffer passed in is port-driver specific.
  1786.        * The PAR1284 port driver does not support this.
  1787.        */
  1788.       rc = ERROR_NOT_SUPPORTED;
  1789.       break;
  1790.     case BIDI_DEL_VIRTUAL_PORT:
  1791.       /*
  1792.        * An application wants to delete a virtual port it has previously
  1793.        *   created.  This is done in response to SplDeletePort() for
  1794.        *   a virtual port.
  1795.        * The PAR1284 port driver does not support virtual ports.
  1796.        */
  1797.       rc = ERROR_NOT_SUPPORTED;
  1798.     case BIDI_DEL_PORT:
  1799.       /*
  1800.        * A port belonging to this port driver was removed from the System INI.
  1801.        * It may have been this port driver that removed it( SplPdRemovePort ).
  1802.        * We can free our instance data for this port now.
  1803.        * Be certain that any reference to the PORTINST structures
  1804.        *  allow for deleting a PORTINST.
  1805.        * Since we only support LPT1-3, we don't actually remove any
  1806.        *  port from our instance list.
  1807.        */
  1808.       break;
  1809.  
  1810.  
  1811.     case BIDI_START_PASSTHRU:
  1812.       /*
  1813.        * An application wants a passthru session and there is no
  1814.        *   protocol converter used on this port(CNV would get called
  1815.        *   with this command instead of the port driver).
  1816.        */
  1817.       rc = StartPassthru( pszDeviceName,
  1818.                           ulFlags,
  1819.                           ulCommand,
  1820.                           pInData,
  1821.                           cbInData );
  1822.       break;
  1823.  
  1824.     case BIDI_SEND_PASSTHRU:
  1825.       /*
  1826.        * An application wants to send passthru data to the printer and there
  1827.        *   is no protocol converter used on this port(CNV would get called
  1828.        *   with this command instead of the port driver).
  1829.        */
  1830.       rc = SendPassthru( pszDeviceName,
  1831.                           ulFlags,
  1832.                           ulCommand,
  1833.                           pInData,
  1834.                           cbInData );
  1835.       break;
  1836.  
  1837.     case BIDI_END_PASSTHRU:
  1838.       /*
  1839.        * An application wants to end a passthru session with the printer and
  1840.        *   there is no protocol converter used on this port(CNV would get
  1841.        *   called with this command instead of the port driver).
  1842.        */
  1843.       rc = EndPassthru( pszDeviceName,
  1844.                           ulFlags,
  1845.                           ulCommand,
  1846.                           pInData,
  1847.                           cbInData );
  1848.       break;
  1849.  
  1850.  
  1851. #endif  // #ifdef BIDI
  1852.     default:
  1853. #ifdef BIDI
  1854.       /*
  1855.       ** Let protocol converter handle any other set command
  1856.       */
  1857.       ulcbOutBuf = 0;
  1858.       rc = MySplProtSendCmd ( pszDeviceName,
  1859.                               ulFlags,
  1860.                               ulCommand,
  1861.                               (PFN) SplPdSendCmd,
  1862.                               (PFN) NULL,
  1863.                               pInData,
  1864.                               cbInData,
  1865.                               NULL,
  1866.                               &ulcbOutBuf );
  1867. #else
  1868.       rc = ERROR_NOT_SUPPORTED;
  1869. #endif  // #ifdef BIDI
  1870.      }
  1871.  
  1872.     #ifdef DEBUG_ALERT
  1873.      {
  1874.       if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSET))
  1875.       {
  1876.          sprintf( logbuf,
  1877.                   "SplPdSet on %s rc=%d\r\n",
  1878.                   pszDeviceName,
  1879.                   rc );
  1880.          LogCall( logbuf );
  1881.       }
  1882.      }
  1883.     #endif /* DEBUG */
  1884.  
  1885.     return(rc);
  1886. }
  1887.  
  1888.  
  1889.  
  1890. /****************************************************************************
  1891.  *
  1892.  * FUNCTION NAME = SplPdSendCmd - EXTERNAL API
  1893.  *
  1894.  * DESCRIPTION   = Send protocol specific commands to the printer
  1895.  *
  1896.  *
  1897.  * INPUT         = pszDeviceName   - name of port printer is attached
  1898.  *                 ulFlags         - query/set options
  1899.  *                       Only channel currently for the PAR1284 port is data
  1900.  *                 ulCommand       - function code for query/set
  1901.  *                 pInData         - command specific input data
  1902.  *                 cbInData        - length in bytes of pInData
  1903.  *
  1904.  * OUTPUT        = 0  - successful.
  1905.  *                 Other - error code, nothing updated
  1906.  *
  1907.  * NOTE            Not in port driver semaphore on entry/exit
  1908.  *                 If cbInData is 0, just check ulCommand value
  1909.  *
  1910.  ****************************************************************************/
  1911.  
  1912. #ifdef BIDI
  1913.  
  1914. ULONG  APIENTRY SplPdSendCmd( PSZ    pszDeviceName,
  1915.                               ULONG  ulFlags,
  1916.                               ULONG  ulCommand,
  1917.                               PVOID  pInData,
  1918.                               ULONG  cbInData )
  1919. {
  1920.     ULONG      rc;
  1921.     PPORTINST  pPortInst;
  1922.     PBYTE      pBufToSend; /* -> buffer to give to PdWrite */
  1923.     ULONG      cbWritten;
  1924.     ULONG      cbWrite;
  1925.     ULONG      ulPortTimeout ;  /* timeout for this port          */
  1926.     ULONG      ulTime ;  /* time prior to issuing DosWrite call   */
  1927.     #ifdef DEBUG_ALERT
  1928.       char logbuf[260];
  1929.     #endif
  1930.  
  1931.  
  1932.  
  1933.     #ifdef DEBUG_ALERT
  1934.      {
  1935.       PULONG pul;
  1936.       pul = (PULONG)pInData;
  1937.       if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
  1938.       {
  1939.          sprintf( logbuf,
  1940.                   "SplPdSendCmd on %s Flags=%lX Cmd=%lX cb=%d Data=%lX %lX\r\n",
  1941.                   pszDeviceName, ulFlags, ulCommand, cbInData,
  1942.                   (cbInData >= 4) ? pul[0]:0,
  1943.                   (cbInData >= 8) ? pul[1]:0
  1944.                   );
  1945.          LogCall( logbuf );
  1946.          /*
  1947.           * Dump out the Bidi commands we are going to send to
  1948.           *   the printer when in debug mode
  1949.           */
  1950.          DumpHex( (PBYTE)pInData, cbInData );
  1951.       }
  1952.      }
  1953.     #endif /* DEBUG */
  1954.  
  1955.     rc          = 0;
  1956.     /*
  1957.      * Get port instance
  1958.      */
  1959.   EnterPdrSem();
  1960.     pPortInst = AddPortInst ( pszDeviceName );
  1961.     if (!pPortInst) {
  1962.         rc = ERROR_FILE_NOT_FOUND;
  1963.     } else {
  1964.        /*
  1965.         * Here we could check for whether a job is printing or not  @BUGBUG
  1966.         * For now, we allow commands to be sent to the printer
  1967.         *   while sending a print job because some protocol converters
  1968.         *   packetize job data writes.
  1969.         * For those protocol converters that do not allow sending commands
  1970.         *   to the printer while in the middle of sending a print job, the
  1971.         *   converter must ensure it does not try to send a command
  1972.         *   use SplPdSendCmd().
  1973.         */
  1974.        //if (pPortInst->ulJobPrinting == PDR_PRINTING ) {
  1975.        //    //
  1976.        //    // Since there is only one channel to the printer
  1977.        //    //  we cannot send commands while in the middle of sending
  1978.        //    //  a print job
  1979.        //    // We handle BIDI_STARTJOB and BIDI_ENDJOB by not setting
  1980.        //    //  the port status to PDR_PRINTING until AFTER STARTJOB
  1981.        //    //  and clearing it BEFORE ENDJOB.
  1982.        //    //
  1983.        //    if (!(ulFlags & FLG_SYNCH) || !(ulFlags & FLG_MUSTCOMPLETE)) {
  1984.        //       rc = ERROR_INFO_NOT_AVAIL;
  1985.        //    }
  1986.        //}
  1987.     }
  1988.   LeavePdrSem();
  1989.     if (rc) {
  1990.        #ifdef DEBUG_ALERT
  1991.         {
  1992.          if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
  1993.          {
  1994.             sprintf( logbuf,
  1995.                      "SplPdSendCmd on %s rc=%d %lX\r\n",
  1996.                      pszDeviceName, rc );
  1997.             LogCall( logbuf );
  1998.          }
  1999.         }
  2000.        #endif /* DEBUG */
  2001.  
  2002.        return(rc);
  2003.     }
  2004.     rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
  2005.     /*
  2006.      * If we wanted to hold the caller until the current job data was  @BUGBUG
  2007.      *   sent to the printer, the following bit of code would do it:
  2008.      */
  2009.     // /*
  2010.     //  * Loop until there is no job data being sent to the printer
  2011.     //  *  variable is reset.
  2012.     //  */
  2013.     // while (pPortInst->ulJobPrinting == PDR_PRINTING) {
  2014.     //     rc = DosReleaseMutexSem ( pPortInst->hPortSem );
  2015.     //     DosSleep(500);
  2016.     //     rc = DosRequestMutexSem ( pPortInst->hPortSem, SEM_INDEFINITE_WAIT );
  2017.     // }
  2018.    EnterPdrSem();
  2019.     /*
  2020.     ** Set TimeLastCmd so that we don't close this
  2021.     **   port from our ControlThread
  2022.     */
  2023.     pPortInst->ulTimeLastCmd = time();
  2024.  
  2025.     /*
  2026.     ** open PAR1284 device if not yet opened
  2027.     */
  2028.     if ( !rc && !(pPortInst->flStatus & PF_PORT_OPEN) ) {
  2029.        rc =  PdOpen(pPortInst);
  2030.     }
  2031.  
  2032.    LeavePdrSem();
  2033.  
  2034.     if (rc) {
  2035.         DosReleaseMutexSem ( pPortInst->hPortSem );
  2036.         #ifdef DEBUG_ALERT
  2037.          {
  2038.           if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
  2039.           {
  2040.              sprintf( logbuf,
  2041.                       "SplPdSendCmd on %s rc=%d %lX\r\n",
  2042.                       pszDeviceName, rc );
  2043.              LogCall( logbuf );
  2044.           }
  2045.          }
  2046.         #endif /* DEBUG */
  2047.  
  2048.         return(rc);
  2049.     }
  2050.  
  2051.     /*
  2052.      * Save time prior to issuing DosWrite
  2053.      * If write fails before printer timeout expired
  2054.      *   retry the request.
  2055.      */
  2056.     cbWrite   = 0;
  2057.     cbWritten = 0;
  2058.     ulTime    = time() ;
  2059.     /*
  2060.     ** Some 32-bit linear addresses are not handled well by DosWrite
  2061.     **  (all pages have to be able to be locked by the filesystem).
  2062.     ** To ensure we do not get rc=5(ACCESS_DENIED) from DosWrite
  2063.     **  we copy the data out to a separately allocated buffer,
  2064.     **  and pass this buffer to DosWrite.
  2065.     ** We only do this for SplPdSendCmd() because our 32-bit print
  2066.     **  drivers(callers of SplPdWrite) already handle this.
  2067.     **/
  2068.     if ((cbInData <= DEFAULT_BUFSIZE) && pPortInst->pbWriteBuf) {
  2069.        memcpy( pPortInst->pbWriteBuf, pInData, cbInData );
  2070.        pBufToSend = pPortInst->pbWriteBuf;
  2071.     } else {
  2072.        pBufToSend = pInData;
  2073.     }
  2074.     rc = PdWrite( pPortInst, pBufToSend, cbInData, &cbWrite );
  2075.  
  2076.     if (rc || ( cbWrite != cbInData ) ) {
  2077.        /*
  2078.         * Check time it took to issue write
  2079.         * If this is a known port
  2080.         *    there is a timeout for the port
  2081.         *    and the time it took to do the DosWrite was
  2082.         *    less than (PortTimeout - 1)
  2083.         * then
  2084.         *   Retry Request
  2085.         */
  2086.        if ( (ulPortTimeout = pPortInst->ulPrintTimeOut) &&
  2087.             ( (time() - ulTime) < (ulPortTimeout - 1) )) {
  2088.  
  2089.            /*
  2090.             * Keep track of total bytes written
  2091.             * Reset clock if DosWrite succeeded without writting all bytes
  2092.             * Retry request
  2093.             */
  2094.            cbWritten = cbWrite ;
  2095.            do
  2096.            {
  2097.               if ( (rc == 0) && ( cbWrite ) ) {
  2098.                  /*
  2099.                   * if DosWrite successful and bytes were written
  2100.                   *    reset timeout value
  2101.                   */
  2102.                  ulTime  = time() ;
  2103.               }
  2104.  
  2105.               /* Sleep one second to avoid hard loop on DosWrite */
  2106.               DosSleep(1000) ;
  2107.  
  2108.               cbWrite = 0 ; /* reset bytes written */
  2109.  
  2110.               /*
  2111.                * Write buffer, taking into account bytes written so far
  2112.                */
  2113.               rc = PdWrite( pPortInst,
  2114.                             (PVOID)((PBYTE)pBufToSend + cbWritten),
  2115.                                      /* index past bytes written */
  2116.                             cbInData - cbWritten,/* only write remaining data */
  2117.                             &cbWrite );
  2118.  
  2119.               cbWritten += cbWrite ;
  2120.  
  2121.            } while ( (cbWritten < cbInData) &&
  2122.                      ( (time() - ulTime) < (ulPortTimeout - 1) )) ;
  2123.        }
  2124.  
  2125.     } /* end giving retry */
  2126.  
  2127.     /*
  2128.     ** Set TimeLastCmd so that we don't close this
  2129.     **   port from our ControlThread until necessary.
  2130.     ** Wakeup control thread if it is waiting indefinitely.
  2131.     **   This is done to ensure we close the port
  2132.     **   when only query commands are sent to it.
  2133.     **   The control thread will just check this port,
  2134.     **   then reset its eventSem timeout to the next time
  2135.     **   it should check this port.
  2136.     **   This is done because we never know when the last
  2137.     **   query buffer for a port is coming.
  2138.     */
  2139.     pPortInst->ulTimeLastCmd = time();
  2140.     if (!fControlWakeupPending)
  2141.     {
  2142.        DosPostEventSem(hevControl);
  2143.     }
  2144.     DosReleaseMutexSem ( pPortInst->hPortSem );
  2145.     /*
  2146.     ** Wakeup ParReadThread so we can get the response
  2147.     **   to the command we just sent.
  2148.     */
  2149.     DosPostEventSem(pPortInst->hevReadThread);
  2150.  
  2151.     #ifdef DEBUG_ALERT
  2152.      {
  2153.       if (!(flChangeDebugLog & FL_PDRDB_DISABLE_SPLPDSENDCMD))
  2154.       {
  2155.          sprintf( logbuf,
  2156.                   "SplPdSendCmd on %s rc=%d %lX\r\n",
  2157.                   pszDeviceName, rc );
  2158.          LogCall( logbuf );
  2159.       }
  2160.      }
  2161.     #endif /* DEBUG */
  2162.  
  2163.     return(rc);
  2164. }
  2165.  
  2166.  
  2167. #endif  // ifdef BIDI
  2168.  
  2169.