Tuesday, October 30, 2012

Ubuntu for Idiots: the new Lenovo X1 Carbon and its USB Ethernet Dongle

So I recently received the best laptop I have ever owned - by far - the Lenovo X1 Carbon. I won't go into all its glory, but it is a very nice machine indeed. And Ubuntu seems to be custom-tailored to it - installing flawlessly, running seamlessly, and requiring nothing special to make go. In fact, it works so well out of the box compared to Windows (which requires a boatload of specialized drivers for the hardware) that it is almost shocking. Of course, most Windows users won't notice because Lenovo does all the hard work with the pre-installation.

But that's besides the issue. Back to the topic at hand.

One thing that the X1 Carbon does not come with is an Ethernet port, on account of just how thin it is. A port simply wouldn't fit in the slim profile. So instead, Lenovo sends you a USB-to-Ethernet dongle that allows the use of a wired connection.

What Lenovo does not do, however, is send you the drivers for it (I mean for Windows, forget Linux, Lenovo doesn't recognize Linux). So users of both operating systems are on their own.

It took me a bit to locate the proper drivers for this device, and a bit more to figure out how to get it working properly, and I figured you might have run across the same problem, too. So without further ado, here are the full instructions on how to get this thing working in Ubuntu. I have only tried it (successfully) on an X1C running both 12.04 (Precise Pangolin) and 12.10 (Quantal Quetzal), but the process should work elsewhere, too, both on other laptops and other Ubuntu versions.

First of all, the Lenovo dongle is based on an Asix chipset, as are many of these from most manufacturers. So you first have to download the driver source code.

Then you need to find your device ID. You do this by opening a command prompt (CTRL+ALT+T) and running: lsusb

This should produce a list that looks like this (from my machine):

Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 003 Device 002: ID 046d:c03d Logitech, Inc. M-BT96a Pilot Optical Mouse
Bus 003 Device 003: ID 0bdb:1926 Ericsson Business Mobile Networks BV
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 007: ID 17ef:7203 Lenovo
Bus 001 Device 004: ID 147e:2020 Upek
Bus 001 Device 005: ID 0a5c:21e6 Broadcom Corp.
Bus 001 Device 006: ID 04f2:b315 Chicony Electronics Co., Ltd


I highlighted the important bits. The word "Lenovo" by its own little self is your clue to the dongle.

Next, you should disconnect (if it is connected) and (re)connect the dongle to your USB 2.0 port (the left one on the X1C). Then type dmesg, and you should get something like this (again from my machine):

[ 3975.632981] eth1: unregister 'asix' usb-0000:00:1a.0-1.2, ASIX AX88772B USB 2.0 Ethernet
[ 3977.876228] usb 1-1.2: >new high-speed USB device number 7 using ehci_hcd
[ 3977.986504] usb 1-1.2: >New USB device found, idVendor=17ef, idProduct=7203
[ 3977.986510] usb 1-1.2: >New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 3977.986513] usb 1-1.2: >Product: AX88772B
[ 3977.986516] usb 1-1.2: >Manufacturer: Lenovo
[ 3977.986519] usb 1-1.2: >SerialNumber: 580B27


I again highlighted the important bits. The two numbers confirm the lsusb information, and the product ID (AX...) is also necessary.

We will call the first number (in this case 17ef) the Manufacturer ID, the second number (in this case 7203) the Device ID, and the third number (in this case AX88772B) the Product ID.

With this information in hand, time to compile the driver.

Extract the zip file you just downloaded into its default folder. Then double click on the file called "asix.c" to edit it (it should open in gedit, or the "Ubuntu notepad").

Once in editing mode, search for the phrase "usb_device_id". You should come across a section in the file that starts with something like this:

static const struct usb_device_id products [] = {
{
// 88178
USB_DEVICE (0x0b95, 0x1780),
.driver_info = (unsigned long) &ax88178_info,
}, {
// 88178 for billianton linksys
USB_DEVICE (0x077b, 0x2226),
.driver_info = (unsigned long) &ax88178_info,
}, {


Here is what you want to do. You want to insert a new section here right after the first one, with the information you discovered, like so:

{
// Lenovo 10/100
USB_DEVICE (Manufacturer ID, Device ID),
.driver_info = (unsigned long) &Product ID_info,
},

In our example, the modified file should look like this (note that I inserted the three ID's in their proper places):

static const struct usb_device_id products [] = {
{
// 88178
USB_DEVICE (0x0b95, 0x1780),
.driver_info = (unsigned long) &ax88178_info,
}, {
// Lenovo 10/100
USB_DEVICE (0x17ef, 0x7203),
.driver_info = (unsigned long) &ax88772b_info,
},
{
// 88178 for billianton linksys
USB_DEVICE (0x077b, 0x2226),
.driver_info = (unsigned long) &ax88178_info,
}, {


That was the hard part.

Now open a terminal window in the folder where these files reside, and type the following commands: make and then sudo make install

That's it. You may need to reboot, but it should work now. Huzzah!