⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 orinoco.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for Hermes or Prism 2 chipset based PCMCIA wireless * adaptors, with Lucent/Agere, Intersil or Symbol firmware. * * Current maintainers (as of 29 September 2003) are: * 	Pavel Roskin <proski AT gnu.org> * and	David Gibson <hermes AT gibson.dropbear.id.au> * * (C) Copyright David Gibson, IBM Corporation 2001-2003. * Copyright (C) 2000 David Gibson, Linuxcare Australia. *	With some help from : * Copyright (C) 2001 Jean Tourrilhes, HP Labs * Copyright (C) 2001 Benjamin Herrenschmidt * * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 * * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy * AT fasta.fh-dortmund.de> *      http://www.stud.fh-dortmund.de/~andy/wvlan/ * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License * at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and * limitations under the License. * * The initial developer of the original code is David A. Hinds * <dahinds AT users.sourceforge.net>.  Portions created by David * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights * Reserved. * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above.  If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the MPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL.  If you do not delete the * provisions above, a recipient may use your version of this file * under either the MPL or the GPL.  *//* * TODO *	o Handle de-encapsulation within network layer, provide 802.11 *	  headers (patch from Thomas 'Dent' Mirlacher) *	o Fix possible races in SPY handling. *	o Disconnect wireless extensions from fundamental configuration. *	o (maybe) Software WEP support (patch from Stano Meduna). *	o (maybe) Use multiple Tx buffers - driver handling queue *	  rather than firmware. *//* Locking and synchronization: * * The basic principle is that everything is serialized through a * single spinlock, priv->lock.  The lock is used in user, bh and irq * context, so when taken outside hardirq context it should always be * taken with interrupts disabled.  The lock protects both the * hardware and the struct orinoco_private. * * Another flag, priv->hw_unavailable indicates that the hardware is * unavailable for an extended period of time (e.g. suspended, or in * the middle of a hard reset).  This flag is protected by the * spinlock.  All code which touches the hardware should check the * flag after taking the lock, and if it is set, give up on whatever * they are doing and drop the lock again.  The orinoco_lock() * function handles this (it unlocks and returns -EBUSY if * hw_unavailable is non-zero). */#define DRIVER_NAME "orinoco"#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/wireless.h>#include <net/iw_handler.h>#include <net/ieee80211.h>#include "hermes_rid.h"#include "orinoco.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, 0644);MODULE_PARM_DESC(orinoco_debug, "Debug level");EXPORT_SYMBOL(orinoco_debug);#endifstatic int suppress_linkstatus; /* = 0 */module_param(suppress_linkstatus, bool, 0644);MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");static int ignore_disconnect; /* = 0 */module_param(ignore_disconnect, int, 0644);MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");static int force_monitor; /* = 0 */module_param(force_monitor, int, 0644);MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");/********************************************************************//* 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_data.spy_number)#else#define SPY_NUMBER(priv)	0#endif /* WIRELESS_SPY *//********************************************************************//* Internal constants                                               *//********************************************************************//* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)#define ORINOCO_MIN_MTU		256#define ORINOCO_MAX_MTU		(IEEE80211_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 )#define MAX_RID_LEN 1024static const struct iw_handler_def orinoco_handler_def;static struct ethtool_ops orinoco_ethtool_ops;/********************************************************************//* 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                                                       *//********************************************************************//* Used in Event handling. * We avoid nested structures as they break on ARM -- Moustafa */struct hermes_tx_descriptor_802_11 {	/* hermes_tx_descriptor */	__le16 status;	__le16 reserved1;	__le16 reserved2;	__le32 sw_support;	u8 retry_count;	u8 tx_rate;	__le16 tx_control;	/* ieee80211_hdr */	__le16 frame_ctl;	__le16 duration_id;	u8 addr1[ETH_ALEN];	u8 addr2[ETH_ALEN];	u8 addr3[ETH_ALEN];	__le16 seq_ctl;	u8 addr4[ETH_ALEN];	__le16 data_len;	/* ethhdr */	u8 h_dest[ETH_ALEN];	/* destination eth addr */	u8 h_source[ETH_ALEN];	/* source ether addr    */	__be16 h_proto;		/* packet type ID field */	/* p8022_hdr */	u8 dsap;	u8 ssap;	u8 ctrl;	u8 oui[3];	__be16 ethertype;} __attribute__ ((packed));/* Rx frame header except compatibility 802.3 header */struct hermes_rx_descriptor {	/* Control */	__le16 status;	__le32 time;	u8 silence;	u8 signal;	u8 rate;	u8 rxflow;	__le32 reserved;	/* 802.11 header */	__le16 frame_ctl;	__le16 duration_id;	u8 addr1[ETH_ALEN];	u8 addr2[ETH_ALEN];	u8 addr3[ETH_ALEN];	__le16 seq_ctl;	u8 addr4[ETH_ALEN];	/* Data length */	__le16 data_len;} __attribute__ ((packed));/********************************************************************//* Function prototypes                                              *//********************************************************************/static int __orinoco_program_rids(struct net_device *dev);static void __orinoco_set_multicast_list(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;	case IW_MODE_MONITOR:		priv->port_type = 3;		priv->createibss = 0;		break;	default:		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",		       priv->ndev->name);	}}/********************************************************************//* 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;}static 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;	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 busy, return the old stats.  Returning NULL may cause	 * the interface to disappear from /proc/net/wireless */	if (orinoco_lock(priv, &flags) != 0)		return wstats;	/* We can't really wait for the tallies inquiry command to	 * complete, so we just use the previous results and trigger	 * a new tallies inquiry command for next time - Jean II */	/* FIXME: Really we should wait for the inquiry to come back -	 * as it is the stats we give don't make a whole lot of sense.	 * Unfortunately, it's not clear how to do that within the	 * wireless extensions framework: I think we're in user	 * context, but a lock seems to be held by the time we get in	 * here so we're not safe to sleep here. */	hermes_inquire(hw, HERMES_INQ_TALLIES);	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_data.spy_stat[0].qual;			wstats->qual.level = priv->spy_data.spy_stat[0].level;			wstats->qual.noise = priv->spy_data.spy_stat[0].noise;			wstats->qual.updated = priv->spy_data.spy_stat[0].updated;		}	} else {		struct {			__le16 qual, signal, noise;		} __attribute__ ((packed)) cq;		err = HERMES_READ_RECORD(hw, USER_BAP,					 HERMES_RID_COMMSQUALITY, &cq);		if (!err) {			wstats->qual.qual = (int)le16_to_cpu(cq.qual);			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;			wstats->qual.updated = 7;		}	}	orinoco_unlock(priv, &flags);	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 + IEEE80211_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;	}	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -