📄 orinoco.c
字号:
* 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). */#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("David Gibson <hermes@gibson.dropbear.id.au>");MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");#ifdef MODULE_LICENSEMODULE_LICENSE("Dual MPL/GPL");#endif/* Level of debugging. Used in the macros in orinoco.h */#ifdef ORINOCO_DEBUGint orinoco_debug = ORINOCO_DEBUG;MODULE_PARM(orinoco_debug, "i");EXPORT_SYMBOL(orinoco_debug);#endifstatic int suppress_linkstatus; /* = 0 */MODULE_PARM(suppress_linkstatus, "i");/********************************************************************//* Compile time configuration and compatibility stuff *//********************************************************************//* Wireless extensions backwards compatibility */#ifndef SIOCIWFIRSTPRIV#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE#endif /* SIOCIWFIRSTPRIV *//* We do this this way to avoid ifdefs in the actual code */#ifdef WIRELESS_SPY#define SPY_NUMBER(priv) (priv->spy_number)#else#define SPY_NUMBER(priv) 0#endif /* WIRELESS_SPY *//********************************************************************//* Internal constants *//********************************************************************/#define ORINOCO_MIN_MTU 256#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)#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 RUP_EVEN(a) (((a) + 1) & (~1))/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ HERMES_MAX_MULTICAST : 0)*/#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST)/********************************************************************//* Data tables *//********************************************************************//* The frequency of each channel in MHz */const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484};#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */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 (sizeof(bitrate_table) / sizeof(bitrate_table[0]))/********************************************************************//* 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)/********************************************************************//* Function prototypes *//********************************************************************/static void orinoco_stat_gather(struct net_device *dev, 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_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);/* 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);/********************************************************************//* Function prototypes *//********************************************************************/int __orinoco_up(struct net_device *dev){ 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); struct hermes *hw = &priv->hw; int err; netif_stop_queue(dev); if (! priv->hw_unavailable) { if (! priv->broken_disableport) { err = hermes_disable_port(hw, 0); if (err) { /* Some firmwares (e.g. Intersil 1.3.x) seem * to have problems disabling the port, oh * 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); hermes_write_regn(hw, EVACK, 0xffff); } /* firmware will have to reassociate */ priv->last_linkstatus = 0xffff; priv->connected = 0; return 0;}int orinoco_reinit_firmware(struct net_device *dev){ 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){ struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; err = orinoco_lock(priv, &flags); if (err) return err; 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 int __orinoco_program_rids(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; /* 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; } /* Set up the link mode */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type); if (err) { printk(KERN_ERR "%s: Error %d setting port type\n", dev->name, err); return err; } /* Set the channel/frequency */ if (priv->channel == 0) { printk(KERN_DEBUG "%s: Channel is 0 in __orinoco_program_rids()\n", dev->name); if (priv->createibss) priv->channel = 10; } err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); if (err) { printk(KERN_ERR "%s: Error %d setting channel\n", dev->name, err); return err; } if (priv->has_ibss) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS, priv->createibss); if (err) { printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err); return err; } if ((strlen(priv->desired_essid) == 0) && (priv->createibss) && (!priv->has_ibss_any)) { printk(KERN_WARNING "%s: This firmware requires an \ESSID in IBSS-Ad-Hoc mode.\n", dev->name); /* With wvlan_cs, in this case, we would crash. * hopefully, this driver will behave better... * Jean II */ } } /* Set the desired ESSID */ 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; } /* Set the station name */ 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) { printk(KERN_ERR "%s: Error %d setting nickname\n", dev->name, err); return err; } /* Set AP density */ if (priv->has_sensitivity) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, priv->ap_density); if (err) { printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " "Disabling sensitivity control\n", dev->name, err); priv->has_sensitivity = 0; } } /* Set RTS threshold */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh); if (err) { printk(KERN_ERR "%s: Error %d setting RTS threshold\n", dev->name, err); return err; } /* Set fragmentation threshold or MWO robustness */ if (priv->has_mwo) err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFMWOROBUST_AGERE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -