PDDR/2 - Printer Bidirectional Communications
Printer Device Driver Reference |
---|
|
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
Contents
- 1 Printer Bidirectional Communications
- 1.1 Introduction
- 1.2 Overview
- 1.3 Spooler Print APIs
- 1.4 Presentation Manager Port-Driver Interface
- 1.5 Bidirectional Protocol Converters
- 1.6 Calling Sequence
- 1.7 Control-Panel Functions
- 1.8 Separator-Page Processing
- 1.9 Alert Handling
- 1.10 Bidirectional Command Structures Format
- 1.11 Bidirectional Command Flow
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:
- Spooler Prt API interface that enables bidirectional communications with printers - this is bidirectional-software protocol independent.
- Presentation Manager (PM) port-driver interface that enables bidirectional communications with printers - this is also bidirectional-software protocol independent.
- Bidirectional protocol router layer that routes generic printer queries/control commands to the correct bidirectional protocol converter.
- Print object that takes advantage of the features of bidirectional printers.
- Network-independent API interface that allows remote printer queries and effective printer-alert handling.
All OS/2 printer drivers developed with a prior DDK version should work without modification when printing to a bidirectional printer.
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.
PrtOpen | Opens a device for output. Routed to the SplPdOpen() routine in the port driver. |
---|---|
PrtClose | Routed to port-driver SplPdClose to close a device connection. |
PrtAbort | Routed to port driver SplPdAbortDoc to abort operations to the device connection. |
PrtAbortDoc | Routed to SplPdAbortDoc for document abort processing. |
PrtResetAbort | Routed to SplPdResetAbort to reset an aborted print job to allow a print driver to send multiple reset sequences to the printer. |
PrtWrite | Routed to SplPdWrite to write print job data to the device. |
PrtDevIOCtl | Passes device-specific commands to the print device. |
PrtNewPage | Routed to port-driver SplPdNewPage to signal the beginning of a new output page. |
PrtQuery | Routed to port-driver SplPdQuery or protocol-converter SplProtSendCmd to get information about the print device. |
PrtSet | Routed to port-driver SplPdSet or protocol-converter SplProtSendCmd to set printer device information. |
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:
- SplPdOpen
- SplPdClose
- SplPdAbortDoc
- SplPdResetAbort
- SplPdWrite
- SplPdNewPage
- SplPdQuery
- SplPdSet
- SplPdEnumPort
- SplPdGetPortIcon
- SplPdInstallPort
- SplPdRemovePort
- SplPdSetPort
as well as (optionally):
- SplPdRemoteSetPort
- SplPdSendCmd
If SplPdOpen is exported by a port driver, then the spooler no longer calls SplPdInitPort or SplPdTermPort for port initialization/termination.
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.
SplPdOpen | Called by PrtOpen to open a device for output. |
---|---|
SplPdClose | Called by PrtClose to close a device connection and free the handle. |
SplPdAbortDoc | Called by PrtAbort and PrtAbortDoc for document-abort processing. |
SplPdResetAbort | Called by PrtResetAbort to reset an aborted device handle to allow writes again. |
SplPdWrite | Called by PrtWrite and SplProtWrite to write data to the device. |
SplPdNewPage | Called by PrtNewPage to signal the beginning of a new output page. |
SplPdQuery | Called by PrtQuery to get information about the print device. |
SplPdSet | Called by PrtSet to set printer device information. |
SplPdSendCmd | Called by SplProtSendCmd to send protocol-specific commands to the printer. |
SplPdEnumPort | Called by the print object to enumerate ports supported by this port driver when the port driver does not export the default install-port extended attribute. |
SplPdGetPortIcon | Returns the resource ID of the icon that represents the ports supported by this port driver. |
SplPdInstallPort | Called by the print object when the user elects to install a new printer port. |
SplPdRemovePort | Called by the print object when the user elects to delete an existing printer port. |
SplPdSetPort | Called by the print object when the user elects to open the settings on a printer port. |
SplPdRemoteSetPort | Called by the network print object when an administrator elects to open the settings on a server's printer port from a client machine. |
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:
- If the "Update Port Driver" button is selected, the print object checks for the spooler being enabled.
- 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. 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.
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. 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.
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.
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.
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:
ApplicationName | = | "PM_PROTOCOL_EXTENSION" |
KeyName | = | Name of new protocol converter; ex: "MYNPAEXT" |
KeyValue | = | Base protocol converter name followed by a comma and the path to this new protocol converter. |
ex: "NPAP,C:\OS2\DLL\MYNPAEXT.CNV" |
The initialization sequence for protocol-converter extensions is as follows:
- Spooler sends BIDI_Q_PORT to port driver.
- Spooler determines base converter to use based on PRTPORT structure.
- Spooler starts BIDI_WAIT_ALERT thread for port driver (if none started for the port driver yet).
- Spooler sends BIDI_INIT_PROTCNV to base protocol converter.
- 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:
Application - "PM_PROTOCOL_CONVERTER" KeyName - "PROTCNV" // Change to new converter name KeyValue - "C:\OS2\DLL\PROTCNV.CNV" // Change to path of new converter
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.
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:
SplProtSendCmd(BIDI_SHUTDOWN) // Tell protocol converter that the // spooler is being shutdown. SplPdSet(BIDI_SHUTDOWN) // Tell port driver that the // spooler is being shutdown.
The following is the sequence when a printer port is removed:
SplProtSendCmd(BIDI_DEL_PORT) // Tell protocol converter that // the port has been removed. SplPdSet(BIDI_DEL_PORT) // Tell port driver that // port has been 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 posts the application that the extended alert has occurred
- the application must use the command BIDI_READ_ALERT to get the alert data
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 following is done to handle printer alerts:
- 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 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.
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.
Query Command | Command Code (Hex) | Sent to Port Driver | Sent to Protocol Converter | Initial Sequence Number | Description |
---|---|---|---|---|---|
BIDI_Q_CONVERTER_INFO | 8021 | First | Requests protocol-converter information. | ||
BIDI_Q_DEVICE | 800D | Second | First | Requests printer device characteristics. Returns capabilities and characteristics of the printer. | |
BIDI_Q_FONTS | 8012 | Second | First | Requests list of fonts for a particular interpreter. | |
BIDI_Q_INPUTBINS | 800F | Second | First | Queries input bins. | |
BIDI_Q_INTERPRETER | 800E | Second | First | Requests information on interpreters available in the printer. | |
BIDI_Q_JOBID | 8017 | First | Requests printer job ID for job being sent to port. Issued by the spooler during PrtOpen after a successful SplPdOpen to the port driver so that the spooler can synchronize the printer job ID with the spooler job ID. | ||
BIDI_Q_JOBS_COMPLETE | 8013 | Second | First | Requests list of completed jobs known to the printer. | |
BIDI_Q_JOBS_QUEUED | 8014 | Second | First | Requests list of queued jobs known to the printer. | |
BIDI_Q_OUTPUTBINS | 8010 | Second | First | Queries output bins. | |
BIDI_Q_PORT | 800B | First | 2 | Requests information about port configuration from port driver. Returns bidirectional capabilities of the port and bidirectional-software protocol of attached printer. | |
BIDI_Q_PORTDRV | 8019 | First | Requests information on port driver's configuration for the port. Free-format buffer. | ||
BIDI_Q_RESPONSE_FMT | 8018 | First | 5 | Requests format of printer-to-host messages. | |
BIDI_Q_SPOOLER_VERSION | 8022 | Requests spooler-version information. Handled by spooler. | |||
BIDI_Q_STATUS | 8015 | Second | First | Queries protocol converter for the current status of the print device. | |
BIDI_Q_STORAGE | 8023 | Second | First | Returns printer storage-media information. | |
BIDI_Q_SW | 800C | First | 7 | Requests information on bidirectional-software capabilities. Passed to the bidirectional protocol converter to tell the system what bidirectional capabilities are available in the printer. | |
BIDI_READ_ALERT | 801D | First | Requests extended alert information from the protocol converter. | ||
BIDI_READ_PASSTHRU | 8001 | First | Send protocol-specific command to the printer. | ||
BIDI_WAIT_ALERT | 8016 | First | 3 | Wait for an alert. One thread per port driver. |
Query Command | Command Code (Hex) | Sent to Port Driver | Sent to Protocol Converter | Initial Sequence Number | Description |
---|---|---|---|---|---|
BIDI_ADD_VIRTUAL_PORT | 26 | First | Add a virtual-printer port. | ||
BIDI_CANCELJOB | 6 | Second | First | Cancel job in printer. | |
BIDI_DEL_PORT | 28 | Second | First | Sent to the protocol converter and port driver after a spooler port has been removed. | |
BIDI_DEL_VIRTUAL_PORT | 27 | First | Delete a virtual-printer port. | ||
BIDI_DISABLE_ALERT | 25 | Second | First | Disable alerts for a printer. | |
BIDI_ENABLE_ALERT | 24 | Second | First | 9 | Enable alerts for a printer. |
BIDI_END_PASSTHRU | 1B | First | Terminate a passthru reading session. | ||
BIDI_ENDJOB | 3 | Second | First | Issued by port driver during SplPdClose to signal the end of the print job being sent to the printer. | |
BIDI_HOLDJOB | 4 | Second | First | Hold job in printer. | |
BIDI_INIT | B | First | Set printer in bidirectional mode. | ||
BIDI_INIT_PORTDRV | 8 | First | 1 | Initialize a port driver. Once per PortDRV. | |
BIDI_INIT_PROTCNV | F | First | 4 | Initialize protocol converter for a port. Given Q_PORT for each port. | |
BIDI_NOTIFY_ENDJOBCONNECT | 2 | First | Notify port driver that a job connection is not needed. | ||
BIDI_NOTIFY_PORT_RELEASED | 22 | First | Notify port driver that a port is no longer selected in a print object. | ||
BIDI_NOTIFY_PORT_SELECTED | 21 | First | 10 | Notify port driver that a port is selected in a print object. | |
BIDI_PACKET_SIZE | E | Second | First | Define printer-to-host maximum packet size. | |
BIDI_RELEASEJOB | 5 | Second | First | Release job held in printer. | |
BIDI_RESET | 9 | Second | First | Reset the printer. | |
BIDI_RESPONSE_FMT | D | First | 6 | Set format of printer-to-host messages. | |
BIDI_SEND_PASSTHRU | 1 | Second | First | Issue protocol-specific command to printer. | |
BIDI_SET_DEVICE_ID | 23 | First | Set printer's device ID. | ||
BIDI_SET_PORTDRV | 19 | First | Store port-driver configuration data. Free-format buffer. | ||
BIDI_SET_SW | 10 | First | 8 | Tell the port driver the bidirectional software capabilities of the printer. | |
BIDI_SHUTDOWN | A | Second | First | Release all threads waiting for this protocol converter and port driver. Sent to both CNV and PDR. | |
BIDI_STARTJOB | 2 | Second | First | Called during SplPdOpen to signal the protocol converter about the start of the print job. | |
BIDI_START_PASSTHRU | 1A | First | Start a passthru reading session. | ||
BIDI_TERM | C | Second | First | Set printer in unidirectional mode. |