Chapter 2. Printer Drivers

This chapter provides an overview of printer driver processing, followed by a detailed analysis of an example printer driver. The required printer filter/driver options and the reserved and unreserved printer filter/driver options are also covered.

The following topics are discussed in this chapter:

Tip: Printer application developers can skip to Chapter 5.


A printer driver must perform the following tasks:

  1. Receive and process an input file.

  2. Send formatted data to the printer or to standard out. (The driver can use standard out when sending data to the generic drivers phandler and nethandler.)

  3. Query the printer and receive status information. (This step is optional if phandler or nethandler is used.)

  4. Read and write the printer object database (POD) files.

All printer drivers must read the POD files to determine printer-specific defaults and to maintain the active status file of the POD so that other clients can determine the printer's status. Chapter 5, “Printing Libraries,” describes libpod, the library that provides an API to the POD. Appendix C, “Printer Object Database (POD) File Formats,” defines the file formats for the printer configuration file, the printer status file, and the printer log file in the POD.

Printer Driver Processing

Figure 2-1 provides an overview of printer driver processing. Note that this is a simplified overview; the actual steps might be more complex.

Figure 2-1. Printer Driver Processing Overview

Figure 2-1 Printer Driver Processing Overview

Printer Driver Examples

Two example printer drivers are provided: laserjetPJL for HP LaserJet printers and phandler for generic parallel printers. The source code files for laserjetPJL are in the directory /usr/impressario/src/drivers/laserjetPJL and the source code files for phandler are in the directory /usr/impressario/src/drivers/phandler. Both drivers follow the steps shown in Figure 2-1, but the laserjetPJL driver is more complex because it also performs data compression. Because this added complexity is not necessary for the example, the focus is on the phandler driver in this chapter.

The example printer driver phandler checks the status of the parallel port while passing data through to the printer. It treats the input as a byte stream and updates the printer status file at various stages of processing.

Among the include files in this program is pod.h, which contains printer status error codes and other defined constants related to printing. The include file plp.h contains information related to the parallel port.

Program Invocation

The command-line interface for phandler is

phandler -P printer_name [options] [filename]


-P printer_name 

The name of the installed printer (required).


The name of the file to send to the printer. Data is read from standard input if no filename is given.

options can be one or more of the following:


Exit immediately on error. (The default is not to exit on error.)


Suppress warning messages.


Enable debugging. -D is the lowest level of detail, -D -D is the second level, and -D -D -D is the highest level of detail. The debugging information is appended to the log file.

-L filename 

Use filename as the log file for debugging information and errors. The default is to use standard error, which the System V, Release 3 lp spooler redirects to the spooler log file.


Reset the parallel port before sending data.


Ignore interrupts.


Enable sensing of the EOI pin. The default is to ignore the EOI pin.

-B int 

Set the size of the internal transfer buffer to int bytes. The default is 1024. Larger buffers enable more page buffering, which may free upstream filters to do more processing while data is being sent to the printer.


Invoke phandler to update the printer's status. Check the parallel port's status unless -u is specified. Update the paper size if -S is specified.


Used only with -s. Don't check the parallel port's status. This allows the driver to ignore the parallel port while it is updating the POD status file.

-S string 

Set the paper size (for example, A, A4, Legal) to string and update the POD status file for the printer.


Send an ASCII Control-D (hexadecimal 0x4) at the end of the job.

To invoke phandler to update the POD data base, enter this command:

/usr/lib/print/phandler -P printername -s -u -K -S A

This use of phandler only updates the POD data base with the paper size. It ignores the parallel port status, and no information is sent to the parallel port. You normally use this command before invoking any filter that accesses the POD data base to insure that the filter gets the correct paper size.

After updating the POD data base with the paper size, you could send a file to the parallel port with phandler like this:

/usr/lib/print/text2ps -J printername textfile | \
/usr/lib/print/phandler -P printername -K -S A -d 

Here, text2ps is used to convert an ASCII text file to a PostScript file. text2ps uses printername to access the POD and get printer-specific information, such as paper size. Other filters operate similarly to text2ps by accessing the POD for printer-specific information. This is why you run phandler to update the POD status before using a filter.

The output of text2ps is piped to phandler, which sends it to the parallel port while monitoring the printer's status and updating the POD.

Program Processing

This section contains a detailed discussion of the phandler driver. A more detailed example driver is supplied in the /usr/impressario/src/drivers/laserjetPJL directory.

Note: The Impressario guidelines strictly require drivers to retry errors. Error exits are to be avoided whenever possible so that print jobs do not disappear before the user has a chance to fix the error condition.

Do the Initial Processing

  1. Parse the command-line arguments with getopts.

  2. Read the printer status file. If phandler cannot open the status file, it exits with an error message.

Open the Printer Port

  1. Open the port. If there is an error and you requested exit on error when invoking phandler, then the program writes an error message and exits. Otherwise, when an error occurs, the program continues trying to open the port. It checks every n seconds (where n is the value of error_retry_wait) and writes an error message to the log file after each failed attempt to open the port.

  2. If phandler successfully opens the port, it updates the current printer status to “Busy” in the printer active status file. If the command line contained the -s option (status only), then phandler exits after updating the status. (The kernel closes the port when it exits the program.)

Allocate and Set Up the Buffer

Allocate and set up the buffer. If phandler cannot allocate the buffer, the program exits with an error message. (It exits only because memory allocation errors are very rarely recoverable.)

Update libpod Status

Use the fork system call to create a child that updates the printer status.

Read, Process, and Send Data to the Printer

Begin reading from the input and begin sending data to the parallel port.

Your driver will probably need to process the input data into an appropriate printable format before sending the data to the printer.

  1. If an unrecoverable error occurs while writing to the parallel port, write an error message to the log file, write the faulted state to the printer status configuration file, and exit.

  2. If the input file is empty or unreadable, write an error message to the log file, update the status file, and exit.

The driver uses signal handling to ensure that it is not interrupted in “critical regions,” during which an interrupt could destroy vital files or the printer state.

Cleaning Up and Exiting

When printing is complete, update the printer status configuration file to “Idle,” terminate the child status process, and exit.

The Filter/Driver Specification and psrip

The command-line options listed in this section must be implemented as specified for any printing filter or driver to be compatible with Impressario. Switch letters have been chosen to maximize the intuitive correlation with function. Additional functionality beyond that listed here must use unreserved switch settings. Please note the following points:

  • All switches are case sensitive. That is, -P does not have the same meaning as -p.

  • Printer drivers must accept and ignore all reserved options that are not supported.

  • Printer drivers must conform to getopts conventions. (See getopts(2) for more information.)

  • Multiple options on a single line have right-to-left precedence. For example:

    -n 1 -n 2

    has the same effect as

    -n 2

  • The STIFF file passed to a printer driver may have command-line options embedded in it by psrip, a program that converts PostScript files to STIFF files. Drivers that accept input from psrip must accept and parse these command-line options. A good example is a PostScript file that contains a PostScript command to print 5 copies. psrip parses that PostScript command and embeds -n5 in the STIFF file header. This header file information tells the printer driver to print 5 copies. The laserjetPJL example driver demonstrates how to parse command-line options embedded in a STIFF file. Appendix A, “Stream TIFF Data Format,” details the STIFF header format.

Required Options

These switches must be supported by all drivers:


Exit immediately on fault without waiting for faults to clear. The default behavior is to wait indefinitely for faults to clear, polling the device at the error-retry intervals specified in the POD configuration file. This option is used when only a quick query should be done.


Update the status file. Exit only after successfully doing so. This switch has the highest precedence. If the -e switch is given, exit after one try at reading status.


Do not report warnings in the status file. Report errors only.


Enable debugging information. Optionally, more -D switches increase the level of debugging detail. For example, entering

-D -D


enables a second level of debugging detail. At least one level of debugging must be supported.

-P string 

The value of string defines the printer name. The printer name is used to find the POD. The printer name is the name given to the printer at installation time. See the libpod(3) reference page for more information. This option is also a required option whenever the driver is invoked.

Impressario printer drivers must read the libpod printer object database to

  • determine defaults

  • maintain the active status portion of the POD database

  • enable other clients to determine printer status

Reserved Options

The following options are reserved and are to be implemented by drivers whose hardware supports them, or by inline filters that process the options before the driver is invoked. You need not implement all options, but every driver must accept or ignore any unimplemented options on this list.

Raster-specific options include the following:


Flip the image, as if in a mirror. The image is rotated horizontally about the y-axis. Useful for transparencies or decals.

-p int 

Scale the image as if it were being printed on a device with the designated resolution specified in int pixels per inch. This is a convenience switch, since the same effect can be obtained by computing the appropriate scale factor for the image size and destination resolution.

-r int 

Rotate the image counter-clockwise by an angle specified in int degrees. Values outside the range 0-359 should be accepted and modulo converted to a value between 0-359.

-z float 

Zoom the image using proportional scaling, where the floating-point argument is nonnegative. Some values are given below:


Do not zoom the image.


Fill one-half of one page.


Fill one page.

Note: The image aspect ratio must be preserved. Future implementations may extend this to multiple pages. For example, 2.0 would mean fill a 2-by-2 page array.

Engine-specific options include the following:

-q int 

Quality mode. Set the engine-specific quality mode. This should be a nonnegative integer, with greater values indicating higher quality.

-n int 

The number of copies to be printed, a positive integer.


Generate a test print. The test print should confirm that all marking media are present and functional.

-m int 

Manual feed request. Wait MediaWaitTimeout seconds for manual feed. Give up after MediaWaitTimeout seconds and print anyway on the available media. See the POD for these values. Giving up is important for shared printers.

-o int 

Request a specific output medium:


paper or a reflective medium



Other media types may be supported; see the libpod(4) reference pages.

Output-specific options include the following:

-L filename 

Log errors to filename instead of standard error. The file specified should be opened in append mode. If the file cannot be opened, errors should be reported to standard error instead.

-O filename 

Output data to filename instead of the device port or standard output. The file specified should be opened. If the file cannot be opened, data should instead be written to the device or standard output, as appropriate. If this option is used, all status reporting is disabled, because the printer driver is not communicating with the actual device.

Unreserved Options

The switches listed below are not reserved and can be used for device-specific options:

  • Lowercase: a, b, c, d, g, h, i, j, k, l, u, v, x, y

  • Uppercase: A, B, C, E, F, G, H, I, J, K, M, N, Q, R, S, T, U, V, W, X, Y, Z