netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHES] wireless: Update in-kernel orinoco driver
@ 2004-10-26 18:12 Dan Williams
  2004-10-26 18:33 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s Dan Williams
                   ` (16 more replies)
  0 siblings, 17 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:12 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

This series of 15 patches updates the in-kernel orinoco wireless drivers
to the level of current upstream orinoco CVS (from sourceforge).  This
level is "0.15rc2HEAD" as found in orinoco.h.

The basis for this patchset was:

upstream orinoco CVS from Mon, Oct 25
kernel sources from linux-2.6.9.tar.bz2 + patch-2.6.10-rc1.bz2

This is a revival of an effort to get the drivers up-to-date from
earlier this year in July.

Dan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
@ 2004-10-26 18:33 ` Dan Williams
  2004-10-26 18:47   ` Christoph Hellwig
  2004-10-26 19:34   ` Jeff Garzik
  2004-10-26 18:38 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: use msleep() Dan Williams
                   ` (15 subsequent siblings)
  16 siblings, 2 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:33 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Use msleep() instead of hardcoded schedule_timeout()s
  (Nishanth Aravamudan via kernel-janitors list).

--- a/drivers/net/wireless/airport.c.1-msleep	2004-10-25 14:44:04.559958488 -0400
+++ b/drivers/net/wireless/airport.c	2004-10-25 14:44:51.372841848 -0400
@@ -28,7 +28,6 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -147,7 +146,7 @@
 	macio_release_resource(mdev, 0);
 
 	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
-	ssleep(1);
+	msleep(1000);
 
 	macio_set_drvdata(mdev, NULL);
 	free_netdev(dev);
@@ -173,12 +172,12 @@
 	disable_irq(dev->irq);
 
 	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
-	ssleep(1);
+	msleep(1000);
 	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
-	ssleep(1);
+	msleep(1000);
 
 	enable_irq(dev->irq);
-	ssleep(1);
+	msleep(1000);
 #endif
 
 	return 0;
@@ -237,7 +236,7 @@
 		
 	/* Power up card */
 	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
-	ssleep(1);
+	msleep(1000);
 
 	/* Reset it before we get the interrupt */
 	hermes_init(hw);
--- a/drivers/net/wireless/orinoco_cs.c.1-msleep	2004-10-25 14:44:04.558958640 -0400
+++ b/drivers/net/wireless/orinoco_cs.c	2004-10-25 14:44:51.374841544 -0400
@@ -136,6 +136,7 @@
 	if (err)
 		return err;
 
+	msleep(100);
 	clear_bit(0, &card->hard_reset_in_progress);
 
 	return 0;
--- a/drivers/net/wireless/orinoco_plx.c.1-msleep	2004-10-25 14:44:04.559958488 -0400
+++ b/drivers/net/wireless/orinoco_plx.c	2004-10-25 14:44:51.376841240 -0400
@@ -352,8 +352,7 @@
 static void __exit orinoco_plx_exit(void)
 {
 	pci_unregister_driver(&orinoco_plx_driver);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout(HZ);
+	msleep(1000);
 }
 
 module_init(orinoco_plx_init);
--- a/drivers/net/wireless/orinoco_tmd.c.1-msleep	2004-10-25 14:44:04.557958792 -0400
+++ b/drivers/net/wireless/orinoco_tmd.c	2004-10-25 14:44:51.377841088 -0400
@@ -218,8 +218,7 @@
 static void __exit orinoco_tmd_exit(void)
 {
 	pci_unregister_driver(&orinoco_tmd_driver);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout(HZ);
+	msleep(1000);
 }
 
 module_init(orinoco_tmd_init);

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 1/15] wireless/orinoco: use msleep()...
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
  2004-10-26 18:33 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s Dan Williams
@ 2004-10-26 18:38 ` Dan Williams
  2004-10-26 18:39 ` [PATCH 2.6.10-rc1 2/15] wireless/orinoco: fix up printk text Dan Williams
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:38 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

This first patch should also have in the comments:

Signed-off-by: Dan Williams <dcbw@redhat.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 2/15] wireless/orinoco: fix up printk text
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
  2004-10-26 18:33 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s Dan Williams
  2004-10-26 18:38 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: use msleep() Dan Williams
@ 2004-10-26 18:39 ` Dan Williams
  2004-10-26 18:43 ` [PATCH 2.6.10-rc1 3/15] wireless/orinoco: encapsulate direct hardware operations Dan Williams
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:39 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Fix up printk text

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/airport.c.2-printk-fixes	2004-10-25 14:46:53.203320800 -0400
+++ b/drivers/net/wireless/airport.c	2004-10-25 14:53:19.929529480 -0400
@@ -193,14 +193,14 @@
 	hermes_t *hw;
 
 	if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
-		printk(KERN_ERR PFX "wrong interrupt/addresses in OF tree\n");
+		printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
 		return -ENODEV;
 	}
 
 	/* Allocate space for private device-specific data */
 	dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
 	if (! dev) {
-		printk(KERN_ERR PFX "can't allocate device datas\n");
+		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		return -ENODEV;
 	}
 	priv = netdev_priv(dev);
@@ -223,11 +223,11 @@
 	/* Setup interrupts & base address */
 	dev->irq = macio_irq(mdev, 0);
 	phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
-	printk(KERN_DEBUG PFX "Airport at physical address %lx\n", phys_addr);
+	printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
 	dev->base_addr = phys_addr;
 	card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
 	if (!card->vaddr) {
-		printk(PFX "ioremap() failed\n");
+		printk(KERN_ERR PFX "ioremap() failed\n");
 		goto failed;
 	}
 
@@ -241,7 +241,7 @@
 	/* Reset it before we get the interrupt */
 	hermes_init(hw);
 
-	if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) {
+	if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
 		printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
 		goto failed;
 	}
@@ -252,7 +252,7 @@
 		printk(KERN_ERR PFX "register_netdev() failed\n");
 		goto failed;
 	}
-	printk(KERN_DEBUG PFX "card registered for interface %s\n", dev->name);
+	printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
 	card->ndev_registered = 1;
 	return 0;
  failed:
--- a/drivers/net/wireless/hermes.c.2-printk-fixes	2004-10-25 14:54:36.425900264 -0400
+++ b/drivers/net/wireless/hermes.c	2004-10-25 14:59:05.506993720 -0400
@@ -235,13 +235,17 @@
 	err = hermes_issue_cmd(hw, cmd, parm0);
 	if (err) {
 		if (! hermes_present(hw)) {
-			printk(KERN_WARNING "hermes @ %s0x%lx: "
-			       "Card removed while issuing command.\n",
-			       IO_TYPE(hw), hw->iobase);
+			if (net_ratelimit())
+				printk(KERN_WARNING "hermes @ %s0x%lx: "
+				       "Card removed while issuing command "
+				       "0x%04x.\n", IO_TYPE(hw), hw->iobase,
+				       cmd);
 			err = -ENODEV;
 		} else 
-			printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.\n",
-			       IO_TYPE(hw), hw->iobase, err);
+			if (net_ratelimit())
+				printk(KERN_ERR "hermes @ %s0x%lx: "
+				       "Error %d issuing command 0x%04x.\n",
+				       IO_TYPE(hw), hw->iobase, err, cmd);
 		goto out;
 	}
 
@@ -254,17 +258,17 @@
 	}
 
 	if (! hermes_present(hw)) {
-		printk(KERN_WARNING "hermes @ %s0x%lx: "
-		       "Card removed while waiting for command completion.\n",
-		       IO_TYPE(hw), hw->iobase);
+		printk(KERN_WARNING "hermes @ %s0x%lx: Card removed "
+		       "while waiting for command 0x%04x completion.\n",
+		       IO_TYPE(hw), hw->iobase, cmd);
 		err = -ENODEV;
 		goto out;
 	}
 		
 	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ %s0x%lx: "
-		       "Timeout waiting for command completion.\n",
-		       IO_TYPE(hw), hw->iobase);
+		printk(KERN_ERR "hermes @ %s0x%lx: Timeout waiting for "
+		       "command 0x%04x completion.\n", IO_TYPE(hw),
+		       hw->iobase, cmd);
 		err = -ETIMEDOUT;
 		goto out;
 	}
@@ -383,12 +387,18 @@
 		reg = hermes_read_reg(hw, oreg);
 	}
 
-	if (reg & HERMES_OFFSET_BUSY) {
-		return -ETIMEDOUT;
-	}
-
-	if (reg & HERMES_OFFSET_ERR) {
-		return -EIO;
+	if (reg != offset) {
+		printk(KERN_ERR "hermes @ %s0x%lx: BAP%d offset %s: "
+		       "reg=0x%x id=0x%x offset=0x%x\n", IO_TYPE(hw),
+		       hw->iobase, bap,
+		       (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
+		       reg, id, offset);
+
+		if (reg & HERMES_OFFSET_BUSY) {
+			return -ETIMEDOUT;
+		}
+ 
+		return -EIO;		/* error or wrong offset */
 	}
 
 	return 0;
@@ -484,9 +494,9 @@
 		*length = rlength;
 
 	if (rtype != rid)
-		printk(KERN_WARNING "hermes @ %s0x%lx: "
-		       "hermes_read_ltv(): rid  (0x%04x) does not match type (0x%04x)\n",
-		       IO_TYPE(hw), hw->iobase, rid, rtype);
+		printk(KERN_WARNING "hermes @ %s0x%lx: %s(): "
+		       "rid (0x%04x) does not match type (0x%04x)\n",
+		       IO_TYPE(hw), hw->iobase, __FUNCTION__, rid, rtype);
 	if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
 		printk(KERN_WARNING "hermes @ %s0x%lx: "
 		       "Truncating LTV record from %d to %d bytes. "
--- a/drivers/net/wireless/orinoco.c.2-printk-fixes	2004-10-25 15:00:16.087263888 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-25 15:09:14.310441528 -0400
@@ -807,8 +807,9 @@
  	desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX);
 	err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0);
 	if (err) {
-		printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n",
-		       dev->name, err);
+		if (net_ratelimit())
+			printk(KERN_ERR "%s: Error %d writing Tx descriptor "
+			       "to BAP\n", dev->name, err);
 		stats->tx_errors++;
 		goto fail;
 	}
@@ -838,8 +839,9 @@
 		err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
 					 txfid, HERMES_802_3_OFFSET);
 		if (err) {
-			printk(KERN_ERR "%s: Error %d writing packet header to BAP\n",
-			       dev->name, err);
+			if (net_ratelimit())
+				printk(KERN_ERR "%s: Error %d writing packet "
+				       "header to BAP\n", dev->name, err);
 			stats->tx_errors++;
 			goto fail;
 		}
@@ -1299,8 +1301,8 @@
 	}
 	break;
 	default:
-		printk(KERN_DEBUG "%s: Unknown information frame received "
-		       "(type %04x).\n", dev->name, type);
+		printk(KERN_DEBUG "%s: Unknown information frame received: "
+		       "type 0x%04x, length %d\n", dev->name, type, len);
 		/* We don't actually do anything about it */
 		break;
 	}
@@ -1309,7 +1311,7 @@
 static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 {
 	if (net_ratelimit())
-		printk(KERN_WARNING "%s: Information frame lost.\n", dev->name);
+		printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
 }
 
 /********************************************************************/
@@ -1787,7 +1789,8 @@
 		}
 		
 		if (p)
-			printk(KERN_WARNING "Multicast list is longer than mc_count\n");
+			printk(KERN_WARNING "%s: Multicast list is "
+			       "longer than mc_count\n", dev->name);
 
 		err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES,
 				       HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
@@ -2049,7 +2052,7 @@
 	/* Get the firmware version */
 	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
 	if (err) {
-		printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n",
+		printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
 		       dev->name, err);
 		memset(&sta_id, 0, sizeof(sta_id));
 	}
@@ -2058,7 +2061,7 @@
 	le16_to_cpus(&sta_id.variant);
 	le16_to_cpus(&sta_id.major);
 	le16_to_cpus(&sta_id.minor);
-	printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
+	printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
 	       dev->name, sta_id.id, sta_id.variant,
 	       sta_id.major, sta_id.minor);
 
@@ -3074,8 +3077,9 @@
 			priv->mwo_robust = 0;
 		else {
 			if (frq->fixed)
-				printk(KERN_WARNING "%s: Fixed fragmentation not \
-supported on this firmware. Using MWO robust instead.\n", dev->name);
+				printk(KERN_WARNING "%s: Fixed fragmentation is "
+				       "not supported on this firmware. "
+				       "Using MWO robust instead.\n", dev->name);
 			priv->mwo_robust = 1;
 		}
 	} else {
--- a/drivers/net/wireless/orinoco_cs.c.2-printk-fixes	2004-10-25 15:11:03.156894352 -0400
+++ b/drivers/net/wireless/orinoco_cs.c	2004-10-25 15:11:39.137424480 -0400
@@ -405,7 +405,7 @@
 		last_ret = pcmcia_get_next_tuple(handle, &tuple);
 		if (last_ret  == CS_NO_MORE_ITEMS) {
 			printk(KERN_ERR PFX "GetNextTuple(): No matching "
-			       "CIS configuration, maybe you need the "
+			       "CIS configuration.  Maybe you need the "
 			       "ignore_cis_vcc=1 parameter.\n");
 			goto cs_failed;
 		}
--- a/drivers/net/wireless/orinoco_pci.c.2-printk-fixes	2004-10-25 15:13:44.962296192 -0400
+++ b/drivers/net/wireless/orinoco_pci.c	2004-10-25 15:15:58.936928952 -0400
@@ -237,8 +237,7 @@
 	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
 			  dev->name, dev);
 	if (err) {
-		printk(KERN_ERR PFX "Error allocating IRQ %d.\n",
-		       pdev->irq);
+		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 		err = -EBUSY;
 		goto fail;
 	}
@@ -257,7 +256,7 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		printk(KERN_ERR "%s: Failed to register net device\n", dev->name);
+		printk(KERN_ERR PFX "Failed to register net device\n");
 		goto fail;
 	}
 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 3/15] wireless/orinoco: encapsulate direct hardware operations
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (2 preceding siblings ...)
  2004-10-26 18:39 ` [PATCH 2.6.10-rc1 2/15] wireless/orinoco: fix up printk text Dan Williams
@ 2004-10-26 18:43 ` Dan Williams
  2004-10-27  3:15   ` David Gibson
  2004-10-26 18:45 ` [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters Dan Williams
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:43 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Encapsulate direct hardware operations so those symbols
    don't need to be exported

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/hermes.c.3-direct-ops	2004-10-25 15:36:28.669981112 -0400
+++ b/drivers/net/wireless/hermes.c	2004-10-25 15:49:38.064974832 -0400
@@ -48,6 +48,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/net.h>
 #include <asm/errno.h>
 
 #include "hermes.h"
@@ -83,6 +84,32 @@
 
 #endif /* ! HERMES_DEBUG */
 
+static int hermes_init_direct(hermes_t *hw);
+static int hermes_docmd_wait_direct(hermes_t *hw, u16 cmd, u16 parm0,
+				    struct hermes_response *resp);
+static int hermes_allocate_direct(hermes_t *hw, u16 size, u16 *fid);
+static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset);
+static int hermes_bap_pread_direct(hermes_t *hw, int bap,
+				   void *buf, unsigned len,
+				   u16 id, u16 offset);
+static int hermes_bap_pwrite_direct(hermes_t *hw, int bap,
+				    const void *buf, unsigned len,
+				    u16 id, u16 offset);
+static int hermes_read_ltv_direct(hermes_t *hw, int bap, u16 rid,
+				  unsigned bufsize, u16 *length, void *buf);
+static int hermes_write_ltv_direct(hermes_t *hw, int bap, u16 rid, 
+				   u16 length, const void *value);
+
+static const struct hermes_ops hermes_ops_direct = {
+	.init = hermes_init_direct,
+	.docmd_wait = hermes_docmd_wait_direct,
+	.allocate = hermes_allocate_direct,
+	.read_ltv = hermes_read_ltv_direct,
+	.write_ltv = hermes_write_ltv_direct,
+	.bap_pread = hermes_bap_pread_direct,
+	.bap_pwrite = hermes_bap_pwrite_direct
+};
+
 
 /*
  * Internal functions
@@ -130,6 +157,7 @@
 	hw->io_space = io_space;
 	hw->reg_spacing = reg_spacing;
 	hw->inten = 0x0;
+	hw->ops = &hermes_ops_direct;
 
 #ifdef HERMES_DEBUG_BUFFER
 	hw->dbufp = 0;
@@ -138,7 +166,7 @@
 #endif
 }
 
-int hermes_init(hermes_t *hw)
+static int hermes_init_direct(hermes_t *hw)
 {
 	u16 status, reg;
 	int err = 0;
@@ -176,7 +204,7 @@
 	reg = hermes_read_regn(hw, EVSTAT);
 	hermes_write_regn(hw, EVACK, reg);
 
-	/* We don't use hermes_docmd_wait here, because the reset wipes
+	/* We don't use hermes_docmd_wait_direct here, because the reset wipes
 	   the magic constant in SWSUPPORT0 away, and it gets confused */
 	err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
 	if (err)
@@ -224,8 +252,8 @@
  * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
  *
  * Callable from any context, but locking is your problem. */
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-		      struct hermes_response *resp)
+static int hermes_docmd_wait_direct(hermes_t *hw, u16 cmd, u16 parm0,
+				    struct hermes_response *resp)
 {
 	int err;
 	int k;
@@ -290,7 +318,7 @@
 	return err;
 }
 
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
+static int hermes_allocate_direct(hermes_t *hw, u16 size, u16 *fid)
 {
 	int err = 0;
 	int k;
@@ -299,7 +327,7 @@
 	if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
 		return -EINVAL;
 
-	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
+	err = hermes_docmd_wait_direct(hw, HERMES_CMD_ALLOC, size, NULL);
 	if (err) {
 		return err;
 	}
@@ -397,7 +425,7 @@
 		if (reg & HERMES_OFFSET_BUSY) {
 			return -ETIMEDOUT;
 		}
- 
+
 		return -EIO;		/* error or wrong offset */
 	}
 
@@ -410,8 +438,8 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
-		     u16 id, u16 offset)
+static int hermes_bap_pread_direct(hermes_t *hw, int bap,
+				   void *buf, unsigned len, u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
@@ -436,8 +464,9 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
-		      u16 id, u16 offset)
+static int hermes_bap_pwrite_direct(hermes_t *hw, int bap,
+				    const void *buf, unsigned len,
+				    u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
@@ -464,8 +493,8 @@
  * practice.
  *
  * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
-		    u16 *length, void *buf)
+static int hermes_read_ltv_direct(hermes_t *hw, int bap, u16 rid,
+				  unsigned bufsize, u16 *length, void *buf)
 {
 	int err = 0;
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -475,7 +504,7 @@
 	if ( (bufsize < 0) || (bufsize % 2) )
 		return -EINVAL;
 
-	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
+	err = hermes_docmd_wait_direct(hw, HERMES_CMD_ACCESS, rid, NULL);
 	if (err)
 		return err;
 
@@ -486,7 +515,7 @@
 	rlength = hermes_read_reg(hw, dreg);
 
 	if (! rlength)
-		return -ENOENT;
+		return -ENODATA;
 
 	rtype = hermes_read_reg(hw, dreg);
 
@@ -510,8 +539,8 @@
 	return 0;
 }
 
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
-		     u16 length, const void *value)
+static int hermes_write_ltv_direct(hermes_t *hw, int bap, u16 rid, 
+				   u16 length, const void *value)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
@@ -531,21 +560,13 @@
 
 	hermes_write_words(hw, dreg, value, count);
 
-	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
+	err = hermes_docmd_wait_direct(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
 				rid, NULL);
 
 	return err;
 }
 
 EXPORT_SYMBOL(hermes_struct_init);
-EXPORT_SYMBOL(hermes_init);
-EXPORT_SYMBOL(hermes_docmd_wait);
-EXPORT_SYMBOL(hermes_allocate);
-
-EXPORT_SYMBOL(hermes_bap_pread);
-EXPORT_SYMBOL(hermes_bap_pwrite);
-EXPORT_SYMBOL(hermes_read_ltv);
-EXPORT_SYMBOL(hermes_write_ltv);
 
 static int __init init_hermes(void)
 {
--- a/drivers/net/wireless/hermes.h.3-direct-ops	2004-10-25 14:44:04.557958792 -0400
+++ b/drivers/net/wireless/hermes.h	2004-10-25 15:52:32.134512240 -0400
@@ -191,6 +191,8 @@
 #define	HERMES_RXSTAT_TUNNEL		(0x4000)	/* bridge-tunnel encoded frame */
 #define	HERMES_RXSTAT_WMP		(0x6000)	/* Wavelan-II Management Protocol frame */
 
+#define HERMES_RXSTAT_GET_MACPORT(s)	(((s) & HERMES_RXSTAT_MACPORT) >> 8)
+
 struct hermes_tx_descriptor {
 	u16 status;
 	u16 reserved1;
@@ -340,7 +342,25 @@
 #ifdef __KERNEL__
 
 /* Timeouts */
-#define HERMES_BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
+#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
+
+struct hermes;
+
+/* Functions to access hardware */
+struct hermes_ops {
+	int (*init)(struct hermes *hw);
+	int (*docmd_wait)(struct hermes *hw, u16 cmd, u16 parm0,
+			  struct hermes_response *resp);
+	int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
+	int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
+			u16 *length, void *buf);
+	int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
+			 u16 length, const void *value);
+	int (*bap_pread)(struct hermes *hw, int bap, void *buf, unsigned len,
+			 u16 id, u16 offset);
+	int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
+			  unsigned len, u16 id, u16 offset);
+};
 
 /* Basic control structure */
 typedef struct hermes {
@@ -353,6 +373,8 @@
 #define HERMES_32BIT_REGSPACING	1
 
 	u16 inten; /* Which interrupts should be enabled? */
+	const struct hermes_ops *ops;
+	void *priv;
 
 #ifdef HERMES_DEBUG_BUFFER
 	struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE];
@@ -375,21 +397,44 @@
 #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);
-int hermes_init(hermes_t *hw);
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-		      struct hermes_response *resp);
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
-
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
-		       u16 id, u16 offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
-			u16 id, u16 offset);
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
-		    u16 *length, void *buf);
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-		      u16 length, const void *value);
+void hermes_struct_init(hermes_t *hw, ulong address, int io_space, int reg_spacing);
+
+static inline int hermes_init(hermes_t *hw)
+{
+	return hw->ops->init(hw);
+}
+static inline int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+				    struct hermes_response *resp)
+{
+	return hw->ops->docmd_wait(hw, cmd, parm0, resp);
+}
+static inline int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
+{
+	return hw->ops->allocate(hw, size, fid);
+}
+
+static inline int hermes_bap_pread(hermes_t *hw, int bap,
+				   void *buf, unsigned len,
+				   u16 id, s32 offset)
+{
+	return hw->ops->bap_pread(hw, bap, buf, len, id, offset);
+}
+static inline int hermes_bap_pwrite(hermes_t *hw, int bap,
+				    const void *buf, unsigned len,
+				    u16 id, u16 offset)
+{
+	return hw->ops->bap_pwrite(hw, bap, buf, len, id, offset);
+}
+static inline int hermes_read_ltv(hermes_t *hw, int bap, u16 rid,
+				  unsigned buflen, u16 *length, void *buf)
+{
+	return hw->ops->read_ltv(hw, bap, rid, buflen, length, buf);
+}
+static inline int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
+				   u16 length, const void *value)
+{
+	return hw->ops->write_ltv(hw, bap, rid, length, value);
+}
 
 /* Inline functions */
 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (3 preceding siblings ...)
  2004-10-26 18:43 ` [PATCH 2.6.10-rc1 3/15] wireless/orinoco: encapsulate direct hardware operations Dan Williams
@ 2004-10-26 18:45 ` Dan Williams
  2004-10-26 19:36   ` Jeff Garzik
  2004-10-27  3:15   ` David Gibson
  2004-10-26 18:47 ` [PATCH 2.6.10-rc1 5/15] wireless/orinoco: Update orinoco pcmcia driver's IRQ handling Dan Williams
                   ` (11 subsequent siblings)
  16 siblings, 2 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:45 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Update orinoco changelog and module parameters

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c.4-module-params	2004-10-26 10:40:47.498252680 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 10:41:11.070669128 -0400
@@ -393,12 +393,67 @@
  *	  in the rx_dropped statistics.
  *	o Provided a module parameter to suppress linkstatus messages.
  *
+ * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
+ *	o Replaced priv->connected logic with netif_carrier_on/off()
+ *	  calls.
+ *	o Remove has_ibss_any and never set the CREATEIBSS RID when
+ *	  the ESSID is empty.  Too many firmwares break if we do.
+ *	o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
+ *	  __devinitdata from PCI ID tables, use free_netdev().
+ *	o Enabled shared-key authentication for Agere firmware (from
+ *	  Robert J. Moore <Robert.J.Moore AT allanbank.com>
+ *	o Move netif_wake_queue() (back) to the Tx completion from the
+ *	  ALLOC event.  This seems to prevent/mitigate the rolling
+ *	  error -110 problems at least on some Intersil firmwares.
+ *	  Theoretically reduces performance, but I can't measure it.
+ *	  Patch from Andrew Tridgell <tridge AT samba.org>
+ *
+ * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
+ *	o Correctly turn off shared-key authentication when requested
+ *	  (bugfix from Robert J. Moore).
+ *	o Correct airport sleep interfaces for current 2.6 kernels.
+ *	o Add code for key change without disabling/enabling the MAC
+ *	  port.  This is supposed to allow 802.1x to work sanely, but
+ *	  doesn't seem to yet.
+ *
+ * v0.14alpha2 -> v0.15rc1 - 19 Apr 2004 - Pavel Roskin & David Gibson
+ *	o Fix bug which prevented setting 32 character ESSIDs from
+ *	  iwconfig (Thomas Schulz).
+ *	o Fix for incorrect CIS access in orinoco_plx (Pavel Roskin).
+ *	o Fix setting WEP key if __orinoco_fastkeychange() is not
+ *	  supported (Pavel Roskin).
+ *	o New wireless extensions API and scanning support (patch from
+ *	  Moustafa Youssef, updated by Jim Carter and Pavel Roskin).
+ *	o Add minimal ethtool support (Pavel Roskin).
+ *	o Replace CardServices() calls for compatibility with Linux
+ *	  2.6.2 and above (Pavel Roskin).
+ *	o Fix recognition of Intersil x.x.1 firmware (Pavel Roskin).
+ *	o Replace dump_recs with more flexible get_rid ioctl (Pavel
+ *	  Roskin).
+ *	o RF monitor mode support (Pavel Roskin).
+ *	o Lots of bugfixes.
+ *
+ * v0.15rc1 -> v0.15rc2 - 28 Jul 2004 - Pavel Roskin & David Gibson
+ *	o orinoco_pci saves PCI registers on suspend (Simon Huggins).
+ *	o Monitor mode disabled on Agere 8.xx firmware - it's broken.
+ *	o BAP timeout increased - needed for Intersil firmware.
+ *	o Tx power is no longer reported - it's unreliable.
+ *	o Use 802.11 header in rx path.  Hide packets with ToDS flag
+ *	  from programs that don't need promiscous mode (John Denker).
+ *	o Manual roaming implemented for Symbol and Intersil firmware.
+ *	o Use netdev_priv() instead of directly dereferencing dev->priv.
+ *	o Some simplification of pcmcia init code in orinoco_cs and
+ *	  spectrum_cs. 
+ *	o Numerous trivial cleanups, mainly arising from long-overdue
+ *	  merge with mainline.
+ *
+ * v0.15rc2 -> ???? - ???? - David Gibson
+ *	o Use msleep() instead of hardcoded schedule_timeout()s
+ *	  (Nishanth Aravamudan via kernel-janitors list).
+ *
  * TODO
- *	o New wireless extensions API (patch from Moustafa
- *	  Youssef, updated by Jim Carter and Pavel Roskin).
  *	o Handle de-encapsulation within network layer, provide 802.11
  *	  headers (patch from Thomas 'Dent' Mirlacher)
- *	o RF monitor mode support
  *	o Fix possible races in SPY handling.
  *	o Disconnect wireless extensions from fundamental configuration.
  *	o (maybe) Software WEP support (patch from Stano Meduna).
@@ -461,12 +516,17 @@
 /* Level of debugging. Used in the macros in orinoco.h */
 #ifdef ORINOCO_DEBUG
 int orinoco_debug = ORINOCO_DEBUG;
-MODULE_PARM(orinoco_debug, "i");
+module_param(orinoco_debug, int, 0644);
+MODULE_PARM_DESC(orinoco_debug, "Debug level");
 EXPORT_SYMBOL(orinoco_debug);
 #endif
 
 static int suppress_linkstatus; /* = 0 */
-MODULE_PARM(suppress_linkstatus, "i");
+module_param(suppress_linkstatus, int, 0644);
+MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
+static int ignore_disconnect; /* = 0 */
+module_param(ignore_disconnect, int, 0644);
+MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
 
 /********************************************************************/
 /* Compile time configuration and compatibility stuff               */
--- a/drivers/net/wireless/orinoco.h.4-module-params	2004-10-26 10:43:24.213428352 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-10-26 10:43:31.138375600 -0400
@@ -14,6 +14,9 @@
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+#include <linux/moduleparam.h>
+#endif
 
 #include "hermes.h"
 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-26 18:33 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s Dan Williams
@ 2004-10-26 18:47   ` Christoph Hellwig
  2004-10-26 19:35     ` Dan Williams
  2004-10-26 19:34   ` Jeff Garzik
  1 sibling, 1 reply; 37+ messages in thread
From: Christoph Hellwig @ 2004-10-26 18:47 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, hermes

On Tue, Oct 26, 2004 at 02:33:24PM -0400, Dan Williams wrote:
> Update in-kernel orinoco wireless drivers to upstream CVS.
> None of this is original code by Dan Williams, simply a
> broken down patch set split-out from upstream orinoco CVS.
> 
> o Use msleep() instead of hardcoded schedule_timeout()s
>   (Nishanth Aravamudan via kernel-janitors list).

the patch doesn't match the description

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 5/15] wireless/orinoco: Update orinoco pcmcia driver's IRQ handling
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (4 preceding siblings ...)
  2004-10-26 18:45 ` [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters Dan Williams
@ 2004-10-26 18:47 ` Dan Williams
  2004-10-26 18:51 ` [PATCH 2.6.10-rc1 6/15] wireless/orinoco: New device data release function Dan Williams
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:47 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Update orinoco pcmcia driver's IRQ handling

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco_cs.c.5-irq-handling	2004-10-26 09:28:06.330250992 -0400
+++ b/drivers/net/wireless/orinoco_cs.c	2004-10-26 09:33:00.939463584 -0400
@@ -54,19 +54,11 @@
 
 /* Module parameters */
 
-/* The old way: bit map of interrupts to choose from */
-/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
-static uint irq_mask = 0xdeb8;
-/* Newer, simpler way of listing specific interrupts */
-static int irq_list[4] = { -1 };
-
 /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
  * don't have any CIS entry for it. This workaround it... */
 static int ignore_cis_vcc; /* = 0 */
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(ignore_cis_vcc, "i");
+module_param(ignore_cis_vcc, int, 0644);
+MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
 
 /********************************************************************/
 /* Magic constants						    */
@@ -162,7 +154,7 @@
 	struct orinoco_pccard *card;
 	dev_link_t *link;
 	client_reg_t client_reg;
-	int ret, i;
+	int ret;
 
 	dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset);
 	if (! dev)
@@ -175,14 +167,11 @@
 	link->priv = dev;
 
 	/* Interrupt setup */
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
 	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-	if (irq_list[0] == -1)
-		link->irq.IRQInfo2 = irq_mask;
-	else
-		for (i = 0; i < 4; i++)
-			link->irq.IRQInfo2 |= 1 << irq_list[i];
-	link->irq.Handler = NULL;
+	link->irq.IRQInfo2 = 0xffffffff;	/* Any ISA IRQ */
+	link->irq.Handler = orinoco_interrupt;
+	link->irq.Instance = dev; 
 
 	/* General socket configuration defaults can go here.  In this
 	 * client, we assume very little, and rely on the CIS for
@@ -263,6 +252,9 @@
 		last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \
 	} while (0)
 
+#define CFG_CHECK(fn, ret) \
+	if (ret != 0) goto next_entry
+
 static void
 orinoco_cs_config(dev_link_t *link)
 {
@@ -323,9 +315,8 @@
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 		cistpl_cftable_entry_t dflt = { .index = 0 };
 
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
-			goto next_entry;
+		CFG_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+		CFG_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
 
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 			dflt = *cfg;
@@ -363,8 +354,7 @@
 			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		
 		/* Do we need to allocate an interrupt? */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
+		link->conf.Attributes |= CONF_ENABLE_IRQ;
 
 		/* IO window settings */
 		link->io.NumPorts1 = link->io.NumPorts2 = 0;
@@ -390,8 +380,8 @@
 			}
 
 			/* This reserves IO space but doesn't actually enable it */
-			if (pcmcia_request_io(link->handle, &link->io) != 0)
-				goto next_entry;
+			CFG_CHECK(RequestIO,
+				  pcmcia_request_io(link->handle, &link->io));
 		}
 
 
@@ -416,22 +406,7 @@
 	 * a handler to the interrupt, unless the 'Handler' member of
 	 * the irq structure is initialized.
 	 */
-	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-		int i;
-
-		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-		link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-		if (irq_list[0] == -1)
-			link->irq.IRQInfo2 = irq_mask;
-		else
-			for (i=0; i<4; i++)
-				link->irq.IRQInfo2 |= 1 << irq_list[i];
-		
-  		link->irq.Handler = orinoco_interrupt; 
-  		link->irq.Instance = dev; 
-		
-		CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-	}
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
 
 	/* We initialize the hermes structure before completing PCMCIA
 	 * configuration just in case the interrupt handler gets
@@ -453,8 +428,6 @@
 	SET_MODULE_OWNER(dev);
 	card->node.major = card->node.minor = 0;
 
-	/* register_netdev will give us an ethX name */
-	dev->name[0] = '\0';
 	/* Tell the stack we exist */
 	if (register_netdev(dev) != 0) {
 		printk(KERN_ERR PFX "register_netdev() failed\n");
@@ -476,8 +449,7 @@
 	if (link->conf.Vpp1)
 		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
 		       link->conf.Vpp1 % 10);
-	if (link->conf.Attributes & CONF_ENABLE_IRQ)
-		printk(", irq %d", link->irq.AssignedIRQ);
+	printk(", irq %d", link->irq.AssignedIRQ);
 	if (link->io.NumPorts1)
 		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
 		       link->io.BasePort1 + link->io.NumPorts1 - 1);

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 6/15] wireless/orinoco: New device data release function
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (5 preceding siblings ...)
  2004-10-26 18:47 ` [PATCH 2.6.10-rc1 5/15] wireless/orinoco: Update orinoco pcmcia driver's IRQ handling Dan Williams
@ 2004-10-26 18:51 ` Dan Williams
  2004-10-26 18:56 ` [PATCH 2.6.10-rc1 7/15] wireless/orinoco: Update card reset/init code and add card-specific data structures Dan Williams
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:51 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o New device data release function, in preparation for 
    device-specific data like scan results

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco_cs.c.6-free-orinocodev	2004-10-26 10:44:27.100868008 -0400
+++ b/drivers/net/wireless/orinoco_cs.c	2004-10-26 10:44:41.440688024 -0400
@@ -239,7 +239,7 @@
 		      dev);
 		unregister_netdev(dev);
 	}
-	free_netdev(dev);
+	free_orinocodev(dev);
 }				/* orinoco_cs_detach */
 
 /*
--- a/drivers/net/wireless/orinoco.c.6-free-orinocodev	2004-10-26 10:41:11.070669128 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 10:44:41.444687416 -0400
@@ -2463,6 +2463,13 @@
 
 }
 
+void free_orinocodev(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	free_netdev(dev);
+}
+
 /********************************************************************/
 /* Wireless extensions                                              */
 /********************************************************************/
@@ -4240,6 +4247,7 @@
 /********************************************************************/
 
 EXPORT_SYMBOL(alloc_orinocodev);
+EXPORT_SYMBOL(free_orinocodev);
 
 EXPORT_SYMBOL(__orinoco_up);
 EXPORT_SYMBOL(__orinoco_down);
--- a/drivers/net/wireless/orinoco.h.6-free-orinocodev	2004-10-26 10:43:31.138375600 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-10-26 10:44:41.445687264 -0400
@@ -111,6 +111,7 @@
 
 extern struct net_device *alloc_orinocodev(int sizeof_card,
 					   int (*hard_reset)(struct orinoco_private *));
+extern void free_orinocodev(struct net_device *dev);
 extern int __orinoco_up(struct net_device *dev);
 extern int __orinoco_down(struct net_device *dev);
 extern int orinoco_stop(struct net_device *dev);
--- a/drivers/net/wireless/orinoco_pci.c.6-free-orinocodev	2004-10-26 10:40:47.501252224 -0400
+++ b/drivers/net/wireless/orinoco_pci.c	2004-10-26 10:44:41.447686960 -0400
@@ -267,7 +267,7 @@
 		if (dev->irq)
 			free_irq(dev->irq, dev);
 
-		free_netdev(dev);
+		free_orinocodev(dev);
 	}
 
 	if (pci_ioaddr)
@@ -292,8 +292,8 @@
 		iounmap((unsigned char *) priv->hw.iobase);
 
 	pci_set_drvdata(pdev, NULL);
-	free_netdev(dev);
 
+	free_orinocodev(dev);
 	pci_disable_device(pdev);
 }
 
--- a/drivers/net/wireless/orinoco_plx.c.6-free-orinocodev	2004-10-26 10:40:36.392940944 -0400
+++ b/drivers/net/wireless/orinoco_plx.c	2004-10-26 10:44:41.448686808 -0400
@@ -273,7 +273,7 @@
 		if (dev->irq)
 			free_irq(dev->irq, dev);
 		
-		free_netdev(dev);
+		free_orinocodev(dev);
 	}
 
 	if (pccard_ioaddr)
@@ -300,10 +300,9 @@
 		
 	pci_set_drvdata(pdev, NULL);
 
-	free_netdev(dev);
-
 	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
 
+	free_orinocodev(dev);
 	pci_disable_device(pdev);
 }
 
--- a/drivers/net/wireless/orinoco_tmd.c.6-free-orinocodev	2004-10-26 10:40:36.393940792 -0400
+++ b/drivers/net/wireless/orinoco_tmd.c	2004-10-26 10:44:41.449686656 -0400
@@ -157,7 +157,7 @@
 		if (dev->irq)
 			free_irq(dev->irq, dev);
 		
-		free_netdev(dev);
+		free_orinocodev(dev);
 	}
 
 	if (pccard_ioaddr)
@@ -181,10 +181,9 @@
 		
 	pci_set_drvdata(pdev, NULL);
 
-	free_netdev(dev);
-
 	release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
 
+	free_orinocodev(dev);
 	pci_disable_device(pdev);
 }
 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 7/15] wireless/orinoco: Update card reset/init code and add card-specific data structures
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (6 preceding siblings ...)
  2004-10-26 18:51 ` [PATCH 2.6.10-rc1 6/15] wireless/orinoco: New device data release function Dan Williams
@ 2004-10-26 18:56 ` Dan Williams
  2004-10-26 19:43   ` Jeff Garzik
  2004-10-26 19:04 ` R[PATCH 2.6.10-rc1 8/15] wireless/orinoco: Refactor spinlocks so we don't necessarily have to disable interrupts Dan Williams
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-26 18:56 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Update card reset/init code and add card-specific data structures.
    Also bind to Samsung MagicLAN SWL-2210P cards. 

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco_pci.c.7-card-data	2004-10-26 09:52:07.125216864 -0400
+++ b/drivers/net/wireless/orinoco_pci.c	2004-10-26 10:00:36.855726048 -0400
@@ -129,6 +129,11 @@
 #define HERMES_PCI_COR_OFFT	(500)		/* ms */
 #define HERMES_PCI_COR_BUSYT	(500)		/* ms */
 
+/* Orinoco PCI specific data */
+struct orinoco_pci_card {
+	u32 pci_state[16];	/* PCI suspend/resume state */
+};
+
 /*
  * Do a soft reset of the PCI card using the Configuration Option Register
  * We need this to get going...
@@ -151,25 +156,15 @@
 
 	/* Assert the reset until the card notice */
 	hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
-	printk(KERN_NOTICE "Reset done");
 	timeout = jiffies + (HERMES_PCI_COR_ONT * HZ / 1000);
-	while(time_before(jiffies, timeout)) {
-		printk(".");
+	while(time_before(jiffies, timeout))
 		mdelay(1);
-	}
-	printk(";\n");
-	//mdelay(HERMES_PCI_COR_ONT);
 
 	/* Give time for the card to recover from this hard effort */
 	hermes_write_regn(hw, PCI_COR, 0x0000);
-	printk(KERN_NOTICE "Clear Reset");
 	timeout = jiffies + (HERMES_PCI_COR_OFFT * HZ / 1000);
-	while(time_before(jiffies, timeout)) {
-		printk(".");
+	while(time_before(jiffies, timeout))
 		mdelay(1);
-	}
-	printk(";\n");
-	//mdelay(HERMES_PCI_COR_OFFT);
 
 	/* The card is ready when it's no longer busy */
 	timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000);
@@ -178,12 +173,12 @@
 		mdelay(1);
 		reg = hermes_read_regn(hw, CMD);
 	}
-	/* Did we timeout ? */
-	if(time_after_eq(jiffies, timeout)) {
+
+	/* Still busy? */
+	if (reg & HERMES_CMD_BUSY) {
 		printk(KERN_ERR PFX "Busy timeout\n");
 		return -ETIMEDOUT;
 	}
-	printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies);
 
 	return 0;
 }
@@ -199,61 +194,68 @@
 	u16 *pci_ioaddr = NULL;
 	unsigned long pci_iolen;
 	struct orinoco_private *priv = NULL;
+	struct orinoco_pci_card *card;
 	struct net_device *dev = NULL;
 
 	err = pci_enable_device(pdev);
-	if (err)
-		return -EIO;
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device\n");
+		return -err;
+	}
+
+	err = pci_request_regions(pdev, DRIVER_NAME);
+	if (err != 0) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+		goto fail_resources;
+	}
 
 	/* Resource 0 is mapped to the hermes registers */
 	pci_iorange = pci_resource_start(pdev, 0);
 	pci_iolen = pci_resource_len(pdev, 0);
 	pci_ioaddr = ioremap(pci_iorange, pci_iolen);
-	if (! pci_iorange)
-		goto fail;
+	if (!pci_iorange) {
+		printk(KERN_ERR PFX "Cannot remap hardware registers\n");
+		goto fail_map;
+	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(0, NULL);
+	dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset);
 	if (! dev) {
 		err = -ENOMEM;
-		goto fail;
+		goto fail_alloc;
 	}
 
 	priv = netdev_priv(dev);
-	dev->base_addr = (unsigned long) pci_ioaddr;
+	card = priv->card;
 	dev->mem_start = pci_iorange;
 	dev->mem_end = pci_iorange + pci_iolen - 1;
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	printk(KERN_DEBUG PFX
-	       "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);
-
-	hermes_struct_init(&priv->hw, dev->base_addr,
+	hermes_struct_init(&priv->hw, (unsigned long) pci_ioaddr,
 			   HERMES_MEM, HERMES_32BIT_REGSPACING);
 	pci_set_drvdata(pdev, dev);
 
+	printk(KERN_DEBUG PFX "Detected PCI device %s, memory 0x%lx-0x%lx, "
+	       "irq %d\n", pci_name(pdev), dev->mem_start, dev->mem_end,
+	       pdev->irq);
+
 	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
 			  dev->name, dev);
 	if (err) {
 		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 		err = -EBUSY;
-		goto fail;
+		goto fail_irq;
 	}
 	dev->irq = pdev->irq;
 
 	/* Perform a COR reset to start the card */
-	if(orinoco_pci_cor_reset(priv) != 0) {
-		printk(KERN_ERR "%s: Failed to start the card\n", dev->name);
-		err = -ETIMEDOUT;
+	err = orinoco_pci_cor_reset(priv);
+	if (err) {
+		printk(KERN_ERR PFX "Initial reset failed\n");
 		goto fail;
 	}
 
-	/* Override the normal firmware detection - the Prism 2.5 PCI
-	 * cards look like Lucent firmware but are actually Intersil */
-	priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
-
 	err = register_netdev(dev);
 	if (err) {
 		printk(KERN_ERR PFX "Failed to register net device\n");
@@ -263,16 +265,19 @@
 	return 0;
 
  fail:
-	if (dev) {
-		if (dev->irq)
-			free_irq(dev->irq, dev);
+	free_irq(pdev->irq, dev);
 
-		free_orinocodev(dev);
-	}
+ fail_irq:
+	pci_set_drvdata(pdev, NULL);
+	free_orinocodev(dev);
 
-	if (pci_ioaddr)
-		iounmap(pci_ioaddr);
+ fail_alloc:
+	iounmap(pci_ioaddr);
 
+ fail_map:
+	pci_release_regions(pdev);
+
+ fail_resources:
 	pci_disable_device(pdev);
 
 	return err;
@@ -282,18 +287,14 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct orinoco_private *priv = netdev_priv(dev);
+	void *pci_ioaddr = (void *) priv->hw.iobase;
 
 	unregister_netdev(dev);
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-
-	if (priv->hw.iobase)
-		iounmap((unsigned char *) priv->hw.iobase);
-
+	free_irq(dev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
-
 	free_orinocodev(dev);
+	iounmap(pci_ioaddr);
+	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
 
@@ -301,6 +302,7 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_pci_card *card = priv->card;
 	unsigned long flags;
 	int err;
 	
@@ -325,6 +327,9 @@
 	
 	orinoco_unlock(priv, &flags);
 
+	pci_save_state(pdev, card->pci_state);
+	pci_set_power_state(pdev, 3);
+
 	return 0;
 }
 
@@ -332,11 +337,15 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_pci_card *card = priv->card;
 	unsigned long flags;
 	int err;
 
 	printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
 
+	pci_set_power_state(pdev, 0);
+	pci_restore_state(pdev, card->pci_state);
+
 	err = orinoco_reinit_firmware(dev);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",
@@ -367,6 +376,8 @@
 	{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
 	/* Intersil Prism 2.5 */
 	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
+	/* Samsung MagicLAN SWL-2210P */
+	{0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
 	{0,},
 };
 
--- a/drivers/net/wireless/orinoco_plx.c.7-card-data	2004-10-26 09:52:13.354269904 -0400
+++ b/drivers/net/wireless/orinoco_plx.c	2004-10-26 10:07:51.854596168 -0400
@@ -142,146 +142,189 @@
 #include "hermes.h"
 #include "orinoco.h"
 
-#define COR_OFFSET	(0x3e0/2) /* COR attribute offset of Prism2 PC card */
+#define COR_OFFSET	(0x3e0)	/* COR attribute offset of Prism2 PC card */
 #define COR_VALUE	(COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+#define COR_RESET     (0x80)	/* reset bit in the COR register */
+#define PLX_RESET_TIME	(500)	/* milliseconds */
 
 #define PLX_INTCSR		0x4c /* Interrupt Control & Status Register */
 #define PLX_INTCSR_INTEN	(1<<6) /* Interrupt Enable bit */
 
-static const u16 cis_magic[] = {
-	0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067
+static const u8 cis_magic[] = {
+	0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
 };
 
+/* Orinoco PLX specific data */
+struct orinoco_plx_card {
+	u8 *attr_mem;
+};
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ */
+static int orinoco_plx_cor_reset(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	struct orinoco_plx_card *card = priv->card;
+	u8 *attr_mem = card->attr_mem;
+	unsigned long timeout;
+	u16 reg;
+
+	attr_mem[COR_OFFSET] = COR_VALUE | COR_RESET;
+	mdelay(1);
+
+	attr_mem[COR_OFFSET] = COR_VALUE;
+	mdelay(1);
+
+	/* Just in case, wait more until the card is no longer busy */
+	timeout = jiffies + (PLX_RESET_TIME * HZ / 1000);
+	reg = hermes_read_regn(hw, CMD);
+	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+		mdelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+
+	/* Did we timeout ? */
+	if (reg & HERMES_CMD_BUSY) {
+		printk(KERN_ERR PFX "Busy timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+
 static int orinoco_plx_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
 	int err = 0;
-	u16 *attr_mem = NULL;
-	u32 reg, addr;
+	u8 *attr_mem = NULL;
+	u32 csr_reg, plx_addr;
 	struct orinoco_private *priv = NULL;
+	struct orinoco_plx_card *card;
 	unsigned long pccard_ioaddr = 0;
 	unsigned long pccard_iolen = 0;
 	struct net_device *dev = NULL;
 	int i;
 
 	err = pci_enable_device(pdev);
-	if (err)
-		return -EIO;
-
-	/* Resource 2 is mapped to the PCMCIA space */
-	attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE);
-	if (! attr_mem)
-		goto fail;
-
-	printk(KERN_DEBUG "orinoco_plx: CIS: ");
-	for (i = 0; i < 16; i++) {
-		printk("%02X:", (int)attr_mem[i]);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device\n");
+		return -err;
 	}
-	printk("\n");
 
-	/* Verify whether PC card is present */
-	/* FIXME: we probably need to be smarted about this */
-	if (memcmp(attr_mem, cis_magic, sizeof(cis_magic)) != 0) {
-		printk(KERN_ERR "orinoco_plx: The CIS value of Prism2 PC card is invalid.\n");
-		err = -EIO;
-		goto fail;
+	err = pci_request_regions(pdev, DRIVER_NAME);
+	if (err != 0) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+		goto fail_resources;
 	}
 
-	/* PCMCIA COR is the first byte following CIS: this write should
-	 * enable I/O mode and select level-triggered interrupts */
-	attr_mem[COR_OFFSET] = COR_VALUE;
-	mdelay(1);
-	reg = attr_mem[COR_OFFSET];
-	if (reg != COR_VALUE) {
-		printk(KERN_ERR "orinoco_plx: Error setting COR value (reg=%x)\n", reg);
-		goto fail;
-	}			
+	/* Resource 1 is mapped to PLX-specific registers */
+	plx_addr = pci_resource_start(pdev, 1);
 
-	iounmap(attr_mem);
-	attr_mem = NULL; /* done with this now, it seems */
-
-	/* bjoern: We need to tell the card to enable interrupts, in
-	   case the serial eprom didn't do this already. See the
-	   PLX9052 data book, p8-1 and 8-24 for reference. */
-	addr = pci_resource_start(pdev, 1);
-	reg = 0;
-	reg = inl(addr+PLX_INTCSR);
-	if (reg & PLX_INTCSR_INTEN)
-		printk(KERN_DEBUG "orinoco_plx: "
-		       "Local Interrupt already enabled\n");
-	else {
-		reg |= PLX_INTCSR_INTEN;
-		outl(reg, addr+PLX_INTCSR);
-		reg = inl(addr+PLX_INTCSR);
-		if(!(reg & PLX_INTCSR_INTEN)) {
-			printk(KERN_ERR "orinoco_plx: "
-			       "Couldn't enable Local Interrupts\n");
-			goto fail;
-		}
+	/* Resource 2 is mapped to the PCMCIA attribute memory */
+	attr_mem = ioremap(pci_resource_start(pdev, 2),
+			   pci_resource_len(pdev, 2));
+	if (!attr_mem) {
+		printk(KERN_ERR PFX "Cannot remap PCMCIA space\n");
+		goto fail_map;
 	}
 
-	/* and 3 to the PCMCIA slot I/O address space */
+	/* Resource 3 is mapped to the PCMCIA I/O address space */
 	pccard_ioaddr = pci_resource_start(pdev, 3);
 	pccard_iolen = pci_resource_len(pdev, 3);
-	if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) {
-		printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n",
-		       pccard_iolen, pccard_ioaddr);
-		pccard_ioaddr = 0;
-		err = -EBUSY;
-		goto fail;
-	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(0, NULL);
-	if (! dev) {
+	dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset);
+	if (!dev) {
+		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
-		goto fail;
+		goto fail_alloc;
 	}
 
 	priv = netdev_priv(dev);
+	card = priv->card;
+	card->attr_mem = attr_mem;
 	dev->base_addr = pccard_ioaddr;
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device "
-	       "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
-	       pccard_ioaddr);
-
 	hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_IO,
 			   HERMES_16BIT_REGSPACING);
 	pci_set_drvdata(pdev, dev);
 
+	printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device "
+	       "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
+	       pccard_ioaddr);
+
 	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
 			  dev->name, dev);
 	if (err) {
-		printk(KERN_ERR PFX "Error allocating IRQ %d.\n", pdev->irq);
+		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 		err = -EBUSY;
-		goto fail;
+		goto fail_irq;
 	}
 	dev->irq = pdev->irq;
 
+	/* bjoern: We need to tell the card to enable interrupts, in
+	   case the serial eprom didn't do this already.  See the
+	   PLX9052 data book, p8-1 and 8-24 for reference. */
+	csr_reg = inl(plx_addr + PLX_INTCSR);
+	if (!(csr_reg & PLX_INTCSR_INTEN)) {
+		csr_reg |= PLX_INTCSR_INTEN;
+		outl(csr_reg, plx_addr + PLX_INTCSR);
+		csr_reg = inl(plx_addr + PLX_INTCSR);
+		if (!(csr_reg & PLX_INTCSR_INTEN)) {
+			printk(KERN_ERR PFX "Cannot enable interrupts\n");
+			goto fail;
+		}
+	}
+
+	err = orinoco_plx_cor_reset(priv);
+	if (err) {
+		printk(KERN_ERR PFX "Initial reset failed\n");
+		goto fail;
+	}
+
+	printk(KERN_DEBUG PFX "CIS: ");
+	for (i = 0; i < 16; i++) {
+		printk("%02X:", attr_mem[2 * i]);
+	}
+	printk("\n");
+
+	/* Verify whether a supported PC card is present */
+	/* FIXME: we probably need to be smarted about this */
+	for (i = 0; i < sizeof(cis_magic); i++) {
+		if (cis_magic[i] != attr_mem[2 * i]) {
+			printk(KERN_ERR PFX "The CIS value of Prism2 PC "
+			       "card is unexpected\n");
+			err = -EIO;
+			goto fail;
+		}
+	}
+
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register network device\n");
 		goto fail;
+	}
 
 	return 0;
 
  fail:
-	printk(KERN_DEBUG PFX "init_one(), FAIL!\n");
+	free_irq(pdev->irq, dev);
 
-	if (dev) {
-		if (dev->irq)
-			free_irq(dev->irq, dev);
-		
-		free_orinocodev(dev);
-	}
+ fail_irq:
+	pci_set_drvdata(pdev, NULL);
+	free_orinocodev(dev);
 
-	if (pccard_ioaddr)
-		release_region(pccard_ioaddr, pccard_iolen);
+ fail_alloc:
+	iounmap(attr_mem);
 
-	if (attr_mem)
-		iounmap(attr_mem);
+ fail_map:
+	pci_release_regions(pdev);
 
+ fail_resources:
 	pci_disable_device(pdev);
 
 	return err;
@@ -290,19 +333,18 @@
 static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct orinoco_plx_card *card = priv->card;
+	u8 *attr_mem = card->attr_mem;
 
 	BUG_ON(! dev);
 
 	unregister_netdev(dev);
-		
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-		
+	free_irq(dev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
-
-	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
-
 	free_orinocodev(dev);
+	iounmap(attr_mem);
+	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
 
@@ -332,6 +374,8 @@
 	.id_table	= orinoco_plx_pci_id_table,
 	.probe		= orinoco_plx_init_one,
 	.remove		= __devexit_p(orinoco_plx_remove_one),
+	.suspend	= 0,
+	.resume		= 0,
 };
 
 static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
--- a/drivers/net/wireless/orinoco_tmd.c.7-card-data	2004-10-26 09:52:19.009410192 -0400
+++ b/drivers/net/wireless/orinoco_tmd.c	2004-10-26 10:15:59.469467440 -0400
@@ -79,90 +79,127 @@
 #include "orinoco.h"
 
 #define COR_VALUE	(COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+#define COR_RESET     (0x80)	/* reset bit in the COR register */
+#define TMD_RESET_TIME	(500)	/* milliseconds */
+
+/* Orinoco TMD specific data */
+struct orinoco_tmd_card {
+	u32 tmd_io;
+};
+
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ */
+static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	struct orinoco_tmd_card *card = priv->card;
+	u32 addr = card->tmd_io;
+	unsigned long timeout;
+	u16 reg;
+
+	outb(COR_VALUE | COR_RESET, addr);
+	mdelay(1);
+
+	outb(COR_VALUE, addr);
+	mdelay(1);
+
+	/* Just in case, wait more until the card is no longer busy */
+	timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
+	reg = hermes_read_regn(hw, CMD);
+	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+		mdelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+
+	/* Did we timeout ? */
+	if (reg & HERMES_CMD_BUSY) {
+		printk(KERN_ERR PFX "Busy timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 
 static int orinoco_tmd_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
 	int err = 0;
-	u32 reg, addr;
 	struct orinoco_private *priv = NULL;
-	unsigned long pccard_ioaddr = 0;
-	unsigned long pccard_iolen = 0;
+	struct orinoco_tmd_card *card;
 	struct net_device *dev = NULL;
 
 	err = pci_enable_device(pdev);
-	if (err)
-		return -EIO;
-
-	printk(KERN_DEBUG PFX "TMD setup\n");
-	pccard_ioaddr = pci_resource_start(pdev, 2);
-	pccard_iolen = pci_resource_len(pdev, 2);
-	if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) {
-		printk(KERN_ERR PFX "I/O resource at 0x%lx len 0x%lx busy\n",
-			pccard_ioaddr, pccard_iolen);
-		pccard_ioaddr = 0;
-		err = -EBUSY;
-		goto fail;
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device\n");
+		return -err;
 	}
-	addr = pci_resource_start(pdev, 1);
-	outb(COR_VALUE, addr);
-	mdelay(1);
-	reg = inb(addr);
-	if (reg != COR_VALUE) {
-		printk(KERN_ERR PFX "Error setting TMD COR values %x should be %x\n", reg, COR_VALUE);
-		err = -EIO;
-		goto fail;
+
+	err = pci_request_regions(pdev, DRIVER_NAME);
+	if (err != 0) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+		goto fail_resources;
 	}
 
 	/* Allocate network device */
-	dev = alloc_orinocodev(0, NULL);
+	dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset);
 	if (! dev) {
+		printk(KERN_ERR PFX "Cannot allocate network device\n");
 		err = -ENOMEM;
-		goto fail;
+		goto fail_alloc;
 	}
 
 	priv = netdev_priv(dev);
-	dev->base_addr = pccard_ioaddr;
+	card = priv->card;
+	card->tmd_io = pci_resource_start(pdev, 1);
+	dev->base_addr = pci_resource_start(pdev, 2);
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device "
-	       "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
-	       pccard_ioaddr);
-
 	hermes_struct_init(&(priv->hw), dev->base_addr,
 			HERMES_IO, HERMES_16BIT_REGSPACING);
 	pci_set_drvdata(pdev, dev);
 
+	printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device "
+	       "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
+	       dev->base_addr);
+
 	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
 			  dev->name, dev);
 	if (err) {
-		printk(KERN_ERR PFX "Error allocating IRQ %d.\n",
-		       pdev->irq);
+		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 		err = -EBUSY;
-		goto fail;
+		goto fail_irq;
 	}
 	dev->irq = pdev->irq;
 
+	err = orinoco_tmd_cor_reset(priv);
+	if (err) {
+		printk(KERN_ERR PFX "Initial reset failed\n");
+		goto fail;
+	}
+
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register network device\n");
 		goto fail;
+	}
 
 	return 0;
 
  fail:
-	printk(KERN_DEBUG PFX "init_one(), FAIL!\n");
+	free_irq(pdev->irq, dev);
 
-	if (dev) {
-		if (dev->irq)
-			free_irq(dev->irq, dev);
-		
-		free_orinocodev(dev);
-	}
+ fail_irq:
+	pci_set_drvdata(pdev, NULL);
+	free_orinocodev(dev);
 
-	if (pccard_ioaddr)
-		release_region(pccard_ioaddr, pccard_iolen);
+ fail_alloc:
+	pci_release_regions(pdev);
 
+ fail_resources:
 	pci_disable_device(pdev);
 
 	return err;
@@ -175,15 +212,10 @@
 	BUG_ON(! dev);
 
 	unregister_netdev(dev);
-		
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-		
+	free_irq(dev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
-
-	release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
-
 	free_orinocodev(dev);
+	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
 
@@ -200,6 +232,8 @@
 	.id_table	= orinoco_tmd_pci_id_table,
 	.probe		= orinoco_tmd_init_one,
 	.remove		= __devexit_p(orinoco_tmd_remove_one),
+	.suspend	= 0,
+	.resume		= 0,
 };
 
 static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION

^ permalink raw reply	[flat|nested] 37+ messages in thread

* R[PATCH 2.6.10-rc1 8/15] wireless/orinoco: Refactor spinlocks so we don't necessarily have to disable interrupts
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (7 preceding siblings ...)
  2004-10-26 18:56 ` [PATCH 2.6.10-rc1 7/15] wireless/orinoco: Update card reset/init code and add card-specific data structures Dan Williams
@ 2004-10-26 19:04 ` Dan Williams
  2004-10-26 19:44   ` Jeff Garzik
  2004-10-26 19:07 ` [PATCH 2.6.10-rc1 9/15] wireless/orinoco: Remove dump_recs in preparation for a more flexible replacement Dan Williams
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:04 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Refactor spinlocks so we don't necessarily have to disable interrupts

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.h.8-orinoco-spinlock	2004-10-26 10:44:41.445687264 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-10-26 10:45:39.296892544 -0400
@@ -71,6 +71,8 @@
 	u16 channel_mask;
 	int broken_disableport;
 
+	unsigned int irq_no_disable:1;
+
 	/* Configuration paramaters */
 	u32 iw_mode;
 	int prefer_port3;
@@ -129,11 +131,17 @@
 extern inline int orinoco_lock(struct orinoco_private *priv,
 			       unsigned long *flags)
 {
-	spin_lock_irqsave(&priv->lock, *flags);
+	if (priv->irq_no_disable)
+		spin_lock_bh(&priv->lock);
+	else
+		spin_lock_irqsave(&priv->lock, *flags);
 	if (priv->hw_unavailable) {
-		printk(KERN_DEBUG "orinoco_lock() called with hw_unavailable (dev=%p)\n",
+		DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
 		       priv->ndev);
-		spin_unlock_irqrestore(&priv->lock, *flags);
+		if (priv->irq_no_disable)
+			spin_unlock_bh(&priv->lock);
+		else
+			spin_unlock_irqrestore(&priv->lock, *flags);
 		return -EBUSY;
 	}
 	return 0;
@@ -142,7 +150,27 @@
 extern inline void orinoco_unlock(struct orinoco_private *priv,
 				  unsigned long *flags)
 {
-	spin_unlock_irqrestore(&priv->lock, *flags);
+	if (priv->irq_no_disable)
+		spin_unlock_bh(&priv->lock);
+	else
+		spin_unlock_irqrestore(&priv->lock, *flags);
+}
+
+extern inline void orinoco_spin_lock(struct orinoco_private *priv)
+{
+	if (priv->irq_no_disable)
+		spin_lock_bh(&priv->lock);
+	else
+		spin_lock_irq(&priv->lock);
 }
 
+extern inline void orinoco_spin_unlock(struct orinoco_private *priv)
+{
+	if (priv->irq_no_disable)
+		spin_unlock_bh(&priv->lock);
+	else
+		spin_unlock_irq(&priv->lock);
+}
+
+
 #endif /* _ORINOCO_H */
--- a/drivers/net/wireless/orinoco.c.8-orinoco-spinlock	2004-10-26 10:44:41.444687416 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 10:45:39.301891784 -0400
@@ -699,13 +699,13 @@
 	/* We mustn't use orinoco_lock() here, because we need to be
 	   able to close the interface even if hw_unavailable is set
 	   (e.g. as we're released after a PC Card removal) */
-	spin_lock_irq(&priv->lock);
+	orinoco_spin_lock(priv);
 
 	priv->open = 0;
 
 	err = __orinoco_down(dev);
 
-	spin_unlock_irq(&priv->lock);
+	orinoco_spin_unlock(priv);
 
 	return err;
 }
@@ -1966,7 +1966,7 @@
 		return;
 	}
 
-	spin_lock_irq(&priv->lock); /* This has to be called from user context */
+	orinoco_spin_lock(priv); /* This has to be called from user context */
 
 	priv->hw_unavailable--;
 
@@ -1981,7 +1981,7 @@
 			dev->trans_start = jiffies;
 	}
 
-	spin_unlock_irq(&priv->lock);
+	orinoco_spin_unlock(priv);
 
 	return;
 }
@@ -2404,9 +2404,9 @@
 
 	/* Make the hardware available, as long as it hasn't been
 	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
-	spin_lock_irq(&priv->lock);
+	orinoco_spin_lock(priv);
 	priv->hw_unavailable--;
-	spin_unlock_irq(&priv->lock);
+	orinoco_spin_unlock(priv);
 
 	printk(KERN_DEBUG "%s: ready\n", dev->name);
 
--- ./orinoco_cs.c.8-orinoco-spinlock	2004-10-26 10:44:41.440688024 -0400
+++ ./orinoco_cs.c	2004-10-26 10:45:39.303891480 -0400
@@ -513,12 +513,12 @@
 	case CS_EVENT_CARD_REMOVAL:
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
-			orinoco_lock(priv, &flags);
+			unsigned long flags;
 
+			spin_lock_irqsave(&priv->lock, flags);
 			netif_device_detach(dev);
 			priv->hw_unavailable++;
-
-			orinoco_unlock(priv, &flags);
+			spin_unlock_irqrestore(&priv->lock, flags);
 		}
 		break;
 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 9/15] wireless/orinoco: Remove dump_recs in preparation for a more flexible replacement
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (8 preceding siblings ...)
  2004-10-26 19:04 ` R[PATCH 2.6.10-rc1 8/15] wireless/orinoco: Refactor spinlocks so we don't necessarily have to disable interrupts Dan Williams
@ 2004-10-26 19:07 ` Dan Williams
  2004-10-26 19:13 ` [PATCH 2.6.10-rc1 10/15] wireless/orinoco: Use wireless handlers rather than ioctl()s Dan Williams
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:07 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Remove dump_recs in preparation for a more flexible replacement

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c.9-no-debug-dump-recs	2004-10-26 10:30:12.685758848 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 10:33:04.220681576 -0400
@@ -639,7 +639,6 @@
 static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int __orinoco_program_rids(struct net_device *dev);
 static void __orinoco_set_multicast_list(struct net_device *dev);
-static int orinoco_debug_dump_recs(struct net_device *dev);
 
 /********************************************************************/
 /* Internal helper functions                                        */
@@ -3976,13 +3975,6 @@
 		err = orinoco_ioctl_getibssport(dev, wrq);
 		break;
 
-	case SIOCIWLASTPRIV:
-		err = orinoco_debug_dump_recs(dev);
-		if (err)
-			printk(KERN_ERR "%s: Unable to dump records (%d)\n",
-			       dev->name, err);
-		break;
-
 
 	default:
 		err = -EOPNOTSUPP;
@@ -3997,187 +3989,6 @@
 	return err;
 }
 
-struct {
-	u16 rid;
-	char *name;
-	int displaytype;
-#define DISPLAY_WORDS	0
-#define DISPLAY_BYTES	1
-#define DISPLAY_STRING	2
-#define DISPLAY_XSTRING	3
-} record_table[] = {
-#define DEBUG_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
-	DEBUG_REC(CNFPORTTYPE,WORDS),
-	DEBUG_REC(CNFOWNMACADDR,BYTES),
-	DEBUG_REC(CNFDESIREDSSID,STRING),
-	DEBUG_REC(CNFOWNCHANNEL,WORDS),
-	DEBUG_REC(CNFOWNSSID,STRING),
-	DEBUG_REC(CNFOWNATIMWINDOW,WORDS),
-	DEBUG_REC(CNFSYSTEMSCALE,WORDS),
-	DEBUG_REC(CNFMAXDATALEN,WORDS),
-	DEBUG_REC(CNFPMENABLED,WORDS),
-	DEBUG_REC(CNFPMEPS,WORDS),
-	DEBUG_REC(CNFMULTICASTRECEIVE,WORDS),
-	DEBUG_REC(CNFMAXSLEEPDURATION,WORDS),
-	DEBUG_REC(CNFPMHOLDOVERDURATION,WORDS),
-	DEBUG_REC(CNFOWNNAME,STRING),
-	DEBUG_REC(CNFOWNDTIMPERIOD,WORDS),
-	DEBUG_REC(CNFMULTICASTPMBUFFERING,WORDS),
-	DEBUG_REC(CNFWEPENABLED_AGERE,WORDS),
-	DEBUG_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
-	DEBUG_REC(CNFWEPDEFAULTKEYID,WORDS),
-	DEBUG_REC(CNFDEFAULTKEY0,BYTES),
-	DEBUG_REC(CNFDEFAULTKEY1,BYTES),
-	DEBUG_REC(CNFMWOROBUST_AGERE,WORDS),
-	DEBUG_REC(CNFDEFAULTKEY2,BYTES),
-	DEBUG_REC(CNFDEFAULTKEY3,BYTES),
-	DEBUG_REC(CNFWEPFLAGS_INTERSIL,WORDS),
-	DEBUG_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
-	DEBUG_REC(CNFAUTHENTICATION,WORDS),
-	DEBUG_REC(CNFMAXASSOCSTA,WORDS),
-	DEBUG_REC(CNFKEYLENGTH_SYMBOL,WORDS),
-	DEBUG_REC(CNFTXCONTROL,WORDS),
-	DEBUG_REC(CNFROAMINGMODE,WORDS),
-	DEBUG_REC(CNFHOSTAUTHENTICATION,WORDS),
-	DEBUG_REC(CNFRCVCRCERROR,WORDS),
-	DEBUG_REC(CNFMMLIFE,WORDS),
-	DEBUG_REC(CNFALTRETRYCOUNT,WORDS),
-	DEBUG_REC(CNFBEACONINT,WORDS),
-	DEBUG_REC(CNFAPPCFINFO,WORDS),
-	DEBUG_REC(CNFSTAPCFINFO,WORDS),
-	DEBUG_REC(CNFPRIORITYQUSAGE,WORDS),
-	DEBUG_REC(CNFTIMCTRL,WORDS),
-	DEBUG_REC(CNFTHIRTY2TALLY,WORDS),
-	DEBUG_REC(CNFENHSECURITY,WORDS),
-	DEBUG_REC(CNFGROUPADDRESSES,BYTES),
-	DEBUG_REC(CNFCREATEIBSS,WORDS),
-	DEBUG_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
-	DEBUG_REC(CNFRTSTHRESHOLD,WORDS),
-	DEBUG_REC(CNFTXRATECONTROL,WORDS),
-	DEBUG_REC(CNFPROMISCUOUSMODE,WORDS),
-	DEBUG_REC(CNFBASICRATES_SYMBOL,WORDS),
-	DEBUG_REC(CNFPREAMBLE_SYMBOL,WORDS),
-	DEBUG_REC(CNFSHORTPREAMBLE,WORDS),
-	DEBUG_REC(CNFWEPKEYS_AGERE,BYTES),
-	DEBUG_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
-	DEBUG_REC(CNFTXKEY_AGERE,WORDS),
-	DEBUG_REC(CNFAUTHENTICATIONRSPTO,WORDS),
-	DEBUG_REC(CNFBASICRATES,WORDS),
-	DEBUG_REC(CNFSUPPORTEDRATES,WORDS),
-	DEBUG_REC(CNFTICKTIME,WORDS),
-	DEBUG_REC(CNFSCANREQUEST,WORDS),
-	DEBUG_REC(CNFJOINREQUEST,WORDS),
-	DEBUG_REC(CNFAUTHENTICATESTATION,WORDS),
-	DEBUG_REC(CNFCHANNELINFOREQUEST,WORDS),
-	DEBUG_REC(MAXLOADTIME,WORDS),
-	DEBUG_REC(DOWNLOADBUFFER,WORDS),
-	DEBUG_REC(PRIID,WORDS),
-	DEBUG_REC(PRISUPRANGE,WORDS),
-	DEBUG_REC(CFIACTRANGES,WORDS),
-	DEBUG_REC(NICSERNUM,XSTRING),
-	DEBUG_REC(NICID,WORDS),
-	DEBUG_REC(MFISUPRANGE,WORDS),
-	DEBUG_REC(CFISUPRANGE,WORDS),
-	DEBUG_REC(CHANNELLIST,WORDS),
-	DEBUG_REC(REGULATORYDOMAINS,WORDS),
-	DEBUG_REC(TEMPTYPE,WORDS),
-/*  	DEBUG_REC(CIS,BYTES), */
-	DEBUG_REC(STAID,WORDS),
-	DEBUG_REC(CURRENTSSID,STRING),
-	DEBUG_REC(CURRENTBSSID,BYTES),
-	DEBUG_REC(COMMSQUALITY,WORDS),
-	DEBUG_REC(CURRENTTXRATE,WORDS),
-	DEBUG_REC(CURRENTBEACONINTERVAL,WORDS),
-	DEBUG_REC(CURRENTSCALETHRESHOLDS,WORDS),
-	DEBUG_REC(PROTOCOLRSPTIME,WORDS),
-	DEBUG_REC(SHORTRETRYLIMIT,WORDS),
-	DEBUG_REC(LONGRETRYLIMIT,WORDS),
-	DEBUG_REC(MAXTRANSMITLIFETIME,WORDS),
-	DEBUG_REC(MAXRECEIVELIFETIME,WORDS),
-	DEBUG_REC(CFPOLLABLE,WORDS),
-	DEBUG_REC(AUTHENTICATIONALGORITHMS,WORDS),
-	DEBUG_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
-	DEBUG_REC(OWNMACADDR,BYTES),
-	DEBUG_REC(SCANRESULTSTABLE,WORDS),
-	DEBUG_REC(PHYTYPE,WORDS),
-	DEBUG_REC(CURRENTCHANNEL,WORDS),
-	DEBUG_REC(CURRENTPOWERSTATE,WORDS),
-	DEBUG_REC(CCAMODE,WORDS),
-	DEBUG_REC(SUPPORTEDDATARATES,WORDS),
-	DEBUG_REC(BUILDSEQ,BYTES),
-	DEBUG_REC(FWID,XSTRING)
-#undef DEBUG_REC
-};
-
-#define DEBUG_LTV_SIZE		128
-
-static int orinoco_debug_dump_recs(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	u8 *val8;
-	u16 *val16;
-	int i,j;
-	u16 length;
-	int err;
-
-	/* I'm not sure: we might have a lock here, so we'd better go
-           atomic, just in case. */
-	val8 = kmalloc(DEBUG_LTV_SIZE + 2, GFP_ATOMIC);
-	if (! val8)
-		return -ENOMEM;
-	val16 = (u16 *)val8;
-
-	for (i = 0; i < ARRAY_SIZE(record_table); i++) {
-		u16 rid = record_table[i].rid;
-		int len;
-
-		memset(val8, 0, DEBUG_LTV_SIZE + 2);
-
-		err = hermes_read_ltv(hw, USER_BAP, rid, DEBUG_LTV_SIZE,
-				      &length, val8);
-		if (err) {
-			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
-			continue;
-		}
-		val16 = (u16 *)val8;
-		if (length == 0)
-			continue;
-
-		printk(KERN_DEBUG "%-15s (0x%04x): length=%d (%d bytes)\tvalue=",
-		       record_table[i].name,
-		       rid, length, (length-1)*2);
-		len = min(((int)length-1)*2, DEBUG_LTV_SIZE);
-
-		switch (record_table[i].displaytype) {
-		case DISPLAY_WORDS:
-			for (j = 0; j < len / 2; j++)
-				printk("%04X-", le16_to_cpu(val16[j]));
-			break;
-
-		case DISPLAY_BYTES:
-		default:
-			for (j = 0; j < len; j++)
-				printk("%02X:", val8[j]);
-			break;
-
-		case DISPLAY_STRING:
-			len = min(len, le16_to_cpu(val16[0])+2);
-			val8[len] = '\0';
-			printk("\"%s\"", (char *)&val16[1]);
-			break;
-
-		case DISPLAY_XSTRING:
-			printk("'%s'", (char *)val8);
-		}
-
-		printk("\n");
-	}
-
-	kfree(val8);
-
-	return 0;
-}
 
 /********************************************************************/
 /* Debugging                                                        */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 10/15] wireless/orinoco: Use wireless handlers rather than ioctl()s
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (9 preceding siblings ...)
  2004-10-26 19:07 ` [PATCH 2.6.10-rc1 9/15] wireless/orinoco: Remove dump_recs in preparation for a more flexible replacement Dan Williams
@ 2004-10-26 19:13 ` Dan Williams
  2004-10-26 19:18 ` [PATCH 2.6.10-rc1 11/15] wireless/orinoco: Clean up firmware version & capability detection Dan Williams
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:13 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Convert to use wireless handler API rather than ioctl() calls.
o Clean up the locking and return -EBUSY if we can't lock the device
o Move some of our driver private data into bitfields rather than 'int's
o Add more flexible get_rid() debug method in place of dump_recs

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c.10-wireless-handlers	2004-10-26 11:06:54.294063512 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 12:55:37.443394080 -0400
@@ -495,6 +495,9 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
+#if WIRELESS_EXT > 12
+#include <net/iw_handler.h>
+#endif	/* WIRELESS_EXT > 12 */
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -569,6 +572,12 @@
 				 | HERMES_EV_WTERR | HERMES_EV_INFO \
 				 | HERMES_EV_INFDROP )
 
+#define MAX_RID_LEN 1024
+
+#if WIRELESS_EXT > 12
+static const struct iw_handler_def orinoco_handler_def;
+#endif
+
 /********************************************************************/
 /* Data tables                                                      */
 /********************************************************************/
@@ -676,9 +685,8 @@
 	unsigned long flags;
 	int err;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	err = __orinoco_up(dev);
 
@@ -721,7 +729,7 @@
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	struct iw_statistics *wstats = &priv->wstats;
-	int err = 0;
+	int err;
 	unsigned long flags;
 
 	if (! netif_device_present(dev)) {
@@ -730,10 +738,17 @@
 		return NULL; /* FIXME: Can we do better than this? */
 	}
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return NULL; /* FIXME: Erg, we've been signalled, how
-			      * do we propagate this back up? */
+	/* If busy, return the old stats.  Returning NULL may cause
+	 * the interface to disappear from /proc/net/wireless */
+	if (orinoco_lock(priv, &flags) != 0)
+		return wstats;
+
+	/* We can't really wait for the tallies inquiry command to
+	 * complete, so we just use the previous results and trigger
+	 * a new tallies inquiry command for next time - Jean II */
+	/* FIXME: We're in user context (I think?), so we should just
+           wait for the tallies to come through */
+	hermes_inquire(hw, HERMES_INQ_TALLIES);
 
 	if (priv->iw_mode == IW_MODE_ADHOC) {
 		memset(&wstats->qual, 0, sizeof(wstats->qual));
@@ -752,25 +767,16 @@
 
 		err = HERMES_READ_RECORD(hw, USER_BAP,
 					 HERMES_RID_COMMSQUALITY, &cq);
-		
-		wstats->qual.qual = (int)le16_to_cpu(cq.qual);
-		wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
-		wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
-		wstats->qual.updated = 7;
+
+		if (!err) {
+			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
+			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
+			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
+			wstats->qual.updated = 7;
+		}
 	}
 
-	/* We can't really wait for the tallies inquiry command to
-	 * complete, so we just use the previous results and trigger
-	 * a new tallies inquiry command for next time - Jean II */
-	/* FIXME: We're in user context (I think?), so we should just
-           wait for the tallies to come through */
-	err = hermes_inquire(hw, HERMES_INQ_TALLIES);
-               
 	orinoco_unlock(priv, &flags);
-
-	if (err)
-		return NULL;
-		
 	return wstats;
 }
 
@@ -1493,55 +1499,76 @@
 	return err;
 }
 
-static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
+/* Set fixed AP address */
+static int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+	int roaming_flag;
+	int err = 0;
+	hermes_t *hw = &priv->hw;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		/* not supported */
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		if (priv->bssid_fixed)
+			roaming_flag = 2;
+		else
+			roaming_flag = 1;
+
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFROAMINGMODE,
+					   roaming_flag);
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		err = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+					  &priv->desired_bssid);
+		break;
+	}
+	return err;
+}
+
+/* Change the WEP keys and/or the current keys.  Can be called
+ * either from __orinoco_hw_setup_wep() or directly from
+ * orinoco_ioctl_setiwencode().  In the later case the association
+ * with the AP is not broken (if the firmware can handle it),
+ * which is needed for 802.1x implementations. */
+static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
-	int	master_wep_flag;
-	int	auth_flag;
 
 	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
-		if (priv->wep_on) {
-			err = hermes_write_wordrec(hw, USER_BAP,
-						   HERMES_RID_CNFTXKEY_AGERE,
-						   priv->tx_key);
-			if (err)
-				return err;
-			
-			err = HERMES_WRITE_RECORD(hw, USER_BAP,
-						  HERMES_RID_CNFWEPKEYS_AGERE,
-						  &priv->keys);
-			if (err)
-				return err;
-		}
+	case FIRMWARE_TYPE_AGERE:
+		err = HERMES_WRITE_RECORD(hw, USER_BAP,
+					  HERMES_RID_CNFWEPKEYS_AGERE,
+					  &priv->keys);
+		if (err)
+			return err;
 		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFWEPENABLED_AGERE,
-					   priv->wep_on);
+					   HERMES_RID_CNFTXKEY_AGERE,
+					   priv->tx_key);
 		if (err)
 			return err;
 		break;
-
-	case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
-		master_wep_flag = 0;		/* Off */
-		if (priv->wep_on) {
+	case FIRMWARE_TYPE_INTERSIL:
+	case FIRMWARE_TYPE_SYMBOL:
+		{
 			int keylen;
 			int i;
 
-			/* Fudge around firmware weirdness */
+			/* Force uniform key length to work around firmware bugs */
 			keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
 			
+			if (keylen > LARGE_KEY_SIZE) {
+				printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
+				       priv->ndev->name, priv->tx_key, keylen);
+				return -E2BIG;
+			}
+
 			/* Write all 4 keys */
 			for(i = 0; i < ORINOCO_MAX_KEYS; i++) {
-/*  				int keylen = le16_to_cpu(priv->keys[i].len); */
-				
-				if (keylen > LARGE_KEY_SIZE) {
-					printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
-					       priv->ndev->name, i, keylen);
-					return -E2BIG;
-				}
-
 				err = hermes_write_ltv(hw, USER_BAP,
 						       HERMES_RID_CNFDEFAULTKEY0 + i,
 						       HERMES_BYTES_TO_RECLEN(keylen),
@@ -1556,27 +1583,60 @@
 						   priv->tx_key);
 			if (err)
 				return err;
-			
-			if (priv->wep_restrict) {
-				auth_flag = 2;
-				master_wep_flag = 3;
-			} else {
-				/* Authentication is where Intersil and Symbol
-				 * firmware differ... */
-				auth_flag = 1;
-				if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-					master_wep_flag = 3; /* Symbol */ 
-				else 
-					master_wep_flag = 1; /* Intersil */
-			}
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	int master_wep_flag;
+	int auth_flag;
+
+	if (priv->wep_on)
+		__orinoco_hw_setup_wepkeys(priv);
+
+	if (priv->wep_restrict)
+		auth_flag = HERMES_AUTH_SHARED_KEY;
+	else
+		auth_flag = HERMES_AUTH_OPEN;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
+		if (priv->wep_on) {
+			/* Enable the shared-key authentication. */
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFAUTHENTICATION_AGERE,
+						   auth_flag);
+		}
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFWEPENABLED_AGERE,
+					   priv->wep_on);
+		if (err)
+			return err;
+		break;
 
+	case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
+	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
+		if (priv->wep_on) {
+			if (priv->wep_restrict ||
+			    (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
+				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
+						  HERMES_WEP_EXCL_UNENCRYPTED;
+			else
+				master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
 
 			err = hermes_write_wordrec(hw, USER_BAP,
 						   HERMES_RID_CNFAUTHENTICATION,
 						   auth_flag);
 			if (err)
 				return err;
-		}
+		} else
+			master_wep_flag = 0;
 
 		/* Master WEP setting : on/off */
 		err = hermes_write_wordrec(hw, USER_BAP,
@@ -1586,13 +1646,6 @@
 			return err;	
 
 		break;
-
-	default:
-		if (priv->wep_on) {
-			printk(KERN_ERR "%s: WEP enabled, although not supported!\n",
-			       priv->ndev->name);
-			return -EINVAL;
-		}
 	}
 
 	return 0;
@@ -1623,38 +1676,49 @@
 		return err;
 	}
 	/* Set the channel/frequency */
-	if (priv->channel == 0) {
-		printk(KERN_DEBUG "%s: Channel is 0 in __orinoco_program_rids()\n", dev->name);
-		if (priv->createibss)
-			priv->channel = 10;
-	}
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL,
-				   priv->channel);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting channel\n",
-		       dev->name, err);
-		return err;
-	}
-
-	if (priv->has_ibss) {
+	if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
 		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNFCREATEIBSS,
-					   priv->createibss);
+					   HERMES_RID_CNFOWNCHANNEL,
+					   priv->channel);
 		if (err) {
-			printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err);
+			printk(KERN_ERR "%s: Error %d setting channel %d\n",
+			       dev->name, err, priv->channel);
 			return err;
 		}
+	}
+
+	if (priv->has_ibss) {
+		u16 createibss;
 
-		if ((strlen(priv->desired_essid) == 0) && (priv->createibss)
-		   && (!priv->has_ibss_any)) {
+		if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
 			printk(KERN_WARNING "%s: This firmware requires an "
 			       "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
 			/* With wvlan_cs, in this case, we would crash.
 			 * hopefully, this driver will behave better...
 			 * Jean II */
+			createibss = 0;
+		} else {
+			createibss = priv->createibss;
+		}
+		
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFCREATEIBSS,
+					   createibss);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+			       dev->name, err);
+			return err;
 		}
 	}
 
+	/* Set the desired BSSID */
+	err = __orinoco_hw_set_wap(priv);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting AP address\n",
+		       dev->name, err);
+		return err;
+	}
+
 	/* Set the desired ESSID */
 	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
 	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
@@ -1869,57 +1933,6 @@
 		dev->flags &= ~IFF_PROMISC;
 }
 
-static int orinoco_reconfigure(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	struct hermes *hw = &priv->hw;
-	unsigned long flags;
-	int err = 0;
-
-	if (priv->broken_disableport) {
-		schedule_work(&priv->reset_work);
-		return 0;
-	}
-
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
-
-		
-	err = hermes_disable_port(hw, 0);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
-		       dev->name);
-		priv->broken_disableport = 1;
-		goto out;
-	}
-
-	err = __orinoco_program_rids(dev);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-		       dev->name);
-		goto out;
-	}
-
-	err = hermes_enable_port(hw, 0);
-	if (err) {
-		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-		       dev->name);
-		goto out;
-	}
-
- out:
-	if (err) {
-		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-		schedule_work(&priv->reset_work);
-		err = 0;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return err;
-
-}
-
 /* This must be called from user context, without locks held - use
  * schedule_work() */
 static void orinoco_reset(struct net_device *dev)
@@ -1929,8 +1942,7 @@
 	int err;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
+	if (orinoco_lock(priv, &flags) != 0)
 		/* When the hardware becomes available again, whatever
 		 * detects that is responsible for re-initializing
 		 * it. So no need for anything further */
@@ -1949,20 +1961,20 @@
 
 	orinoco_unlock(priv, &flags);
 
-	if (priv->hard_reset)
+	if (priv->hard_reset) {
 		err = (*priv->hard_reset)(priv);
-	if (err) {
-		printk(KERN_ERR "%s: orinoco_reset: Error %d "
-		       "performing  hard reset\n", dev->name, err);
-		/* FIXME: shutdown of some sort */
-		return;
+		if (err) {
+			printk(KERN_ERR "%s: orinoco_reset: Error %d "
+			       "performing hard reset\n", dev->name, err);
+			goto disable;
+		}
 	}
 
 	err = orinoco_reinit_firmware(dev);
 	if (err) {
 		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
 		       dev->name, err);
-		return;
+		goto disable;
 	}
 
 	orinoco_spin_lock(priv); /* This has to be called from user context */
@@ -1983,6 +1995,11 @@
 	orinoco_spin_unlock(priv);
 
 	return;
+
+ disable:
+	hermes_set_irqmask(hw, 0);
+	netif_device_detach(dev);
+	printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
 }
 
 /********************************************************************/
@@ -2133,7 +2150,6 @@
 	priv->has_preamble = 0;
 	priv->has_port3 = 1;
 	priv->has_ibss = 1;
-	priv->has_ibss_any = 0;
 	priv->has_wep = 0;
 	priv->has_big_wep = 0;
 
@@ -2149,7 +2165,6 @@
 		firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
 
 		priv->has_ibss = (firmver >= 0x60006);
-		priv->has_ibss_any = (firmver >= 0x60010);
 		priv->has_wep = (firmver >= 0x40020);
 		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
 					  Gold cards from the others? */
@@ -2426,7 +2441,7 @@
 	priv = netdev_priv(dev);
 	priv->ndev = dev;
 	if (sizeof_card)
-		priv->card = (void *)((unsigned long)netdev_priv(dev)
+		priv->card = (void *)((unsigned long)priv
 				      + sizeof(struct orinoco_private));
 	else
 		priv->card = NULL;
@@ -2438,6 +2453,9 @@
 	dev->watchdog_timeo = HZ; /* 1 second timeout */
 	dev->get_stats = orinoco_get_stats;
 	dev->get_wireless_stats = orinoco_get_wireless_stats;
+#if WIRELESS_EXT > 12
+	dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
+#endif
 	dev->do_ioctl = orinoco_ioctl;
 	dev->change_mtu = orinoco_change_mtu;
 	dev->set_multicast_list = orinoco_set_multicast_list;
@@ -2473,25 +2491,6 @@
 /* Wireless extensions                                              */
 /********************************************************************/
 
-static int orinoco_hw_get_bssid(struct orinoco_private *priv,
-				char buf[ETH_ALEN])
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	unsigned long flags;
-
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-			      ETH_ALEN, NULL, buf);
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
 static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
 				char buf[IW_ESSID_MAX_SIZE+1])
 {
@@ -2502,9 +2501,8 @@
 	int len;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	if (strlen(priv->desired_essid) > 0) {
 		/* We read the desired SSID from the hardware rather
@@ -2535,6 +2533,7 @@
 	}
 
 	len = le16_to_cpu(essidbuf.len);
+	BUG_ON(len > IW_ESSID_MAX_SIZE);
 
 	memset(buf, 0, IW_ESSID_MAX_SIZE+1);
 	memcpy(buf, p, len);
@@ -2555,9 +2554,8 @@
 	long freq = 0;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 	
 	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
 	if (err)
@@ -2597,9 +2595,8 @@
 	int i;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
 			      sizeof(list), NULL, &list);
@@ -2619,143 +2616,265 @@
 	return 0;
 }
 
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int orinoco_ioctl_getname(struct net_device *dev,
+				 struct iw_request_info *info,
+				 char *name,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
-	int mode;
-	struct iw_range range;
 	int numrates;
-	int i, k;
-	unsigned long flags;
-
-	TRACE_ENTER(dev->name);
-
-	err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range));
-	if (err)
-		return err;
+	int err;
 
-	rrq->length = sizeof(range);
+	err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (!err && (numrates > 2))
+		strcpy(name, "IEEE 802.11b");
+	else
+		strcpy(name, "IEEE 802.11-DS");
 
-	mode = priv->iw_mode;
-	orinoco_unlock(priv, &flags);
+	return 0;
+}
 
-	memset(&range, 0, sizeof(range));
+static int orinoco_ioctl_setwap(struct net_device *dev,
+				struct iw_request_info *info,
+				struct sockaddr *ap_addr,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
+	static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-	/* Much of this shamelessly taken from wvlan_cs.c. No idea
-	 * what it all means -dgibson */
-	range.we_version_compiled = WIRELESS_EXT;
-	range.we_version_source = 11;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
-	range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+	/* Enable automatic roaming - no sanity checks are needed */
+	if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+	    memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+		priv->bssid_fixed = 0;
+		memset(priv->desired_bssid, 0, ETH_ALEN);
 
-	/* Set available channels/frequencies */
-	range.num_channels = NUM_CHANNELS;
-	k = 0;
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		if (priv->channel_mask & (1 << i)) {
-			range.freq[k].i = i + 1;
-			range.freq[k].m = channel_frequency[i] * 100000;
-			range.freq[k].e = 1;
-			k++;
+		/* "off" means keep existing connection */
+		if (ap_addr->sa_data[0] == 0) {
+			__orinoco_hw_set_wap(priv);
+			err = 0;
 		}
-		
-		if (k >= IW_MAX_FREQUENCIES)
-			break;
+		goto out;
 	}
-	range.num_frequency = k;
 
-	range.sensitivity = 3;
+	if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+		printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+		       "support manual roaming\n",
+		       dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
-	if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
-		/* Quality stats meaningless in ad-hoc mode */
-		range.max_qual.qual = 0;
-		range.max_qual.level = 0;
-		range.max_qual.noise = 0;
-		range.avg_qual.qual = 0;
-		range.avg_qual.level = 0;
-		range.avg_qual.noise = 0;
-	} else {
-		range.max_qual.qual = 0x8b - 0x2f;
-		range.max_qual.level = 0x2f - 0x95 - 1;
-		range.max_qual.noise = 0x2f - 0x95 - 1;
-		/* Need to get better values */
-		range.avg_qual.qual = 0x24;
-		range.avg_qual.level = 0xC2;
-		range.avg_qual.noise = 0x9E;
+	if (priv->iw_mode != IW_MODE_INFRA) {
+		printk(KERN_WARNING "%s: Manual roaming supported only in "
+		       "managed mode\n", dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
 	}
 
-	err = orinoco_hw_get_bitratelist(priv, &numrates,
-					 range.bitrate, IW_MAX_BITRATES);
-	if (err)
-		return err;
-	range.num_bitrates = numrates;
-	
-	/* Set an indication of the max TCP throughput in bit/s that we can
-	 * expect using this interface. May be use for QoS stuff...
-	 * Jean II */
-	if(numrates > 2)
-		range.throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
-	else
-		range.throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
+	/* Intersil firmware hangs without Desired ESSID */
+	if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+	    strlen(priv->desired_essid) == 0) {
+		printk(KERN_WARNING "%s: Desired ESSID must be set for "
+		       "manual roaming\n", dev->name);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
-	range.min_rts = 0;
-	range.max_rts = 2347;
-	range.min_frag = 256;
-	range.max_frag = 2346;
+	/* Finally, enable manual roaming */
+	priv->bssid_fixed = 1;
+	memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
-	if (priv->has_wep) {
-		range.max_encoding_tokens = ORINOCO_MAX_KEYS;
+ out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+				struct iw_request_info *info,
+				struct sockaddr *ap_addr,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	ap_addr->sa_family = ARPHRD_ETHER;
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+			      ETH_ALEN, NULL, ap_addr->sa_data);
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_setmode(struct net_device *dev,
+				 struct iw_request_info *info,
+				 u32 *mode,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = -EINPROGRESS;		/* Call commit handler */
+	unsigned long flags;
+
+	if (priv->iw_mode == *mode)
+		return 0;
 
-		range.encoding_size[0] = SMALL_KEY_SIZE;
-		range.num_encoding_sizes = 1;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	switch (*mode) {
+	case IW_MODE_ADHOC:
+		if (!priv->has_ibss && !priv->has_port3)
+			err = -EOPNOTSUPP;
+		break;
+
+	case IW_MODE_INFRA:
+		break;
+
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	if (err == -EINPROGRESS) {
+		priv->iw_mode = *mode;
+		set_port_type(priv);
+	}
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_ioctl_getmode(struct net_device *dev,
+				 struct iw_request_info *info,
+				 u32 *mode,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	*mode = priv->iw_mode;
+	return 0;
+}
+
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_point *rrq,
+				    char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	struct iw_range *range = (struct iw_range *) extra;
+	int numrates;
+	int i, k;
+
+	TRACE_ENTER(dev->name);
+
+	rrq->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(struct iw_range));
+
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = 14;
+
+	/* Set available channels/frequencies */
+	range->num_channels = NUM_CHANNELS;
+	k = 0;
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (priv->channel_mask & (1 << i)) {
+			range->freq[k].i = i + 1;
+			range->freq[k].m = channel_frequency[i] * 100000;
+			range->freq[k].e = 1;
+			k++;
+		}
+		
+		if (k >= IW_MAX_FREQUENCIES)
+			break;
+	}
+	range->num_frequency = k;
+	range->sensitivity = 3;
+
+	if (priv->has_wep) {
+		range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+		range->encoding_size[0] = SMALL_KEY_SIZE;
+		range->num_encoding_sizes = 1;
 
 		if (priv->has_big_wep) {
-			range.encoding_size[1] = LARGE_KEY_SIZE;
-			range.num_encoding_sizes = 2;
+			range->encoding_size[1] = LARGE_KEY_SIZE;
+			range->num_encoding_sizes = 2;
 		}
+	}
+
+	if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
+		/* Quality stats meaningless in ad-hoc mode */
 	} else {
-		range.num_encoding_sizes = 0;
-		range.max_encoding_tokens = 0;
+		range->max_qual.qual = 0x8b - 0x2f;
+		range->max_qual.level = 0x2f - 0x95 - 1;
+		range->max_qual.noise = 0x2f - 0x95 - 1;
+#if WIRELESS_EXT > 11
+		/* Need to get better values */
+		range->avg_qual.qual = 0x24;
+		range->avg_qual.level = 0xC2;
+		range->avg_qual.noise = 0x9E;
+#endif /* WIRELESS_EXT > 11 */
 	}
-	orinoco_unlock(priv, &flags);
-		
-	range.min_pmp = 0;
-	range.max_pmp = 65535000;
-	range.min_pmt = 0;
-	range.max_pmt = 65535 * 1000;	/* ??? */
-	range.pmp_flags = IW_POWER_PERIOD;
-	range.pmt_flags = IW_POWER_TIMEOUT;
-	range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-	range.num_txpower = 1;
-	range.txpower[0] = 15; /* 15dBm */
-	range.txpower_capa = IW_TXPOW_DBM;
-
-	range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-	range.retry_flags = IW_RETRY_LIMIT;
-	range.r_time_flags = IW_RETRY_LIFETIME;
-	range.min_retry = 0;
-	range.max_retry = 65535;	/* ??? */
-	range.min_r_time = 0;
-	range.max_r_time = 65535 * 1000;	/* ??? */
 
-	if (copy_to_user(rrq->pointer, &range, sizeof(range)))
-		return -EFAULT;
+	err = orinoco_hw_get_bitratelist(priv, &numrates,
+					 range->bitrate, IW_MAX_BITRATES);
+	if (err)
+		return err;
+	range->num_bitrates = numrates;
+
+	/* Set an indication of the max TCP throughput in bit/s that we can
+	 * expect using this interface. May be use for QoS stuff...
+	 * Jean II */
+	if (numrates > 2)
+		range->throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
+	else
+		range->throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
+
+	range->min_rts = 0;
+	range->max_rts = 2347;
+	range->min_frag = 256;
+	range->max_frag = 2346;
+
+	range->min_pmp = 0;
+	range->max_pmp = 65535000;
+	range->min_pmt = 0;
+	range->max_pmt = 65535 * 1000;	/* ??? */
+	range->pmp_flags = IW_POWER_PERIOD;
+	range->pmt_flags = IW_POWER_TIMEOUT;
+	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->r_time_flags = IW_RETRY_LIFETIME;
+	range->min_retry = 0;
+	range->max_retry = 65535;	/* ??? */
+	range->min_r_time = 0;
+	range->max_r_time = 65535 * 1000;	/* ??? */
 
 	TRACE_EXIT(dev->name);
 
 	return 0;
 }
 
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq,
+				     char *keybuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
@@ -2763,35 +2882,25 @@
 	int enable = priv->wep_on;
 	int restricted = priv->wep_restrict;
 	u16 xlen = 0;
-	int err = 0;
-	char keybuf[ORINOCO_MAX_KEY_SIZE];
+	int err = -EINPROGRESS;		/* Call commit handler */
 	unsigned long flags;
 	
+	if (! priv->has_wep)
+		return -EOPNOTSUPP;
+
 	if (erq->pointer) {
-		/* We actually have a key to set */
-		if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > ORINOCO_MAX_KEY_SIZE) )
-			return -EINVAL;
-		
-		if (copy_from_user(keybuf, erq->pointer, erq->length))
-			return -EFAULT;
+		/* We actually have a key to set - check its length */
+		if (erq->length > LARGE_KEY_SIZE)
+			return -E2BIG;
+
+		if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
+			return -E2BIG;
 	}
 	
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 	
 	if (erq->pointer) {
-		if (erq->length > ORINOCO_MAX_KEY_SIZE) {
-			err = -E2BIG;
-			goto out;
-		}
-		
-		if ( (erq->length > LARGE_KEY_SIZE)
-		     || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE))  ) {
-			err = -EINVAL;
-			goto out;
-		}
-		
 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 			index = priv->tx_key;
 
@@ -2829,7 +2938,6 @@
 	
 	if (erq->flags & IW_ENCODE_DISABLED)
 		enable = 0;
-	/* Only for Prism2 & Symbol cards (so far) - Jean II */
 	if (erq->flags & IW_ENCODE_OPEN)
 		restricted = 0;
 	if (erq->flags & IW_ENCODE_RESTRICTED)
@@ -2842,6 +2950,15 @@
 		memcpy(priv->keys[index].data, keybuf, erq->length);
 	}
 	priv->tx_key = setindex;
+
+	/* Try fast key change if connected and only keys are changed */
+	if (priv->wep_on && enable && (priv->wep_restrict == restricted) &&
+	    netif_carrier_ok(dev)) {
+		err = __orinoco_hw_setup_wepkeys(priv);
+		/* No need to commit if successful */
+		goto out;
+	}
+
 	priv->wep_on = enable;
 	priv->wep_restrict = restricted;
 
@@ -2851,18 +2968,21 @@
 	return err;
 }
 
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq,
+				     char *keybuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	u16 xlen = 0;
-	char keybuf[ORINOCO_MAX_KEY_SIZE];
-	int err;
 	unsigned long flags;
-	
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+
+	if (! priv->has_wep)
+		return -EOPNOTSUPP;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 		index = priv->tx_key;
@@ -2872,69 +2992,60 @@
 		erq->flags |= IW_ENCODE_DISABLED;
 	erq->flags |= index + 1;
 	
-	/* Only for symbol cards - Jean II */
-	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-		if(priv->wep_restrict)
-			erq->flags |= IW_ENCODE_RESTRICTED;
-		else
-			erq->flags |= IW_ENCODE_OPEN;
-	}
+	if (priv->wep_restrict)
+		erq->flags |= IW_ENCODE_RESTRICTED;
+	else
+		erq->flags |= IW_ENCODE_OPEN;
 
 	xlen = le16_to_cpu(priv->keys[index].len);
 
 	erq->length = xlen;
 
-	if (erq->pointer) {
-		memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
-	}
-	
-	orinoco_unlock(priv, &flags);
+	memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
 
-	if (erq->pointer) {
-		if (copy_to_user(erq->pointer, keybuf, xlen))
-			return -EFAULT;
-	}
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
 
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_point *erq,
+				  char *essidbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
-	int err;
 	unsigned long flags;
 
 	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
 	 * anyway... - Jean II */
 
-	memset(&essidbuf, 0, sizeof(essidbuf));
-
-	if (erq->flags) {
-		if (erq->length > IW_ESSID_MAX_SIZE)
-			return -E2BIG;
-		
-		if (copy_from_user(&essidbuf, erq->pointer, erq->length))
-			return -EFAULT;
+	/* Hum... Should not use Wireless Extension constant (may change),
+	 * should use our own... - Jean II */
+	if (erq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
 
-		essidbuf[erq->length] = '\0';
-	}
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
 
-	memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
+	/* If not ANY, get the new ESSID */
+	if (erq->flags) {
+		memcpy(priv->desired_essid, essidbuf, erq->length);
+	}
 
 	orinoco_unlock(priv, &flags);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_point *erq,
+				  char *essidbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
 	int active;
 	int err = 0;
 	unsigned long flags;
@@ -2946,86 +3057,74 @@
 		if (err)
 			return err;
 	} else {
-		err = orinoco_lock(priv, &flags);
-		if (err)
-			return err;
-		memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
+		if (orinoco_lock(priv, &flags) != 0)
+			return -EBUSY;
+		memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
 		orinoco_unlock(priv, &flags);
 	}
 
 	erq->flags = 1;
 	erq->length = strlen(essidbuf) + 1;
-	if (erq->pointer)
-		if (copy_to_user(erq->pointer, essidbuf, erq->length))
-			return -EFAULT;
 
 	TRACE_EXIT(dev->name);
 	
 	return 0;
 }
 
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *nrq,
+				 char *nickbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
-	int err;
 	unsigned long flags;
 
 	if (nrq->length > IW_ESSID_MAX_SIZE)
 		return -E2BIG;
 
-	memset(nickbuf, 0, sizeof(nickbuf));
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
-	if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
-		return -EFAULT;
-
-	nickbuf[nrq->length] = '\0';
-	
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
-
-	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+	memset(priv->nick, 0, sizeof(priv->nick));
+	memcpy(priv->nick, nickbuf, nrq->length);
 
 	orinoco_unlock(priv, &flags);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *nrq,
+				 char *nickbuf)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
-	int err;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
 	orinoco_unlock(priv, &flags);
 
 	nrq->length = strlen(nickbuf)+1;
 
-	if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
-		return -EFAULT;
-
 	return 0;
 }
 
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_freq *frq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int chan = -1;
-	int err;
 	unsigned long flags;
+	int err = -EINPROGRESS;		/* Call commit handler */
 
-	/* We can only use this in Ad-Hoc demo mode to set the operating
-	 * frequency, or in IBSS mode to set the frequency where the IBSS
-	 * will be created - Jean II */
-	if (priv->iw_mode != IW_MODE_ADHOC)
-		return -EOPNOTSUPP;
+	/* In infrastructure mode the AP sets the channel */
+	if (priv->iw_mode == IW_MODE_INFRA)
+		return -EBUSY;
 
 	if ( (frq->e == 0) && (frq->m <= 1000) ) {
 		/* Setting by channel number */
@@ -3047,16 +3146,39 @@
 	     ! (priv->channel_mask & (1 << (chan-1)) ) )
 		return -EINVAL;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
 	priv->channel = chan;
 	orinoco_unlock(priv, &flags);
 
+	return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_freq *frq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int tmp;
+
+	/* Locking done in there */
+	tmp = orinoco_hw_get_freq(priv);
+	if (tmp < 0) {
+		return tmp;
+	}
+
+	frq->m = tmp;
+	frq->e = 1;
+
 	return 0;
 }
 
-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_getsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3067,9 +3189,9 @@
 	if (!priv->has_sensitivity)
 		return -EOPNOTSUPP;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
 	err = hermes_read_wordrec(hw, USER_BAP,
 				  HERMES_RID_CNFSYSTEMSCALE, &val);
 	orinoco_unlock(priv, &flags);
@@ -3083,11 +3205,13 @@
 	return 0;
 }
 
-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_setsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int val = srq->value;
-	int err;
 	unsigned long flags;
 
 	if (!priv->has_sensitivity)
@@ -3096,20 +3220,22 @@
 	if ((val < 1) || (val > 3))
 		return -EINVAL;
 	
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
 	priv->ap_density = val;
 	orinoco_unlock(priv, &flags);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrts(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_param *rrq,
+				char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int val = rrq->value;
-	int err;
 	unsigned long flags;
 
 	if (rrq->disabled)
@@ -3118,25 +3244,39 @@
 	if ( (val < 0) || (val > 2347) )
 		return -EINVAL;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	priv->rts_thresh = val;
 	orinoco_unlock(priv, &flags);
 
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_param *rrq,
+				char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	rrq->value = priv->rts_thresh;
+	rrq->disabled = (rrq->value == 2347);
+	rrq->fixed = 1;
 	return 0;
 }
 
-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *frq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
+	int err = -EINPROGRESS;		/* Call commit handler */
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	if (priv->has_mwo) {
 		if (frq->disabled)
@@ -3164,18 +3304,20 @@
 	return err;
 }
 
-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *frq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
-	int err = 0;
+	int err;
 	u16 val;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
-	
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
 	if (priv->has_mwo) {
 		err = hermes_read_wordrec(hw, USER_BAP,
 					  HERMES_RID_CNFMWOROBUST_AGERE,
@@ -3187,7 +3329,8 @@
 		frq->disabled = ! val;
 		frq->fixed = 0;
 	} else {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
 					  &val);
 		if (err)
 			val = 0;
@@ -3202,10 +3345,12 @@
 	return err;
 }
 
-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *rrq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
 	int ratemode = -1;
 	int bitrate; /* 100s of kilobits */
 	int i;
@@ -3236,16 +3381,19 @@
 	if (ratemode == -1)
 		return -EINVAL;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
 	priv->bitratemode = ratemode;
 	orinoco_unlock(priv, &flags);
 
-	return err;
+	return -EINPROGRESS;
 }
 
-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *rrq,
+				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3255,9 +3403,8 @@
 	u16 val;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	ratemode = priv->bitratemode;
 
@@ -3311,15 +3458,17 @@
 	return err;
 }
 
-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_setpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *prq,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int err = 0;
+	int err = -EINPROGRESS;		/* Call commit handler */
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	if (prq->disabled) {
 		priv->pm_on = 0;
@@ -3364,7 +3513,10 @@
 	return err;
 }
 
-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_getpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *prq,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3372,9 +3524,8 @@
 	u16 enable, period, timeout, mcast;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 	
 	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable);
 	if (err)
@@ -3413,7 +3564,10 @@
 	return err;
 }
 
-static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getretry(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *rrq,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
@@ -3421,9 +3575,8 @@
 	u16 short_limit, long_limit, lifetime;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 	
 	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
 				  &short_limit);
@@ -3465,16 +3618,41 @@
 	return err;
 }
 
-static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_reset(struct net_device *dev,
+			       struct iw_request_info *info,
+			       void *wrqu,
+			       char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int val = *( (int *) wrq->u.name );
-	int err;
+
+	if (! capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
+		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+		/* Firmware reset */
+		orinoco_reset(dev);
+	} else {
+		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+		schedule_work(&priv->reset_work);
+	}
+
+	return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int val = *( (int *) extra );
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	priv->ibss_port = val ;
 
@@ -3482,36 +3660,33 @@
 	set_port_type(priv);
 
 	orinoco_unlock(priv, &flags);
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int *val = (int *)wrq->u.name;
-	int err;
-	unsigned long flags;
-
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	int *val = (int *) extra;
 
 	*val = priv->ibss_port;
-	orinoco_unlock(priv, &flags);
-
 	return 0;
 }
 
-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  void *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int val = *( (int *) wrq->u.name );
+	int val = *( (int *) extra );
 	int err = 0;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	switch (val) {
 	case 0: /* Try to do IEEE ad-hoc mode */
@@ -3535,57 +3710,133 @@
 		err = -EINVAL;
 	}
 
-	if (! err)
+	if (! err) {
 		/* Actually update the mode we are using */
 		set_port_type(priv);
+		err = -EINPROGRESS;
+	}
 
 	orinoco_unlock(priv, &flags);
 
 	return err;
 }
 
-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  void *wrqu,
+				  char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int *val = (int *) extra;
+
+	*val = priv->prefer_port3;
+	return 0;
+}
+
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	int val;
+
+	if (! priv->has_preamble)
+		return -EOPNOTSUPP;
+
+	/* 802.11b has recently defined some short preamble.
+	 * Basically, the Phy header has been reduced in size.
+	 * This increase performance, especially at high rates
+	 * (the preamble is transmitted at 1Mb/s), unfortunately
+	 * this give compatibility troubles... - Jean II */
+	val = *( (int *) extra );
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	if (val)
+		priv->preamble = 1;
+	else
+		priv->preamble = 0;
+
+	orinoco_unlock(priv, &flags);
+
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     void *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int *val = (int *) extra;
+
+	if (! priv->has_preamble)
+		return -EOPNOTSUPP;
+
+	*val = priv->preamble;
+	return 0;
+}
+
+/* ioctl interface to hermes_read_ltv()
+ * To use with iwpriv, pass the RID as the token argument, e.g.
+ * iwpriv get_rid [0xfc00]
+ * At least Wireless Tools 25 is required to use iwpriv.
+ * For Wireless Tools 25 and 26 append "dummy" are the end. */
+static int orinoco_ioctl_getrid(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_point *data,
+				char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int *val = (int *)wrq->u.name;
+	hermes_t *hw = &priv->hw;
+	int rid = data->flags;
+	u16 length;
 	int err;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
+	/* It's a "get" function, but we don't want users to access the
+	 * WEP key and other raw firmware data */
+	if (! capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (rid < 0xfc00 || rid > 0xffff)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+			      extra);
 	if (err)
-		return err;
+		goto out;
 
-	*val = priv->prefer_port3;
+	data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
+			     MAX_RID_LEN);
+
+ out:
 	orinoco_unlock(priv, &flags);
-	return 0;
+	return err;
 }
 
 /* Spy is used for link quality/strength measurements in Ad-Hoc mode
  * Jean II */
-static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_setspy(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_point *srq,
+				char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	struct sockaddr address[IW_MAX_SPY];
+	struct sockaddr *address = (struct sockaddr *) extra;
 	int number = srq->length;
 	int i;
-	int err = 0;
 	unsigned long flags;
 
-	/* Check the number of addresses */
-	if (number > IW_MAX_SPY)
-		return -E2BIG;
-
-	/* Get the data in the driver */
-	if (srq->pointer) {
-		if (copy_from_user(address, srq->pointer,
-				   sizeof(struct sockaddr) * number))
-			return -EFAULT;
-	}
-
 	/* Make sure nobody mess with the structure while we do */
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	/* orinoco_lock() doesn't disable interrupts, so make sure the
 	 * interrupt rx path don't get confused while we copy */
@@ -3606,25 +3857,32 @@
 	/* Now, let the others play */
 	orinoco_unlock(priv, &flags);
 
-	return err;
+	/* Do NOT call commit handler */
+	return 0;
 }
 
-static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_getspy(struct net_device *dev,
+				struct iw_request_info *info,
+				struct iw_point *srq,
+				char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	struct sockaddr address[IW_MAX_SPY];
-	struct iw_quality spy_stat[IW_MAX_SPY];
+	struct sockaddr *address = (struct sockaddr *) extra;
 	int number;
 	int i;
-	int err;
 	unsigned long flags;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
 
 	number = priv->spy_number;
-	if ((number > 0) && (srq->pointer)) {
+	/* Create address struct */
+	for (i = 0; i < number; i++) {
+		memcpy(address[i].sa_data, priv->spy_address[i],
+		       ETH_ALEN);
+		address[i].sa_family = AF_UNIX;
+	}
+	if (number > 0) {
 		/* Create address struct */
 		for (i = 0; i < number; i++) {
 			memcpy(address[i].sa_data, priv->spy_address[i],
@@ -3633,217 +3891,380 @@
 		}
 		/* Copy stats */
 		/* In theory, we should disable irqs while copying the stats
-		 * because the rx path migh update it in the middle...
+		 * because the rx path might update it in the middle...
 		 * Bah, who care ? - Jean II */
-		memcpy(&spy_stat, priv->spy_stat,
-		       sizeof(struct iw_quality) * IW_MAX_SPY);
-		for (i=0; i < number; i++)
-			priv->spy_stat[i].updated = 0;
+		memcpy(extra  + (sizeof(struct sockaddr) * number),
+		       priv->spy_stat, sizeof(struct iw_quality) * number);
 	}
+	/* Reset updated flags. */
+	for (i = 0; i < number; i++)
+		priv->spy_stat[i].updated = 0;
 
 	orinoco_unlock(priv, &flags);
 
-	/* Push stuff to user space */
 	srq->length = number;
-	if(copy_to_user(srq->pointer, address,
-			 sizeof(struct sockaddr) * number))
-		return -EFAULT;
-	if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
-			&spy_stat, sizeof(struct iw_quality) * number))
-		return -EFAULT;
 
 	return 0;
 }
 
-static int
-orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/* Commit handler, called after set operations */
+static int orinoco_ioctl_commit(struct net_device *dev,
+				struct iw_request_info *info,
+				void *wrqu,
+				char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	unsigned long flags;
+	int err = 0;
+
+	if (!priv->open)
+		return 0;
+
+	if (priv->broken_disableport) {
+		orinoco_reset(dev);
+		return 0;
+	}
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return err;
+
+	err = hermes_disable_port(hw, 0);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to disable port "
+		       "while reconfiguring card\n", dev->name);
+		priv->broken_disableport = 1;
+		goto out;
+	}
+
+	err = __orinoco_program_rids(dev);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+		       dev->name);
+		goto out;
+	}
+
+	err = hermes_enable_port(hw, 0);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+		       dev->name);
+		goto out;
+	}
+
+ out:
+	if (err) {
+		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+		schedule_work(&priv->reset_work);
+		err = 0;
+	}
+
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+static const struct iw_priv_args orinoco_privtab[] = {
+	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+	{ SIOCIWFIRSTPRIV + 0x2,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_port3" },
+	{ SIOCIWFIRSTPRIV + 0x3, 0,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_port3" },
+	{ SIOCIWFIRSTPRIV + 0x4,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x5, 0,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x6,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_ibssport" },
+	{ SIOCIWFIRSTPRIV + 0x7, 0,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_ibssport" },
+	{ SIOCIWFIRSTPRIV + 0x9, 0,
+	  IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
+	  "get_rid" },
+};
+
+#if WIRELESS_EXT > 12
+
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const iw_handler		orinoco_handler[] =
+{
+	(iw_handler) orinoco_ioctl_commit,		/* SIOCSIWCOMMIT */
+	(iw_handler) orinoco_ioctl_getname,		/* SIOCGIWNAME */
+	(iw_handler) NULL,				/* SIOCSIWNWID */
+	(iw_handler) NULL,				/* SIOCGIWNWID */
+	(iw_handler) orinoco_ioctl_setfreq,		/* SIOCSIWFREQ */
+	(iw_handler) orinoco_ioctl_getfreq,		/* SIOCGIWFREQ */
+	(iw_handler) orinoco_ioctl_setmode,		/* SIOCSIWMODE */
+	(iw_handler) orinoco_ioctl_getmode,		/* SIOCGIWMODE */
+	(iw_handler) orinoco_ioctl_setsens,		/* SIOCSIWSENS */
+	(iw_handler) orinoco_ioctl_getsens,		/* SIOCGIWSENS */
+	(iw_handler) NULL,				/* SIOCSIWRANGE */
+	(iw_handler) orinoco_ioctl_getiwrange,		/* SIOCGIWRANGE */
+	(iw_handler) NULL,				/* SIOCSIWPRIV */
+	(iw_handler) NULL,				/* SIOCGIWPRIV */
+	(iw_handler) NULL,				/* SIOCSIWSTATS */
+	(iw_handler) NULL,				/* SIOCGIWSTATS */
+	(iw_handler) orinoco_ioctl_setspy,		/* SIOCSIWSPY */
+	(iw_handler) orinoco_ioctl_getspy,		/* SIOCGIWSPY */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) orinoco_ioctl_setwap,		/* SIOCSIWAP */
+	(iw_handler) orinoco_ioctl_getwap,		/* SIOCGIWAP */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+	(iw_handler) NULL,		/* SIOCSIWSCAN */
+	(iw_handler) NULL,		/* SIOCGIWSCAN */
+#else	/* WIRELESS_EXT > 13 */
+	(iw_handler) NULL,				/* SIOCSIWSCAN */
+	(iw_handler) NULL,				/* SIOCGIWSCAN */
+#endif	/* WIRELESS_EXT > 13 */
+	(iw_handler) orinoco_ioctl_setessid,		/* SIOCSIWESSID */
+	(iw_handler) orinoco_ioctl_getessid,		/* SIOCGIWESSID */
+	(iw_handler) orinoco_ioctl_setnick,		/* SIOCSIWNICKN */
+	(iw_handler) orinoco_ioctl_getnick,		/* SIOCGIWNICKN */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) orinoco_ioctl_setrate,		/* SIOCSIWRATE */
+	(iw_handler) orinoco_ioctl_getrate,		/* SIOCGIWRATE */
+	(iw_handler) orinoco_ioctl_setrts,		/* SIOCSIWRTS */
+	(iw_handler) orinoco_ioctl_getrts,		/* SIOCGIWRTS */
+	(iw_handler) orinoco_ioctl_setfrag,		/* SIOCSIWFRAG */
+	(iw_handler) orinoco_ioctl_getfrag,		/* SIOCGIWFRAG */
+	(iw_handler) NULL,				/* SIOCSIWTXPOW */
+	(iw_handler) NULL,				/* SIOCGIWTXPOW */
+	(iw_handler) NULL,				/* SIOCSIWRETRY */
+	(iw_handler) orinoco_ioctl_getretry,		/* SIOCGIWRETRY */
+	(iw_handler) orinoco_ioctl_setiwencode,		/* SIOCSIWENCODE */
+	(iw_handler) orinoco_ioctl_getiwencode,		/* SIOCGIWENCODE */
+	(iw_handler) orinoco_ioctl_setpower,		/* SIOCSIWPOWER */
+	(iw_handler) orinoco_ioctl_getpower,		/* SIOCGIWPOWER */
+};
+
+/*
+  Added typecasting since we no longer use iwreq_data -- Moustafa
+ */
+static const iw_handler		orinoco_private_handler[] =
+{
+	(iw_handler) orinoco_ioctl_reset,		/* SIOCIWFIRSTPRIV */
+	(iw_handler) orinoco_ioctl_reset,		/* SIOCIWFIRSTPRIV + 1 */
+	(iw_handler) orinoco_ioctl_setport3,		/* SIOCIWFIRSTPRIV + 2 */
+	(iw_handler) orinoco_ioctl_getport3,		/* SIOCIWFIRSTPRIV + 3 */
+	(iw_handler) orinoco_ioctl_setpreamble,		/* SIOCIWFIRSTPRIV + 4 */
+	(iw_handler) orinoco_ioctl_getpreamble,		/* SIOCIWFIRSTPRIV + 5 */
+	(iw_handler) orinoco_ioctl_setibssport,		/* SIOCIWFIRSTPRIV + 6 */
+	(iw_handler) orinoco_ioctl_getibssport,		/* SIOCIWFIRSTPRIV + 7 */
+	(iw_handler) NULL,				/* SIOCIWFIRSTPRIV + 8 */
+	(iw_handler) orinoco_ioctl_getrid		/* SIOCIWFIRSTPRIV + 9 */
+};
+
+static const struct iw_handler_def	orinoco_handler_def =
+{
+	.num_standard = sizeof(orinoco_handler) / sizeof(iw_handler),
+	.num_private = sizeof(orinoco_private_handler) 	/ sizeof(iw_handler),
+	.num_private_args = sizeof(orinoco_privtab) / sizeof(struct iw_priv_args),
+	.standard = (iw_handler *) orinoco_handler,
+	.private = (iw_handler *) orinoco_private_handler,
+	.private_args = (struct iw_priv_args *) orinoco_privtab,
+};
+#endif /* WIRELESS_EXT > 12 */
+
+#if WIRELESS_EXT <= 12
+/* Old style support for wireless extensions */
+static int orinoco_ioctl_we_old(struct net_device *dev, struct ifreq *rq, int cmd)
+{
 	struct iwreq *wrq = (struct iwreq *)rq;
 	int err = 0;
-	int tmp;
-	int changed = 0;
-	unsigned long flags;
 
 	TRACE_ENTER(dev->name);
 
-	/* In theory, we could allow most of the the SET stuff to be
-	 * done. In practice, the lapse of time at startup when the
-	 * card is not ready is very short, so why bother...  Note
-	 * that netif_device_present is different from up/down
-	 * (ifconfig), when the device is not yet up, it is usually
-	 * already ready...  Jean II */
-	if (! netif_device_present(dev))
-		return -ENODEV;
-
 	switch (cmd) {
 	case SIOCGIWNAME:
-		strcpy(wrq->u.name, "IEEE 802.11-DS");
+		err = orinoco_ioctl_getname(dev, NULL, wrq->u.name, NULL);
 		break;
 		
 	case SIOCGIWAP:
-		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-		err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
+		err = orinoco_ioctl_getwap(dev, NULL, &wrq->u.ap_addr, NULL);
 		break;
 
 	case SIOCGIWRANGE:
-		err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
+		{
+			struct iw_range range;
+			err = orinoco_ioctl_getiwrange(dev, NULL,
+						       &(wrq->u.data),
+						       (char *) &range);
+			if (copy_to_user(wrq->u.data.pointer, &range,
+					 sizeof(struct iw_range)))
+				err = -EFAULT;
+		}
 		break;
 
 	case SIOCSIWMODE:
-		err = orinoco_lock(priv, &flags);
-		if (err)
-			return err;
-		switch (wrq->u.mode) {
-		case IW_MODE_ADHOC:
-			if (! (priv->has_ibss || priv->has_port3) )
-				err = -EINVAL;
-			else {
-				priv->iw_mode = IW_MODE_ADHOC;
-				changed = 1;
-			}
-			break;
-
-		case IW_MODE_INFRA:
-			priv->iw_mode = IW_MODE_INFRA;
-			changed = 1;
-			break;
-
-		default:
-			err = -EINVAL;
-			break;
-		}
-		set_port_type(priv);
-		orinoco_unlock(priv, &flags);
+		err = orinoco_ioctl_setmode(dev, NULL, &wrq->u.mode, NULL);
 		break;
 
 	case SIOCGIWMODE:
-		err = orinoco_lock(priv, &flags);
-		if (err)
-			return err;
-		wrq->u.mode = priv->iw_mode;
-		orinoco_unlock(priv, &flags);
+		err = orinoco_ioctl_getmode(dev, NULL, &wrq->u.mode, NULL);
 		break;
 
 	case SIOCSIWENCODE:
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
+		{
+			char keybuf[ORINOCO_MAX_KEY_SIZE];
+			if (wrq->u.encoding.pointer) {
+				/* We actually have a key to set */
+				if (wrq->u.encoding.length > ORINOCO_MAX_KEY_SIZE) {
+					err = -E2BIG;
+					break;
+				}
+				if (copy_from_user(keybuf,
+						   wrq->u.encoding.pointer,
+						   wrq->u.encoding.length)) {
+					err = -EFAULT;
+					break;
+				}
+			} else if (wrq->u.encoding.length != 0) {
+				err = -EINVAL;
+				break;
+			}
+			err = orinoco_ioctl_setiwencode(dev, NULL,
+							&(wrq->u.encoding),
+							keybuf);
 		}
-
-		err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
-		if (! err)
-			changed = 1;
 		break;
 
 	case SIOCGIWENCODE:
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
-		}
-
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
+		{
+			char keybuf[ORINOCO_MAX_KEY_SIZE];
+			err = orinoco_ioctl_getiwencode(dev, NULL,
+							&(wrq->u.encoding),
+							keybuf);
+			if (wrq->u.encoding.pointer) {
+				if (copy_to_user(wrq->u.encoding.pointer,
+						 keybuf,
+						 wrq->u.encoding.length))
+					err = -EFAULT;
+			}
 		}
-
-		err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding);
 		break;
 
 	case SIOCSIWESSID:
-		err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
-		if (! err)
-			changed = 1;
+		{
+			char essidbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
+				err = -E2BIG;
+				break;
+			}
+			if (copy_from_user(essidbuf, wrq->u.essid.pointer,
+					   wrq->u.essid.length)) {
+				err = -EFAULT;
+				break;
+			}
+			err = orinoco_ioctl_setessid(dev, NULL,
+						     &(wrq->u.essid),
+						     essidbuf);
+		}
 		break;
 
 	case SIOCGIWESSID:
-		err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
+		{
+			char essidbuf[IW_ESSID_MAX_SIZE+1];
+			err = orinoco_ioctl_getessid(dev, NULL,
+						     &(wrq->u.essid),
+						     essidbuf);
+			if (wrq->u.essid.pointer)
+				if ( copy_to_user(wrq->u.essid.pointer,
+						  essidbuf,
+						  wrq->u.essid.length) )
+					err = -EFAULT;
+		}
 		break;
 
 	case SIOCSIWNICKN:
-		err = orinoco_ioctl_setnick(dev, &wrq->u.data);
-		if (! err)
-			changed = 1;
+		{
+			char nickbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
+				err = -E2BIG;
+				break;
+			}
+			if (copy_from_user(nickbuf, wrq->u.essid.pointer,
+					   wrq->u.essid.length)) {
+				err = -EFAULT;
+				break;
+			}
+			err = orinoco_ioctl_setnick(dev, NULL, &(wrq->u.essid),
+						    nickbuf);
+		}
 		break;
 
 	case SIOCGIWNICKN:
-		err = orinoco_ioctl_getnick(dev, &wrq->u.data);
+		{
+			char nickbuf[IW_ESSID_MAX_SIZE+1];
+			err = orinoco_ioctl_getnick(dev, NULL, &(wrq->u.essid),
+						    nickbuf);
+			if (wrq->u.essid.pointer)
+				if ( copy_to_user(wrq->u.essid.pointer,
+						  nickbuf,
+						  wrq->u.essid.length) )
+					err = -EFAULT;
+		}
 		break;
 
 	case SIOCGIWFREQ:
-		tmp = orinoco_hw_get_freq(priv);
-		if (tmp < 0) {
-			err = tmp;
-		} else {
-			wrq->u.freq.m = tmp;
-			wrq->u.freq.e = 1;
-		}
+		err = orinoco_ioctl_getfreq(dev, NULL, &(wrq->u.freq), NULL);
 		break;
 
 	case SIOCSIWFREQ:
-		err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setfreq(dev, NULL, &(wrq->u.freq), NULL);
 		break;
 
 	case SIOCGIWSENS:
-		err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
+		err = orinoco_ioctl_getsens(dev, NULL, &(wrq->u.sens), NULL);
 		break;
 
 	case SIOCSIWSENS:
-		err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setsens(dev, NULL, &(wrq->u.sens), NULL);
 		break;
 
 	case SIOCGIWRTS:
-		wrq->u.rts.value = priv->rts_thresh;
-		wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
-		wrq->u.rts.fixed = 1;
+		err = orinoco_ioctl_getrts(dev, NULL, &(wrq->u.rts), NULL);
 		break;
 
 	case SIOCSIWRTS:
-		err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setrts(dev, NULL, &(wrq->u.rts), NULL);
 		break;
 
 	case SIOCSIWFRAG:
-		err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setfrag(dev, NULL, &(wrq->u.frag), NULL);
 		break;
 
 	case SIOCGIWFRAG:
-		err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
+		err = orinoco_ioctl_getfrag(dev, NULL, &(wrq->u.frag), NULL);
 		break;
 
 	case SIOCSIWRATE:
-		err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setrate(dev, NULL, &(wrq->u.bitrate),
+					    NULL);
 		break;
 
 	case SIOCGIWRATE:
-		err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
+		err = orinoco_ioctl_getrate(dev, NULL, &(wrq->u.bitrate),
+					    NULL);
 		break;
 
 	case SIOCSIWPOWER:
-		err = orinoco_ioctl_setpower(dev, &wrq->u.power);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setpower(dev, NULL, &(wrq->u.power), NULL);
 		break;
 
 	case SIOCGIWPOWER:
-		err = orinoco_ioctl_getpower(dev, &wrq->u.power);
-		break;
-
-	case SIOCGIWTXPOW:
-		/* The card only supports one tx power, so this is easy */
-		wrq->u.txpower.value = 15; /* dBm */
-		wrq->u.txpower.fixed = 1;
-		wrq->u.txpower.disabled = 0;
-		wrq->u.txpower.flags = IW_TXPOW_DBM;
+		err = orinoco_ioctl_getpower(dev, NULL, &(wrq->u.power), NULL);
 		break;
 
 	case SIOCSIWRETRY:
@@ -3851,143 +4272,173 @@
 		break;
 
 	case SIOCGIWRETRY:
-		err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
+		err = orinoco_ioctl_getretry(dev, NULL, &(wrq->u.retry), NULL);
 		break;
 
 	case SIOCSIWSPY:
-		err = orinoco_ioctl_setspy(dev, &wrq->u.data);
+		{
+			struct sockaddr address[IW_MAX_SPY];
+			/* Check the number of addresses */
+			if (wrq->u.data.length > IW_MAX_SPY) {
+				err = -E2BIG;
+				break;
+			}
+			/* Get the data in the driver */
+			if (wrq->u.data.pointer) {
+				if (copy_from_user((char *) address,
+						   wrq->u.data.pointer,
+						   sizeof(struct sockaddr) *
+						   wrq->u.data.length)) {
+					err = -EFAULT;
+					break;
+				}
+			} else if (wrq->u.data.length != 0) {
+				err = -EINVAL;
+				break;
+			}
+			err = orinoco_ioctl_setspy(dev, NULL, &(wrq->u.data),
+						   (char *) address);
+		}
 		break;
 
 	case SIOCGIWSPY:
-		err = orinoco_ioctl_getspy(dev, &wrq->u.data);
+		{
+			char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
+						  sizeof(struct iw_quality))];
+			err = orinoco_ioctl_getspy(dev, NULL, &(wrq->u.data),
+						   buffer);
+			if (wrq->u.data.pointer) {
+				if (copy_to_user(wrq->u.data.pointer,
+						 buffer,
+						 (wrq->u.data.length *
+						  (sizeof(struct sockaddr) +
+						   sizeof(struct iw_quality)))
+						 ))
+					err = -EFAULT;
+			}
+		}
 		break;
 
 	case SIOCGIWPRIV:
 		if (wrq->u.data.pointer) {
-			struct iw_priv_args privtab[] = {
-				{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
-				{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
-				{ SIOCIWFIRSTPRIV + 0x2,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_port3" },
-				{ SIOCIWFIRSTPRIV + 0x3, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_port3" },
-				{ SIOCIWFIRSTPRIV + 0x4,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_preamble" },
-				{ SIOCIWFIRSTPRIV + 0x5, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_preamble" },
-				{ SIOCIWFIRSTPRIV + 0x6,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_ibssport" },
-				{ SIOCIWFIRSTPRIV + 0x7, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_ibssport" },
-				{ SIOCIWLASTPRIV, 0, 0, "dump_recs" },
-			};
-
-			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
-			if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
+			wrq->u.data.length = ARRAY_SIZE(orinoco_privtab);
+			if (copy_to_user(wrq->u.data.pointer,
+					 orinoco_privtab,
+					 sizeof(orinoco_privtab)))
 				err = -EFAULT;
 		}
 		break;
 	       
 	case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
 	case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
+		{
+			struct iw_request_info info;
+			info.cmd = cmd;
+			err = orinoco_ioctl_reset(dev, &info, &(wrq->u),
+						  (char *) &(wrq->u));
 		}
-		
-		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
-
-		schedule_work(&priv->reset_work);
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		err = orinoco_ioctl_setport3(dev, wrq);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setport3(dev, NULL, &(wrq->u),
+					     (char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
-		err = orinoco_ioctl_getport3(dev, wrq);
+		err = orinoco_ioctl_getport3(dev, NULL, &(wrq->u),
+					     (char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		/* 802.11b has recently defined some short preamble.
-		 * Basically, the Phy header has been reduced in size.
-		 * This increase performance, especially at high rates
-		 * (the preamble is transmitted at 1Mb/s), unfortunately
-		 * this give compatibility troubles... - Jean II */
-		if(priv->has_preamble) {
-			int val = *( (int *) wrq->u.name );
-
-			err = orinoco_lock(priv, &flags);
-			if (err)
-				return err;
-			if (val)
-				priv->preamble = 1;
-			else
-				priv->preamble = 0;
-			orinoco_unlock(priv, &flags);
-			changed = 1;
-		} else
-			err = -EOPNOTSUPP;
+		err = orinoco_ioctl_setpreamble(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
-		if(priv->has_preamble) {
-			int *val = (int *)wrq->u.name;
-
-			err = orinoco_lock(priv, &flags);
-			if (err)
-				return err;
-			*val = priv->preamble;
-			orinoco_unlock(priv, &flags);
-		} else
-			err = -EOPNOTSUPP;
+		err = orinoco_ioctl_getpreamble(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
-	case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
 
-		err = orinoco_ioctl_setibssport(dev, wrq);
-		if (! err)
-			changed = 1;
+	case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
+		err = orinoco_ioctl_setibssport(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
-		err = orinoco_ioctl_getibssport(dev, wrq);
+		err = orinoco_ioctl_getibssport(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
 
+	case SIOCIWFIRSTPRIV + 0x9: /* get_rid */
+		{
+			u16 lenght;
+			char *buffer = kmalloc(MAX_RID_LEN, GFP_KERNEL);
+
+			if (!buffer) {
+				err = -ENOMEM;
+				break;
+			}
+			err = orinoco_ioctl_getrid(dev, NULL, &wrq->u.data,
+						   buffer);
+			if (err) {
+				kfree(buffer);
+				break;
+			}
+
+			lenght = min_t(u16, wrq->u.data.length, MAX_RID_LEN);
+			if (copy_to_user(wrq->u.data.pointer, buffer,
+					 lenght) != 0)
+				err = -EFAULT;
+
+			kfree(buffer);
+		}
+		break;
 
 	default:
 		err = -EOPNOTSUPP;
 	}
 	
-	if (! err && changed && netif_running(dev)) {
-		err = orinoco_reconfigure(dev);
-	}		
-
+	if (err == -EINPROGRESS) {
+		if (netif_running(dev))
+			err = orinoco_ioctl_commit(dev, NULL, NULL, NULL);
+		else
+			err = 0;
+	}
 	TRACE_EXIT(dev->name);
 
 	return err;
 }
+#endif /* WIRELESS_EXT > 12 */
+
+static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int err = 0;
+
+	TRACE_ENTER(dev->name);
+
+	/* In theory, we could allow most of the the SET stuff to be
+	 * done. In practice, the lapse of time at startup when the
+	 * card is not ready is very short, so why bother...  Note
+	 * that netif_device_present is different from up/down
+	 * (ifconfig), when the device is not yet up, it is usually
+	 * already ready...  Jean II */
+	if (! netif_device_present(dev))
+		return -ENODEV;
+
+#if WIRELESS_EXT <= 12
+	/* Old style wireless extensions support */
+	if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
+		err = orinoco_ioctl_we_old(dev, rq, cmd);
+	else
+#endif /* WIRELESS_EXT <= 12 */
+	switch (cmd) {
+	default:
+		err = -EOPNOTSUPP;
+	}
+
+	TRACE_EXIT(dev->name);
+	return err;
+}
 
 
 /********************************************************************/
--- a/drivers/net/wireless/orinoco.h.10-wireless-handlers	2004-10-26 11:10:25.446963392 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-10-26 12:42:22.112302784 -0400
@@ -23,6 +23,9 @@
 /* To enable debug messages */
 //#define ORINOCO_DEBUG		3
 
+#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 11)
+#error "orinoco driver requires Wireless extensions v11 or later."
+#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 11) */
 #define WIRELESS_SPY		// enable iwspy support
 
 #define ORINOCO_MAX_KEY_SIZE	14
@@ -61,16 +64,21 @@
 #define FIRMWARE_TYPE_AGERE 1
 #define FIRMWARE_TYPE_INTERSIL 2
 #define FIRMWARE_TYPE_SYMBOL 3
-	int has_ibss, has_port3, has_ibss_any, ibss_port;
-	int has_wep, has_big_wep;
-	int has_mwo;
-	int has_pm;
-	int has_preamble;
-	int has_sensitivity;
+	int ibss_port;
+	int has_ibss_any;
 	int nicbuf_size;
 	u16 channel_mask;
-	int broken_disableport;
 
+	/* Boolean capabilities */
+	unsigned int has_ibss:1;
+	unsigned int has_port3:1;
+	unsigned int has_wep:1;
+	unsigned int has_big_wep:1;
+	unsigned int has_mwo:1;
+	unsigned int has_pm:1;
+	unsigned int has_preamble:1;
+	unsigned int has_sensitivity:1;
+	unsigned int broken_disableport:1;
 	unsigned int irq_no_disable:1;
 
 	/* Configuration paramaters */
@@ -81,6 +89,8 @@
 	int bitratemode;
  	char nick[IW_ESSID_MAX_SIZE+1];
 	char desired_essid[IW_ESSID_MAX_SIZE+1];
+	char desired_bssid[ETH_ALEN];
+	int bssid_fixed;
 	u16 frag_thresh, mwo_robust;
 	u16 channel;
 	u16 ap_density, rts_thresh;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 11/15] wireless/orinoco: Clean up firmware version & capability detection
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (10 preceding siblings ...)
  2004-10-26 19:13 ` [PATCH 2.6.10-rc1 10/15] wireless/orinoco: Use wireless handlers rather than ioctl()s Dan Williams
@ 2004-10-26 19:18 ` Dan Williams
  2004-10-26 19:20 ` [PATCH 2.6.10-rc1 12/15] wireless/orinoco: Use netif routines rather than keeping link state ourselves Dan Williams
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:18 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Clean up firmware version & capability detection

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c.11-firmware-fixes	2004-10-26 15:15:11.454350912 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 15:15:11.456350608 -0400
@@ -1452,7 +1452,7 @@
 		return err;
 
 	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-	if (err == -EIO) {
+	if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
 		/* Try workaround for old Symbol firmware bug */
 		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
 		       "(old Symbol firmware?). Trying to work around... ",
@@ -2098,39 +2098,54 @@
 /* Initialization                                                   */
 /********************************************************************/
 
-struct sta_id {
+struct comp_id {
 	u16 id, variant, major, minor;
 } __attribute__ ((packed));
 
-static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id)
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
 {
-	/* FIXME: this is fundamentally broken */
-	unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor;
-	
-	if (sta_id->variant == 1)
+	if (nic_id->id < 0x8000)
 		return FIRMWARE_TYPE_AGERE;
-	else if ((sta_id->variant == 2) &&
-		   ((firmver == 0x10001) || (firmver == 0x20001)))
+	else if (nic_id->id == 0x8000 && nic_id->major == 0)
 		return FIRMWARE_TYPE_SYMBOL;
 	else
 		return FIRMWARE_TYPE_INTERSIL;
 }
 
-static void determine_firmware(struct net_device *dev)
+/* Set priv->firmware type, determine firmware properties */
+static int determine_firmware(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	int err;
-	struct sta_id sta_id;
+	struct comp_id nic_id, sta_id;
 	unsigned int firmver;
 	char tmp[SYMBOL_MAX_VER_LEN+1];
 
+	/* Get the hardware version */
+	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
+		       dev->name, err);
+		return err;
+	}
+
+	le16_to_cpus(&nic_id.id);
+	le16_to_cpus(&nic_id.variant);
+	le16_to_cpus(&nic_id.major);
+	le16_to_cpus(&nic_id.minor);
+	printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
+	       dev->name, nic_id.id, nic_id.variant,
+	       nic_id.major, nic_id.minor);
+
+	priv->firmware_type = determine_firmware_type(&nic_id);
+
 	/* Get the firmware version */
 	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
 	if (err) {
 		printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
 		       dev->name, err);
-		memset(&sta_id, 0, sizeof(sta_id));
+		return err;
 	}
 
 	le16_to_cpus(&sta_id.id);
@@ -2141,8 +2156,23 @@
 	       dev->name, sta_id.id, sta_id.variant,
 	       sta_id.major, sta_id.minor);
 
-	if (! priv->firmware_type)
-		priv->firmware_type = determine_firmware_type(dev, &sta_id);
+	switch (sta_id.id) {
+	case 0x15:
+		printk(KERN_ERR "%s: Primary firmware is active\n",
+		       dev->name);
+		return -ENODEV;
+	case 0x14b:
+		printk(KERN_ERR "%s: Tertiary firmware is active\n",
+		       dev->name);
+		return -ENODEV;
+	case 0x1f:	/* Intersil, Agere, Symbol Spectrum24 */
+	case 0x21:	/* Symbol Spectrum24 Trilogy */
+		break;
+	default:
+		printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
+		       dev->name);
+		break;
+	}
 
 	/* Default capabilities */
 	priv->has_sensitivity = 1;
@@ -2158,9 +2188,8 @@
 	case FIRMWARE_TYPE_AGERE:
 		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
 		   ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
-		printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware "
-		       "version %d.%02d\n", dev->name,
-		       sta_id.major, sta_id.minor);
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
 
 		firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
 
@@ -2203,16 +2232,19 @@
 			tmp[SYMBOL_MAX_VER_LEN] = '\0';
 		}
 
-		printk(KERN_DEBUG "%s: Looks like a Symbol firmware "
-		       "version [%s] (parsing to %X)\n", dev->name,
-		       tmp, firmver);
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Symbol %s", tmp);
 
 		priv->has_ibss = (firmver >= 0x20000);
 		priv->has_wep = (firmver >= 0x15012);
 		priv->has_big_wep = (firmver >= 0x20000);
-		priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000);
+		priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || 
+			       (firmver >= 0x29000 && firmver < 0x30000) ||
+			       firmver >= 0x31000;
 		priv->has_preamble = (firmver >= 0x20000);
 		priv->ibss_port = 4;
+		priv->broken_disableport = (firmver == 0x25013) ||
+					   (firmver >= 0x30000 && firmver <= 0x31000);
 		/* Tested with Intel firmware : 0x20015 => Jean II */
 		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
 		break;
@@ -2222,9 +2254,9 @@
 		 * different and less well tested */
 		/* D-Link MAC : 00:40:05:* */
 		/* Addtron MAC : 00:90:D1:* */
-		printk(KERN_DEBUG "%s: Looks like an Intersil firmware "
-		       "version %d.%d.%d\n", dev->name,
-		       sta_id.major, sta_id.minor, sta_id.variant);
+		snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+			 "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+			 sta_id.variant);
 
 		firmver = ((unsigned long)sta_id.major << 16) |
 			((unsigned long)sta_id.minor << 8) | sta_id.variant;
@@ -2242,9 +2274,11 @@
 			priv->ibss_port = 1;
 		}
 		break;
-	default:
-		break;
 	}
+	printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
+	       priv->fw_name);
+
+	return 0;
 }
 
 static int orinoco_init(struct net_device *dev)
@@ -2263,14 +2297,19 @@
 	priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
 
 	/* Initialize the firmware */
-	err = hermes_init(hw);
+	err = orinoco_reinit_firmware(dev);
 	if (err != 0) {
 		printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
 		       dev->name, err);
 		goto out;
 	}
 
-	determine_firmware(dev);
+	err = determine_firmware(dev);
+	if (err != 0) {
+		printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+		       dev->name);
+		goto out;
+	}
 
 	if (priv->has_port3)
 		printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name);
@@ -2391,31 +2430,12 @@
 	/* By default use IEEE/IBSS ad-hoc mode if we have it */
 	priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
 	set_port_type(priv);
-	priv->channel = 10; /* default channel, more-or-less arbitrary */
+	priv->channel = 0; /* use firmware default */
 
 	priv->promiscuous = 0;
 	priv->wep_on = 0;
 	priv->tx_key = 0;
 
-	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-	if (err == -EIO) {
-		/* Try workaround for old Symbol firmware bug */
-		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
-		       "(old Symbol firmware?). Trying to work around... ",
-		       dev->name);
-		
-		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-		if (err)
-			printk("failed!\n");
-		else
-			printk("ok.\n");
-	}
-	if (err) {
-		printk("%s: Error %d allocating Tx buffer\n", dev->name, err);
-		goto out;
-	}
-
 	/* Make the hardware available, as long as it hasn't been
 	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
 	orinoco_spin_lock(priv);
--- a/drivers/net/wireless/orinoco.h.11-firmware-fixes	2004-10-26 15:15:11.454350912 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-10-26 15:15:11.456350608 -0400
@@ -36,6 +36,12 @@
 	char data[ORINOCO_MAX_KEY_SIZE];
 } __attribute__ ((packed));
 
+typedef enum {
+	FIRMWARE_TYPE_AGERE,
+	FIRMWARE_TYPE_INTERSIL,
+	FIRMWARE_TYPE_SYMBOL
+} fwtype_t;
+
 struct orinoco_private {
 	void *card;	/* Pointer to card dependent structure */
 	int (*hard_reset)(struct orinoco_private *);
@@ -60,12 +66,9 @@
 	u16 txfid;
 
 	/* Capabilities of the hardware/firmware */
-	int firmware_type;
-#define FIRMWARE_TYPE_AGERE 1
-#define FIRMWARE_TYPE_INTERSIL 2
-#define FIRMWARE_TYPE_SYMBOL 3
+	fwtype_t firmware_type;
+	char fw_name[32];
 	int ibss_port;
-	int has_ibss_any;
 	int nicbuf_size;
 	u16 channel_mask;
 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 12/15] wireless/orinoco: Use netif routines rather than keeping link state ourselves
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (11 preceding siblings ...)
  2004-10-26 19:18 ` [PATCH 2.6.10-rc1 11/15] wireless/orinoco: Clean up firmware version & capability detection Dan Williams
@ 2004-10-26 19:20 ` Dan Williams
  2004-10-26 19:22 ` [PATCH 2.6.10-rc1 13/15] wireless/orinoco: RF monitor mode support Dan Williams
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:20 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Use netif routines rather than keeping link state ourselves

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c.12-netif	2004-10-26 13:09:22.313994688 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 13:20:51.649199808 -0400
@@ -851,7 +851,7 @@
 		return 1;
 	}
 
-	if (! priv->connected) {
+	if (! netif_carrier_ok(dev)) {
 		/* Oops, the firmware hasn't established a connection,
                    silently drop the packet (this seems to be the
                    safest approach). */
@@ -966,8 +966,6 @@
 			printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
 			       dev->name, fid);
 		return;
-	} else {
-		netif_wake_queue(dev);
 	}
 
 	hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
@@ -980,6 +978,8 @@
 
 	stats->tx_packets++;
 
+	netif_wake_queue(dev);
+
 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
@@ -1006,6 +1006,8 @@
 	
 	stats->tx_errors++;
 
+	netif_wake_queue(dev);
+
 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
@@ -1338,6 +1340,7 @@
 	case HERMES_INQ_LINKSTATUS: {
 		struct hermes_linkstatus linkstatus;
 		u16 newstatus;
+		int connected;
 
 		if (len != sizeof(linkstatus)) {
 			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
@@ -1345,24 +1348,26 @@
 			break;
 		}
 
-		hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus,
-				  len / 2);
+		err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
+
 		newstatus = le16_to_cpu(linkstatus.linkstatus);
 
-		if ( (newstatus == HERMES_LINKSTATUS_CONNECTED)
+		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
 		     || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
-		     || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) )
-			priv->connected = 1;
-		else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED)
-			  || (newstatus == HERMES_LINKSTATUS_DISCONNECTED)
-			  || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE)
-			  || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) )
-			priv->connected = 0;
+		     || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
 
-		if (newstatus != priv->last_linkstatus)
-			print_linkstatus(dev, newstatus);
+		if (connected)
+			netif_carrier_on(dev);
+		else if (!ignore_disconnect)
+			netif_carrier_off(dev);
 
-		priv->last_linkstatus = newstatus;
+		if (newstatus != priv->last_linkstatus) {
+			priv->last_linkstatus = newstatus;
+			print_linkstatus(dev, newstatus);
+		}
 	}
 	break;
 	default:
@@ -1389,6 +1394,8 @@
 	struct hermes *hw = &priv->hw;
 	int err;
 
+	netif_carrier_off(dev); /* just to make sure */
+
 	err = __orinoco_program_rids(dev);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d configuring card\n",
@@ -1435,8 +1442,8 @@
 	}
 	
 	/* firmware will have to reassociate */
+	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
-	priv->connected = 0;
 
 	return 0;
 }
@@ -1957,7 +1964,7 @@
 
 	priv->hw_unavailable++;
 	priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
-	priv->connected = 0;
+	netif_carrier_off(dev);
 
 	orinoco_unlock(priv, &flags);
 
@@ -2493,8 +2500,8 @@
 				   * hardware */
 	INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
 
+	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
-	priv->connected = 0;
 
 	return dev;
 
--- a/drivers/net/wireless/orinoco.h.12-netif	2004-10-26 13:09:29.785858792 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-10-26 13:09:38.486536088 -0400
@@ -54,7 +54,6 @@
 	/* driver state */
 	int open;
 	u16 last_linkstatus;
-	int connected;
 
 	/* Net device stuff */
 	struct net_device *ndev;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 13/15] wireless/orinoco: RF monitor mode support
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (12 preceding siblings ...)
  2004-10-26 19:20 ` [PATCH 2.6.10-rc1 12/15] wireless/orinoco: Use netif routines rather than keeping link state ourselves Dan Williams
@ 2004-10-26 19:22 ` Dan Williams
  2004-10-26 19:24 ` [PATCH 2.6.10-rc1 14/15] wireless/orinoco: add minimal ethtool support Dan Williams
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:22 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o o RF monitor mode support (Pavel Roskin)

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c.13-monitor-mode	2004-10-26 13:22:02.674402336 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 13:38:35.020542792 -0400
@@ -612,26 +612,45 @@
 /* Data types                                                       */
 /********************************************************************/
 
-struct header_struct {
-	/* 802.3 */
-	u8 dest[ETH_ALEN];
-	u8 src[ETH_ALEN];
-	u16 len;
-	/* 802.2 */
+/* Used in Event handling.
+ * We avoid nested structres as they break on ARM -- Moustafa */
+struct hermes_tx_descriptor_802_11 {
+	/* hermes_tx_descriptor */        
+	u16 status;
+	u16 reserved1;
+	u16 reserved2;
+	u32 sw_support;
+	u8 retry_count;
+	u8 tx_rate;
+	u16 tx_control;
+
+	/* ieee802_11_hdr */
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+	u16 data_len;
+
+	/* ethhdr */
+	unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
+	unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
+	unsigned short  h_proto;                /* packet type ID field */
+
+	/* p8022_hdr */
 	u8 dsap;
 	u8 ssap;
 	u8 ctrl;
-	/* SNAP */
 	u8 oui[3];
+
 	u16 ethertype;
 } __attribute__ ((packed));
 
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-
-#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
-
+/* Rx frame header except compatibility 802.3 header */
 struct hermes_rx_descriptor {
+	/* Control */
 	u16 status;
 	u32 time;
 	u8 silence;
@@ -639,6 +658,18 @@
 	u8 rate;
 	u8 rxflow;
 	u32 reserved;
+
+	/* 802.11 header */
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+
+	/* Data length */
+	u16 data_len;
 } __attribute__ ((packed));
 
 /********************************************************************/
@@ -669,6 +700,10 @@
 			priv->createibss = 1;
 		}
 		break;
+	case IW_MODE_MONITOR:
+		priv->port_type = 3;
+		priv->createibss = 0;
+		break;
 	default:
 		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
 		       priv->ndev->name);
@@ -851,7 +886,7 @@
 		return 1;
 	}
 
-	if (! netif_carrier_ok(dev)) {
+	if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
 		/* Oops, the firmware hasn't established a connection,
                    silently drop the packet (this seems to be the
                    safest approach). */
@@ -988,27 +1023,57 @@
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
-	struct hermes_tx_descriptor desc;
+	struct hermes_tx_descriptor_802_11 hdr;
 	int err = 0;
 
 	if (fid == DUMMY_FID)
 		return; /* Nothing's really happened */
 
-	err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
+	/* Read the frame header */
+	err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+			       sizeof(struct hermes_tx_descriptor) +
+			       sizeof(struct ieee802_11_hdr),
+			       fid, 0);
+
+	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+	stats->tx_errors++;
+
 	if (err) {
 		printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
 		       "(FID=%04X error %d)\n",
 		       dev->name, fid, err);
-	} else {
-		DEBUG(1, "%s: Tx error, status %d\n",
-		      dev->name, le16_to_cpu(desc.status));
+		return;
 	}
 	
-	stats->tx_errors++;
+	DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+	      err, fid);
+    
+#if WIRELESS_EXT > 13
+	/* We produce a TXDROP event only for retry or lifetime
+	 * exceeded, because that's the only status that really mean
+	 * that this particular node went away.
+	 * Other errors means that *we* screwed up. - Jean II */
+	hdr.status = le16_to_cpu(hdr.status);
+	if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+		union iwreq_data	wrqu;
+
+		/* Copy 802.11 dest address.
+		 * We use the 802.11 header because the frame may
+		 * not be 802.3 or may be mangled...
+		 * In Ad-Hoc mode, it will be the node address.
+		 * In managed mode, it will be most likely the AP addr
+		 * User space will figure out how to convert it to
+		 * whatever it needs (IP address or else).
+		 * - Jean II */
+		memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+		wrqu.addr.sa_family = ARPHRD_ETHER;
 
-	netif_wake_queue(dev);
+		/* Send event to user space */
+		wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+	}
+#endif /* WIRELESS_EXT > 13 */
 
-	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+	netif_wake_queue(dev);
 }
 
 static void orinoco_tx_timeout(struct net_device *dev)
@@ -1033,15 +1098,17 @@
 
 /* Does the frame have a SNAP header indicating it should be
  * de-encapsulated to Ethernet-II? */
-static inline int is_ethersnap(struct header_struct *hdr)
+static inline int is_ethersnap(void *_hdr)
 {
+	u8 *hdr = _hdr;
+
 	/* We de-encapsulate all packets which, a) have SNAP headers
 	 * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
 	 * and where b) the OUI of the SNAP header is 00:00:00 or
 	 * 00:00:f8 - we need both because different APs appear to use
 	 * different OUIs for some reason */
-	return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0)
-		&& ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) );
+	return (memcmp(hdr, &encaps_hdr, 5) == 0)
+		&& ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) );
 }
 
 static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
@@ -1083,18 +1150,124 @@
 	}
 }
 
-static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ *	dev		network device
+ *	rxfid		received FID
+ *	desc		rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+			       struct hermes_rx_descriptor *desc)
+{
+	u32 hdrlen = 30;	/* return full header by default */
+	u32 datalen = 0;
+	u16 fc;
+	int err;
+	int len;
+	struct sk_buff *skb;
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	hermes_t *hw = &priv->hw;
+
+	len = le16_to_cpu(desc->data_len);
+
+	/* Determine the size of the header and the data */
+	fc = le16_to_cpu(desc->frame_ctl);
+	switch (fc & IEEE802_11_FCTL_FTYPE) {
+	case IEEE802_11_FTYPE_DATA:
+		if ((fc & IEEE802_11_FCTL_TODS)
+		    && (fc & IEEE802_11_FCTL_FROMDS))
+			hdrlen = 30;
+		else
+			hdrlen = 24;
+		datalen = len;
+		break;
+	case IEEE802_11_FTYPE_MGMT:
+		hdrlen = 24;
+		datalen = len;
+		break;
+	case IEEE802_11_FTYPE_CTL:
+		switch (fc & IEEE802_11_FCTL_STYPE) {
+		case IEEE802_11_STYPE_PSPOLL:
+		case IEEE802_11_STYPE_RTS:
+		case IEEE802_11_STYPE_CFEND:
+		case IEEE802_11_STYPE_CFENDACK:
+			hdrlen = 16;
+			break;
+		case IEEE802_11_STYPE_CTS:
+		case IEEE802_11_STYPE_ACK:
+			hdrlen = 10;
+			break;
+		}
+		break;
+	default:
+		/* Unknown frame type */
+		break;
+	}
+
+	/* sanity check the length */
+	if (datalen > IEEE802_11_DATA_LEN + 12) {
+		printk(KERN_DEBUG "%s: oversized monitor frame, "
+		       "data length = %d\n", dev->name, datalen);
+		err = -EIO;
+		goto drop;
+	}
+
+	skb = dev_alloc_skb(hdrlen + datalen);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+		       dev->name);
+		err = -ENOMEM;
+		goto drop;
+	}
+
+	/* Copy the 802.11 header to the skb */
+	memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+	skb->mac.raw = skb->data;
+
+	/* If any, copy the data from the card to the skb */
+	if (datalen > 0) {
+		err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+				       ALIGN(datalen, 2), rxfid,
+				       HERMES_802_2_OFFSET);
+		if (err) {
+			printk(KERN_ERR "%s: error %d reading monitor frame\n",
+			       dev->name, err);
+			goto drop;
+		}
+	}
+
+	skb->dev = dev;
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = __constant_htons(ETH_P_802_2);
+	
+	dev->last_rx = jiffies;
+	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
+
+	netif_rx(skb);
+	return;
+
+ drop:
+	stats->rx_errors++;
+	stats->rx_dropped++;
+}
+
+void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
 	struct iw_statistics *wstats = &priv->wstats;
 	struct sk_buff *skb = NULL;
-	u16 rxfid, status;
-	int length, data_len, data_off;
-	char *p;
+	u16 rxfid, status, fc;
+	int length;
 	struct hermes_rx_descriptor desc;
-	struct header_struct hdr;
-	struct ethhdr *eh;
+	struct ethhdr *hdr;
 	int err;
 
 	rxfid = hermes_read_regn(hw, RXFID);
@@ -1110,33 +1283,31 @@
 
 	status = le16_to_cpu(desc.status);
 
-	if (status & HERMES_RXSTAT_ERR) {
-		if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
-			wstats->discard.code++;
-			DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
-			       dev->name);
-		} else {
-			stats->rx_crc_errors++;
-			DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
-		}
+	if (status & HERMES_RXSTAT_BADCRC) {
+		DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+		      dev->name);
+		stats->rx_crc_errors++;
 		stats->rx_errors++;
 		goto drop;
 	}
 
-	/* For now we ignore the 802.11 header completely, assuming
-           that the card's firmware has handled anything vital */
+	/* Handle frames in monitor mode */
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		orinoco_rx_monitor(dev, rxfid, &desc);
+		return;
+	}
 
-	err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
-			       rxfid, HERMES_802_3_OFFSET);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading frame header. "
-		       "Frame dropped.\n", dev->name, err);
+	if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+		DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+		      dev->name);
+		wstats->discard.code++;
 		stats->rx_errors++;
 		goto drop;
 	}
 
-	length = ntohs(hdr.len);
-	
+	length = le16_to_cpu(desc.data_len);
+	fc = le16_to_cpu(desc.frame_ctl);
+
 	/* Sanity checks */
 	if (length < 3) { /* No for even an 802.2 LLC header */
 		/* At least on Symbol firmware with PCF we get quite a
@@ -1165,57 +1336,51 @@
 		goto drop;
 	}
 
-	skb_reserve(skb, 2); /* This way the IP header is aligned */
+	/* We'll prepend the header, so reserve space for it.  The worst
+	   case is no decapsulation, when 802.3 header is prepended and
+	   nothing is removed.  2 is for aligning the IP header.  */
+	skb_reserve(skb, ETH_HLEN + 2);
+
+	err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+			       ALIGN(length, 2), rxfid,
+			       HERMES_802_2_OFFSET);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading frame. "
+		       "Frame dropped.\n", dev->name, err);
+		stats->rx_errors++;
+		goto drop;
+	}
 
 	/* Handle decapsulation
 	 * In most cases, the firmware tell us about SNAP frames.
 	 * For some reason, the SNAP frames sent by LinkSys APs
 	 * are not properly recognised by most firmwares.
 	 * So, check ourselves */
-	if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
-	    ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-	    is_ethersnap(&hdr)) {
+	if (length >= ENCAPS_OVERHEAD &&
+	    (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+	     ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+	     is_ethersnap(skb->data))) {
 		/* These indicate a SNAP within 802.2 LLC within
 		   802.11 frame which we'll need to de-encapsulate to
 		   the original EthernetII frame. */
-
-		if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
-			stats->rx_length_errors++;
-			goto drop;
-		}
-
-		/* Remove SNAP header, reconstruct EthernetII frame */
-		data_len = length - ENCAPS_OVERHEAD;
-		data_off = HERMES_802_3_OFFSET + sizeof(hdr);
-
-		eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
-
-		memcpy(eh, &hdr, 2 * ETH_ALEN);
-		eh->h_proto = hdr.ethertype;
+		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
 	} else {
-		/* All other cases indicate a genuine 802.3 frame.  No
-		   decapsulation needed.  We just throw the whole
-		   thing in, and hope the protocol layer can deal with
-		   it as 802.3 */
-		data_len = length;
-		data_off = HERMES_802_3_OFFSET;
-		/* FIXME: we re-read from the card data we already read here */
-	}
-
-	p = skb_put(skb, data_len);
-	err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2),
-			       rxfid, data_off);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading frame. "
-		       "Frame dropped.\n", dev->name, err);
-		stats->rx_errors++;
-		goto drop;
-	}
+		/* 802.3 frame - prepend 802.3 header as is */
+		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+		hdr->h_proto = htons(length);
+	}
+	memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
+	if (fc & IEEE802_11_FCTL_FROMDS)
+		memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
+	else
+		memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
 
 	dev->last_rx = jiffies;
 	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
 	skb->ip_summed = CHECKSUM_NONE;
+	if (fc & IEEE802_11_FCTL_TODS)
+		skb->pkt_type = PACKET_OTHERHOST;
 	
 	/* Process the wireless stats if needed */
 	orinoco_stat_gather(dev, skb, &desc);
@@ -1276,7 +1441,33 @@
 	       dev->name, s, status);
 }
 
-static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+#if WIRELESS_EXT > 13
+/* Send new BSSID to userspace */
+static void orinoco_send_wevents(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	union iwreq_data wrqu;
+	int err;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return;
+
+	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+	if (err != 0)
+		return;
+
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+	orinoco_unlock(priv, &flags);
+}
+#endif
+
+void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	u16 infofid;
@@ -1316,10 +1507,11 @@
 			len = sizeof(tallies);
 		}
 		
-		/* Read directly the data (no seek) */
-		hermes_read_words(hw, HERMES_DATA1, (void *) &tallies,
-				  len / 2); /* FIXME: blech! */
-		
+		err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
+
 		/* Increment our various counters */
 		/* wstats->discard.nwid - no wrong BSSID stuff */
 		wstats->discard.code +=
@@ -1330,11 +1522,13 @@
 				le16_to_cpu(tallies.RxDiscards_WEPExcluded);
 		wstats->discard.misc +=
 			le16_to_cpu(tallies.TxDiscardsWrongSA);
+#if WIRELESS_EXT > 11
 		wstats->discard.fragment +=
 			le16_to_cpu(tallies.RxMsgInBadMsgFragments);
 		wstats->discard.retries +=
 			le16_to_cpu(tallies.TxRetryLimitExceeded);
 		/* wstats->miss.beacon - no match */
+#endif /* WIRELESS_EXT > 11 */
 	}
 	break;
 	case HERMES_INQ_LINKSTATUS: {
@@ -1342,6 +1536,9 @@
 		u16 newstatus;
 		int connected;
 
+		if (priv->iw_mode == IW_MODE_MONITOR)
+			break;
+
 		if (len != sizeof(linkstatus)) {
 			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
 			       dev->name, len);
@@ -1370,6 +1567,12 @@
 		}
 	}
 	break;
+	case HERMES_INQ_SEC_STAT_AGERE:
+		/* Security status (Agere specific) */
+		/* Ignore this frame for now */
+		if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+			break;
+		/* fall through */
 	default:
 		printk(KERN_DEBUG "%s: Unknown information frame received: "
 		       "type 0x%04x, length %d\n", dev->name, type, len);
@@ -1645,6 +1848,9 @@
 		} else
 			master_wep_flag = 0;
 
+		if (priv->iw_mode == IW_MODE_MONITOR)
+			master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
+
 		/* Master WEP setting : on/off */
 		err = hermes_write_wordrec(hw, USER_BAP,
 					   HERMES_RID_CNFWEPFLAGS_INTERSIL,
@@ -1864,6 +2070,20 @@
 		}
 	}
 
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		/* Enable monitor mode */
+		dev->type = ARPHRD_IEEE80211;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST | 
+					    HERMES_TEST_MONITOR, 0, NULL);
+	} else {
+		/* Disable monitor mode */
+		dev->type = ARPHRD_ETHER;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+					    HERMES_TEST_STOP, 0, NULL);
+	}
+	if (err)
+		return err;
+
 	/* Set promiscuity / multicast*/
 	priv->promiscuous = 0;
 	priv->mc_count = 0;
@@ -2091,7 +2311,7 @@
 		if (events & HERMES_EV_ALLOC)
 			__orinoco_ev_alloc(dev, hw);
 		
-		hermes_write_regn(hw, EVACK, events);
+		hermes_write_regn(hw, EVACK, evstat);
 
 		evstat = hermes_read_regn(hw, EVSTAT);
 		events = evstat & hw->inten;
@@ -2207,6 +2427,7 @@
 		priv->has_mwo = (firmver >= 0x60000);
 		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
 		priv->ibss_port = 1;
+		priv->broken_monitor = (firmver >= 0x80000);
 
 		/* Tested with Agere firmware :
 		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2499,6 +2720,9 @@
 				   * before anything else touches the
 				   * hardware */
 	INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+#if WIRELESS_EXT > 13
+	INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
+#endif
 
 	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
@@ -2770,6 +2994,15 @@
 	case IW_MODE_INFRA:
 		break;
 
+	case IW_MODE_MONITOR:
+		if (priv->broken_monitor) {
+			printk(KERN_WARNING "%s: Monitor mode support is "
+			       "buggy in this firmware, not enabling\n",
+			       dev->name);
+			err = -EOPNOTSUPP;
+		}
+		break;
+
 	default:
 		err = -EOPNOTSUPP;
 		break;
@@ -3177,6 +3410,13 @@
 		return -EBUSY;
 
 	priv->channel = chan;
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		/* Fast channel change - no commit if successful */
+		hermes_t *hw = &priv->hw;
+		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+					    HERMES_TEST_SET_CHANNEL,
+					chan, NULL);
+	}
 	orinoco_unlock(priv, &flags);
 
 	return err;
@@ -4544,6 +4784,8 @@
 EXPORT_SYMBOL(orinoco_reinit_firmware);
 
 EXPORT_SYMBOL(orinoco_interrupt);
+EXPORT_SYMBOL(__orinoco_ev_rx);
+EXPORT_SYMBOL(__orinoco_ev_info);
 
 /* Can't be declared "const" or the whole __initdata section will
  * become const */
--- a/drivers/net/wireless/orinoco.h.13-monitor-mode	2004-10-26 13:22:08.011590960 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-10-26 13:35:27.978977432 -0400
@@ -36,6 +36,25 @@
 	char data[ORINOCO_MAX_KEY_SIZE];
 } __attribute__ ((packed));
 
+struct header_struct {
+	/* 802.3 */
+	u8 dest[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	u16 len;
+	/* 802.2 */
+	u8 dsap;
+	u8 ssap;
+	u8 ctrl;
+	/* SNAP */
+	u8 oui[3];
+	u16 ethertype;
+} __attribute__ ((packed));
+
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+#define encaps_hdr ((u8[]){0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00})
+
+#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
+
 typedef enum {
 	FIRMWARE_TYPE_AGERE,
 	FIRMWARE_TYPE_INTERSIL,
@@ -54,6 +73,10 @@
 	/* driver state */
 	int open;
 	u16 last_linkstatus;
+	struct work_struct join_work;
+#if WIRELESS_EXT > 13
+	struct work_struct wevent_work;
+#endif
 
 	/* Net device stuff */
 	struct net_device *ndev;
@@ -81,6 +104,7 @@
 	unsigned int has_preamble:1;
 	unsigned int has_sensitivity:1;
 	unsigned int broken_disableport:1;
+	unsigned int broken_monitor:1;
 	unsigned int irq_no_disable:1;
 
 	/* Configuration paramaters */
@@ -131,6 +155,8 @@
 extern int orinoco_stop(struct net_device *dev);
 extern int orinoco_reinit_firmware(struct net_device *dev);
 extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+extern void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
+extern void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
 
 /********************************************************************/
 /* Locking and synchronization functions                            */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 14/15] wireless/orinoco: add minimal ethtool support
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (13 preceding siblings ...)
  2004-10-26 19:22 ` [PATCH 2.6.10-rc1 13/15] wireless/orinoco: RF monitor mode support Dan Williams
@ 2004-10-26 19:24 ` Dan Williams
  2004-10-26 19:46   ` Jeff Garzik
  2004-10-26 19:28 ` [PATCH 2.6.10-rc1 15/15] wireless/orinoco: Wireless scanning support Dan Williams
  2004-10-27  2:05 ` [PATCHES] wireless: Update in-kernel orinoco driver David Gibson
  16 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:24 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o Add minimal ethtool support (Pavel Roskin)

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c.14-ethtool	2004-10-26 13:40:22.388220424 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-10-26 13:44:23.281599064 -0400
@@ -494,6 +494,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/wireless.h>
 #if WIRELESS_EXT > 12
 #include <net/iw_handler.h>
@@ -4229,6 +4230,48 @@
 	return err;
 }
 
+static int orinoco_ioctl_ethtool(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+	struct orinoco_private *priv = netdev_priv(dev);
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strncpy(info.driver, DRIVER_NAME, sizeof(info.driver) - 1);
+		strncpy(info.version, DRIVER_VERSION,
+			sizeof(info.version) - 1);
+		strncpy(info.fw_version, priv->fw_name,
+			sizeof(info.fw_version) - 1);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
+		if (dev->class_dev.dev)
+			strncpy(info.bus_info, dev->class_dev.dev->bus_id,
+				sizeof(info.bus_info) - 1);
+		else
+			snprintf(info.bus_info, sizeof(info.bus_info) - 1,
+				 "PCMCIA 0x%lx", priv->hw.iobase);
+#endif
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+#ifdef ETHTOOL_GLINK
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		edata.data = netif_carrier_ok(dev) ? 1 : 0;
+		if (copy_to_user (useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+#endif
+	}
+
+	return -EOPNOTSUPP;
+}
+
 static const struct iw_priv_args orinoco_privtab[] = {
 	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
 	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
@@ -4699,6 +4742,10 @@
 	else
 #endif /* WIRELESS_EXT <= 12 */
 	switch (cmd) {
+	case SIOCETHTOOL:
+		err = orinoco_ioctl_ethtool(dev, (void *) rq->ifr_data);
+		break;
+
 	default:
 		err = -EOPNOTSUPP;
 	}

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 2.6.10-rc1 15/15] wireless/orinoco: Wireless scanning support
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (14 preceding siblings ...)
  2004-10-26 19:24 ` [PATCH 2.6.10-rc1 14/15] wireless/orinoco: add minimal ethtool support Dan Williams
@ 2004-10-26 19:28 ` Dan Williams
  2004-10-26 19:33   ` Francois Romieu
  2004-10-27  2:05 ` [PATCHES] wireless: Update in-kernel orinoco driver David Gibson
  16 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:28 UTC (permalink / raw)
  To: netdev; +Cc: jgarzik, hermes

Update in-kernel orinoco wireless drivers to upstream CVS.
None of this is original code by Dan Williams, simply a
broken down patch set split-out from upstream orinoco CVS.

o New wireless extensions API and scanning support (patch from
    Moustafa Youssef, updated by Jim Carter and Pavel Roskin)

Signed-off-by: Dan Williams <dcbw@redhat.com>

--- a/drivers/net/wireless/orinoco.c	2004-10-26 13:44:23.281599064 -0400
+++ b/drivers/net/wireless/orinoco.c	2004-08-17 17:26:31.000000000 -0400
@@ -1442,6 +1442,80 @@
 	       dev->name, s, status);
 }
 
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct net_device *dev)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	struct hermes *hw = &priv->hw;
+	int err;
+	unsigned long flags;
+	struct join_req {
+		u8 bssid[ETH_ALEN];
+		u16 channel;
+	} __attribute__ ((packed)) req;
+	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+	struct prism2_scan_apinfo *atom;
+	int offset = 4;
+	int found = 0;
+	u8 *buf = NULL;
+	u16 len;
+
+	/* Allocate buffer for scan results */
+	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return;
+
+	/* Sanity checks in case user changed something in the meantime */
+	if (!priv->bssid_fixed)
+		goto out;
+
+	if (strlen(priv->desired_essid) == 0)
+		goto out;
+
+	/* Read scan results from the firmware */
+	err = hermes_read_ltv(hw, USER_BAP,
+			      HERMES_RID_SCANRESULTSTABLE,
+			      MAX_SCAN_LEN, &len, buf);
+	if (err) {
+		printk(KERN_ERR "%s: Cannot read scan results\n",
+		       dev->name);
+		goto out;
+	}
+
+	len = HERMES_RECLEN_TO_BYTES(len);
+
+	/* Go through the scan results looking for the channel of the AP
+	 * we were requested to join */
+	for (; offset + atom_len <= len; offset += atom_len) {
+		atom = (struct prism2_scan_apinfo *) (buf + offset);
+		if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		DEBUG(1, "%s: Requested AP not found in scan results\n",
+		      dev->name);
+		goto out;
+	}
+
+	memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+	req.channel = atom->channel;	/* both are little-endian */
+	err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+				  &req);
+	if (err)
+		printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+	if (buf)
+		kfree(buf);
+	orinoco_unlock(priv, &flags);
+}
+
 #if WIRELESS_EXT > 13
 /* Send new BSSID to userspace */
 static void orinoco_send_wevents(struct net_device *dev)
@@ -1553,6 +1627,15 @@
 
 		newstatus = le16_to_cpu(linkstatus.linkstatus);
 
+		/* Symbol firmware uses "out of range" to signal that
+		 * the hostscan frame can be requested.  */
+		if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+		    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+		    priv->has_hostscan && priv->scan_inprogress) {
+			hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+			break;
+		}
+
 		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
 		     || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
 		     || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1565,7 +1648,82 @@
 		if (newstatus != priv->last_linkstatus) {
 			priv->last_linkstatus = newstatus;
 			print_linkstatus(dev, newstatus);
+#if WIRELESS_EXT > 13
+			/* The info frame contains only one word which is the
+			 * status (see hermes.h). The status is pretty boring
+			 * in itself, that's why we export the new BSSID...
+			 * Jean II */
+			schedule_work(&priv->wevent_work);
+#endif
+		}
+	}
+	break;
+	case HERMES_INQ_SCAN:
+		if (!priv->scan_inprogress && priv->bssid_fixed &&
+		    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+			schedule_work(&priv->join_work);
+			break;
+		}
+		/* fall through */
+	case HERMES_INQ_HOSTSCAN:
+	case HERMES_INQ_HOSTSCAN_SYMBOL: {
+		/* Result of a scanning. Contains information about
+		 * cells in the vicinity - Jean II */
+#if WIRELESS_EXT > 13
+		union iwreq_data	wrqu;
+		unsigned char *buf;
+
+		/* Sanity check */
+		if (len > 4096) {
+			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		/* We are a strict producer. If the previous scan results
+		 * have not been consumed, we just have to drop this
+		 * frame. We can't remove the previous results ourselves,
+		 * that would be *very* racy... Jean II */
+		if (priv->scan_result != NULL) {
+			printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
+			break;
 		}
+
+		/* Allocate buffer for results */
+		buf = kmalloc(len, GFP_ATOMIC);
+		if (buf == NULL)
+			/* No memory, so can't printk()... */
+			break;
+
+		/* Read scan data */
+		err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
+
+#ifdef ORINOCO_DEBUG
+		{
+			int	i;
+			printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+			for(i = 1; i < (len * 2); i++)
+				printk(":%02X", buf[i]);
+			printk("]\n");
+		}
+#endif	/* ORINOCO_DEBUG */
+
+		/* Allow the clients to access the results */
+		priv->scan_len = len;
+		priv->scan_result = buf;
+
+		/* Send an empty event to user space.
+		 * We don't send the received data on the event because
+		 * it would require us to do complex transcoding, and
+		 * we want to minimise the work done in the irq handler
+		 * Use a request to extract the data - Jean II */
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+#endif /* WIRELESS_EXT > 13 */
 	}
 	break;
 	case HERMES_INQ_SEC_STAT_AGERE:
@@ -2189,6 +2347,13 @@
 
 	orinoco_unlock(priv, &flags);
 
+	/* Scanning support: Cleanup of driver struct */
+	if (priv->scan_result != NULL) {
+		kfree(priv->scan_result);
+		priv->scan_result = NULL;
+	}
+	priv->scan_inprogress = 0;
+
 	if (priv->hard_reset) {
 		err = (*priv->hard_reset)(priv);
 		if (err) {
@@ -2428,6 +2593,7 @@
 		priv->has_mwo = (firmver >= 0x60000);
 		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
 		priv->ibss_port = 1;
+		priv->has_hostscan = (firmver >= 0x8000a);
 		priv->broken_monitor = (firmver >= 0x80000);
 
 		/* Tested with Agere firmware :
@@ -2474,6 +2640,8 @@
 		priv->ibss_port = 4;
 		priv->broken_disableport = (firmver == 0x25013) ||
 					   (firmver >= 0x30000 && firmver <= 0x31000);
+		priv->has_hostscan = (firmver >= 0x31001) ||
+				     (firmver >= 0x29057 && firmver < 0x30000);
 		/* Tested with Intel firmware : 0x20015 => Jean II */
 		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
 		break;
@@ -2493,6 +2661,7 @@
 		priv->has_ibss = (firmver >= 0x000700); /* FIXME */
 		priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
 		priv->has_pm = (firmver >= 0x000700);
+		priv->has_hostscan = (firmver >= 0x010301);
 
 		if (firmver >= 0x000800)
 			priv->ibss_port = 0;
@@ -2721,6 +2890,7 @@
 				   * before anything else touches the
 				   * hardware */
 	INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+	INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
 #if WIRELESS_EXT > 13
 	INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
 #endif
@@ -2736,6 +2906,9 @@
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 
+	if (priv->scan_result)
+		kfree(priv->scan_result);
+
 	free_netdev(dev);
 }
 
@@ -4175,6 +4348,334 @@
 	return 0;
 }
 
+#if WIRELESS_EXT > 13
+/* Trigger a scan (look for other cells in the vicinity */
+static int orinoco_ioctl_setscan(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_param *srq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	unsigned long flags;
+
+	/* Note : you may have realised that, as this is a SET operation,
+	 * this is priviledged and therefore a normal user can't
+	 * perform scanning.
+	 * This is not an error, while the device perform scanning,
+	 * traffic doesn't flow, so it's a perfect DoS...
+	 * Jean II */
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* Scanning with port 0 disabled would fail */
+	if (!netif_running(dev)) {
+		err = -ENETDOWN;
+		goto out;
+	}
+
+	/* In monitor mode, the scan results are always empty.
+	 * Probe responses are passed to the driver as received
+	 * frames and could be processed in software. */
+	if (priv->iw_mode == IW_MODE_MONITOR) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Note : because we don't lock out the irq handler, the way
+	 * we access scan variables in priv is critical.
+	 *	o scan_inprogress : not touched by irq handler
+	 *	o scan_mode : not touched by irq handler
+	 *	o scan_result : irq is strict producer, non-irq is strict
+	 *		consumer.
+	 *	o scan_len : synchronised with scan_result
+	 * Before modifying anything on those variables, please think hard !
+	 * Jean II */
+
+	/* If there is still some left-over scan results, get rid of it */
+	if (priv->scan_result != NULL) {
+		/* What's likely is that a client did crash or was killed
+		 * between triggering the scan request and reading the
+		 * results, so we need to reset everything.
+		 * Some clients that are too slow may suffer from that...
+		 * Jean II */
+		kfree(priv->scan_result);
+		priv->scan_result = NULL;
+	}
+
+	/* Save flags */
+	priv->scan_mode = srq->flags;
+
+	/* Always trigger scanning, even if it's in progress.
+	 * This way, if the info frame get lost, we will recover somewhat
+	 * gracefully  - Jean II */
+
+	if (priv->has_hostscan) {
+		switch (priv->firmware_type) {
+		case FIRMWARE_TYPE_SYMBOL:
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFHOSTSCAN_SYMBOL,
+						   HERMES_HOSTSCAN_SYMBOL_ONCE |
+						   HERMES_HOSTSCAN_SYMBOL_BCAST);
+			break;
+		case FIRMWARE_TYPE_INTERSIL: {
+			u16 req[3];
+
+			req[0] = cpu_to_le16(0x3fff);	/* All channels */
+			req[1] = cpu_to_le16(0x0001);	/* rate 1 Mbps */
+			req[2] = 0;			/* Any ESSID */
+			err = HERMES_WRITE_RECORD(hw, USER_BAP,
+						  HERMES_RID_CNFHOSTSCAN, &req);
+		}
+		break;
+		case FIRMWARE_TYPE_AGERE:
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFSCANSSID_AGERE,
+						   0);	/* Any ESSID */
+			if (err)
+				break;
+
+			err = hermes_inquire(hw, HERMES_INQ_SCAN);
+			break;
+		}
+	} else
+		err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+	/* One more client */
+	if (! err)
+		priv->scan_inprogress = 1;
+
+ out:
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline int orinoco_translate_scan(struct net_device *dev,
+					 char *buffer,
+					 char *scan,
+					 int scan_len)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int			offset;		/* In the scan data */
+	union hermes_scan_info *atom;
+	int			atom_len;
+	u16			capabilities;
+	u16			channel;
+	struct iw_event		iwe;		/* Temporary buffer */
+	char *			current_ev = buffer;
+	char *			end_buf = buffer + IW_SCAN_MAX_DATA;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		atom_len = sizeof(struct agere_scan_apinfo);
+ 		offset = 0;
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		/* Lack of documentation necessitates this hack.
+		 * Different firmwares have 68 or 76 byte long atoms.
+		 * We try modulo first.  If the length divides by both,
+		 * we check what would be the channel in the second
+		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
+		 * Valid channel cannot be 0.  */
+		if (scan_len % 76)
+			atom_len = 68;
+		else if (scan_len % 68)
+			atom_len = 76;
+		else if (scan_len >= 1292 && scan[68] == 0)
+			atom_len = 76;
+		else
+			atom_len = 68;
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		offset = 4;
+		if (priv->has_hostscan)
+			atom_len = scan[0] + (scan[1] << 8);
+		else
+			atom_len = offsetof(struct prism2_scan_apinfo, atim);
+		break;
+	default:
+		return 0;
+	}
+
+	/* Check that we got an whole number of atoms */
+	if ((scan_len - offset) % atom_len) {
+		printk(KERN_ERR "%s: Unexpected scan data length %d, "
+		       "atom_len %d, offset %d\n", dev->name, scan_len,
+		       atom_len, offset);
+		return 0;
+	}
+
+	/* Read the entries one by one */
+	for (; offset + atom_len <= scan_len; offset += atom_len) {
+		/* Get next atom */
+		atom = (union hermes_scan_info *) (scan + offset);
+
+		/* First entry *MUST* be the AP MAC address */
+		iwe.cmd = SIOCGIWAP;
+		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+		memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+		/* Other entries will be displayed in the order we give them */
+
+		/* Add the ESSID */
+		iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
+		if (iwe.u.data.length > 32)
+			iwe.u.data.length = 32;
+		iwe.cmd = SIOCGIWESSID;
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+		/* Add mode */
+		iwe.cmd = SIOCGIWMODE;
+		capabilities = le16_to_cpu(atom->a.capabilities);
+		if (capabilities & 0x3) {
+			if (capabilities & 0x1)
+				iwe.u.mode = IW_MODE_MASTER;
+			else
+				iwe.u.mode = IW_MODE_ADHOC;
+			current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+		}
+
+		channel = atom->s.channel;
+		if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
+			/* Add frequency */
+			iwe.cmd = SIOCGIWFREQ;
+			iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+			iwe.u.freq.e = 1;
+			current_ev = iwe_stream_add_event(current_ev, end_buf,
+							  &iwe, IW_EV_FREQ_LEN);
+		}
+
+		/* Add quality statistics */
+		iwe.cmd = IWEVQUAL;
+		iwe.u.qual.updated = 0x10;	/* no link quality */
+		iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
+		iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
+		/* Wireless tools prior to 27.pre22 will show link quality
+		 * anyway, so we provide a reasonable value. */
+		if (iwe.u.qual.level > iwe.u.qual.noise)
+			iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+		else
+			iwe.u.qual.qual = 0;
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+		/* Add encryption capability */
+		iwe.cmd = SIOCGIWENCODE;
+		if (capabilities & 0x10)
+			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+		else
+			iwe.u.data.flags = IW_ENCODE_DISABLED;
+		iwe.u.data.length = 0;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+		/* Bit rate is not available in Lucent/Agere firmwares */
+		if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+			char *	current_val = current_ev + IW_EV_LCP_LEN;
+			int	i;
+			int	step;
+
+			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+				step = 2;
+			else
+				step = 1;
+
+			iwe.cmd = SIOCGIWRATE;
+			/* Those two flags are ignored... */
+			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+			/* Max 10 values */
+			for (i = 0; i < 10; i += step) {
+				/* NULL terminated */
+				if (atom->p.rates[i] == 0x0)
+					break;
+				/* Bit rate given in 500 kb/s units (+ 0x80) */
+				iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
+				current_val = iwe_stream_add_value(current_ev, current_val,
+								   end_buf, &iwe,
+								   IW_EV_PARAM_LEN);
+			}
+			/* Check if we added any event */
+			if ((current_val - current_ev) > IW_EV_LCP_LEN)
+				current_ev = current_val;
+		}
+
+		/* The other data in the scan result are not really
+		 * interesting, so for now drop it - Jean II */
+	}
+	return current_ev - buffer;
+}
+
+/* Return results of a scan */
+static int orinoco_ioctl_getscan(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *srq,
+				 char *extra)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int err = 0;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0)
+		return -EBUSY;
+
+	/* If no results yet, ask to try again later */
+	if (priv->scan_result == NULL) {
+		if (priv->scan_inprogress)
+			/* Important note : we don't want to block the caller
+			 * until results are ready for various reasons.
+			 * First, managing wait queues is complex and racy.
+			 * Second, we grab some rtnetlink lock before comming
+			 * here (in dev_ioctl()).
+			 * Third, we generate an Wireless Event, so the
+			 * caller can wait itself on that - Jean II */
+			err = -EAGAIN;
+		else
+			/* Client error, no scan results...
+			 * The caller need to restart the scan. */
+			err = -ENODATA;
+	} else {
+		/* We have some results to push back to user space */
+
+		/* Translate to WE format */
+		srq->length = orinoco_translate_scan(dev, extra,
+						     priv->scan_result,
+						     priv->scan_len);
+
+		/* Return flags */
+		srq->flags = (__u16) priv->scan_mode;
+
+		/* Results are here, so scan no longer in progress */
+		priv->scan_inprogress = 0;
+
+		/* In any case, Scan results will be cleaned up in the
+		 * reset function and when exiting the driver.
+		 * The person triggering the scanning may never come to
+		 * pick the results, so we need to do it in those places.
+		 * Jean II */
+
+#ifdef SCAN_SINGLE_READ
+		/* If you enable this option, only one client (the first
+		 * one) will be able to read the result (and only one
+		 * time). If there is multiple concurent clients that
+		 * want to read scan results, this behavior is not
+		 * advisable - Jean II */
+		kfree(priv->scan_result);
+		priv->scan_result = NULL;
+#endif /* SCAN_SINGLE_READ */
+		/* Here, if too much time has elapsed since last scan,
+		 * we may want to clean up scan results... - Jean II */
+	}
+	  
+	orinoco_unlock(priv, &flags);
+	return err;
+}
+#endif	/* WIRELESS_EXT > 13 */
+
 /* Commit handler, called after set operations */
 static int orinoco_ioctl_commit(struct net_device *dev,
 				struct iw_request_info *info,
@@ -4331,8 +4832,8 @@
 	(iw_handler) NULL,				/* -- hole -- */
 	(iw_handler) NULL,				/* SIOCGIWAPLIST */
 #if WIRELESS_EXT > 13
-	(iw_handler) NULL,		/* SIOCSIWSCAN */
-	(iw_handler) NULL,		/* SIOCGIWSCAN */
+	(iw_handler) orinoco_ioctl_setscan,		/* SIOCSIWSCAN */
+	(iw_handler) orinoco_ioctl_getscan,		/* SIOCGIWSCAN */
 #else	/* WIRELESS_EXT > 13 */
 	(iw_handler) NULL,				/* SIOCSIWSCAN */
 	(iw_handler) NULL,				/* SIOCGIWSCAN */
--- a/drivers/net/wireless/orinoco.h	2004-10-26 13:35:27.978977432 -0400
+++ b/drivers/net/wireless/orinoco.h	2004-07-28 02:19:49.000000000 -0400
@@ -7,7 +7,7 @@
 #ifndef _ORINOCO_H
 #define _ORINOCO_H
 
-#define DRIVER_VERSION "0.13e"
+#define DRIVER_VERSION "0.15rc2HEAD"
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
@@ -28,6 +29,8 @@
 #endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 11) */
 #define WIRELESS_SPY		// enable iwspy support
 
+#define MAX_SCAN_LEN 4096
+
 #define ORINOCO_MAX_KEY_SIZE	14
 #define ORINOCO_MAX_KEYS	4
 
@@ -103,6 +106,7 @@
 	unsigned int has_pm:1;
 	unsigned int has_preamble:1;
 	unsigned int has_sensitivity:1;
+	unsigned int has_hostscan:1;
 	unsigned int broken_disableport:1;
 	unsigned int broken_monitor:1;
 	unsigned int irq_no_disable:1;
@@ -131,6 +135,12 @@
 	/* Configuration dependent variables */
 	int port_type, createibss;
 	int promiscuous, mc_count;
+
+	/* Scanning support */
+	int	scan_inprogress;	/* Scan pending... */
+	u32	scan_mode;		/* Type of scan done */
+	char *	scan_result;		/* Result of previous scan */
+	int	scan_len;		/* Lenght of result */
 };
 
 #ifdef ORINOCO_DEBUG

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 15/15] wireless/orinoco: Wireless scanning support
  2004-10-26 19:28 ` [PATCH 2.6.10-rc1 15/15] wireless/orinoco: Wireless scanning support Dan Williams
@ 2004-10-26 19:33   ` Francois Romieu
  2004-10-27  4:06     ` David Gibson
  0 siblings, 1 reply; 37+ messages in thread
From: Francois Romieu @ 2004-10-26 19:33 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, hermes

[...]
> --- a/drivers/net/wireless/orinoco.c	2004-10-26 13:44:23.281599064 -0400
> +++ b/drivers/net/wireless/orinoco.c	2004-08-17 17:26:31.000000000 -0400
> @@ -1442,6 +1442,80 @@
>  	       dev->name, s, status);
>  }
>  
> +/* Search scan results for requested BSSID, join it if found */
> +static void orinoco_join_ap(struct net_device *dev)
> +{
> +	struct orinoco_private *priv = netdev_priv(dev);
> +	struct hermes *hw = &priv->hw;
> +	int err;
> +	unsigned long flags;
> +	struct join_req {
> +		u8 bssid[ETH_ALEN];
> +		u16 channel;
> +	} __attribute__ ((packed)) req;
> +	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
> +	struct prism2_scan_apinfo *atom;
> +	int offset = 4;
> +	int found = 0;
> +	u8 *buf = NULL;
> +	u16 len;
> +
> +	/* Allocate buffer for scan results */
> +	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
> +	if (!buf)
> +		return;
> +
> +	if (orinoco_lock(priv, &flags) != 0)
> +		return;

Leak.

--
Ueimor

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-26 18:33 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s Dan Williams
  2004-10-26 18:47   ` Christoph Hellwig
@ 2004-10-26 19:34   ` Jeff Garzik
  1 sibling, 0 replies; 37+ messages in thread
From: Jeff Garzik @ 2004-10-26 19:34 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, hermes

Dan Williams wrote:
> --- a/drivers/net/wireless/airport.c.1-msleep	2004-10-25 14:44:04.559958488 -0400
> +++ b/drivers/net/wireless/airport.c	2004-10-25 14:44:51.372841848 -0400
> @@ -28,7 +28,6 @@
>  #include <linux/if_arp.h>
>  #include <linux/etherdevice.h>
>  #include <linux/wireless.h>
> -#include <linux/delay.h>
>  
>  #include <asm/io.h>
>  #include <asm/system.h>
> @@ -147,7 +146,7 @@
>  	macio_release_resource(mdev, 0);
>  
>  	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
> -	ssleep(1);
> +	msleep(1000);
>  
>  	macio_set_drvdata(mdev, NULL);
>  	free_netdev(dev);
> @@ -173,12 +172,12 @@
>  	disable_irq(dev->irq);
>  
>  	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
> -	ssleep(1);
> +	msleep(1000);
>  	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
> -	ssleep(1);
> +	msleep(1000);
>  
>  	enable_irq(dev->irq);
> -	ssleep(1);
> +	msleep(1000);
>  #endif
>  
>  	return 0;
> @@ -237,7 +236,7 @@
>  		
>  	/* Power up card */
>  	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
> -	ssleep(1);
> +	msleep(1000);
>  
>  	/* Reset it before we get the interrupt */
>  	hermes_init(hw);

these changes are all regressions


> --- a/drivers/net/wireless/orinoco_cs.c.1-msleep	2004-10-25 14:44:04.558958640 -0400
> +++ b/drivers/net/wireless/orinoco_cs.c	2004-10-25 14:44:51.374841544 -0400
> @@ -136,6 +136,7 @@
>  	if (err)
>  		return err;
>  
> +	msleep(100);
>  	clear_bit(0, &card->hard_reset_in_progress);
>  
>  	return 0;
> --- a/drivers/net/wireless/orinoco_plx.c.1-msleep	2004-10-25 14:44:04.559958488 -0400
> +++ b/drivers/net/wireless/orinoco_plx.c	2004-10-25 14:44:51.376841240 -0400
> @@ -352,8 +352,7 @@
>  static void __exit orinoco_plx_exit(void)
>  {
>  	pci_unregister_driver(&orinoco_plx_driver);
> -	current->state = TASK_UNINTERRUPTIBLE;
> -	schedule_timeout(HZ);
> +	msleep(1000);
>  }
>  
>  module_init(orinoco_plx_init);
> --- a/drivers/net/wireless/orinoco_tmd.c.1-msleep	2004-10-25 14:44:04.557958792 -0400
> +++ b/drivers/net/wireless/orinoco_tmd.c	2004-10-25 14:44:51.377841088 -0400
> @@ -218,8 +218,7 @@
>  static void __exit orinoco_tmd_exit(void)
>  {
>  	pci_unregister_driver(&orinoco_tmd_driver);
> -	current->state = TASK_UNINTERRUPTIBLE;
> -	schedule_timeout(HZ);
> +	msleep(1000);

use ssleep() not msleep()

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-26 18:47   ` Christoph Hellwig
@ 2004-10-26 19:35     ` Dan Williams
  2004-10-26 19:42       ` Christoph Hellwig
  0 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:35 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: netdev, jgarzik, hermes

New description:

o Use msleep() instead of hardcoded schedule_timeout()s
o Normalize sleep calls to use msleep() everywhere

Dan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters
  2004-10-26 18:45 ` [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters Dan Williams
@ 2004-10-26 19:36   ` Jeff Garzik
  2004-10-27  3:15   ` David Gibson
  1 sibling, 0 replies; 37+ messages in thread
From: Jeff Garzik @ 2004-10-26 19:36 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, hermes

Dan Williams wrote:
> --- a/drivers/net/wireless/orinoco.h.4-module-params	2004-10-26 10:43:24.213428352 -0400
> +++ b/drivers/net/wireless/orinoco.h	2004-10-26 10:43:31.138375600 -0400
> @@ -14,6 +14,9 @@
>  #include <linux/netdevice.h>
>  #include <linux/wireless.h>
>  #include <linux/version.h>
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
> +#include <linux/moduleparam.h>
> +#endif
>  


this is for out-of-tree drivers and patches

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-26 19:35     ` Dan Williams
@ 2004-10-26 19:42       ` Christoph Hellwig
  2004-10-26 19:55         ` Dan Williams
  0 siblings, 1 reply; 37+ messages in thread
From: Christoph Hellwig @ 2004-10-26 19:42 UTC (permalink / raw)
  To: Dan Williams; +Cc: Christoph Hellwig, netdev, jgarzik, hermes

On Tue, Oct 26, 2004 at 03:35:36PM -0400, Dan Williams wrote:
> New description:
> 
> o Use msleep() instead of hardcoded schedule_timeout()s
> o Normalize sleep calls to use msleep() everywhere

care to explain what's the point of the latter?

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 7/15] wireless/orinoco: Update card reset/init code and add card-specific data structures
  2004-10-26 18:56 ` [PATCH 2.6.10-rc1 7/15] wireless/orinoco: Update card reset/init code and add card-specific data structures Dan Williams
@ 2004-10-26 19:43   ` Jeff Garzik
  2004-10-27  4:00     ` David Gibson
  0 siblings, 1 reply; 37+ messages in thread
From: Jeff Garzik @ 2004-10-26 19:43 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, hermes

Dan Williams wrote:
> +/* Orinoco PCI specific data */
> +struct orinoco_pci_card {
> +	u32 pci_state[16];	/* PCI suspend/resume state */
> +};

no need with GregKH's latest upstream changes



> -	printk(KERN_NOTICE "Reset done");
>  	timeout = jiffies + (HERMES_PCI_COR_ONT * HZ / 1000);
> -	while(time_before(jiffies, timeout)) {
> -		printk(".");
> +	while(time_before(jiffies, timeout))
>  		mdelay(1);


the loop is non-sensical... at this point use msleep() or actually 
mdelay() for the correct period, rather than looping on mdelay(1)


> -	printk(KERN_NOTICE "Clear Reset");
>  	timeout = jiffies + (HERMES_PCI_COR_OFFT * HZ / 1000);
> -	while(time_before(jiffies, timeout)) {
> -		printk(".");
> +	while(time_before(jiffies, timeout))
>  		mdelay(1);
> -	}
> -	printk(";\n");
> -	//mdelay(HERMES_PCI_COR_OFFT);

ditto


> @@ -199,61 +194,68 @@
>  	u16 *pci_ioaddr = NULL;
>  	unsigned long pci_iolen;
>  	struct orinoco_private *priv = NULL;
> +	struct orinoco_pci_card *card;
>  	struct net_device *dev = NULL;
>  
>  	err = pci_enable_device(pdev);
> -	if (err)
> -		return -EIO;
> +	if (err) {
> +		printk(KERN_ERR PFX "Cannot enable PCI device\n");
> +		return -err;
> +	}

incorrect...  err is already negative.


> @@ -325,6 +327,9 @@
>  	
>  	orinoco_unlock(priv, &flags);
>  
> +	pci_save_state(pdev, card->pci_state);
> +	pci_set_power_state(pdev, 3);
> +
>  	return 0;
>  }
>  
> @@ -332,11 +337,15 @@
>  {
>  	struct net_device *dev = pci_get_drvdata(pdev);
>  	struct orinoco_private *priv = netdev_priv(dev);
> +	struct orinoco_pci_card *card = priv->card;
>  	unsigned long flags;
>  	int err;
>  
>  	printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
>  
> +	pci_set_power_state(pdev, 0);
> +	pci_restore_state(pdev, card->pci_state);
> +
>  	err = orinoco_reinit_firmware(dev);
>  	if (err) {
>  		printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",

These two don't build in the latest 2.6.x kernel.



> --- a/drivers/net/wireless/orinoco_plx.c.7-card-data	2004-10-26 09:52:13.354269904 -0400
> +++ b/drivers/net/wireless/orinoco_plx.c	2004-10-26 10:07:51.854596168 -0400
> @@ -142,146 +142,189 @@
>  #include "hermes.h"
>  #include "orinoco.h"
>  
> -#define COR_OFFSET	(0x3e0/2) /* COR attribute offset of Prism2 PC card */
> +#define COR_OFFSET	(0x3e0)	/* COR attribute offset of Prism2 PC card */
>  #define COR_VALUE	(COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
> +#define COR_RESET     (0x80)	/* reset bit in the COR register */
> +#define PLX_RESET_TIME	(500)	/* milliseconds */
>  
>  #define PLX_INTCSR		0x4c /* Interrupt Control & Status Register */
>  #define PLX_INTCSR_INTEN	(1<<6) /* Interrupt Enable bit */
>  
> -static const u16 cis_magic[] = {
> -	0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067
> +static const u8 cis_magic[] = {
> +	0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
>  };
>  
> +/* Orinoco PLX specific data */
> +struct orinoco_plx_card {
> +	u8 *attr_mem;
> +};
> +
> +/*
> + * Do a soft reset of the card using the Configuration Option Register
> + */
> +static int orinoco_plx_cor_reset(struct orinoco_private *priv)
> +{
> +	hermes_t *hw = &priv->hw;
> +	struct orinoco_plx_card *card = priv->card;
> +	u8 *attr_mem = card->attr_mem;
> +	unsigned long timeout;
> +	u16 reg;
> +
> +	attr_mem[COR_OFFSET] = COR_VALUE | COR_RESET;
> +	mdelay(1);
> +
> +	attr_mem[COR_OFFSET] = COR_VALUE;
> +	mdelay(1);
> +
> +	/* Just in case, wait more until the card is no longer busy */
> +	timeout = jiffies + (PLX_RESET_TIME * HZ / 1000);
> +	reg = hermes_read_regn(hw, CMD);
> +	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
> +		mdelay(1);
> +		reg = hermes_read_regn(hw, CMD);
> +	}
> +
> +	/* Did we timeout ? */
> +	if (reg & HERMES_CMD_BUSY) {
> +		printk(KERN_ERR PFX "Busy timeout\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +
>  static int orinoco_plx_init_one(struct pci_dev *pdev,
>  				const struct pci_device_id *ent)
>  {
>  	int err = 0;
> -	u16 *attr_mem = NULL;
> -	u32 reg, addr;
> +	u8 *attr_mem = NULL;
> +	u32 csr_reg, plx_addr;
>  	struct orinoco_private *priv = NULL;
> +	struct orinoco_plx_card *card;
>  	unsigned long pccard_ioaddr = 0;
>  	unsigned long pccard_iolen = 0;
>  	struct net_device *dev = NULL;
>  	int i;
>  
>  	err = pci_enable_device(pdev);
> -	if (err)
> -		return -EIO;
> -
> -	/* Resource 2 is mapped to the PCMCIA space */
> -	attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE);
> -	if (! attr_mem)
> -		goto fail;
> -
> -	printk(KERN_DEBUG "orinoco_plx: CIS: ");
> -	for (i = 0; i < 16; i++) {
> -		printk("%02X:", (int)attr_mem[i]);
> +	if (err) {
> +		printk(KERN_ERR PFX "Cannot enable PCI device\n");
> +		return -err;

ditto earlier comment, same bug here


> @@ -332,6 +374,8 @@
>  	.id_table	= orinoco_plx_pci_id_table,
>  	.probe		= orinoco_plx_init_one,
>  	.remove		= __devexit_p(orinoco_plx_remove_one),
> +	.suspend	= 0,
> +	.resume		= 0,
>  };

superfluous change


> + * Do a soft reset of the card using the Configuration Option Register
> + */
> +static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
> +{
> +	hermes_t *hw = &priv->hw;
> +	struct orinoco_tmd_card *card = priv->card;
> +	u32 addr = card->tmd_io;
> +	unsigned long timeout;
> +	u16 reg;
> +
> +	outb(COR_VALUE | COR_RESET, addr);
> +	mdelay(1);
> +
> +	outb(COR_VALUE, addr);
> +	mdelay(1);

PCI posting bugs?


> +	/* Just in case, wait more until the card is no longer busy */
> +	timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
> +	reg = hermes_read_regn(hw, CMD);
> +	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
> +		mdelay(1);
> +		reg = hermes_read_regn(hw, CMD);
> +	}

max delay without sleep way too long



>  	err = pci_enable_device(pdev);
> -	if (err)
> -		return -EIO;
> -
> -	printk(KERN_DEBUG PFX "TMD setup\n");
> -	pccard_ioaddr = pci_resource_start(pdev, 2);
> -	pccard_iolen = pci_resource_len(pdev, 2);
> -	if (! request_region(pccard_ioaddr, pccard_iolen, DRIVER_NAME)) {
> -		printk(KERN_ERR PFX "I/O resource at 0x%lx len 0x%lx busy\n",
> -			pccard_ioaddr, pccard_iolen);
> -		pccard_ioaddr = 0;
> -		err = -EBUSY;
> -		goto fail;
> +	if (err) {
> +		printk(KERN_ERR PFX "Cannot enable PCI device\n");
> +		return -err;

same bug yet again



> @@ -200,6 +232,8 @@
>  	.id_table	= orinoco_tmd_pci_id_table,
>  	.probe		= orinoco_tmd_init_one,
>  	.remove		= __devexit_p(orinoco_tmd_remove_one),
> +	.suspend	= 0,
> +	.resume		= 0,

superfluous

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: R[PATCH 2.6.10-rc1 8/15] wireless/orinoco: Refactor spinlocks so we don't necessarily have to disable interrupts
  2004-10-26 19:04 ` R[PATCH 2.6.10-rc1 8/15] wireless/orinoco: Refactor spinlocks so we don't necessarily have to disable interrupts Dan Williams
@ 2004-10-26 19:44   ` Jeff Garzik
  2004-10-27  4:14     ` David Gibson
  0 siblings, 1 reply; 37+ messages in thread
From: Jeff Garzik @ 2004-10-26 19:44 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, hermes

Dan Williams wrote:
> Update in-kernel orinoco wireless drivers to upstream CVS.
> None of this is original code by Dan Williams, simply a
> broken down patch set split-out from upstream orinoco CVS.
> 
> o Refactor spinlocks so we don't necessarily have to disable interrupts
> 
> Signed-off-by: Dan Williams <dcbw@redhat.com>
> 
> --- a/drivers/net/wireless/orinoco.h.8-orinoco-spinlock	2004-10-26 10:44:41.445687264 -0400
> +++ b/drivers/net/wireless/orinoco.h	2004-10-26 10:45:39.296892544 -0400
> @@ -71,6 +71,8 @@
>  	u16 channel_mask;
>  	int broken_disableport;
>  
> +	unsigned int irq_no_disable:1;
> +
>  	/* Configuration paramaters */
>  	u32 iw_mode;
>  	int prefer_port3;
> @@ -129,11 +131,17 @@
>  extern inline int orinoco_lock(struct orinoco_private *priv,
>  			       unsigned long *flags)
>  {
> -	spin_lock_irqsave(&priv->lock, *flags);
> +	if (priv->irq_no_disable)
> +		spin_lock_bh(&priv->lock);
> +	else
> +		spin_lock_irqsave(&priv->lock, *flags);
>  	if (priv->hw_unavailable) {
> -		printk(KERN_DEBUG "orinoco_lock() called with hw_unavailable (dev=%p)\n",
> +		DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
>  		       priv->ndev);
> -		spin_unlock_irqrestore(&priv->lock, *flags);
> +		if (priv->irq_no_disable)
> +			spin_unlock_bh(&priv->lock);
> +		else
> +			spin_unlock_irqrestore(&priv->lock, *flags);
>  		return -EBUSY;

This entire area has problems.

Orinoco doesn't need to invent its own locking primitives, nor does it 
need to be inventing functions that take *flags as an argument.

	Jeff

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 14/15] wireless/orinoco: add minimal ethtool support
  2004-10-26 19:24 ` [PATCH 2.6.10-rc1 14/15] wireless/orinoco: add minimal ethtool support Dan Williams
@ 2004-10-26 19:46   ` Jeff Garzik
  2004-10-27  4:01     ` David Gibson
  0 siblings, 1 reply; 37+ messages in thread
From: Jeff Garzik @ 2004-10-26 19:46 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, hermes

Dan Williams wrote:
> Update in-kernel orinoco wireless drivers to upstream CVS.
> None of this is original code by Dan Williams, simply a
> broken down patch set split-out from upstream orinoco CVS.
> 
> o Add minimal ethtool support (Pavel Roskin)

should use ethtool_ops rather than manually handling the ioctl

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-26 19:42       ` Christoph Hellwig
@ 2004-10-26 19:55         ` Dan Williams
  2004-10-27  3:13           ` David Gibson
  0 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-26 19:55 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: netdev, jgarzik, hermes

I will leave that do David/jgarzik since I didn't actually write any of
this code, I just broke the megadiff down.

Dan

On Tue, 2004-10-26 at 20:42 +0100, Christoph Hellwig wrote:
> On Tue, Oct 26, 2004 at 03:35:36PM -0400, Dan Williams wrote:
> > New description:
> > 
> > o Use msleep() instead of hardcoded schedule_timeout()s
> > o Normalize sleep calls to use msleep() everywhere
> 
> care to explain what's the point of the latter?
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCHES] wireless: Update in-kernel orinoco driver
  2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
                   ` (15 preceding siblings ...)
  2004-10-26 19:28 ` [PATCH 2.6.10-rc1 15/15] wireless/orinoco: Wireless scanning support Dan Williams
@ 2004-10-27  2:05 ` David Gibson
  16 siblings, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-27  2:05 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik, Pavel Roskin

On Tue, Oct 26, 2004 at 02:12:00PM -0400, Dan Williams wrote:
> This series of 15 patches updates the in-kernel orinoco wireless drivers
> to the level of current upstream orinoco CVS (from sourceforge).  This
> level is "0.15rc2HEAD" as found in orinoco.h.
> 
> The basis for this patchset was:
> 
> upstream orinoco CVS from Mon, Oct 25
> kernel sources from linux-2.6.9.tar.bz2 + patch-2.6.10-rc1.bz2
> 
> This is a revival of an effort to get the drivers up-to-date from
> earlier this year in July.

This is a much better effort at splitting up the CVS differences than
the last one I saw, but there are still some problems.  In particular,
you've aimed the patch series at the CVS HEAD branch, which isn't what
we want to do.  We want to merge to mainline the "for_linus" branch ,
not HEAD.  The HEAD branch has a bunch of compatibility code so that
the code can work standalone against a range of kernels - this should
not be merge.  Also it has several things that are there because they
kind-of work, but are really too ugly to live and should not be merged
to mainline.

Some more specific comments coming, on the individual patches.

Oh, and CCing Pavel Roskin <proski@gnu.org> the other orinoco
maintainer would be a good idea, too.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-26 19:55         ` Dan Williams
@ 2004-10-27  3:13           ` David Gibson
  2004-10-27 13:11             ` Dan Williams
  0 siblings, 1 reply; 37+ messages in thread
From: David Gibson @ 2004-10-27  3:13 UTC (permalink / raw)
  To: Dan Williams; +Cc: Christoph Hellwig, netdev, jgarzik

On Tue, Oct 26, 2004 at 03:55:12PM -0400, Dan Williams wrote:
> I will leave that do David/jgarzik since I didn't actually write any of
> this code, I just broke the megadiff down.

What's happened is that the old explicit schedule_timeout() constructs
were replaced in CVS with msleep() (ssleep() didn't exist at the
time).  In the meantime, at least some of them were replaced with
ssleep() in mainline.

I'm about to commit a patch to CVS replacing the msleep()s with
ssleep()s.  In the for_linus branch, at least, HEAD will take longer
because we'll need to come up with something to maintain compatibility
with pre-ssleep() kernels.

> On Tue, 2004-10-26 at 20:42 +0100, Christoph Hellwig wrote:
> > On Tue, Oct 26, 2004 at 03:35:36PM -0400, Dan Williams wrote:
> > > New description:
> > > 
> > > o Use msleep() instead of hardcoded schedule_timeout()s
> > > o Normalize sleep calls to use msleep() everywhere
> > 
> > care to explain what's the point of the latter?

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 3/15] wireless/orinoco: encapsulate direct hardware operations
  2004-10-26 18:43 ` [PATCH 2.6.10-rc1 3/15] wireless/orinoco: encapsulate direct hardware operations Dan Williams
@ 2004-10-27  3:15   ` David Gibson
  0 siblings, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-27  3:15 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik

On Tue, Oct 26, 2004 at 02:43:09PM -0400, Dan Williams wrote:
> Update in-kernel orinoco wireless drivers to upstream CVS.
> None of this is original code by Dan Williams, simply a
> broken down patch set split-out from upstream orinoco CVS.
> 
> o Encapsulate direct hardware operations so those symbols
>     don't need to be exported

No!  Don't apply this.  This abstraction is only needed for the
orinoco_usb driver (so is in HEAD, but not the for_linus branch), but
IMO the abstraction is in the wrong place, and should not go
upstream.  Of course, patches to make the abstraction not suck are
welcome.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters
  2004-10-26 18:45 ` [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters Dan Williams
  2004-10-26 19:36   ` Jeff Garzik
@ 2004-10-27  3:15   ` David Gibson
  1 sibling, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-27  3:15 UTC (permalink / raw)
  To: Dan Williams; +Cc: netdev, jgarzik

On Tue, Oct 26, 2004 at 02:45:55PM -0400, Dan Williams wrote:
> Update in-kernel orinoco wireless drivers to upstream CVS.
> None of this is original code by Dan Williams, simply a
> broken down patch set split-out from upstream orinoco CVS.
> 
> o Update orinoco changelog and module parameters

I don't think it's a good idea to apply this in the middle of the
others - it implies all the things in the changelog have gone in,
which they haven't, yet.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 7/15] wireless/orinoco: Update card reset/init code and add card-specific data structures
  2004-10-26 19:43   ` Jeff Garzik
@ 2004-10-27  4:00     ` David Gibson
  0 siblings, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-27  4:00 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Dan Williams, netdev, jgarzik

On Tue, Oct 26, 2004 at 03:43:20PM -0400, Jeff Garzik wrote:
> Dan Williams wrote:
> >+/* Orinoco PCI specific data */
> >+struct orinoco_pci_card {
> >+	u32 pci_state[16];	/* PCI suspend/resume state */
> >+};
> 
> no need with GregKH's latest upstream changes

And recently removed from the for_linus branch.

> >-	printk(KERN_NOTICE "Reset done");
> > 	timeout = jiffies + (HERMES_PCI_COR_ONT * HZ / 1000);
> >-	while(time_before(jiffies, timeout)) {
> >-		printk(".");
> >+	while(time_before(jiffies, timeout))
> > 		mdelay(1);
> 
> the loop is non-sensical... at this point use msleep() or actually 
> mdelay() for the correct period, rather than looping on mdelay(1)

Oh, yes, that really shouldn't have survived this long.  Now fixed in
CVS (for_linus branch, merge to HEAD coming shortly).

> >@@ -199,61 +194,68 @@
> > 	u16 *pci_ioaddr = NULL;
> > 	unsigned long pci_iolen;
> > 	struct orinoco_private *priv = NULL;
> >+	struct orinoco_pci_card *card;
> > 	struct net_device *dev = NULL;
> > 
> > 	err = pci_enable_device(pdev);
> >-	if (err)
> >-		return -EIO;
> >+	if (err) {
> >+		printk(KERN_ERR PFX "Cannot enable PCI device\n");
> >+		return -err;
> >+	}
> 
> incorrect...  err is already negative.

Also now fixed in CVS.

> >@@ -325,6 +327,9 @@
> > 	
> > 	orinoco_unlock(priv, &flags);
> > 
> >+	pci_save_state(pdev, card->pci_state);
> >+	pci_set_power_state(pdev, 3);
> >+
> > 	return 0;
> > }
> > 
> >@@ -332,11 +337,15 @@
> > {
> > 	struct net_device *dev = pci_get_drvdata(pdev);
> > 	struct orinoco_private *priv = netdev_priv(dev);
> >+	struct orinoco_pci_card *card = priv->card;
> > 	unsigned long flags;
> > 	int err;
> > 
> > 	printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
> > 
> >+	pci_set_power_state(pdev, 0);
> >+	pci_restore_state(pdev, card->pci_state);
> >+
> > 	err = orinoco_reinit_firmware(dev);
> > 	if (err) {
> > 		printk(KERN_ERR "%s: Error %d re-initializing firmware on 
> > 		orinoco_pci_resume()\n",
> 
> These two don't build in the latest 2.6.x kernel.

This was fixed by Pavel in the last day or so.

> >@@ -332,6 +374,8 @@
> > 	.id_table	= orinoco_plx_pci_id_table,
> > 	.probe		= orinoco_plx_init_one,
> > 	.remove		= __devexit_p(orinoco_plx_remove_one),
> >+	.suspend	= 0,
> >+	.resume		= 0,
> > };
> 
> superfluous change

Removed from CVS.

> >+ * Do a soft reset of the card using the Configuration Option Register
> >+ */
> >+static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
> >+{
> >+	hermes_t *hw = &priv->hw;
> >+	struct orinoco_tmd_card *card = priv->card;
> >+	u32 addr = card->tmd_io;
> >+	unsigned long timeout;
> >+	u16 reg;
> >+
> >+	outb(COR_VALUE | COR_RESET, addr);
> >+	mdelay(1);
> >+
> >+	outb(COR_VALUE, addr);
> >+	mdelay(1);
> 
> PCI posting bugs?

That I don't know.  Unfortunately a lot of these cards are rather
nasty and fragile, so I don't really want to mess with it.

> >+	/* Just in case, wait more until the card is no longer busy */
> >+	timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
> >+	reg = hermes_read_regn(hw, CMD);
> >+	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
> >+		mdelay(1);
> >+		reg = hermes_read_regn(hw, CMD);
> >+	}
> 
> max delay without sleep way too long

Yes, yes it is.  However, we've had a lot of trouble with timeouts and
locking and sleeping in the driver.  On the grounds that the bad case
usually won't be hit, I'd rather not mess with that until someone has
a rather better insight on how to organize this stuff to ensure we
give the cards the delays they need, without the blocks-in-sleep.  I
don't have a TMD card myself, so I'm extra wary about changing it.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 14/15] wireless/orinoco: add minimal ethtool support
  2004-10-26 19:46   ` Jeff Garzik
@ 2004-10-27  4:01     ` David Gibson
  0 siblings, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-27  4:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Dan Williams, netdev, jgarzik

On Tue, Oct 26, 2004 at 03:46:04PM -0400, Jeff Garzik wrote:
> Dan Williams wrote:
> >Update in-kernel orinoco wireless drivers to upstream CVS.
> >None of this is original code by Dan Williams, simply a
> >broken down patch set split-out from upstream orinoco CVS.
> >
> >o Add minimal ethtool support (Pavel Roskin)
> 
> should use ethtool_ops rather than manually handling the ioctl

Yes, we should, but no-one's done to work for the change.  I really
don't have time or resources myself - hence the long overdue merge in
the first place.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 15/15] wireless/orinoco: Wireless scanning support
  2004-10-26 19:33   ` Francois Romieu
@ 2004-10-27  4:06     ` David Gibson
  0 siblings, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-27  4:06 UTC (permalink / raw)
  To: Francois Romieu; +Cc: Dan Williams, netdev, jgarzik

On Tue, Oct 26, 2004 at 09:33:56PM +0200, Francois Romieu wrote:
> [...]
> > +++ b/drivers/net/wireless/orinoco.c	2004-08-17 17:26:31.000000000 -0400
> > @@ -1442,6 +1442,80 @@
> >  	       dev->name, s, status);
> >  }
> >  
> > +/* Search scan results for requested BSSID, join it if found */
> > +static void orinoco_join_ap(struct net_device *dev)
> > +{
> > +	struct orinoco_private *priv = netdev_priv(dev);
> > +	struct hermes *hw = &priv->hw;
> > +	int err;
> > +	unsigned long flags;
> > +	struct join_req {
> > +		u8 bssid[ETH_ALEN];
> > +		u16 channel;
> > +	} __attribute__ ((packed)) req;
> > +	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
> > +	struct prism2_scan_apinfo *atom;
> > +	int offset = 4;
> > +	int found = 0;
> > +	u8 *buf = NULL;
> > +	u16 len;
> > +
> > +	/* Allocate buffer for scan results */
> > +	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
> > +	if (!buf)
> > +		return;
> > +
> > +	if (orinoco_lock(priv, &flags) != 0)
> > +		return;
> 
> Leak.

Indeed.  Fix committed to CVS.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: R[PATCH 2.6.10-rc1 8/15] wireless/orinoco: Refactor spinlocks so we don't necessarily have to disable interrupts
  2004-10-26 19:44   ` Jeff Garzik
@ 2004-10-27  4:14     ` David Gibson
  0 siblings, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-27  4:14 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Dan Williams, netdev, jgarzik

On Tue, Oct 26, 2004 at 03:44:21PM -0400, Jeff Garzik wrote:
> Dan Williams wrote:
> >Update in-kernel orinoco wireless drivers to upstream CVS.
> >None of this is original code by Dan Williams, simply a
> >broken down patch set split-out from upstream orinoco CVS.
> >
> >o Refactor spinlocks so we don't necessarily have to disable
> interrupts

No, this should *not* be applied.  This again is orinoco_usb stuff,
which is in HEAD but not for_linus and which should not go upstream.

> >10:44:41.445687264 -0400
> >+++ b/drivers/net/wireless/orinoco.h	2004-10-26 10:45:39.296892544 -0400
> >@@ -71,6 +71,8 @@
> > 	u16 channel_mask;
> > 	int broken_disableport;
> > 
> >+	unsigned int irq_no_disable:1;
> >+
> > 	/* Configuration paramaters */
> > 	u32 iw_mode;
> > 	int prefer_port3;
> >@@ -129,11 +131,17 @@
> > extern inline int orinoco_lock(struct orinoco_private *priv,
> > 			       unsigned long *flags)
> > {
> >-	spin_lock_irqsave(&priv->lock, *flags);
> >+	if (priv->irq_no_disable)
> >+		spin_lock_bh(&priv->lock);
> >+	else
> >+		spin_lock_irqsave(&priv->lock, *flags);
> > 	if (priv->hw_unavailable) {
> >-		printk(KERN_DEBUG "orinoco_lock() called with hw_unavailable 
> >(dev=%p)\n",
> >+		DEBUG(1, "orinoco_lock() called with hw_unavailable 
> >(dev=%p)\n",
> > 		       priv->ndev);
> >-		spin_unlock_irqrestore(&priv->lock, *flags);
> >+		if (priv->irq_no_disable)
> >+			spin_unlock_bh(&priv->lock);
> >+		else
> >+			spin_unlock_irqrestore(&priv->lock, *flags);
> > 		return -EBUSY;
> 
> This entire area has problems.

Yes, it does.

> Orinoco doesn't need to invent its own locking primitives, nor does it 
> need to be inventing functions that take *flags as an argument.

The (already existing) orinoco_lock()/unlock() functions are somewhat
yucky, though I don't think abolishing them is an urgent item.  This
conditional locking stuff is completely insane.  It was added in HEAD
as part of the orinco_usb support, because I got sick of people
whinging about me not merging the usb support - in the hope that the
vile hacks would get removed over time.  I've told the USB folks on
several occasions that this conditional locking stuff is absolutely
too ugly to live, and needs to be done differently, but I've got
nothing but the "but it works!" argument.  I have neither the hardware
nor the time to figure out how to fix it properly myself.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-27  3:13           ` David Gibson
@ 2004-10-27 13:11             ` Dan Williams
  2004-10-28  1:42               ` David Gibson
  0 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2004-10-27 13:11 UTC (permalink / raw)
  To: David Gibson; +Cc: Christoph Hellwig, netdev, jgarzik

Ok, so in my zeal to get the kernel orinoco drivers to _not_ _suck_,
what branch is the most up-to-date?  Have you been commiting the stuff
here that you say is "committed to CVS" to _both_ HEAD and for_linus?

The things I care about (to bring orinoco drivers up to par with others
like prism54 & aironet):

1) Scanning support
2) monitor mode
3) the better firmware handling

Dan

On Wed, 2004-10-27 at 13:13 +1000, David Gibson wrote:
> On Tue, Oct 26, 2004 at 03:55:12PM -0400, Dan Williams wrote:
> > I will leave that do David/jgarzik since I didn't actually write any of
> > this code, I just broke the megadiff down.
> 
> What's happened is that the old explicit schedule_timeout() constructs
> were replaced in CVS with msleep() (ssleep() didn't exist at the
> time).  In the meantime, at least some of them were replaced with
> ssleep() in mainline.
> 
> I'm about to commit a patch to CVS replacing the msleep()s with
> ssleep()s.  In the for_linus branch, at least, HEAD will take longer
> because we'll need to come up with something to maintain compatibility
> with pre-ssleep() kernels.
> 
> > On Tue, 2004-10-26 at 20:42 +0100, Christoph Hellwig wrote:
> > > On Tue, Oct 26, 2004 at 03:35:36PM -0400, Dan Williams wrote:
> > > > New description:
> > > > 
> > > > o Use msleep() instead of hardcoded schedule_timeout()s
> > > > o Normalize sleep calls to use msleep() everywhere
> > > 
> > > care to explain what's the point of the latter?
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s
  2004-10-27 13:11             ` Dan Williams
@ 2004-10-28  1:42               ` David Gibson
  0 siblings, 0 replies; 37+ messages in thread
From: David Gibson @ 2004-10-28  1:42 UTC (permalink / raw)
  To: Dan Williams; +Cc: Christoph Hellwig, netdev, jgarzik

On Wed, Oct 27, 2004 at 09:11:11AM -0400, Dan Williams wrote:
> Ok, so in my zeal to get the kernel orinoco drivers to _not_ _suck_,
> what branch is the most up-to-date?  Have you been commiting the stuff
> here that you say is "committed to CVS" to _both_ HEAD and for_linus?

They are all equally up-to-date, more or less.  The difference between
the three branches is:
	HEAD - Has backwards compatibility code and experimental code
notready for merging (at preset, just USB support)
	standalone - Has backwards compatibility code, but not the
experimental code (so no USB support)
	for_linus - Has neither backwards compatibility code nor
experimental code.

Apart from the differences noted, the branches are kept merged.

I'm well aware that this merge with mainline is long, long overdue,
and frankly I've been a completely slack-arse maintainer.
Unfortunately, I really don't have the time or energy to spend on
this, and there doesn't seem to be anyone else eager to take over
maintainership.

> The things I care about (to bring orinoco drivers up to par with others
> like prism54 & aironet):
> 
> 1) Scanning support
> 2) monitor mode
> 3) the better firmware handling

All these are in all 3 branches.

-- 
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2004-10-28  1:42 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-10-26 18:12 [PATCHES] wireless: Update in-kernel orinoco driver Dan Williams
2004-10-26 18:33 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: Use msleep() instead of hardcoded schedule_timeout()s Dan Williams
2004-10-26 18:47   ` Christoph Hellwig
2004-10-26 19:35     ` Dan Williams
2004-10-26 19:42       ` Christoph Hellwig
2004-10-26 19:55         ` Dan Williams
2004-10-27  3:13           ` David Gibson
2004-10-27 13:11             ` Dan Williams
2004-10-28  1:42               ` David Gibson
2004-10-26 19:34   ` Jeff Garzik
2004-10-26 18:38 ` [PATCH 2.6.10-rc1 1/15] wireless/orinoco: use msleep() Dan Williams
2004-10-26 18:39 ` [PATCH 2.6.10-rc1 2/15] wireless/orinoco: fix up printk text Dan Williams
2004-10-26 18:43 ` [PATCH 2.6.10-rc1 3/15] wireless/orinoco: encapsulate direct hardware operations Dan Williams
2004-10-27  3:15   ` David Gibson
2004-10-26 18:45 ` [PATCH 2.6.10-rc1 4/15] wireless/orinoco: Update orinoco changelog and module parameters Dan Williams
2004-10-26 19:36   ` Jeff Garzik
2004-10-27  3:15   ` David Gibson
2004-10-26 18:47 ` [PATCH 2.6.10-rc1 5/15] wireless/orinoco: Update orinoco pcmcia driver's IRQ handling Dan Williams
2004-10-26 18:51 ` [PATCH 2.6.10-rc1 6/15] wireless/orinoco: New device data release function Dan Williams
2004-10-26 18:56 ` [PATCH 2.6.10-rc1 7/15] wireless/orinoco: Update card reset/init code and add card-specific data structures Dan Williams
2004-10-26 19:43   ` Jeff Garzik
2004-10-27  4:00     ` David Gibson
2004-10-26 19:04 ` R[PATCH 2.6.10-rc1 8/15] wireless/orinoco: Refactor spinlocks so we don't necessarily have to disable interrupts Dan Williams
2004-10-26 19:44   ` Jeff Garzik
2004-10-27  4:14     ` David Gibson
2004-10-26 19:07 ` [PATCH 2.6.10-rc1 9/15] wireless/orinoco: Remove dump_recs in preparation for a more flexible replacement Dan Williams
2004-10-26 19:13 ` [PATCH 2.6.10-rc1 10/15] wireless/orinoco: Use wireless handlers rather than ioctl()s Dan Williams
2004-10-26 19:18 ` [PATCH 2.6.10-rc1 11/15] wireless/orinoco: Clean up firmware version & capability detection Dan Williams
2004-10-26 19:20 ` [PATCH 2.6.10-rc1 12/15] wireless/orinoco: Use netif routines rather than keeping link state ourselves Dan Williams
2004-10-26 19:22 ` [PATCH 2.6.10-rc1 13/15] wireless/orinoco: RF monitor mode support Dan Williams
2004-10-26 19:24 ` [PATCH 2.6.10-rc1 14/15] wireless/orinoco: add minimal ethtool support Dan Williams
2004-10-26 19:46   ` Jeff Garzik
2004-10-27  4:01     ` David Gibson
2004-10-26 19:28 ` [PATCH 2.6.10-rc1 15/15] wireless/orinoco: Wireless scanning support Dan Williams
2004-10-26 19:33   ` Francois Romieu
2004-10-27  4:06     ` David Gibson
2004-10-27  2:05 ` [PATCHES] wireless: Update in-kernel orinoco driver David Gibson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).