Table of contents:
This one got quite long as I’ve tried to make it as accessible as possible to people without Yocto experience. Oh well :) Use the TOC above to jump to specific pieces.
There have been several topics in the Intel Makers community asking for additional drivers or enabling support for specific features/hardware in the Linux kernel for Galileo’s Linux image. Thanks to Yocto framework, that is rather simple and I’m going to describe the process in this post, using USB Wi-Fi dongle as an example.
In general, we’ll be talking about so-called “in tree” drivers, i.e. those supported by Linux kernel out of the box. There may be cases, when the hardware you have isn’t [yet] supported by Linux kernel directly and manufacturer provides drivers separately, in such a case the process will be different and generally the same as for any other software you install from sources (compile, install, run), I’m not covering it here.
The idea itself is not specific to Galileo, you can use it with any Yocto-based Linux. Specific instructions and screenshots below are based on Yocto 1.4.2 and Galileo (actually Quark) Board Support package version 1.0.1 (the latest one at the time of writing) and can be used as-is with them. The same goes for BSP 1.0.0, which is what the latest officially released Galileo SD card Linux image is based upon right now.
So let’s get started.
Let’s assume you have an existing SD card with Linux image on it and a Wi-Fi dongle you want to use with Galileo, so you connect it and the only thing you see – on the serial console if you’re connected using serial cable or in the kernel log if you’re connected via SSH – is:
[email protected]:~# dmesg |tail -1 [ 580.500164] usb 2-1: new high-speed USB device number 3 using ehci-pci
That's a clear indication that the driver you need is at least not loaded or maybe not even present in the image.
How to determine which driver you need
There are at least two approaches you can use to determine which driver (kernel module) you need:
- By connecting your device to a computer with a "full-blown" Linux distro (Debian, Ubuntu, openSUSE, you name it) and watching the
dmesgoutput. Desktop and server distros typically have many drivers enabled by default and mechanisms for loading them automatically when supported hardware is connected. When the driver loads and initializes the hardware, you usually see some output with kernel module name in the kernel log.
- By using
lspciutilities on Galileo to find out the Device ID and then looking it up using Google or specialized resources like Web LKDDb.
After you've obtained the kernel module name, you'll need to determine which kernel configuration option enables it. LKDDb is very nice in this regard, because it gives you that right away, along with the module name.
I use the second approach most of the time and the first place I check is namely LKDDb + Google if something is unclear there.
Let's see how exactly does that work. As long as this is a USB device, use
lsusb to find the ID:
[email protected]:~# lsusb Bus 002 Device 003: ID 0bda:8171 Bus 001 Device 001: ID 1d6b:0001 Bus 002 Device 001: ID 1d6b:0002
You can use that command before and after connecting the device to filter out irrelevant entries. In our case the full Device ID is
0bda:8171. It's comprised of Vendor ID (
0bda) and Product ID (
Use the Google custom search form on the LKDDb site to find the Product ID and then select the right Vendor. Make sure to narrow down the search to the LKDDb web site, otherwise it will be harder for you to filter relevant information out.
Our search returns four results and we need the fourth one, because the first and the third ones are irrelevant due to different Vendor ID (
10ec), the second one is also off the table after looking at the entry on detail - it's for 2.6.x Linux kernels ("found in Linux kernels: 2.6.31–2.6.36") and Galileo currently has kernel version 3.8.7. See screenshots below for an illustration.
Looking at the fourth search result in detail we see that we need a module called
r8712u and it's enabled using CONFIG_R8712U kernel configuration option. Let's now see how to get it built.
How to reconfigure the kernel and build the driver
You'll need a Linux system with Quark BSP unpacked and prepared for building per the BSP Build Guide. I'm not covering the details of preparing the environment here as BSP Build Guide is generally sufficient + there are articles on this elsewhere. Let me know in comments if you want an article on this :) You can use a VM appliance I've build using SUSE Studio to make the setup a bit easier.
Note that you need to create the kernel config at least once after initializing the build environment, to have a base for your changes. You don't need to build a full OS image if your only goal is to add the driver or change an option, you can simply build the kernel and modules and add them to an existing image you have on SD card. Assuming your Yocto environment is in
/tmp/meta-clanton_v1.0.1, run these commands:
cd /tmp/meta-clanton_v1.0.1 source poky/oe-init-build-env yocto_build/ bitbake -c configure linux-yocto-clanton
That will build a bunch of utilities, fetch and configure Linux kernel sources.
After it's done, let's enable our driver using standard kernel configuration process. The default way to do this is to run
bitbake -c menuconfig linux-yocto-clanton
That should open up a separate console window with kernel's graphical configuration utility. However on some distros (e.g. the one I'm using, openSUSE 12.3) that may not work, so there's an alternative, which is pretty much the same, but slightly longer in invocation:
bitbake -c devshell linux-yocto-clanton
and then in the devshell window that opens up:
You'll see something like this:
And we now need to enable the respective config option in this hierarchical menu. The simplest way to find out where it is located is to use search (F8 key):
which will return this information about the item's location, current state and dependencies:
Go to Device Drivers -> Staging drivers, highlight the "RealTek RTL8712U <...>" entry and hit Enter key, that will add a "M" in front of the option, which means this driver will be built as a shared module. The utility will also enable all the necessary dependencies automatically.
Now, save the config with the default name by hitting F6 and Enter. After that exit the configuration utility by hitting F9 and close the devshell window with Ctrl+D. If you've used
menuconfig, the keys may be a bit different and you won't have a devshell to close.
Now build the kernel and kernel modules by running
After it's finished, you'll have the module in a form of *.ipk package in
/tmp/meta-clanton_v1.0.1/yocto_build/tmp/deploy/ipk/clanton/kernel-module-r8712u_3.8-r0_clanton.ipk and the kernel itself in
How to install the driver
Boot the board, copy the ipk file with the kernel module there using scp utility (PuTTY, WinSCP and so on for Windows) to e.g
scp /tmp/meta-clanton_v1.0.0/yocto_build/tmp/deploy/ipk/kernel-module-r8712u_3.8-r0_clanton.ipk [email protected]:/tmp
and install it using opkg:
[email protected]:~# opkg install /tmp/kernel-module-r8712u_3.8-r0_clanton.ipk Installing kernel-module-r8712u (3.8-r0) to root... Configuring kernel-module-r8712u.
Load the module with
Then connect the USB dongle and verify that
dmesg output now contains meaningful information about the device being recognized. This is Wi-Fi device, so it also requires a firmware blob I haven't bothered to download yet, thus that "firmware request failed", but as you can see the driver is functioning and correctly initializes the HW and reports its MAC address:
[email protected]:~# dmesg |tail [ 64.694928] usbcore: registered new interface driver r8712u [ 72.290164] usb 2-1: new high-speed USB device number 2 using ehci-pci [ 72.450979] r8712u: Staging version [ 72.454822] r8712u: register rtl8712_netdev_ops to netdev_ops [ 72.460714] r8712u: USB_SPEED_HIGH with 4 endpoints [ 72.478649] r8712u: Boot from EFUSE: Autoload OK [ 73.203898] r8712u: CustomerID = 0x0000 [ 73.207813] r8712u: MAC Address from efuse = 08:10:76:0d:bd:45 [ 73.213771] r8712u: Loading firmware from "rtlwifi/rtl8712u.bin" [ 73.232265] r8712u: Firmware request failed
By the way, FWIW some further experimenting revealed that this particular driver fully deserves its "staging" status in this kernel version and doesn't work well on Galileo - crashes from time to time and the behavior is generally unstable. So I went on and built a driver (using absolutely the same approach) for my other dongle, based on some Ralink chipset. It worked perfectly and that's what I use day to day.
Note also that if you change something beyond just a simple module build - you may need to replace your kernel (
bzImage file) in the SD card root with the one you've just built. E.g. in this particular case we've also enabled two options as dependencies for the driver, so it's worth doing that. Make sure to back up the existing file before replacing.
You can also make these changes more permanent by using Yocto layers, recipes and so called configuration fragments. This can also help you to introduce your changes faster than the above manual ad-hoc way, provided you have the environment ready and know exactly which kernel config options (with dependencies) you need to enable - you can simply create a config fragment and let Yocto merge it for you.