Cliff Hacks Things.

Tuesday, November 27, 2007

ASUS eeePC: some sources posted.

Looks like ASUS has posted some source archives on their FTP site. On initial inspection, the asus_acpi module sources are not the ones that compiled the module that ships on the machine, but are very close. Gonna try 'em out this evening -- as long as they work, I can chalk the previous binary release up to an error on ASUS's part and forge ahead.

Edit (2007-11-30): I've pored over ASUS's source release and extracted their changes into patches. Everything seems to work -- they even released some packages that they weren't technically obligated to, like their on-screen display code for the volume and wifi buttons.

I'm delighted to report that this situation is resolved, as far as I'm concerned. ASUS has reacted admirably and swiftly, and I'm proud to have given them my money (with the small exception of the arbitrary and potentially illegal restrictions they've placed on upgrades).

Gonna go back to my enjoying my laptop now, and hopefully not get viciously attacked on Slashdot and my own blog for a while. Happy hacking!

Labels: ,

Sunday, November 25, 2007

eeebuntu tip: unloading/reloading the wifi drivers

The eee's wifi does not survive a suspend: the hardware and drivers get into different states, and things quit working. The wifi control scripts in ASUS's Linux distribution hold the key.

There's a particular sequence of rmmod/insmod calls that will force the system to rediscover the wifi, and (for me at least) fixes all the various b0rked states it can get into. I call it the "Magic Wifi Dance," because it's a ritual that I don't completely understand.

My control script is below. You'll need the Atheros drivers and the ASUS ACPI module.


#!/bin/sh

# The sequence here *may* be important.
# (It seems to fail intermittently if you deviate.)
unload_modules() {
rmmod wlan_scan_sta
rmmod wlan_tkip
rmmod wlan_wep
rmmod wlan_ccmp
rmmod wlan_acl
rmmod ath_pci
sleep 1
rmmod ath_rate_atheros
rmmod ath_hal
rmmod wlan
rmmod ath_dfs
}

# At least this one's straightforward.
load_modules() {
modprobe ath_pci
}

wifi_on() {
# Force PCI Express Hotplug to reinit
rmmod pciehp
sleep 1
# pciehp_force may be unnecessary; Xandros did it.
modprobe pciehp pciehp_force=1
sleep 1
# Switch on the hardware
echo 1 >/proc/acpi/asus/wlan
sleep 1
load_modules
}

wifi_off() {
unload_modules
echo 0 >/proc/acpi/asus/wlan
}

case $1 in
on)
wifi_on
;;
off)
wifi_off
;;
toggle)
STAT=`cat /proc/acpi/asus/wlan`
if [ "$STAT" = "1" ];
then wifi_off;
else wifi_on;
fi
;;
esac


When executed on an "eeebuntu" machine with ASUS's binary modules, that script should be capable of shutting down and bringing up the Atheros wifi card. The on and off arguments do what their names imply; the toggle argument checks the card's status in proc and responds appropriately. (I use toggle to make the keyboard's wifi key work, which I'll demonstrate in my upcoming post on ACPI events.)

For those playing along at home, this resulting control script is a good one to call from /etc/acpi/suspend.d and /etc/acpi/resume.d, with off and on arguments, respectively. (Just make sure it's called after the interfaces are shut down on suspend, and before they're brought up on resume. On default Ubuntu, calling the suspend script "56-eee-wifi-off" and the resume script "60-eee-wifi-on" gets the order right.)

Labels: ,

Saturday, November 24, 2007

eeebuntu tip: ifup/down for NetworkManager

By switching to NetworkManager, I lost the use of the Linux ifup/ifdown scripts for quickly bringing network interfaces up and down. (These scripts rely on the information in /etc/network/interfaces, which I've stripped bare to transfer control to NetworkManager.)

Now, with nm-applet and kin, I have no real need or desire to control my network interfaces from the shell. However, some of my other scripts do -- in particular, when suspending and resuming the machine, I need to remove/reload the Atheros kernel modules, and I can't do that while the interface is up.

Also, my keyboard has a cute little "Wifi On/Off" button that I want to work. (More info on that in a later post.)

Fortunately, the solution turns out to be dead-simple: NetworkManager's dbus API exposes methods for bringing the network up and down.

To bring all NetworkManager-controlled interfaces down:

dbus-send --system --type=method_call \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.sleep

(Yes, all those switches are necessary.)

To bring 'em back up:

dbus-send --system --type=method_call \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.wake


In my case, I dropped these into scripts in /etc/acpi/suspend.d and /etc/acpi/resume.d, respectively, alongside their old-school ifup/down counterparts. Works great, assuming the drivers come back up; I'll post the trick for that in a subsequent post. (I'm transcribing my porting notes as fast as I can here.)

eeebuntu tip: wireless with hal and NetworkManager

I've been away from Linux for quite a while, off in Mac-land, where things generally just work. I was delighted to notice, upon my return, that the community (and RedHat in particular) noticed that manually configuring your wireless interfaces is lame, and built a solution: NetworkManager.

NetworkManager is built atop hal, a daemon that interrogates hardware and makes the information available over a dbus interface. (dbus is a simple mechanism for interprocess messaging and procedure call, similar to DCOP, but more general.)

If you install Ubuntu and subsequently bring up your network using a panel applet, you're using NetworkManager -- and boy, is it nice. Unfortunately, most instructions for getting the eee's wireless working on Ubuntu revolve around the "old-world" configuration mechanism in /etc/network/interfaces. While Ubuntu has graphical configurators that generate this file, using it prevents you from applying the full power of NetworkManager. (Fun fact: NetworkManager will silently ignore any interfaces that are configured in /etc/network/interfaces.)

NetworkManager and hal are really poorly documented. (No offense to the authors intended; the tech is impressive, and I understand that sometimes precious little time is left over to write a design document.) I don't understand the system well enough to write a general tutorial, so here's a specific one: how to get NetworkManager and hal playing nice with the binary Atheros drivers on "eeebuntu" -- Ubuntu 7.10 using the ASUS-compatible 2.6.21.4 kernel I described in my last post.

Getting hal to create ath0 automatically



The Atheros wireless drivers create two network interfaces: wlan0 by default, which seems to be good for very little, and ath0 on demand, which is what you actually use to speak to the intarweb. You have to explicitly request creation of the ath0 interface like so:
wlanconfig ath0 create wlandev wlan0 wlanmode sta


hal, by default, sees the wlan0 interface as an 802.e interface, and does not see ath0 at all. What we want is for hal to ignore wlan0 and treat ath0 as an 802.11 interface. hal supports policy files (written in XML, which surprised me in a Linux tool) that rewrite its view of devices -- and that's what we'll use to fix this.

But first -- we need ath0 created automatically when wlan0 appears. A simple script suffices. I've put mine in a file called /etc/hal/callouts/eee-wifi for reasons that will become apparent in the next step. The script need only contain:

#!/bin/sh

case $HALD_ACTION in
add)
sleep 1 # May be unnecessary, experiment
/sbin/wlanconfig ath0 create wlandev wlan0 wlanmode sta
sleep 1
;;
remove)
/sbin/wlanconfig ath0 destroy
;;
esac


Notice that the script takes its input, not from a command-line parameter, but from an environment variable named HALD_ACTION. This will make sense in a minute. For now, you can test the script thusly:

# Should create ath0 if wlan0 exists and drivers are loaded
env HALD_ACTION=add /etc/hal/callouts/eee-wifi
# Should remove ath0
env HALD_ACTION=remove /etc/hal/callouts/eee-wifi


Now, we convince hal to invoke our script when wlan0 appears or disappears. Create a file named /etc/hal/fdi/policy/10-networking-ath0.fdi containing the following:

<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
<device>
<match key="net.interface" string="wlan0">
<append key="info.callouts.add" type="strlist">/etc/hal/callouts/eee-wifi</append>
</match>
</device>
</deviceinfo>


This adds our script as a "callout" for wlan0 -- hal's notion of an event handler. hal will invoke our script when wlan0 comes or goes, and set HALD_ACTION appropriately.

Restart hal (or killall -HUP hald) and try loading or unloading the Atheros drivers. ath0 should be created and destroyed automatically. (Make sure the ath0 interface is down when you do this.)

Letting NetworkManager configure ath0



For NetworkManager to configure an interface, a few conditions must be met:

  1. hal must see the interface and recognize it correctly (e.g. seeing ath0 as a wired Ethernet connection is not good);

  2. The interface must not be configured in /etc/network/interfaces. If you currently have a stanza configuring ath0 or wlan0, remove it.



First things first. Modify the 10-networking-ath0.fdi policy we created in the last step by adding the code marked below:

<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
<device>
<match key="net.interface" string="wlan0">
<append key="info.callouts.add" type="strlist">/etc/hal/callouts/eee-wifi</append>
<merge key="info.capabilities" type="strlist">net</merge>
<append key="info.capabilities" type="strlist">net.80211</append>
<merge key="info.category" type="string">net.80211</merge>
<merge key="net.interface" type="string">ath0</merge>
<merge key="net.80211.mac_address" type="copy_property">net.80203.mac_address</merge>
<remove key="net.80203.mac_address"></remove>
<merge key="linux.sysfs_path" type="string">/sys/class/net/ath0</merge>

</match>
</device>
</deviceinfo>

Note: special thanks to "Triarm" on the eeeuser forums for pointing out this approach.

Line by line, this does the following:

  1. Replaces wlan0's info.capabilities property with the single item "net", indicating that it's a network interface.

  2. Appends "net.80211", indicating that it's a wireless interface.

  3. Changes the device's category, again to indicate that it's a wireless interface.

  4. Switches the entry to refer to ath0, instead of wlan0.

  5. Copies the 802.3 (wired Ethernet) MAC address to the 802.11 MAC address (I'm surprised that these are separate).

  6. Removes the old 802.3 MAC address.

  7. Rewrites the entry's sysfs path to point to ath0's.



To sum up, at this point we have:

  1. Instructed hal to invoke our callout when wlan0 is added or removed, thereby automagically creating/destroying ath0.

  2. Rewritten the device descriptor for wlan0 to describe ath0 (which is unfortunately not picked up automatically by hal).

  3. Removed wlan0/ath0 configuration from /etc/network/interfaces. (You remembered that, right?)



Bring NetworkManager down, restart or HUP hald, and bring NetworkManager back up. (The control script for NetworkManager on Ubuntu 7.10 is at /etc/dbus-1/event.d/25NetworkManager.)

Assuming I haven't forgotten anything, NetworkManager should now offer to configure your wireless, and the interface should show up in configurators like nm-applet.

If it doesn't work, try rebooting. (I know it's lame to say that, but the Atheros drivers are incredibly sensitive and can get into weird states that make your interface stop working, usually after you remove/readd them or suspend/resume. I have a magic dance that repairs the driver, but it's lengthy so I'll post it in a followup.)

Labels: ,

Friday, November 23, 2007

eeebuntu tip: using a custom kernel with ASUS's modules

I like the eee hardware but dislike the software. Personal preference; when I can't use a Mac I use Ubuntu. Readers will surely like some other distro (I know I used to be big on Gentoo), but this tip should not be distro-specific.

I wanted to put Ubuntu 7.10 on my eee without sacrificing any features. I've largely pulled it off, but it's a long journey down a narrow, undocumented road (sigh, Linux). The journey starts with the proverbial single step, which in this case is replacing the kernel with a largely identical one built from source. (If you're going to do anything cool to the kernel, you've got to be able to build it.)

I started out by installing Ubuntu 7.10 off a live stick. This isn't strictly necessary -- the kernel we're building will probably work in Xandros -- but since Ubuntu is my eventual goal, I aimed high. The live stick boots without a hitch (into Compiz, no less!) and the install was uneventful. Note before installing: there are files on the eee's filesystem you will need to complete this tutorial! It is worth your time to make a backup in an accessible form, such as dd'ing the filesystem to somewhere you can loop-mount it.

(Caveat lector: I actually installed onto an SD card, leaving the internal flash disk unmodified, but doing this requires a bunch of extra steps that are not documented here. It's sufficiently involved that I'll have to describe it in a followup.)

The install was largely uneventful and is not the topic of this post.

Ubuntu 7.10 does not, out of the box, support the following hardware on the eee:

  • The Atheros wireless card. (The madwifi drivers ASUS ships are not the 9.3.3 drivers, and a freshly built set from SVN trunk doesn't work either.)

  • The ASUS ACPI features for controlling backlight and powering PCIe devices on and off. The mechanism is conceptually similar to the kernel's asus_acpi module, but as I noted in a previous post, ASUS ships a modified driver.



(Those of you who have been in the Linux/FreeBSD laptop community for some time may notice how incredibly short that list is, and the fact that it does not include multihead 3D accelerated graphics, audio, and USB 2. How far we've come.)

As a result of the botched ACPI support, suspend/resume doesn't work quite right. Suspend-to-RAM will work sometimes, kinda, after a few VT switches to thunk the display adapter. Not good enough! I want instant suspend/resume and working wireless! Waaaah, the Mac has spoiled me! :-)

The pragmatic solution, if not the most FSF-friendly one, is to build a kernel with the exact version string from ASUS's so their binary modules will work. (If you care, note your kernel will be tainted! Danger Will Robinson!)

The recipe below skips some steps and is not intended for Linux or Unix newbies. Sorry; I've been immersed in Unix long enough that I'm not the right guy to write the newbie tutorial. Feel free to steal my instructions to make one!


  1. Prereq: a Linux machine with a working set of devtools and the 2.6 version of depmod. This might be the eee, I suppose, but I used a much faster machine. (Specifically, an Ubuntu 7.10 virtual machine under VMware Fusion.)

  2. Download the sources for the matching Linux kernel version -- in this case, 2.6.21.4. (For the kernel-impaired, it comes from kernel.org's 2.6 site.)

  3. Untar.

  4. Nab the ASUS kernel configuration, helpfully shipped right on your eee. It lives in /boot/config-2.6.21.4-eeepc. Copy it into your untarred kernel sources as a file named .config .

  5. If you tried to build the kernel now, you'd notice some errors about missing unionfs. Unionfs isn't in the 2.6.21.4 mainline kernel, but ASUS uses it. If you want it, download the version for 2.6.21.7 and apply it in the kernel tree with
    patch -p1 </path/to/patch
    If you don't want it, simply delete or comment out all lines in the config containing the word UNIONFS.

  6. ASUS's config in place, build a replacement kernel by issuing
    make oldconfig && make

  7. Create a directory to hold your new kernel and modules, and issue
    make INSTALL_PATH=/your/directory install
    make INSTALL_MOD_PATH=/your/directory modules_install
    You do not need to (and should not!) run these commands as root.

  8. In your directory are a bunch of files: a kernel and associated files at the root, and a lib/modules/2.6.21.4-eeepc directory with your modules in it.

  9. Copy the files out of the directory into /boot on your eeepc. Note at this point that, if you are still running Xandros, you have just overwritten your kernel. Hope you had a backup. (If you're running Ubuntu 7.10 you have installed an additional kernel alongside the main one. This is safe.)

  10. Copy the contents of the /lib... directory, not into /boot with the others, but into /lib/modules/2.6.21.4-eeepc.

  11. Try booting your eee. You will need to get to the grub menu and change the "kernel=" parameter. (How to do this is beyond the scope of this article.) If it does not work, I'm afraid I am not the man to help you; I make Linux work through sheer dumb luck and a lot of Unix engineering experience, but a Linux guru I'm not.

  12. If it seems to work, simply copy the atheros and acpi. directories from /lib/modules/2.6.21.4-eeepc on your eee backup filesystem into the same locations on the new one, and run (as root) depmod -a.



At this point, if it worked, you have a booting Ubuntu (or ${YOUR_DISTRO}) system running on a reasonable facsimile of ASUS's 2.6.21.4 kernel. If you issue modprobe asus_acpi or modprobe ath_pci, the modules should load (and put some control files in /proc/acpi/asus, or create wlan0, respectively).

You may find that suspend/resume to RAM works with the asus_acpi module loaded. Edit your /etc/modules as you see fit.

Getting from "loading the Atheros modules" to "reading Slashdot" is unfortunately involved -- but the process is no different than the normal madwifi drivers. (Hint: until I post my scripts, search on Google for "wlanconfig ath0 create".)

Happy hacking!

Labels: ,

Thursday, November 22, 2007

ASUS eeePC: First impressions and GPL violations

Most recent edit (2007-11-30): please see my more recent post for updates. ASUS has released the sources for some of the applications and drivers on the eee. I can't say whether it's complete and accurate yet, but it's a great sign from ASUS.


Edit: This post has gotten wider circulation than I was expecting (I rarely get readers, much less comments!). I've been clarifying some points in the comments, but people don't seem to be reading them before posting (and some of the posts have been hostile in tone). So:

  • Yes, I've downloaded and poked around in the 1.8GB archive ASUS insists is the source, from both the US and Taiwan sites. It does not contain the sources in question, or at least did not when I retrieved it. I tend to assume incompetence before malice, and I really do believe they just messed up. (Even the asus_acpi stripping seems more like a botched search-replace job by some overworked driver author than a malicious act. Doesn't make it legit, of course.)

  • I realize that blogging about a GPL violation doesn't fix it. My purpose in writing this article was to document the violation; I have neither the inclination nor the time to press a complaint or (god forbid) file a lawsuit! If others want to do that in response to this post, I'm happy to serve as an expert witness and provide the evidence I've collected, but for now, I'm enjoying my laptop and a cup of coffee.

  • I either suck at using ndiswrapper (I freely admit this) or it's my Airport base station causing the problems there. More on wireless drivers in a followup post.


Now on to the original post:

For my birthday, I bought myself an ASUS eeePC. Now, I've been lusting after very-small-form-factor laptops for some time (ever since I saw the Zaurus C series), and this is quite the small one. It also ships with Linux, which (I thought) was a good indication that the hardware is well supported by Linux. (Not so; read on.)

I'm very pleased with the hardware with a few exceptions, which I'll detail in the latter two thirds of this post. The screen is bright and clear, the keyboard is surprisingly usable (even with my giant hands), etc. I'm really happy with it, now that I've bent it to my will. Obligatory laptop porn below.

The eee on a sheet of 8.5x11 paper:


The eee next to a coffee mug:


The eee atop my 15" MacBook Pro:


Now then.

Proprietary Hardware Woes


ASUS ships the eee with a variant of Xandros Linux, which in turn is a variant of Debian. It also ships with binary modules for much of the hardware, and some of the hardware won't work without 'em. Specifically,

  • The wireless works with the madwifi version that ships on the machine, but not with HEAD or 9.3.3, and

  • The ACPI does not work with the Linux kernel's asus_acpi module, but does with ASUS's variant of it.



Several folks have gotten the wifi working with ndiswrapper, but this just tells me that those folks don't run WEP. (I need to figure out where they live.) I've gotten both wifi and ACPI working in Ubuntu, but only by loading ASUS's binary modules. Instructions in a subsequent post, once I'm done ranting.

(Edit (2007-11-23): Folks have posted saying they got ndiswrapper working with WPA. They're clearly 1337er than I am; turning on any encryption at all would spike it to 50%+ CPU. Lame!)

Proprietary Software Woes


The system is set to update itself and add packages from a repository at ASUS's site (specifically this one), where the little machine can fetch new kernels, Linux userland, KDE updates, and optional packages.

What you won't find on that site are sources. ASUS is bound by the GPL to make the sources for the software they're distributing available, even if they have not modified them. (Check the license if you don't believe me.) ASUS has posted a 1.8GB ZIP file on their website that they claim is the sources, but it's not -- it contains a few .debs (not even the versions that ship on the machine) and some kernel headers. (Perhaps they figured nobody would pull 1.8GB from their slow-as-molasses site and find out.)

Through disassembly (I can do that, the software is GPL'd), it appears that ASUS has extensively modified the asus_acpi kernel module from Linux 2.6.21.4, so that it now works with the eee's hardware. This would be good except that

  • They appear to have stripped out all attribution. (Kernel modules contain information about the module name, version, and author. This has been removed.)

  • They appear to have attempted to hide what they were doing. (All references to "asus_acpi" have been removed, but other identifying features remain.)

  • They are not distributing their modified sources, or even a patch.


I have not contacted the author of asus_acpi, and it's possible that he has worked out a copyright licensing deal with ASUS -- but I was under the impression that the copyright of contributions to the Linux kernel were assigned to Linus or an agent thereof, which would not leave him with this right.

The madwifi drivers that ship on the machine are also a version never before seen in the wild, but as madwifi is dual-licensed GPL/BSD, modifying it is within ASUS's rights.

It's worth noting, from a legal perspective, that ASUS is also distributing BusyBox inside the system's initramfs image. (They do not appear, at first glance, to have stripped the attribution out of this one.) This is interesting because someone else distributing BusyBox without complying with the GPL is currently getting themselves sued in the first US civil suit over GPL violations.

Also worth noting: this is not the first time that ASUS has stolen from the community in this way. They were caught in 2004 stealing code from iptables/netfilter. They're also trying to cover their ass: they include the GPL in the box with the product, and state

This product includes copyrighted third-party software licensed under the terms of the GNU General Public License. ... ASUSTeK COMPUTER Inc. has exposed the full source code of the GPL licensed software, including any scripts to control compilation and installation the object code ... For more information how you can obtain our open source code, visit our website (http://support.asus.com.tw/download/).

...that website, for reference, is Home of the Giant Zip File I mentioned above.

Sigh.

(Edit (2007-11-23): To be fair, as commenters have pointed out, this may very well be simple negligence on ASUS's part. Yes, I and others have contacted ASUS about this with no response yet. Let's hope they just say "Whoops!" and fix the ZIP.)

Warranty Void If Removed


The last annoyance about the eee PC is the bright yellow "Warranty void if seal is broken or removed" sticker over the RAM upgrade slot.

Yes, you read that right: a computer manufacturer has decided that it voids your warranty to replace a DIMM.

The door in question also hides an available mini-PCI-Express slot, so needless to say, people would like to open it. For me, until I get out of the front of the bathtub curve and verify that the hardware works with Ubuntu, that sticker stays intact.

However, since I'm already pretending to be a lawyer in this post, allow me to discuss the Magnuson-Moss Act, what it says about tie-ins, and what exactly ASUS is doing here.

The Magnuson-Moss Act is a 1975 Federal law that lays down some rules for how consumer warranties work. One of the specific things it prohibits are "tie-ins," additional items or services you must buy from the manufacturer to make your warranty work. (This is why for-pay warranties these days are euphemistically termed 'service contracts.')

Examples of tie-ins are provided on the FTC's site. There's the unacceptable tie-in:

In order to keep your new Plenum Brand Vacuum Cleaner warranty in effect, you must use genuine Plenum Brand Filter Bags. Failure to have scheduled maintenance performed, at your expense, by the Great American Maintenance Company, Inc., voids this warranty.


...and the acceptable one:

While necessary maintenance or repairs on your AudioMundo Stereo System can be performed by any company, we recommend that you use only authorized AudioMundo dealers. Improper or incorrectly performed maintenance or repair voids this warranty.


Specifically, it's acceptable to void someone's warranty if maintenance is screwed up. (I'm paraphrasing the FTC's page, which was clearly paid by the word.)

Here are snippets from ASUS's warranty:

The warranty only covers failures or malfunctions occurred during the warranty period and in normal use conditions as will as for any material or workmanship defect. The warranty will not apply if: (a) the product has been tampered, repaired, or modified by non-authorized personnel; ... (c) the warranty seals have been broken or altered; ...

(Yes, those typos were in the original.)

Clause (a) above is clearly unenforceable under Magnuson-Moss -- it's one of the specific cases that the FTC cites as illegal.

Clause (c) follows as unenforceable: repairs (even normal upgrades) of the system cannot be performed without breaking the warranty seal. I'm not a lawyer, but I trust the judgment of judges; I doubt that a warranty stating "You can get this repaired by any qualified person but they can't look at it!" would be upheld. This is no different.

Edit (2007-11-23): One more note on my tie-in point: ASUS will be selling a "higher model" of the eee in the US, with more RAM and 8GB of Flash, starting at the end of this month. Someone will open this model up and post pictures. If the model is simply the original with a different DIMM and, say, a PCIe SSD dropped in, then what ASUS is saying is "These socketed, consumer-upgradeable parts will void your warranty if you touch them -- but if you pay us another $150 we'll change them for you." That's a bit more blatant than what I'd cited above.

Labels: , ,