Commit d97bdc8d authored by David Gibson's avatar David Gibson Committed by Jeff Garzik

[PATCH] orinoco merge preliminaries - rearrange code

Rearrange functions in the orinoco driver in a more logical order.
This patch is large and looks complicated, but in fact only moves code
around (within or between files) without changing it.  The only
exceptions are some extra comments describing the file's layout, and
updated prototypes for the new function order.

This makes the order of functions match the 0.15rc1 version, so later
patches have a fighting chance of being meaningful.
Signed-off-by: default avatarDavid Gibson <hermes@gibson.dropbear.id.au>

Index: working-2.6/drivers/net/wireless/orinoco.c
===================================================================
parent 8d50e0e0
...@@ -157,16 +157,6 @@ ...@@ -157,16 +157,6 @@
#define HERMES_802_3_OFFSET (14+32) #define HERMES_802_3_OFFSET (14+32)
#define HERMES_802_2_OFFSET (14+32+14) #define HERMES_802_2_OFFSET (14+32+14)
struct hermes_rx_descriptor {
u16 status;
u32 time;
u8 silence;
u8 signal;
u8 rate;
u8 rxflow;
u32 reserved;
} __attribute__ ((packed));
#define HERMES_RXSTAT_ERR (0x0003) #define HERMES_RXSTAT_ERR (0x0003)
#define HERMES_RXSTAT_BADCRC (0x0001) #define HERMES_RXSTAT_BADCRC (0x0001)
#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) #define HERMES_RXSTAT_UNDECRYPTABLE (0x0002)
...@@ -262,6 +252,20 @@ struct hermes_linkstatus { ...@@ -262,6 +252,20 @@ struct hermes_linkstatus {
u16 linkstatus; /* Link status */ u16 linkstatus; /* Link status */
} __attribute__ ((packed)); } __attribute__ ((packed));
typedef struct hermes_response {
u16 status, resp0, resp1, resp2;
} hermes_response_t;
/* "ID" structure - used for ESSID and station nickname */
struct hermes_idstring {
u16 len;
u16 val[16];
} __attribute__ ((packed));
typedef struct hermes_multicast {
u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
} __attribute__ ((packed)) hermes_multicast_t;
// #define HERMES_DEBUG_BUFFER 1 // #define HERMES_DEBUG_BUFFER 1
#define HERMES_DEBUG_BUFSIZE 4096 #define HERMES_DEBUG_BUFSIZE 4096
struct hermes_debug_entry { struct hermes_debug_entry {
...@@ -294,10 +298,6 @@ typedef struct hermes { ...@@ -294,10 +298,6 @@ typedef struct hermes {
#endif #endif
} hermes_t; } hermes_t;
typedef struct hermes_response {
u16 status, resp0, resp1, resp2;
} hermes_response_t;
/* Register access convenience macros */ /* Register access convenience macros */
#define hermes_read_reg(hw, off) ((hw)->io_space ? \ #define hermes_read_reg(hw, off) ((hw)->io_space ? \
inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \ inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
......
...@@ -140,14 +140,4 @@ ...@@ -140,14 +140,4 @@
#define HERMES_RID_BUILDSEQ 0xFFFE #define HERMES_RID_BUILDSEQ 0xFFFE
#define HERMES_RID_FWID 0xFFFF #define HERMES_RID_FWID 0xFFFF
/* "ID" structure - used for ESSID and station nickname */
struct hermes_idstring {
u16 len;
u16 val[16];
} __attribute__ ((packed));
typedef struct hermes_multicast {
u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
} __attribute__ ((packed)) hermes_multicast_t;
#endif #endif
...@@ -496,6 +496,10 @@ MODULE_PARM(suppress_linkstatus, "i"); ...@@ -496,6 +496,10 @@ MODULE_PARM(suppress_linkstatus, "i");
HERMES_MAX_MULTICAST : 0)*/ HERMES_MAX_MULTICAST : 0)*/
#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) #define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST)
#define ORINOCO_INTEN ( HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | \
HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \
HERMES_EV_INFDROP )
/********************************************************************/ /********************************************************************/
/* Data tables */ /* Data tables */
/********************************************************************/ /********************************************************************/
...@@ -548,133 +552,55 @@ u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ...@@ -548,133 +552,55 @@ u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
struct hermes_rx_descriptor {
u16 status;
u32 time;
u8 silence;
u8 signal;
u8 rate;
u8 rxflow;
u32 reserved;
} __attribute__ ((packed));
/********************************************************************/ /********************************************************************/
/* Function prototypes */ /* Function prototypes */
/********************************************************************/ /********************************************************************/
static void orinoco_stat_gather(struct net_device *dev, static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
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 net_device *dev); static int __orinoco_program_rids(struct net_device *dev);
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]);
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);
static void __orinoco_set_multicast_list(struct net_device *dev); static void __orinoco_set_multicast_list(struct net_device *dev);
/* Interrupt handling routines */
static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw);
static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw);
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw);
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw);
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw);
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw);
/* ioctl() routines */
static int orinoco_debug_dump_recs(struct net_device *dev); static int orinoco_debug_dump_recs(struct net_device *dev);
/********************************************************************/ /********************************************************************/
/* Function prototypes */ /* Internal helper functions */
/********************************************************************/ /********************************************************************/
int __orinoco_up(struct net_device *dev) static inline void
{ set_port_type(struct orinoco_private *priv)
struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
err = __orinoco_program_rids(dev);
if (err) {
printk(KERN_ERR "%s: Error %d configuring card\n",
dev->name, err);
return err;
}
/* 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;
}
netif_start_queue(dev);
return 0;
}
int __orinoco_down(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); switch (priv->iw_mode) {
struct hermes *hw = &priv->hw; case IW_MODE_INFRA:
int err; priv->port_type = 1;
priv->createibss = 0;
netif_stop_queue(dev); break;
case IW_MODE_ADHOC:
if (! priv->hw_unavailable) { if (priv->prefer_port3) {
if (! priv->broken_disableport) { priv->port_type = 3;
err = hermes_disable_port(hw, 0); priv->createibss = 0;
if (err) { } else {
/* Some firmwares (e.g. Intersil 1.3.x) seem priv->port_type = priv->ibss_port;
* to have problems disabling the port, oh priv->createibss = 1;
* well, too bad. */
printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
dev->name, err);
priv->broken_disableport = 1;
}
} }
hermes_set_irqmask(hw, 0); break;
hermes_write_regn(hw, EVACK, 0xffff); default:
printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
priv->ndev->name);
} }
/* firmware will have to reassociate */
priv->last_linkstatus = 0xffff;
priv->connected = 0;
return 0;
} }
int orinoco_reinit_firmware(struct net_device *dev) /********************************************************************/
{ /* Device methods */
struct orinoco_private *priv = netdev_priv(dev); /********************************************************************/
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");
}
return err;
}
static int orinoco_open(struct net_device *dev) static int orinoco_open(struct net_device *dev)
{ {
...@@ -715,337 +641,323 @@ int orinoco_stop(struct net_device *dev) ...@@ -715,337 +641,323 @@ int orinoco_stop(struct net_device *dev)
return err; return err;
} }
static int __orinoco_program_rids(struct net_device *dev) struct net_device_stats *
orinoco_get_stats(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
return &priv->stats;
}
struct iw_statistics *
orinoco_get_wireless_stats(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int err; struct iw_statistics *wstats = &priv->wstats;
struct hermes_idstring idbuf; int err = 0;
unsigned long flags;
/* Set the MAC address */ if (! netif_device_present(dev)) {
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); dev->name);
if (err) { return NULL; /* FIXME: Can we do better than this? */
printk(KERN_ERR "%s: Error %d setting MAC address\n", dev->name, err);
return err;
} }
/* Set up the link mode */ err = orinoco_lock(priv, &flags);
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type); if (err)
if (err) { return NULL; /* FIXME: Erg, we've been signalled, how
printk(KERN_ERR "%s: Error %d setting port type\n", dev->name, err); * do we propagate this back up? */
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->iw_mode == IW_MODE_ADHOC) {
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS, memset(&wstats->qual, 0, sizeof(wstats->qual));
priv->createibss); /* If a spy address is defined, we report stats of the
if (err) { * first spy address - Jean II */
printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err); if (SPY_NUMBER(priv)) {
return err; wstats->qual.qual = priv->spy_stat[0].qual;
wstats->qual.level = priv->spy_stat[0].level;
wstats->qual.noise = priv->spy_stat[0].noise;
wstats->qual.updated = priv->spy_stat[0].updated;
} }
} else {
struct {
u16 qual, signal, noise;
} __attribute__ ((packed)) cq;
if ((strlen(priv->desired_essid) == 0) && (priv->createibss) err = HERMES_READ_RECORD(hw, USER_BAP,
&& (!priv->has_ibss_any)) { HERMES_RID_COMMSQUALITY, &cq);
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 */
}
}
/* Set the desired ESSID */ wstats->qual.qual = (int)le16_to_cpu(cq.qual);
idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
/* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ wstats->qual.updated = 7;
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
&idbuf);
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) {
printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", dev->name, err);
return err;
} }
/* Set the station name */ /* We can't really wait for the tallies inquiry command to
idbuf.len = cpu_to_le16(strlen(priv->nick)); * complete, so we just use the previous results and trigger
memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); * a new tallies inquiry command for next time - Jean II */
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, /* FIXME: We're in user context (I think?), so we should just
HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), wait for the tallies to come through */
&idbuf); err = hermes_inquire(hw, HERMES_INQ_TALLIES);
if (err) {
printk(KERN_ERR "%s: Error %d setting nickname\n", dev->name, err);
return err;
}
/* Set AP density */ orinoco_unlock(priv, &flags);
if (priv->has_sensitivity) {
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
priv->ap_density);
if (err) {
printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
"Disabling sensitivity control\n", dev->name, err);
priv->has_sensitivity = 0; if (err)
} return NULL;
}
/* Set RTS threshold */ return wstats;
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh); }
if (err) {
printk(KERN_ERR "%s: Error %d setting RTS threshold\n", dev->name, err);
return err;
}
/* Set fragmentation threshold or MWO robustness */ static void
if (priv->has_mwo) orinoco_set_multicast_list(struct net_device *dev)
err = hermes_write_wordrec(hw, USER_BAP, {
HERMES_RID_CNFMWOROBUST_AGERE, struct orinoco_private *priv = netdev_priv(dev);
priv->mwo_robust); unsigned long flags;
else
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
priv->frag_thresh);
if (err) {
printk(KERN_ERR "%s: Error %d setting framentation\n", dev->name, err);
return err;
}
/* Set bitrate */ if (orinoco_lock(priv, &flags) != 0) {
err = __orinoco_hw_set_bitrate(priv); printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
if (err) { "called when hw_unavailable\n", dev->name);
printk(KERN_ERR "%s: Error %d setting bitrate\n", dev->name, err); return;
return err;
} }
/* Set power management */ __orinoco_set_multicast_list(dev);
if (priv->has_pm) { orinoco_unlock(priv, &flags);
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, }
priv->pm_on);
if (err) {
printk(KERN_ERR "%s: Error %d setting up PM\n",
dev->name, err);
return err;
}
err = hermes_write_wordrec(hw, USER_BAP, static int
HERMES_RID_CNFMULTICASTRECEIVE, orinoco_change_mtu(struct net_device *dev, int new_mtu)
priv->pm_mcast); {
if (err) { struct orinoco_private *priv = netdev_priv(dev);
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) {
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) {
printk(KERN_ERR "%s: Error %d setting up PM\n",
dev->name, err);
return err;
}
}
/* Set preamble - only for Symbol so far... */ if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
if (priv->has_preamble) { return -EINVAL;
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFPREAMBLE_SYMBOL,
priv->preamble);
if (err) {
printk(KERN_ERR "%s: Error %d setting preamble\n",
dev->name, err);
return err;
}
}
/* Set up encryption */ if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) >
if (priv->has_wep) { (priv->nicbuf_size - ETH_HLEN) )
err = __orinoco_hw_setup_wep(priv); return -EINVAL;
if (err) {
printk(KERN_ERR "%s: Error %d activating WEP\n",
dev->name, err);
return err;
}
}
/* Set promiscuity / multicast*/ dev->mtu = new_mtu;
priv->promiscuous = 0;
priv->mc_count = 0;
__orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
return 0; return 0;
} }
/* xyzzy */ /********************************************************************/
static int orinoco_reconfigure(struct net_device *dev) /* Tx path */
/********************************************************************/
static int
orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw; struct net_device_stats *stats = &priv->stats;
unsigned long flags; hermes_t *hw = &priv->hw;
int err = 0; int err = 0;
u16 txfid = priv->txfid;
char *p;
struct ethhdr *eh;
int len, data_len, data_off;
struct hermes_tx_descriptor desc;
unsigned long flags;
if (priv->broken_disableport) { TRACE_ENTER(dev->name);
schedule_work(&priv->reset_work);
return 0;
}
err = orinoco_lock(priv, &flags);
if (err)
return err;
err = hermes_disable_port(hw, 0); if (! netif_running(dev)) {
if (err) { printk(KERN_ERR "%s: Tx on stopped device!\n",
printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
dev->name); dev->name);
priv->broken_disableport = 1; TRACE_EXIT(dev->name);
goto out; return 1;
} }
err = __orinoco_program_rids(dev); if (netif_queue_stopped(dev)) {
if (err) { printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
printk(KERN_WARNING "%s: Unable to reconfigure card\n",
dev->name); dev->name);
goto out; TRACE_EXIT(dev->name);
return 1;
} }
err = hermes_enable_port(hw, 0); if (orinoco_lock(priv, &flags) != 0) {
if (err) { printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
dev->name); dev->name);
goto out; TRACE_EXIT(dev->name);
} /* BUG(); */
return 1;
out:
if (err) {
printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
schedule_work(&priv->reset_work);
err = 0;
} }
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); orinoco_unlock(priv, &flags);
return err; dev_kfree_skb(skb);
TRACE_EXIT(dev->name);
return 0;
}
} /* Length of the packet body */
/* FIXME: what if the skb is smaller than this? */
len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
/* This must be called from user context, without locks held - use eh = (struct ethhdr *)skb->data;
* schedule_work() */
static void orinoco_reset(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
unsigned long flags;
err = orinoco_lock(priv, &flags); memset(&desc, 0, sizeof(desc));
if (err) desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX);
/* When the hardware becomes available again, whatever err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0);
* detects that is responsible for re-initializing if (err) {
* it. So no need for anything further*/ printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n",
return; dev->name, err);
stats->tx_errors++;
goto fail;
}
netif_stop_queue(dev); /* Clear the 802.11 header and data length fields - some
* firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
* if this isn't done. */
hermes_clear_words(hw, HERMES_DATA0,
HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
/* Shut off interrupts. Depending on what state the hardware /* Encapsulate Ethernet-II frames */
* is in, this might not work, but we'll try anyway */ if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
hermes_set_irqmask(hw, 0); struct header_struct hdr;
hermes_write_regn(hw, EVACK, 0xffff); data_len = len;
data_off = HERMES_802_3_OFFSET + sizeof(hdr);
p = skb->data + ETH_HLEN;
priv->hw_unavailable++; /* 802.3 header */
priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ memcpy(hdr.dest, eh->h_dest, ETH_ALEN);
priv->connected = 0; memcpy(hdr.src, eh->h_source, ETH_ALEN);
hdr.len = htons(data_len + ENCAPS_OVERHEAD);
orinoco_unlock(priv, &flags); /* 802.2 header */
memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr));
if (priv->hard_reset) hdr.ethertype = eh->h_proto;
err = (*priv->hard_reset)(priv); err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
txfid, HERMES_802_3_OFFSET);
if (err) { if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d performing hard reset\n", printk(KERN_ERR "%s: Error %d writing packet header to BAP\n",
dev->name, err); dev->name, err);
/* FIXME: shutdown of some sort */ stats->tx_errors++;
return; goto fail;
}
} else { /* IEEE 802.3 frame */
data_len = len + ETH_HLEN;
data_off = HERMES_802_3_OFFSET;
p = skb->data;
} }
err = orinoco_reinit_firmware(dev); /* Round up for odd length packets */
err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off);
if (err) { if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
dev->name, err); dev->name, err);
return; stats->tx_errors++;
goto fail;
} }
spin_lock_irq(&priv->lock); /* This has to be called from user context */ /* Finally, we actually initiate the send */
netif_stop_queue(dev);
priv->hw_unavailable--;
/* priv->open or priv->hw_unavailable might have changed while err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, NULL);
* we dropped the lock */
if (priv->open && (! priv->hw_unavailable)) {
err = __orinoco_up(dev);
if (err) { if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", netif_start_queue(dev);
dev->name, err); printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err);
} else stats->tx_errors++;
dev->trans_start = jiffies; goto fail;
} }
spin_unlock_irq(&priv->lock); dev->trans_start = jiffies;
stats->tx_bytes += data_off + data_len;
orinoco_unlock(priv, &flags);
dev_kfree_skb(skb);
TRACE_EXIT(dev->name);
return 0;
fail:
TRACE_EXIT(dev->name);
orinoco_unlock(priv, &flags);
return err;
}
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
{
struct orinoco_private *priv = netdev_priv(dev);
u16 fid = hermes_read_regn(hw, ALLOCFID);
if (fid != priv->txfid) {
if (fid != DUMMY_FID)
printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
dev->name, fid);
return; return;
} else {
netif_wake_queue(dev);
}
hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
} }
/********************************************************************/ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
/* Internal helper functions */ {
/********************************************************************/ struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats;
static inline void stats->tx_packets++;
set_port_type(struct orinoco_private *priv)
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
}
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
{ {
switch (priv->iw_mode) { struct orinoco_private *priv = netdev_priv(dev);
case IW_MODE_INFRA: struct net_device_stats *stats = &priv->stats;
priv->port_type = 1; u16 fid = hermes_read_regn(hw, TXCOMPLFID);
priv->createibss = 0; struct hermes_tx_descriptor desc;
break; int err = 0;
case IW_MODE_ADHOC:
if (priv->prefer_port3) { if (fid == DUMMY_FID)
priv->port_type = 3; return; /* Nothing's really happened */
priv->createibss = 0;
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
if (err) {
printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
"(FID=%04X error %d)\n",
dev->name, fid, err);
} else { } else {
priv->port_type = priv->ibss_port; DEBUG(1, "%s: Tx error, status %d\n",
priv->createibss = 1; dev->name, le16_to_cpu(desc.status));
}
break;
default:
printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
priv->ndev->name);
} }
stats->tx_errors++;
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
}
static void
orinoco_tx_timeout(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct hermes *hw = &priv->hw;
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++;
schedule_work(&priv->reset_work);
} }
/********************************************************************/
/* Rx path (data frames) */
/********************************************************************/
/* Does the frame have a SNAP header indicating it should be /* Does the frame have a SNAP header indicating it should be
* de-encapsulated to Ethernet-II? */ * de-encapsulated to Ethernet-II? */
static inline int static inline int
...@@ -1060,887 +972,1116 @@ is_ethersnap(struct header_struct *hdr) ...@@ -1060,887 +972,1116 @@ is_ethersnap(struct header_struct *hdr)
&& ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) );
} }
static void static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
orinoco_set_multicast_list(struct net_device *dev) int level, int noise)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
unsigned long flags; int i;
if (orinoco_lock(priv, &flags) != 0) { /* Gather wireless spy statistics: for each packet, compare the
printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " * source address with out list, and if match, get the stats... */
"called when hw_unavailable\n", dev->name); for (i = 0; i < priv->spy_number; i++)
return; if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) {
priv->spy_stat[i].level = level - 0x95;
priv->spy_stat[i].noise = noise - 0x95;
priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0;
priv->spy_stat[i].updated = 7;
} }
__orinoco_set_multicast_list(dev);
orinoco_unlock(priv, &flags);
} }
/********************************************************************/ void
/* Hardware control functions */ orinoco_stat_gather(struct net_device *dev,
/********************************************************************/ struct sk_buff *skb,
struct hermes_rx_descriptor *desc)
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
{ {
hermes_t *hw = &priv->hw; struct orinoco_private *priv = netdev_priv(dev);
int err = 0;
if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
priv->ndev->name, priv->bitratemode);
return -EINVAL;
}
switch (priv->firmware_type) { /* Using spy support with lots of Rx packets, like in an
case FIRMWARE_TYPE_AGERE: * infrastructure (AP), will really slow down everything, because
err = hermes_write_wordrec(hw, USER_BAP, * the MAC address must be compared to each entry of the spy list.
HERMES_RID_CNFTXRATECONTROL, * If the user really asks for it (set some address in the
bitrate_table[priv->bitratemode].agere_txratectrl); * spy list), we do it, but he will pay the price.
break; * Note that to get here, you need both WIRELESS_SPY
case FIRMWARE_TYPE_INTERSIL: * compiled in AND some addresses in the list !!!
case FIRMWARE_TYPE_SYMBOL: */
err = hermes_write_wordrec(hw, USER_BAP, /* Note : gcc will optimise the whole section away if
HERMES_RID_CNFTXRATECONTROL, * WIRELESS_SPY is not defined... - Jean II */
bitrate_table[priv->bitratemode].intersil_txratectrl); if (SPY_NUMBER(priv)) {
break; orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN,
default: desc->signal, desc->silence);
BUG();
} }
return err;
} }
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
{ {
hermes_t *hw = &priv->hw; struct orinoco_private *priv = netdev_priv(dev);
int err = 0; struct net_device_stats *stats = &priv->stats;
int master_wep_flag; struct iw_statistics *wstats = &priv->wstats;
int auth_flag; struct sk_buff *skb = NULL;
u16 rxfid, status;
int length, data_len, data_off;
char *p;
struct hermes_rx_descriptor desc;
struct header_struct hdr;
struct ethhdr *eh;
int err;
switch (priv->firmware_type) { rxfid = hermes_read_regn(hw, RXFID);
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, err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc),
HERMES_RID_CNFWEPKEYS_AGERE, rxfid, 0);
&priv->keys); if (err) {
if (err) printk(KERN_ERR "%s: error %d reading Rx descriptor. "
return err; "Frame dropped.\n", dev->name, err);
stats->rx_errors++;
goto drop;
} }
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 */ status = le16_to_cpu(desc.status);
case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
master_wep_flag = 0; /* Off */
if (priv->wep_on) {
int keylen;
int i;
/* Fudge around firmware weirdness */ if (status & HERMES_RXSTAT_ERR) {
keylen = le16_to_cpu(priv->keys[priv->tx_key].len); 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);
}
stats->rx_errors++;
goto drop;
}
/* Write all 4 keys */ /* For now we ignore the 802.11 header completely, assuming
for(i = 0; i < ORINOCO_MAX_KEYS; i++) { that the card's firmware has handled anything vital */
/* int keylen = le16_to_cpu(priv->keys[i].len); */
if (keylen > LARGE_KEY_SIZE) { err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", rxfid, HERMES_802_3_OFFSET);
priv->ndev->name, i, keylen); if (err) {
return -E2BIG; printk(KERN_ERR "%s: error %d reading frame header. "
"Frame dropped.\n", dev->name, err);
stats->rx_errors++;
goto drop;
} }
err = hermes_write_ltv(hw, USER_BAP, length = ntohs(hdr.len);
HERMES_RID_CNFDEFAULTKEY0 + i,
HERMES_BYTES_TO_RECLEN(keylen),
priv->keys[i].data);
if (err)
return err;
}
/* Write the index of the key used in transmission */ /* Sanity checks */
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID, if (length < 3) { /* No for even an 802.2 LLC header */
priv->tx_key); /* At least on Symbol firmware with PCF we get quite a
if (err) lot of these legitimately - Poll frames with no
return err; data. */
stats->rx_dropped++;
goto drop;
}
if (length > IEEE802_11_DATA_LEN) {
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
dev->name, length);
stats->rx_length_errors++;
stats->rx_errors++;
goto drop;
}
if (priv->wep_restrict) { /* We need space for the packet data itself, plus an ethernet
auth_flag = 2; header, plus 2 bytes so we can align the IP header on a
master_wep_flag = 3; 32bit boundary, plus 1 byte so we can read in odd length
} else { packets from the card, which has an IO granularity of 16
/* Authentication is where Intersil and Symbol bits */
* firmware differ... */ skb = dev_alloc_skb(length+ETH_HLEN+2+1);
auth_flag = 1; if (!skb) {
if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
master_wep_flag = 3; /* Symbol */ dev->name);
else goto drop;
master_wep_flag = 1; /* Intersil */
} }
skb_reserve(skb, 2); /* This way the IP header is aligned */
err = hermes_write_wordrec(hw, USER_BAP, /* Handle decapsulation
HERMES_RID_CNFAUTHENTICATION, auth_flag); * In most cases, the firmware tell us about SNAP frames.
if (err) * For some reason, the SNAP frames sent by LinkSys APs
return err; * 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)) {
/* 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;
} }
/* Master WEP setting : on/off */ /* Remove SNAP header, reconstruct EthernetII frame */
err = hermes_write_wordrec(hw, USER_BAP, data_len = length - ENCAPS_OVERHEAD;
HERMES_RID_CNFWEPFLAGS_INTERSIL, data_off = HERMES_802_3_OFFSET + sizeof(hdr);
master_wep_flag);
if (err)
return err;
break; eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
default: memcpy(eh, &hdr, 2 * ETH_ALEN);
if (priv->wep_on) { eh->h_proto = hdr.ethertype;
printk(KERN_ERR "%s: WEP enabled, although not supported!\n", } else {
priv->ndev->name); /* All other cases indicate a genuine 802.3 frame. No
return -EINVAL; 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, RUP_EVEN(data_len),
rxfid, data_off);
if (err) {
printk(KERN_ERR "%s: error %d reading frame. "
"Frame dropped.\n", dev->name, err);
stats->rx_errors++;
goto drop;
} }
return 0; dev->last_rx = jiffies;
} skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
static int orinoco_hw_get_bssid(struct orinoco_private *priv, /* Process the wireless stats if needed */
char buf[ETH_ALEN]) orinoco_stat_gather(dev, skb, &desc);
{
hermes_t *hw = &priv->hw;
int err = 0;
unsigned long flags;
err = orinoco_lock(priv, &flags); /* Pass the packet to the networking stack */
if (err) netif_rx(skb);
return err; stats->rx_packets++;
stats->rx_bytes += length;
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, return;
ETH_ALEN, NULL, buf);
orinoco_unlock(priv, &flags); drop:
stats->rx_dropped++;
return err; if (skb)
dev_kfree_skb_irq(skb);
return;
} }
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, /********************************************************************/
char buf[IW_ESSID_MAX_SIZE+1]) /* Rx path (info frames) */
/********************************************************************/
static void print_linkstatus(struct net_device *dev, u16 status)
{ {
hermes_t *hw = &priv->hw; char * s;
int err = 0;
struct hermes_idstring essidbuf;
char *p = (char *)(&essidbuf.val);
int len;
unsigned long flags;
err = orinoco_lock(priv, &flags); if (suppress_linkstatus)
if (err) return;
return err;
if (strlen(priv->desired_essid) > 0) { switch (status) {
/* We read the desired SSID from the hardware rather case HERMES_LINKSTATUS_NOT_CONNECTED:
than from priv->desired_essid, just in case the s = "Not Connected";
firmware is allowed to change it on us. I'm not break;
sure about this */ case HERMES_LINKSTATUS_CONNECTED:
/* My guess is that the OWNSSID should always be whatever s = "Connected";
* we set to the card, whereas CURRENT_SSID is the one that break;
* may change... - Jean II */ case HERMES_LINKSTATUS_DISCONNECTED:
u16 rid; 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";
}
*active = 1; printk(KERN_INFO "%s: New link status: %s (%04x)\n",
dev->name, s, status);
}
rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
HERMES_RID_CNFDESIREDSSID; {
struct orinoco_private *priv = netdev_priv(dev);
u16 infofid;
struct {
u16 len;
u16 type;
} __attribute__ ((packed)) info;
int len, type;
int err;
err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), /* This is an answer to an INQUIRE command that we did earlier,
NULL, &essidbuf); * or an information "event" generated by the card
if (err) * The controller return to us a pseudo frame containing
goto fail_unlock; * the information in question - Jean II */
} else { infofid = hermes_read_regn(hw, INFOFID);
*active = 0;
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, /* Read the info frame header - don't try too hard */
sizeof(essidbuf), NULL, &essidbuf); err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
if (err) infofid, 0);
goto fail_unlock; if (err) {
printk(KERN_ERR "%s: error %d reading info frame. "
"Frame dropped.\n", dev->name, err);
return;
} }
len = le16_to_cpu(essidbuf.len); len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
type = le16_to_cpu(info.type);
memset(buf, 0, IW_ESSID_MAX_SIZE+1);
memcpy(buf, p, len);
buf[len] = '\0';
fail_unlock:
orinoco_unlock(priv, &flags);
return err; switch (type) {
} case HERMES_INQ_TALLIES: {
struct hermes_tallies_frame tallies;
struct iw_statistics *wstats = &priv->wstats;
static long orinoco_hw_get_freq(struct orinoco_private *priv) if (len > sizeof(tallies)) {
{ printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
dev->name, len);
len = sizeof(tallies);
}
hermes_t *hw = &priv->hw; /* Read directly the data (no seek) */
int err = 0; hermes_read_words(hw, HERMES_DATA1, (void *) &tallies,
u16 channel; len / 2); /* FIXME: blech! */
long freq = 0;
unsigned long flags;
err = orinoco_lock(priv, &flags); /* Increment our various counters */
if (err) /* wstats->discard.nwid - no wrong BSSID stuff */
return err; wstats->discard.code +=
le16_to_cpu(tallies.RxWEPUndecryptable);
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); if (len == sizeof(tallies))
if (err) wstats->discard.code +=
goto out; le16_to_cpu(tallies.RxDiscards_WEPICVError) +
le16_to_cpu(tallies.RxDiscards_WEPExcluded);
wstats->discard.misc +=
le16_to_cpu(tallies.TxDiscardsWrongSA);
wstats->discard.fragment +=
le16_to_cpu(tallies.RxMsgInBadMsgFragments);
wstats->discard.retries +=
le16_to_cpu(tallies.TxRetryLimitExceeded);
/* wstats->miss.beacon - no match */
}
break;
case HERMES_INQ_LINKSTATUS: {
struct hermes_linkstatus linkstatus;
u16 newstatus;
/* Intersil firmware 1.3.5 returns 0 when the interface is down */ if (len != sizeof(linkstatus)) {
if (channel == 0) { printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
err = -EBUSY; dev->name, len);
goto out; break;
} }
if ( (channel < 1) || (channel > NUM_CHANNELS) ) { hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus,
printk(KERN_WARNING "%s: Channel out of range (%d)!\n", len / 2);
priv->ndev->name, channel); newstatus = le16_to_cpu(linkstatus.linkstatus);
err = -EBUSY;
goto out;
} if ( (newstatus == HERMES_LINKSTATUS_CONNECTED)
freq = channel_frequency[channel-1] * 100000; || (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;
out: if (newstatus != priv->last_linkstatus)
orinoco_unlock(priv, &flags); print_linkstatus(dev, newstatus);
if (err > 0) priv->last_linkstatus = newstatus;
err = -EBUSY; }
return err ? err : freq; break;
default:
printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n",
dev->name, type);
/* We don't actually do anything about it */
break;
}
} }
static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
int *numrates, s32 *rates, int max)
{ {
hermes_t *hw = &priv->hw; if (net_ratelimit())
struct hermes_idstring list; printk(KERN_WARNING "%s: Information frame lost.\n", dev->name);
unsigned char *p = (unsigned char *)&list.val; }
int err = 0;
int num;
int i;
unsigned long flags;
err = orinoco_lock(priv, &flags); /********************************************************************/
if (err) /* Internal hardware control routines */
return err; /********************************************************************/
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, int __orinoco_up(struct net_device *dev)
sizeof(list), NULL, &list); {
orinoco_unlock(priv, &flags); struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
if (err) err = __orinoco_program_rids(dev);
if (err) {
printk(KERN_ERR "%s: Error %d configuring card\n",
dev->name, err);
return err; return err;
}
num = le16_to_cpu(list.len); /* Fire things up again */
*numrates = num; hermes_set_irqmask(hw, ORINOCO_INTEN);
num = min(num, max); err = hermes_enable_port(hw, 0);
if (err) {
for (i = 0; i < num; i++) { printk(KERN_ERR "%s: Error %d enabling MAC port\n",
rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ dev->name, err);
return err;
} }
netif_start_queue(dev);
return 0; return 0;
} }
#if 0 int __orinoco_down(struct net_device *dev)
static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
{ {
printk(KERN_DEBUG "RX descriptor:\n"); struct orinoco_private *priv = netdev_priv(dev);
printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); struct hermes *hw = &priv->hw;
printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); int err;
printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence);
printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal);
printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate);
printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow);
printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved);
printk(KERN_DEBUG "IEEE 802.11 header:\n"); netif_stop_queue(dev);
printk(KERN_DEBUG " frame_ctl = 0x%04x\n",
frame->p80211.frame_ctl);
printk(KERN_DEBUG " duration_id = 0x%04x\n",
frame->p80211.duration_id);
printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr1[0], frame->p80211.addr1[1],
frame->p80211.addr1[2], frame->p80211.addr1[3],
frame->p80211.addr1[4], frame->p80211.addr1[5]);
printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr2[0], frame->p80211.addr2[1],
frame->p80211.addr2[2], frame->p80211.addr2[3],
frame->p80211.addr2[4], frame->p80211.addr2[5]);
printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr3[0], frame->p80211.addr3[1],
frame->p80211.addr3[2], frame->p80211.addr3[3],
frame->p80211.addr3[4], frame->p80211.addr3[5]);
printk(KERN_DEBUG " seq_ctl = 0x%04x\n",
frame->p80211.seq_ctl);
printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr4[0], frame->p80211.addr4[1],
frame->p80211.addr4[2], frame->p80211.addr4[3],
frame->p80211.addr4[4], frame->p80211.addr4[5]);
printk(KERN_DEBUG " data_len = 0x%04x\n",
frame->p80211.data_len);
printk(KERN_DEBUG "IEEE 802.3 header:\n"); if (! priv->hw_unavailable) {
printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", if (! priv->broken_disableport) {
frame->p8023.h_dest[0], frame->p8023.h_dest[1], err = hermes_disable_port(hw, 0);
frame->p8023.h_dest[2], frame->p8023.h_dest[3], if (err) {
frame->p8023.h_dest[4], frame->p8023.h_dest[5]); /* Some firmwares (e.g. Intersil 1.3.x) seem
printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", * to have problems disabling the port, oh
frame->p8023.h_source[0], frame->p8023.h_source[1], * well, too bad. */
frame->p8023.h_source[2], frame->p8023.h_source[3], printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
frame->p8023.h_source[4], frame->p8023.h_source[5]); dev->name, err);
printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); priv->broken_disableport = 1;
}
}
hermes_set_irqmask(hw, 0);
hermes_write_regn(hw, EVACK, 0xffff);
}
printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); /* firmware will have to reassociate */
printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); priv->last_linkstatus = 0xffff;
printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); priv->connected = 0;
printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl);
printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", return 0;
frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype);
} }
#endif /* 0 */
/* int orinoco_reinit_firmware(struct net_device *dev)
* Interrupt handler
*/
irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct net_device *dev = (struct net_device *)dev_id;
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; struct hermes *hw = &priv->hw;
int count = MAX_IRQLOOPS_PER_IRQ; int err;
u16 evstat, events;
/* These are used to detect a runaway interrupt situation */
/* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
* 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 (orinoco_lock(priv, &flags) != 0) { err = hermes_init(hw);
/* If hw is unavailable - we don't know if the irq was if (err)
* for us or not */ return err;
return IRQ_HANDLED;
}
evstat = hermes_read_regn(hw, EVSTAT); err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
events = evstat & hw->inten; if (err == -EIO) {
if (! events) { /* Try workaround for old Symbol firmware bug */
orinoco_unlock(priv, &flags); printk(KERN_WARNING "%s: firmware ALLOC bug detected "
return IRQ_NONE; "(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 (jiffies != last_irq_jiffy) return err;
loops_this_jiffy = 0; }
last_irq_jiffy = jiffies;
while (events && count--) { static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { {
printk(KERN_WARNING "%s: IRQ handler is looping too " hermes_t *hw = &priv->hw;
"much! Resetting.\n", dev->name); int err = 0;
/* Disable interrupts for now */
hermes_set_irqmask(hw, 0); if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
schedule_work(&priv->reset_work); printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
break; priv->ndev->name, priv->bitratemode);
return -EINVAL;
} }
/* Check the card hasn't been removed */ switch (priv->firmware_type) {
if (! hermes_present(hw)) { case FIRMWARE_TYPE_AGERE:
DEBUG(0, "orinoco_interrupt(): card removed\n"); err = hermes_write_wordrec(hw, USER_BAP,
break; HERMES_RID_CNFTXRATECONTROL,
} bitrate_table[priv->bitratemode].agere_txratectrl);
if (events & HERMES_EV_TICK)
__orinoco_ev_tick(dev, hw);
if (events & HERMES_EV_WTERR)
__orinoco_ev_wterr(dev, hw);
if (events & HERMES_EV_INFDROP)
__orinoco_ev_infdrop(dev, hw);
if (events & HERMES_EV_INFO)
__orinoco_ev_info(dev, hw);
if (events & HERMES_EV_RX)
__orinoco_ev_rx(dev, hw);
if (events & HERMES_EV_TXEXC)
__orinoco_ev_txexc(dev, hw);
if (events & HERMES_EV_TX)
__orinoco_ev_tx(dev, hw);
if (events & HERMES_EV_ALLOC)
__orinoco_ev_alloc(dev, hw);
hermes_write_regn(hw, EVACK, events);
evstat = hermes_read_regn(hw, EVSTAT);
events = evstat & hw->inten;
};
orinoco_unlock(priv, &flags);
return IRQ_HANDLED;
}
static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
{
printk(KERN_DEBUG "%s: TICK\n", dev->name);
}
static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
{
/* This seems to happen a fair bit under load, but ignoring it
seems to work fine...*/
printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
dev->name);
}
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);
}
static void print_linkstatus(struct net_device *dev, u16 status)
{
char * s;
if (suppress_linkstatus)
return;
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; break;
case HERMES_LINKSTATUS_ASSOC_FAILED: case FIRMWARE_TYPE_INTERSIL:
s = "Association Failed"; case FIRMWARE_TYPE_SYMBOL:
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFTXRATECONTROL,
bitrate_table[priv->bitratemode].intersil_txratectrl);
break; break;
default: default:
s = "UNKNOWN"; BUG();
} }
printk(KERN_INFO "%s: New link status: %s (%04x)\n", return err;
dev->name, s, status);
} }
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
{ {
struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw;
u16 infofid; int err = 0;
struct { int master_wep_flag;
u16 len; int auth_flag;
u16 type;
} __attribute__ ((packed)) info;
int len, type;
int err;
/* This is an answer to an INQUIRE command that we did earlier, switch (priv->firmware_type) {
* or an information "event" generated by the card case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
* The controller return to us a pseudo frame containing if (priv->wep_on) {
* the information in question - Jean II */ err = hermes_write_wordrec(hw, USER_BAP,
infofid = hermes_read_regn(hw, INFOFID); HERMES_RID_CNFTXKEY_AGERE,
priv->tx_key);
if (err)
return err;
/* Read the info frame header - don't try too hard */ err = HERMES_WRITE_RECORD(hw, USER_BAP,
err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), HERMES_RID_CNFWEPKEYS_AGERE,
infofid, 0); &priv->keys);
if (err) { if (err)
printk(KERN_ERR "%s: error %d reading info frame. " return err;
"Frame dropped.\n", dev->name, err);
return;
} }
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFWEPENABLED_AGERE,
priv->wep_on);
if (err)
return err;
break;
len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
type = le16_to_cpu(info.type); case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
master_wep_flag = 0; /* Off */
switch (type) { if (priv->wep_on) {
case HERMES_INQ_TALLIES: { int keylen;
struct hermes_tallies_frame tallies; int i;
struct iw_statistics *wstats = &priv->wstats;
if (len > sizeof(tallies)) { /* Fudge around firmware weirdness */
printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
dev->name, len);
len = sizeof(tallies);
}
/* Read directly the data (no seek) */ /* Write all 4 keys */
hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, for(i = 0; i < ORINOCO_MAX_KEYS; i++) {
len / 2); /* FIXME: blech! */ /* int keylen = le16_to_cpu(priv->keys[i].len); */
/* Increment our various counters */ if (keylen > LARGE_KEY_SIZE) {
/* wstats->discard.nwid - no wrong BSSID stuff */ printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
wstats->discard.code += priv->ndev->name, i, keylen);
le16_to_cpu(tallies.RxWEPUndecryptable); return -E2BIG;
if (len == sizeof(tallies))
wstats->discard.code +=
le16_to_cpu(tallies.RxDiscards_WEPICVError) +
le16_to_cpu(tallies.RxDiscards_WEPExcluded);
wstats->discard.misc +=
le16_to_cpu(tallies.TxDiscardsWrongSA);
wstats->discard.fragment +=
le16_to_cpu(tallies.RxMsgInBadMsgFragments);
wstats->discard.retries +=
le16_to_cpu(tallies.TxRetryLimitExceeded);
/* wstats->miss.beacon - no match */
} }
break;
case HERMES_INQ_LINKSTATUS: {
struct hermes_linkstatus linkstatus;
u16 newstatus;
if (len != sizeof(linkstatus)) { err = hermes_write_ltv(hw, USER_BAP,
printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", HERMES_RID_CNFDEFAULTKEY0 + i,
dev->name, len); HERMES_BYTES_TO_RECLEN(keylen),
break; priv->keys[i].data);
if (err)
return err;
} }
hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus, /* Write the index of the key used in transmission */
len / 2); err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID,
newstatus = le16_to_cpu(linkstatus.linkstatus); priv->tx_key);
if (err)
return err;
if ( (newstatus == HERMES_LINKSTATUS_CONNECTED) if (priv->wep_restrict) {
|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE) auth_flag = 2;
|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) ) master_wep_flag = 3;
priv->connected = 1; } else {
else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) /* Authentication is where Intersil and Symbol
|| (newstatus == HERMES_LINKSTATUS_DISCONNECTED) * firmware differ... */
|| (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) auth_flag = 1;
|| (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) ) if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
priv->connected = 0; master_wep_flag = 3; /* Symbol */
else
master_wep_flag = 1; /* Intersil */
}
if (newstatus != priv->last_linkstatus)
print_linkstatus(dev, newstatus);
priv->last_linkstatus = newstatus; err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFAUTHENTICATION, auth_flag);
if (err)
return err;
} }
/* Master WEP setting : on/off */
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFWEPFLAGS_INTERSIL,
master_wep_flag);
if (err)
return err;
break; break;
default: default:
printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n", if (priv->wep_on) {
dev->name, type); printk(KERN_ERR "%s: WEP enabled, although not supported!\n",
/* We don't actually do anything about it */ priv->ndev->name);
break; return -EINVAL;
}
} }
return 0;
} }
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) static int __orinoco_program_rids(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw;
struct iw_statistics *wstats = &priv->wstats;
struct sk_buff *skb = NULL;
u16 rxfid, status;
int length, data_len, data_off;
char *p;
struct hermes_rx_descriptor desc;
struct header_struct hdr;
struct ethhdr *eh;
int err; int err;
struct hermes_idstring idbuf;
rxfid = hermes_read_regn(hw, RXFID); /* 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;
}
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), /* Set up the link mode */
rxfid, 0); err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type);
if (err) { if (err) {
printk(KERN_ERR "%s: error %d reading Rx descriptor. " printk(KERN_ERR "%s: Error %d setting port type\n", dev->name, err);
"Frame dropped.\n", dev->name, err); return err;
stats->rx_errors++; }
goto drop; /* 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;
} }
status = le16_to_cpu(desc.status); if (priv->has_ibss) {
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS,
priv->createibss);
if (err) {
printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err);
return err;
}
if (status & HERMES_RXSTAT_ERR) { if ((strlen(priv->desired_essid) == 0) && (priv->createibss)
if (status & HERMES_RXSTAT_UNDECRYPTABLE) { && (!priv->has_ibss_any)) {
wstats->discard.code++; printk(KERN_WARNING "%s: This firmware requires an \
DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
dev->name); /* With wvlan_cs, in this case, we would crash.
} else { * hopefully, this driver will behave better...
stats->rx_crc_errors++; * Jean II */
DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
} }
stats->rx_errors++;
goto drop;
} }
/* For now we ignore the 802.11 header completely, assuming /* Set the desired ESSID */
that the card's firmware has handled anything vital */ idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
/* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
&idbuf);
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) {
printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", dev->name, err);
return err;
}
err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), /* Set the station name */
rxfid, HERMES_802_3_OFFSET); idbuf.len = cpu_to_le16(strlen(priv->nick));
memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
&idbuf);
if (err) { if (err) {
printk(KERN_ERR "%s: error %d reading frame header. " printk(KERN_ERR "%s: Error %d setting nickname\n", dev->name, err);
"Frame dropped.\n", dev->name, err); return err;
stats->rx_errors++;
goto drop;
} }
length = ntohs(hdr.len); /* Set AP density */
if (priv->has_sensitivity) {
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
priv->ap_density);
if (err) {
printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
"Disabling sensitivity control\n", dev->name, err);
/* Sanity checks */ priv->has_sensitivity = 0;
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) {
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
dev->name, length);
stats->rx_length_errors++;
stats->rx_errors++;
goto drop;
} }
/* We need space for the packet data itself, plus an ethernet /* Set RTS threshold */
header, plus 2 bytes so we can align the IP header on a err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh);
32bit boundary, plus 1 byte so we can read in odd length if (err) {
packets from the card, which has an IO granularity of 16 printk(KERN_ERR "%s: Error %d setting RTS threshold\n", dev->name, err);
bits */ return err;
skb = dev_alloc_skb(length+ETH_HLEN+2+1);
if (!skb) {
printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
dev->name);
goto drop;
} }
skb_reserve(skb, 2); /* This way the IP header is aligned */ /* Set fragmentation threshold or MWO robustness */
if (priv->has_mwo)
/* Handle decapsulation err = hermes_write_wordrec(hw, USER_BAP,
* In most cases, the firmware tell us about SNAP frames. HERMES_RID_CNFMWOROBUST_AGERE,
* For some reason, the SNAP frames sent by LinkSys APs priv->mwo_robust);
* are not properly recognised by most firmwares. else
* So, check ourselves */ err = hermes_write_wordrec(hw, USER_BAP,
if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || priv->frag_thresh);
is_ethersnap(&hdr)) { if (err) {
/* These indicate a SNAP within 802.2 LLC within printk(KERN_ERR "%s: Error %d setting framentation\n", dev->name, err);
802.11 frame which we'll need to de-encapsulate to return err;
the original EthernetII frame. */ }
if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ /* Set bitrate */
stats->rx_length_errors++; err = __orinoco_hw_set_bitrate(priv);
goto drop; if (err) {
printk(KERN_ERR "%s: Error %d setting bitrate\n", dev->name, err);
return err;
} }
/* Remove SNAP header, reconstruct EthernetII frame */ /* Set power management */
data_len = length - ENCAPS_OVERHEAD; if (priv->has_pm) {
data_off = HERMES_802_3_OFFSET + sizeof(hdr); err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED,
priv->pm_on);
if (err) {
printk(KERN_ERR "%s: Error %d setting up PM\n",
dev->name, err);
return err;
}
eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFMULTICASTRECEIVE,
priv->pm_mcast);
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) {
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) {
printk(KERN_ERR "%s: Error %d setting up PM\n",
dev->name, err);
return err;
}
}
memcpy(eh, &hdr, 2 * ETH_ALEN); /* Set preamble - only for Symbol so far... */
eh->h_proto = hdr.ethertype; if (priv->has_preamble) {
} else { err = hermes_write_wordrec(hw, USER_BAP,
/* All other cases indicate a genuine 802.3 frame. No HERMES_RID_CNFPREAMBLE_SYMBOL,
decapsulation needed. We just throw the whole priv->preamble);
thing in, and hope the protocol layer can deal with if (err) {
it as 802.3 */ printk(KERN_ERR "%s: Error %d setting preamble\n",
data_len = length; dev->name, err);
data_off = HERMES_802_3_OFFSET; return err;
/* FIXME: we re-read from the card data we already read here */ }
} }
p = skb_put(skb, data_len); /* Set up encryption */
err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), if (priv->has_wep) {
rxfid, data_off); err = __orinoco_hw_setup_wep(priv);
if (err) { if (err) {
printk(KERN_ERR "%s: error %d reading frame. " printk(KERN_ERR "%s: Error %d activating WEP\n",
"Frame dropped.\n", dev->name, err); dev->name, err);
stats->rx_errors++; return err;
goto drop; }
} }
dev->last_rx = jiffies; /* Set promiscuity / multicast*/
skb->dev = dev; priv->promiscuous = 0;
skb->protocol = eth_type_trans(skb, dev); priv->mc_count = 0;
skb->ip_summed = CHECKSUM_NONE; __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
/* Process the wireless stats if needed */ return 0;
orinoco_stat_gather(dev, skb, &desc); }
/* Pass the packet to the networking stack */ /* FIXME: return int? */
netif_rx(skb); static void
stats->rx_packets++; __orinoco_set_multicast_list(struct net_device *dev)
stats->rx_bytes += length;
return;
drop:
stats->rx_dropped++;
if (skb)
dev_kfree_skb_irq(skb);
return;
}
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw;
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
struct hermes_tx_descriptor desc;
int err = 0; int err = 0;
int promisc, mc_count;
if (fid == DUMMY_FID) /* The Hermes doesn't seem to have an allmulti mode, so we go
return; /* Nothing's really happened */ * into promiscuous mode and let the upper levels deal. */
if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
(dev->mc_count > MAX_MULTICAST(priv)) ) {
promisc = 1;
mc_count = 0;
} else {
promisc = 0;
mc_count = dev->mc_count;
}
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); if (promisc != priv->promiscuous) {
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFPROMISCUOUSMODE,
promisc);
if (err) { if (err) {
printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
"(FID=%04X error %d)\n", dev->name, err);
dev->name, fid, err); } else
} else { priv->promiscuous = promisc;
DEBUG(1, "%s: Tx error, status %d\n",
dev->name, le16_to_cpu(desc.status));
} }
stats->tx_errors++; if (! promisc && (mc_count || priv->mc_count) ) {
struct dev_mc_list *p = dev->mc_list;
hermes_multicast_t mclist;
int i;
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); for (i = 0; i < mc_count; i++) {
} /* Paranoia: */
if (! p)
BUG(); /* Multicast list shorter than mc_count */
if (p->dmi_addrlen != ETH_ALEN)
BUG(); /* Bad address size in multicast list */
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
{ p = p->next;
struct orinoco_private *priv = netdev_priv(dev); }
struct net_device_stats *stats = &priv->stats;
stats->tx_packets++; if (p)
printk(KERN_WARNING "Multicast list is longer than mc_count\n");
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES,
HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
&mclist);
if (err)
printk(KERN_ERR "%s: Error %d setting multicast list.\n",
dev->name, err);
else
priv->mc_count = mc_count;
}
/* Since we can set the promiscuous flag when it wasn't asked
for, make sure the net_device knows about it. */
if (priv->promiscuous)
dev->flags |= IFF_PROMISC;
else
dev->flags &= ~IFF_PROMISC;
} }
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) static int orinoco_reconfigure(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
unsigned long flags;
int err = 0;
u16 fid = hermes_read_regn(hw, ALLOCFID); if (priv->broken_disableport) {
schedule_work(&priv->reset_work);
return 0;
}
if (fid != priv->txfid) { err = orinoco_lock(priv, &flags);
if (fid != DUMMY_FID) if (err)
printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", return err;
dev->name, fid);
return;
} else { err = hermes_disable_port(hw, 0);
netif_wake_queue(dev); if (err) {
printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
dev->name);
priv->broken_disableport = 1;
goto out;
} }
hermes_write_regn(hw, ALLOCFID, DUMMY_FID); err = __orinoco_program_rids(dev);
} if (err) {
printk(KERN_WARNING "%s: Unable to reconfigure card\n",
dev->name);
goto out;
}
struct sta_id { err = hermes_enable_port(hw, 0);
u16 id, variant, major, minor; if (err) {
} __attribute__ ((packed)); printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
dev->name);
goto out;
}
static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id) out:
{ if (err) {
/* FIXME: this is fundamentally broken */ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor; schedule_work(&priv->reset_work);
err = 0;
}
orinoco_unlock(priv, &flags);
return err;
if (sta_id->variant == 1)
return FIRMWARE_TYPE_AGERE;
else if ((sta_id->variant == 2) &&
((firmver == 0x10001) || (firmver == 0x20001)))
return FIRMWARE_TYPE_SYMBOL;
else
return FIRMWARE_TYPE_INTERSIL;
} }
static void determine_firmware(struct net_device *dev) /* This must be called from user context, without locks held - use
* schedule_work() */
static void orinoco_reset(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; struct hermes *hw = &priv->hw;
int err; int err;
struct sta_id sta_id; unsigned long flags;
unsigned int firmver;
char tmp[SYMBOL_MAX_VER_LEN+1];
/* Get the firmware version */ err = orinoco_lock(priv, &flags);
err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err)
/* When the hardware becomes available again, whatever
* detects that is responsible for re-initializing
* it. So no need for anything further*/
return;
netif_stop_queue(dev);
/* Shut off interrupts. Depending on what state the hardware
* is in, this might not work, but we'll try anyway */
hermes_set_irqmask(hw, 0);
hermes_write_regn(hw, EVACK, 0xffff);
priv->hw_unavailable++;
priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
priv->connected = 0;
orinoco_unlock(priv, &flags);
if (priv->hard_reset)
err = (*priv->hard_reset)(priv);
if (err) { if (err) {
printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", printk(KERN_ERR "%s: orinoco_reset: Error %d performing hard reset\n",
dev->name, err); dev->name, err);
memset(&sta_id, 0, sizeof(sta_id)); /* FIXME: shutdown of some sort */
return;
} }
le16_to_cpus(&sta_id.id);
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", err = orinoco_reinit_firmware(dev);
dev->name, sta_id.id, sta_id.variant, if (err) {
sta_id.major, sta_id.minor); printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
dev->name, err);
return;
}
if (! priv->firmware_type) spin_lock_irq(&priv->lock); /* This has to be called from user context */
priv->firmware_type = determine_firmware_type(dev, &sta_id);
/* Default capabilities */ priv->hw_unavailable--;
priv->has_sensitivity = 1;
priv->has_mwo = 0;
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;
/* Determine capabilities from the firmware version */ /* priv->open or priv->hw_unavailable might have changed while
switch (priv->firmware_type) { * we dropped the lock */
case FIRMWARE_TYPE_AGERE: if (priv->open && (! priv->hw_unavailable)) {
/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, err = __orinoco_up(dev);
ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ if (err) {
printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware " printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
"version %d.%02d\n", dev->name, dev->name, err);
sta_id.major, sta_id.minor); } else
dev->trans_start = jiffies;
}
firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; spin_unlock_irq(&priv->lock);
priv->has_ibss = (firmver >= 0x60006); return;
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? */
priv->has_mwo = (firmver >= 0x60000);
priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
priv->ibss_port = 1;
/* Tested with Agere firmware : /********************************************************************/
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II /* Interrupt handler */
* Tested CableTron firmware : 4.32 => Anton */ /********************************************************************/
break;
case FIRMWARE_TYPE_SYMBOL: static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ {
/* Intel MAC : 00:02:B3:* */ printk(KERN_DEBUG "%s: TICK\n", dev->name);
}
static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
{
/* This seems to happen a fair bit under load, but ignoring it
seems to work fine...*/
printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
dev->name);
}
irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *)dev_id;
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
int count = MAX_IRQLOOPS_PER_IRQ;
u16 evstat, events;
/* These are used to detect a runaway interrupt situation */
/* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
* 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 (orinoco_lock(priv, &flags) != 0) {
/* If hw is unavailable - we don't know if the irq was
* for us or not */
return IRQ_HANDLED;
}
evstat = hermes_read_regn(hw, EVSTAT);
events = evstat & hw->inten;
if (! events) {
orinoco_unlock(priv, &flags);
return IRQ_NONE;
}
if (jiffies != last_irq_jiffy)
loops_this_jiffy = 0;
last_irq_jiffy = jiffies;
while (events && count--) {
if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
printk(KERN_WARNING "%s: IRQ handler is looping too "
"much! Resetting.\n", dev->name);
/* Disable interrupts for now */
hermes_set_irqmask(hw, 0);
schedule_work(&priv->reset_work);
break;
}
/* Check the card hasn't been removed */
if (! hermes_present(hw)) {
DEBUG(0, "orinoco_interrupt(): card removed\n");
break;
}
if (events & HERMES_EV_TICK)
__orinoco_ev_tick(dev, hw);
if (events & HERMES_EV_WTERR)
__orinoco_ev_wterr(dev, hw);
if (events & HERMES_EV_INFDROP)
__orinoco_ev_infdrop(dev, hw);
if (events & HERMES_EV_INFO)
__orinoco_ev_info(dev, hw);
if (events & HERMES_EV_RX)
__orinoco_ev_rx(dev, hw);
if (events & HERMES_EV_TXEXC)
__orinoco_ev_txexc(dev, hw);
if (events & HERMES_EV_TX)
__orinoco_ev_tx(dev, hw);
if (events & HERMES_EV_ALLOC)
__orinoco_ev_alloc(dev, hw);
hermes_write_regn(hw, EVACK, events);
evstat = hermes_read_regn(hw, EVSTAT);
events = evstat & hw->inten;
};
orinoco_unlock(priv, &flags);
return IRQ_HANDLED;
}
/********************************************************************/
/* Initialization */
/********************************************************************/
struct sta_id {
u16 id, variant, major, minor;
} __attribute__ ((packed));
static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id)
{
/* FIXME: this is fundamentally broken */
unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor;
if (sta_id->variant == 1)
return FIRMWARE_TYPE_AGERE;
else if ((sta_id->variant == 2) &&
((firmver == 0x10001) || (firmver == 0x20001)))
return FIRMWARE_TYPE_SYMBOL;
else
return FIRMWARE_TYPE_INTERSIL;
}
static void 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;
unsigned int firmver;
char tmp[SYMBOL_MAX_VER_LEN+1];
/* 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",
dev->name, err);
memset(&sta_id, 0, sizeof(sta_id));
}
le16_to_cpus(&sta_id.id);
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",
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);
/* Default capabilities */
priv->has_sensitivity = 1;
priv->has_mwo = 0;
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;
/* Determine capabilities from the firmware version */
switch (priv->firmware_type) {
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);
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? */
priv->has_mwo = (firmver >= 0x60000);
priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
priv->ibss_port = 1;
/* Tested with Agere firmware :
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
* Tested CableTron firmware : 4.32 => Anton */
break;
case FIRMWARE_TYPE_SYMBOL:
/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
/* Intel MAC : 00:02:B3:* */
/* 3Com MAC : 00:50:DA:* */ /* 3Com MAC : 00:50:DA:* */
memset(tmp, 0, sizeof(tmp)); memset(tmp, 0, sizeof(tmp));
/* Get the Symbol firmware version */ /* Get the Symbol firmware version */
...@@ -2009,10 +2150,6 @@ static void determine_firmware(struct net_device *dev) ...@@ -2009,10 +2150,6 @@ static void determine_firmware(struct net_device *dev)
} }
} }
/*
* struct net_device methods
*/
static int static int
orinoco_init(struct net_device *dev) orinoco_init(struct net_device *dev)
{ {
...@@ -2193,357 +2330,202 @@ orinoco_init(struct net_device *dev) ...@@ -2193,357 +2330,202 @@ orinoco_init(struct net_device *dev)
return err; return err;
} }
struct net_device_stats * struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *))
orinoco_get_stats(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
return &priv->stats;
}
struct iw_statistics *
orinoco_get_wireless_stats(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct net_device *dev;
hermes_t *hw = &priv->hw; struct orinoco_private *priv;
struct iw_statistics *wstats = &priv->wstats;
int err = 0;
unsigned long flags;
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? */
}
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));
/* If a spy address is defined, we report stats of the
* first spy address - Jean II */
if (SPY_NUMBER(priv)) {
wstats->qual.qual = priv->spy_stat[0].qual;
wstats->qual.level = priv->spy_stat[0].level;
wstats->qual.noise = priv->spy_stat[0].noise;
wstats->qual.updated = priv->spy_stat[0].updated;
}
} else {
struct {
u16 qual, signal, noise;
} __attribute__ ((packed)) cq;
err = HERMES_READ_RECORD(hw, USER_BAP,
HERMES_RID_COMMSQUALITY, &cq);
wstats->qual.qual = (int)le16_to_cpu(cq.qual); dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; if (!dev)
wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; return NULL;
wstats->qual.updated = 7; priv = netdev_priv(dev);
} priv->ndev = dev;
if (sizeof_card)
priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private));
else
priv->card = NULL;
/* We can't really wait for the tallies inquiry command to /* Setup / override net_device fields */
* complete, so we just use the previous results and trigger dev->init = orinoco_init;
* a new tallies inquiry command for next time - Jean II */ dev->hard_start_xmit = orinoco_xmit;
/* FIXME: We're in user context (I think?), so we should just dev->tx_timeout = orinoco_tx_timeout;
wait for the tallies to come through */ dev->watchdog_timeo = HZ; /* 1 second timeout */
err = hermes_inquire(hw, HERMES_INQ_TALLIES); dev->get_stats = orinoco_get_stats;
dev->get_wireless_stats = orinoco_get_wireless_stats;
dev->do_ioctl = orinoco_ioctl;
dev->change_mtu = orinoco_change_mtu;
dev->set_multicast_list = orinoco_set_multicast_list;
/* we use the default eth_mac_addr for setting the MAC addr */
orinoco_unlock(priv, &flags); /* Set up default callbacks */
dev->open = orinoco_open;
dev->stop = orinoco_stop;
priv->hard_reset = hard_reset;
if (err) spin_lock_init(&priv->lock);
return NULL; priv->open = 0;
priv->hw_unavailable = 1; /* orinoco_init() must clear this
* before anything else touches the
* hardware */
INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
return wstats; priv->last_linkstatus = 0xffff;
} priv->connected = 0;
static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, return dev;
int level, int noise)
{
struct orinoco_private *priv = netdev_priv(dev);
int i;
/* Gather wireless spy statistics: for each packet, compare the
* source address with out list, and if match, get the stats... */
for (i = 0; i < priv->spy_number; i++)
if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) {
priv->spy_stat[i].level = level - 0x95;
priv->spy_stat[i].noise = noise - 0x95;
priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0;
priv->spy_stat[i].updated = 7;
}
} }
void /********************************************************************/
orinoco_stat_gather(struct net_device *dev, /* Wireless extensions */
struct sk_buff *skb, /********************************************************************/
struct hermes_rx_descriptor *desc)
{
struct orinoco_private *priv = netdev_priv(dev);
/* Using spy support with lots of Rx packets, like in an
* infrastructure (AP), will really slow down everything, because
* the MAC address must be compared to each entry of the spy list.
* If the user really asks for it (set some address in the
* spy list), we do it, but he will pay the price.
* Note that to get here, you need both WIRELESS_SPY
* compiled in AND some addresses in the list !!!
*/
/* Note : gcc will optimise the whole section away if
* WIRELESS_SPY is not defined... - Jean II */
if (SPY_NUMBER(priv)) {
orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN,
desc->signal, desc->silence);
}
}
static int static int orinoco_hw_get_bssid(struct orinoco_private *priv,
orinoco_xmit(struct sk_buff *skb, struct net_device *dev) char buf[ETH_ALEN])
{ {
struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int err = 0; int err = 0;
u16 txfid = priv->txfid;
char *p;
struct ethhdr *eh;
int len, data_len, data_off;
struct hermes_tx_descriptor desc;
unsigned long flags; unsigned long flags;
TRACE_ENTER(dev->name); err = orinoco_lock(priv, &flags);
if (err)
if (! netif_running(dev)) { return err;
printk(KERN_ERR "%s: Tx on stopped device!\n",
dev->name);
TRACE_EXIT(dev->name);
return 1;
}
if (netif_queue_stopped(dev)) {
printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
dev->name);
TRACE_EXIT(dev->name);
return 1;
}
if (orinoco_lock(priv, &flags) != 0) { err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", ETH_ALEN, NULL, buf);
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); 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? */
len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
eh = (struct ethhdr *)skb->data;
memset(&desc, 0, sizeof(desc));
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);
stats->tx_errors++;
goto fail;
}
/* Clear the 802.11 header and data length fields - some
* firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
* if this isn't done. */
hermes_clear_words(hw, HERMES_DATA0,
HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
/* Encapsulate Ethernet-II frames */
if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
struct header_struct hdr;
data_len = len;
data_off = HERMES_802_3_OFFSET + sizeof(hdr);
p = skb->data + ETH_HLEN;
/* 802.3 header */
memcpy(hdr.dest, eh->h_dest, ETH_ALEN);
memcpy(hdr.src, eh->h_source, ETH_ALEN);
hdr.len = htons(data_len + ENCAPS_OVERHEAD);
/* 802.2 header */ return err;
memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); }
hdr.ethertype = eh->h_proto; static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), char buf[IW_ESSID_MAX_SIZE+1])
txfid, HERMES_802_3_OFFSET); {
if (err) { hermes_t *hw = &priv->hw;
printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", int err = 0;
dev->name, err); struct hermes_idstring essidbuf;
stats->tx_errors++; char *p = (char *)(&essidbuf.val);
goto fail; int len;
} unsigned long flags;
} else { /* IEEE 802.3 frame */
data_len = len + ETH_HLEN;
data_off = HERMES_802_3_OFFSET;
p = skb->data;
}
/* Round up for odd length packets */ err = orinoco_lock(priv, &flags);
err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); if (err)
if (err) { return err;
printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
dev->name, err);
stats->tx_errors++;
goto fail;
}
/* Finally, we actually initiate the send */ if (strlen(priv->desired_essid) > 0) {
netif_stop_queue(dev); /* We read the desired SSID from the hardware rather
than from priv->desired_essid, just in case the
firmware is allowed to change it on us. I'm not
sure about this */
/* My guess is that the OWNSSID should always be whatever
* we set to the card, whereas CURRENT_SSID is the one that
* may change... - Jean II */
u16 rid;
err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, NULL); *active = 1;
if (err) {
netif_start_queue(dev);
printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err);
stats->tx_errors++;
goto fail;
}
dev->trans_start = jiffies; rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
stats->tx_bytes += data_off + data_len; HERMES_RID_CNFDESIREDSSID;
orinoco_unlock(priv, &flags); err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
NULL, &essidbuf);
if (err)
goto fail_unlock;
} else {
*active = 0;
dev_kfree_skb(skb); err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
sizeof(essidbuf), NULL, &essidbuf);
if (err)
goto fail_unlock;
}
TRACE_EXIT(dev->name); len = le16_to_cpu(essidbuf.len);
return 0; memset(buf, 0, IW_ESSID_MAX_SIZE+1);
fail: memcpy(buf, p, len);
TRACE_EXIT(dev->name); buf[len] = '\0';
fail_unlock:
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return err; return err;
} }
static void static long orinoco_hw_get_freq(struct orinoco_private *priv)
orinoco_tx_timeout(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct hermes *hw = &priv->hw;
printk(KERN_WARNING "%s: Tx timeout! " hermes_t *hw = &priv->hw;
"ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", int err = 0;
dev->name, hermes_read_regn(hw, ALLOCFID), u16 channel;
hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); long freq = 0;
unsigned long flags;
stats->tx_errors++; err = orinoco_lock(priv, &flags);
if (err)
return err;
schedule_work(&priv->reset_work); err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
} if (err)
goto out;
static int /* Intersil firmware 1.3.5 returns 0 when the interface is down */
orinoco_change_mtu(struct net_device *dev, int new_mtu) if (channel == 0) {
{ err = -EBUSY;
struct orinoco_private *priv = netdev_priv(dev); goto out;
}
if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
return -EINVAL; printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
priv->ndev->name, channel);
err = -EBUSY;
goto out;
if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > }
(priv->nicbuf_size - ETH_HLEN) ) freq = channel_frequency[channel-1] * 100000;
return -EINVAL;
dev->mtu = new_mtu; out:
orinoco_unlock(priv, &flags);
return 0; if (err > 0)
err = -EBUSY;
return err ? err : freq;
} }
/* FIXME: return int? */ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
static void int *numrates, s32 *rates, int max)
__orinoco_set_multicast_list(struct net_device *dev)
{ {
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
struct hermes_idstring list;
unsigned char *p = (unsigned char *)&list.val;
int err = 0; int err = 0;
int promisc, mc_count; int num;
/* 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) ||
(dev->mc_count > MAX_MULTICAST(priv)) ) {
promisc = 1;
mc_count = 0;
} else {
promisc = 0;
mc_count = dev->mc_count;
}
if (promisc != priv->promiscuous) {
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFPROMISCUOUSMODE,
promisc);
if (err) {
printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
dev->name, err);
} else
priv->promiscuous = promisc;
}
if (! promisc && (mc_count || priv->mc_count) ) {
struct dev_mc_list *p = dev->mc_list;
hermes_multicast_t mclist;
int i; int i;
unsigned long flags;
for (i = 0; i < mc_count; i++) { err = orinoco_lock(priv, &flags);
/* Paranoia: */ if (err)
if (! p) return err;
BUG(); /* Multicast list shorter than mc_count */
if (p->dmi_addrlen != ETH_ALEN)
BUG(); /* Bad address size in multicast list */
memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
p = p->next;
}
if (p) err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
printk(KERN_WARNING "Multicast list is longer than mc_count\n"); sizeof(list), NULL, &list);
orinoco_unlock(priv, &flags);
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES,
HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
&mclist);
if (err) if (err)
printk(KERN_ERR "%s: Error %d setting multicast list.\n", return err;
dev->name, err);
else num = le16_to_cpu(list.len);
priv->mc_count = mc_count; *numrates = num;
num = min(num, max);
for (i = 0; i < num; i++) {
rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
} }
/* Since we can set the promiscuous flag when it wasn't asked return 0;
for, make sure the net_device knows about it. */
if (priv->promiscuous)
dev->flags |= IFF_PROMISC;
else
dev->flags &= ~IFF_PROMISC;
} }
/********************************************************************/
/* Wireless extensions support */
/********************************************************************/
static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
...@@ -4102,51 +4084,68 @@ static int orinoco_debug_dump_recs(struct net_device *dev) ...@@ -4102,51 +4084,68 @@ static int orinoco_debug_dump_recs(struct net_device *dev)
return 0; return 0;
} }
struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *)) /********************************************************************/
{ /* Debugging */
struct net_device *dev; /********************************************************************/
struct orinoco_private *priv;
dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
if (!dev)
return NULL;
priv = netdev_priv(dev);
priv->ndev = dev;
if (sizeof_card)
priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private));
else
priv->card = NULL;
/* Setup / override net_device fields */
dev->init = orinoco_init;
dev->hard_start_xmit = orinoco_xmit;
dev->tx_timeout = orinoco_tx_timeout;
dev->watchdog_timeo = HZ; /* 1 second timeout */
dev->get_stats = orinoco_get_stats;
dev->get_wireless_stats = orinoco_get_wireless_stats;
dev->do_ioctl = orinoco_ioctl;
dev->change_mtu = orinoco_change_mtu;
dev->set_multicast_list = orinoco_set_multicast_list;
/* we use the default eth_mac_addr for setting the MAC addr */
/* Set up default callbacks */
dev->open = orinoco_open;
dev->stop = orinoco_stop;
priv->hard_reset = hard_reset;
spin_lock_init(&priv->lock); #if 0
priv->open = 0; static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
priv->hw_unavailable = 1; /* orinoco_init() must clear this {
* before anything else touches the printk(KERN_DEBUG "RX descriptor:\n");
* hardware */ printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status);
INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time);
printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence);
printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal);
printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate);
printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow);
printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved);
priv->last_linkstatus = 0xffff; printk(KERN_DEBUG "IEEE 802.11 header:\n");
priv->connected = 0; printk(KERN_DEBUG " frame_ctl = 0x%04x\n",
frame->p80211.frame_ctl);
printk(KERN_DEBUG " duration_id = 0x%04x\n",
frame->p80211.duration_id);
printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr1[0], frame->p80211.addr1[1],
frame->p80211.addr1[2], frame->p80211.addr1[3],
frame->p80211.addr1[4], frame->p80211.addr1[5]);
printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr2[0], frame->p80211.addr2[1],
frame->p80211.addr2[2], frame->p80211.addr2[3],
frame->p80211.addr2[4], frame->p80211.addr2[5]);
printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr3[0], frame->p80211.addr3[1],
frame->p80211.addr3[2], frame->p80211.addr3[3],
frame->p80211.addr3[4], frame->p80211.addr3[5]);
printk(KERN_DEBUG " seq_ctl = 0x%04x\n",
frame->p80211.seq_ctl);
printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p80211.addr4[0], frame->p80211.addr4[1],
frame->p80211.addr4[2], frame->p80211.addr4[3],
frame->p80211.addr4[4], frame->p80211.addr4[5]);
printk(KERN_DEBUG " data_len = 0x%04x\n",
frame->p80211.data_len);
return dev; printk(KERN_DEBUG "IEEE 802.3 header:\n");
printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p8023.h_dest[0], frame->p8023.h_dest[1],
frame->p8023.h_dest[2], frame->p8023.h_dest[3],
frame->p8023.h_dest[4], frame->p8023.h_dest[5]);
printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
frame->p8023.h_source[0], frame->p8023.h_source[1],
frame->p8023.h_source[2], frame->p8023.h_source[3],
frame->p8023.h_source[4], frame->p8023.h_source[5]);
printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto);
printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n");
printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap);
printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap);
printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl);
printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n",
frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype);
} }
#endif /* 0 */
/********************************************************************/ /********************************************************************/
/* Module initialization */ /* Module initialization */
......
...@@ -27,11 +27,6 @@ struct orinoco_key { ...@@ -27,11 +27,6 @@ struct orinoco_key {
char data[ORINOCO_MAX_KEY_SIZE]; char data[ORINOCO_MAX_KEY_SIZE];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define ORINOCO_INTEN ( HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | \
HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \
HERMES_EV_INFDROP )
struct orinoco_private { struct orinoco_private {
void *card; /* Pointer to card dependent structure */ void *card; /* Pointer to card dependent structure */
int (*hard_reset)(struct orinoco_private *); int (*hard_reset)(struct orinoco_private *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment