Saturday, July 16, 2011

Print Server for DD-WRT (hotplug version)

Hotplug is a set of scripts running upon certain predefined conditions. On today's Linux system, hotplug can do many things from auto mounting USB drives to pairing bluetooth devices to network configuration.

It's seldom mentioned, but DD-WRT does offer (very preliminary) hotplug support. With almost no info on the web, the job is done by digging though DD-WRT's source code and various Linux documents.

  1. Replace DD-WRT's event handler with our own
    By default, DD-WRT registers
    /sbin/hotplug to handle all hotplug requests, but the program doesn't follow standard hotplug rules, and, per my understanding, is a dummy and does nothing at all. So let's replace it with our own.

    Create a startup script /opt/etc/init.d/hotplugd with only one line:

    echo /opt/sbin/hotplug > /proc/sys/kernel/hotplug

    Then set it to run upon start up
    chmod a+x /opt/etc/init.d/hotplugd
    ln -s /opt/etc/init.d/hotplugd /opt/etc/init.d/S95hotplugd

    run
    /opt/etc/init.d/hotplugd

    and check the result:
    cat /proc/sys/kernel/hotplug

    The output should be /opt/sbin/hotplug, which is our new event handler.

  2. Test drive hotplug
    So how does the hotplug work? The script below will give you some idea to start with:
    Create /opt/sbin/hotplug with following:

    #!/bin/sh
    #For Debugging
    echo "Customized hotplug" >> /tmp/hotplug.log
    echo -------------$(date)----------- >> /tmp/hotplug.log
    set >> /tmp/hotplug.logset it as executable
    chmod a+x /opt/sbin/hotplug
    Unplug the printer, wait few seconds and plug the printer back in.  Check the log by running:
    cat /tmp/hotplug.log

    You can see there are bunch of environmental variables logged, two of them are worth noting:
    • ACTION: The value for "ACTION" variable can be "add" or "remove", corresponding to device plugin and removal.
    • PRODUCT: This is the unique device ID for the USB device, my printer is HP 1020 and value is 3f0/2b17/100.

    In a full Linux system, hotplug is much more complex. My script is a quick dirty hack but should be sufficient to handle USB printers.

  3. Configure hotplug to upload firmware to the printer
    Some GDI printers (Windows printers) will require extra work on Linux. Below is an example of my HP Laserjet 1020 but also applies to others.


    You'll need two things to start with:
    • The printer's firmware - this must be in the printer before printing. Some popular HP printers can be downloaded from http://oleg.wl500g.info/hplj/
    • Usb_printerid - this is used to detect if the firmware is already in place to prevent duplicated firmware uploading. Above link has one but that's for Broadcom devices. So I compiled one for Atheros routers. Download here. Extract and put it on the router.

    Put the firmware in /opt/usr/local/lib/ and usb_printerid in /opt/usr/local/bin/, and run:

    chmod a+x /opt/usr/local/bin/usb_printerid

    And finally, here is the full script for /opt/sbin/hotplug. Be sure to replace the red parts with your own details.

    #!/bin/sh

    #For Debugging
    #echo "Customized hotplug" >> /tmp/hotplug.log
    #echo -------------$(date)----------- >> /tmp/hotplug.log
    #set >> /tmp/hotplug.log
    P910ND='/opt/usr/sbin/p910nd'
    PRINTERID='/opt/usr/local/bin/usb_printerid'
    FIRMWARE='/opt/usr/local/lib/sihp1020.dl'
    #replace it with your printer's firmware.
    if [ $DEVTYPE == 'usb_device' ] && [ $PRODUCT == '3f0/2b17/100' ]; then
    #replace with your printer's device id.
      if [  $ACTION == 'add' ]; then
        #check and upload firmware
        ${PRINTERID} /dev/usb/lp0 | grep -q FWVER || cat ${FIRMWARE} > /dev/usb/lp0
        #kill and restart p910nd
        kill -9 $(pidof p9100d)
        ${P910ND}  -b -f /dev/usb/lp0 0
      fi
      if [ $ACTION == 'remove' ]; then    #printer removed, lets stop p910nd
        kill -9 $(pidof p9100d)
      fi
    fi


    The above script will upload firmware to the printer then start p910nd daemon upon printer plug-in and stop p910nd when it's removed.

  4. Modified p910nd startup script
    With above script, DD-WRT will automatically configure the printer after the router is fully booted. However, a similar approach has to be done during startup as hotplug does not take effect at that moment.

    For unknown reasons, DD-WRT will NOT create /dev/usb/lp0 for printer even we have printer support enabled. As a result, we can't use this device node to detect the printer's presence.

    Here is a modified version of the /opt/etc/init.d/p910nd startup script:

    source /mnt/root/.profile
    mkdir -m 755 -p /dev/usb
    mknod -m 660 /dev/usb/lp0 c 180 0
    sleep 1
    P910ND='/opt/usr/sbin/p910nd'
    PRINTER_ID='/opt/usr/local/bin/usb_printerid'
    FIRMWARE='/opt/usr/local/lib/sihp1020.dl'
    #replace with yours
    PNAME='LaserJet'
    #printer name id string, see below
    i=$(find /sys/devices/platform/ -name product -exec cat {} \; | grep -c ${PNAME})
    if [ $i != '0' ]; then
         ${PRINTER_ID} /dev/usb/lp0 | grep -q FWVER || cat ${FIRMWARE} > /dev/usb/lp0
         kill -9 `pidof p9100d`
         ${P910ND}  -b -f /dev/usb/lp0 0
    fi

    Notice the PNAME='LaserJet' line. The 'LaserJet" is part of the printer's name and can be used to check if the printer is plugged. To determine yours, run:

    find /sys/devices/platform/ -name product -exec cat {} \;

    The result looks like this:
    HP LaserJet 1020 #printer
    DataTravelerMini #USB flash drive
    Atheros AR91xx built-in EHCI controller #USB controller
Now just follow the simple tutorial to install the printer in Windows if you haven't done so. And enjoy the convenience of your hotplugged networked printer!

0 comments:

Post a Comment