ipw2200bg project

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.