ADC Membership Technical Business Join ADC
Search Advanced Search
Technical Note TN1199
USB Printer Sharing Compatibility

CONTENTS

This Technote describes how USB printer driver developers can make their drivers compatible with USB Printer Sharing.

For printer drivers that support it, USB Printer Sharing provides transparent sharing of printers across a TCP/IP network (including AirPort) and is a significant added benefit for users. By paying attention to a few simple guidelines, printer driver developers can ensure that their drivers work seamlessly with USB Printer Sharing while retaining the ability to use custom csCodes, pass pointers to private data, and display the correct printer name in the Chooser.

This Note is directed at USB printer driver developers who want their drivers to be compatible with USB Printer Sharing.

 Updated: [Jun 19 2000]






Introduction

USB Printer Sharing operates by breaking the local link between a printer driver and its USB printer class driver. The link between these two drivers is traditionally made using a pair of device drivers having entries in both the unit table and the name registry. USB Printer Sharing creates a pair of device drivers on the client. The client printer driver sends commands to these device drivers as it normally would, but instead of passing the commands to a local printer class driver, the USB Printer Sharing device drivers send the commands over the network using TCP/IP to a server Macintosh. The serving Macintosh takes the commands off the wire and invokes the device drivers on the server.

Nonshared printer

A Typical USB Printer Driver



shared printer

A USB Printer Driver Running with USB Printer Sharing




In order for USB Printer Sharing to work correctly on the client Macintosh, it must export a name registry entry from the serving Macintosh into the name registry on the client Macintosh. When the name registry is transferred, USB Printer Sharing tries to maintain the properties from the serving Macintosh. For compatibility reasons, however, there are certain properties that are not transferred. These properties are:

  • name
  • privateData
  • read
  • write

The most basic compatibility problem occurs when the name registry contains properties whose data contains pointers into the serving Macintosh's memory. When this data is transferred to the client Macintosh, these pointers are no longer valid and when software on the client tries to dereference the pointers, the Macintosh will either crash or the printer driver will get incorrect data. See Control and Status Calls for a way around this problem. In addition to the properties listed above, the USB Printer Sharing software will not transfer a property whose name ends with '.private'. For example, the property 'mydata.private' will not be sent from the server to the client's name registry. Printer software can use the '.private' suffix naming convention in order to prevent properties with pointers from being sent across the wire.


Back to top


Printer Name in the Chooser

If a printer driver follows the USB DDK printer driver example, the printer names shown in the Chooser will be taken from the name registry. This is the recommended method for determining the name of a particular printer. There is a maximum length of 31 characters for name registry names, however, and the names created by USB Printer Sharing (a concatenation of the printer name, " on ", and the Computer name as set in the File Sharing control panel) can easily exceed this length. In order to make this full printer name available to printer drivers, the USB Printer Sharing software adds a property, usbps.name, that contains the entire printer name and can be up to 66 characters in length.


Back to top


Name Registry Properties

Any unique name registry properties created by the USB Printer Sharing software, as opposed to those simply transferred from machine to machine by the Printer Sharing software, will be prefixed by 'usbps.'. Currently there are two such properties:

  • usbps.name - The full name of the printer
  • usbps.url - The url for the remote printer

Back to top


Handling Errors

It is important that printer drivers check the errors returned from device driver calls, both those immediately returned and those in the ioResult field of the IOParam block for asynchronous calls. Because of the network nature of USB Printer Sharing, errors (such as host unreachable) are much more common than local USB errors. Printer drivers should be prepared for these errors. In particular, a printer driver should be prepared for an open error as a result of their first read or write transaction. When the device driver is opened, USB Printer Sharing begins to connect with the remote printer, but it returns from open before this potentially long operation is completed. When the printer driver calls read or write, USB Printer Sharing may take that opportunity to return an error indicating that the open failed.


Back to top


Control and Status Calls

In order for USB Printer Sharing to work, it needs to translate a device driver call made on a local Macintosh into a set of network packets that can be decoded and sent to a device driver on the server side. Using pointers in calls to the local device driver can cause problems as they reference memory on the local machine and these pointers are not valid on the server. USB Printer Sharing knows how to handle the buffer pointers that are part of the device driver read and write calls, but control and status can be problematic. USB Printer Sharing special cases the following status call csCodes and knows how to dereference the pointers inherent in these calls:

  • kDrvrCentronicsStatus
  • kDrvr1284IdString
  • kDrvrSoftReset
  • kDrvrNumDevices

In order for USB Printer Sharing to support your custom csCodes, you can define any number of csCodes for USB Printer Sharing to handle using one of two methods: Direct or Indirect.

Direct:

In the Direct method, USB Printer Sharing looks for drvrOut.csCodes2 and drvrIn.csCodes2 entries in the Name Registry. If either is found, its data is taken as an array of shorts representing the extended csCodes that are Direct csCodes. The Printer Class driver supports these with the following protocol: the csParam[ ] array contains 11 shorts that are treated as 22 bytes of raw data, starting at address &csParam[0]. Please note that USB Printer Sharing does not handle pointers in the Direct case. Do not include pointers in the 22 bytes of raw data. If you need to pass pointer-based data, use the Indirect method described below.

Indirect:

In the Indirect method, USB Printer Sharing looks for drvrOut.csCodes1 and drvrIn.csCodes1 entries in the Name Registry. If either is found, its data is taken as an array of shorts representing the extended csCodes that are Indirect csCodes. The Printer Class driver supports these with the following protocol:

Data Address

Data Size

Data Type

Description

&csParam[0]

4 bytes

pointer

A pointer to a buffer that is passed from a device manager client to a device driver (i.e., the printer class driver).

&csParam[2]

4 bytes

unsigned long

The actual size of the data buffer pointed to by csParam[0]. This value is passed over to the Server in the case of drvrOut.csCodes1 and back to the Client in the case of drvrIn.csCodes1.

&csParam[4]

4 bytes

pointer

A pointer to a buffer that is to receive data returned from the printer class driver.

&csParam[6]

4 bytes

unsigned long

The maximum size of the data that can be returned in the buffer pointed to by csParam[4]. Upon return, this value is updated to indicate the actual number of bytes that were copied into the buffer.

Notes:

  • The four bytes beginning at csParam[0] point to a buffer that is passed from a device manager client to a device driver (i.e., the printer class driver).
  • The four bytes beginning at csParam[2] are the actual size of the data pointed to by csParam[0].
  • If csParam[0] is NULL or csParam[2] is 0, then no data is passed from the client to the server.
  • The four bytes beginning at csParam[4] point to a buffer that is to receive data returned from the printer class driver.
  • The four bytes beginning at csParam[6] are the maximum size of the data that can be returned in csParam[4].
  • If csParam[4] is NULL or csParam[6] is 0, then no data will be copied back from the server to the client.
  • The pointers to the buffers in csParam[0] and csParam[4] may overlap.

To add this capability to the sample PrinterClassDriver, insert the following pieces of code.

In PrinterClassDriver.c's RegisterDevice() add:



static short    ourCSCodes[] = { 200, 201, 202 };
RegEntryID    self;
OSErrerr = noErr;

...
if ( err == noErr )
err = RegistryPropertyCreate( &self, "drvrOut.csCodes1",
&ourCSCodes, sizeof (ourCSCodes) );
if ( err == noErr && pPrinterPB->printerProtocol
    != kUSBPrinterUnidirectionalProtocol )
err = RegistryPropertyCreate( &self, "drvrIn.csCodes1",
&ourCSCodes, sizeof (ourCSCodes) );
...


In usbprint.c's DRVRStatus() add:



switch ( pb->csCode )
{
case kDrvrCentronicsStatus:
...
case 200:
case 201:
case 202:
    // do something useful here
...
}


In PrinterClassDriver.c's ControlStatusRequests() add:



switch( ((CntrlParam *) pb)->csCode )
{
case kDrvrCentronicsStatus:
...
case 200:
case 201:
case 202:
    // do something useful here
    break;
...
}



Back to top


Gestalt Information

The Gestalt Selector for USB Printer Sharing is 'zak ' and it returns the version number of the running server. The version number is encoded in the low order word in the same manner as the system software version, e.g., for 1.0 it would be 0x0100 and for version 1.2.3 it would be 0x0123. The upper two bits in the high order word are used as flags to indicate the current state of USB Printer Sharing.

  • If the bit 0x80000000 is set, then USB Printer Sharing is running.
  • If the bit 0x40000000 is set, then USB Printer Sharing was installed at boot time.
  • A Gestalt error means that USB Printer Sharing is not installed.

Here are the constants to use for the above values:

Constant

Value

kServerSignature

'zak '

gestaltUSBPrinterSharingVersion

kServerSignature

gestaltUSBPrinterSharingVersionMask

0x0000FFFF

gestaltUSBPrinterSharingAttr

kServerSignature

gestaltUSBPrinterSharingAttrMask

0xFFFF0000

gestaltUSBPrinterSharingAttrRunning

0x80000000

gestaltUSBPrinterSharingAttrBooted

0x40000000


Back to top


Summary

By paying attention to these simple guidelines, printer driver developers can ensure that their drivers work seamlessly with USB Printer Sharing while retaining the ability to use custom csCodes and pass pointers to private data.

References

Apple's Printing Technologies

Current USB DDK


Back to top


Downloadables

Acrobat

Acrobat version of this Note (120K).

Download




Back to top


Technical Notes by Date | Number | Technology | Title
Developer Documentation | Technical Q&As | Development Kits | Sample Code




Gray line

Contact ADC |  ADC Site Map |  ADC Advanced Search
For information about Apple Products, please visit Apple.com.
Contact Apple | Privacy Notice
Copyright © 2002 Apple Computer, Inc. All rights reserved.
1-800-MY-APPLE