When I bought UNI-T UT61E digital multimeter, I planned to to use the open source tool Sigrok to capture voltage, current or resistance data with my Ubuntu 14.04 machine. Unfortunately, it was just not working for me and I kept getting some “Invalid function byte” error messages, so I asked on Sigrok mailing list, and since it worked for others, I was in big troubles. It turned out the RS-232 to USB dongle I used:
idVendor 0x1a86 QinHeng Electronics
idProduct 0x7523 HL-340 USB-Serial adapter
was most likely to culprit, so I decided to buy another random USB to serial dongle on eBay, and after a few weeks I received it only to find out it had the exact same VID:PID, so I was out of luck. Finally, I gave up on Sigrok on Linux, and tested the power consumption of some Rockchip RK3288 & Amlogic S802 devices in a Windows 7 virtual machine running in my Ubuntu 14.04 host PC. A few days later, Karl Parsonn left a comment saying ch341 driver just ignored parity (UNI-T DMM use odd parity), but that he wrote a patch that should eventually make it to mainline.
Since I did not want to wait I decided to build ch341.ko with the patched driver, and I can now use Sigrok with my HL-340 USB-Serial adapter successfully, but I’ll write more about that in another post, and today, I’ll document the steps I followed to build the driver for my machine.
Instructions to build a kernel module in Ubuntu are already available, but the patch for ch341 driver is for Linux 3.18.6, and Ubuntu 14.04 comes with Linux 3.13. So I had two choices:
- Backport the driver to Linux 3.13
- Upgrade my Ubuntu kernel to 3.18
I decided to go with option 1 at first, but I quickly changed my mind as there’s been a bit too many modifications between the two versions, and it started to be time consuming. So it was time for plan B, or rather option 2. I could probably have use the Karl’s Linux kernel, but I remembered having read that Canonical makes some changes to the Linux kernel, so instead I went to http://kernel.ubuntu.com/~kernel-ppa/mainline/ to download and install Linux 3.18 in my machine (This is 3.18.0, but with hindsights I should have gone with 3.18.6 instead, but it still worked):
sudo dpkg -i linux-headers-3.18.0-*.deb linux-image-3.18.0-*.deb
This steps requires a reboot. In case it does not boot at all, you should be able to boot one of the older Linux kernel via grub, and remove the new mainline kernel, so I believe this step is relatively safe.
Then I checkout the Linux kernel and downloaded and applied Ubuntu specific patchsets:
git clone git://kernel.ubuntu.com/virgin/linux-stable.git v3.18
patch -p1 < 0001-base-packaging.patch
patch -p1 < 0002-debian-changelog.patch
patch -p1 < 0003-configs-based-on-Ubuntu-3.18.0-6.7.patch
Backup the current driver:
sudo mv -v /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ch341.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ch341.ko_backup
Then I mostly followed the build instructions found on Askubuntu to setup the kernel to build modules:
cp -v /usr/src/linux-headers-3.18.0-031800-generic/Module.symvers .
and update the code with the new driver, build and install the module:
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
sudo make -C /lib/modules/$(uname -r)/build M=$(pwd) modules_install
Finally run depmod, unload the old module if needed, and load the newly built module.
sudo modprobe -r ch341
sudo modprobe -v ch341
Done. I’ve now got a CH341 driver that supports no parity or odd/even parities.