Building a Stubborn Driver: An Ubuntu Adventure

Posted on

I was confused, frustrated and defeated. My back was on fire and I could barely feel my legs. If there had been a bed within range I would have crawled in, closed my eyes and tried to forget the last five hours I had sat trying to build Linux drivers for my son’s new USB wireless adapter. It didn’t work. Nothing was working!

Wireless Adapter
Now I’m no Linux expert but I can usually figure out how to make the OS do what I need it to do. In this case it should have been simple – just make and install the source files and maybe change some setting on another file. But things went wrong from the beginning.
It was Saturday and I anticipated getting the project done fairly quickly. I had actually tried to get the WiFi working the day before but I was trying to do it without a wired connection to help out. I had just installed Ubuntu 14.04.03 and I really didn’t think I would have any trouble.

The open source drivers that come with Ubuntu take care of most of the hardware I want to use. But this particular wireless adapter was a plug-in USB with a proprietary driver that had to be compiled by hand. The adapter came with one of those mini-cds. It had three folders with drivers for Linux, Windows and Macs.

The windows and mac folders had exactly one file that you can click on to load the driver. I’ve used this adapter on a windows box and it works really well. All you have to do to get it working is double-click the executable and away you go. On Linux you have to build the driver from source code. So we’ve gone from one .exe file to about 450 files that you have to figure out how to put together and get to work. OK, but this is Linux. That’s what you expect from an open source OS.

But even building drivers shouldn’t be that difficult if you know basic Linux commands, how to traverse directories, edit files and use Make. Still, with such a large user and contributor base (for Ubuntu) you would think someone would have made the process for this driver a little clearer. Here are the build instructions that came with the adapter:

Build Instructions:  
====================

1> $tar -xvzf DPB_RT2870_Linux_STA_x.x.x.x.tgz
    go to "./DPB_RT2870_Linux_STA_x.x.x.x" directory.
    
2> In Makefile
	 set the "MODE = STA" in Makefile and chose the TARGET to Linux by set "TARGET = LINUX"
	 define the linux kernel source include file path LINUX_SRC
	 modify to meet your need.

3> In os/linux/config.mk 
	define the GCC and LD of the target machine
	define the compiler flags CFLAGS
	modify to meet your need.
	** Build for being controlled by NetworkManager or wpa_supplicant wext functions
	   Please set 'HAS_WPA_SUPPLICANT=y' and 'HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y'.
	   => #>cd wpa_supplicant-x.x
	   => #>./wpa_supplicant -Dwext -ira0 -c wpa_supplicant.conf -d
	** Build for being controlled by WpaSupplicant with Ralink Driver
	   Please set 'HAS_WPA_SUPPLICANT=y' and 'HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=n'.
	   => #>cd wpa_supplicant-0.5.7
	   => #>./wpa_supplicant -Dralink -ira0 -c wpa_supplicant.conf -d

4> $make
	# compile driver source code
	# To fix "error: too few arguments to function ¡¥iwe_stream_add_event"
	  => $patch -i os/linux/sta_ioctl.c.patch os/linux/sta_ioctl.c

5> $cp RT2870STA.dat  /etc/Wireless/RT2870STA/RT2870STA.dat
    
6> load driver, go to "os/linux/" directory.
    #[kernel 2.4]
    #    $/sbin/insmod rt2870sta.o
    #    $/sbin/ifconfig ra0 inet YOUR_IP up
        
    #[kernel 2.6]
    #    $/sbin/insmod rt2870sta.ko
    #    $/sbin/ifconfig ra0 inet YOUR_IP up

7> unload driver    
    $/sbin/ifconfig ra0 down
	$/sbin/rmmod rt2870sta

I started by simply trying to make the driver according to the instructions above. But the process kept showing an error and acting like it couldn’t find certain files that should have either been included or created when the make command was run. So I went searching “How to compile RT2870STA driver”. There were a lot of sites giving basic instructions about how to build the driver and it seemed like it should work fine. What I didn’t notice were the dates of most of these articles. They were pre 2010.

I finally came across a newer post that explained this driver was built with an earlier Linux kernel in mind (2.x). In the 3.x kernel, some functions that are referenced by my driver source files were re-named! Then I finally did what I should have done from the very beginning: I got specific. I searched “How to compile RT2870STA on Linux 3.19 kernel”. This seemed like a god idea at the time. In fact, it yielded a great blog post that provided a patch that supposedly would fix the discrepancy in the driver files. But for the life of me, I couldn’t even get that to run.
It was at that point I became too frustrated and defeated to continue. My entire day had been wasted. My kids were complaining that they hadn’t seen me all day. My wife was giving me that concerned “Oh dear, he’s trying to do smart people things again” look. Even my dog seemed annoyed at me that I had spent more time typing “make install” than I had spent throwing her ball.

So I gave up and took a few days away from my little project and did some other tasks that were just slightly easier for me like taking out the garbage. Then, Saturday morning I thought why not give it one more try? So I searched “How to compile RT2870STA on Ubuntu 14.04.03”. It was like magic! The very first result was a post on ubuntuforums.org that explained everything in a few simple steps. It seems there were two functions that had been renamed in newer builds of Ubuntu. I had to edit a file in one of the driver folders and change the names of a couple functions. I then ran Make again and voila, my adapter was up and running.

Looking back I realize I’ve learned (and re-learned) a lot about working with Linux. I now have much better terminal skills. I understand driver compilation processes better and how they interact with the kernel. I also reinforced my belief that an Ethernet connection to the internet is always superior to wireless, although inconvenient.