If you thought that sticking a supported miniPCI wireless card into a HP
nx6110 notebook and getting it to work is trivial or fast or well
documented, then you are quite wrong! Let me walk people trough the misery
here...
So you have you great
HP nx6110 notebook
with some kind of Linux installed. For this exercise we will assume that
we have Ubuntu Dapper Drake here, but similar problems will happen
anywhere else too. You have you shiny new
Intel PRO/Wireless 2200
card (or newer
IPW2915
that has even more problems) in miniPCI form factor. You open the back of
your notebook, stick the card into the slot, attach leads from the
antennae and ... the fun begins ...
The first problem is that you were cheap and instead of buying HP branded
IPW2200 card for 100$, you bought an OEM version for 20$. HP will not like
that, so right on the boot up you will be greeted by: "104 unsuported
wirless network device detected, system halted, remove device and
restart". Friendly, ne? The best workaround to this problem can be found
on a
HP forum
and it is to edit EEPROM of the miniPCI card so that it contains the PCI
ID that the HP laptop BIOS expects it to contain. Neat :)
WARNING: EEPROM contains lots of important data. Anything could happen if
wrong values are put there.
So, how will we do that? It is quite simple, really. First remove the card
and boot your Ubuntu. We will use the new Linux 2.6.16 kernel. To add
support to writing to EEPROM we will need
Martin Stachon's patch, but we will have to modify it a bit so that it fits 2.6.16 kernel, so
here is the updated patch:
--- linux-2.6.16/drivers/net/wireless/ipw2200.c 2006-03-20
07:53:29.000000000 +0200
+++
linux-2.6.16.new/drivers/net/wireless/ipw2200.c 2006-03-24
22:07:12.000000000 +0200
@@ -2345,6 +2345,8 @@
* NOTE: To better understand how these functions work (i.e what is a
chip
* select and why do have to keep driving the eeprom clock?), read
* just about any data sheet for a Microwire compatible EEPROM.
+ *
+ * The chip is 93C66 in 16x256 mode. */
/* write a 32 bit value into the indirect accessor register */
@@
-2425,6 +2427,37 @@
return r; }
+/* write 16 bits to the eeprom */
+static void
eeprom_write_u16(struct ipw_priv* priv, u8 addr, u16 data)
+{
+ int i;
+
+ printk(KERN_INFO DRV_NAME "
eeprom_write_u16(%02x, %04x) ", addr, data);
+
+ /*
write/erase enable */
+ eeprom_op(priv, EEPROM_CMD_EWEN,
EEPROM_CMD_EWEN_ADDR);
+ eeprom_disable_cs(priv);
+
+
eeprom_op(priv, EEPROM_CMD_WRITE, addr);
+
+ /* now the data
bits follow */
+ for ( i=15; i>=0; i-- ) {
+
eeprom_write_bit(priv, ( (data&(1<<i)) != 0 ) ? 1 : 0 );
+
}
+
+ /* CS needs to be taken low before next clock */
+
eeprom_write_reg(priv,0);
+ eeprom_write_reg(priv,EEPROM_BIT_SK);
+
+ msleep(10); /* wait for the write to complete */
+
+ eeprom_write_reg(priv,0);
+
+ /* write/erase disable
*/
+ eeprom_op(priv,EEPROM_CMD_EWDS,EEPROM_CMD_EWDS_ADDR);
+
eeprom_disable_cs(priv);
+}
+ /* helper function for pulling
the mac address out of the private */
/* data's copy of the eeprom data */
static void
eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
@@ -9946,19
+9979,45 @@
return 0; }
+#define IPW2200_EEPROM_MAGIC 0x2200
+#define
CX2_CHECKSUM 0x0040
static int ipw_ethtool_set_eeprom(struct
net_device *dev,
struct ethtool_eeprom *eeprom, u8 * bytes)
{
struct ipw_priv *p = ieee80211_priv(dev);
- int i;
+ u8
wordoffset;
+ u16 w;
+ int i;
+
+
if(eeprom->magic != IPW2200_EEPROM_MAGIC)
+ return -EINVAL;
if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
return -EINVAL;
+
+ wordoffset = eeprom->offset / 2;
+
+ /* TODO ethtool currently supports writing only 1 byte,
+ * take eeprom->len into account */
+
+ if
(eeprom->offset % 2 == 0) /* LSB */
+ w =
(p->eeprom[(eeprom->offset)+1] << 8 ) | *bytes;
+ else
/* MSB */
+ w = p->eeprom[(eeprom->offset)-1] | (*bytes
<< 8 ); down(&p->sem);
+ eeprom_write_u16(p,
wordoffset, w); memcpy(&p->eeprom[eeprom->offset], bytes,
eeprom->len);
- for (i = IPW_EEPROM_DATA;
- i <
IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++)
- ipw_write8(p, i,
p->eeprom[i]);
+ if (wordoffset > CX2_CHECKSUM / 2) {
+
p->eeprom[CX2_CHECKSUM] = 0;
+ p->eeprom[CX2_CHECKSUM+1] = 0;
+ for (i = CX2_CHECKSUM+2; i < IPW_EEPROM_IMAGE_SIZE; i+=2) {
+ p->eeprom[CX2_CHECKSUM] ^= p->eeprom[i];
+
p->eeprom[CX2_CHECKSUM+1] ^= p->eeprom[i+1];
+ }
+
eeprom_write_u16(p, CX2_CHECKSUM/2, (p->eeprom[CX2_CHECKSUM+1] <<
8 ) | p->eeprom[CX2_CHECKSUM]);
+ IPW_ERROR("New EEPROM Checksum
%04x ", (p->eeprom[CX2_CHECKSUM+1] << 8 ) |
p->eeprom[CX2_CHECKSUM]);
+ }
up(&p->sem);
return 0;
}
diff -u linux-2.6.16/drivers/net/wireless/ipw2200.h
linux-2.6.16.new/drivers/net/wireless/ipw2200.h
---
linux-2.6.16/drivers/net/wireless/ipw2200.h 2006-03-20 07:53:29.000000000
+0200
+++ linux-2.6.16.new/drivers/net/wireless/ipw2200.h 2006-03-24
21:15:47.000000000 +0200
@@ -1583,6 +1583,13 @@
#define
EEPROM_BIT_DO (1<<4)
#define EEPROM_CMD_READ 0x2
+#define EEPROM_CMD_WRITE 0x1
+#define EEPROM_CMD_EWEN 0x0 /*
write/erase enable */
+#define EEPROM_CMD_EWDS 0x0 /* write/erase
disable */
+
+/* these latter two are distinguished by two
upper bits in address */
+#define EEPROM_CMD_EWEN_ADDR 0xC0
+#define EEPROM_CMD_EWDS_ADDR 0x00 /* Interrupts masks */
#define IPW_INTA_NONE 0x00000000
Now that the kernel is patched with this patch, configure it, but be very
careful to configure both ipw2200 and ieee80211 as modules and _not_
compiled into the kernel. Compile and install the kernel as usual. Also
download IPW2200
firmware and
place it into /lib/firmware/.
Turn off your computer and prepare for hot insertion of the card - remove
the miniPCI slots cover, insert your IPW2200 card into the slot, attach
the antennae and then eject it from the slot, but leave it just there.
Turn on the computer and press "Esc" to get into GRUB bootup menu. At this
point turn over your computer and insert the IPW2200 card into the slot
while the computer is still running. Be very careful about static
electricity and try not to touch any contacts - you can easily fry your
notebook if you do something stupid here. When the card is inserted, boot
your new kernel.
The card should come up normally. The main check at this point is running
"iwconfig" (all commands as root) to see which interface is your wireless
card (it was "eth1" for me, substitute "eth1" for your interface name
further on if you have a different one) and then running "ethtool -e eth1"
to see a hex dump of the EEPROM of the WiFi card. If you get only bunch of
zeros, then something is wrong there - maybe your firmware does not match
with your driver version. Save the hex dump to a file - you might need it
if you do something wrong with it later.
Now it is the time to actually change the data in EEPROM. The commands to
get a HP approved European version of IPW2200 card
ethtool -E eth1 magic 0x2200 offset 0x8 value 0xf6
ethtool -E
eth1 magic 0x2200 offset 0x9 value 0x12
ethtool -E eth1 magic 0x2200
offset 0xa value 0x3c
ethtool -E eth1 magic 0x2200 offset 0xb value
0x10
To get HP approved USA version of IPW2200
ethtool -E eth1 magic 0x2200 offset 0x8 value 0xf5
ethtool -E
eth1 magic 0x2200 offset 0x9 value 0x12
ethtool -E eth1 magic 0x2200
offset 0xa value 0x3c
ethtool -E eth1 magic 0x2200 offset 0xb value
0x10
At this point it should be safe to reboot your system with the card inside
and the BIOS error should be no problem for you any more. Once a card has
been altered this way it can be used in any HP notebook in any OS.
However if you are like me then another stumbling block will be in your
way: Kill switch. HP nx6110 has a switch in BIOS that permanently switches
off miniPCI WiFi. The drives sees that as hardware kill switch. And of
course I had to spend an hour until I figured that I had disabled that
option in the BIOS "to save a bit of power" several months ago.
To gain some extra geekness points you should also download and compile
the newest versions of
ieee80211 and ipw2200 driver with
the newest
firmware, but
remember that you will need to erase the modules that you built from your
kernel tree and also comment out some options in few kernel config files.
The installation docs of ipw2200 have all the details on that. And also do
not forget to get a newer version of the firmware to go with those
drivers.
After I had done all those manipulations and also enabled ipw2200 drivers
led option I gained fully functional WiFi card with fully functional LED
indication and working software kill switch - I press the WiFi button and
the radio goes off (along with the indicator LED), I press it again and
the LED starts blinking and when the card associates with an access point
the LED lights up fully in its great wireless glory.
If your IPW2200 minPCI card still does not work, then check again if you
have the firmware in place and then see what "dmesg" says to you after you
tried to load the drivers.
HP, this is really not nice at all!