This project has been started by a linux user frustrated by the unsupportive attitude of the original driver. I just wanted my LEDs to show what was going on. And then of course proof of concept :) <enno dot vet AT gmx dot net>.
The README file (below) should answer most questions, any unanswered please send email.
Alternative access via sourceforge.net/projects/ipw2200bg/.
================================ README for modified ipw2200 code. ipw2200bgN For kernel version >= 2.6.20 Tested on 2.6.30 and 2.6.32 from debian For kernels prior to 2.6.20 use the old code (ipw2200bg), this one won't work there. This has not been tested on SMP machines. This has not been tested on preemptible kernels. This has not been tested on anything other than a Dell Inspiron 1300 with an Intel PRO/Wireless 2200BG chip. Use At Your Own Risk. For the impatient: skip the philosophic part and start reading from 'USAGE'. INTRODUCTION [20110319: The original code from Intel hasn't been changed considerably in recent years. No effort to improve anything on the led things. They have only changed a few names. Which is the reason I don't provide patches anymore. -- And I have never received a reply from the Intel folk, either, so.] Bloody firmware. It's like experimenting with a black box! Logic would suggest that the LED primarily is to indicate if the device is switched on or off. Secondly it could flash while the device is unassociated (not a priority). Thirdly it could flash in different ways depending on circumstances (not a priority). The LED should really be hardwired IMHO. Otherwise you'll never know is your device switched on or off while the module is not loaded. Which latter needn't always be the case. With the original driver loaded with parameter led=1 the LED doesn't react before switching radio first on, then off, then back on again. After that it doesn't go off before unloading the module, no matter if the radio is switched on or not. As I've found that I'm not the only user being annoyed or perplexed by this behaviour (google is your witness), I decided to give it a try. Alas, I'm neither a kernel hacker nor even a proficient C programmer. And I don't dispose of lots of different hardware, so no testing on (real) SMP systems or different Intel Wireless NICs has been performed. You might have to adapt the PCI_IDS in ipw_led_init (ipw2200.c) to your subsystem_device's. Whoever feels inclined to adapt this code to other platforms than the i386 it has been tested on, please do. Though I don't think there'll be many SMP machines or sparcs or alphas out there equipped with an Intel PRO/Wireless 2200BG NIC. The original driver decides on the nic_type reported by the firmware, which parts of the LED code to use, if any. However the previous version of the firmware reported my nic_type as 1 while the chip was switched on, and 0 while switched off. This has changed now with a newer firmware, now it always says 'TYPE: 0'. This inconsistency in combination with the code claiming that type 1 has several LEDs instead of only one like mine made me believe there was some confusion in the intel household. I have changed a few strategic aspects and tried to simplify the code a little. Intel folk seem to have done quite a bit of work on associated code to adapt to new kernel structures. Also they have redefined some of their code into new libraries like libipw and lib80211. And due to kernel changes it isn't necessary anymore to load all involved modules manually (if you choose appropriate kernel config options that is). However Intel folk haven't done any changes regarding the LED code. But they've added quite a lot of le_to_cpu and cpu_to_le things, some of which are completely contrary to former settings. May those settings have been inadequate or are they just eyecandy, I don't know, at least for a driver which I suppose is not in broad use on platforms other than i.86. If Intel were as negligent about their CPUs as they seem to be about other chips they'd been long out of business (I think). USAGE Download Start with the original driver in place and check the following: ~ # cd /sys/bus/pci/drivers/ipw2200/[0000:02:03.0]* /sys/bus/pci/drivers/ipw2200/[0000:02:03.0]* $ cat device 0x4220 /sys/bus/pci/drivers/ipw2200/[0000:02:03.0]* $ cat subsystem_device 0x2722 (* This depends on which PCI location your chip is actually attached) These two (device and subsystem_device) are the identifiers that my code uses to decide about switching on the LED code. If your values are the same it should be safe to use my modified code. Otherwise you'll have to experiment and adapt the settings in ipw2200.c. You have to have a kernel build tree at hand. That means you'll have to have a kernel source directory and appropriate kernel configuration (usually: /usr/src/<YourSourceDir>/.config) and dependency information of your current kernel -- otherwise the compiler won't know if f.i. you have some dependencies built in or compiled as modules and such. If you don't have such a thing, create it -- by configuring and compiling your own kernel -- it's exciting, and usually worth doing, it can speed up your machine by discarding things that are not present on your system, and you'll learn some things about your linux kernel! `recent kernel' in the text below refers to 2.6.29 or 2.6.30. Kernel configuration: It's advisable to activate at least the CONFIG_MAGIC_SYSRQ (s. below) and to use a journalling filesystem (such as ext3 or reiser), to be on the safe side. Modules are part of the kernel and if something doesn't work out you can end up with quite undesirable results -- like a complete system hang, where even sysrq can't help you, therefore use a safe filesystem. You might also need the following, found in older kernels: `Networking -> Networking support -> Generic IEEE 802.11 Networking Stack': ieee80211_crypt_ccmp, ieee80211_crypt_tkip, ieee80211_crypt_wep. The following three, needed for WPA/WPA2 (found in `Cryptographic options'), should automatically be selected by the above: arc4, crc32c, michael_mic. recent kernels: `Networking support -> Wireless -> Common routines for IEEE802.11 drivers': lib80211, libipw (Should be automatically enabled if you choose IPW2200=m). I would suggest to compile all these settings as modules as it gives you more control over what happens when the kernel boots. Nota bene: When playing with kernels you should always have a working kernel available as fallback to boot if anything goes wrong. You have been warned. Finally you'll need the firmware, available from the Intel website, contents of ipw-fw-n.n.gtz to be placed in /lib/firmware/. The firmware is usually not shipped with the Linux source. In case you have to compile your kernel first, you can of course just place the two files (ipw2200bg.c, ipw2200bg.h) into your linux source tree at the appropriate place (back up original code just in case): older kernels: /usr/src/%lt;YourSourceDir>/drivers/net/wireless/ recent kernel: /usr/src/<YourSourceDir>/drivers/net/wireless/ipw2x00/ and link or name them to ipw2200.c and ipw2200.h Otherwise (if you're not going to compile your kernel) just create a directory for the code (e.g. ~/ipw), put the two source files there (ipw2200.c and ipw2200.h) and create a Makefile there with the text editor of your choice: #==========================================================# ifneq ($(KERNELRELEASE),) obj-m:= ipw2200.o else KERNELDIR ?= /lib/modules/<YourKernelVersion2>/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif #=====================End Of File==========================# Of course you can name the obj-m dinosaur.o instead of ipw2200.o if you like. With a recent kernel you will then have to symlink ieee80211.h to your ipw directory: ~/ipw # ln -s /usr/src/<YourSourceDir>/drivers/net/wireless/ipw2x00/ieee80211.h After that, you can simply issue: ~/ipw # make For all this hard work you'll obtain a file named ipw2200.ko, which is the new (modified) module. For the following steps you'll have to obtain root privileges. Back up the original driver in your module directory (for instance by simply renaming it to ipw2200.ko.orig) older kernels: /lib/modules/<YourKernelVersion>/kernel/drivers/net/wireless/ recent kernel: /lib/modules/<YourKernelVersion>/kernel/drivers/net/wireless/ipw2x00/ then copy the file from your ipw directory to the module directory. Depending on your distribution and settings, you might have to rmmod the original module before playing with the new one. Read the footnote about sysrq if you don't already know what that is. Then modprobe your new module first without setting the led parameter, just to see if the device still works with the modified code. If so, you can ~ # echo 1 > /sys/bus/pci/drivers/ipw2200/<YOURpciIDhere>/led and watch your LED. If it works, you can either set the modprobe to default your ipw2200.led to 1 by editing appropriate files (/etc/modprobe.d/ipw2200 on debian), or alter the source code and recompile. Good luck. As is with free and open_source software, the risk is with you. Not me, not Intel, only you. It works on my machine, to my satisfaction. FEATURES: Added a sysfs entry for en|disable, soft_off. $ echo 1 > soft_off to soft_switch_off the module, echo 0 > soft_off to soft_switch_on. I don't really know if anybody would need such a feature, but now it's there. Added different LED states: While switched off (so called RF_KILL switch), no LED. When switched on, while unassociated: fast blink, while associated: solid. When soft_switched off, slow blink. LOCKING: I've tested this with an SMP-kernel, but only on a UP machine, and sometimes during development got locking errors. These might be due to bugs (?) in the lock-debugging code, I don't know. ED <enno doT vet At gmx Dot net> 31 Dec 2009 =========================================================================== Footnotes: 1) SYSRQ: If you compile the 'magic' sysrq into the kernel, you can avoid severe crashes (even if you don't see the commands' output) by using the keys advertised in kernel-tree/Documentation/sysrq.txt. Usually this means you can sync your disk[s] with key-combination Alt+SysRq+S, unmount them with Alt+SysRq+U, reboot with Alt+SysRq+R. This should save you from having to boot from not cleanly unmounted filesystems. 2) `uname -r' will tell you your current kernel version. Alternatively you can look it up in /proc/sys/kernel/osrelease.