As someone who works with a lot of development boards, most of which come with a USB-to-serial chip of some kind, I deal with an annoying problem pretty often in Linux (currently, Ubuntu 16.04). When I plug the development board into my computer, I’m blocked from doing anything with the USB serial port it creates. The first error I usually get is that permission was denied:

$ cat /dev/ttyUSB0
cat: /dev/ttyUSB0: Permission denied

This is a common problem which is easy to solve — the problem is that the port’s permissions and ownership don’t allow me to access it:

$ ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0 Oct 25 13:45 /dev/ttyUSB0

I usually just add myself to the dialout group after I install Ubuntu to get around this issue. But…this isn’t what this blog post is about. The problem is that after I fix this, log out, log back in, and plug the board back into my computer, I run into this next problem:

$ cat /dev/ttyUSB0
cat: /dev/ttyUSB0: Device or resource busy

What’s interesting about this problem is that if I wait for 15-30 seconds and try again, it works. The problem goes away on its own. I did some sleuthing with the “lsof” command and figured out why this happens. The reason is that ModemManager opens the port when you plug it in, checking to see if a modem is attached to the serial port. I personally find this really annoying.

Luckily, it’s pretty easy to fix with a udev rule. udev already comes with several default rules which prevent ModemManager from looking at some USB serial devices (see the files /lib/udev/rules.d/77-mm-usb-device-blacklist.rules and /lib/udev/rules.d/77-mm-usb-serial-adapters-greylist.rules). Following the pattern in these files, you can create your own blacklist rule which you can put in /etc/udev/rules.d. In this example, I’m going to prevent an imaginary USB-to-serial adapter with USB vendor ID 0x1234 and product ID 0x5678 from being checked by ModemManager.

Create the file /etc/udev/rules.d/99-sample-usb-blacklist.rules and enter the following content, all on a single line:

ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", ENV{ID_MM_DEVICE_IGNORE}="1"

That’s all there is to it. This rule checks for a device in the subsystem “usb” with a DEVTYPE of “usb_device” and a matching USB PID/VID combination. If it finds a matching device, it sets an environment variable called ID_MM_DEVICE_IGNORE to 1, which will tell ModemManager to ignore it. Reload the udev rules with the following command:

sudo udevadm control --reload-rules

Now unplug and replug your development board (or USB-to-serial adapter or whatever it is) and you should notice that ModemManager didn’t interfere.

Luckily, this problem is not as common today as it used to be. Modern versions of ModemManager come with a default rule that “greylists” all USB devices with the FTDI vendor ID so they are only checked if you manually scan for modems–see the 77-mm-usb-serial-adapters-greylist.rules file I mentioned earlier. Most development boards that I’ve seen use FTDI chips, so that rule takes care of them. I still occasionally run into this problem with non-FTDI chips or older versions of Ubuntu, though, and the rule pattern I gave above should fix it.

Note that the ID_MM_DEVICE_IGNORE environment variable needs to be set on the USB device, and not the tty device. In other words, your rule needs to say SUBSYSTEM==”usb” and not SUBSYSTEM==”tty”. I have spent an embarrassing amount of time trying to troubleshoot a rule that didn’t work because of this requirement. If you already have another rule that sets custom permissions on the tty device, you need to create a separate rule to add the ID_MM_DEVICE_IGNORE environment variable to the actual USB device rather than the tty device.

Have you ever wanted to be able to call a C++ Qt library from Python? It turns out it’s pretty easy to do. This tutorial explains how to do it in Mac OS X, but it’s slightly out of date. I’d like to provide the world with a way to make it work with Ubuntu 14.04 out of the box. My instructions are based on that tutorial and the PySide Binding Generation Tutorial. Let’s check it out. Note: This mechanism seems to work for wrapping Qt 4 libraries. I don’t think PySide works with Qt 5, at least in Ubuntu 14.04. Keep that in mind. Everything we do will be with Qt 4.

We’re going to create a library called libdougtest. It’s going to contain a QObject subclass called TestClass. We will create a Python wrapper for it called libDougTestPy, which we will eventually be able to refer to as DougTestPy to follow Python’s library naming conventions. Let’s get started.

Install some prerequisites

There are many things you need installed:

sudo apt-get install build-essential qt-sdk python-pyside* libshiboken-dev shiboken pyside-tools libpyside-dev

I got a warning saying I should install a Phonon backend when I did this, so I also installed the package phonon-backend-gstreamer just in case.

Create a project directory

We’re going to start out by creating a directory for this entire project. Let’s call it  dougtest_project:

mkdir dougtest_project
cd dougtest_project

All work we do will be inside of this directory. The reason I’m naming it dougtest_project instead of just dougtest is because I’m going to create another directory inside of it called dougtest for the C++ library itself.

Create libdougtest

Now, let’s create the good old C++ library that we want to wrap. This is pretty easy, since you just follow the standard Qt way of creating a library. For simplicity, I’ve provided a barebones library containing a single class. We are going to create a directory inside of dougtest_project called dougtest which will be the home for this library:

mkdir dougtest

First of all, create the project file:


QT += core
TARGET = dougtest

HEADERS += testclass.h
SOURCES += testclass.cpp

Now, create the header and source files:



#include <QObject>

class TestClass : public QObject
    TestClass(QObject *parent = 0);
    virtual ~TestClass();
    void doSomething();

    int value;



#include "testclass.h"

TestClass::TestClass(QObject *parent) :


void TestClass::doSomething()
    qDebug("Testing: %d", value);

This concludes the creation of the library. Let’s make sure it compiles:

cd dougtest

If you’re successful, you should see with several symlinks. Change back to the main directory:

cd ..

OK, we have successfully created the library that we’re going to wrap. We haven’t seen anything special yet; the fun is coming now.

Create files for shiboken

Next, we’re going to create some files that shiboken will use during the wrapping process. shiboken is a binding generator for creating Python bindings for C++ libraries, which is exactly what we want.

mkdir data

Create the following two files:


#undef QT_NO_STL

#ifndef NULL
#define NULL 0

#include <QtCore/QtCore>

#include <pyside_global.h>
#include <testclass.h>


<?xml version="1.0"?>
<typesystem package="DougTestPy">
    <load-typesystem name="typesystem_core.xml" generate="no"/>
    <object-type name="TestClass"/>

These files specify the classes to wrap, and will be passed as parameters to shiboken, as you will see shortly.

Create wrapped library project file

Next, we need to create a Qt project that will generate the wrapper library. Create the directory DougTestPy (inside of the main dougtest_project directory):

mkdir DougTestPy

Create the file DougTestPy/

QT += core

# Need to have access to header files from the library being wrapped.
INCLUDEPATH += ../dougtest

# PySide include paths
QMAKE_CXXFLAGS += $$system(pkg-config --cflags pyside)
INCLUDEPATH += $$system(pkg-config --variable=includedir pyside)/QtCore

# PySide dependencies
LIBS += $$system(pkg-config --libs pyside)

# Link against the library being wrapped
LIBS += -L../bin/ -ldougtest

# Generate the wrapper library in the bin directory
TARGET = ../bin/DougTestPy

# Here are all the sources that go with it
    DougTestPy/dougtestpy_module_wrapper.cpp \

This script may be confusing because it refers to source files that we haven’t created yet. This is the naming scheme that shiboken will use when we use it to create the wrapper code.

Create the build script and run it

We are finally ready to create a shell script that will call shiboken and do everything that needs to be done. I hope this isn’t too complicated. It’s very possible that a Makefile would work too, but this is what I have working.

Create the file inside the main dougtest_project directory:


# Absolute path to this script, e.g. /home/user/bin/
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, e.g. /home/user/bin


QT_INC=$(pkg-config --variable=includedir QtCore)/..
QTCORE_INC=$(pkg-config --variable=includedir QtCore)
PYSIDE_INC=$(pkg-config --variable=includedir pyside)
QTTYPESYSTEM=$(pkg-config --variable=typesystemdir pyside)

# I'm assuming the wrapped library is built in-place; if not,
# change WRAPPED_BIN_DIR to the location of the final binaries.


# Clean up the old build to ensure we start fresh. If we don't do this,
# old stale stuff can be left behind, which can cause crashes in the
# library after you make changes.
rm -rf ./bin ./${WRAPPER_NAME}/Makefile ./${WRAPPER_NAME}/${WRAPPER_NAME}

# Copy the latest C++ library build into the bin directory.
mkdir -p bin
cp -R ${WRAPPED_BIN_DIR}/lib${WRAPPED_NAME}* ./bin/

# Now work inside the wrapper directory

# Create the wrappers for the library
shiboken ../data/global.h \
    --typesystem-paths=../data:$QTTYPESYSTEM \
    --output-directory=. \
    --avoid-protected-hack \
if [ $? -ne 0 ]; then
    echo "shiboken returned error. Something is shibroken :-("
    exit 1

# Build the python wrapper library
if [ $? -ne 0 ]; then
    echo "qmake-qt4 returned error."
    exit 1

if [ $? -ne 0 ]; then
    echo "make returned error."
    exit 1

# Back into the directory containing the script
cd ..

# Make meaningful symlink so Python can use the generated library
rm -rf ./bin/${WRAPPER_NAME}.so
ln -s lib${WRAPPER_NAME}.so ./bin/${WRAPPER_NAME}.so

OK, you’re ready to run this build script:


Assuming everything succeeds, you should end up with a bin directory with the following contents:

  • (a symlink to
  •,,, and
  •,,, and

The symlink has to be created because the build process generates a library that begins with “lib”, but Python expects the library to not be prefixed with “lib”. Maybe there is a way to fix it so that qmake doesn’t add the “lib” prefix, but I couldn’t figure out how after a quick search, and this did the trick, so I let it go.

Test the library

We’re ready to test it out. Create the file in the main dougtest_project directory:

import sys
from PySide.QtCore import *
from DougTestPy import *

# Create a TestClass instance
tc = TestClass()

print "Created test class"

# Test the TestClass

print "Called test class function"


print "Called test class function again"

Now, run it. Note that I had to add the “bin” directory to Python’s path in order to use the library. We’re not done with library trickery yet though: depends on So needs to be in the system library path. The easiest way to do this temporarily is to add the bin directory to LD_LIBRARY_PATH:

export LD_LIBRARY_PATH=bin/

For a more permanent solution, you could put* into /usr/local/lib and run “sudo ldconfig” to eliminate the need for that hack.

Now, run the test script:


You should get this output:

Created test class
Testing: 1
Called test class function
Testing: 2
Called test class function again


I hope this was helpful. It’s really not that bad; it’s just that it requires a lot of manual setup. It would be nice if there was something that could automatically generate all the junk we had to make by hand. Maybe such a tool already exists and I’m wasting my time. Either way, I think this is interesting. Thanks again to the people who wrote the tutorials I linked above.

Note that if you use libraries other than QtCore, you will need to add them into the appropriate places in data/global.h, data/typesystem.xml, DougTestPy/, and Just see where the word “core” or “Core” appears, and add your extra libraries such as QtGui and QtXml in the same format.

I’ve already gotten my Willem programmer working in Windows 7 with a custom DLL, so I figured why not do the same in Wine under Linux? I meant to make directions for this earlier, but the last time I looked at this, Wine had a bug that made it really annoying to build 32-bit DLLs on 64-bit Linux. That’s all fixed now, so here we go. These instructions are tested with Ubuntu 14.04 with Wine 1.6. Some older versions of Wine had problems, so this is all I can test with.

Warning: This DLL is slow, and these instructions are fairly complicated. I don’t really want to supply prebuilt binaries, and it requires some special work that might have to be repeated when new versions of Wine are installed due to updates. I’m also too lazy to make it configurable, so you need to change a #define in the code if your parallel port is at an I/O address other than 0x378. If you’re still feeling brave, here’s what I have:

Get your parallel port address

First of all, figure out your parallel port address. Type the following command:

cat /proc/ioports | grep parport

You should see something like this:

  0378-037a : parport0

In this case, the output means my parallel port is at 0x378. Remember this address; we will customize it when we compile the DLL.

Download the DLL source code

Download the DLL source code here:


Extract it. If your parallel port is at an address other than 0x378, open up io_main.c and update the LPT_BASE_ADDR define near the top of the code to match your parallel port address.

Install prerequisites

These packages will probably be necessary to make everything work. I hope I got all of them, but I may have forgotten something. If I forgot something, I apologize. Let me know in the comments.

sudo apt-get install build-essential wine1.6-dev gcc-multilib

Build the DLL

Inside the DLL source directory, type:


Assuming everything goes without error, you should find the file which is the DLL we will be using.

Install the DLL

Remove any io.dll from your Wine installation. It’s useless inside of Wine anyway, so there’s no need for it. Make sure there’s no io.dll file next to EpromM51.exe either. I’m trying to make sure that Wine doesn’t look anywhere else for this DLL. Now, we’re going to put the file in a place where Wine can find it:

sudo cp /usr/lib/i386-linux-gnu/wine/

I messed around, but couldn’t get this to work without putting it right in Wine’s library directory. There might be a better way to do this, but this was the best I could find.

Even if you’re on a 64-bit system, you’ll find that this DLL gets compiled as a 32-bit DLL. So /usr/lib/i386-linux-gnu/wine is always the correct location for this library, regardless of whether your system is 32-bit or 64-bit.

Set up permissions

Here’s the weird part. Raw port access doesn’t work unless you’re root, or you allow the program to have capabilities to access I/O ports. Running things as root is a bad idea, so let’s give the program capabilities to access the I/O ports. Warning: This could pose a potential security threat to your system. We’re actually going to be giving all Wine programs access to the I/O ports.

Here’s the magic command that allows Wine programs to use raw I/O:

sudo setcap cap_sys_rawio=ep /usr/bin/wine-preloader

You may or may not have to re-run this command every time you update Wine. I just don’t know. Anybody else have a better solution for direct port access? I hate having to mess with wine-preloader, but I don’t want to create a separate daemon or whatever due to the added latency.

All done

If you’re followed all these directions, it’s very possible that your Willem programmer is all ready to go now. Give it a shot. I hope this helps someone out there.

Boring details for developers

For anyone who’s interested in how I did this, I created this DLL by taking the original io.dll, fixing its header file so it doesn’t use weird typedefs that confuse winedump, and then running this command:

winedump spec io.dll -I . -t -C

After that, I ran this command:

winemaker . --nosource-fix --dll --nomfc -D__WINESRC__ --wine32

This gave me everything I needed to get this to work. I also had to fix up the generated code–for example, I commented out the line: #include “config.h” in io_main.c.

I’ve been using /etc/network/interfaces to automatically bring up a Grid Connect PCAN-USB adapter when my computer boots up (or when the adapter is hotplugged). It was working perfectly fine in Ubuntu 13.04 and 13.10.

When I upgraded from Ubuntu 13.10 to 14.04, my previous method of adding the CAN adapter to /etc/network/interfaces caused Ubuntu to take forever to boot with a “Waiting for network configuration…” message (and completely broke all of my network interfaces including both ethernet and CAN). It turns out my previous method was bad because I was using the “inet” address family instead of the “can” address family. See “man 5 interfaces” for details on this address family. I found a much better way to make it work. Here’s my new entry in /etc/network/interfaces:

allow-hotplug can0
iface can0 can static
	bitrate 250000
	up /sbin/ip link set $IFACE down
	up /sbin/ip link set $IFACE up txqueuelen 1000 type can bitrate 250000 sample-point 0.7 triple-sampling off restart-ms 500

Make sure that the three indented lines are indented using tabs. Spaces will cause the file to parse incorrectly, but I had to use spaces to make it format correctly on this blog. (BTW, I believe ifupdown is not supposed to be picky about spaces and tabs, but Network Manager is picky about it). I checked and supposedly even 12.04’s ifupdown has this CAN address family supported, so it should probably work in 12.04 (however, it’s untested by me).

I like to set a custom txqueuelen and restart-ms, neither of which seem to be supported in /etc/network/interfaces, so I added a couple of /sbin/ip commands to do it manually. I first have to bring the interface down, then set the rest of the custom options and bring it back up in the process. These commands seem to be executed after the interface has already been brought up, so that’s why I have to bring it back down. The ip command complains if I try to set options on the interface while it’s already up.

The first indented line that says “bitrate 250000” is required. Even though I end up setting the bit rate again in my manual ip command, the first line has to be there or ifup will complain. You can also set the sample point and triple sampling options with lines that say “triple off” and “samplepoint 0.7”, but since I’m specifying them in the manual command anyway, I figured it would be a waste to repeat them.

Hope this helps someone trying to get their CAN adapter to automatically go up. It’s really quite simple, but I couldn’t find any correct examples online.

Update 8/21/2014: I changed these instructions slightly to use “allow-hotplug can0” instead of “auto can0”. This ensures that it works correctly if the USB CAN adapter is not plugged in when the computer starts up. With “auto can0” you may see a long “Waiting for network configuration…” delay if you boot the system with the adapter unplugged.

I have to admit: until recently, udev completely intimidated me. I needed udev rules for changing device permissions or creating symlinks with special names, but usually I had to use Google to find somebody else’s rule. Sometimes a rule I found wouldn’t work because the udev syntax changed–for example, you need to use ATTR or ATTRS instead of SYSFS with recent versions. It still scares me a little bit, but at least I feel like I actually understand what’s going on with it now. I’d like to share a few tips and tricks I’ve picked up about making udev rules.

First of all, the man page for udev is extremely useful. I know man pages can be boring, but this one has just about everything you need to know, and it’s not too long.

Where udev rules are stored

There are two directories where you can find udev rules:

  • /etc/udev/rules.d
  • /lib/udev/rules.d

The rules in /lib/udev/rules.d are bundled rules that you probably shouldn’t be messing with. Instead, put your custom rules in /etc/udev/rules.d. You’ll notice they are named in the form “number-description.rules”. The number is used for ordering the rules, so you can pick an order that makes sense for your needs. It’s a good idea to use that same form so that you have a good idea of the order in which the rules will be parsed. This can definitely matter–I have had troubles with creating symlinks for USB serial devices if the number is too small, probably due to some bundled rule that overrides something my rule does.

If you want to override a bundled rule file that’s in /lib/udev/rules.d, you should create a file with the same name in /etc/udev/rules.d. This will cause the new file in /etc/udev/rules.d to be used instead of the file in /lib/udev/rules.d.

The format of udev rules

udev rules are basically a comma-separated list of things–conditions and assignments. If all of the conditions in a rule are true, the rule is a match and all of the assignments are performed. Similar to many programming languages, a single equal sign (=) represents an assignment, while two equal signs (==) represent a comparison. != represents a “not equals” comparison, += adds a value to a list, and := assigns a value for the final time, disallowing any higher-numbered rules from modifying whatever you assigned. Every condition or assignment is a key-value pair separated by one of the operators listed above.

Keys you can match against

This section, I believe, is the most important part to understand. If you don’t understand the intricacies of how these matches work, especially with the keys ending in S, you will probably make mistaken assumptions about how they work (I did!). You can match against these keys:

  • ACTION — what happened to the device that caused udev to be invoked. Common actions checked against are “add” and “remove”.
  • KERNEL — the name of the device as given by the kernel
  • KERNELS — the name of the device or a parent device as given by the kernel
  • SUBSYSTEM — the kernel subsystem of the device (example: tty or usb)
  • SUBSYSTEMS — the subsystem of the device or a parent device
  • DRIVER — the name of the device’s driver
  • DRIVERS — the name of the device’s driver or the name of a parent device’s driver
  • ATTR{name} — a sysfs attribute of the device
  • ATTRS{name} — a sysfs attribute of the device or a parent device
  • IMPORTANT NOTE: If you are using any of the keys above that match against a parent device (KERNELS, SUBSYSTEMS, DRIVERS, ATTRS) in a rule, the parent device you’re matching against must be the same. For example, you can’t search for ATTRS of two different parent devices in the same rule. You also can’t search for the ATTRS of one parent device and the SUBSYSTEMS of a different parent device in the same rule. You can work around this limitation by creating multiple rules and using GOTO, but you can’t do it all in the same rule. This is actually a good thing because it allows you to do things like make sure you’re looking at a USB serial number instead of a PCI serial number for example.

This is very much an incomplete list, but these are some of the more important ones.

How to find values to match against

The info above is great, but it doesn’t really help much unless you know which driver, subsystem, and event attribute you’re trying to match against. That’s where a really handy command comes into play:

udevadm info --attribute-walk --name=ttyUSB0

ttyUSB0 is an example device name in this case — a USB serial port. This attribute walk command will find all of the keys/attributes for a particular device and all of its parent devices. If you run this command on a USB serial port, you will notice it finds the tty device at the top of the output, which is actually fairly boring as far as matching goes. Then as you scroll down, you will see udevadm walk all the way up the tree of parent devices.. You will see it reach the actual USB device that provides the serial port, the USB hub it’s connected to, the USB host controller the hub is connected to, and then probably a PCI controller or something like that depending on your host system.

Here is some example output from a PL-2303-based USB to serial converter I have connected to a VMware virtual machine:

looking at device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1/2-2.1:1.0/ttyUSB0/tty/ttyUSB0':

looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1/2-2.1:1.0/ttyUSB0':

looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1/2-2.1:1.0':
 ATTRS{bAlternateSetting}==" 0"

looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1':
 ATTRS{bNumInterfaces}==" 1"
 ATTRS{version}==" 1.10"
 ATTRS{manufacturer}=="Prolific Technology Inc."
 ATTRS{product}=="USB-Serial Controller"

looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2':
 ATTRS{bNumInterfaces}==" 1"
 ATTRS{configuration}=="VMware Virtual USB Hub"
 ATTRS{version}==" 1.10"
 ATTRS{product}=="VMware Virtual USB Hub"

looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2':
 ATTRS{bNumInterfaces}==" 1"
 ATTRS{version}==" 1.10"
 ATTRS{manufacturer}=="Linux 3.11.0-12-generic uhci_hcd"
 ATTRS{product}=="UHCI Host Controller"

looking at parent device '/devices/pci0000:00/0000:00:11.0/0000:02:00.0':

looking at parent device '/devices/pci0000:00/0000:00:11.0':

looking at parent device '/devices/pci0000:00':

Let’s pretend we want to match against this device in order to give the device node in /dev permissions that allow it to be read and written by all users on the computer. Unfortunately, this PL-2303-based serial adapter does not seem to provide a serial number, so we’ll have to match against every PL-2303 device that uses the product and vendor ID that this device uses. (Side note: FTDI USB to serial chipsets such as the FT232RL also include a unique serial number, so you can identify a particular USB to serial converter dongle by its serial number. The PL-2303 chipset, at least in this case, does not seem to provide that capability)

First of all, notice that one of the parent devices (/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1) contains the vendor and product IDs of the USB dongle:

  • ATTRS{idVendor}==”067b”
  • ATTRS{idProduct}==”2303″

That will be how we will identify this particular device. This is not the device we want to change the permissions of though; we want to change the permissions of the device at the top of the output that belongs to the “tty” subsystem. That is the actual character device shown in /dev for the port.

Everything above is all of the information we need. Let’s get started creating the rule. I’m going to put it in /etc/udev/rules.d/99-test-usb-dongle.rules. First of all, we will specify that we want to match a device that has a subsystem of tty:


This will ensure we’re changing the permissions of the actual tty device rather than any of the parent USB or PCI devices. Next, we want to match the USB dongle by its USB product and vendor IDs. The USB dongle is represented by several parent devices. In order to match a parent device’s attributes, we will have to use the items that end in S (e.g. ATTRS, KERNELS, SUBSYSTEMS). In this case, we will use the idVendor and idProduct attributes of the device I talked about above:

SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303"

Luckily, both of the ATTRS{} values we need to match belong to the same parent device, which is exactly how it has to work with udev. Now that we’ve matched ATTRS{} contained in the device “/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1”, we can’t match the ATTRS{} or other “ending in S” keys of any other parent device. In this case, we luckily don’t have to worry about that. In other cases, it may be useful to be able to match against keys of multiple parent devices. If you ever run into that kind of situation, you can use LABEL and GOTO to jump to another rule that does another check for other properties of a different parent device. I’m not going to talk about that in this post, but if you look at some of the bundled rules you should be able to figure out how GOTO and LABEL work.

Anyway, back to what we were doing. We have completed the match portion of our rule. All that is left to do is add an assignment to the permissions when the conditions are matched:

SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE="0666"

This sets the permissions of the tty device to allow reading and writing for the owner, the group, and everyone else. Notice that the assignment uses a single “=” rather than a double “==” like the comparisons used. I think that difference was the biggest stumbling block when I first began looking at udev rules. I was very familiar with the difference between “=” and “==” in C, but I didn’t expect udev to use the same distinction. It turns out that it does.

That’s really all it takes. If you save that file in the location I mentioned earlier (/etc/udev/rules.d/99-test-usb-dongle.rules) and reload the udev rules, the next time you plug a PL-2303 USB dongle in, it should have correct permissions.

To reload the udev rules type the following command:

sudo udevadm control --reload-rules

That’s really all there is to it. Now I’d like to do a more complicated example:

More complicated example

Here’s a rule I created for giving certain USB-serial adapters a different name. If a USB-serial adapter with the serial number “12345678” is plugged in, I want a symlink of the form “ttyBlah#” to be created to point to it, where # is an integer. So if I plug three of them in, I want them to be called ttyBlah0, ttyBlah1, and ttyBlah2. This seems straightforward, but there might be other USB-serial adapters plugged in so I can’t just copy the kernel’s device number. For example, let’s pretend five USB-serial adapters are plugged in, named ttyUSB0 through ttyUSB4. ttyUSB0, ttyUSB1, and ttyUSB4 have the serial number “12345678” and ttyUSB2 and ttyUSB3 are other things that don’t use that serial number. I want my symlinks to be called ttyBlah0, ttyBlah1, and ttyBlah2. Notice that I can’t just blindly copy the number over because I want the third one to be called ttyBlah2, not ttyBlah4. It turns out udev can do this with a little bit of help.

I know this idea of having multiple USB devices with the same serial number seems goofy, but I actually did this in the real world. I programmed several FTDI chips to have the same serial number. It’s more convenient than getting a new USB device ID and not knowing if the Linux kernel is going to support it out of the box. The main reason I did it, though, was not Linux-related: it helps prevent Windows from creating a new COM port number each time a device with a different serial number is plugged in. In certain scenarios this behavior is undesirable.

Let’s get to the fun part. Here’s my example rule:

ACTION=="add", KERNEL="ttyUSB[0-9]*", SUBSYSTEMS=="usb", ATTRS{serial}=="12345678", PROGRAM="/home/doug/ ttyBlah", SYMLINK+="ttyBlah%c"

This rule makes use of several new ideas. First of all, I have to match a device with a kernel name of ttyUSB followed by zero or more digits. This should match all USB serial ports. A parent device needs to be in the USB subsystem. This same parent device also needs to have a serial number of 12345678. The reason we’re checking for a subsystem of USB is to ensure that we don’t match against a device that has a PCI serial number (for example) of 12345678 instead. It’s probably overkill since ttyUSB devices are only going to be USB devices anyway, but it’s a good example of how the “ending in S” keys work. Anyway, we’re making sure we match against a ttyUSB* device which has a USB serial number of 12345678. Those three rules combined should match my three adapters that have that serial number.

If they match, we have two assignments. The first assignment is to PROGRAM. If you assign a value to PROGRAM, the value is interpreted as a command to run. The command is executed and the program’s output to stdout can be used in various ways in udev. This script (which we will see later) will print out the next available number to use for ttyBlah. Note that I passed a single argument to my script: ttyBlah. As you’ll see, I made this script generic so it could be used for numbering various different symlinks.

The second assignment uses the += operator, which as I said earlier adds a value to a list. The SYMLINK variable is a list of names of symlinks to create that will point to the matched device. We use += in case another rule has already set up a symlink for this same port.

You’ll notice that the symlink will be named ttyBlah%c. Several of the assigned values (one of which is SYMLINK) can be given names with printf-style formatters to add extra information. %c will be replaced with the stdout output from the program that was executed from the PROGRAM assignment. Another example of the available printf-style substitutions is %b which is the name of the parent device that was matched with the “ending in S” keys.

OK, so that’s pretty straightforward. Finally, I’ll give you the contents of my script (make sure you chmod +x it!):



for i in `seq 0 100`
    if [ ! -e /dev/${SYMPREFIX}${i} ]; then
        echo ${i}
        exit 0

echo Unknown

This is a really crude script, but basically it searches for the next free index between 0 and 100. If for some reason it can’t find a free one, it prints out Unknown. This is actually a pretty lame way to write a script and there are probably better ways to do it. I was just lazy. I’ll never have more than about 5 USB-serial adapters plugged in at a time, so the crude technique doesn’t really bother me.


Don’t be scared by udev. It’s really not that bad. Just sit down, read the very helpful man page, and don’t be afraid to use udevadm’s attribute-walk feature to help you figure out what you need to do.

The other day, I was working on a TI AM3517-based Linux device and I needed to open a serial port at a weird baud rate (31250 bps). The AM3517 is one of TI’s Sitara processors, which are very similar to the popular OMAP chips. The AM3517 is definitely physically capable of doing this baud rate — it starts out with a 48 MHz clock, then it oversamples by either 16X or 13X (thus giving you a 3 MHz or 3.692308 MHz base clock), and then you can supply an integer divisor at that point. With the 16X oversampling, a divisor of 96 would give you 48,000,000 / 16 / 96 = 31250 baud. There was no question that the AM3517 could do the job.

Although the hardware supports it, Linux made it difficult to get the job done. Well, I guess it’s more accurate to say that the combination of Linux and the C library made it difficult.

First of all, the standard way of setting the serial speed is to do the following:

struct termios tio;
tcgetattr(fd, &tio);
cfsetispeed(&tio, B115200);
cfsetospeed(&tio, B115200);
/* do other miscellaneous setup options with the flags here */
tcsetattr(fd, TCSANOW, &amp;tio);

That’s great, except only some standard baud rates have constants: B9600, B19200, B38400, B57600, B115200, etc. There’s no B31250 constant, and you can’t just pass a number to cfsetispeed() and cfsetospeed(). It doesn’t work that way because the speeds are really combinations of bits that get set in the c_cflag member of the termios struct. So essentially, the standard POSIX tcsetattr/tcgetattr API is kind of lame.

I already knew there were ways to get around that problem. I started out by trying the old method that setserial uses:

struct serial_struct serialsettings;
ioctl(fd, TIOCGSERIAL, &serialsettings);
serialsettings.flags &= ~ASYNC_SPD_MASK;
serialsettings.flags |= ASYNC_SPD_CUST;
serialsettings.custom_divisor = 96;
ioctl(fd, TIOCSSERIAL, &serialsettings);

After running that, opening the port with a baud rate of 38400 is supposed to actually use the custom divisor. It’s an ugly way to do it, but it works on a Linux 2.4-based device that I’ve used in the past.

It compiled just fine, but first of all, as soon as my program tried to do the above code, the kernel (the device I’m using has Linux 2.6.37) warned me that setting a custom divisor is deprecated. Worse yet, the TIOCSSERIAL ioctl failed with an error of EINVAL. This is because the kernel’s OMAP serial driver (drivers/serial/omap-serial.c, or drivers/tty/serial/omap-serial.c on newer kernels) doesn’t support that call: serial_omap_verify_port() function returns -EINVAL. So deprecated or not, it just plain doesn’t work with the OMAP serial driver.

I did some looking and dug up a discussion about a replacement for the old, deprecated TIOCSSERIAL method. I also found some other promising leads, including a post on StackOverflow asking the same question.

The discussion about a replacement comes to a conclusion: if the CBAUDEX bit in the c_cflag member of the termios structure is set without any of the other bits from the other B#### constants, then you can put an integer value for the desired baud rate into the c_ispeed and c_ospeed members in the struct. Then, I found a draft patch for this change. The patch includes a new constant called BOTHER (that’s B-OTHER, not “bother!”) defined as the same thing as CBAUDEX by itself.

The patch ended up changing–nowadays, you’ll find that in the kernel, there’s a struct termios and then a struct termios2. termios2 is the new struct that implements the new speed fields. I looked in my glibc header file bits/termios.h, and glibc’s header file actually includes the c_ispeed and c_ospeed members in the standard termios struct. However, the actual code that talks to the Linux kernel, at least in my case, was copying the termios data into an old-style termios struct and using the old-style ioctl that doesn’t look at c_ispeed and c_ospeed.

So after a ton of messing around, I figured out what it takes to do a new-style termios call to set a custom baud rate on newer (2.6+) versions of Linux:

#include <asm/termios.h>

struct termios2 tio;
ioctl(fd, TCGETS2, &tio);
tio.c_cflag &= ~CBAUD;
tio.c_cflag |= BOTHER;
tio.c_ispeed = 31250;
tio.c_ospeed = 31250;
/* do other miscellaneous setup options with the flags here */
ioctl(fd, TCSETS2, &tio);

After doing that, everything worked fine and the OMAP UART worked perfectly at 31250 baud, confirmed with an oscilloscope.

I ran into some #include hell with asm/termios.h, especially if I already had the normal termios.h included elsewhere, so you might have to copy relevant struct definitions into your own code if you can’t get it to work (I know, nasty!). The other thing to keep in mind is that the definition of NCCS might be different between your libc and kernel, so you need to make sure you’re using the kernel’s definition of NCCS. I believe asm/termbits.h has the correct NCCS and structures defined.

Make sure you don’t do another normal tcsetattr() call after the TCSETS2 ioctl, because I’m guessing it’ll probably revert the custom baud rate back to a standard baud rate if you do. I’m not 100% sure on that though.

Anyway, I hope this helps someone. In the end, it wasn’t really that complicated to get working, but it took a lot of research and playing around to understand how to make it work. Maybe I’m missing something, but it seems like glibc and the kernel don’t play well together in this case. It’s also possible that glibc supports this all perfectly and my glibc is compiled incorrectly or something, but either way, manually doing the new-style ioctl like I did above seems to work.

For a few years now, I’ve been fighting a weird problem: X-CTU (which is a software utility provided by Digi for programming XBee modules) is only available for Windows. I do most of my development in Linux so X-CTU is always a pain to work with. It does run pretty well under Wine if you need to use it with Linux or Mac OS X, but when you run it under Wine, it doesn’t detect any serial ports:


Now of course, we all know that you have to add a symlink in your ~/.wine/dosdevices directory to link Wine to your computer’s serial ports:

# ls -l ~/.wine/dosdevices/
total 0
lrwxrwxrwx 1 doug doug  8 Oct 30 21:30 a:: -> /dev/fd0
lrwxrwxrwx 1 doug doug 10 Oct 30 21:30 c: -> ../drive_c
lrwxrwxrwx 1 doug doug 10 Mar 29 18:08 com1 -> /dev/ttyS0
lrwxrwxrwx 1 doug doug 10 Mar 29 18:08 com2 -> /dev/ttyS1
lrwxrwxrwx 1 doug doug  8 Oct 30 21:30 d:: -> /dev/sr0
lrwxrwxrwx 1 doug doug  1 Oct 30 21:30 z: -> /

But even after doing that, X-CTU still doesn’t detect anything. All of the workarounds that I have found require you to define a user COM port in X-CTU:


After going through that process, you can pick the user COM port and X-CTU works perfectly fine (aside from not being able to download newer firmware versions from Digi’s site). As soon as you quit X-CTU, though, the user COM ports you have defined are gone. So whenever you re-open X-CTU, you have to redefine your user COM port. It gets old. So that’s the problem I’ve been fighting: having to manually add the user COM port every time I open X-CTU.

Today I got fed up and ran X-CTU with all of Wine’s debugging information enabled so I could get a clear idea of what X-CTU does when it first loads, in an attempt to figure out how to get the serial ports to show up. Good news: I got it working and now my serial ports show up automatically when I open X-CTU!


I’d like to explain how X-CTU detects attached serial ports, what Wine does in response, and finally, how you can get it working for yourself. Let’s dive in!

How X-CTU detects attached serial ports

X-CTU uses Windows’ Setup API to get a list of attached serial ports. I ran it with Wine set for full debugging and traced out the calls to Setup API functions to figure out exactly what it does. It starts out with a call to SetupDiClassGuidsFromName which, given the name of a device class (“Ports” in this case), returns a list of GUIDs that go with that class. Next, it calls SetupDiGetClassDevs with the list of GUIDs to get a list of devices that belong to the Ports class. It goes through the list of devices and requests the “friendly name” of each port by calling SetupDiGetDeviceRegistryProperty. The “friendly name” will look like one of these examples:

  • USB Serial Port (COM5)
  • Communications Port (COM1)
  • Printer Port (LPT1)
  • Blah blah blah port (COM7)

Notice how the friendly name always seems to end with (COM#) and it also includes other ports like printer ports. Well, X-CTU uses this info to detect the port — if the name of the port contains the string “(COM”, then it grabs the number directly after that string and uses it as the COM port number. It also ignores parallel ports.

So to get Wine to correctly populate the list, we need to figure out what Wine is doing in response to the three Windows functions I listed above. This information was readily available by both checking out the debug trace from earlier and also reading the Wine source code. Let’s go there now…

What Wine does when the setup API functions are called

SetupDiClassGuidsFromName searches in the registry for classes named “Port”. I don’t think it behaves exactly like an actual Windows machine, but here’s what it does on Wine. It searches for subkeys of:


and looks for subkeys that have a class matching the name provided to it. In Wine, it finds the class with GUID {4d36e978-e325-11ce-bfc1-08002be10318}, which according to Microsoft is for COM and LPT ports. Anyway, that’s the single GUID it finds in Wine.

SetupDiGetClassDevs searches in:


for items that match the GUID we found earlier. The above key contains various keys that represent different categories. Then the categories contain keys that represent devices, and the devices contain keys that represent instances of the devices (I believe). The gist of it is that it goes three levels deep through the Enum directory to try to find anything that has a string value “ClassGUID”. If the GUID matches the GUID we found earlier, Wine decides it’s a serial port and returns it in the list of discovered devices. This is the root cause of the whole problem — nothing is put into the registry automatically by Wine for these serial ports. So we’ll definitely need to add this manually, as we’ll see later.

SetupDiGetDeviceRegistryProperty is finally used to get the friendly name for the port. It looks in the same location it looked for the ClassGUID value, but this time it looks for a string called FriendlyName — which, as you guessed it, contains a string in the format of my examples above.

Once I figured this out, I was pretty much home free. So without further adieu, here are the instructions for getting it working.

What to add to the registry

The key (no pun intended) is to add your serial ports as subkeys of:


to satisfy the functions I described in the section above:

  • Create a subkey of Enum and call it SERIAL (although the name you use doesn’t really matter–I believe it searches everything, not just the SERIAL subkey).
  • Create a subkey of SERIAL and call it COM1 (if your port is COM1 — although this name doesn’t really matter)
  • Create a subkey of the COM1 key you just created and call it COM1 also (this name doesn’t really matter either though)
  • In the final COM1 subkey you created, add two string values:
    • ClassGUID — containing the value {4D36E978-E325-11CE-BFC1-08002BE10318} (the GUID for the Ports class)
    • FriendlyName — containing a name in the format “Serial Port (COM1)” without the quotes of course.
      • Make sure the name ends with the COM port name in parentheses as in this example — (COM1). It has to be that way or it won’t work–it might appear in the list, but it will fail to open unless you do it exactly in that format.
      • This is what X-CTU actually uses to decide which port to open. The other “COM1” subkeys we added in the earlier steps aren’t checked for anything — I just named them that way for clarity while you’re browsing the registry.

You can make these modifications using regedit in Wine (type “wine regedit” in a terminal window). Here’s an example screenshot to make it clear what you have to add:


That’s it! You’re done. The ports should now appear automatically in X-CTU. Assuming you have also created the symlinks in ~/.wine/dosdevices for the COM ports you added, they should also be operational.


This is tested in Ubuntu 12.10 with Wine 1.4.1. I would imagine if you can figure out where the dosdevices folder is to stick the symlinks, it will probably work in Mac OS X as well. Your mileage may vary. Good luck!

This strategy definitely works for X-CTU, but it’s not a generic strategy that will work for any Windows program under Wine. Different programs use different methods to get a list of serial ports. Some programs may check for a different key called PortName next to FriendlyName. X-CTU in particular only checks for FriendlyName. If you’re trying to get this to work with a different Windows program, play around. Check programming tutorials to see the various methods people use to enumerate COM ports on Windows. Figure out which method your particular program is using — disassemble it, check what functions it links against, run it in Wine with debugging enabled, etc. Once you’ve figured it out, use Wine’s debugging facilities (and the Wine source code) to see what Wine is doing in response to the various functions that are called. Chances are good that it is looking into the registry and you just need to tweak your registry to give the Windows functions the results they are expecting.

I hope this helps someone out there someday!

I recently dug out an old KVM switch I was playing with back in 2005–the Linkskey LKU-UA02. It’s a compact two-output switch with two USB ports (keyboard and mouse), a VGA port, a speaker jack, and a microphone jack. It works great, but I was a little saddened after I got it and realized it had no Linux or Mac OS X drivers. It was still OK because it has a physical button for changing between which computer to control, but it also had a cool little Windows-only utility for controlling it through software or locking the audio output to a specific computer–and I couldn’t use any of those features from my Mac or a Linux machine.

In 2005 (a.k.a. my college days), I had attempted to write a control utility for it in OS X. I installed USB sniffing software on my Windows PC and recorded the USB traffic as I sent various commands through the Windows control program. I gave it my best shot, even going so far as to ask for a bit of help on Apple’s USB mailing list, but I never figured out how to get past a roadblock I was running into when opening the device in Apple’s I/O Kit. In hindsight, I was probably jumping into something just a little too complicated for my knowledge at the time. With that said, the best way to learn something in the programming world is to do it! It wasn’t wasted time; I definitely learned a lot about USB in the process. I actually believe that the device has something invalid in the descriptor for the endpoint I was using (a zero value for bInterval), and older versions of Mac OS X choked on that problem, so it may not have even been my fault–I think that was the reason I eventually gave up. In fact, if I look at the latest (as of this writing) version of AppleUSBOHCI_UIM.cpp, I see that it still complains if you try to create an interrupt endpoint with a polling rate of zero (it says, “that’s illegal!”), while the analogous UHCI controller code does not have this check.

When I stumbled upon the switch again last week, I decided to take another stab at it. This time, I decided to use libusb, which is better suited for the task given its simplicity compared to I/O Kit and its cross-platform compatibility. I ended up succeeding! Not only does it work in OS X, but it also works great in Linux and Windows 7.

The vendor ID of this KVM switch is 10d5 and the product ID is 000d. The chipset appears to be made by Uni Class, so it’s possible that other KVM switches use the exact same chipset (and thus may be compatible with my control software). In particular, some Googling seems to imply that the TRENDnet TK-407 has the exact same vendor and device ID, although it’s a 4-port KVM switch–I can see how the protocol would scale in that case to switch between four outputs, so I have left room in my code to allow switching between four outputs. Anyway, if you have a device with the same device and vendor ID, you should try it out!

Here is the code (just compile it with your favorite C compiler, remembering to link against libusb-1.0):

#include <libusb-1.0/libusb.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// USB vendor and product ID of the KVM device
#define KVM_VENDOR_ID           0x10D5
#define KVM_DEVICE_ID           0x000D

bool is_kvm(libusb_device *dev);
void print_usage(char *argv[]);

int main(int argc, char *argv[]) {
    int exit_code = 0;

    // Make sure there is a single argument passed to the app
    if (argc != 2) {
        exit_code = 1;
        goto exit_err_early;

    // Convert the argument to a number
    char *endptr;
    unsigned long index = strtoul(argv[1], &endptr, 10);
    if ((endptr == argv[1]) || (index > 3)) {
        exit_code = 1;
        goto exit_err_early;

    // Initialize libusb
    int result;
    result = libusb_init(NULL);
    if (result) {
        fprintf(stderr, "Unable to initialize libusb.\n");
        exit_code = 1;
        goto exit_err_early;

    // Find devices
    libusb_device **list;
    libusb_device *found = NULL;
    ssize_t cnt = libusb_get_device_list(NULL, &list);
    ssize_t i = 0;
    if (cnt < 0) {
        fprintf(stderr, "Unable to get list of USB devices.\n");
        exit_code = 1;
        goto exit_err_dev_list;

    // Look for a match
    for (i = 0; i < cnt; i++) {
        libusb_device *device = list[i];
        if (is_kvm(device)) {
            found = device;

    // Did we find the KVM?
    if (found) {
        libusb_device_handle *handle;

        // Open the device...
        result = libusb_open(found, &handle);
        if (result) {
            fprintf(stderr, "Unable to open KVM device.\n");
            exit_code = 1;
            goto exit_error_open;

        // Claim interface 1...
        result = libusb_claim_interface(handle, 1);
        if (result) {
            fprintf(stderr, "Unable to claim KVM interface.\n");
            exit_code = 1;
            goto exit_error_claim_interface;

        // Send the interrupt transfer
        unsigned char transfer[8] = "\x01\x00\x00\x78\x01\x3B\x00\x00";
        transfer[1] = (unsigned char)index;
        int bytes_sent = 0;
        result = libusb_interrupt_transfer(handle,
            0x02 /* EP 2 OUT */, 
            0 /* no timeout */

        // Check result of transfer
        if (result) {
            fprintf(stderr, "Unable to send KVM switch message.\n");
            exit_code = 1;
            goto exit_error_transfer;

        // Print result
        printf("Switched to KVM output %lu.\n", index);

        // Clean up
        result = libusb_release_interface(handle, 1);
        if (result) {
            fprintf(stderr, "Error releasing interface 1.\n");

    } else {
        fprintf(stderr, "Unable to find KVM USB device.\n");

    libusb_free_device_list(list, 1);
    return exit_code;

// Checks a libusb_device to see if it matches
bool is_kvm(libusb_device *dev) {
    // Grab the descriptor...
    struct libusb_device_descriptor desc;
    if (libusb_get_device_descriptor(dev, &desc) != 0) {
        fprintf(stderr, "Warning: Unable to get device descriptor.\n");
        return false;

    // And see if the vendor/product ID matches
    if ((desc.idVendor == KVM_VENDOR_ID) &&
        (desc.idProduct == KVM_DEVICE_ID)) {
        return true;

    // No match, so false
    return false;

// Prints usage info about the program
void print_usage(char *argv[]) {
    fprintf(stderr, "Usage: %s <index of KVM output (0-3)>\n", argv[0]);

I have noticed occasional error messages saying “Unable to send KVM switch message”, but despite the error, it still switches correctly. My guess is that the USB device disappears before I get a chance to completely close it. There may be a few small improvements needed in that regard, even if the improvement is just to always assume success at that point and not print an error message.

I plan on making a graphical interface (probably with Qt) for easy control in the future, but for now this command line utility works great! There are some extra features available in the KVM switch’s protocol such as automatically cycling between the outputs, fixing the audio port to a specific output, and determining which output is the currently active output. I haven’t implemented any of that extra protocol yet, but it shouldn’t be too difficult to do.

I do want to figure out how to do the equivalent task in I/O Kit at some point just for my own sanity and for some closure on the problem I had back in 2005, but it’s not high on my priority list. After my research into Apple’s open source code described above, I’m fairly sure that I still won’t be able to make it work on an older PowerPC computer at all. It will probably work OK with newer Intel computers, though. In fact, it would be interesting to test the libusb solution on a PowerPC computer to see if it works at all (my guess is it won’t work). So much to try and so little time!

After recently installing Ubuntu 11.10 onto my Mac mini, I’ve been mildly annoyed when I connect to it through PuTTY from my Windows machine. It’s working fine, except gcc displays a weird “â” character instead of quotes in its error messages. I figured it was some weird locale or terminal setting I hadn’t configured properly in Ubuntu because I did a minimal install with only a few server packages, but I was dead wrong. I tried SSHing to a standard Ubuntu 11.10 install with a regular desktop environment and everything, and it still had the weird character in PuTTY!

It turns out that it’s really simple — PuTTY defaults to an ISO-8859-1 character set and Ubuntu defaults to a UTF-8 character set. All I had to do was change my PuTTY settings to use UTF-8 instead:

(The highlight is kind of hard to see, but I clicked “Translation” underneath the “Window” category on the left side to get to that screen.)

After making that change in PuTTY, it works perfectly. Passing the gcc output to hexdump -C shows that the quote characters are represented as:

0xE2 0x80 0x98


0xE2 0x80 0x99

(which are UTF-8 sequences for ‘ and ’, respectively). Sure enough, 0xE2 in ISO-8859-1 is â, and 0x80, 0x98, and 0x99 are C1 control codes, which don’t actually display a character. So that’s the “why” behind this whole situation.

I know this probably seems like a simple thing to write a blog post about, but sometimes it’s kind of freaky when you do a minimal install of a Linux distribution and little glitches like this pop up because you forgot to install or configure a standard package that everyone tends to use. Even though that wasn’t the case here, I know others will run into the same problem and suspect the same thing I did originally, so I hope this helps someone else out (and maybe teaches a little bit of trivia in the process)!

This should also apply to other PowerPC Macs such as the G3, G4, iBook, and various iMac models (I think)…

I wanted to install Ubuntu 11.10 onto my Mac mini after replacing its hard drive. I found some excellent netboot install directions by Evan Martin, which I was able to follow (although I used the files from this directory for the netboot). However, I ran into a small problem when beginning the install–the netboot image for 11.10 does not include the parallel ATA driver for Macs (pata_macio.ko). It causes the installer to not detect any hard drives.

The Ubuntu FAQ I linked to above suggests installing 11.04 and then upgrading to 11.10. I didn’t feel like doing an upgrade install, so I decided to go another route. Here’s how I did it (starting at the point where I was told that no hard drives could be detected)…

  1. I manually downloaded the PowerPC kernel package.
  2. Next, I extracted lib/modules/3.0.0-12-powerpc/kernel/drivers/ata/pata_macio.ko by opening the .deb file with Archive Manager, and stuck it in my TFTP server directory.
  3. Almost there…I used tftp to grab it from my TFTP server and put it in /tmp on the Mac mini
    • Get to a console on the Mac mini by pressing Alt-F2. Remember, on an Apple keyboard, Alt is the option key and you may have to hold down the “fn” key to get F2 to be recognized as F2 instead of a brightness key.
  4. Finally, I inserted the module with insmod, switched back to the installer by pressing Alt-F1, and continued on with my install. I think I had to go back one step and try again, and then the hard drive was recognized.

By the way, it sounds like this will be fixed in 12.04. Yippee! Until then, this is another way of getting it done. I hope this helps someone else out there…