IPW2200 on HP nx6110
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!