FTDI, D2XX and Linux: Overcoming the big problem!
FTDI chip provides really excellent USB chips, that will handle all the USB communication for you with really excellent bandwidth performance. FTDI provide an exhaustive documentation for their cross platform driver. In contrast with the VCP (Virtual Com Port) mode, the D2XX driver allows direct access to the USB device ports in a completely transparent fashion. The Windows drivers are already certified by Windows, so you can just pick your favorite chip from FTDI, and use it in your product without having to worry about time consuming driver development and certification.
All those arguments make FTDI a very good choice if you are willing to launch a cross platform USB based product as we did for ScanaPLUS. However, be warned, there is One Big Problem you will face on Linux platforms. This short post is all about this problem, and the solution we found to overcome it in a nice, transparent and beautiful way.
Note: I am anything but a Linux specialist! I have dug my way into Linux world with the help of forums and online tutorials over the last 15 months. Me posting this article is a “Thank you” to the Linux community and hopefully an addition that will help many others!
The problem
When you connect an FTDI device on a Linux system, most of the time, the Kernel will automatically mound this device using the VCP driver, making your device completely undetectable and unusable by the D2XX library. More practically, when you try to open your device from within your program using the function FT_Open(); it will fail even though the device is connected to the computer and is fully functional.
FTDI recommends this procedure to solve this:
If the message “FT_Open failed” appears:
Perhaps the kernel automatically loaded another driver for theFTDI USB device.sudo lsmod
If “ftdi_sio” is listed:
Unload it (and its helper module, usbserial), as follows.sudo rmmod ftdi_sio
sudo rmmod usbserialOtherwise, it’s possible that libftd2xx does not recognise yourdevice’s Vendor and Product Identifiers.
Using Linux’s very flexible and versatile “udev rules”, one can write a script to make sure this operation is executed each time the device is plugged to the USB.
The Big Problem: collateral damage.
The big problem in the solution provided by FTDI is that it will prevent any other FTDI device to be detected as VCP. This can be quite a concern: Imagine if your product prevents any other FTDI based virtual COM port from functioning. This in deed is not acceptable, and can be a serious show stopper.
The complex, long, time consuming solution
The first solution that comes to mind is to use other, proprietary PID/VID. Although this instantly solves the problem for Linux, it will require you to completely start over the windows driver part. Since changing PID or VID voids the Windows certification of the driver given by FTDI, you will have to go through the hole driver certification circuit. Doing a certification once is not the worst part. The worst part is that each time you want to update the driver you have to go through the certification process again. If you’re a free lancer or a small/medium sized company like us, a time consuming process like that is your enemy! Besides, having to take care about the driver would make no sense, if you’re choice of using FTDI was to have peace of mind regarding the whole driver maintenance part.
Our solution
Enough bla bla! let’s see how to make Linux keep VCP driver away from your FTDI chip without any collateral damage.
It all fits in a single line, in the udev rule file for your product.
Normally your *.rules file would contain this line:
ATTRS{idVendor}==”0403″, ATTRS{idProduct}==”6014″, MODE=”0666″
This line will make your device accessible from applications that do not have super user rights (i.e. normal users, not administrators)
Simply add this line to tell the kernel to unbind the ftdi_sio (usb to serial port driver) from your device:
[alert type=”primary” display=”inline”]ATTRS{idVendor}==”0403″, ATTRS{idProduct}==”6014″, ATTRS{product}==”PRODUCT_NAME”, RUN+=”/bin/sh -c ‘echo $kernel > /sys/bus/usb/drivers/ftdi_sio/unbind'”[/alert]
(this is a single line, even though it might appear here as 2 lines)
The idea to differentiate between various FTDI devices using the product name defined in the USB descriptor. Once the product named “PRODUCT_NAME” is detected, the shell command above is run, which will effectively unbind the ftdi_sio and your USB device!
And voila! please don’t hesitate to post comments or ideas. I hope this post could help others.
Source: Ikalogic