patch-2.4.21 linux-2.4.21/drivers/net/wireless/orinoco.c
Next file: linux-2.4.21/drivers/net/wireless/orinoco.h
Previous file: linux-2.4.21/drivers/net/wireless/ieee802_11.h
Back to the patch index
Back to the overall index
- Lines: 3266
- Date:
2003-06-13 07:51:35.000000000 -0700
- Orig file:
linux-2.4.20/drivers/net/wireless/orinoco.c
- Orig date:
2002-08-02 17:39:44.000000000 -0700
diff -urN linux-2.4.20/drivers/net/wireless/orinoco.c linux-2.4.21/drivers/net/wireless/orinoco.c
@@ -1,4 +1,4 @@
-/* orinoco.c 0.11b - (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.13b - (formerly known as dldwd_cs.c and orinoco_cs.c)
*
* A driver for Hermes or Prism 2 chipset based PCMCIA wireless
* adaptors, with Lucent/Agere, Intersil or Symbol firmware.
@@ -240,7 +240,7 @@
* was never very useful.
* o Make Rx errors less noisy.
*
- * v0.10 -> v0.11 - 5 Apr Mar 2002 - David Gibson
+ * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
* o Laid the groundwork in hermes.[ch] for devices which map
* into PCI memory space rather than IO space.
* o Fixed bug in multicast handling (cleared multicast list when
@@ -256,7 +256,7 @@
* o Fixes for recent Symbol firmwares which lack AP density
* (Pavel Roskin).
*
- * v0.11 -> v0.11b - 29 Apr 2002 - David Gibson
+ * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
* o Handle different register spacing, necessary for Prism 2.5
* PCI adaptors (Steve Hill).
* o Cleaned up initialization of card structures in orinoco_cs
@@ -279,44 +279,101 @@
* o Fixed multiple bad kfree() bugs introduced by the
* alloc_orinocodev() changes.
*
+ * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
+ * o Support changing the MAC address.
+ * o Correct display of Intersil firmware revision numbers.
+ * o Entirely revised locking scheme. Should be both simpler and
+ * better.
+ * o Merged some common code in orinoco_plx, orinoco_pci and
+ * airport by creating orinoco_default_{open,stop,reset}()
+ * which are used as the dev->open, dev->stop, priv->reset
+ * callbacks if none are specified when alloc_orinocodev() is
+ * called.
+ * o Removed orinoco_plx_interupt() and orinoco_pci_interrupt().
+ * They didn't do anything.
+ *
+ * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
+ * o Some rearrangement of code.
+ * o Numerous fixups to locking and rest handling, particularly
+ * for PCMCIA.
+ * o This allows open and stop net_device methods to be in
+ * orinoco.c now, rather than in the init modules.
+ * o In orinoco_cs.c link->priv now points to the struct
+ * net_device not to the struct orinoco_private.
+ * o Added a check for undersized SNAP frames, which could cause
+ * crashes.
+ *
+ * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
+ * o Fix hw->num_init testing code, so num_init is actually
+ * incremented.
+ * o Fix very stupid bug in orinoco_cs which broke compile with
+ * CONFIG_SMP.
+ * o Squashed a warning.
+ *
+ * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
+ * o Change to C9X style designated initializers.
+ * o Add support for 3Com AirConnect PCI.
+ * o No longer ignore the hard_reset argument to
+ * alloc_orinocodev(). Oops.
+ *
+ * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
+ * o Revert the broken 0.12* locking scheme and go to a new yet
+ * simpler scheme.
+ * o Do firmware resets only in orinoco_init() and when waking
+ * the card from hard sleep.
+ *
+ * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
+ * o Re-introduced full resets (via schedule_task()) on Tx
+ * timeout.
+ *
+ * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
+ * o Minor cleanups to info frame handling. Add basic support
+ * for linkstatus info frames.
+ * o Include required kernel headers in orinoco.h, to avoid
+ * compile problems.
+ *
+ * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
+ * o Implemented hard reset for Airport cards
+ * o Experimental suspend/resume implementation for orinoco_pci
+ * o Abolished /proc debugging support, replaced with a debugging
+ * iwpriv. Now it's ugly and simple instead of ugly and complex.
+ * o Bugfix in hermes.c if the firmware returned a record length
+ * of 0, we could go clobbering memory.
+ * o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
+ * was set, which was usually true on PCMCIA hot removes.
+ * o Track LINKSTATUS messages, silently drop Tx packets before
+ * we are connected (avoids cofusing the firmware), and only
+ * give LINKSTATUS printk()s if the status has changed.
+ *
* TODO
- * o New wireless extensions API
+
+ * o New wireless extensions API (patch from Moustafa
+ * Youssef, updated by Jim Carter).
+ * o Fix PCMCIA hard resets with pcmcia-cs.
* o Handle de-encapsulation within network layer, provide 802.11
- * headers
+ * headers (patch from Thomas 'Dent' Mirlacher)
* o Fix possible races in SPY handling.
* o Disconnect wireless extensions from fundamental configuration.
- *
- * o Convert /proc debugging stuff to seqfile
- * o Use multiple Tx buffers
- */
-/* Notes on locking:
- *
- * The basic principle of operation is that everything except the
- * interrupt handler is serialized through a single spinlock in the
- * struct orinoco_private structure, using orinoco_lock() and
- * orinoco_unlock() (which in turn use spin_lock_bh() and
- * spin_unlock_bh()).
- *
- * The kernel's IRQ handling stuff ensures that the interrupt handler
- * does not re-enter itself. The interrupt handler is written such
- * that everything it does is safe without a lock: chiefly this means
- * that the Rx path uses one of the Hermes chipset's BAPs while
- * everything else uses the other.
- *
- * Actually, strictly speaking, the updating of the statistics from
- * the interrupt handler isn't safe without a lock. However the worst
- * that can happen is that we perturb the packet/byte counts slightly.
- * We could fix this to use atomic types, but it's probably not worth
- * it.
- *
- * The big exception is that that we don't want the irq handler
- * running when we actually reset or shut down the card, because
- * strange things might happen (probably the worst would be one packet
- * of garbage, but you can't be too careful). For this we use
- * __orinoco_stop_irqs() which will set a flag to disable the interrupt
- * handler, and wait for any outstanding instances of the handler to
- * complete. THIS WILL LOSE INTERRUPTS! so it shouldn't be used except
- * for resets, where losing a few interrupts is acceptable. */
+ * o (maybe) Software WEP support (patch from Stano Meduna).
+ * o (maybe) Use multiple Tx buffers - driver handling queue
+ * rather than firmware. */
+
+/* Locking and synchronization:
+ *
+ * The basic principle is that everything is serialized through a
+ * single spinlock, priv->lock. The lock is used in user, bh and irq
+ * context, so when taken outside hardirq context it should always be
+ * taken with interrupts disabled. The lock protects both the
+ * hardware and the struct orinoco_private.
+ *
+ * Another flag, priv->hw_unavailable indicates that the hardware is
+ * unavailable for an extended period of time (e.g. suspended, or in
+ * the middle of a hard reset). This flag is protected by the
+ * spinlock. All code which touches the hardware should check the
+ * flag after taking the lock, and if it is set, give up on whatever
+ * they are doing and drop the lock again. The orinoco_lock()
+ * function handles this (it unlocks and returns -EBUSY if
+ * hw_unavailable is true). */
#include <linux/config.h>
@@ -332,32 +389,20 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/wireless.h>
-#include <linux/list.h>
#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
#include "ieee802_11.h"
-/* Wireless extensions backwards compatibility */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-
-/* We do this this way to avoid ifdefs in the actual code */
-#ifdef WIRELESS_SPY
-#define SPY_NUMBER(priv) (priv->spy_number)
-#else
-#define SPY_NUMBER(priv) 0
-#endif /* WIRELESS_SPY */
+/********************************************************************/
+/* Module information */
+/********************************************************************/
-static char version[] __initdata = "orinoco.c 0.11b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");
#ifdef MODULE_LICENSE
@@ -371,6 +416,26 @@
EXPORT_SYMBOL(orinoco_debug);
#endif
+/********************************************************************/
+/* Compile time configuration and compatibility stuff */
+/********************************************************************/
+
+/* Wireless extensions backwards compatibility */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+
+/* We do this this way to avoid ifdefs in the actual code */
+#ifdef WIRELESS_SPY
+#define SPY_NUMBER(priv) (priv->spy_number)
+#else
+#define SPY_NUMBER(priv) 0
+#endif /* WIRELESS_SPY */
+
+/********************************************************************/
+/* Internal constants */
+/********************************************************************/
+
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
@@ -379,13 +444,15 @@
#define IRQ_BAP 1
#define MAX_IRQLOOPS_PER_IRQ 10
#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the
- device can legitimately generate */
+ device could legitimately generate */
#define SMALL_KEY_SIZE 5
#define LARGE_KEY_SIZE 13
#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */
#define DUMMY_FID 0xFFFF
+#define RUP_EVEN(a) (((a) + 1) & (~1))
+
/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
HERMES_MAX_MULTICAST : 0)*/
#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST)
@@ -403,7 +470,7 @@
/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */
struct {
- int bitrate; /* in 100s of kilbits */
+ int bitrate; /* in 100s of kilobits */
int automatic;
u16 agere_txratectrl;
u16 intersil_txratectrl;
@@ -419,6 +486,10 @@
};
#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
+/********************************************************************/
+/* Data types */
+/********************************************************************/
+
struct header_struct {
/* 802.3 */
u8 dest[ETH_ALEN];
@@ -438,27 +509,29 @@
#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
-/*
- * Function prototypes
- */
+/********************************************************************/
+/* Function prototypes */
+/********************************************************************/
static void orinoco_stat_gather(struct net_device *dev,
- struct sk_buff *skb,
- struct hermes_rx_descriptor *desc);
+ struct sk_buff *skb,
+ struct hermes_rx_descriptor *desc);
static struct net_device_stats *orinoco_get_stats(struct net_device *dev);
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev);
/* Hardware control routines */
+static int __orinoco_program_rids(struct orinoco_private *priv);
+
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
static int __orinoco_hw_setup_wep(struct orinoco_private *priv);
static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]);
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
- char buf[IW_ESSID_MAX_SIZE+1]);
+ char buf[IW_ESSID_MAX_SIZE+1]);
static long orinoco_hw_get_freq(struct orinoco_private *priv);
static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
- s32 *rates, int max);
+ s32 *rates, int max);
static void __orinoco_set_multicast_list(struct net_device *dev);
/* Interrupt handling routines */
@@ -471,6 +544,7 @@
static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);
static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);
+/* ioctl() routines */
static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
@@ -491,164 +565,168 @@
static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
-/* /proc debugging stuff */
-static int orinoco_proc_init(void);
-static void orinoco_proc_cleanup(void);
+static int orinoco_debug_dump_recs(struct orinoco_private *priv);
-/*
- * Inline functions
- */
-static inline void
-orinoco_lock(struct orinoco_private *priv)
-{
- spin_lock_bh(&priv->lock);
-}
+/********************************************************************/
+/* Function prototypes */
+/********************************************************************/
-static inline void
-orinoco_unlock(struct orinoco_private *priv)
+int __orinoco_up(struct net_device *dev)
{
- spin_unlock_bh(&priv->lock);
-}
+ struct orinoco_private *priv = dev->priv;
+ struct hermes *hw = &priv->hw;
+ int err;
-static inline int
-orinoco_irqs_allowed(struct orinoco_private *priv)
-{
- return test_bit(ORINOCO_STATE_DOIRQ, &priv->state);
-}
+ err = __orinoco_program_rids(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d configuring card\n",
+ dev->name, err);
+ return err;
+ }
-static inline void
-__orinoco_stop_irqs(struct orinoco_private *priv)
-{
- hermes_t *hw = &priv->hw;
+ /* Fire things up again */
+ hermes_set_irqmask(hw, ORINOCO_INTEN);
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d enabling MAC port\n",
+ dev->name, err);
+ return err;
+ }
- hermes_set_irqmask(hw, 0);
- clear_bit(ORINOCO_STATE_DOIRQ, &priv->state);
- while (test_bit(ORINOCO_STATE_INIRQ, &priv->state))
- ;
+ netif_start_queue(dev);
+
+ return 0;
}
-static inline void
-__orinoco_start_irqs(struct orinoco_private *priv, u16 irqmask)
+int __orinoco_down(struct net_device *dev)
{
- hermes_t *hw = &priv->hw;
+ struct orinoco_private *priv = dev->priv;
+ struct hermes *hw = &priv->hw;
+ int err;
- TRACE_ENTER(priv->ndev->name);
+ netif_stop_queue(dev);
- __cli(); /* FIXME: is this necessary? */
- set_bit(ORINOCO_STATE_DOIRQ, &priv->state);
- hermes_set_irqmask(hw, irqmask);
- __sti();
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d disabling MAC port\n",
+ dev->name, err);
+ return err;
+ }
+ hermes_set_irqmask(hw, 0);
+ hermes_write_regn(hw, EVACK, 0xffff);
- TRACE_EXIT(priv->ndev->name);
+ return 0;
}
-static inline void
-set_port_type(struct orinoco_private *priv)
+int orinoco_reinit_firmware(struct net_device *dev)
{
- switch (priv->iw_mode) {
- case IW_MODE_INFRA:
- priv->port_type = 1;
- priv->allow_ibss = 0;
- break;
- case IW_MODE_ADHOC:
- if (priv->prefer_port3) {
- priv->port_type = 3;
- priv->allow_ibss = 0;
- } else {
- priv->port_type = priv->ibss_port;
- priv->allow_ibss = 1;
- }
- break;
- default:
- printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
- priv->ndev->name);
+ struct orinoco_private *priv = dev->priv;
+ struct hermes *hw = &priv->hw;
+ int err;
+
+ err = hermes_init(hw);
+ if (err)
+ return err;
+
+ 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");
}
-}
-static inline int
-is_snap(struct header_struct *hdr)
-{
- return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
+ return err;
}
-static void
-orinoco_set_multicast_list(struct net_device *dev)
+static int orinoco_open(struct net_device *dev)
{
struct orinoco_private *priv = dev->priv;
+ unsigned long flags;
+ int err;
- orinoco_lock(priv);
- __orinoco_set_multicast_list(dev);
- orinoco_unlock(priv);
-}
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
-/*
- * Hardware control routines
- */
+ priv->open = 1;
-void
-orinoco_shutdown(struct orinoco_private *priv)
+ err = __orinoco_up(dev);
+
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
+
+static int orinoco_stop(struct net_device *dev)
{
+ struct orinoco_private *priv = dev->priv;
int err = 0;
- TRACE_ENTER(priv->ndev->name);
+ /* 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_lock(priv);
- __orinoco_stop_irqs(priv);
+ priv->open = 0;
- err = hermes_reset(&priv->hw);
- if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */
- printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev->name, err);
+ if (! priv->hw_unavailable)
+ err = __orinoco_down(dev);
- orinoco_unlock(priv);
+ spin_unlock_irq(&priv->lock);
- TRACE_EXIT(priv->ndev->name);
+ return err;
}
-int
-orinoco_reset(struct orinoco_private *priv)
+static int __orinoco_program_rids(struct orinoco_private *priv)
{
struct net_device *dev = priv->ndev;
hermes_t *hw = &priv->hw;
- int err = 0;
+ int err;
struct hermes_idstring idbuf;
- TRACE_ENTER(priv->ndev->name);
-
- /* Stop other people bothering us */
- orinoco_lock(priv);
- __orinoco_stop_irqs(priv);
-
- /* Check if we need a card reset */
- if (priv->hard_reset)
- priv->hard_reset(priv);
-
- /* Do standard firmware reset if we can */
- err = hermes_reset(hw);
- if (err)
- goto out;
-
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err == -EIO) {
- /* Try workaround for old Symbol firmware bug */
- priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err)
- goto out;
+ /* Set the MAC address */
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+ HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting MAC address\n", dev->name, err);
+ return err;
}
- /* Now set up all the parameters on the card */
-
/* Set up the link mode */
-
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting port type\n", dev->name, err);
+ 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) {
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS,
- priv->allow_ibss);
- if (err)
- goto out;
- if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss)
+ priv->createibss);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err);
+ return err;
+ }
+
+ if ((strlen(priv->desired_essid) == 0) && (priv->createibss)
&& (!priv->has_ibss_any)) {
printk(KERN_WARNING "%s: This firmware requires an \
ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
@@ -665,13 +743,17 @@
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
&idbuf);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting OWNSSID\n", dev->name, err);
+ return err;
+ }
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
&idbuf);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", dev->name, err);
+ return err;
+ }
/* Set the station name */
idbuf.len = cpu_to_le16(strlen(priv->nick));
@@ -679,26 +761,29 @@
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
&idbuf);
- if (err)
- goto out;
-
- /* Set the channel/frequency */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting nickname\n", dev->name, err);
+ return err;
+ }
/* Set AP density */
if (priv->has_sensitivity) {
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
priv->ap_density);
- if (err)
+ if (err) {
+ printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
+ "Disabling sensitivity control\n", dev->name, err);
+
priv->has_sensitivity = 0;
+ }
}
/* Set RTS threshold */
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting RTS threshold\n", dev->name, err);
+ return err;
+ }
/* Set fragmentation threshold or MWO robustness */
if (priv->has_mwo)
@@ -709,35 +794,52 @@
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
priv->frag_thresh);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting framentation\n", dev->name, err);
+ return err;
+ }
/* Set bitrate */
err = __orinoco_hw_set_bitrate(priv);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting bitrate\n", dev->name, err);
+ return err;
+ }
/* Set power management */
if (priv->has_pm) {
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED,
priv->pm_on);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFMULTICASTRECEIVE,
priv->pm_mcast);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFMAXSLEEPDURATION,
priv->pm_period);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFPMHOLDOVERDURATION,
priv->pm_timeout);
- if (err)
- goto out;
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
}
/* Set preamble - only for Symbol so far... */
@@ -746,8 +848,9 @@
HERMES_RID_CNFPREAMBLE_SYMBOL,
priv->preamble);
if (err) {
- printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name);
- goto out;
+ printk(KERN_ERR "%s: Error %d setting preamble\n",
+ dev->name, err);
+ return err;
}
}
@@ -755,41 +858,159 @@
if (priv->has_wep) {
err = __orinoco_hw_setup_wep(priv);
if (err) {
- printk(KERN_ERR "%s: Error %d activating WEP.\n",
+ printk(KERN_ERR "%s: Error %d activating WEP\n",
dev->name, err);
- goto out;
+ return err;
}
}
/* Set promiscuity / multicast*/
priv->promiscuous = 0;
priv->mc_count = 0;
- __orinoco_set_multicast_list(dev);
-
- __orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
- HERMES_EV_TX | HERMES_EV_TXEXC |
- HERMES_EV_WTERR | HERMES_EV_INFO |
- HERMES_EV_INFDROP);
+ __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
- err = hermes_enable_port(hw, 0);
+ return 0;
+}
+
+/* xyzzy */
+static int orinoco_reconfigure(struct orinoco_private *priv)
+{
+ struct hermes *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
+
+ orinoco_lock(priv, &flags);
+
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to disable port in orinco_reconfigure()\n",
+ priv->ndev->name);
+ goto out;
+ }
+
+ err = __orinoco_program_rids(priv);
if (err)
goto out;
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to enable port in orinco_reconfigure()\n",
+ priv->ndev->name);
+ goto out;
+ }
+
out:
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
+ return err;
- TRACE_EXIT(priv->ndev->name);
+}
- return err;
+/* This must be called from user context, without locks held - use
+ * schedule_task() */
+static void orinoco_reset(struct net_device *dev)
+{
+ struct orinoco_private *priv = dev->priv;
+ int err;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return;
+
+ priv->hw_unavailable = 1;
+ orinoco_unlock(priv, &flags);
+
+ 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;
+ }
+
+ err = orinoco_reinit_firmware(dev);
+ if (err) {
+ printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
+ dev->name, err);
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->hw_unavailable = 0;
+
+ err = __orinoco_up(dev);
+ if (err) {
+ printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
+ dev->name, err);
+ } else
+ dev->trans_start = jiffies;
+
+ orinoco_unlock(priv, &flags);
+
+ return;
+}
+
+/********************************************************************/
+/* Internal helper functions */
+/********************************************************************/
+
+static inline void
+set_port_type(struct orinoco_private *priv)
+{
+ switch (priv->iw_mode) {
+ case IW_MODE_INFRA:
+ priv->port_type = 1;
+ priv->createibss = 0;
+ break;
+ case IW_MODE_ADHOC:
+ if (priv->prefer_port3) {
+ priv->port_type = 3;
+ priv->createibss = 0;
+ } else {
+ priv->port_type = priv->ibss_port;
+ priv->createibss = 1;
+ }
+ break;
+ default:
+ printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
+ priv->ndev->name);
+ }
+}
+
+static inline int
+is_snap(struct header_struct *hdr)
+{
+ return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
}
+static void
+orinoco_set_multicast_list(struct net_device *dev)
+{
+ struct orinoco_private *priv = dev->priv;
+ unsigned long flags;
+
+ if (orinoco_lock(priv, &flags) != 0) {
+ printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
+ "called when hw_unavailable\n", dev->name);
+ return;
+ }
+
+ __orinoco_set_multicast_list(dev);
+ orinoco_unlock(priv, &flags);
+}
+
+/********************************************************************/
+/* Hardware control functions */
+/********************************************************************/
+
+
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
{
hermes_t *hw = &priv->hw;
int err = 0;
- TRACE_ENTER(priv->ndev->name);
-
if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
priv->ndev->name, priv->bitratemode);
@@ -812,8 +1033,6 @@
BUG();
}
- TRACE_EXIT(priv->ndev->name);
-
return err;
}
@@ -825,8 +1044,6 @@
int master_wep_flag;
int auth_flag;
- TRACE_ENTER(priv->ndev->name);
-
switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
if (priv->wep_on) {
@@ -920,8 +1137,6 @@
}
}
- TRACE_EXIT(priv->ndev->name);
-
return 0;
}
@@ -929,13 +1144,16 @@
{
hermes_t *hw = &priv->hw;
int err = 0;
+ unsigned long flags;
- orinoco_lock(priv);
+ 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);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -948,10 +1166,11 @@
struct hermes_idstring essidbuf;
char *p = (char *)(&essidbuf.val);
int len;
+ unsigned long flags;
- TRACE_ENTER(priv->ndev->name);
-
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
if (strlen(priv->desired_essid) > 0) {
/* We read the desired SSID from the hardware rather
@@ -988,9 +1207,7 @@
buf[len] = '\0';
fail_unlock:
- orinoco_unlock(priv);
-
- TRACE_EXIT(priv->ndev->name);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -1002,13 +1219,22 @@
int err = 0;
u16 channel;
long freq = 0;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
if (err)
goto out;
+ /* Intersil firmware 1.3.5 returns 0 when the interface is down */
+ if (channel == 0) {
+ err = -EBUSY;
+ goto out;
+ }
+
if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
struct net_device *dev = priv->ndev;
@@ -1020,7 +1246,7 @@
freq = channel_frequency[channel-1] * 100000;
out:
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
if (err > 0)
err = -EBUSY;
@@ -1036,11 +1262,15 @@
int err = 0;
int num;
int i;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
- orinoco_lock(priv);
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
sizeof(list), NULL, &list);
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
if (err)
return err;
@@ -1122,7 +1352,7 @@
/*
* Interrupt handler
*/
-void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs)
+void orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct orinoco_private *priv = (struct orinoco_private *) dev_id;
hermes_t *hw = &priv->hw;
@@ -1134,38 +1364,26 @@
* we panic and shut down the hardware */
static int last_irq_jiffy = 0; /* jiffies value the last time we were called */
static int loops_this_jiffy = 0;
+ unsigned long flags;
- if (test_and_set_bit(ORINOCO_STATE_INIRQ, &priv->state))
- BUG();
-
- if (! orinoco_irqs_allowed(priv)) {
- clear_bit(ORINOCO_STATE_INIRQ, &priv->state);
+ if (orinoco_lock(priv, &flags) != 0) {
+ /* If hw is unavailable */
return;
}
- DEBUG(3, "%s: orinoco_interrupt()\n", priv->ndev->name);
-
evstat = hermes_read_regn(hw, EVSTAT);
events = evstat & hw->inten;
-/* if (! events) { */
-/* printk(KERN_WARNING "%s: Null event\n", dev->name); */
-/* } */
-
if (jiffies != last_irq_jiffy)
loops_this_jiffy = 0;
last_irq_jiffy = jiffies;
while (events && count--) {
- DEBUG(3, "__orinoco_interrupt(): count=%d EVSTAT=0x%04x\n",
- count, evstat);
-
if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
printk(KERN_CRIT "%s: IRQ handler is looping too \
much! Shutting down.\n",
dev->name);
/* Perform an emergency shutdown */
- clear_bit(ORINOCO_STATE_DOIRQ, &priv->state);
hermes_set_irqmask(hw, 0);
break;
}
@@ -1199,7 +1417,7 @@
events = evstat & hw->inten;
};
- clear_bit(ORINOCO_STATE_INIRQ, &priv->state);
+ orinoco_unlock(priv, &flags);
}
static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw)
@@ -1211,8 +1429,8 @@
{
/* This seems to happen a fair bit under load, but ignoring it
seems to work fine...*/
- DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n",
- priv->ndev->name);
+ printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
+ priv->ndev->name);
}
static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw)
@@ -1220,6 +1438,40 @@
printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name);
}
+static void print_linkstatus(struct net_device *dev, u16 status)
+{
+ char * s;
+
+ switch (status) {
+ case HERMES_LINKSTATUS_NOT_CONNECTED:
+ s = "Not Connected";
+ break;
+ case HERMES_LINKSTATUS_CONNECTED:
+ s = "Connected";
+ break;
+ case HERMES_LINKSTATUS_DISCONNECTED:
+ s = "Disconnected";
+ break;
+ case HERMES_LINKSTATUS_AP_CHANGE:
+ s = "AP Changed";
+ break;
+ case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+ s = "AP Out of Range";
+ break;
+ case HERMES_LINKSTATUS_AP_IN_RANGE:
+ s = "AP In Range";
+ break;
+ case HERMES_LINKSTATUS_ASSOC_FAILED:
+ s = "Association Failed";
+ break;
+ default:
+ s = "UNKNOWN";
+ }
+
+ printk(KERN_INFO "%s: New link status: %s (%04x)\n",
+ dev->name, s, status);
+}
+
static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw)
{
struct net_device *dev = priv->ndev;
@@ -1228,6 +1480,7 @@
u16 len;
u16 type;
} __attribute__ ((packed)) info;
+ int len, type;
int err;
/* This is an answer to an INQUIRE command that we did earlier,
@@ -1235,8 +1488,6 @@
* The controller return to us a pseudo frame containing
* the information in question - Jean II */
infofid = hermes_read_regn(hw, INFOFID);
- DEBUG(3, "%s: __orinoco_ev_info(): INFOFID=0x%04x\n", dev->name,
- infofid);
/* Read the info frame header - don't try too hard */
err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
@@ -1247,25 +1498,29 @@
return;
}
- switch (le16_to_cpu(info.type)) {
+ len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
+ type = le16_to_cpu(info.type);
+
+ switch (type) {
case HERMES_INQ_TALLIES: {
struct hermes_tallies_frame tallies;
struct iw_statistics *wstats = &priv->wstats;
- int len = le16_to_cpu(info.len) - 1;
- if (len > (sizeof(tallies) / 2)) {
- DEBUG(1, "%s: tallies frame too long.\n", dev->name);
- len = sizeof(tallies) / 2;
+ if (len > sizeof(tallies)) {
+ printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
+ dev->name, len);
+ len = sizeof(tallies);
}
/* Read directly the data (no seek) */
- hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, len);
+ hermes_read_words(hw, HERMES_DATA1, (void *) &tallies,
+ len / 2); /* FIXME: blech! */
/* Increment our various counters */
/* wstats->discard.nwid - no wrong BSSID stuff */
wstats->discard.code +=
le16_to_cpu(tallies.RxWEPUndecryptable);
- if (len == (sizeof(tallies) / 2))
+ if (len == sizeof(tallies))
wstats->discard.code +=
le16_to_cpu(tallies.RxDiscards_WEPICVError) +
le16_to_cpu(tallies.RxDiscards_WEPExcluded);
@@ -1277,17 +1532,42 @@
wstats->discard.retries +=
le16_to_cpu(tallies.TxRetryLimitExceeded);
/* wstats->miss.beacon - no match */
-#if ORINOCO_DEBUG > 3
- /* Hack for debugging - should not be taken as an example */
- wstats->discard.nwid += le16_to_cpu(tallies.TxUnicastFrames);
- wstats->miss.beacon += le16_to_cpu(tallies.RxUnicastFrames);
-#endif
#endif /* WIRELESS_EXT > 11 */
}
break;
+ case HERMES_INQ_LINKSTATUS: {
+ struct hermes_linkstatus linkstatus;
+ u16 newstatus;
+
+ if (len != sizeof(linkstatus)) {
+ printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
+ dev->name, len);
+ break;
+ }
+
+ hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus,
+ len / 2);
+ newstatus = le16_to_cpu(linkstatus.linkstatus);
+
+ if ( (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;
+
+ if (newstatus != priv->last_linkstatus)
+ print_linkstatus(dev, newstatus);
+
+ priv->last_linkstatus = newstatus;
+ }
+ break;
default:
- DEBUG(1, "%s: Unknown information frame received (type %04x).\n",
- priv->ndev->name, le16_to_cpu(info.type));
+ printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n",
+ dev->name, type);
/* We don't actually do anything about it */
break;
}
@@ -1308,7 +1588,6 @@
int err;
rxfid = hermes_read_regn(hw, RXFID);
- DEBUG(3, "__orinoco_ev_rx(): RXFID=0x%04x\n", rxfid);
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc),
rxfid, 0);
@@ -1349,11 +1628,11 @@
length = ntohs(hdr.len);
/* Sanity checks */
- if (length < sizeof(struct header_struct)) {
- printk(KERN_WARNING "%s: Undersized frame received (%d bytes)\n",
- dev->name, length);
- stats->rx_length_errors++;
- stats->rx_errors++;
+ if (length < 3) { /* No for even an 802.2 LLC header */
+ /* At least on Symbol firmware with PCF we get quite a
+ lot of these legitimately - Poll frames with no
+ data. */
+ stats->rx_dropped++;
goto drop;
}
if (length > IEEE802_11_DATA_LEN) {
@@ -1373,7 +1652,6 @@
if (!skb) {
printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
dev->name);
- stats->rx_dropped++;
goto drop;
}
@@ -1383,8 +1661,7 @@
* 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 (note : only 3 bytes out of 6).
- */
+ * So, check ourselves */
if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
is_snap(&hdr)) {
@@ -1392,7 +1669,7 @@
802.11 frame which we'll need to de-encapsulate to
the original EthernetII frame. */
- if (length < ENCAPS_OVERHEAD) {
+ if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
stats->rx_length_errors++;
stats->rx_dropped++;
goto drop;
@@ -1420,7 +1697,7 @@
err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
rxfid, data_off);
if (err) {
- printk(KERN_ERR "%s: error %d reading frame header. "
+ printk(KERN_ERR "%s: error %d reading frame. "
"Frame dropped.\n", dev->name, err);
stats->rx_errors++;
goto drop;
@@ -1442,6 +1719,8 @@
return;
drop:
+ stats->rx_dropped++;
+
if (skb)
dev_kfree_skb_irq(skb);
return;
@@ -1475,11 +1754,7 @@
static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw)
{
-/* struct net_device *dev = priv->ndev; */
struct net_device_stats *stats = &priv->stats;
-/* u16 fid = hermes_read_regn(hw, TXCOMPLFID); */
-
-/* DEBUG(2, "%s: Transmit completed (FID=%04X)\n", priv->ndev->name, fid); */
stats->tx_packets++;
@@ -1491,8 +1766,6 @@
struct net_device *dev = priv->ndev;
u16 fid = hermes_read_regn(hw, ALLOCFID);
- DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev->name, fid);
-
if (fid != priv->txfid) {
if (fid != DUMMY_FID)
printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
@@ -1506,16 +1779,17 @@
}
struct sta_id {
- u16 id, vendor, major, minor;
+ u16 id, variant, major, minor;
} __attribute__ ((packed));
static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id)
{
- u32 firmver = ((u32)sta_id->major << 16) | sta_id->minor;
+ /* FIXME: this is fundamentally broken */
+ unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor;
- if (sta_id->vendor == 1)
+ if (sta_id->variant == 1)
return FIRMWARE_TYPE_AGERE;
- else if ((sta_id->vendor == 2) &&
+ else if ((sta_id->variant == 2) &&
((firmver == 0x10001) || (firmver == 0x20001)))
return FIRMWARE_TYPE_SYMBOL;
else
@@ -1528,7 +1802,7 @@
hermes_t *hw = &priv->hw;
int err;
struct sta_id sta_id;
- u32 firmver;
+ unsigned int firmver;
char tmp[SYMBOL_MAX_VER_LEN+1];
/* Get the firmware version */
@@ -1539,14 +1813,12 @@
memset(&sta_id, 0, sizeof(sta_id));
}
le16_to_cpus(&sta_id.id);
- le16_to_cpus(&sta_id.vendor);
+ le16_to_cpus(&sta_id.variant);
le16_to_cpus(&sta_id.major);
le16_to_cpus(&sta_id.minor);
- firmver = ((u32)sta_id.major << 16) | sta_id.minor;
-
printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
- dev->name, sta_id.id, sta_id.vendor,
+ dev->name, sta_id.id, sta_id.variant,
sta_id.major, sta_id.minor);
if (! priv->firmware_type)
@@ -1561,7 +1833,6 @@
priv->has_ibss_any = 0;
priv->has_wep = 0;
priv->has_big_wep = 0;
- priv->broken_cor_reset = 0;
/* Determine capabilities from the firmware version */
switch (priv->firmware_type) {
@@ -1572,6 +1843,8 @@
"version %d.%02d\n", dev->name,
sta_id.major, sta_id.minor);
+ 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);
@@ -1581,8 +1854,6 @@
priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
priv->ibss_port = 1;
- /* FIXME: Which firmware really do have a broken reset */
- priv->broken_cor_reset = (firmver < 0x60000);
/* Tested with Agere firmware :
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
* Tested CableTron firmware : 4.32 => Anton */
@@ -1634,18 +1905,21 @@
/* D-Link MAC : 00:40:05:* */
/* Addtron MAC : 00:90:D1:* */
printk(KERN_DEBUG "%s: Looks like an Intersil firmware "
- "version %d.%02d\n", dev->name,
- sta_id.major, sta_id.minor);
+ "version %d.%d.%d\n", dev->name,
+ sta_id.major, sta_id.minor, sta_id.variant);
- priv->has_ibss = (firmver >= 0x00007); /* FIXME */
- priv->has_big_wep = priv->has_wep = (firmver >= 0x00008);
- priv->has_pm = (firmver >= 0x00007);
+ firmver = ((unsigned long)sta_id.major << 16) |
+ ((unsigned long)sta_id.minor << 8) | sta_id.variant;
- if (firmver >= 0x00008)
+ priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+ priv->has_pm = (firmver >= 0x000700);
+
+ if (firmver >= 0x000800)
priv->ibss_port = 0;
else {
printk(KERN_NOTICE "%s: Intersil firmware earlier "
- "than v0.08 - several features not supported\n",
+ "than v0.8.x - several features not supported\n",
dev->name);
priv->ibss_port = 1;
}
@@ -1669,16 +1943,16 @@
u16 reclen;
int len;
- TRACE_ENTER("orinoco");
-
- orinoco_lock(priv);
+ TRACE_ENTER(dev->name);
+ /* No need to lock, the resetting flag is already set in
+ * alloc_orinocodev() */
priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
- /* Do standard firmware reset */
- err = hermes_reset(hw);
+ /* Initialize the firmware */
+ err = hermes_init(hw);
if (err != 0) {
- printk(KERN_ERR "%s: failed to reset hardware (err = %d)\n",
+ printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
dev->name, err);
goto out;
}
@@ -1807,20 +2081,38 @@
priv->wep_on = 0;
priv->tx_key = 0;
- printk(KERN_DEBUG "%s: ready\n", dev->name);
+ priv->hw_unavailable = 0;
- out:
- orinoco_unlock(priv);
+ 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;
+ }
- TRACE_EXIT("orinoco");
+ printk(KERN_DEBUG "%s: ready\n", dev->name);
+ out:
+ TRACE_EXIT(dev->name);
return err;
}
struct net_device_stats *
orinoco_get_stats(struct net_device *dev)
{
- struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+ struct orinoco_private *priv = dev->priv;
return &priv->stats;
}
@@ -1828,15 +2120,22 @@
struct iw_statistics *
orinoco_get_wireless_stats(struct net_device *dev)
{
- struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+ struct orinoco_private *priv = dev->priv;
hermes_t *hw = &priv->hw;
struct iw_statistics *wstats = &priv->wstats;
int err = 0;
+ unsigned long flags;
- if (! netif_device_present(dev))
- return NULL; /* FIXME: We may be able to do better than this */
+ if (! netif_device_present(dev)) {
+ printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
+ dev->name);
+ return NULL; /* FIXME: Can we do better than this? */
+ }
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return NULL; /* FIXME: Erg, we've been signalled, how
+ * do we propagate this back up? */
if (priv->iw_mode == IW_MODE_ADHOC) {
memset(&wstats->qual, 0, sizeof(wstats->qual));
@@ -1856,9 +2155,6 @@
err = HERMES_READ_RECORD(hw, USER_BAP,
HERMES_RID_COMMSQUALITY, &cq);
- DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name,
- cq.qual, cq.signal, cq.noise);
-
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;
@@ -1868,11 +2164,11 @@
/* 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: Hmm.. seems a bit ugly, I wonder if there's a way to
- do better - dgibson */
+ /* 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);
+ orinoco_unlock(priv, &flags);
if (err)
return NULL;
@@ -1932,21 +2228,42 @@
struct ethhdr *eh;
int len, data_len, data_off;
struct hermes_tx_descriptor desc;
+ unsigned long flags;
+
+ TRACE_ENTER(dev->name);
if (! netif_running(dev)) {
printk(KERN_ERR "%s: Tx on stopped device!\n",
dev->name);
+ TRACE_EXIT(dev->name);
return 1;
-
}
if (netif_queue_stopped(dev)) {
- printk(KERN_ERR "%s: Tx while transmitter busy!\n",
+ printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
dev->name);
+ TRACE_EXIT(dev->name);
return 1;
}
- orinoco_lock(priv);
+ if (orinoco_lock(priv, &flags) != 0) {
+ printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
+ dev->name);
+ TRACE_EXIT(dev->name);
+/* BUG(); */
+ return 1;
+ }
+
+ if (! priv->connected) {
+ /* Oops, the firmware hasn't established a connection,
+ silently drop the packet (this seems to be the
+ safest approach). */
+ stats->tx_errors++;
+ orinoco_unlock(priv, &flags);
+ dev_kfree_skb(skb);
+ TRACE_EXIT(dev->name);
+ return 0;
+ }
/* Length of the packet body */
/* FIXME: what if the skb is smaller than this? */
@@ -2017,14 +2334,17 @@
dev->trans_start = jiffies;
stats->tx_bytes += data_off + data_len;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
dev_kfree_skb(skb);
+ TRACE_EXIT(dev->name);
+
return 0;
fail:
+ TRACE_EXIT(dev->name);
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2034,27 +2354,21 @@
struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
struct net_device_stats *stats = &priv->stats;
struct hermes *hw = &priv->hw;
- int err = 0;
- printk(KERN_WARNING "%s: Tx timeout! Resetting card. ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", dev->name, hermes_read_regn(hw, ALLOCFID), hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
+ printk(KERN_WARNING "%s: Tx timeout! "
+ "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
+ dev->name, hermes_read_regn(hw, ALLOCFID),
+ hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
stats->tx_errors++;
- err = orinoco_reset(priv);
- if (err)
- printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
- dev->name, err);
- else {
- dev->trans_start = jiffies;
- netif_wake_queue(dev);
- }
+ schedule_task(&priv->timeout_task);
}
static int
orinoco_change_mtu(struct net_device *dev, int new_mtu)
{
struct orinoco_private *priv = dev->priv;
- TRACE_ENTER(dev->name);
if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
return -EINVAL;
@@ -2065,11 +2379,10 @@
dev->mtu = new_mtu;
- TRACE_EXIT(dev->name);
-
return 0;
}
+/* FIXME: return int? */
static void
__orinoco_set_multicast_list(struct net_device *dev)
{
@@ -2078,17 +2391,6 @@
int err = 0;
int promisc, mc_count;
- /* We'll wait until it's ready. Anyway, the network doesn't call us
- * here until we are open - Jean II */
- /* FIXME: do we need this test at all? */
- if (! netif_device_present(dev)) {
- printk(KERN_WARNING "%s: __orinoco_set_multicast_list() called while device "
- "not present.\n", dev->name);
- return;
- }
-
- TRACE_ENTER(dev->name);
-
/* The Hermes doesn't seem to have an allmulti mode, so we go
* into promiscuous mode and let the upper levels deal. */
if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
@@ -2146,8 +2448,6 @@
dev->flags |= IFF_PROMISC;
else
dev->flags &= ~IFF_PROMISC;
-
- TRACE_EXIT(dev->name);
}
/********************************************************************/
@@ -2162,6 +2462,7 @@
struct iw_range range;
int numrates;
int i, k;
+ unsigned long flags;
TRACE_ENTER(dev->name);
@@ -2171,9 +2472,12 @@
rrq->length = sizeof(range);
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
+
mode = priv->iw_mode;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
memset(&range, 0, sizeof(range));
@@ -2246,7 +2550,9 @@
range.min_frag = 256;
range.max_frag = 2346;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
if (priv->has_wep) {
range.max_encoding_tokens = ORINOCO_MAX_KEYS;
@@ -2261,7 +2567,7 @@
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
}
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
range.min_pmp = 0;
range.max_pmp = 65535000;
@@ -2303,6 +2609,7 @@
u16 xlen = 0;
int err = 0;
char keybuf[ORINOCO_MAX_KEY_SIZE];
+ unsigned long flags;
if (erq->pointer) {
/* We actually have a key to set */
@@ -2313,7 +2620,9 @@
return -EFAULT;
}
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
if (erq->pointer) {
if (erq->length > ORINOCO_MAX_KEY_SIZE) {
@@ -2377,9 +2686,10 @@
priv->tx_key = setindex;
priv->wep_on = enable;
priv->wep_restrict = restricted;
+
out:
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2390,9 +2700,12 @@
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0;
char keybuf[ORINOCO_MAX_KEY_SIZE];
-
+ int err;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
index = priv->tx_key;
@@ -2418,7 +2731,7 @@
memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
}
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
if (erq->pointer) {
if (copy_to_user(erq->pointer, keybuf, xlen))
@@ -2432,6 +2745,8 @@
{
struct orinoco_private *priv = dev->priv;
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 */
@@ -2448,11 +2763,13 @@
essidbuf[erq->length] = '\0';
}
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -2463,6 +2780,7 @@
char essidbuf[IW_ESSID_MAX_SIZE+1];
int active;
int err = 0;
+ unsigned long flags;
TRACE_ENTER(dev->name);
@@ -2471,9 +2789,11 @@
if (err)
return err;
} else {
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
}
erq->flags = 1;
@@ -2491,6 +2811,8 @@
{
struct orinoco_private *priv = dev->priv;
char nickbuf[IW_ESSID_MAX_SIZE+1];
+ int err;
+ unsigned long flags;
if (nrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG;
@@ -2502,11 +2824,13 @@
nickbuf[nrq->length] = '\0';
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
memcpy(priv->nick, nickbuf, sizeof(priv->nick));
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -2515,10 +2839,15 @@
{
struct orinoco_private *priv = dev->priv;
char nickbuf[IW_ESSID_MAX_SIZE+1];
+ int err;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
- orinoco_lock(priv);
memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
nrq->length = strlen(nickbuf)+1;
@@ -2532,6 +2861,8 @@
{
struct orinoco_private *priv = dev->priv;
int chan = -1;
+ int err;
+ unsigned long flags;
/* 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
@@ -2559,9 +2890,11 @@
! (priv->channel_mask & (1 << (chan-1)) ) )
return -EINVAL;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
priv->channel = chan;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -2572,13 +2905,16 @@
hermes_t *hw = &priv->hw;
u16 val;
int err;
+ unsigned long flags;
if (!priv->has_sensitivity)
return -EOPNOTSUPP;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &val);
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
if (err)
return err;
@@ -2593,6 +2929,8 @@
{
struct orinoco_private *priv = dev->priv;
int val = srq->value;
+ int err;
+ unsigned long flags;
if (!priv->has_sensitivity)
return -EOPNOTSUPP;
@@ -2600,9 +2938,11 @@
if ((val < 1) || (val > 3))
return -EINVAL;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
priv->ap_density = val;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -2611,6 +2951,8 @@
{
struct orinoco_private *priv = dev->priv;
int val = rrq->value;
+ int err;
+ unsigned long flags;
if (rrq->disabled)
val = 2347;
@@ -2618,9 +2960,12 @@
if ( (val < 0) || (val > 2347) )
return -EINVAL;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
+
priv->rts_thresh = val;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -2629,8 +2974,11 @@
{
struct orinoco_private *priv = dev->priv;
int err = 0;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
if (priv->has_mwo) {
if (frq->disabled)
@@ -2652,7 +3000,7 @@
}
}
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2663,8 +3011,11 @@
hermes_t *hw = &priv->hw;
int err = 0;
u16 val;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
if (priv->has_mwo) {
err = hermes_read_wordrec(hw, USER_BAP,
@@ -2687,7 +3038,7 @@
frq->fixed = 1;
}
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2699,6 +3050,7 @@
int ratemode = -1;
int bitrate; /* 100s of kilobits */
int i;
+ unsigned long flags;
/* As the user space doesn't know our highest rate, it uses -1
* to ask us to set the highest rate. Test it using "iwconfig
@@ -2725,9 +3077,11 @@
if (ratemode == -1)
return -EINVAL;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
priv->bitratemode = ratemode;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2740,12 +3094,15 @@
int ratemode;
int i;
u16 val;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
ratemode = priv->bitratemode;
- if ( (ratemode < 0) || (ratemode > BITRATE_TABLE_SIZE) )
+ if ( (ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE) )
BUG();
rrq->value = bitrate_table[ratemode].bitrate * 100000;
@@ -2791,7 +3148,7 @@
}
out:
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2800,9 +3157,11 @@
{
struct orinoco_private *priv = dev->priv;
int err = 0;
+ unsigned long flags;
-
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
if (prq->disabled) {
priv->pm_on = 0;
@@ -2842,7 +3201,7 @@
}
out:
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2853,8 +3212,11 @@
hermes_t *hw = &priv->hw;
int err = 0;
u16 enable, period, timeout, mcast;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable);
if (err)
@@ -2888,7 +3250,7 @@
prq->flags |= IW_POWER_UNICAST_R;
out:
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2900,8 +3262,11 @@
hermes_t *hw = &priv->hw;
int err = 0;
u16 short_limit, long_limit, lifetime;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
&short_limit);
@@ -2938,7 +3303,7 @@
}
out:
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -2948,14 +3313,19 @@
{
struct orinoco_private *priv = dev->priv;
int val = *( (int *) wrq->u.name );
+ int err;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
- orinoco_lock(priv);
priv->ibss_port = val ;
/* Actually update the mode we are using */
set_port_type(priv);
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -2963,10 +3333,15 @@
{
struct orinoco_private *priv = dev->priv;
int *val = (int *)wrq->u.name;
+ int err;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
- orinoco_lock(priv);
*val = priv->ibss_port;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -2976,15 +3351,18 @@
struct orinoco_private *priv = dev->priv;
int val = *( (int *) wrq->u.name );
int err = 0;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
- orinoco_lock(priv);
switch (val) {
case 0: /* Try to do IEEE ad-hoc mode */
if (! priv->has_ibss) {
err = -EINVAL;
break;
}
- DEBUG(2, "%s: Prefer IBSS Ad-Hoc mode\n", dev->name);
priv->prefer_port3 = 0;
break;
@@ -2994,7 +3372,6 @@
err = -EINVAL;
break;
}
- DEBUG(2, "%s: Prefer Ad-Hoc demo mode\n", dev->name);
priv->prefer_port3 = 1;
break;
@@ -3006,7 +3383,7 @@
/* Actually update the mode we are using */
set_port_type(priv);
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -3015,10 +3392,15 @@
{
struct orinoco_private *priv = dev->priv;
int *val = (int *)wrq->u.name;
+ int err;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
- orinoco_lock(priv);
*val = priv->prefer_port3;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return 0;
}
@@ -3032,6 +3414,7 @@
int number = srq->length;
int i;
int err = 0;
+ unsigned long flags;
/* Check the number of addresses */
if (number > IW_MAX_SPY)
@@ -3045,7 +3428,9 @@
}
/* Make sure nobody mess with the structure while we do */
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
/* orinoco_lock() doesn't disable interrupts, so make sure the
* interrupt rx path don't get confused while we copy */
@@ -3063,18 +3448,8 @@
priv->spy_number = number;
}
- /* Time to show what we have done... */
- DEBUG(0, "%s: New spy list:\n", dev->name);
- for (i = 0; i < number; i++) {
- DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, i+1,
- priv->spy_address[i][0], priv->spy_address[i][1],
- priv->spy_address[i][2], priv->spy_address[i][3],
- priv->spy_address[i][4], priv->spy_address[i][5]);
- }
-
/* Now, let the others play */
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
return err;
}
@@ -3086,8 +3461,12 @@
struct iw_quality spy_stat[IW_MAX_SPY];
int number;
int i;
+ int err;
+ unsigned long flags;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
number = priv->spy_number;
if ((number > 0) && (srq->pointer)) {
@@ -3107,7 +3486,7 @@
priv->spy_stat[i].updated = 0;
}
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
/* Push stuff to user space */
srq->length = number;
@@ -3127,39 +3506,39 @@
struct orinoco_private *priv = dev->priv;
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 laps 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 */
+ * 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:
- DEBUG(1, "%s: SIOCGIWNAME\n", dev->name);
strcpy(wrq->u.name, "IEEE 802.11-DS");
break;
case SIOCGIWAP:
- DEBUG(1, "%s: SIOCGIWAP\n", dev->name);
wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
break;
case SIOCGIWRANGE:
- DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name);
err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
break;
case SIOCSIWMODE:
- DEBUG(1, "%s: SIOCSIWMODE\n", dev->name);
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
switch (wrq->u.mode) {
case IW_MODE_ADHOC:
if (! (priv->has_ibss || priv->has_port3) )
@@ -3180,18 +3559,18 @@
break;
}
set_port_type(priv);
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
break;
case SIOCGIWMODE:
- DEBUG(1, "%s: SIOCGIWMODE\n", dev->name);
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
wrq->u.mode = priv->iw_mode;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
break;
case SIOCSIWENCODE:
- DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name);
if (! priv->has_wep) {
err = -EOPNOTSUPP;
break;
@@ -3203,7 +3582,6 @@
break;
case SIOCGIWENCODE:
- DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name);
if (! priv->has_wep) {
err = -EOPNOTSUPP;
break;
@@ -3218,106 +3596,94 @@
break;
case SIOCSIWESSID:
- DEBUG(1, "%s: SIOCSIWESSID\n", dev->name);
err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
if (! err)
changed = 1;
break;
case SIOCGIWESSID:
- DEBUG(1, "%s: SIOCGIWESSID\n", dev->name);
err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
break;
case SIOCSIWNICKN:
- DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name);
err = orinoco_ioctl_setnick(dev, &wrq->u.data);
if (! err)
changed = 1;
break;
case SIOCGIWNICKN:
- DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name);
err = orinoco_ioctl_getnick(dev, &wrq->u.data);
break;
case SIOCGIWFREQ:
- DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name);
- wrq->u.freq.m = orinoco_hw_get_freq(priv);
- wrq->u.freq.e = 1;
+ tmp = orinoco_hw_get_freq(priv);
+ if (tmp < 0) {
+ err = tmp;
+ } else {
+ wrq->u.freq.m = tmp;
+ wrq->u.freq.e = 1;
+ }
break;
case SIOCSIWFREQ:
- DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name);
err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
if (! err)
changed = 1;
break;
case SIOCGIWSENS:
- DEBUG(1, "%s: SIOCGIWSENS\n", dev->name);
err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
break;
case SIOCSIWSENS:
- DEBUG(1, "%s: SIOCSIWSENS\n", dev->name);
err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
if (! err)
changed = 1;
break;
case SIOCGIWRTS:
- DEBUG(1, "%s: SIOCGIWRTS\n", dev->name);
wrq->u.rts.value = priv->rts_thresh;
wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
wrq->u.rts.fixed = 1;
break;
case SIOCSIWRTS:
- DEBUG(1, "%s: SIOCSIWRTS\n", dev->name);
err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
if (! err)
changed = 1;
break;
case SIOCSIWFRAG:
- DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name);
err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
if (! err)
changed = 1;
break;
case SIOCGIWFRAG:
- DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name);
err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
break;
case SIOCSIWRATE:
- DEBUG(1, "%s: SIOCSIWRATE\n", dev->name);
err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
if (! err)
changed = 1;
break;
case SIOCGIWRATE:
- DEBUG(1, "%s: SIOCGIWRATE\n", dev->name);
err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
break;
case SIOCSIWPOWER:
- DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name);
err = orinoco_ioctl_setpower(dev, &wrq->u.power);
if (! err)
changed = 1;
break;
case SIOCGIWPOWER:
- DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name);
err = orinoco_ioctl_getpower(dev, &wrq->u.power);
break;
case SIOCGIWTXPOW:
- DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name);
/* The card only supports one tx power, so this is easy */
wrq->u.txpower.value = 15; /* dBm */
wrq->u.txpower.fixed = 1;
@@ -3327,30 +3693,23 @@
#if WIRELESS_EXT > 10
case SIOCSIWRETRY:
- DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name);
err = -EOPNOTSUPP;
break;
case SIOCGIWRETRY:
- DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name);
err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
break;
#endif /* WIRELESS_EXT > 10 */
case SIOCSIWSPY:
- DEBUG(1, "%s: SIOCSIWSPY\n", dev->name);
-
err = orinoco_ioctl_setspy(dev, &wrq->u.data);
break;
case SIOCGIWSPY:
- DEBUG(1, "%s: SIOCGIWSPY\n", dev->name);
-
err = orinoco_ioctl_getspy(dev, &wrq->u.data);
break;
case SIOCGIWPRIV:
- DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name);
if (wrq->u.data.pointer) {
struct iw_priv_args privtab[] = {
{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
@@ -3372,7 +3731,8 @@
0, "set_ibssport" },
{ SIOCIWFIRSTPRIV + 0x7, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_ibssport" }
+ "get_ibssport" },
+ { SIOCIWLASTPRIV, 0, 0, "dump_recs" },
};
err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
@@ -3387,25 +3747,17 @@
case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
- DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x0 (force_reset)\n",
- dev->name);
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
}
- printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+ printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
- /* We need the xmit lock because it protects the
- multicast list which orinoco_reset() reads */
- spin_lock_bh(&dev->xmit_lock);
- orinoco_reset(priv);
- spin_unlock_bh(&dev->xmit_lock);
+ schedule_task(&priv->timeout_task);
break;
case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
- DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x2 (set_port3)\n",
- dev->name);
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
@@ -3417,14 +3769,10 @@
break;
case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
- DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x3 (get_port3)\n",
- dev->name);
err = orinoco_ioctl_getport3(dev, wrq);
break;
case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
- DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x4 (set_preamble)\n",
- dev->name);
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
@@ -3438,32 +3786,32 @@
if(priv->has_preamble) {
int val = *( (int *) wrq->u.name );
- orinoco_lock(priv);
- if(val)
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
+ if (val)
priv->preamble = 1;
else
priv->preamble = 0;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
changed = 1;
} else
err = -EOPNOTSUPP;
break;
case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
- DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x5 (get_preamble)\n",
- dev->name);
if(priv->has_preamble) {
int *val = (int *)wrq->u.name;
- orinoco_lock(priv);
+ err = orinoco_lock(priv, &flags);
+ if (err)
+ return err;
*val = priv->preamble;
- orinoco_unlock(priv);
+ orinoco_unlock(priv, &flags);
} else
err = -EOPNOTSUPP;
break;
case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
- DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x6 (set_ibssport)\n",
- dev->name);
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
@@ -3475,109 +3823,28 @@
break;
case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
- DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x7 (get_ibssport)\n",
- dev->name);
err = orinoco_ioctl_getibssport(dev, wrq);
break;
+ case SIOCIWLASTPRIV:
+ err = orinoco_debug_dump_recs(priv);
+ if (err)
+ printk(KERN_ERR "%s: Unable to dump records (%d)\n",
+ dev->name, err);
+ break;
+
default:
err = -EOPNOTSUPP;
}
if (! err && changed && netif_running(dev)) {
- /* We need the xmit lock because it protects the
- multicast list which orinoco_reset() reads */
- spin_lock_bh(&dev->xmit_lock);
- err = orinoco_reset(priv);
- spin_unlock_bh(&dev->xmit_lock);
- if (err) {
- /* Ouch ! What are we supposed to do ? */
- printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n",
- dev->name);
- netif_device_detach(dev);
- orinoco_shutdown(priv);
- }
+ err = orinoco_reconfigure(priv);
}
TRACE_EXIT(dev->name);
-
- return err;
-}
-
-/********************************************************************/
-/* procfs stuff */
-/********************************************************************/
-
-static struct proc_dir_entry *dir_base = NULL;
-
-#define PROC_LTV_SIZE 128
-
-/*
- * This function updates the total amount of data printed so far. It then
- * determines if the amount of data printed into a buffer has reached the
- * offset requested. If it hasn't, then the buffer is shifted over so that
- * the next bit of data can be printed over the old bit. If the total
- * amount printed so far exceeds the total amount requested, then this
- * function returns 1, otherwise 0.
- */
-static int
-shift_buffer(char *buffer, int requested_offset, int requested_len,
- int *total, int *slop, char **buf)
-{
- int printed;
-
- printed = *buf - buffer;
- if (*total + printed <= requested_offset) {
- *total += printed;
- *buf = buffer;
- }
- else {
- if (*total < requested_offset) {
- *slop = requested_offset - *total;
- }
- *total = requested_offset + printed - *slop;
- }
- if (*total > requested_offset + requested_len) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-/*
- * This function calculates the actual start of the requested data
- * in the buffer. It also calculates actual length of data returned,
- * which could be less that the amount of data requested.
- */
-#define PROC_BUFFER_SIZE 4096
-#define PROC_SAFE_SIZE 3072
-static int
-calc_start_len(char *buffer, char **start, int requested_offset,
- int requested_len, int total, char *buf)
-{
- int return_len, buffer_len;
-
- buffer_len = buf - buffer;
- if (buffer_len >= PROC_BUFFER_SIZE - 1) {
- printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n");
- }
-
- /*
- * There may be bytes before and after the
- * chunk that was actually requested.
- */
- return_len = total - requested_offset;
- if (return_len < 0) {
- return_len = 0;
- }
- *start = buf - return_len;
- if (return_len > requested_len) {
- return_len = requested_len;
- }
- return return_len;
+ return err;
}
struct {
@@ -3589,140 +3856,134 @@
#define DISPLAY_STRING 2
#define DISPLAY_XSTRING 3
} record_table[] = {
-#define PROC_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
- PROC_REC(CNFPORTTYPE,WORDS),
- PROC_REC(CNFOWNMACADDR,BYTES),
- PROC_REC(CNFDESIREDSSID,STRING),
- PROC_REC(CNFOWNCHANNEL,WORDS),
- PROC_REC(CNFOWNSSID,STRING),
- PROC_REC(CNFOWNATIMWINDOW,WORDS),
- PROC_REC(CNFSYSTEMSCALE,WORDS),
- PROC_REC(CNFMAXDATALEN,WORDS),
- PROC_REC(CNFPMENABLED,WORDS),
- PROC_REC(CNFPMEPS,WORDS),
- PROC_REC(CNFMULTICASTRECEIVE,WORDS),
- PROC_REC(CNFMAXSLEEPDURATION,WORDS),
- PROC_REC(CNFPMHOLDOVERDURATION,WORDS),
- PROC_REC(CNFOWNNAME,STRING),
- PROC_REC(CNFOWNDTIMPERIOD,WORDS),
- PROC_REC(CNFMULTICASTPMBUFFERING,WORDS),
- PROC_REC(CNFWEPENABLED_AGERE,WORDS),
- PROC_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
- PROC_REC(CNFWEPDEFAULTKEYID,WORDS),
- PROC_REC(CNFDEFAULTKEY0,BYTES),
- PROC_REC(CNFDEFAULTKEY1,BYTES),
- PROC_REC(CNFMWOROBUST_AGERE,WORDS),
- PROC_REC(CNFDEFAULTKEY2,BYTES),
- PROC_REC(CNFDEFAULTKEY3,BYTES),
- PROC_REC(CNFWEPFLAGS_INTERSIL,WORDS),
- PROC_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
- PROC_REC(CNFAUTHENTICATION,WORDS),
- PROC_REC(CNFMAXASSOCSTA,WORDS),
- PROC_REC(CNFKEYLENGTH_SYMBOL,WORDS),
- PROC_REC(CNFTXCONTROL,WORDS),
- PROC_REC(CNFROAMINGMODE,WORDS),
- PROC_REC(CNFHOSTAUTHENTICATION,WORDS),
- PROC_REC(CNFRCVCRCERROR,WORDS),
- PROC_REC(CNFMMLIFE,WORDS),
- PROC_REC(CNFALTRETRYCOUNT,WORDS),
- PROC_REC(CNFBEACONINT,WORDS),
- PROC_REC(CNFAPPCFINFO,WORDS),
- PROC_REC(CNFSTAPCFINFO,WORDS),
- PROC_REC(CNFPRIORITYQUSAGE,WORDS),
- PROC_REC(CNFTIMCTRL,WORDS),
- PROC_REC(CNFTHIRTY2TALLY,WORDS),
- PROC_REC(CNFENHSECURITY,WORDS),
- PROC_REC(CNFGROUPADDRESSES,BYTES),
- PROC_REC(CNFCREATEIBSS,WORDS),
- PROC_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
- PROC_REC(CNFRTSTHRESHOLD,WORDS),
- PROC_REC(CNFTXRATECONTROL,WORDS),
- PROC_REC(CNFPROMISCUOUSMODE,WORDS),
- PROC_REC(CNFBASICRATES_SYMBOL,WORDS),
- PROC_REC(CNFPREAMBLE_SYMBOL,WORDS),
- PROC_REC(CNFSHORTPREAMBLE,WORDS),
- PROC_REC(CNFWEPKEYS_AGERE,BYTES),
- PROC_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
- PROC_REC(CNFTXKEY_AGERE,WORDS),
- PROC_REC(CNFAUTHENTICATIONRSPTO,WORDS),
- PROC_REC(CNFBASICRATES,WORDS),
- PROC_REC(CNFSUPPORTEDRATES,WORDS),
- PROC_REC(CNFTICKTIME,WORDS),
- PROC_REC(CNFSCANREQUEST,WORDS),
- PROC_REC(CNFJOINREQUEST,WORDS),
- PROC_REC(CNFAUTHENTICATESTATION,WORDS),
- PROC_REC(CNFCHANNELINFOREQUEST,WORDS),
- PROC_REC(MAXLOADTIME,WORDS),
- PROC_REC(DOWNLOADBUFFER,WORDS),
- PROC_REC(PRIID,WORDS),
- PROC_REC(PRISUPRANGE,WORDS),
- PROC_REC(CFIACTRANGES,WORDS),
- PROC_REC(NICSERNUM,WORDS),
- PROC_REC(NICID,WORDS),
- PROC_REC(MFISUPRANGE,WORDS),
- PROC_REC(CFISUPRANGE,WORDS),
- PROC_REC(CHANNELLIST,WORDS),
- PROC_REC(REGULATORYDOMAINS,WORDS),
- PROC_REC(TEMPTYPE,WORDS),
-/* PROC_REC(CIS,BYTES), */
- PROC_REC(STAID,WORDS),
- PROC_REC(CURRENTSSID,STRING),
- PROC_REC(CURRENTBSSID,BYTES),
- PROC_REC(COMMSQUALITY,WORDS),
- PROC_REC(CURRENTTXRATE,WORDS),
- PROC_REC(CURRENTBEACONINTERVAL,WORDS),
- PROC_REC(CURRENTSCALETHRESHOLDS,WORDS),
- PROC_REC(PROTOCOLRSPTIME,WORDS),
- PROC_REC(SHORTRETRYLIMIT,WORDS),
- PROC_REC(LONGRETRYLIMIT,WORDS),
- PROC_REC(MAXTRANSMITLIFETIME,WORDS),
- PROC_REC(MAXRECEIVELIFETIME,WORDS),
- PROC_REC(CFPOLLABLE,WORDS),
- PROC_REC(AUTHENTICATIONALGORITHMS,WORDS),
- PROC_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
- PROC_REC(OWNMACADDR,BYTES),
- PROC_REC(SCANRESULTSTABLE,WORDS),
- PROC_REC(PHYTYPE,WORDS),
- PROC_REC(CURRENTCHANNEL,WORDS),
- PROC_REC(CURRENTPOWERSTATE,WORDS),
- PROC_REC(CCAMODE,WORDS),
- PROC_REC(SUPPORTEDDATARATES,WORDS),
- PROC_REC(BUILDSEQ,BYTES),
- PROC_REC(FWID,XSTRING)
-#undef PROC_REC
+#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,WORDS),
+ 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 NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) )
-static int
-orinoco_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
- int requested_len, int *eof, void *data)
+#define DEBUG_LTV_SIZE 128
+
+static int orinoco_debug_dump_recs(struct orinoco_private *priv)
{
- struct orinoco_private *priv = (struct orinoco_private *)data;
- struct net_device *dev = priv->ndev;
hermes_t *hw = &priv->hw;
- char *buf = page;
- int total = 0, slop = 0;
u8 *val8;
u16 *val16;
int i,j;
u16 length;
int err;
- if (! netif_device_present(dev))
- return -ENODEV;
-
- val8 = kmalloc(PROC_LTV_SIZE + 2, GFP_KERNEL);
+ /* 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 < NUM_RIDS; i++) {
+ for (i = 0; i < ARRAY_SIZE(record_table); i++) {
u16 rid = record_table[i].rid;
int len;
- memset(val8, 0, PROC_LTV_SIZE + 2);
+ memset(val8, 0, DEBUG_LTV_SIZE + 2);
- err = hermes_read_ltv(hw, USER_BAP, rid, PROC_LTV_SIZE,
+ 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);
@@ -3732,210 +3993,46 @@
if (length == 0)
continue;
- buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
- rid, length, (length-1)*2);
- len = min(((int)length-1)*2, PROC_LTV_SIZE);
+ 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++) {
- buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j]));
- }
- buf--;
+ 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++) {
- buf += sprintf(buf, "%02X:", val8[j]);
- }
- buf--;
+ 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';
- buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
+ printk("\"%s\"", (char *)&val16[1]);
break;
case DISPLAY_XSTRING:
- buf += sprintf(buf, "'%s'", (char *)val8);
+ printk("'%s'", (char *)val8);
}
- buf += sprintf(buf, "\n");
-
- if (shift_buffer(page, requested_offset, requested_len,
- &total, &slop, &buf))
- break;
-
- if ( (buf - page) > PROC_SAFE_SIZE )
- break;
+ printk("\n");
}
kfree(val8);
- return calc_start_len(page, start, requested_offset, requested_len,
- total, buf);
-}
-
-#ifdef HERMES_DEBUG_BUFFER
-static int
-orinoco_proc_get_hermes_buf(char *page, char **start, off_t requested_offset,
- int requested_len, int *eof, void *data)
-{
- struct orinoco_private *priv = (struct orinoco_private *)data;
- hermes_t *hw = &priv->hw;
- char *buf = page;
- int total = 0, slop = 0;
- int i;
-
- for (i = 0; i < min_t(int,hw->dbufp, HERMES_DEBUG_BUFSIZE); i++) {
- memcpy(buf, &hw->dbuf[i], sizeof(hw->dbuf[i]));
- buf += sizeof(hw->dbuf[i]);
-
- if (shift_buffer(page, requested_offset, requested_len,
- &total, &slop, &buf))
- break;
-
- if ( (buf - page) > PROC_SAFE_SIZE )
- break;
- }
-
- return calc_start_len(page, start, requested_offset, requested_len,
- total, buf);
-}
-
-static int
-orinoco_proc_get_hermes_prof(char *page, char **start, off_t requested_offset,
- int requested_len, int *eof, void *data)
-{
- struct orinoco_private *priv = (struct orinoco_private *)data;
- hermes_t *hw = &priv->hw;
- char *buf = page;
- int total = 0, slop = 0;
- int i;
-
- for (i = 0; i < (HERMES_BAP_BUSY_TIMEOUT+1); i++) {
- memcpy(buf, &hw->profile[i], sizeof(hw->profile[i]));
- buf += sizeof(hw->profile[i]);
-
- if (shift_buffer(page, requested_offset, requested_len,
- &total, &slop, &buf))
- break;
-
- if ( (buf - page) > PROC_SAFE_SIZE )
- break;
- }
-
- return calc_start_len(page, start, requested_offset, requested_len,
- total, buf);
-}
-#endif /* HERMES_DEBUG_BUFFER */
-
-/* initialise the /proc subsystem for the hermes driver, creating the
- * separate entries */
-static int
-orinoco_proc_init(void)
-{
- int err = 0;
-
- TRACE_ENTER("orinoco");
-
- /* create the directory for it to sit in */
- dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root);
- if (dir_base == NULL) {
- printk(KERN_ERR "Unable to initialise /proc/hermes.\n");
- orinoco_proc_cleanup();
- err = -ENOMEM;
- }
-
- TRACE_EXIT("orinoco");
-
- return err;
-}
-
-int
-orinoco_proc_dev_init(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct proc_dir_entry *e;
-
- priv->dir_dev = NULL;
-
- /* create the directory for it to sit in */
- priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO,
- dir_base);
- if (! priv->dir_dev) {
- printk(KERN_ERR "Unable to initialize /proc/hermes/%s\n", dev->name);
- goto fail;
- }
-
- e = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
- priv->dir_dev, orinoco_proc_get_hermes_recs, priv);
- if (! e) {
- printk(KERN_ERR "Unable to initialize /proc/hermes/%s/recs\n", dev->name);
- goto fail;
- }
-
-#ifdef HERMES_DEBUG_BUFFER
- e = create_proc_read_entry("buf", S_IFREG | S_IRUGO,
- priv->dir_dev, orinoco_proc_get_hermes_buf, priv);
- if (! e) {
- printk(KERN_ERR "Unable to intialize /proc/hermes/%s/buf\n", dev->name);
- goto fail;
- }
-
- e = create_proc_read_entry("prof", S_IFREG | S_IRUGO,
- priv->dir_dev, orinoco_proc_get_hermes_prof, priv);
- if (! e) {
- printk(KERN_ERR "Unable to intialize /proc/hermes/%s/prof\n", dev->name);
- goto fail;
- }
-#endif /* HERMES_DEBUG_BUFFER */
-
return 0;
- fail:
- orinoco_proc_dev_cleanup(priv);
- return -ENOMEM;
-}
-
-void
-orinoco_proc_dev_cleanup(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
-
- TRACE_ENTER(priv->ndev->name);
-
- if (priv->dir_dev) {
- remove_proc_entry("prof", priv->dir_dev);
- remove_proc_entry("buf", priv->dir_dev);
- remove_proc_entry("recs", priv->dir_dev);
- remove_proc_entry(dev->name, dir_base);
- priv->dir_dev = NULL;
- }
-
- TRACE_EXIT(priv->ndev->name);
-}
-
-static void
-orinoco_proc_cleanup(void)
-{
- TRACE_ENTER("orinoco");
-
- if (dir_base) {
- remove_proc_entry("hermes", &proc_root);
- dir_base = NULL;
- }
-
- TRACE_EXIT("orinoco");
}
-struct net_device *alloc_orinocodev(int sizeof_card)
+struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *))
{
struct net_device *dev;
struct orinoco_private *priv;
- TRACE_ENTER("orinoco");
dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
priv = (struct orinoco_private *)dev->priv;
priv->ndev = dev;
@@ -3955,39 +4052,49 @@
dev->change_mtu = orinoco_change_mtu;
dev->set_multicast_list = orinoco_set_multicast_list;
- dev->open = NULL; /* Caller *must* override these */
- dev->stop = NULL;
-
- /* Setup the private structure */
+ /* Set up default callbacks */
+ dev->open = orinoco_open;
+ dev->stop = orinoco_stop;
+ priv->hard_reset = hard_reset;
spin_lock_init(&priv->lock);
- priv->hard_reset = NULL; /* Caller may override */
-
- TRACE_EXIT("orinoco");
+ priv->open = 0;
+ priv->hw_unavailable = 1; /* orinoco_init() must clear this
+ * before anything else touches the
+ * hardware */
+ INIT_TQUEUE(&priv->timeout_task, (void (*)(void *))orinoco_reset, dev);
+
+ priv->last_linkstatus = 0xffff;
+ priv->connected = 0;
+
return dev;
}
/********************************************************************/
-/* module bookkeeping */
+/* Module initialization */
/********************************************************************/
EXPORT_SYMBOL(alloc_orinocodev);
-EXPORT_SYMBOL(orinoco_shutdown);
-EXPORT_SYMBOL(orinoco_reset);
-EXPORT_SYMBOL(orinoco_proc_dev_init);
-EXPORT_SYMBOL(orinoco_proc_dev_cleanup);
+
+EXPORT_SYMBOL(__orinoco_up);
+EXPORT_SYMBOL(__orinoco_down);
+EXPORT_SYMBOL(orinoco_reinit_firmware);
+
EXPORT_SYMBOL(orinoco_interrupt);
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = "orinoco.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+
static int __init init_orinoco(void)
{
printk(KERN_DEBUG "%s\n", version);
- return orinoco_proc_init();
+ return 0;
}
static void __exit exit_orinoco(void)
{
- orinoco_proc_cleanup();
}
module_init(init_orinoco);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)