diff -Naur linux-2.6.2/drivers/net/wireless/airport.c linux-2.6.2-orinoco/drivers/net/wireless/airport.c
--- linux-2.6.2/drivers/net/wireless/airport.c	2003-12-18 10:59:45.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/airport.c	2004-02-17 15:26:40.000000000 +0800
@@ -16,24 +16,26 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
 
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/current.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/irq.h>
-#include <asm/uaccess.h>
 
 #include "orinoco.h"
 
@@ -46,115 +48,96 @@
 	int ndev_registered;
 };
 
-static int
-airport_suspend(struct macio_dev *mdev, u32 state)
-{
-	struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-	struct orinoco_private *priv = dev->priv;
-	struct airport *card = priv->card;
-	unsigned long flags;
-	int err;
-
-	printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
-
-	err = orinoco_lock(priv, &flags);
-	if (err) {
-		printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
-		       dev->name);
-		return 0;
-	}
-
-	err = __orinoco_down(dev);
-	if (err)
-		printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
-		       dev->name, err);
-
-	netif_device_detach(dev);
-
-	priv->hw_unavailable++;
+#ifdef CONFIG_PMAC_PBOOK
+static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier airport_sleep_notifier = {
+	airport_sleep_notify, SLEEP_LEVEL_NET,
+};
+#endif
 
-	orinoco_unlock(priv, &flags);
+/*
+ * Function prototypes
+ */
 
-	disable_irq(dev->irq);
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
+static struct net_device *airport_attach(struct device_node *of_node);
+static void airport_detach(struct net_device *dev);
 
-	return 0;
-}
+static struct net_device *airport_dev;
 
+#ifdef CONFIG_PMAC_PBOOK
 static int
-airport_resume(struct macio_dev *mdev)
+airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
-	struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
+	struct net_device *dev = airport_dev;
 	struct orinoco_private *priv = dev->priv;
 	struct airport *card = priv->card;
 	unsigned long flags;
 	int err;
+	
+	if (! airport_dev)
+		return PBOOK_SLEEP_OK;
+
+	switch (when) {
+	case PBOOK_SLEEP_NOW:
+		printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
+
+		err = orinoco_lock(priv, &flags);
+		if (err) {
+			printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
+			       dev->name);
+			break;
+		}
 
-	printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
+		err = __orinoco_down(dev);
+		if (err)
+			printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
+			       dev->name, err);
 
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
-	mdelay(200);
+		netif_device_detach(dev);
 
-	enable_irq(dev->irq);
+		priv->hw_unavailable++;
 
-	err = orinoco_reinit_firmware(dev);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
-		       dev->name, err);
-		return 0;
-	}
+		orinoco_unlock(priv, &flags);
 
-	spin_lock_irqsave(&priv->lock, flags);
+		disable_irq(dev->irq);
+		pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
+		break;
 
-	netif_device_attach(dev);
+	case PBOOK_WAKE:
+		printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
+		pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
+		mdelay(200);
 
-	priv->hw_unavailable--;
+		enable_irq(dev->irq);
 
-	if (priv->open && (! priv->hw_unavailable)) {
-		err = __orinoco_up(dev);
-		if (err)
-			printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
+		err = orinoco_reinit_firmware(dev);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
 			       dev->name, err);
-	}
+			break;
+		}
 
+		spin_lock_irqsave(&priv->lock, flags);
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return 0;
-}
-
-static int
-airport_detach(struct macio_dev *mdev)
-{
-	struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-	struct orinoco_private *priv = dev->priv;
-	struct airport *card = priv->card;
+		netif_device_attach(dev);
 
-	if (card->ndev_registered)
-		unregister_netdev(dev);
-	card->ndev_registered = 0;
+		priv->hw_unavailable--;
 
-	if (card->irq_requested)
-		free_irq(dev->irq, dev);
-	card->irq_requested = 0;
+		if (priv->open && (! priv->hw_unavailable)) {
+			err = __orinoco_up(dev);
+			if (err)
+				printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
+				       dev->name, err);
+		}
 
-	if (card->vaddr)
-		iounmap(card->vaddr);
-	card->vaddr = 0;
 
-	dev->base_addr = 0;
+		spin_unlock_irqrestore(&priv->lock, flags);
 
-	release_OF_resource(card->node, 0);
-
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout(HZ);
-
-	dev_set_drvdata(&mdev->ofdev.dev, NULL);
-	free_netdev(dev);
-
-	return 0;
+		break;
+	}
+	return PBOOK_SLEEP_OK;
 }
+#endif /* CONFIG_PMAC_PBOOK */
 
 static int airport_hard_reset(struct orinoco_private *priv)
 {
@@ -187,26 +170,25 @@
 	return 0;
 }
 
-static int
-airport_attach(struct macio_dev *mdev, const struct of_match *match)
+static struct net_device *
+airport_attach(struct device_node *of_node)
 {
 	struct orinoco_private *priv;
 	struct net_device *dev;
 	struct airport *card;
 	unsigned long phys_addr;
-	struct device_node *of_node = mdev->ofdev.node;
 	hermes_t *hw;
 
 	if (of_node->n_addrs < 1 || of_node->n_intrs < 1) {
 		printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
-		return -ENODEV;
+		return NULL;
 	}
 
 	/* Allocate space for private device-specific data */
 	dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
 	if (! dev) {
 		printk(KERN_ERR "airport: can't allocate device datas\n");
-		return -ENODEV;
+		return NULL;
 	}
 	priv = dev->priv;
 	card = priv->card;
@@ -217,14 +199,11 @@
 	if (! request_OF_resource(of_node, 0, " (airport)")) {
 		printk(KERN_ERR "airport: can't request IO resource !\n");
 		kfree(dev);
-		return -ENODEV;
+		return NULL;
 	}
 
 	dev->name[0] = '\0';	/* register_netdev will give us an ethX name */
 	SET_MODULE_OWNER(dev);
-	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
-
-	dev_set_drvdata(&mdev->ofdev.dev, dev);
 
 	/* Setup interrupts & base address */
 	dev->irq = of_node->intrs[0].line;
@@ -261,50 +240,79 @@
 	}
 	printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
 	card->ndev_registered = 1;
-	return 0;
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&airport_sleep_notifier);
+#endif
+	return dev;
+	
  failed:
-	airport_detach(mdev);
-	return -ENODEV;
+	airport_detach(dev);
+	return NULL;
 }				/* airport_attach */
 
+/*======================================================================
+  This deletes a driver "instance".  
+  ======================================================================*/
+
+static void
+airport_detach(struct net_device *dev)
+{
+	struct orinoco_private *priv = dev->priv;
+	struct airport *card = priv->card;
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_unregister_sleep_notifier(&airport_sleep_notifier);
+#endif
+	if (card->ndev_registered)
+		unregister_netdev(dev);
+	card->ndev_registered = 0;
+
+	if (card->irq_requested)
+		free_irq(dev->irq, dev);
+	card->irq_requested = 0;
+
+	if (card->vaddr)
+		iounmap(card->vaddr);
+	card->vaddr = 0;
+
+	dev->base_addr = 0;
+
+	release_OF_resource(card->node, 0);
+
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+
+	kfree(dev);
+}				/* airport_detach */
 
 static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
 MODULE_LICENSE("Dual MPL/GPL");
 
-static struct of_match airport_match[] = 
-{
-	{
-	.name 		= "radio",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
-	},
-	{},
-};
-
-static struct macio_driver airport_driver = 
-{
-	.name 		= "airport",
-	.match_table	= airport_match,
-	.probe		= airport_attach,
-	.remove		= airport_detach,
-	.suspend	= airport_suspend,
-	.resume		= airport_resume,
-};
-
 static int __init
 init_airport(void)
 {
+	struct device_node *airport_node;
+
 	printk(KERN_DEBUG "%s\n", version);
 
-	return macio_register_driver(&airport_driver);
+	/* Lookup card in device tree */
+	airport_node = find_devices("radio");
+	if (airport_node && !strcmp(airport_node->parent->name, "mac-io"))
+		airport_dev = airport_attach(airport_node);
+
+	return airport_dev ? 0 : -ENODEV;
 }
 
 static void __exit
 exit_airport(void)
 {
-	return macio_unregister_driver(&airport_driver);
+	if (airport_dev)
+		airport_detach(airport_dev);
+	airport_dev = NULL;
 }
 
 module_init(init_airport);
diff -Naur linux-2.6.2/drivers/net/wireless/hermes.c linux-2.6.2-orinoco/drivers/net/wireless/hermes.c
--- linux-2.6.2/drivers/net/wireless/hermes.c	2003-12-18 10:58:16.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/hermes.c	2004-02-17 15:26:40.000000000 +0800
@@ -183,6 +183,10 @@
 	if (err)
 		return err;
 
+        for ( k = 0; k < HERMES_NUMPORTS_MAX; k++) {
+		hw->port_enabled[k] = 0;
+	}
+
 	reg = hermes_read_regn(hw, EVSTAT);
 	k = CMD_INIT_TIMEOUT;
 	while ( (! (reg & HERMES_EV_CMD)) && k) {
diff -Naur linux-2.6.2/drivers/net/wireless/hermes.conf linux-2.6.2-orinoco/drivers/net/wireless/hermes.conf
--- linux-2.6.2/drivers/net/wireless/hermes.conf	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/hermes.conf	2004-02-17 15:26:40.000000000 +0800
@@ -0,0 +1,118 @@
+device "orinoco_cs"
+  class "network"
+  module "hermes", "orinoco", "orinoco_cs"
+#  module "hermes", "orinoco", "orinoco_cs" opts "pc_debug=3"
+
+#
+# Wireless network adapters
+#
+# We should use the manfid (which cover multiple cards), otherwise we will
+# go crazy listing all cards and their variations !!!
+
+# First class of device : Lucent & OEM
+card "Orinoco or Intersil Prism 2 Wireless"
+  manfid 0x0156,0x0002
+  bind "orinoco_cs"
+
+card "Lucent Technologies Wavelan/IEEE"
+  version "Lucent Technologies", "WaveLAN/IEEE"
+  bind "orinoco_cs"
+
+card "Avaya World Card"
+  version "Avaya Communication", "Avaya Wireless PC Card"
+  bind "orinoco_cs"
+
+card "Cabletron RoamAbout 802.11 DS"
+  version "Cabletron", "RoamAbout 802.11 DS"
+  bind "orinoco_cs"
+
+card "ELSA AirLancer MC-11"
+  version "ELSA", "AirLancer MC-11"
+  bind "orinoco_cs"
+
+card "MELCO WLI-PCM-L11"
+  version "MELCO", "WLI-PCM-L11"
+  bind "orinoco_cs"
+
+# Second class of device : Symbol & OEM
+card "LA4111 Spectrum24 Wireless LAN PC Card"
+  version "Symbol Technologies"
+  bind "orinoco_cs"
+
+card "3Com AirConnect"
+  version "3Com", "3CRWE737A AirConnect Wireless LAN PC Card"
+  bind "orinoco_cs"
+
+card "Intel PRO/Wireless 2011"
+  manfid 0x0089,0x0001
+  bind "orinoco_cs"
+
+card "Ericsson WLAN Card C11"
+  manfid 0x016b,0x0001
+  bind "orinoco_cs" 
+
+card "Nortel Networks e-mobility 802.11 Wireless LAN PC Card"
+  version "Nortel Networks", "emobility 802.11 Wireless LAN PC Card", "1.00"
+  bind "orinoco_cs"
+
+card "D-Link DWL-650H"
+  version "D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter"
+  bind "orinoco_cs"
+
+# Third class of device : other Intersil clones
+card "Farallon SkyLINE"
+  version "INTERSIL", "HFA384x/IEEE"
+  bind "orinoco_cs"
+
+card "D-Link DWL-650"
+  version "D", "Link DWL-650 11Mbps WLAN Card"
+  bind "orinoco_cs"
+
+card "SAMSUNG 11Mbps WLAN Card"
+  version "SAMSUNG", "11Mbps WLAN Card"
+  bind "orinoco_cs"
+# Does this one cover Compaq as well ???
+
+card "HyperLink Wireless PC Card 11Mbps"
+  version "HyperLink","Wireless PC Card 11Mbps"
+  bind "orinoco_cs"
+
+card "PROXIM LAN PC CARD HARMONY 80211B"
+  version "PROXIM","LAN PC CARD HARMONY 80211B"
+  bind "orinoco_cs"
+
+card "Linksys WPC11 11Mbps 802.11b WLAN Card"
+  version "Instant Wireless ", " Network PC CARD", "Version 01.02"
+  bind "orinoco_cs"
+
+card "Linksys WPC11 11Mbps 802.11b WLAN Card"
+  version "The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", "RevA"
+  bind "orinoco_cs"
+
+card "Linksys CompactFlash Wireless Card"
+  version "Linksys", "Wireless CompactFlash Card"
+  bind "orinoco_cs"
+
+card "Tekram PCF-200"
+  version "PCMCIA", "11M WLAN Card v2.5", "ISL37300P", "RevA"
+  bind "orinoco_cs"
+
+card "ACTIONTEC PRISM Wireless LAN PC Card"
+  version "ACTIONTEC", "PRISM Wireless LAN PC Card"
+  bind "orinoco_cs"
+
+card "Zcomax XI-325HP"
+  version " ", "IEEE 802.11 Wireless LAN/PC Card"
+  bind "orinoco_cs"
+
+card "Microsoft Wireless Notebook Adapter MN-520 1.0.3" 
+  version "Microsoft", "Wireless Notebook Adapter MN-520", "", "1.0.3"
+  bind "orinoco_cs"
+
+card "Linksys WPC11 Version 3"
+  manfid 0x0274,0x1613
+  bind "orinoco_cs"
+
+card "Netgear MA401RA"
+  version "NETGEAR MA401RA Wireless PC", "Card", "ISL37300P", "Eval-RevA"
+  bind "orinoco_cs"
diff -Naur linux-2.6.2/drivers/net/wireless/hermes.h linux-2.6.2-orinoco/drivers/net/wireless/hermes.h
--- linux-2.6.2/drivers/net/wireless/hermes.h	2003-12-18 10:58:08.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/hermes.h	2004-02-17 15:26:40.000000000 +0800
@@ -33,6 +33,10 @@
 #include <linux/if_ether.h>
 #include <asm/byteorder.h>
 
+#define		HFA384x_PORTTYPE_IBSS			((uint16_t)3)
+#define		HFA384x_WEPFLAGS_DISABLE_TXCRYPT	(0x10)
+#define		HFA384x_WEPFLAGS_DISABLE_RXCRYPT	(0x80)
+
 /*
  * Limits and constants
  */
@@ -149,6 +153,38 @@
 #define		HERMES_MONITOR_DISABLE		(0x000f)
 
 /*
+ * Configuration RIDs
+ */
+
+#define		HERMES_RID_CNF_PORTTYPE		(0xfc00)
+#define		HERMES_RID_CNF_CHANNEL		(0xfc03)
+#define		HERMES_RID_CNF_PRISM2_WEP_ON	(0xfc28)
+
+/*-- Status Fields --*/
+#define		HERMES_RXSTATUS_MSGTYPE		(0xE000)
+#define		HERMES_RXSTATUS_MACPORT		(0x0700)
+#define		HERMES_RXSTATUS_UNDECR		(0x0002)
+#define		HERMES_RXSTATUS_FCSERR		(0x0001)
+
+/*--------------------------------------------------------------------
+Communication Frames: Test/Get/Set Field Values for Receive Frames
+--------------------------------------------------------------------*/
+#define		HERMES_RXSTATUS_MSGTYPE_GET(value)	(((value) & HERMES_RXSTATUS_MSGTYPE) >> 13)
+#define		HERMES_RXSTATUS_MSGTYPE_SET(value)	((value) << 13)
+#define		HERMES_RXSTATUS_MACPORT_GET(value)	(((value) & HERMES_RXSTATUS_MACPORT) >> 8)
+#define		HERMES_RXSTATUS_MACPORT_SET(value)	((value) << 8)
+#define		HERMES_RXSTATUS_ISUNDECR(value)	((value) & HERMES_RXSTATUS_UNDECR)
+#define		HERMES_RXSTATUS_ISFCSERR(value)	((value) & HERMES_RXSTATUS_FCSERR)
+
+/*--------------------------------------------------------------------
+Communication Frames: Field Masks for Receive Frames
+--------------------------------------------------------------------*/
+/*-- Offsets --------*/
+#define		HERMES_RX_DATA_LEN_OFF		(44)
+#define		HERMES_RX_80211HDR_OFF		(14)
+#define		HERMES_RX_DATA_OFF			(60)
+
+/*
  * Frame structures and constants
  */
 
@@ -286,6 +322,7 @@
 #define HERMES_32BIT_REGSPACING	1
 
 	u16 inten; /* Which interrupts should be enabled? */
+ 	uint8_t		port_enabled[HERMES_NUMPORTS_MAX];
 
 #ifdef HERMES_DEBUG_BUFFER
 	struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE];
@@ -302,14 +339,12 @@
 #define hermes_read_reg(hw, off) ((hw)->io_space ? \
 	inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
 	readw((hw)->iobase + ( (off) << (hw)->reg_spacing )))
-#define hermes_write_reg(hw, off, val) do { \
-	if ((hw)->io_space) \
-		outw_p((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \
-	else \
-		writew((val), (hw)->iobase + ((off) << (hw)->reg_spacing)); \
-	} while (0)
-#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name)
-#define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val))
+#define hermes_write_reg(hw, off, val) ((hw)->io_space ? \
+	outw_p((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
+	writew((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )))
+
+#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name))
+#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val)))
 
 /* Function prototypes */
 void hermes_struct_init(hermes_t *hw, ulong address, int io_space, int reg_spacing);
@@ -341,12 +376,14 @@
 
 static inline int hermes_enable_port(hermes_t *hw, int port)
 {
+        hw->port_enabled[port] = 1;
 	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
 				 0, NULL);
 }
 
 static inline int hermes_disable_port(hermes_t *hw, int port)
 {
+        hw->port_enabled[port] = 0;
 	return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 
 				 0, NULL);
 }
diff -Naur linux-2.6.2/drivers/net/wireless/orinoco.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco.c
--- linux-2.6.2/drivers/net/wireless/orinoco.c	2003-12-18 11:00:00.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco.c	2004-02-17 15:26:40.000000000 +0800
@@ -458,6 +458,7 @@
 #endif
 
 static int suppress_linkstatus; /* = 0 */
+static int suppress_linkstatus_copy; /* = 0 */
 MODULE_PARM(suppress_linkstatus, "i");
 
 /********************************************************************/
@@ -1673,6 +1674,7 @@
 	struct header_struct hdr;
 	struct ethhdr *eh;
 	int err;
+        struct ieee802_11_hdr hdr80211;
 
 	rxfid = hermes_read_regn(hw, RXFID);
 
@@ -1689,6 +1691,7 @@
 	
 	if (status & HERMES_RXSTAT_ERR) {
 		if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+                    if (dev->type != ARPHRD_ETHER) goto sniffing;
 			wstats->discard.code++;
 			DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
 			       dev->name);
@@ -1699,7 +1702,7 @@
 		stats->rx_errors++;
 		goto drop;
 	}
-
+sniffing:
 	/* For now we ignore the 802.11 header completely, assuming
            that the card's firmware has handled anything vital */
 
@@ -1730,6 +1733,11 @@
 		goto drop;
 	}
 
+	/* Now handle frame based on port# */
+	switch( HERMES_RXSTATUS_MACPORT_GET(status) )
+	{
+	case 0:
+
 	/* We need space for the packet data itself, plus an ethernet
 	   header, plus 2 bytes so we can align the IP header on a
 	   32bit boundary, plus 1 byte so we can read in odd length
@@ -1804,6 +1812,26 @@
 
 	return;
 
+	case 7:
+        	if ( ! HERMES_RXSTATUS_ISFCSERR(status) ) {
+                   if (hermes_bap_pread(hw, IRQ_BAP, &hdr80211, sizeof(hdr80211), 
+                                       rxfid, HERMES_RX_80211HDR_OFF)) {
+                      stats->rx_errors++;
+                   }
+                   else {
+                        /* Copy to wlansnif skb */
+                        orinoco_int_rxmonitor( priv, rxfid, length, &desc, &hdr80211);
+                   }
+                } else {
+                        printk("Received monitor frame: FCSerr set\n");
+                }
+                break;
+	default:
+		printk("Received frame on unsupported port=%d\n",
+			HERMES_RXSTATUS_MACPORT_GET(status) );
+		break;
+	}
+
  drop:	
 	stats->rx_dropped++;
 
@@ -2446,6 +2474,24 @@
 	return err;
 }
 
+//#define SET_MAC_ADDRESS
+#ifdef SET_MAC_ADDRESS
+static int
+orinoco_set_mac_address(struct net_device *dev, void *addr)
+{
+  struct orinoco_private *priv = dev->priv;
+  struct sockaddr *mac = addr;
+
+  /* Copy the address */
+  memcpy(dev->dev_addr, mac->sa_data, WLAN_ADDR_LEN);
+
+  /* Reconfig the beast */
+  orinoco_reset(priv);
+
+  return 0;
+}
+#endif	/* SET_MAC_ADDRESS */
+
 static void
 orinoco_tx_timeout(struct net_device *dev)
 {
@@ -3598,6 +3644,170 @@
 	return 0;
 }
 
+/*----------------------------------------------------------------
+* orinoco_wlansniff
+*
+* Start or stop sniffing.
+*
+* Arguments:
+*	wlandev		wlan device structure
+*	msgp		ptr to msg buffer
+*
+* Returns: 
+*	0	success and done
+*	<0	success, but we're waiting for something to finish.
+*	>0	an error occurred while handling the message.
+* Side effects:
+*
+* Call context:
+*	process thread  (usually)
+*	interrupt
+----------------------------------------------------------------*/
+static int orinoco_wlansniff(struct net_device *dev, struct iwreq *wrq)
+{
+	struct orinoco_private *priv = dev->priv;
+	hermes_t *hw = &(priv->hw);
+        hermes_response_t  resp;
+	int result = 0;
+	uint16_t word;
+
+	int *parms = (int *) wrq->u.name;
+	int enable = parms[0] > 0;
+	unsigned long flags;
+	int noMonitor = dev->type != ARPHRD_IEEE80211_PRISM &&
+	                dev->type != ARPHRD_IEEE80211;
+
+	orinoco_lock(priv, &flags);
+
+	switch (enable)
+	{
+	case P80211ENUM_truth_false:
+		/* Confirm that we're in monitor mode */
+		if ( noMonitor ) {
+			result = -EFAULT;
+		}
+		/* Disable monitor mode */
+		suppress_linkstatus = suppress_linkstatus_copy;
+	        word =	HERMES_CMD_MONITOR | (HERMES_MONITOR_DISABLE << 8);
+	        result = hermes_docmd_wait(hw, word, 0, &resp);
+
+		if ( result ) break;
+
+		/* Disable port 0 */
+		result = hermes_disable_port(hw, 0);
+		if ( result ) break;
+
+		/* Clear the driver state */
+		dev->type = ARPHRD_ETHER;
+
+		/* Restore the wepflags */   //Orinoco doesn't like this
+/*
+		result = hermes_write_wordrec(hw, USER_BAP,
+				HERMES_RID_CNF_PRISM2_WEP_ON, 
+				priv->presniff_wepflags);
+		if ( result ) break;
+
+*/
+		/* Set the port to its prior type and enable (if necessary) */
+		if (priv->presniff_port_type != 0 ) {
+			word = priv->presniff_port_type;
+			result = hermes_write_wordrec(hw, USER_BAP, 
+				HERMES_RID_CNF_PORTTYPE, word);
+		    if ( result ) break;
+
+			/* Enable the port */
+			result = hermes_enable_port(hw, 0);
+		    if ( result ) break;
+
+		}
+
+		break;
+	case P80211ENUM_truth_true:
+        	// Only do this if we're not in monitor mode already
+	        if (noMonitor) {
+	            /* Re-initialize the card before changing channel as advised at
+        	     * http://lists.samba.org/pipermail/wireless/2002-June/004491.html
+        	     * by Ian Goldberg.  Implementation by Pat Swieskowski.
+        	     */
+        	    //		__orinoco_down(dev);
+        	    hermes_set_irqmask(hw, 0);
+        	    hermes_init(hw);
+        	    //		_orinoco_up(dev);
+        	    hermes_set_irqmask(hw, ORINOCO_INTEN);
+		    suppress_linkstatus = 1;
+        	    /*
+        	       __orinoco_stop_irqs(priv);
+        	       hermes_reset(hw);
+        	       __orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
+        	       HERMES_EV_TX | HERMES_EV_TXEXC |
+        	       HERMES_EV_WTERR | HERMES_EV_INFO |
+        	       HERMES_EV_INFDROP);
+        	       */
+        	    /* Disable the port (if enabled), only check Port 0 */
+        	    if ( hw->port_enabled[0] ) {
+        	        /* Save macport 0 state */
+        	        result = hermes_read_wordrec(hw, USER_BAP,
+        	                                     HERMES_RID_CNF_PORTTYPE,
+        	                                     &(priv->presniff_port_type));
+        	        if ( result ) break;
+	
+        	        /* Save the wepflags state */
+        	        result = hermes_read_wordrec(hw, USER_BAP,
+        	                                     HERMES_RID_CNF_PRISM2_WEP_ON,
+	                                             &(priv->presniff_wepflags));
+        	        if ( result ) break;
+        	    }
+        	    else {
+        	        priv->presniff_port_type = 0;
+        	    }
+        	}
+
+        	// Disable the port
+        	result = hermes_disable_port(hw, 0);
+        	if ( result ) break;
+
+        	/* Set the channel we wish to sniff  */
+        	if (parms[1] > 0 && parms[1] < 15) {
+        	    word = parms[1];
+        	    result = hermes_write_wordrec(hw, USER_BAP, 
+        	                                  HERMES_RID_CNF_CHANNEL, word);
+        	} else {
+        	    result = -EFAULT;
+        	}
+
+        	if ( result ) break;
+
+        	if (noMonitor) {
+        	    /* Set the port type to pIbss */
+        	    word = HFA384x_PORTTYPE_IBSS;
+        	    result = hermes_write_wordrec(hw, USER_BAP, 
+        	                                  HERMES_RID_CNF_PORTTYPE, word);
+        	    if ( result ) break;
+
+        	    /* Enable monitor mode */
+        	    word = HERMES_CMD_MONITOR | (HERMES_MONITOR_ENABLE << 8);
+        	    result = hermes_docmd_wait(hw, word, 0, &resp);
+        	    if ( result ) break;
+        	}
+
+        	/* Enable the port */
+        	result = hermes_enable_port(hw, 0);
+        	if ( result ) break;
+		/* Set the driver state */
+		/* Do we want the prism2 header? */
+		if (parms[0] == 1)
+		  dev->type = ARPHRD_IEEE80211_PRISM;
+		else 
+		  dev->type = ARPHRD_IEEE80211;
+		break;
+	default:
+		result = -EFAULT;
+		break;
+	}
+	orinoco_unlock(priv, &flags);
+	return result;
+}
+
 static int
 orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -3830,9 +4040,16 @@
 				{ SIOCIWFIRSTPRIV + 0x7, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  "get_ibssport" },
+				{ SIOCIWFIRSTPRIV + 0x8,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+				  0, "monitor" },
 				{ SIOCIWLASTPRIV, 0, 0, "dump_recs" },
 			};
 
+			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
+			if (err)
+				break;
+			
 			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
 			if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
 				err = -EFAULT;
@@ -3920,6 +4137,16 @@
 		err = orinoco_ioctl_getibssport(dev, wrq);
 		break;
 
+        case SIOCIWFIRSTPRIV + 0x8: /* set sniff (monitor) mode */ 
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x8 (monitor)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+                err = orinoco_wlansniff(dev, wrq);
+		break;
+
 	case SIOCIWLASTPRIV:
 		err = orinoco_debug_dump_recs(dev);
 		if (err)
@@ -4142,6 +4369,9 @@
 	dev->tx_timeout = orinoco_tx_timeout;
 	dev->watchdog_timeo = HZ; /* 1 second timeout */
 	dev->get_stats = orinoco_get_stats;
+#ifdef SET_MAC_ADDRESS
+        dev->set_mac_address = orinoco_set_mac_address;
+#endif	/* SET_MAC_ADDRESS */
 	dev->get_wireless_stats = orinoco_get_wireless_stats;
 	dev->do_ioctl = orinoco_ioctl;
 	dev->change_mtu = orinoco_change_mtu;
@@ -4167,6 +4397,197 @@
 
 }
 
+/*----------------------------------------------------------------
+* orinoco_int_rxmonitor
+*
+* Helper function for int_rx.  Handles monitor frames.
+* Note that this function allocates space for the FCS and sets it
+* to 0xffffffff.  The hfa384x doesn't give us the FCS value but the
+* higher layers expect it.  0xffffffff is used as a flag to indicate
+* the FCS is bogus.
+*
+* Arguments:
+*	dev		wlan device structure
+*	rxfid		received FID
+*	rxdesc		rx descriptor read from card in int_rx
+*
+* Returns: 
+*	nothing
+*
+* Side effects:
+*	Allocates an skb and passes it up via the PF_PACKET interface.
+* Call context:
+*	interrupt
+----------------------------------------------------------------*/
+void orinoco_int_rxmonitor( struct orinoco_private *dev, uint16_t rxfid, int len,
+                            struct hermes_rx_descriptor *rxdesc, struct ieee802_11_hdr *hdr)
+{
+	hermes_t			*hw = &(dev->hw);
+	uint32_t				hdrlen = 0;
+	uint32_t				datalen = 0;
+	uint32_t				skblen = 0;
+	p80211msg_lnxind_wlansniffrm_t	*msg;
+	struct net_device_stats *stats = &dev->stats;
+
+
+	uint8_t				*datap;
+	uint16_t				fc;
+	struct sk_buff			*skb;
+
+	/* Don't forget the status, time, and data_len fields are in host order */
+	/* Figure out how big the frame is */
+	fc = le16_to_cpu(hdr->frame_ctl);
+	switch ( WLAN_GET_FC_FTYPE(fc) )
+	{
+	case WLAN_FTYPE_DATA:
+		if ( WLAN_GET_FC_TODS(fc) && WLAN_GET_FC_FROMDS(fc) ) {
+			hdrlen = WLAN_HDR_A4_LEN;
+		} else {
+			hdrlen = WLAN_HDR_A3_LEN;
+		}
+		datalen = len;
+		break;
+	case WLAN_FTYPE_MGMT:
+		hdrlen = WLAN_HDR_A3_LEN;
+		datalen = len;
+		break;
+	case WLAN_FTYPE_CTL:
+		switch ( WLAN_GET_FC_FSTYPE(fc) )
+		{
+		case WLAN_FSTYPE_PSPOLL:
+		case WLAN_FSTYPE_RTS:
+		case WLAN_FSTYPE_CFEND:
+		case WLAN_FSTYPE_CFENDCFACK:
+			hdrlen = 16;
+			break;
+		case WLAN_FSTYPE_CTS:
+		case WLAN_FSTYPE_ACK:
+			hdrlen = 10;
+			break;
+		}
+		datalen = 0;
+		break;
+	default:
+		printk("unknown frm: fc=0x%04x\n", fc);
+		return;
+	}
+
+	/* Allocate an ind message+framesize skb */
+	skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + 
+	  hdrlen + datalen;
+	
+	/* sanity check the length */
+	if ( skblen > 
+		(sizeof(p80211msg_lnxind_wlansniffrm_t) + 
+		WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) {
+		printk("overlen frm: len=%d\n", 
+			skblen - sizeof(p80211msg_lnxind_wlansniffrm_t));
+	}
+			
+	if ( (skb = dev_alloc_skb(skblen)) == NULL ) {
+		printk("alloc_skb failed trying to allocate %d bytes\n", skblen);
+		return;
+	}
+
+	/* only prepend the prism header if in the right mode */
+	if (dev->ndev->type != ARPHRD_IEEE80211_PRISM) {
+	  skb_put(skb, skblen - sizeof(p80211msg_lnxind_wlansniffrm_t));
+	  datap = skb->data;
+	} else {
+	  skb_put(skb, skblen);
+	  datap = skb->data + sizeof(p80211msg_lnxind_wlansniffrm_t);
+	  msg = (p80211msg_lnxind_wlansniffrm_t*)skb->data;
+	  
+	  /* Initialize the message members */
+	  msg->msgcode = DIDmsg_lnxind_wlansniffrm;
+	  msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t);
+	  strcpy(msg->devname, dev->ndev->name);
+	  
+	  msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime;
+	  msg->hosttime.status = 0;
+	  msg->hosttime.len = 4;
+	  msg->hosttime.data = jiffies;
+	  
+	  msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime;
+	  msg->mactime.status = 0;
+	  msg->mactime.len = 4;
+	  msg->mactime.data = rxdesc->time;
+	  
+	  msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel;
+	  msg->channel.status = P80211ENUM_msgitem_status_no_value;
+	  msg->channel.len = 4;
+	  msg->channel.data = 0;
+
+	  msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi;
+	  msg->rssi.status = P80211ENUM_msgitem_status_no_value;
+	  msg->rssi.len = 4;
+	  msg->rssi.data = 0;
+	  
+	  msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq;
+	  msg->sq.status = P80211ENUM_msgitem_status_no_value;
+	  msg->sq.len = 4;
+	  msg->sq.data = 0;
+	  
+	  msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal;
+	  msg->signal.status = 0;
+	  msg->signal.len = 4;
+	  msg->signal.data = rxdesc->signal;
+	  
+	  msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise;
+	  msg->noise.status = 0;
+	  msg->noise.len = 4;
+	  msg->noise.data = rxdesc->silence;
+
+	  msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate;
+	  msg->rate.status = 0;
+	  msg->rate.len = 4;
+	  msg->rate.data = rxdesc->rate / 5; /* set to 802.11 units */
+  
+	  msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx;
+	  msg->istx.status = 0;
+	  msg->istx.len = 4;
+	  msg->istx.data = P80211ENUM_truth_false;
+	  
+	  msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen;
+	  msg->frmlen.status = 0;
+	  msg->frmlen.len = 4;
+	  msg->frmlen.data = hdrlen + datalen;
+	}	  
+
+	/* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */
+	memcpy( datap, &(hdr->frame_ctl), hdrlen);
+
+	/* If any, copy the data from the card to the skb */
+	if ( datalen > 0 )
+	{
+		hermes_bap_pread(hw, IRQ_BAP, datap + hdrlen, (datalen+1)&~1,
+				       rxfid, HERMES_RX_DATA_OFF);
+
+		/* check for unencrypted stuff if WEP bit set. */
+		if (*(datap+1) & 0x40) // wep set
+		  if ((*(datap+hdrlen) == 0xaa) && (*(datap+hdrlen+1) == 0xaa))
+		    *(datap+1) &= 0xbf; // clear wep; it's the 802.2 header!
+	}
+
+       /* pass it up via the PF_PACKET interface */
+       {
+	   skb->dev = dev->ndev;
+	   skb->dev->last_rx = jiffies;
+
+	   skb->mac.raw = skb->data ;
+	   skb->ip_summed = CHECKSUM_NONE;
+	   skb->pkt_type = PACKET_OTHERHOST;
+	   skb->protocol = htons(ETH_P_80211_RAW);  /* XXX ETH_P_802_2? */
+
+	   stats->rx_packets++;
+	   stats->rx_bytes += skb->len;
+
+	   netif_rx(skb);
+       }
+
+	return;
+}
+
 /********************************************************************/
 /* Module initialization                                            */
 /********************************************************************/
@@ -4187,6 +4608,7 @@
 static int __init init_orinoco(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
+	suppress_linkstatus_copy = suppress_linkstatus;
 	return 0;
 }
 
diff -Naur linux-2.6.2/drivers/net/wireless/orinoco.h linux-2.6.2-orinoco/drivers/net/wireless/orinoco.h
--- linux-2.6.2/drivers/net/wireless/orinoco.h	2003-12-18 10:58:39.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco.h	2004-02-17 15:26:40.000000000 +0800
@@ -37,6 +37,20 @@
 /* To enable debug messages */
 //#define ORINOCO_DEBUG		3
 
+#ifndef ETH_P_ECONET
+#define ETH_P_ECONET   0x0018    /* needed for 2.2.x kernels */
+#endif
+
+#define ETH_P_80211_RAW        (ETH_P_ECONET + 1)
+
+#ifndef ARPHRD_IEEE80211
+#define ARPHRD_IEEE80211 801     /* kernel 2.4.6 */
+#endif
+
+#ifndef ARPHRD_IEEE80211_PRISM  /* kernel 2.4.18 */
+#define ARPHRD_IEEE80211_PRISM 802
+#endif
+
 #if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10)
 #error "orinoco driver requires Wireless extensions v10 or later."
 #endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */
@@ -54,6 +68,158 @@
 				HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \
 				HERMES_EV_INFDROP )
 
+#define WLAN_DEVNAMELEN_MAX 16
+
+/* message data item for INT, BOUNDEDINT, ENUMINT */
+typedef struct p80211item_uint32
+{
+	uint32_t		did		__attribute__ ((packed));
+	uint16_t		status	__attribute__ ((packed));
+	uint16_t		len		__attribute__ ((packed));
+	uint32_t		data	__attribute__ ((packed));
+} __attribute__ ((packed)) p80211item_uint32_t;
+
+typedef struct p80211msg
+{
+	uint32_t	msgcode		__attribute__ ((packed));
+	uint32_t	msglen		__attribute__ ((packed));
+	uint8_t	devname[WLAN_DEVNAMELEN_MAX]	__attribute__ ((packed));
+} __attribute__ ((packed)) p80211msg_t;
+
+#define DIDmsg_lnxind_wlansniffrm 0x0041
+#define DIDmsg_lnxind_wlansniffrm_hosttime 0x1041
+#define DIDmsg_lnxind_wlansniffrm_mactime 0x2041
+#define DIDmsg_lnxind_wlansniffrm_channel 0x3041
+#define DIDmsg_lnxind_wlansniffrm_rssi 0x4041
+#define DIDmsg_lnxind_wlansniffrm_sq 0x5041
+#define DIDmsg_lnxind_wlansniffrm_signal 0x6041
+#define DIDmsg_lnxind_wlansniffrm_noise 0x7041
+#define DIDmsg_lnxind_wlansniffrm_rate 0x8041
+#define DIDmsg_lnxind_wlansniffrm_istx 0x9041
+#define DIDmsg_lnxind_wlansniffrm_frmlen 0xA041
+
+typedef struct p80211msg_lnxind_wlansniffrm
+{
+	uint32_t		msgcode;
+	uint32_t		msglen;
+	uint8_t		    devname[WLAN_DEVNAMELEN_MAX];
+	p80211item_uint32_t	hosttime;
+	p80211item_uint32_t	mactime;
+	p80211item_uint32_t	channel;
+	p80211item_uint32_t	rssi;
+	p80211item_uint32_t	sq;
+	p80211item_uint32_t	signal;
+	p80211item_uint32_t	noise;
+	p80211item_uint32_t	rate;
+	p80211item_uint32_t	istx;
+	p80211item_uint32_t	frmlen;
+} __attribute__ ((packed)) p80211msg_lnxind_wlansniffrm_t;
+
+#define P80211ENUM_truth_false			0
+#define P80211ENUM_truth_true			1
+#define P80211ENUM_resultcode_success		1
+#define P80211ENUM_resultcode_invalid_parameters	2
+#define P80211ENUM_resultcode_not_supported	3
+#define P80211ENUM_resultcode_timeout		4
+#define P80211ENUM_resultcode_too_many_req	5
+#define P80211ENUM_resultcode_refused		6
+#define P80211ENUM_resultcode_bss_already	7
+#define P80211ENUM_resultcode_invalid_access	8
+#define P80211ENUM_resultcode_invalid_mibattribute	9
+#define P80211ENUM_resultcode_cant_set_readonly_mib	10
+#define P80211ENUM_resultcode_implementation_failure	11
+#define P80211ENUM_resultcode_cant_get_writeonly_mib	12
+#define P80211ENUM_msgitem_status_data_ok		0
+#define P80211ENUM_msgitem_status_no_value		1
+#define P80211ENUM_msgitem_status_invalid_itemname	2
+#define P80211ENUM_msgitem_status_invalid_itemdata	3
+#define P80211ENUM_msgitem_status_missing_itemdata	4
+#define P80211ENUM_msgitem_status_incomplete_itemdata	5
+#define P80211ENUM_msgitem_status_invalid_msg_did	6
+#define P80211ENUM_msgitem_status_invalid_mib_did	7
+#define P80211ENUM_msgitem_status_missing_conv_func	8
+#define P80211ENUM_msgitem_status_string_too_long	9
+#define P80211ENUM_msgitem_status_data_out_of_range	10
+#define P80211ENUM_msgitem_status_string_too_short	11
+#define P80211ENUM_msgitem_status_missing_valid_func	12
+#define P80211ENUM_msgitem_status_unknown		13
+#define P80211ENUM_msgitem_status_invalid_did		14
+#define P80211ENUM_msgitem_status_missing_print_func	15
+
+#define WLAN_GET_FC_FTYPE(n)	(((n) & 0x0C) >> 2)
+#define WLAN_GET_FC_FSTYPE(n)	(((n) & 0xF0) >> 4)
+#define WLAN_GET_FC_TODS(n) 	(((n) & 0x0100) >> 8)
+#define WLAN_GET_FC_FROMDS(n)	(((n) & 0x0200) >> 9)
+
+/*--- Sizes -----------------------------------------------*/
+#define WLAN_ADDR_LEN			6
+#define WLAN_CRC_LEN			4
+#define WLAN_BSSID_LEN			6
+#define WLAN_BSS_TS_LEN			8
+#define WLAN_HDR_A3_LEN			24
+#define WLAN_HDR_A4_LEN			30
+#define WLAN_SSID_MAXLEN		32
+#define WLAN_DATA_MAXLEN		2312
+
+/*--- Frame Control Field -------------------------------------*/
+/* Frame Types */
+#define WLAN_FTYPE_MGMT			0x00
+#define WLAN_FTYPE_CTL			0x01
+#define WLAN_FTYPE_DATA			0x02
+
+/* Frame subtypes */
+/* Management */
+#define WLAN_FSTYPE_ASSOCREQ		0x00
+#define WLAN_FSTYPE_ASSOCRESP		0x01
+#define WLAN_FSTYPE_REASSOCREQ		0x02
+#define WLAN_FSTYPE_REASSOCRESP		0x03
+#define WLAN_FSTYPE_PROBEREQ		0x04 
+#define WLAN_FSTYPE_PROBERESP		0x05
+#define WLAN_FSTYPE_BEACON		0x08
+#define WLAN_FSTYPE_ATIM		0x09
+#define WLAN_FSTYPE_DISASSOC		0x0a
+#define WLAN_FSTYPE_AUTHEN		0x0b
+#define WLAN_FSTYPE_DEAUTHEN		0x0c
+
+/* Control */
+#define WLAN_FSTYPE_PSPOLL		0x0a
+#define WLAN_FSTYPE_RTS			0x0b
+#define WLAN_FSTYPE_CTS			0x0c
+#define WLAN_FSTYPE_ACK			0x0d
+#define WLAN_FSTYPE_CFEND		0x0e
+#define WLAN_FSTYPE_CFENDCFACK		0x0f
+
+/* Data */
+#define WLAN_FSTYPE_DATAONLY		0x00
+#define WLAN_FSTYPE_DATA_CFACK		0x01
+#define WLAN_FSTYPE_DATA_CFPOLL		0x02
+#define WLAN_FSTYPE_DATA_CFACK_CFPOLL	0x03
+#define WLAN_FSTYPE_NULL		0x04
+#define WLAN_FSTYPE_CFACK		0x05
+#define WLAN_FSTYPE_CFPOLL		0x06
+#define WLAN_FSTYPE_CFACK_CFPOLL	0x07
+
+/*----------------------------------------------------------------*/
+/* Magic number, a quick test to see we're getting the desired struct */
+
+#define P80211_IOCTL_MAGIC	(0x4a2d464dUL)
+
+/*================================================================*/
+/* Types */
+
+/*----------------------------------------------------------------*/
+/* A ptr to the following structure type is passed as the third */
+/*  argument to the ioctl system call when issuing a request to */
+/*  the p80211 module. */
+
+typedef struct p80211ioctl_req
+{
+	char 	name[WLAN_DEVNAMELEN_MAX] __attribute__ ((packed));
+	void	*data 		__attribute__ ((packed));
+	uint32_t	magic 	__attribute__ ((packed));
+	uint16_t	len 	__attribute__ ((packed));
+	uint32_t	result 	__attribute__ ((packed));
+} __attribute__ ((packed)) p80211ioctl_req_t;
 
 struct orinoco_private {
 	void *card;	/* Pointer to card dependent structure */
@@ -116,6 +282,9 @@
 	/* Configuration dependent variables */
 	int port_type, createibss;
 	int promiscuous, mc_count;
+
+	uint16_t		presniff_port_type;
+	uint16_t		presniff_wepflags;
 };
 
 #ifdef ORINOCO_DEBUG
@@ -163,4 +332,12 @@
 	spin_unlock_irqrestore(&priv->lock, *flags);
 }
 
+/*================================================================*/
+/* Function Declarations */
+
+struct ieee802_11_hdr;
+
+void orinoco_int_rxmonitor( struct orinoco_private *dev, uint16_t rxfid, int len,
+                            struct hermes_rx_descriptor *rxdesc, struct ieee802_11_hdr *hdr);
+
 #endif /* _ORINOCO_H */
diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_cs.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_cs.c
--- linux-2.6.2/drivers/net/wireless/orinoco_cs.c	2004-02-17 15:14:27.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_cs.c	2004-02-17 15:26:40.000000000 +0800
@@ -110,7 +110,7 @@
 
 /* PCMCIA gumpf */
 static void orinoco_cs_config(dev_link_t * link);
-static void orinoco_cs_release(dev_link_t * link);
+static void orinoco_cs_release(u_long arg);
 static int orinoco_cs_event(event_t event, int priority,
 			    event_callback_args_t * args);
 
@@ -153,6 +153,24 @@
 	pcmcia_report_error(handle, &err);
 }
 
+
+/* Remove zombie instances (card removed, detach pending) */
+static void
+flush_stale_links(void)
+{
+	dev_link_t *link, *next;
+
+	TRACE_ENTER("");
+
+	for (link = dev_list; link; link = next) {
+		next = link->next;
+		if (link->state & DEV_STALE_LINK) {
+			orinoco_cs_detach(link);
+		}
+	}
+	TRACE_EXIT("");
+}
+
 /*
  * This creates an "instance" of the driver, allocating local data
  * structures for one device.  The device is registered with Card
@@ -171,6 +189,9 @@
 	client_reg_t client_reg;
 	int ret, i;
 
+	/* A bit of cleanup */
+	flush_stale_links();
+
 	dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset);
 	if (! dev)
 		return NULL;
@@ -181,6 +202,12 @@
 	link = &card->link;
 	link->priv = dev;
 
+	/* Initialize the dev_link_t structure */
+	/*init_timer(&link->release);
+	link->release.function = &orinoco_cs_release;
+	link->release.data = (u_long) link;
+	removed by Adrian 6-2-04 */
+
 	/* Interrupt setup */
 	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
@@ -245,8 +272,13 @@
 		return;
 	}
 
-	if (link->state & DEV_CONFIG)
-		orinoco_cs_release(link);
+	if (link->state & DEV_CONFIG) {
+		orinoco_cs_release((u_long)link);
+		if (link->state & DEV_CONFIG) {
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
+	}
 
 	/* Break the link with Card Services */
 	if (link->handle)
@@ -260,7 +292,7 @@
 		      dev);
 		unregister_netdev(dev);
 	}
-	free_netdev(dev);
+	kfree(dev);
 }				/* orinoco_cs_detach */
 
 /*
@@ -498,7 +530,7 @@
 	orinoco_cs_error(link->handle, last_fn, last_ret);
 
  failed:
-	orinoco_cs_release(link);
+	orinoco_cs_release((u_long) link);
 }				/* orinoco_cs_config */
 
 /*
@@ -507,8 +539,9 @@
  * still open, this will be postponed until it is closed.
  */
 static void
-orinoco_cs_release(dev_link_t *link)
+orinoco_cs_release(u_long arg)
 {
+	dev_link_t *link = (dev_link_t *) arg;
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = dev->priv;
 	unsigned long flags;
diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_pci.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_pci.c
--- linux-2.6.2/drivers/net/wireless/orinoco_pci.c	2004-02-17 15:14:27.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_pci.c	2004-02-17 15:26:40.000000000 +0800
@@ -223,7 +223,7 @@
 
 	printk(KERN_DEBUG
 	       "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n",
-	       pci_name(pdev), dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq);
+	       pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq);
 
 	hermes_struct_init(&priv->hw, dev->base_addr,
 			   HERMES_MEM, HERMES_32BIT_REGSPACING);
@@ -289,7 +289,7 @@
 		iounmap((unsigned char *) priv->hw.iobase);
 
 	pci_set_drvdata(pdev, NULL);
-	free_netdev(dev);
+	kfree(dev);
 
 	pci_disable_device(pdev);
 }
@@ -359,8 +359,7 @@
 	return 0;
 }
 
-static struct pci_device_id orinoco_pci_pci_id_table[] = {
-	{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
+static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = {
 	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
 	{0,},
 };
diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_plx.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_plx.c
--- linux-2.6.2/drivers/net/wireless/orinoco_plx.c	2003-12-18 10:59:45.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_plx.c	2004-02-17 15:26:40.000000000 +0800
@@ -236,7 +236,7 @@
 
 	printk(KERN_DEBUG
 	       "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n",
-	       pci_name(pdev), pdev->irq, pccard_ioaddr);
+	       pdev->slot_name, pdev->irq, pccard_ioaddr);
 
 	hermes_struct_init(&(priv->hw), dev->base_addr,
 			HERMES_IO, HERMES_16BIT_REGSPACING);
@@ -291,7 +291,7 @@
 		
 	pci_set_drvdata(pdev, NULL);
 
-	free_netdev(dev);
+	kfree(dev);
 
 	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
 
@@ -299,7 +299,7 @@
 }
 
 
-static struct pci_device_id orinoco_plx_pci_id_table[] = {
+static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
 	{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},	/* Siemens SpeedStream SS1023 */
 	{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},	/* Netgear MA301 */
 	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga  - does this work? */
diff -Naur linux-2.6.2/drivers/net/wireless/orinoco_tmd.c linux-2.6.2-orinoco/drivers/net/wireless/orinoco_tmd.c
--- linux-2.6.2/drivers/net/wireless/orinoco_tmd.c	2003-12-18 10:58:16.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/orinoco_tmd.c	2004-02-17 15:26:40.000000000 +0800
@@ -128,7 +128,7 @@
 
 	printk(KERN_DEBUG
 	       "Detected Orinoco/Prism2 TMD device at %s irq:%d, io addr:0x%lx\n",
-	       pci_name(pdev), pdev->irq, pccard_ioaddr);
+	       pdev->slot_name, pdev->irq, pccard_ioaddr);
 
 	hermes_struct_init(&(priv->hw), dev->base_addr,
 			HERMES_IO, HERMES_16BIT_REGSPACING);
@@ -182,7 +182,7 @@
 		
 	pci_set_drvdata(pdev, NULL);
 
-	free_netdev(dev);
+	kfree(dev);
 
 	release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
 
@@ -190,7 +190,7 @@
 }
 
 
-static struct pci_device_id orinoco_tmd_pci_id_table[] = {
+static struct pci_device_id orinoco_tmd_pci_id_table[] __devinitdata = {
 	{0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,},      /* NDC and OEMs, e.g. pheecom */
 	{0,},
 };
diff -Naur linux-2.6.2/drivers/net/wireless/userhermes.c linux-2.6.2-orinoco/drivers/net/wireless/userhermes.c
--- linux-2.6.2/drivers/net/wireless/userhermes.c	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.2-orinoco/drivers/net/wireless/userhermes.c	2004-02-17 15:26:40.000000000 +0800
@@ -0,0 +1,477 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/io.h>
+#include <errno.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <linux/types.h>
+
+typedef __u8 u8;
+typedef __u16 u16;
+typedef __u32 u32;
+
+#include "hermes.h"
+
+#define BAP_BUSY_TIMEOUT (50)
+#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
+#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
+
+#define fatal(s) do { perror(s); exit(1); } while (0)
+
+typedef struct record_info {
+	u16 rid;
+	u16 len;
+	char *name;
+} record_info_t;
+
+record_info_t rid_table[] = {
+	{0xfc00,  2, "CNFPORTTYPE"},
+	{0xfc01,  6, "CNFOWNMACADDR"},
+	{0xfc02, 34, "CNFDESIREDSSID"},
+	{0xfc03,  2, "CNFOWNCHANNEL"},
+	{0xfc04, 34, "CNFOWNSSID"},
+	{0xfc05,  2, "CNFOWNATIMWIN"},
+	{0xfc06,  0, "CNFSYSSCALE"},
+	{0xfc07,  0, "CNFMAXDATALEN"},
+	{0xfc08,  0, "CNFWDSADDR"},
+	{0xfc09,  0, "CNFPMENABLED"},
+	{0xfc0a,  0, "CNFPMEPS"},
+	{0xfc0b,  0, "CNFMULTICASTRX"},
+	{0xfc0c,  0, "CNFMAXSLEEPDUR"},
+	{0xfc0d,  0, "CNFCNFPMHOLDDUR"},
+	{0xfc0e,  0, "CNFOWNNAME"},
+	{0xfc10,  0, "CNFOWNDTIMPER"},
+	{0xfc11,  0, "CNFWDSADDR1"},
+	{0xfc12,  0, "CNFWDSADDR2"},
+	{0xfc13,  0, "CNFWDSADDR3"},
+	{0xfc14,  0, "CNFWDSADDR4"},
+	{0xfc15,  0, "CNFWDSADDR5"},
+	{0xfc16,  0, "CNFWDSADDR6"},
+	{0xfc17,  0, "CNFMCASTPMBUFF"},
+	{0xfcb0,  0, "CNFSHORTPREAMBLE"}
+};
+
+#define NUM_RIDS (sizeof(rid_table) / sizeof(record_info_t))
+
+typedef struct record {
+	u16 len;
+	u16 type;
+	u16 value[4096];
+} record_t;
+
+
+/* Set up a BAP to read a particular chunk of data from card's internal buffer.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, >0 on error from firmware 
+ *
+ * Callable from any context */
+static int hermes_bap_seek(ulong hw, int bap, u16 id, u16 offset)
+{
+	int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
+	int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
+	int k;
+	u16 reg;
+
+	/* Paranoia.. */
+	if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
+		return -EINVAL;
+
+	/* Now we actually set up the transfer */
+	hermes_write_reg(hw, sreg, id);
+	hermes_write_reg(hw, oreg, offset);
+	/* Wait for the BAP to be ready */
+	k = BAP_BUSY_TIMEOUT;
+	reg = hermes_read_reg(hw, oreg);
+	while ( (reg & HERMES_OFFSET_BUSY) && k) {
+		k--;
+		reg = hermes_read_reg(hw, oreg);
+	}
+
+	if (reg & HERMES_OFFSET_BUSY)
+		return -ETIMEDOUT;
+	if (reg & HERMES_OFFSET_ERR)
+		return reg;
+
+	return 0;
+}
+
+/* Read a block of data from the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem.  len
+ * must be even.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ *
+ * Callable from any context */
+int hermes_bap_pread(ulong hw, int bap, char *buf, u16 len,
+		      u16 id, u16 offset)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err;
+
+	err = hermes_bap_seek(hw, bap, id, offset);
+	if (err)
+		return err;
+
+	/* Actually do the transfer */
+	hermes_read_data(hw, dreg, buf, len/2);
+
+	return 0;
+}
+
+/* Write a block of data to the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem. len
+ * must be even.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ *
+ * Callable from any context */
+int hermes_bap_pwrite(ulong hw, int bap, const char *buf, u16 len,
+		       u16 id, u16 offset)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err;
+
+	if (len % 2)
+		return -EINVAL;
+
+	err = hermes_bap_seek(hw, bap, id, offset);
+	if (err)
+		return err;
+
+	/* Actually do the transfer */
+	hermes_write_data(hw, dreg, buf, len/2);
+
+	return 0;
+}
+
+void usage(void)
+{
+	fprintf(stderr, "Usage: userprism <base io> [showrecords]\n");
+	exit(1);
+}
+
+char *
+rl_gets (void)
+{
+	char * line;
+
+	/* Get a line from the user. */
+	line = readline ("> ");
+	
+	/* If the line has any text in it, save it on the history. */
+	if (line && *line)
+		add_history (line);
+	
+	return (line);
+}
+
+void display(unsigned long base)
+{
+#define DREG(name) printf("%-16s: %04x\n", #name, inw(base + HERMES_##name))
+	DREG(CMD);
+	DREG(PARAM0);
+	DREG(PARAM1);
+	DREG(PARAM2);
+	DREG(STATUS);
+	DREG(RESP0);
+	DREG(RESP1);
+	DREG(RESP2);
+	DREG(INFOFID);
+	DREG(RXFID);
+	DREG(ALLOCFID);
+	DREG(TXCOMPLFID);
+	DREG(SELECT0);
+	DREG(OFFSET0);
+	DREG(SELECT1);
+	DREG(OFFSET1);
+
+	DREG(EVSTAT);
+	DREG(INTEN);
+	DREG(EVACK);
+	DREG(CONTROL);
+	DREG(SWSUPPORT0);
+	DREG(SWSUPPORT1);
+	DREG(SWSUPPORT2);
+	DREG(AUXPAGE);
+	DREG(AUXOFFSET);
+	DREG(AUXDATA);
+#undef DREG
+}
+
+#undef udelay
+void udelay(ulong usec) {
+	struct timespec ts;
+
+	ts.tv_sec = 0;
+	ts.tv_nsec = 1000 * usec;
+	nanosleep(&ts, NULL);
+}
+
+static int hermes_issue_cmd(ulong base, u16 cmd, u16 param0)
+{
+	int k = CMD_BUSY_TIMEOUT;
+	u16 reg;
+
+	/* First wait for the command register to unbusy */
+	reg = hermes_read_regn(base, CMD);
+	while ( (reg & HERMES_CMD_BUSY) && k ) {
+		k--;
+		udelay(1);
+		reg = hermes_read_regn(base, CMD);
+	}
+	if (reg & HERMES_CMD_BUSY) {
+		return -EBUSY;
+	}
+
+	hermes_write_regn(base, PARAM2, 0);
+	hermes_write_regn(base, PARAM1, 0);
+	hermes_write_regn(base, PARAM0, param0);
+	hermes_write_regn(base, CMD, cmd);
+	
+	return 0;
+}
+
+int hermes_docmd_wait(ulong base, u16 cmd, u16 parm0)
+{
+	int err;
+	int k;
+	u16 reg;
+	u16 status;
+
+	err = hermes_issue_cmd(base, cmd, parm0);
+	if (err) {
+		return -EIO;
+	}
+
+	reg = hermes_read_regn(base, EVSTAT);
+	k = CMD_COMPL_TIMEOUT;
+	while ( (! (reg & HERMES_EV_CMD)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(base, EVSTAT);
+	}
+
+	if (! (reg & HERMES_EV_CMD)) {
+		return -ETIMEDOUT;
+	}
+
+	status = hermes_read_regn(base, STATUS);
+
+	hermes_write_regn(base, EVACK, HERMES_EV_CMD);
+
+	if (status & HERMES_STATUS_RESULT)
+		return -EIO;
+
+	return 0;
+}
+
+int read_lt(ulong base, int bap, u16 rid, record_t *rec)
+{
+	int err;
+
+	err = hermes_docmd_wait(base, HERMES_CMD_ACCESS, rid);
+	if (err) {
+		fprintf(stderr, "Cannot access RID 0x%04x\n", rid);
+		return err;
+	}
+
+	err = hermes_bap_pread(base, bap, (char *)rec, 4, rid, 0);
+	if (err) {
+		fprintf(stderr, "Error %d reading type/length\n", err);
+		return err;
+	}
+
+	if (rid != rec->type) {
+		fprintf(stderr, "RID (0x%04x) doesn't match rec->type (0x%04x)\n",
+			rid, rec->type);
+		return -1;
+	}
+
+	if (rec->len <= 1) {
+		fprintf(stderr, "Record too short, rec->len = %d\n", rec->len);
+		return err;
+	}
+
+	/* Convert length to bytes */
+	rec->len = 2 * (rec->len - 1);
+
+	err = hermes_bap_pread(base, bap, (char *)&rec->value, rec->len, rid, 4);
+	if (err) {
+		fprintf(stderr, "Error %d reading value (%d bytes)\n", err, rec->len);
+		return err;
+	}
+
+	return 0;
+}
+
+void
+show_records(unsigned long base)
+{
+	int i, j;
+	record_t rec;
+
+	printf("%d records total.\n", NUM_RIDS);
+	for (i = 0; i < NUM_RIDS; i++) {
+		record_info_t *info = &rid_table[i];
+		printf("Record %s [0x%04x]:", info->name, info->rid);
+		if (info->len)
+			printf(" expected length %04d\n", info->len);
+		else
+			printf("\n");
+
+		if (read_lt(base, 1, info->rid, &rec) != 0)
+			continue;
+		printf("Type 0x%04x, Len %04d: ", rec.type, rec.len);
+		for (j = 0; j < rec.len / 2; j++)
+			printf("%04x:", rec.value[j]);
+		printf("\n");
+	}
+}
+
+void
+show_record(unsigned long base, u16 rid)
+{
+	record_t rec;
+	int j;
+
+	if (read_lt(base, 1, rid, &rec) != 0)
+		return;
+	printf("RID 0x%04x: ", rid);
+	printf("type=0x%04x len=%04d value=", rec.type, rec.len);
+	for (j = 0; j < rec.len / 2; j++)
+		printf("%04x:", rec.value[j]);
+	printf("\n");
+}
+
+void do_line(unsigned long base, const char *line)
+{
+	char reg[100];
+	int off;
+	int val;
+	int n;
+
+	n = sscanf(line, "%s %i\n", reg, &val);
+	if (n < 1 || n > 2) {
+		fprintf(stderr, "?\n");
+		return;
+	}
+
+	if (strcasecmp(reg, "CMD") == 0) {
+		off = HERMES_CMD;
+	} else if (strcasecmp(reg, "PARAM0") == 0) {
+		off = HERMES_PARAM0;
+	} else if (strcasecmp(reg, "PARAM1") == 0) {
+		off = HERMES_PARAM1;
+	} else if (strcasecmp(reg, "PARAM2") == 0) {
+		off = HERMES_PARAM2;
+	} else if (strcasecmp(reg, "STATUS") == 0) {
+		off = HERMES_STATUS;
+	} else if (strcasecmp(reg, "RESP0") == 0) {
+		off = HERMES_RESP0;
+	} else if (strcasecmp(reg, "RESP1") == 0) {
+		off = HERMES_RESP1;
+	} else if (strcasecmp(reg, "RESP2") == 0) {
+		off = HERMES_RESP2;
+	} else if (strcasecmp(reg, "INFOFID") == 0) {
+		off = HERMES_INFOFID;
+	} else if (strcasecmp(reg, "RXFID") == 0) {
+		off = HERMES_RXFID;
+	} else if (strcasecmp(reg, "ALLOCFID") == 0) {
+		off = HERMES_ALLOCFID;
+	} else if (strcasecmp(reg, "TXCOMPLFID") == 0) {
+		off = HERMES_TXCOMPLFID;
+	} else if (strcasecmp(reg, "SELECT0") == 0) {
+		off = HERMES_SELECT0;
+	} else if (strcasecmp(reg, "OFFSET0") == 0) {
+		off = HERMES_OFFSET0;
+	} else if (strcasecmp(reg, "DATA0") == 0) {
+		off = HERMES_DATA0;
+	} else if (strcasecmp(reg, "SELECT1") == 0) {
+		off = HERMES_SELECT1;
+	} else if (strcasecmp(reg, "OFFSET1") == 0) {
+		off = HERMES_OFFSET1;
+	} else if (strcasecmp(reg, "DATA1") == 0) {
+		off = HERMES_DATA1;
+	} else if (strcasecmp(reg, "EVSTAT") == 0) {
+		off = HERMES_EVSTAT;
+	} else if (strcasecmp(reg, "INTEN") == 0) {
+		off = HERMES_INTEN;
+	} else if (strcasecmp(reg, "EVACK") == 0) {
+		off = HERMES_EVACK;
+	} else if (strcasecmp(reg, "CONTROL") == 0) {
+		off = HERMES_CONTROL;
+	} else if (strcasecmp(reg, "SWSUPPORT0") == 0) {
+		off = HERMES_SWSUPPORT0;
+	} else if (strcasecmp(reg, "SWSUPPORT1") == 0) {
+		off = HERMES_SWSUPPORT1;
+	} else if (strcasecmp(reg, "SWSUPPORT2") == 0) {
+		off = HERMES_SWSUPPORT2;
+	} else if (strcasecmp(reg, "AUXPAGE") == 0) {
+		off = HERMES_AUXPAGE;
+	} else if (strcasecmp(reg, "AUXOFFSET") == 0) {
+		off = HERMES_AUXOFFSET;
+	} else if (strcasecmp(reg, "AUXDATA") == 0) {
+		off = HERMES_AUXDATA;
+	} else if (strcasecmp(reg, ".") == 0) {
+		display(base);
+		return;
+	} else if (strcasecmp(reg, ",") == 0) {
+		if (n != 2) {
+			fprintf(stderr, "? No FID given\n");
+			return;
+		}
+		show_record(base, val);
+		return;
+	} else {
+		fprintf(stderr, "? Unknown register \"%s\"\n", reg);
+		return;
+	}
+
+	if (n == 2) {
+		printf("0x%04x -> 0x%04x\n", val, (int)base+off);
+		outw(val, base+off);
+	}
+	printf("%s (0x%04x) = 0x%04x\n", reg, off, inw(base+off));
+}
+
+int
+main(int argc, char *argv[])
+{
+	char *e;
+	unsigned long base;
+	int err;
+	char * line;
+	
+	if (argc < 2)
+		usage();
+
+	base = strtol(argv[1], &e, 0);
+	if (*e)
+		usage();
+
+	err = ioperm(base, 0x40, 1);
+	if (err != 0)
+		fatal("ioperm");
+
+	if (argc > 2) {
+		show_records(base);
+		exit(0);
+	}
+		
+
+	while (1) {
+		line = rl_gets();
+		
+		if (! line)
+			break;
+
+		do_line(base, line);
+
+		free(line);
+	};
+	
+
+	exit(0);
+}

