PDDR/2 - Printer Bidirectional Communications

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation =Printer Bidirectional Communications= This chapter discusses OS/2 communications for bidirectional printers.

Introduction
The OS/2 print spooler and print object take advantage of the features of bidirectional printing. The IBM Developer Connection Device Driver Kit for OS/2 (DDK) now provides the following in support of bidirectional printers: All OS/2 printer drivers developed with a prior DDK version should work without modification when printing to a bidirectional printer.
 * 1) Spooler Prt API interface that enables bidirectional communications with printers - this is bidirectional-software protocol independent.
 * 2) Presentation Manager (PM) port-driver interface that enables bidirectional communications with printers - this is also bidirectional-software protocol independent.
 * 3) Bidirectional protocol router layer that routes generic printer queries/control commands to the correct bidirectional protocol converter.
 * 4) Print object that takes advantage of the features of bidirectional printers.
 * 5) Network-independent API interface that allows remote printer queries and effective printer-alert handling.

PM port drivers developed with a prior DDK version should work without modification, but they will not provide bidirectional communication.

The changes to the OS/2 print subsystem:
 * provide precise printer warnings/errors to users
 * keep print jobs until they appear in an output bin
 * provide remote control panel functions for certain printers

Overview
The OS/2 print subsystem has a set of APIs that applications and OS/2 printer drivers can use to communicate bidirectionally with printers. The application interface consists of PrtXXXX APIs supported by the spooler. These APIs support generic query and set commands that allow OS/2 applications to get information about any type of supported printer without having to know the printer's specific command language.

From the set of PrtXXXX APIs, the spooler calls PM port drivers written to support bidirectional printers. The port driver is then responsible for sending data across the physical medium to the printer. A port driver can be written to support a parallel-port attached printer, a network-wire attached printer, or a printer attached in any other way.

Many printers use the same command language and structure for query and response information. In order to limit the amount of code required by new port-driver interfaces, the OS/2 print subsystem allows port drivers to use bidirectional protocol converters to formulate the commands necessary to query and set information in the printer. These protocol converters assist port drivers by interpreting data received by the printer and converting generic query as well as set commands into commands that the printer understands. ++                |     OS/2       | | Printer Driver | ++                        |                  +--+          +---+                  | OS/2 Spooler |- | Bidirectional | \--/         |   Protocol    | |  Converter   | |        |            | (PJL or NPAP) | |        |            +---+                     |     +---+---+   |                           |                       |         +--+  | +---+     |         | Network Port | -+ | Parallel Port |     | |   Driver    |    |    Driver     | + +--+   +---+                 |                  |            +-+       +-+      +---+            | Network |       |     OS/2    |      | OS/2 Parallel | +-+      | File System |  |  Port Driver  | +-+     |    Driver     | |                                +---+                 |                 |                                         |

+-+                              +-+            | Printer |                               | Printer | +-+                              +-+

Spooler Print APIs
See the OS/2 Presentation Device Driver Reference for detailed information on these APIs, their syntax, and their parameters.

Presentation Manager Port-Driver Interface
A port driver is responsible for transmitting data to a printer and receiving data from a printer. The port driver does not need to know the format of the data - a protocol converter handles the command language for bidirectional printers.

The following API definitions are exported by bidirectional PM port drivers: as well as (optionally): If SplPdOpen is exported by a port driver, then the spooler no longer calls SplPdInitPort or SplPdTermPort for port initialization/termination.
 * SplPdOpen
 * SplPdClose
 * SplPdAbortDoc
 * SplPdResetAbort
 * SplPdWrite
 * SplPdNewPage
 * SplPdQuery
 * SplPdSet
 * SplPdEnumPort
 * SplPdGetPortIcon
 * SplPdInstallPort
 * SplPdRemovePort
 * SplPdSetPort
 * SplPdRemoteSetPort
 * SplPdSendCmd

If SplPdSendCmd is exported, the spooler may call the bidirectional-software protocol converter directly, instead of calling SplPdQuery/SplPdSet first. The protocol converter then calls SplPdSendCmd to pass the command data to the printer.

The spooler handles all inter-process communication for the port driver. All calls for sending print jobs, querying, or setting printer configurations are done from the single spooler process.

All structures returned by PrtQuery or passed into PrtSet must use offsets from the beginning of the buffer instead of imbedded pointers. This is done to allow the spooler to perform more efficient inter-process communications.

The following is the flow when a port driver exports SplPdSendCmd: |                PrtSet +-+         | Spooler |---+ +-+          |                                  SplProtSendCmd +---+                          | Bidirectional | |   Protocol   | |  Converter   | +---+                 +-+                  |                    SplPdSendCmd +-+         | Port Driver | +-+ The following is the flow when a port driver does not export SplPdSendCmd: |        PrtSet +-+ | Spooler |            Send set command to port driver +-+      |         SplPdSet +-+ | Port Driver |        Gives port driver's SendCmd function address to converter +-+      |         SplProtSendCmd +-+ | Spooler |            Routes to correct bidirectional protocol converter +-+      |         SplProtSendCmd ++ | Protocol Converter | Generates command string, and sends it to port driver ++      |         SendCmd +-+ | Port Driver |        Sends protocol-specific commands to printer +-+      |       /       /       |   +-+   |         |   | Printer | |        |   +-+ See the OS/2 Presentation Device Driver Reference for detailed information on these APIs, their syntax, and their parameters.

Port-Driver Extended Attributes
Port-driver files (with a .PDR extension) can have the following extended attributes to assist the print object in installing the port driver:
 * DEFAULT_PORT (Optional):Name of default output port to install from this port driver.
 * The format is default-port name followed by a semi-colon and the default-port name's description.
 * For example, "MyPort;A default port called MyPort".
 * This makes enumerating ports to install from the print object more efficient. Without this EA, the print object has to load and call the port driver's SplPdEnumPort API to display the list of ports available to install.


 * VENDORNAME (Optional):Vendor name of the port driver.
 * This is used to specify the subdirectory from /OS2/DLL in which to install the port driver. If not given, the port driver is installed in the /OS2/DLL directory.


 * REQUIREDVENDORFILES (Optional unless other files are required):Comma-separated list of extra files required for correct operation of the driver.
 * These files are copied into the VENDORNAME directory. If this EA is not given, only the port-driver file (.PDR) is copied into the /OS2/DLL directory when installing the port driver.
 * For example, REQUIREDVENDORFILES=MYHELPER.DLL,MYNET.HLP.


 * OPTIONALDRIVERFILES (Optional):Names of extra files that are optional - that is, files not required for correct operation, such as OPTIONALDRIVERFILES=LASERJET.SYM, LASERJET.MAP.
 * These files are copied into the driver directory, which is a subdirectory under /OS2/DLL.


 * REQUIREDDRIVERFILES (Required for multi-file drivers):Names of extra files required by the driver for correct operation, such as REQUIREDDRIVERFILES=LASERJET.DRV.
 * These files are copied into the driver directory, which is a subdirectory under /OS2/DLL.


 * CLASSNAME (Optional):Name of the output stream created by the hardcopy driver, such as CLASSNAME=PCL.
 * REQUIREDCLASSFILES (Optional unless the driver requires other files):Names of extra files required for correct operation by the driver files in the CLASSNAME directory, such as REQUIREDCLASSFILES=GENERIC.DLL.
 * These files are copied into the CLASSNAME directory.


 * OPTIONALCLASSFILES (Optional):Names of extra files that are optional, that is, files not required for correct operation, such as OPTIONALCLASSFILES=*.FNT, GENERIC.SYM, GENERIC.MAP.
 * These files are copied into the CLASSNAME directory.


 * OPTIONALVENDORFILES (Optional):Comma-separated list of extra files that are not required for correct driver operation.
 * These files are copied into the VENDORNAME directory.
 * For example, OPTIONALVENDORFILES=MYNET.SYM.


 * .ICON (Optional):Gives the icon definition used by the workplace shell to display the port objects for this port driver.
 * This extended attribute is automatically created during the build process if the ICON keyword is used with a resource identifier of 1 or if the DEFAULTICON keyword is used in the RC file for the port driver.
 * For example, .ICON 1 PORT.ICO.


 * .VERSION (Optional):Can be used to indicate the version number of a port driver.

For example, .VERSION=30.001.

Port-Installation Steps
The user opens an existing print object's settings notebook's "Output Port" settings page to install a new port or port driver or to update an existing port driver. This settings page has two buttons-one for installing a new port, and the other for updating an existing port driver.

To update an existing port driver, the following steps are taken:
 * 1) If the "Update Port Driver" button is selected, the print object checks for the spooler being enabled.
 * 2) If the spooler is enabled, the user
 * is told that port drivers cannot be updated while the spooler is enabled
 * is asked if they want to disable the spooler at this time.
 * 3.If the spooler is disabled, the user:
 * is asked for the path to an updated port driver
 * must select a port driver from the list of port drivers that exist on that path.

To install a new printer port, the following steps are taken:
 * 1.If the user selects the "Install New Port" pushbutton or selects the "Install" menu item from an existing port object, a dialog box appears listing all ports available to be installed by the existing port drivers. Each port driver can export the extended attribute DEFAULT_PORT - whose contents are the port name followed by a semi-colon and the port description. This is the name and description of a default new port to install for this port driver.
 * If the port driver does not have this extended attribute, the print object calls SplPdEnumPort to list ports available to be installed for this port driver.
 * The port driver can also export the extended attribute ".ICON"-which contains the port driver's icon for the new port to install. This avoids loading and calling a port driver just to display the ports available to be installed by the port driver.
 * There are two radio buttons in this install dialog box. The default is selected to install a new port from an existing port driver, the other button is selected to install a new port driver. If the "Install New Portdriver" is selected, the user is prompted for the path to the new port driver. The print object uses the above method to determine the installable ports.
 * 2.When the user selects a port object to install, the print object installs the port driver-if it is a new port driver, by copying the port driver and its files and then adding the port driver entry to the system initialization file.
 * 3.The print object calls the port driver's SplPdInstallPort API with the default port name selected by the user.
 * The port driver can display a configuration dialog to the user at this time. This configuration dialog can be similar to the one displayed by SplPdSetPort. The print object does not call SplPdSetPort during port installation; it is up to each port driver to decide whether or not a configuration dialog is needed when installing a new port.
 * If the port driver decides to display a configuration dialog during SplPdInstallPort, the port driver may need to add a "virtual" port name to the system. This is needed to allow PrtQuery and PrtSet commands to be sent to the port-driver code running under the spooler process. It is suggested that the port driver start a background thread to issue the PrtQuery and PrtSet commands, since the port driver might not even be initialized under the spooler process yet.

Once the configuration dialog is complete, the port name configured by the user can be installed and the virtual port can be removed by the port driver.

At this point, the port selected by the user is installed and ready to connect to a print object.

Virtual-Printer Ports
The spooler allows applications and port drivers to communicate with printers that are not connected to the print subsystem in OS/2. This is done by allowing the port driver to use a virtual port to connect to non-OS /2 printers. This allows query and set commands to be sent to these printers, but the OS/2 print subsystem is not allowed to select these printer ports for output.

An application can add a virtual-printer port by calling SplCreatePort. The application must know extra information about the port driver to be allowed to create a virtual port-such as the network adapter address-and this information is passed into SplCreatePort.

When SplCreatePort is called with a unique port name, the spooler calls the port driver with command BIDI_ADD_VIRTUAL_PORT, passing the data buffer supplied by the application. If this is the first port installed by the port driver, the port driver is first called with BIDI_INIT_PORTDRV to allow the port driver to initialize. If this is successful, the port driver is called to add the virtual port.

Once the virtual port is created, the application can issue queries to the printer using the virtual-port name. When the application no longer needs a virtual port, the application should remove the port by calling SplDeletePort. This causes the spooler to call the port driver with command BIDI_DEL_VIRTUAL_PORT.

Virtual ports allow use of the existing port-driver and protocol-converter interfaces while not allowing the user to select the virtual port as an output port. These virtual ports do not get stored in the INI file, and they are deleted when the spooler is disabled or when the system is rebooted.

See the OS/2 Presentation Device Driver Reference for detailed information on these APIs, their syntax, and their parameters.
 * SplCreatePort Called to create a printer port.
 * SplDeletePort Called to remove a printer port.

Sample Bidirectional Infrared Port Driver
A port driver is only responsible for transmitting data to and from the printer; it is not responsible for interpreting the information being sent to or returned by the printer. A PM port driver is a DLL that is used to communicate with a printer. The PM port-driver interface now passes all print job data to the port driver and allows the port driver to return information sent by the printer. Example port drivers are the:
 * /OS2/DLL/PARALLEL.PDR for parallel attached printers
 * /OS2/DLL/SERIAL.PDR for COM devices

While different manufacturers may use unique protocols to connect to their printers, developers can write a port driver for a set of printers that use a unique communications mechanism. For example, a port driver can be written for network-wire attached printers.

Our sample infrared port driver, when compiled with the target BIDIDBG, logs informational messages into a file called "C:\ALERT.INF". This is to help with debugging only. To disable logging to this file, change the makefile so that it no longer defines compile-flag DEBUG_ALERT.

The sample infrared port driver can be changed to support a different communications media. Make copies of our port-driver makefile and source; then, change the string "INFRARED" in the names of these files to a string that matches the new port driver being developed-e.g., "MYDRIVER".

Here is a code roadmap:


 * help.c||Initializes and calls help functions. To enable easier loading, this dynamically loads HELPMGR.DLL instead of linking to the help manager.
 * -style="vertical-align: top;"
 * infrared.c||Handles all communication with the infrared device. This code uses some callback functions to interface with the LMDLL.DLL infrared helper DLL. This should be replaced with code specific to the communications media used by your new port driver.
 * init.c||Contains DLL initialization and port-driver initialization routines. This code loads LMDLL.DLL when needed by the port driver.
 * pdrapi.c||Public-entry points for port driver. This contains all the public SplPd APIs for the port driver.
 * util.c||Utility functions for the port driver, including memory-allocation and global semaphore-access routines.
 * }
 * util.c||Utility functions for the port driver, including memory-allocation and global semaphore-access routines.
 * }
 * }

Sample Bidirectional Parallel Port Driver
A port driver is only responsible for transmitting data to and from the printer; it is not responsible for interpreting the information being sent to or returned by the printer. A PM port driver is a DLL that is used to communicate with a printer. The PM port-driver interface now passes all print job data to the port driver and allows the port driver to return information sent by the printer. Example port drivers are the:
 * \OS2\DLL\PARALLEL.PDR for parallel attached printers
 * \OS2\DLL\SERIAL.PDR for COM devices

While different manufacturers may use unique protocols to connect to their printers, developers can write a port driver for a set of printers that use a unique communications mechanism. For example, a port driver can be written for network wire-attached printers.

Our sample parallel port driver, when compiled with the target BIDIDBG, logs informational messages to the debug terminal if the flag /C1 (or /C2 for COM2) is added to the "DEVICE=X:\OS2\PMDD.SYS" statement in CONFIG.SYS. This is to help with debugging only. To disable logging to this file, change the makefile so that it no longer defines compile flag DEBUG_ALERT.

The sample parallel port driver can be changed to support a different communications media. Make copies of the port-driver makefile and source; then, change the string "PARALLEL" in the names of these files to a string that matches the new port driver being developed, for example, "MYDRIVER".

Here is a code roadmap:


 * help.c||Initializes and calls help functions. To enable easier loading, this dynamically loads HELPMGR.DLL instead of linking to the help manager.
 * - style="vertical-align: top;"
 * par1284.c||Handles all communication with the parallel attached printer. This code uses IOCtls supported by the PAR1284.SYS bidirectional parallel device driver. This should be replaced with code specific to the communications media used by your new port driver.

For more information on the IOCtl commands supported, refer to the Category 05H Parallel Port Control IOCtl Commands found in the Physical Device Driver Reference.
 * init.c||Contains DLL initialization and port-driver initialization routines.
 * pdrapi.c||Public entry points for port driver. This contains all the public SplPd APIs for the port driver.
 * util.c||Utility functions for the port driver, including memory-allocation and global semaphore-access routines.
 * }
 * util.c||Utility functions for the port driver, including memory-allocation and global semaphore-access routines.
 * }
 * }

Bidirectional Protocol Converters
A protocol converter is responsible for generating the commands to issue to the printer and for being able to interpret data sent by the printer.

The spooler(PMSPL.DLL) exports two new entry points, as does each bidirectional protocol converter:
 * SplProtSendCmd-route generic Query or Set request to bidirectional-software protocol-specific converter to create command, send command to printer, and wait for printer response.
 * SplProtXlateCmd-convert printer to host message into generic bidirectional command/response packets.

Protocol converters may optionally export SplProtWrite if they need to wrap print job data in a bidirectional-software protocol header.

The spooler handles all inter-process communication for the protocol converter. All calls for sending print jobs, querying, or setting printer configurations are done from the single spooler process.

See the OS/2 Presentation Device Driver Reference for detailed information on these APIs, their syntax, and their parameters.

SplProtWrite|Optional API called by PrtWrite to put a bidirectional protocol wrapper around print data being sent to the printer.
 * SplProtSendCmd||Called by PrtQuery, PrtSet, SplPdQuery, or SplPdSet to convert generic commands and pass bidirectional protocol-specific commands to the printer.
 * SplProtXlateCmd||Called only by port drivers when processing the BIDI_WAIT_ALERT(8016h) command to convert a protocol specific message received from the printer into a generic command structure that can be used by the port driver and spooler.
 * SplProtXlateCmd||Called only by port drivers when processing the BIDI_WAIT_ALERT(8016h) command to convert a protocol specific message received from the printer into a generic command structure that can be used by the port driver and spooler.
 * }

Protocol-Converter Extensions
The spooler allows protocol converters to be written that make use of a converter already installed on the system. These are extensions to the base protocol converters, and they are called before the base converter is called to allow the extension converters to handle specific printers better than the base converter.

A protocol extension is installed by writing the following to the system INI file: The initialization sequence for protocol-converter extensions is as follows:
 * 1) Spooler sends BIDI_Q_PORT to port driver.
 * 2) Spooler determines base converter to use based on PRTPORT structure.
 * 3) Spooler starts BIDI_WAIT_ALERT thread for port driver (if none started for the port driver yet).
 * 4) Spooler sends BIDI_INIT_PROTCNV to base protocol converter.
 * 5) Spooler calls each extension to the base protocol converter with BIDI_INIT_PROTCNV. If the extension converter supports this specific printer model, it returns 0 for success; otherwise, it returns ERROR_NOT_SUPPORTED.

The spooler uses the first extension to the base protocol converter that returns success. The sequence of calling protocol-converter extensions is indeterminate.

Once an extension converter is loaded for a port, all protocol-converter commands go to the extension converter. The extension converter has the option of calling the base protocol converter to process the command.

Sample Protocol Converter
A protocol converter is a DLL written to support printers capable of returning information to the host PC. A protocol converter is responsible for understanding the control language of the printer. Example control languages are Network Printer Alliance Protocol (NPAP), Printer Job Language (PJL), and Simple Network Management Protocol (SNMP). The protocol converter does not get involved in the physical transmission of commands or data to the printer. The converter generates appropriate printer commands to send to the printer, and the converter is able to translate data sent from the printer to the host PC.

Developers can write a usable protocol converter if they have a port driver that can communicate with a set of printers.

Our sample protocol converter does not support any control language. It uses strings as examples of data sent and received from a printer. An actual protocol converter would use printer control-language commands to query or set information in the printer.

Make copies of our protocol-converter makefile and source; then, change the string "PROTCNV" in the names of these files to a string that matches the new protocol converter being developed-e.g., "MYCNV". The OS2SYS.INI entry to install the sample protocol converter is: Here is a code roadmap:


 * buildcmd.c||Routines to build commands to send to the printer.
 * cache.c||Routines to store information returned by the printer in the protocol converter's cache.
 * getcmd.c||Routines to get response data from the protocol converter's cache.
 * init.c||DLL initialization and termination routines.
 * passthru.c||Routines to handle a bidirectional passthru session.
 * proctype.c||Routines to process the ulType field to determine whether to get data from the cache or to ask the printer for the information.
 * sendcmd.c||Exports SplProtSendCmd API, which is the main entry point for the protocol converter. For each command, this generates the control-language buffer to send to the port driver for transmission to the printer.
 * util.c||Utility functions for the converter, including memory-allocation and global semaphore-access routines.
 * xlatecmd.c||Exports SplProtXlateCmd API, which the port driver calls when data is received from the printer. These routines interpret the data coming from the printer and look for threads that may be waiting for this data.
 * }
 * proctype.c||Routines to process the ulType field to determine whether to get data from the cache or to ask the printer for the information.
 * sendcmd.c||Exports SplProtSendCmd API, which is the main entry point for the protocol converter. For each command, this generates the control-language buffer to send to the port driver for transmission to the printer.
 * util.c||Utility functions for the converter, including memory-allocation and global semaphore-access routines.
 * xlatecmd.c||Exports SplProtXlateCmd API, which the port driver calls when data is received from the printer. These routines interpret the data coming from the printer and look for threads that may be waiting for this data.
 * }
 * xlatecmd.c||Exports SplProtXlateCmd API, which the port driver calls when data is received from the printer. These routines interpret the data coming from the printer and look for threads that may be waiting for this data.
 * }
 * }

Calling Sequence
Route Alert +--- +--+     +--+                       |        ++    |      | Printer Driver   |                       | Spooler|Alert Thread | | (or Application) |                      |        |             | +--+                      +--+          |                                           | PrtQuery |     | Query response                      |   | Returned alert |                           PrtQuery |   | +--+                                     |        |       +--| --+       +-+        | Spooler  |---+               |       | Spooler | +--+      |               |       +-+                           |               |          |                           |               |          +---+---+                                           |              |                        ++                        | Protocol     Wait for     Cache Data Clear | | Converter   Response     Waiting Threads  | |             (Alert)                       | SplPdSendCmd   ++ +---+                                  +--+           |                               |              ++               +---+                   |   |      +-+                                              |      | Port Driver |                                     +-+ +-+                                    | Port Driver | |                                             +-+  DosWrite |   |                                               |   | Returned ++                                DosRead  |   | Alert data | FileSystem |                                             | ++                                     ++           |                                               | FileSystem | |  |                                           ++               |                                               |      +---+                                        |   |      |    Kernal     |                                            | | Device Driver |                                  +---+ +---+                                  |    Kernal     | | Device Driver | +---+ For a query request, the following happens: PrtQuery(BIDI_Q_INPUTBINS) SplProtSendCmd             // Spooler calls bidirectional // converter directly. if(InputBins information is cached in protocol converter) return(cached information) do       Create command sequence to query printer SplPdSendCmd(in port driver) to send query command to printer DosWrite(send command sequence to printer) do         wait on alert thread while(response not yet received)

At this point, the information requested from printer is in       the protocol converter's information cache.

while(more commands need to be issued to satisfy query) copy cached information into SplProtSendCmd buffer and return The following is the initialization sequence for a bidirectional printer port: --- Spooler thread 1 --- SplPdSet( BIDI_INIT_PORTDRV )           // Initialize port driver. // If it fails, the port driver is unloaded. // Network port drivers can open the // network adapter at this time.

SplPdQuery( BIDI_Q_PORT )               // Initialize port driver for this port and // get device ID and protocol used by the printer.

if query successful and printer is bidirectional capable

Create Spooler thread 2 to wait for alerts from the port driver

SplProtSendCmd( BIDI_INIT_PROTCNV )   // Initializes protocol converter.

SplPdSet( BIDI_RESPONSE_FMT )         // Tell port driver the format of                                           // printer-to-host messages.

SplProtSendCmd( BIDI_Q_RESPONSE_FMT ) // Get format of printer-to-host // messages from protocol converter.

SplProtSendCmd( BIDI_Q_SW )           // Get bidirectional-software characteristics.

SplPdSet( BIDI_SET_SW )               // Tell port driver the bidirectional capabilities.

SplProtSendCmd( BIDI_ENABLE_ALERT )   // Enable core printer alerts.

SplPdSendCmd                        // Port driver sends alert-enable commands // that were generated by the protocol converter.

SplPdSet( BIDI_NOTIFY_PORT_SELECTED ) // Tell port driver that this port // is connected to a print queue.

....        --- Spooler thread 2 (one instance per port driver) --- do

PrtQuery( BIDI_WAIT_ALERT )                 // Single spooler thread to get all alerts.

SplPdQuery( BIDI_WAIT_ALERT )             // PM port driver called to wait for // data from any of its printer ports.

SplProtXlateCmd( in PMSPL.DLL )         // Port driver calls protocol-converter // routine to translate alert data received // from printer.

SplProtXlateCmd( protocol converter ) // Translate software protocol-specific // alert data into generic alert structure.

Convert to generic-alert structure

Update protocol converter's information cache

if any thread is waiting on response for this port

Clear Protocol Converter's Port wait semaphore

return PRTALERT structure to Port Driver, then to spooler

if Alert

call alert handling routines in PMSPL

pass alert to registered applications, take action on the alert, etc...

while( port driver assigned to printer port ) The following is the termination sequence when the spooler is disabled: The following is the sequence when a printer port is removed:

Control-Panel Functions
The print object adds a menu item to the print object and port object to display a control panel if the support for the control panel is in the system. The following APIs add the support for control panels.

See the OS/2 Presentation Device Driver Reference for detailed information on these APIs, their syntax, and their parameters.
 * SplRegisterControlPanel:Registers a DLL with the spooler that can display a control panel for printers.
 * SplGetControlPanelList:Queries installed control panel DLLs and protocol converters for support for the printer attached to the given port.
 * SplQueryControlPanel:Queries specific control panel DLL or protocol converter for support for the printer attached to the given port.
 * SplDisplayControlPanel:Displays a control panel for a printer.

Separator-Page Processing
The spooler alters the PRTOPENSTRUCT0->ulSpoolerJobID by adding the value 0x10000 to the spooler job ID when sending the separator page. This gives the protocol converter a unique spooler job ID with the separator print job. This is done to assist the protocol converter in choosing a unique printer job ID in case the printer does not support printer job IDs.

Alert Handling
There are two types of alerts that can be returned by the printer:
 * core alerts
 * extended alerts

Core alerts are those alerts that the OS/2 print subsystem can understand and take action on when encountered. These include cover open, out of paper, and job completed printing.

Extended alerts are those alerts that the print subsystem either does not understand or is incapable of responding to. These alerts often have very specific information sent by the printer to the host PC.

The spooler, by default, enables the core alerts when printing to a bidirectional-capable printer. This allows the spooler to take advantage of the capabilities of the advanced printer. Other applications might be interested in these core alerts.

Applications might also be written that can request additional status or information from a particular set of printers. This additional information can be considered an extended alert. The application must know what extended alerts are supported, and this is done by calling PrtQuery(BIDI_Q_CONVERTER_INFO) to determine the protocol converter being used. It is up to the protocol converter to publish any extended-alert definitions it wants to make available to applications or printer drivers.

When an application registers for an alert, the spooler enables that alert in the printer by calling PrtSet(BIDI_ENABLE_ALERT). When the alert is generated, the spooler posts a message to those applications that have registered for the alert. If the alert is an extended alert, the application must call PrtQuery(BIDI_READ_ALERT) to get the extended-alert information. The format of this returned information is defined by the protocol converter supporting the extended alert.

The spooler mediates what alerts are activated on the printer when multiple clients have applications that register for alerts from the same printer. The spooler only posts an alert to those applications that request the particular alert.

Once an extended alert is activated (by an application calling SplRegister), if an event occurs that causes the extended alert: The spooler issues BIDI_READ_ALERT to save the alert data until the registered application(s) ask for the alert. However, this data is not be kept indefinitely by the spooler.
 * the spooler posts the application that the extended alert has occurred
 * the application must use the command BIDI_READ_ALERT to get the alert data

The following is done to handle printer alerts: When an application calls SplRegister, the spooler determines whether or not the alert being registered is enabled. If it is not enabled yet, the spooler calls the protocol converter with BIDI_ENABLE_ALERT to enable the alert.
 * SplRegister API available to request alert notification from the spooler.
 * SplUnRegister API available to terminate alert notification from the spooler.
 * PrtQuery(BIDI_READ_ALERT) available to applications to read extended-alert information.

When an application calls SplUnRegister, the spooler determines whether or not the alert being unregistered should be disabled. If another application has registered for this alert, the spooler keeps the alert enabled; otherwise, the spooler calls the protocol converter with BIDI_ DISABLE_ALERT to disable the alert.

See the OS/2 Presentation Device Driver Reference for detailed information on these APIs, their syntax, and their parameters.


 * SplRegister||Allows applications to register for notification of events about printers.
 * SplUnRegister||Allows applications to deregister for notification of events about printers.
 * }
 * }

Bidirectional Command Structures Format
All structures used by PrtQuery and PrtSet use offsets into the return buffer for variable-length data instead of returning pointers. This is done to make transmission of these bidirectional structures easier between processes and machines.

An example would be a structure that returns a description string. The field that references the storage location of this string would be a ULONG. If zero, then that string was not returned. If non-zero, the field is the offset, from the beginning of the output buffer, to the description string.

All structures with variable-length data should pack this data immediately following all the fixed-length structures. This way, *pcbOutData contains the number of bytes to copy from the beginning of the pOutData buffer.

Note: All returned structure offset fields are offsets from the beginning of the output buffer given, not offsets from the beginning of the structure.

Bidirectional Command Flow
The following are tables of query and set command flows, showing which part of the system gets called for each command.

A First a Second

These lists assume that the port driver exports SplPdSendCmd.