📄 orinoco.c
字号:
* spinlock. All code which touches the hardware should check the * flag after taking the lock, and if it is set, give up on whatever * they are doing and drop the lock again. The orinoco_lock() * function handles this (it unlocks and returns -EBUSY if * hw_unavailable is non-zero). */#define DRIVER_NAME "orinoco"#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/ptrace.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ioport.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/etherdevice.h>#include <linux/wireless.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/system.h>#include "hermes.h"#include "hermes_rid.h"#include "orinoco.h"#include "ieee802_11.h"/********************************************************************//* Module information *//********************************************************************/MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>");MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");MODULE_LICENSE("Dual MPL/GPL");/* Level of debugging. Used in the macros in orinoco.h */#ifdef ORINOCO_DEBUGint orinoco_debug = ORINOCO_DEBUG;module_param(orinoco_debug, int, 0);EXPORT_SYMBOL(orinoco_debug);#endifstatic int suppress_linkstatus; /* = 0 */module_param(suppress_linkstatus, bool, 0);/********************************************************************//* Compile time configuration and compatibility stuff *//********************************************************************//* We do this this way to avoid ifdefs in the actual code */#ifdef WIRELESS_SPY#define SPY_NUMBER(priv) (priv->spy_number)#else#define SPY_NUMBER(priv) 0#endif /* WIRELESS_SPY *//********************************************************************//* Internal constants *//********************************************************************/#define ORINOCO_MIN_MTU 256#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)#define SYMBOL_MAX_VER_LEN (14)#define USER_BAP 0#define IRQ_BAP 1#define MAX_IRQLOOPS_PER_IRQ 10#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of * how many events the * device could * legitimately generate */#define SMALL_KEY_SIZE 5#define LARGE_KEY_SIZE 13#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */#define DUMMY_FID 0xFFFF/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ HERMES_MAX_MULTICAST : 0)*/#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 *//********************************************************************//* The frequency of each channel in MHz */static const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484};#define NUM_CHANNELS ARRAY_SIZE(channel_frequency)/* This tables gives the actual meanings of the bitrate IDs returned * by the firmware. */static struct { int bitrate; /* in 100s of kilobits */ int automatic; u16 agere_txratectrl; u16 intersil_txratectrl;} bitrate_table[] = { {110, 1, 3, 15}, /* Entry 0 is the default */ {10, 0, 1, 1}, {10, 1, 1, 1}, {20, 0, 2, 2}, {20, 1, 6, 3}, {55, 0, 4, 4}, {55, 1, 7, 7}, {110, 0, 5, 8},};#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)/********************************************************************//* Data types *//********************************************************************/struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; u16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; u16 ethertype;} __attribute__ ((packed));/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};#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 *//********************************************************************/static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int __orinoco_program_rids(struct net_device *dev);static void __orinoco_set_multicast_list(struct net_device *dev);static int orinoco_debug_dump_recs(struct net_device *dev);/********************************************************************//* Internal helper functions *//********************************************************************/static inline void set_port_type(struct orinoco_private *priv){ switch (priv->iw_mode) { case IW_MODE_INFRA: priv->port_type = 1; priv->createibss = 0; break; case IW_MODE_ADHOC: if (priv->prefer_port3) { priv->port_type = 3; priv->createibss = 0; } else { priv->port_type = priv->ibss_port; priv->createibss = 1; } break; default: printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", priv->ndev->name); }}/********************************************************************//* Device methods *//********************************************************************/static int orinoco_open(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; err = __orinoco_up(dev); if (! err) priv->open = 1; orinoco_unlock(priv, &flags); return err;}int orinoco_stop(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); int err = 0; /* We mustn't use orinoco_lock() here, because we need to be able to close the interface even if hw_unavailable is set (e.g. as we're released after a PC Card removal) */ spin_lock_irq(&priv->lock); priv->open = 0; err = __orinoco_down(dev); spin_unlock_irq(&priv->lock); return err;}static struct net_device_stats *orinoco_get_stats(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); return &priv->stats;}static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; 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? */ } if (orinoco_lock(priv, &flags) != 0) 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); wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; wstats->qual.updated = 7; } /* We can't really wait for the tallies inquiry command to * complete, so we just use the previous results and trigger * a new tallies inquiry command for next time - Jean II */ /* FIXME: We're in user context (I think?), so we should just wait for the tallies to come through */ err = hermes_inquire(hw, HERMES_INQ_TALLIES); orinoco_unlock(priv, &flags); if (err) return NULL; return wstats;}static void orinoco_set_multicast_list(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " "called when hw_unavailable\n", dev->name); return; } __orinoco_set_multicast_list(dev); orinoco_unlock(priv, &flags);}static int orinoco_change_mtu(struct net_device *dev, int new_mtu){ struct orinoco_private *priv = netdev_priv(dev); if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > (priv->nicbuf_size - ETH_HLEN) ) return -EINVAL; dev->mtu = new_mtu; return 0;}/********************************************************************//* Tx path *//********************************************************************/static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; 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; TRACE_ENTER(dev->name); if (! netif_running(dev)) { printk(KERN_ERR "%s: Tx on stopped device!\n", dev->name); TRACE_EXIT(dev->name); return 1; } if (netif_queue_stopped(dev)) { printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", dev->name); TRACE_EXIT(dev->name); return 1; } if (orinoco_lock(priv, &flags) != 0) { printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", dev->name); TRACE_EXIT(dev->name); return 1; } if (! priv->connected) { /* Oops, the firmware hasn't established a connection, silently drop the packet (this seems to be the safest approach). */ stats->tx_errors++; orinoco_unlock(priv, &flags); dev_kfree_skb(skb); TRACE_EXIT(dev->name); return 0; } /* Length of the packet body */ /* FIXME: what if the skb is smaller than this? */ 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) > ETH_DATA_LEN) { /* 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 */ memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); hdr.ethertype = eh->h_proto; err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, HERMES_802_3_OFFSET); if (err) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -