Skip to content

Hacking per-port power switching into an USB hub

February 2, 2014

This post will show you how to modify a USB hub to enable per-port software controlled power switching

———

Recently I started working on automating the second stage backups on my server. In contrast to plugging in manually a hard drive and start the backup script by hand I wanted to have a cron job which does the thing automatically. For this to work, the hard drive needs to be connected to the system all the time.

My server at home is an ODROID embedded board. One of the reasons, besides many others, why I prefer this over a “virtual private server” is cost. The ODROID only consumes 1.5W in idle, which is equivalent to 4€ per year. When I added my second stage backup hard disk, I noticed that the power consumption increased by 2W. Note that this is the consumption when the disk is not spinning. This is quite horrible, because the disk needs to run only once a month for some hours. Thats where my hacker instincs said: “There has to be done something to make this better”.

My first idea was to use one of those manually switchable hubs as seen in the image below.

 

I would have thrown an AVR in there, connected it to one of the USB ports and replaced the mechanical switches by transistors. This way I could have switched the hard disk completely off. This looked doable but also a bit too complicated. That’s why I continued to look if the USB standard offers a similar functionality. And apparently it does! It is call per port power switching (PPPS). Nice! See http://tiebing.blogspot.de/2011/01/use-linux-to-control-outlet.html for an introduction on how to check if your hub is compatible.

However, although most of the USB hubs advertise that they are able to do PPPS, they actually are not supporting this feature. The reason for this is that the chipsets inside the hub usually support PPPS (and advertise themselves as so) but the manufacturer of the hub omitted the switches (to save costs)  and instead connected the USB ports directly to +5V.

The USB hub I had (no-name china crap “ID 0409:0059 NEC Corp. HighSpeed Hub”) did not advertise itself to support PPPS. I cracked it open anyways to see what chip it used. It was the uPD720112 from NEC. And according to the datasheet, it does support PPPS. The trick to enable it was to tie the configuration pin GANG_B to +3.3V. After that the chip did advertise itself as PPPS compatible :) Of course PPPS was still not working as this hub is missing the power switches.

According to the datasheet, the output pins PPB(1:4) for power control of the ports are open-drain Nmos active low drivers which are 5V tolerant. This is exactly what you need for controlling a high-side Pmos switch. Nice! All that there was to do is to cut the VBUS connection to the USB port and add a transistor and a resistor. The circuit of all this is below:

Circuit

A picture of the modified USB hub with one switchable port (note that this picture shows my first attempt using a PNP bipolar instead of a Pmos):

Transistor on USB port

And a picture of the hub controller where I patched into with some enameled wire:

DSCF2004

To switch the port on and off, I used the following program: http://www.advistatech.com/software/hub-ctrl-20060120.c.

A nice feature in the case of a hard drive connected to a switchable port is that you can make the power switching transparent to the user. This can be done by the help of autofs.

The auto.master file looks like this:

/mnt/usbdisk /etc/auto.usbdisk

The contents of auto.usbdisk are:

#!/bin/bash

./hub -b 1 -d 4 -P 1 -p 1

sleep 2

echo "-fstype=auto :/dev/$1"

The auto.usbdisk file is a shell script and needs the rights 755. To explain what this script does: ./hub is the program mentioned above to switch the USB port power on and off. The parameters are:
-b 1: USB bus id to which the hub is connected
-d 4: USB device id to which the hub is connected
-P 1: USB hub port which shall be switched on
-p 1: switch the power on

The parameters for the bus and device id of the hub can be found with the command lsusb. After switching on the port, the script waits for two seconds until the hard disk is recogcnized by Linux. Then the location of the hard disk is reported back to autofs by the echo statement.
If you access /mnt/usbdisk/sda1, autofs will call the script above, which turns on power to the hard disk. After that, autofs will mount the file system and you can access the data. Pretty neat!

After a timeout (the default is 600s) autofs will unmount the file system. I haven’t found a hook to this event to also turn off the power of the usb port. Instead, I wrote a little script which checks if the disk is still mounted. If this is not the case, it is safe to turn off the power.

#!/bin/bash

if [ $# -ne 4 ]
then
	echo "Usage: $0 <disk device> <busid> <deviceid> <portnum>"
	exit 1
fi

if mount | grep "$1 on" > /dev/null
then
	echo "$0: $1 is mounted. Doing nothing"
else
	echo "$0: $1 is unmounted. Turning power off on bus $2 device $3 port $4"
	./hub -b $2 -d $3 -P $4 -p
fi

The script is called at a regular interval by cron. The crontab line for calling it every 15 minutes looks like this:


*/15 * * * * power_off_unmounted_disks.sh /dev/sda1 1 4 1

To be honest, a fixed bus id and device id is not the most elegant thing. A script which finds the bus and device id of the hub automatically is still on my todo list.

So, in summary this post showed you how to enable per-port power switching to off-the-shelve USB hubs. In my case, I use it for switching off two hard disks, a USB TV receiver and a USB sound card. This saves around 10W, which is equivalent to 30€ per year. The best thing about this is that this does not create any overhead for me as the devices are all powered on and off automatically.


UPDATE: Finished scripts

You can get the finished scripts here:

hg clone https://bitbucket.org/befi/general

(The scripts are inside the subdirectory usb_hup_ppps_scripts )

How to use them:

  • Create a symlink to every partition device you need under /opt
    Example:
    ln -s /dev/disk/by-uuid/7865fdg67fh6fd7888dfg5d /opt/data_partition


    The name here is important. The first part is the name of the partition, _partition needs to be fixed!

  • Copy the scripts from the repository (except for auto.*) to /usr/local/bin
  • Put a compiled binary named “hub-control” of this program to /usr/local/bin (gcc -o hub-control hub-ctrl-20060120.c -lusb)
  • Place the auto.* files unter /etc
  • Edit hub_power_control and replace HUB_PID with the product id of your hub. lsusb helps to find the right PID
  • Create a crontab entry:
    */15 * * * * power_off_unmounted_disks /opt/data_partition

  • This can be done with as many disks as you like. Only the first and the last step have to be repeated to add another disk.

    How to use all this? Well, simply access /mnt/data and the disk will be powered on and mounted. That’s all :) The crontab entry then takes care of removing the power.

    To explain the scripts:

  • auto.master: This is the autofs.master file
  • auto.usbdisk: This script constructs the partition device (/opt/data_partition) out of the name given by the acces to /mnt (/mnt/data). It then powers on the disk, waits for 10s and returns the device to be mounted. The rest is done by autofs
  • find_hub_port_of_partition: This script returns the port on which the disk sits on the hub. The argument is the partition device (/opt/data_partition), the output is a number from 1-N (the port number)
  • hub_power_control: This script turn individual ports of a hub on and off. Parameters are the port number and 1/0 (power on or off). The right hub is found with a constant of the product id inside the script. You need to change this to your hub product id (lsusb helps)
  • power_off_unmounted_disk: This script powers off a disk if the partition is unmounted. This does not work with multiple partitions! If another partition on the same disk is still mounted the disk will be powered down. Argument is partition device (/opt/data_partition). This is intended to be called by cron.
  • From → Uncategorized

    One Comment

    Trackbacks & Pingbacks

    1. DIE Lösung für den Heimserver - 9mal6.de

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s

    Follow

    Get every new post delivered to your Inbox.

    %d bloggers like this: