2014-09-18

Getting USB printer to work under OpenBSD

I am writing this post mainly for myself, although it may be helpful to other OpenBSD users as well.

Preparation

The first and most important step is to find a driver for your printer. Binary Linux–only support packages most likely won't help, particularily in case of amd64 system, so your only hope is open–source driver.

I was lucky to find that my printer is supported by Gutenprint project, and thus a driver is available in gutenprint package (print/gutenprint port).

So, the preparation stage concludes into following command:

$ sudo pkg_add a2ps gutenprint

Now, that packages are installed, we are ready to continue with configuration.

Device

By default OpenBSD recognizes USB printers and assigns ulpt(4) driver to them. Unfortunately, this printer can't work via ulpt(4), so we have to disable this driver in kernel:

$ sudo config -fe /bsd
OpenBSD 5.6-current (GENERIC.MP) #372: Wed Sep 10 18:03:54 MDT 2014
todd@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
Enter 'help' for information
ukc> disable ulpt
282 ulpt* disabled
ukc> quit
Saving modified kernel.

Running the same command without -f switch will result in modification to the current kernel, which is needed to avoid rebooting.

Now that printer will be identified as generic usb device (ugen(4), the appropriate file permissions for corresponding devices should be set. Once printer is connected to OpenBSD PC, it will show up in dmesg and usbdevs as ulptN device:

$ usbdevs -d
addr 1: EHCI root hub, ATI
uhub0
addr 2: MP210 series, Canon
ugen1
addr 1: EHCI root hub, ATI
uhub1
addr 2: Integrated Camera, Ricoh Company Ltd.
uvideo0
addr 1: OHCI root hub, ATI
uhub2
addr 2: Broadcom Bluetooth Device, Broadcom Corp
ugen0
addr 1: OHCI root hub, ATI
uhub3

In this case it appears as ugen1 (its identifier, "MP210 series, Canon") will also be needed later.

As lpt operates with "daemon" permissions, and sane operates with group "_saned", both daemon will be able to use device after following change in ownership:

$ chown daemon:_saned /dev/ugen1.*

Getting PPD

According to /usr/local/share/doc/pkg-readmes/cups-filters, there are two ways of getting PPDs:

  1. Get readily available PPD file from /usr/local/share/foomatic/db/source/PPD or
  2. Generating one from source.

Unfortunately, there is no pre-build PPD for Canon PIXMA MP10, so PPD should be generated manually following instruction from /usr/local/share/doc/pkg-readmes/foomatic-db-engine:

$ sudo mkdir /etc/foomatic/direct
$ foomatic-ppdfile -P MP210
Canon MP210-series Id='Canon-MP210-series' Driver='No Default Driver' CompatibleDrivers='gutenprint-ijs-simplified.5.2 gutenprint-ijs.5.2 '
Canon MULTIPASS-MP210 Id='Canon-MULTIPASS-MP210' Driver='No Default Driver' CompatibleDrivers='gutenprint-ijs-simplified.5.2 gutenprint-ijs.5.2 '
$ foomatic-ppdfile -p 'Canon-MP210-series' -d 'gutenprint-ijs.5.2' | sudo tee /etc/foomatic/direct/canon.ppd >/dev/null

(Of course "MP210" and "Canon-MP210-series" "gutenprint-ijs.5.2" and "canon" in PPD path should be replaced with parameters corresponding to actual printer. Choice of particular driver among several matching is, of course, individual. If in doubt, choose randomly and try; you'll always have a chance to make different choice any time later.)

Configuration

Readme file /usr/local/share/doc/pkg-readmes/cups-filters gently suggests continuing with creating a converter script (filename may be chosen by user; I chose /etc/converter.sh):

#!/bin/sh

/usr/local/bin/a2ps -BRq --columns=1 -o - | \
 /usr/local/bin/foomatic-rip -P canon

Next, /etc/printcap entry pointing to actual printer device and converter script should be created:

lp|canon:\
 :lp=/dev/ugen1.01:\
 :if=/etc/converter.sh:\
 :sd=/var/spool/output:\
 :lf=/var/log/lpd-errs:\
 :sh:

(In MP210 the actual device turned out to be /dev/ugen1.01. Actual number of sub–device may be different on other devices.)

Ultimately lpd service should be enabled and started:

$ sudo rcctl enable lpd
$ sudo /etc/rc.d/lpd start

At this stage printing test document should succeed:

$ lpr test.pdf

Scanner

Scanner component of the device should already work since changing ownership of /dev/ugen1.*:

$ scanimage > 1.pnm
scanimage: open of device pixma:04A91721 failed: Access to resource has been denied
$ sudo scanimage > test.pnm

(Scanning should probably work without "sudo". The last command, although it produces the output image, exists with non-zero status and "Bus error (core dumped)" message. I'll investigate these issues and update this post "later".)

Hotplugging

Although contrary to /usr/local/share/doc/pkg-readmes/cups-filters ownership of /dev/ugen1.* devices persists over reboots, there is no guarantee that every single time the printer will attach as ugen1 each and every time.

The process of changing and restoring permissions may be automated using hotplugd(8) daemon. To make hotplugd do its job the following files should be created:

  • /etc/hotplugs/attach:
    #!/bin/ksh
    
    DEVCLASS=$1
    DEVNAME=$2
    
    case $DEVCLASS in
      0) # Generic devices
        if [ "${DEVNAME%%+([0-9])}" == "ugen" ]; then
          DEVDESCR=$(usbdevs -d | grep -B1 ugen1 | sed -Ee 's/ addr [0-9]+: (.+)$/\1/' -e 1q)
          if [ "${DEVDESCR}" == "MP210 series, Canon" ]; then
            chown daemon:_saned /dev/${DEVNAME}.*
            echo "#!/bin/ksh\nchown root:wheel /dev/${DEVNAME}.*" > /etc/hotplug/detach.$DEVNAME
            chmod +x /etc/hotplug/detach.$DEVNAME
            echo "/canon/\n/:lp=/c\n\t:lp=/dev/${DEVNAME}.01:\\n.\nwq" | ed /etc/printcap
          fi
        fi
        ;;
    esac
    
    (Upon detecting "MP210 series, Canon" device the script changes permissions, fixes device name in /etc/printcap and creates a script for cleaning up permissions after device is disconnected.
  • /etc/hotplug/detach:
    #!/bin/ksh
    
    DEVCLASS=$1
    DEVNAME=$2
    
    if [ -x /etc/hotplug/detach.${DEVNAME} ]; then
      /etc/hotplug/detach.${DEVNAME} && rm /etc/hotplug/detach.${DEVNAME}
    fi
    
    (Basically this file just calls cleanup scripts and removes them after completion.

With this setup the printer may be connected and disconnected on demand with no additional actions required.

Further directions

By default a2ps and foomatic-rip understand several formats including PostScript, PDF and DVI documents, as well as popular image types and several other formats. Support for additional formats may be added by modifying /etc/a2ps.cfg and /etc/a2ps-site.cfg files. Reading manuals may also help.