Al Williams

Dr. Dobb's Bloggers

Your Own Devices

June 15, 2012

I have seen more than one project that succeeded by redefining what success means to fit what the project managed to do.

Everyone has their own definition of success. Some people think money or material goods are indicative of success. Others think friends, family, or life experiences constitute success. I have seen more than one project that succeeded by redefining what success means to fit what the project managed to do.

Last time, I asked the question: Can you write a device driver as a shell script? If I change my definition of a device driver, the answer is yes. Actually, a few weeks back I talked about what amounts to a USB driver written in user space. So if you define a "device driver" as a program that facilitates communicating with a device, it is easy to see that you could do that in a shell script. If you define it as something like "code that handles interrupts in kernel space" then, of course, the answer is no. But what fun is that?

You might think I've gone over the deep end, but honestly this isn't an original idea. The Linux Documentation Project has an article entitled "User-Space Device Drivers". Granted, they aren't using a shell script — they rely on root processes to do arbitrary I/O and map memory. There's even an old (and probably undeveloped) framework for user space drivers called FUSD.

Of course, neither of these have the audacity to claim you can write a driver in the shell. With a sufficient redefinition of success, I assert that you can do it. Continuing on the BeagleBoard LEDs I talked about last time, imagine a device /dev/blinker. The idea is that you can write to this device file a number alone on a line and the LED will blink that many times. If the calling program puts an optional number after the first one (but on the same line), the driver will use that number as the delay (in seconds) for the blinking.

Granted, that's a bit narrow, but I did warn you that I was going to define my own success criteria. The key is to recognize that in Linux (or UNIX before it) everything should look like a file. I say should, because an alarming trend these days is for new features to not look like files, and that worries me. Ignoring that, though, the device I just defined is a file in the /dev directory. The only problem is, a regular file won't let you easily write a program that responds when someone writes to the file. A named pipe, or a FIFO if you prefer, fits the bill perfectly. It looks exactly like a file, but it simply sends data from one end to the other end.

Notice I did cheat a little. Named pipes on Linux are strictly one way. Luckily, I defined the problem so that you only had to have data transfer in one direction. Still, you could easily define two pipes, if you like — one to read and one to write. You have to make some sacrifices if you want to avoid writing a real device driver.

Here's a quick implementation:

#!/bin/bash
# Output pin
LED=/sys/class/leds/beaglebone::usr0
# Device node to make
DEVNAME=/dev/blinker
# default pause in seconds
DEFPAUSE=.5
# Turn off LED automation just in case
echo none >$LED/trigger
# arrange to delete fifo on exit
trap 'rm $DEVNAME' EXIT
# See if node exists
if [ ! -p "$DEVNAME" ]
then
# nope, make it
mkfifo =m 622 "$DEVNAME"
fi
# either it was there or we made it
# either way, it should be here
if [ ! -p "$DEVNAME" ]
then
echo 1>&2 Can\'t create device file
exit 1
fi
# Read input from the pipe
while read -a INDATA <"$DEVNAME"
do
# set default pause
PAUSE=$DEFPAUSE
# get the count
COUNT=${INDATA[0]}
# see if there was an override pause
if [ "${INDATA[1]}" != "" ]
then
PAUSE=${INDATA[1]}
fi
# special case: if COUNT=-1 shut down "driver"
if [ $COUNT == -1 ]
then
exit 0
fi
# now do the work
# loop for count times and blink the led
for (( i=1; i <= $COUNT; i++ ))
do
echo 255 >$LED/brightness
sleep $PAUSE
echo 0 >$LED/brightness
sleep $PAUSE
done
done
# Should not get here
exit 0

This all goes along with my theme that if you are using Linux, you can take a different approach to development than if you were programming a classic embedded system. I don't know that I'd seriously suggest writing a driver like this in shell script, but then again, if this is what you really needed, why not?

This isn't even the strangest use of script I've seen. Google "bash web server" and you will see multiple HTTP servers written in bash (one in only one line).

There is at least one other objection to coding in shell script. Users may decide to "hack" your software which, after all, is just a text file. I ran into that problem years ago, and I'll share my solution with you next time. Meanwhile, even if you don't write any device drivers in the shell, maybe you can at least use it to win a bar bet. Assuming, of course, you hang out in bars with other programmers.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!