hpoj reference: ptal-mlcd

The ptal-mlcd daemon implements the HP MLC (Multiple Logical Channels) and IEEE 1284.4 packetized transport protocols over parallel ports and USB, and enables access to the various MLC/1284.4 services on the device, such as print, scan, and PML. Applications use the PTAL frontend API to access local or remote devices, and libptal accesses locally-connected devices controlled by ptal-mlcd through the use of Unix-domain sockets, which, unlike TCP/IP sockets, are not accessible across a network.

Currently, ptal-mlcd performs parallel-port I/O by accessing the hardware registers and performing the IEEE 1284 ECP- and nibble-mode signalling directly from user mode, with no kernel or accelerated hardware assistance. On the other hand, USB support depends on kernel printer-class device driver support.

Click here for more information on setting up basic device connectivity with the hpoj package.

Syntax

The ptal-mlcd command-line syntax is as follows:
	ptal-mlcd bus:name [options...]
Where:

General notes

ptal-mlcd and ptal-printd are typically called by ptal-init, and it's generally unnecessary to invoke them manually from the command line except for development or debugging purposes.

A ptal-mlcd process exists in one of several overall states. When startup is complete, it is in the inactive state. When an application tries to access the device, ptal-mlcd starts to activate, or in other words, establish an MLC/1284.4 communication session with the device. Once that is complete, ptal-mlcd is in the active state. If a communication error happens, which could be the result of a power-off or disconnection of the device or a protocol error, ptal-mlcd deactivates, which includes closing all active application sessions and returning to the inactive state.

ptal-mlcd special-cases the PML (Peripheral Management Language) service on the device, by keeping open a single PML channel while activated, virtualizing application requests to open the PML service, and multiplexing PML requests (gets and sets but not yet traps) from possibly multiple applications over a single PML session with the device. On the other hand, if you specify the -nopml switch, then this behavior is disabled, and only one application may open PML at a time but it has exclusive access to the device's PML service.

Parallel-specific notes

The typical invocation for ptal-mlcd on parallel, set up automatically by "ptal-init setup", is something like the following (split into multiple lines for clarity):
	ptal-mlcd mlc:par:OfficeJet_K80 [-remconsole] \
		-devidmatch "MDL:OfficeJet K80;" \
		-devidmatch "SERN:000000000010;" \
		-base 0x378 -basehigh 0x778 -device /dev/lp0
Specifying the -device switch is recommended if your system has kernel parallel-port support, because it gives ptal-mlcd a mechanism to lock the parallel port and prevent other processes from opening it and interfering with its signalling. Just make sure you specify the right device node, or it won't do any good. Also, unlike for USB, do not specify multiple device nodes, including using wildcards.

USB-specific notes

The typical invocation for ptal-mlcd on USB, set up automatically by "ptal-init setup", is something like the following (split into multiple lines for clarity):
	ptal-mlcd mlc:usb:OfficeJet_K80 [-remconsole] \
		-devidmatch "MDL:OfficeJet K80;" \
		-devidmatch "SERN:000000000010;" \
		-device /dev/usb/lp*
This means that whenever ptal-mlcd tries to activate, it will open up each USB printer device node in turn, search the device ID string for the specified string (normally the model field and possibly also the serial number field), and use the first matching device it finds.

Alternatively, if you only have one USB-connected printer device, you can use a simpler command line such as the following:

	ptal-mlcd usb:0 -device /dev/usb/lp0 [-remconsole]
This usage is not recommended, however, because if you add another USB printer, you'll find that the /dev/usb/lp0 device node assignment may change, depending on what order the devices are connected and powered on. Even if you have multiple USB printers with only one connected and powered on at a time, having a separate instance of the daemons for each model makes it easier to have different print queues/drivers and scanning profiles set up for the different devices as needed.

The -hotplug switch is provided if you want to load ptal-mlcd from a hotplug script. It causes ptal-mlcd to attempt to activate right away and exit if it ever loses and fails to re-establish communication with the device, which would normally only happen due to an unplug or power-off event. However, this usage is not recommended under Linux, because the information on which printer device node corresponds to the hotplugged device is not available to user-mode tools such as ptal-mlcd.

User interface

ptal-mlcd includes the following user-interface features: ptal-mlcd supports the following "virtual" services through ptal-connect: ptal-mlcd logs various kinds of messages to standard output (which may not be visible unless started in a particular terminal window) and syslog (/var/log/messsages): Here is a sample log message followed by an explanation of the components:
	ptal-mlcd: ERROR at ExMgr.cpp:899, dev=<mlc:usb:OfficeJet_K80@/dev/usb/lp0>, pid=17306, e=19
	exClose(reason=0x0010)
ptal-mlcd's debug console is accessible in either of the following ways: When the debug console is active, the following commands may be used:

File-system usage

ptal-mlcd creates Unix-domain sockets in the directory /var/run/ptal-mlcd with the filename based on the first command-line parameter, such as par:0 or usb:OfficeJet_G85. If you specify the -alias switch, then it also creates in that same directory a symlink with the name you specify to the socket. For example, you can specify "-alias mlcpp0" to help migrate from hpoj-0.7 or earlier if you already have a lot of scripts or configuration files that reference the now-obsolete PTAL device name mlc:mlcpp0.

When libptal first opens the Unix-domain socket, it exchanges several request/reply packets with ptal-mlcd, which might include getting the device ID string, service name to socket ID lookup, socket ID to service name ("reverse") lookup, and channel open. In most cases, ptal-mlcd attempts to activate if it's not already active before processing one of these requests. After a successful open reply, for all practical purposes the connection is then a pass-through connection to the requested service on the device.

ptal-mlcd maintains a fixed-maximum-size table of various kinds of "session" structures. Whenever a new connection is received from the named socket, it is assigned to a "command session", which handles the request/reply command interaction with libptal. When an open request is received, the command session is linked with either a "transport session" or virtual "PML session", depending on whether the open request was for a peripheral socket corresponding to the PML service (which is virtualized) or for a different service. As the open is processed the linked sessions go through several state transitions together. If/when the open succeeds, the connection is fully transferred from the command session to the transport or PML session, but if the open fails then the linked session is freed and the connection stays with the command session ready for possibly other commands.

ptal-mlcd depends on the /dev/null "bit-bucket" device for several purposes. First of all, it substitutes /dev/null for the standard input, output, and/or error file descriptors if they aren't already open, which is the case when invoked from a hotplug script. Second, it substitutes /dev/null file descriptors for sessions which don't have an associated file descriptor (such as the master PML session) or sessions which have been closed by libptal but are not ready to be completely torn down by ptal-mlcd (such as when ptal-mlcd gets an error writing to a session's file descriptor, which is not the right state for tearing down the session). The basic requirements for the /dev/null device are that select() should indicate ready to read and write, read() should return an end-of-file condition (zero bytes read), and write() should always "succeed" in writing all of the requested bytes.

Class hierarchy

ParPort: ExMgr: ExTransport:

Porting considerations

The ExTransport classes were ported directly from the USB I/O firmware of the HP JetDirect 175X external print server, which is a VxWorks-based embedded system. The porting task was greatly simplified because the code has almost no system-level dependencies. It was designed to run in a task context with other code, so it doesn't block on anything. The rest of the necessary functionality was largely re-written for Linux and (for better or for worse) dumped into the ExMgr class, with an auxilliary ParPort class. The following system-level assumptions are made by ptal-mlcd: