Print

Installing FTDI USB Serial Driver on Mac

A USB serial device has three components needed to make it work as a traditional serial port (by which I mean a device in /dev that a terminal program can be connected to:
  • the hardware
  • the usb driver
  • the serial driver

Having plugged in (and powered on) the USB serial port device, it will show up as a USB device on most operating systems without further action. The standard operating system USB driver can recognize a USB device and display information about it in System Profiler.
However a serial driver needs to sit on top of the USB interface to make the device actually behave like a serial port.
There is a further complication in that many products (serial ports or other) might want to implement a USB interface. So that each software driver can identify it's own USB device, every USB device has a Vendor Identifier (VID) and a Product ID (PID).
The VID/PID tend to be unique to each different product so that drivers can identify their own device/product in a system with multiple USB devices (small bespoke devices may violate this guideline). This property of uniqueness means that even two different products both using the same USB serial chipset effectively need different drivers. There doesn't appear to be a usable "class of device" concept (eg 'Generic Serial Port') even for products using the same chipset. This problem is resolved by a configuration file with each (serial) driver that lists every product (ie every PID/VID combination) that can be used with the specified driver.
Mass produced devices are typically pre-registered in the driver config file, but other products, particularly bespoke devices often won't be in the configuration file, so the serial driver (in this case) won't recognise them as belonging to it. Some device manufacturers don't bother obtaining a personalised vendor ID and just use (in this case) FTDI's vendor ID (0x0403 in hex or 1027 decimal).

Thankfully a text editor and a little courage is all that is required on Linux and Mac to address this problem.

My Environment

  • Mac OS X 10.5.8 (Leopard) - Should work same on Tiger, Snow Leopard etc.
  • FTDI USB Serial chip (FT2232D) on a Marvell 88F6281 OpenRD Eval Platform


Steps

Step 1 - Look for any existing USB devices
  • Make sure the device in question is DISconnected
  • Since we probably don't know what the device will be named in /dev we will look for changes.
In a terminal window: ls -las /dev > $HOME/dev_off.txt
If you happen to know it will contain say "usb" (ignoring case) you can do the step visually: ls -las /dev | grep -i usb

Step 2 - Connect the device
Plug in the device with the FTDI chip on it and power up device as required.

Step 3 - Look for any new USB devices
  • In a terminal window: ls -las /dev > $HOME/serdev_connected.txt
  • Then: diff $HOME/serdev_off.txt $HOME/dev_connected.txt
  • (If you're doing this visually just use ls -las /dev | grep -i usb instead of the above lines
  • Look for any changes, hopefully something with a "tty" and/or "usb" in its name.

If you do get a new device appearing then chances are you have the right driver installed and you can STOP here(low-level operating system USB drivers typically don't create entries in /dev for each device attached).
Assuming you're not this lucky (which is probably why you are reading this, continue on with the following steps...

Step 4 - Check Operating System has detected the USB device
  • Open System Profiler
  • Select Hardware -> USB and look for the device (you may need to expand the USB Device tree).
(Note if you don't recognise it, try unplugging the device, then close and reopen the Profiler window and look for differences. This step can also be done using the ioreg command line or even iosnoop if you're really stuck. Eg ioreg |grep FTDI.

In my case the new device appears in System Profiler as:
System Profiler Information
OpenRD JTAGKey FT2232D B:
  Product ID:	0x9e90
  Vendor ID:	0x0403  (Future Technology Devices International Limited)
  Version:	5.00
  Serial Number:	FTSDIXOJ
  Speed:	Up to 12 Mb/sec
  Manufacturer:	FTDI
  Location ID:	0x1d100000
  Current Available (mA):	500
  Current Required (mA):	100


Step 5 - Record the PID and VID
  • Note down the Product ID and Vendor ID.

Step 6 - Obtain Driver.
  • Go to the vendor's website and download the correct driver for your chip and operating system.
  • Example: FTDI and OS X
    • Go to FTDI website: http://www.ftdichip.com/Drivers/VCP.htm (external link)
    • Find the Mac OS X entry for your chip (FTDI appear to combine all devices in the same driver so it should be easy)
    • Download the driver - eg click on the driver version link (version 2.2.14 as at December 2009)
Note: In my case the list only had FT2232H not FH2232D, but the H version worked fine.

Step 7 - Install the Driver
  • Open the dmg and select the right package for your version of Mac OS X.
  • Install it.
  • At this point the kernel extension (driver) is not loaded - which is good for us.

Step 8 - Maths...
  • Convert the PID and VID to decimal.
    • Either use the Programmer mode of the desktop Calculator, or
    • if you like command line stuff see the box
    • or if you're a hacker do it by hand or in your head :-)

Information Converting Hex to Decimal
Converting number bases on the command line.
  • In a terminal window enter: dc -e "16i XXXX p XXXX p"
    • where XXXXs are replaced with the PID and VID as follows:
    • first remove the leading ox
    • convert any lower case letters to uppercase.

Example:
dc -e "16i 9E90 p 403 p" 
40592
1027

All this does is convert base 16 into base 10 for each of the two numbers (man dc or man bc if you want to learn more).
So 0x9e90 (hex) is 40592 in decimal and 0x403 is 1027 in decimal.


Step 9 - Look for your product in the driver.
  • cd /System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/
  • view the Info.plist file (read only) in a text editor and search the file for for your PID (and VID).

Note that each device is grouped in a section. For the FTDI file each entry in the relevant XML section looks something like:
<key>XXXX_Product Name_XXXX</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.FTDI.driver.FTDIUSBSerialDriver</string>
            <key>IOClass</key>
            <string>FTDIUSBSerialDriver</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>XXXX_PID_XXXX</integer>
            <key>idVendor</key>
            <integer>XXXX_VID_XXXX</integer>
        </dict>

The key thing to look for in the FTDI file is <dict>'s containing com.FTDI.driver.FTDIUSBSerialDriver as the CFBundleIdentifier.

If you find your device (both VID and PID match and hopefully the Product Title looks something like that shown in System profiler) you can skip straight to Step 11.
Note: you could just try installing the kernel and checking /dev but if it fails you need to unload the driver which can be troublesome in some cases (and may require a reboot).

Step 10 - Add the new device configuration
Note: If you not comfortable with XML, phone a friend!
  • open Info.plist in a text editor (preferably read only).
  • Select a complete device description such as the example in the previous section. Some may have extra parameters, choose one of the simplest as your template.
  • copy and paste it into TextEdit (say).
  • Carefully substitute in your device info: description (from System Profiler - doesn't have to be identical AFAIK), VID, PID.
    • The description should not contain any XML special characters. If in doubt just avoid non-alphanumeric characters
  • sudo bash
  • cp Info.plist Info.plist.ORIG (make a backup copy)
  • Edit (eg vi) Info.plist (use a text editor only, not a word processor)
  • Find the first or last com.FTDI.driver.FTDIUSBSerialDriver dict item
  • Add in your entry CAREFULLY.

Example new entry
<key>OpenRD JTAGKey FT2232D A</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.FTDI.driver.FTDIUSBSerialDriver</string>
            <key>IOClass</key>
            <string>FTDIUSBSerialDriver</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>40592</integer>
            <key>idVendor</key>
            <integer>1027</integer>
        </dict>


My case was a little more complex. The FT2232 IC has two serial ports (even though only the 'B' port showed up in System Profiler!, so I needed two entries with subtle differences (note the difference in the description and bInterfaceNumber.

My FT2232 dual serial port entry
<key>OpenRD JTAGKey FT2232D A</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.FTDI.driver.FTDIUSBSerialDriver</string>
            <key>IOClass</key>
            <string>FTDIUSBSerialDriver</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>40592</integer>
            <key>idVendor</key>
            <integer>1027</integer>
        </dict>
        <key>OpenRD JTAGKey FT2232D B</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.FTDI.driver.FTDIUSBSerialDriver</string>
            <key>IOClass</key>
            <string>FTDIUSBSerialDriver</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>1</integer>
            <key>idProduct</key>
            <integer>40592</integer>
            <key>idVendor</key>
            <integer>1027</integer>
        </dict>


Some devices may take additional configuration data, but you have to know what it is...

Example of FTDI specific extra configuration data
<key>Frodo Device</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.FTDI.driver.FTDIUSBSerialDriver</string>
           <key>ConfigData</key>
            <dict>
                <key>BaudRates</key>
                <dict>
                    <key>BAUDALL</key>
                    <integer>115200</integer>
                </dict>
                <key>PortName</key>
                <string>BLAH</string>
            </dict>
           <key>IOClass</key>
            <string>FTDIUSBSerialDriver</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>12345</integer>
            <key>idVendor</key>
            <integer>1027</integer>
        </dict>



Step 11 - Load and driver
  • Check the kernel extension is not already loaded: kextstat |grep FTDI
    • It should not return anything (ie not currently loaded) If it is you need to unload it or just reboot.
    • To unload it: kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext
    • Note: Unloads do sometimes fail for various reasons not discussed here... look for "success" output
  • To load it (you need to be root or use sudo for this):
    • kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext
    • It should say: kextload: FTDIUSBSerialDriver.kext loaded successfully
  • Check it's loaded:
    • kextstat | grep FTDI should return something similar to (numbers may be different):
bash-3.2# kextstat |grep FTDI
  117    0 0x5b589000 0x7000     0x6000     com.FTDI.driver.FTDIUSBSerialDriver (2.2.14) <102 38 12>


Step 12 - Look for new /dev entries
  • Make sure your device is plugged in and powered up (as these /dev entries tend to appear and disappear dynamically these days)
  • ls -las /dev | grep -i usb
    0 crw-rw-rw-   1 root  wheel      10,   5 29 Dec 23:42 cu.usbserial-FTSDIXOJA
    0 crw-rw-rw-   1 root  wheel      10,   4 29 Dec 23:42 tty.usbserial-FTSDIXOJA

In my case I have two serial ports on the chip so:
bash-3.2#  ls -las /dev | grep -i usb
0 crw-rw-rw-   1 root  wheel      10,   7 30 Dec 00:10 cu.usbserial-FTSDIXOJA
0 crw-rw-rw-   1 root  wheel      10,   9 30 Dec 00:10 cu.usbserial-FTSDIXOJB
0 crw-rw-rw-   1 root  wheel      10,   6 30 Dec 00:10 tty.usbserial-FTSDIXOJA
0 crw-rw-rw-   1 root  wheel      10,   8 30 Dec 00:10 tty.usbserial-FTSDIXOJB


where FTSDIXOJ is my serial number (or pseudo serial number) and is appended by the port number (A = 0, B = 1) as I have two ports.

Step 12 - Select a port for use
  • Now you can use one of the serial port devices for use in kermit/minicom/cu/screen etc.

The FTDI driver provides two devices per port (cu and tty). The difference between them is deeply historical, in short cu was for modems, tty for terminals.
This post has a good explanation: http://lists.apple.com/archives/darwin-dev/2009/Nov/msg00099.html (external link)
I suspect they are both effectively identical for most current uses, with cu possibly having the edge even though its name would "scare" most people off.
If in doubt try both and pick your favourite :-)

Step 13 - Drink a beverage of your choice.

  • + : A leading plus sign indicates that this word must be present in every object returned.
  • - : A leading minus sign indicates that this word must not be present in any row returned.
  • By default (when neither plus nor minus is specified) the word is optional, but the object that contain it will be rated higher.
  • < > : These two operators are used to change a word's contribution to the relevance value that is assigned to a row.
  • ( ) : Parentheses are used to group words into subexpressions.
  • ~ : A leading tilde acts as a negation operator, causing the word's contribution to the object relevance to be negative. It's useful for marking noise words. An object that contains such a word will be rated lower than others, but will not be excluded altogether, as it would be with the - operator.
  • * : An asterisk is the truncation operator. Unlike the other operators, it should be appended to the word, not prepended.
  • " : The phrase, that is enclosed in double quotes ", matches only objects that contain this phrase literally, as it was typed.

Categories

Related Sites

Toolbox

Print