xref: /openbmc/linux/drivers/net/wireless/intersil/orinoco/main.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
12be45b66SKalle Valo /* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c)
22be45b66SKalle Valo  *
32be45b66SKalle Valo  * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
42be45b66SKalle Valo  * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
52be45b66SKalle Valo  *
62be45b66SKalle Valo  * Current maintainers (as of 29 September 2003) are:
72be45b66SKalle Valo  *	Pavel Roskin <proski AT gnu.org>
82be45b66SKalle Valo  * and	David Gibson <hermes AT gibson.dropbear.id.au>
92be45b66SKalle Valo  *
102be45b66SKalle Valo  * (C) Copyright David Gibson, IBM Corporation 2001-2003.
112be45b66SKalle Valo  * Copyright (C) 2000 David Gibson, Linuxcare Australia.
122be45b66SKalle Valo  *	With some help from :
132be45b66SKalle Valo  * Copyright (C) 2001 Jean Tourrilhes, HP Labs
142be45b66SKalle Valo  * Copyright (C) 2001 Benjamin Herrenschmidt
152be45b66SKalle Valo  *
162be45b66SKalle Valo  * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
172be45b66SKalle Valo  *
182be45b66SKalle Valo  * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
192be45b66SKalle Valo  * AT fasta.fh-dortmund.de>
202be45b66SKalle Valo  *      http://www.stud.fh-dortmund.de/~andy/wvlan/
212be45b66SKalle Valo  *
222be45b66SKalle Valo  * The contents of this file are subject to the Mozilla Public License
232be45b66SKalle Valo  * Version 1.1 (the "License"); you may not use this file except in
242be45b66SKalle Valo  * compliance with the License. You may obtain a copy of the License
252be45b66SKalle Valo  * at http://www.mozilla.org/MPL/
262be45b66SKalle Valo  *
272be45b66SKalle Valo  * Software distributed under the License is distributed on an "AS IS"
282be45b66SKalle Valo  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
292be45b66SKalle Valo  * the License for the specific language governing rights and
302be45b66SKalle Valo  * limitations under the License.
312be45b66SKalle Valo  *
322be45b66SKalle Valo  * The initial developer of the original code is David A. Hinds
332be45b66SKalle Valo  * <dahinds AT users.sourceforge.net>.  Portions created by David
342be45b66SKalle Valo  * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights
352be45b66SKalle Valo  * Reserved.
362be45b66SKalle Valo  *
372be45b66SKalle Valo  * Alternatively, the contents of this file may be used under the
382be45b66SKalle Valo  * terms of the GNU General Public License version 2 (the "GPL"), in
392be45b66SKalle Valo  * which case the provisions of the GPL are applicable instead of the
402be45b66SKalle Valo  * above.  If you wish to allow the use of your version of this file
412be45b66SKalle Valo  * only under the terms of the GPL and not to allow others to use your
422be45b66SKalle Valo  * version of this file under the MPL, indicate your decision by
432be45b66SKalle Valo  * deleting the provisions above and replace them with the notice and
442be45b66SKalle Valo  * other provisions required by the GPL.  If you do not delete the
452be45b66SKalle Valo  * provisions above, a recipient may use your version of this file
462be45b66SKalle Valo  * under either the MPL or the GPL.  */
472be45b66SKalle Valo 
482be45b66SKalle Valo /*
492be45b66SKalle Valo  * TODO
502be45b66SKalle Valo  *	o Handle de-encapsulation within network layer, provide 802.11
512be45b66SKalle Valo  *	  headers (patch from Thomas 'Dent' Mirlacher)
522be45b66SKalle Valo  *	o Fix possible races in SPY handling.
532be45b66SKalle Valo  *	o Disconnect wireless extensions from fundamental configuration.
542be45b66SKalle Valo  *	o (maybe) Software WEP support (patch from Stano Meduna).
552be45b66SKalle Valo  *	o (maybe) Use multiple Tx buffers - driver handling queue
562be45b66SKalle Valo  *	  rather than firmware.
572be45b66SKalle Valo  */
582be45b66SKalle Valo 
592be45b66SKalle Valo /* Locking and synchronization:
602be45b66SKalle Valo  *
612be45b66SKalle Valo  * The basic principle is that everything is serialized through a
622be45b66SKalle Valo  * single spinlock, priv->lock.  The lock is used in user, bh and irq
632be45b66SKalle Valo  * context, so when taken outside hardirq context it should always be
642be45b66SKalle Valo  * taken with interrupts disabled.  The lock protects both the
652be45b66SKalle Valo  * hardware and the struct orinoco_private.
662be45b66SKalle Valo  *
672be45b66SKalle Valo  * Another flag, priv->hw_unavailable indicates that the hardware is
682be45b66SKalle Valo  * unavailable for an extended period of time (e.g. suspended, or in
692be45b66SKalle Valo  * the middle of a hard reset).  This flag is protected by the
702be45b66SKalle Valo  * spinlock.  All code which touches the hardware should check the
712be45b66SKalle Valo  * flag after taking the lock, and if it is set, give up on whatever
722be45b66SKalle Valo  * they are doing and drop the lock again.  The orinoco_lock()
732be45b66SKalle Valo  * function handles this (it unlocks and returns -EBUSY if
742be45b66SKalle Valo  * hw_unavailable is non-zero).
752be45b66SKalle Valo  */
762be45b66SKalle Valo 
772be45b66SKalle Valo #define DRIVER_NAME "orinoco"
782be45b66SKalle Valo 
792be45b66SKalle Valo #include <linux/module.h>
802be45b66SKalle Valo #include <linux/kernel.h>
812be45b66SKalle Valo #include <linux/slab.h>
822be45b66SKalle Valo #include <linux/init.h>
832be45b66SKalle Valo #include <linux/delay.h>
842be45b66SKalle Valo #include <linux/device.h>
852be45b66SKalle Valo #include <linux/netdevice.h>
862be45b66SKalle Valo #include <linux/etherdevice.h>
872be45b66SKalle Valo #include <linux/suspend.h>
882be45b66SKalle Valo #include <linux/if_arp.h>
892be45b66SKalle Valo #include <linux/wireless.h>
902be45b66SKalle Valo #include <linux/ieee80211.h>
912be45b66SKalle Valo #include <net/iw_handler.h>
922be45b66SKalle Valo #include <net/cfg80211.h>
932be45b66SKalle Valo 
942be45b66SKalle Valo #include "hermes_rid.h"
952be45b66SKalle Valo #include "hermes_dld.h"
962be45b66SKalle Valo #include "hw.h"
972be45b66SKalle Valo #include "scan.h"
982be45b66SKalle Valo #include "mic.h"
992be45b66SKalle Valo #include "fw.h"
1002be45b66SKalle Valo #include "wext.h"
1012be45b66SKalle Valo #include "cfg.h"
1022be45b66SKalle Valo #include "main.h"
1032be45b66SKalle Valo 
1042be45b66SKalle Valo #include "orinoco.h"
1052be45b66SKalle Valo 
1062be45b66SKalle Valo /********************************************************************/
1072be45b66SKalle Valo /* Module information                                               */
1082be45b66SKalle Valo /********************************************************************/
1092be45b66SKalle Valo 
1102be45b66SKalle Valo MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & "
1112be45b66SKalle Valo 	      "David Gibson <hermes@gibson.dropbear.id.au>");
1122be45b66SKalle Valo MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based "
1132be45b66SKalle Valo 		   "and similar wireless cards");
1142be45b66SKalle Valo MODULE_LICENSE("Dual MPL/GPL");
1152be45b66SKalle Valo 
1162be45b66SKalle Valo /* Level of debugging. Used in the macros in orinoco.h */
1172be45b66SKalle Valo #ifdef ORINOCO_DEBUG
1182be45b66SKalle Valo int orinoco_debug = ORINOCO_DEBUG;
1192be45b66SKalle Valo EXPORT_SYMBOL(orinoco_debug);
1202be45b66SKalle Valo module_param(orinoco_debug, int, 0644);
1212be45b66SKalle Valo MODULE_PARM_DESC(orinoco_debug, "Debug level");
1222be45b66SKalle Valo #endif
1232be45b66SKalle Valo 
1242be45b66SKalle Valo static bool suppress_linkstatus; /* = 0 */
1252be45b66SKalle Valo module_param(suppress_linkstatus, bool, 0644);
1262be45b66SKalle Valo MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
1272be45b66SKalle Valo 
1282be45b66SKalle Valo static int ignore_disconnect; /* = 0 */
1292be45b66SKalle Valo module_param(ignore_disconnect, int, 0644);
1302be45b66SKalle Valo MODULE_PARM_DESC(ignore_disconnect,
1312be45b66SKalle Valo 		 "Don't report lost link to the network layer");
1322be45b66SKalle Valo 
1332be45b66SKalle Valo int force_monitor; /* = 0 */
1342be45b66SKalle Valo module_param(force_monitor, int, 0644);
1352be45b66SKalle Valo MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
1362be45b66SKalle Valo 
1372be45b66SKalle Valo /********************************************************************/
1382be45b66SKalle Valo /* Internal constants                                               */
1392be45b66SKalle Valo /********************************************************************/
1402be45b66SKalle Valo 
1412be45b66SKalle Valo /* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
1422be45b66SKalle Valo static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
1432be45b66SKalle Valo #define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
1442be45b66SKalle Valo 
1452be45b66SKalle Valo #define ORINOCO_MIN_MTU		256
1462be45b66SKalle Valo #define ORINOCO_MAX_MTU		(IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
1472be45b66SKalle Valo 
1482be45b66SKalle Valo #define MAX_IRQLOOPS_PER_IRQ	10
1492be45b66SKalle Valo #define MAX_IRQLOOPS_PER_JIFFY	(20000 / HZ)	/* Based on a guestimate of
1502be45b66SKalle Valo 						 * how many events the
1512be45b66SKalle Valo 						 * device could
1522be45b66SKalle Valo 						 * legitimately generate */
1532be45b66SKalle Valo 
1542be45b66SKalle Valo #define DUMMY_FID		0xFFFF
1552be45b66SKalle Valo 
1562be45b66SKalle Valo /*#define MAX_MULTICAST(priv)	(priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
1572be45b66SKalle Valo   HERMES_MAX_MULTICAST : 0)*/
1582be45b66SKalle Valo #define MAX_MULTICAST(priv)	(HERMES_MAX_MULTICAST)
1592be45b66SKalle Valo 
1602be45b66SKalle Valo #define ORINOCO_INTEN		(HERMES_EV_RX | HERMES_EV_ALLOC \
1612be45b66SKalle Valo 				 | HERMES_EV_TX | HERMES_EV_TXEXC \
1622be45b66SKalle Valo 				 | HERMES_EV_WTERR | HERMES_EV_INFO \
1632be45b66SKalle Valo 				 | HERMES_EV_INFDROP)
1642be45b66SKalle Valo 
1652be45b66SKalle Valo /********************************************************************/
1662be45b66SKalle Valo /* Data types                                                       */
1672be45b66SKalle Valo /********************************************************************/
1682be45b66SKalle Valo 
1692be45b66SKalle Valo /* Beginning of the Tx descriptor, used in TxExc handling */
1702be45b66SKalle Valo struct hermes_txexc_data {
1712be45b66SKalle Valo 	struct hermes_tx_descriptor desc;
1722be45b66SKalle Valo 	__le16 frame_ctl;
1732be45b66SKalle Valo 	__le16 duration_id;
1742be45b66SKalle Valo 	u8 addr1[ETH_ALEN];
1752be45b66SKalle Valo } __packed;
1762be45b66SKalle Valo 
1772be45b66SKalle Valo /* Rx frame header except compatibility 802.3 header */
1782be45b66SKalle Valo struct hermes_rx_descriptor {
1792be45b66SKalle Valo 	/* Control */
1802be45b66SKalle Valo 	__le16 status;
1812be45b66SKalle Valo 	__le32 time;
1822be45b66SKalle Valo 	u8 silence;
1832be45b66SKalle Valo 	u8 signal;
1842be45b66SKalle Valo 	u8 rate;
1852be45b66SKalle Valo 	u8 rxflow;
1862be45b66SKalle Valo 	__le32 reserved;
1872be45b66SKalle Valo 
1882be45b66SKalle Valo 	/* 802.11 header */
1892be45b66SKalle Valo 	__le16 frame_ctl;
1902be45b66SKalle Valo 	__le16 duration_id;
1912be45b66SKalle Valo 	u8 addr1[ETH_ALEN];
1922be45b66SKalle Valo 	u8 addr2[ETH_ALEN];
1932be45b66SKalle Valo 	u8 addr3[ETH_ALEN];
1942be45b66SKalle Valo 	__le16 seq_ctl;
1952be45b66SKalle Valo 	u8 addr4[ETH_ALEN];
1962be45b66SKalle Valo 
1972be45b66SKalle Valo 	/* Data length */
1982be45b66SKalle Valo 	__le16 data_len;
1992be45b66SKalle Valo } __packed;
2002be45b66SKalle Valo 
2012be45b66SKalle Valo struct orinoco_rx_data {
2022be45b66SKalle Valo 	struct hermes_rx_descriptor *desc;
2032be45b66SKalle Valo 	struct sk_buff *skb;
2042be45b66SKalle Valo 	struct list_head list;
2052be45b66SKalle Valo };
2062be45b66SKalle Valo 
2072be45b66SKalle Valo struct orinoco_scan_data {
2082be45b66SKalle Valo 	void *buf;
2092be45b66SKalle Valo 	size_t len;
2102be45b66SKalle Valo 	int type;
2112be45b66SKalle Valo 	struct list_head list;
2122be45b66SKalle Valo };
2132be45b66SKalle Valo 
2142be45b66SKalle Valo /********************************************************************/
2152be45b66SKalle Valo /* Function prototypes                                              */
2162be45b66SKalle Valo /********************************************************************/
2172be45b66SKalle Valo 
2182be45b66SKalle Valo static int __orinoco_set_multicast_list(struct net_device *dev);
2192be45b66SKalle Valo static int __orinoco_up(struct orinoco_private *priv);
2202be45b66SKalle Valo static int __orinoco_down(struct orinoco_private *priv);
2212be45b66SKalle Valo static int __orinoco_commit(struct orinoco_private *priv);
2222be45b66SKalle Valo 
2232be45b66SKalle Valo /********************************************************************/
2242be45b66SKalle Valo /* Internal helper functions                                        */
2252be45b66SKalle Valo /********************************************************************/
2262be45b66SKalle Valo 
set_port_type(struct orinoco_private * priv)2272be45b66SKalle Valo void set_port_type(struct orinoco_private *priv)
2282be45b66SKalle Valo {
2292be45b66SKalle Valo 	switch (priv->iw_mode) {
2302be45b66SKalle Valo 	case NL80211_IFTYPE_STATION:
2312be45b66SKalle Valo 		priv->port_type = 1;
2322be45b66SKalle Valo 		priv->createibss = 0;
2332be45b66SKalle Valo 		break;
2342be45b66SKalle Valo 	case NL80211_IFTYPE_ADHOC:
2352be45b66SKalle Valo 		if (priv->prefer_port3) {
2362be45b66SKalle Valo 			priv->port_type = 3;
2372be45b66SKalle Valo 			priv->createibss = 0;
2382be45b66SKalle Valo 		} else {
2392be45b66SKalle Valo 			priv->port_type = priv->ibss_port;
2402be45b66SKalle Valo 			priv->createibss = 1;
2412be45b66SKalle Valo 		}
2422be45b66SKalle Valo 		break;
2432be45b66SKalle Valo 	case NL80211_IFTYPE_MONITOR:
2442be45b66SKalle Valo 		priv->port_type = 3;
2452be45b66SKalle Valo 		priv->createibss = 0;
2462be45b66SKalle Valo 		break;
2472be45b66SKalle Valo 	default:
2482be45b66SKalle Valo 		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
2492be45b66SKalle Valo 		       priv->ndev->name);
2502be45b66SKalle Valo 	}
2512be45b66SKalle Valo }
2522be45b66SKalle Valo 
2532be45b66SKalle Valo /********************************************************************/
2542be45b66SKalle Valo /* Device methods                                                   */
2552be45b66SKalle Valo /********************************************************************/
2562be45b66SKalle Valo 
orinoco_open(struct net_device * dev)2572be45b66SKalle Valo int orinoco_open(struct net_device *dev)
2582be45b66SKalle Valo {
2592be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
2602be45b66SKalle Valo 	unsigned long flags;
2612be45b66SKalle Valo 	int err;
2622be45b66SKalle Valo 
2632be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
2642be45b66SKalle Valo 		return -EBUSY;
2652be45b66SKalle Valo 
2662be45b66SKalle Valo 	err = __orinoco_up(priv);
2672be45b66SKalle Valo 
2682be45b66SKalle Valo 	if (!err)
2692be45b66SKalle Valo 		priv->open = 1;
2702be45b66SKalle Valo 
2712be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
2722be45b66SKalle Valo 
2732be45b66SKalle Valo 	return err;
2742be45b66SKalle Valo }
2752be45b66SKalle Valo EXPORT_SYMBOL(orinoco_open);
2762be45b66SKalle Valo 
orinoco_stop(struct net_device * dev)2772be45b66SKalle Valo int orinoco_stop(struct net_device *dev)
2782be45b66SKalle Valo {
2792be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
2802be45b66SKalle Valo 	int err = 0;
2812be45b66SKalle Valo 
2822be45b66SKalle Valo 	/* We mustn't use orinoco_lock() here, because we need to be
2832be45b66SKalle Valo 	   able to close the interface even if hw_unavailable is set
2842be45b66SKalle Valo 	   (e.g. as we're released after a PC Card removal) */
2852be45b66SKalle Valo 	orinoco_lock_irq(priv);
2862be45b66SKalle Valo 
2872be45b66SKalle Valo 	priv->open = 0;
2882be45b66SKalle Valo 
2892be45b66SKalle Valo 	err = __orinoco_down(priv);
2902be45b66SKalle Valo 
2912be45b66SKalle Valo 	orinoco_unlock_irq(priv);
2922be45b66SKalle Valo 
2932be45b66SKalle Valo 	return err;
2942be45b66SKalle Valo }
2952be45b66SKalle Valo EXPORT_SYMBOL(orinoco_stop);
2962be45b66SKalle Valo 
orinoco_set_multicast_list(struct net_device * dev)2972be45b66SKalle Valo void orinoco_set_multicast_list(struct net_device *dev)
2982be45b66SKalle Valo {
2992be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
3002be45b66SKalle Valo 	unsigned long flags;
3012be45b66SKalle Valo 
3022be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0) {
3032be45b66SKalle Valo 		printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
3042be45b66SKalle Valo 		       "called when hw_unavailable\n", dev->name);
3052be45b66SKalle Valo 		return;
3062be45b66SKalle Valo 	}
3072be45b66SKalle Valo 
3082be45b66SKalle Valo 	__orinoco_set_multicast_list(dev);
3092be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
3102be45b66SKalle Valo }
3112be45b66SKalle Valo EXPORT_SYMBOL(orinoco_set_multicast_list);
3122be45b66SKalle Valo 
orinoco_change_mtu(struct net_device * dev,int new_mtu)3132be45b66SKalle Valo int orinoco_change_mtu(struct net_device *dev, int new_mtu)
3142be45b66SKalle Valo {
3152be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
3162be45b66SKalle Valo 
3172be45b66SKalle Valo 	/* MTU + encapsulation + header length */
3182be45b66SKalle Valo 	if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
3192be45b66SKalle Valo 	     (priv->nicbuf_size - ETH_HLEN))
3202be45b66SKalle Valo 		return -EINVAL;
3212be45b66SKalle Valo 
3222be45b66SKalle Valo 	dev->mtu = new_mtu;
3232be45b66SKalle Valo 
3242be45b66SKalle Valo 	return 0;
3252be45b66SKalle Valo }
3262be45b66SKalle Valo EXPORT_SYMBOL(orinoco_change_mtu);
3272be45b66SKalle Valo 
3282be45b66SKalle Valo /********************************************************************/
3292be45b66SKalle Valo /* Tx path                                                          */
3302be45b66SKalle Valo /********************************************************************/
3312be45b66SKalle Valo 
3322be45b66SKalle Valo /* Add encapsulation and MIC to the existing SKB.
3332be45b66SKalle Valo  * The main xmit routine will then send the whole lot to the card.
3342be45b66SKalle Valo  * Need 8 bytes headroom
3352be45b66SKalle Valo  * Need 8 bytes tailroom
3362be45b66SKalle Valo  *
3372be45b66SKalle Valo  *                          With encapsulated ethernet II frame
3382be45b66SKalle Valo  *                          --------
3392be45b66SKalle Valo  *                          803.3 header (14 bytes)
3402be45b66SKalle Valo  *                           dst[6]
3412be45b66SKalle Valo  * --------                  src[6]
3422be45b66SKalle Valo  * 803.3 header (14 bytes)   len[2]
3432be45b66SKalle Valo  *  dst[6]                  803.2 header (8 bytes)
3442be45b66SKalle Valo  *  src[6]                   encaps[6]
3452be45b66SKalle Valo  *  len[2] <- leave alone -> len[2]
3462be45b66SKalle Valo  * --------                 -------- <-- 0
3472be45b66SKalle Valo  * Payload                  Payload
3482be45b66SKalle Valo  * ...                      ...
3492be45b66SKalle Valo  *
3502be45b66SKalle Valo  * --------                 --------
3512be45b66SKalle Valo  *                          MIC (8 bytes)
3522be45b66SKalle Valo  *                          --------
3532be45b66SKalle Valo  *
3542be45b66SKalle Valo  * returns 0 on success, -ENOMEM on error.
3552be45b66SKalle Valo  */
orinoco_process_xmit_skb(struct sk_buff * skb,struct net_device * dev,struct orinoco_private * priv,int * tx_control,u8 * mic_buf)3562be45b66SKalle Valo int orinoco_process_xmit_skb(struct sk_buff *skb,
3572be45b66SKalle Valo 			     struct net_device *dev,
3582be45b66SKalle Valo 			     struct orinoco_private *priv,
3592be45b66SKalle Valo 			     int *tx_control,
3602be45b66SKalle Valo 			     u8 *mic_buf)
3612be45b66SKalle Valo {
3622be45b66SKalle Valo 	struct orinoco_tkip_key *key;
3632be45b66SKalle Valo 	struct ethhdr *eh;
3642be45b66SKalle Valo 	int do_mic;
3652be45b66SKalle Valo 
3662be45b66SKalle Valo 	key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
3672be45b66SKalle Valo 
3682be45b66SKalle Valo 	do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
3692be45b66SKalle Valo 		  (key != NULL));
3702be45b66SKalle Valo 
3712be45b66SKalle Valo 	if (do_mic)
3722be45b66SKalle Valo 		*tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
3732be45b66SKalle Valo 			HERMES_TXCTRL_MIC;
3742be45b66SKalle Valo 
3752be45b66SKalle Valo 	eh = (struct ethhdr *)skb->data;
3762be45b66SKalle Valo 
3772be45b66SKalle Valo 	/* Encapsulate Ethernet-II frames */
3782be45b66SKalle Valo 	if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
3792be45b66SKalle Valo 		struct header_struct {
3802be45b66SKalle Valo 			struct ethhdr eth;	/* 802.3 header */
3812be45b66SKalle Valo 			u8 encap[6];		/* 802.2 header */
3822be45b66SKalle Valo 		} __packed hdr;
3832be45b66SKalle Valo 		int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
3842be45b66SKalle Valo 
3852be45b66SKalle Valo 		if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
3862be45b66SKalle Valo 			if (net_ratelimit())
3872be45b66SKalle Valo 				printk(KERN_ERR
3882be45b66SKalle Valo 				       "%s: Not enough headroom for 802.2 headers %d\n",
3892be45b66SKalle Valo 				       dev->name, skb_headroom(skb));
3902be45b66SKalle Valo 			return -ENOMEM;
3912be45b66SKalle Valo 		}
3922be45b66SKalle Valo 
3932be45b66SKalle Valo 		/* Fill in new header */
3942be45b66SKalle Valo 		memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
3952be45b66SKalle Valo 		hdr.eth.h_proto = htons(len);
3962be45b66SKalle Valo 		memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
3972be45b66SKalle Valo 
3982be45b66SKalle Valo 		/* Make room for the new header, and copy it in */
399d58ff351SJohannes Berg 		eh = skb_push(skb, ENCAPS_OVERHEAD);
4002be45b66SKalle Valo 		memcpy(eh, &hdr, sizeof(hdr));
4012be45b66SKalle Valo 	}
4022be45b66SKalle Valo 
4032be45b66SKalle Valo 	/* Calculate Michael MIC */
4042be45b66SKalle Valo 	if (do_mic) {
4052be45b66SKalle Valo 		size_t len = skb->len - ETH_HLEN;
4062be45b66SKalle Valo 		u8 *mic = &mic_buf[0];
4072be45b66SKalle Valo 
4082be45b66SKalle Valo 		/* Have to write to an even address, so copy the spare
4092be45b66SKalle Valo 		 * byte across */
4102be45b66SKalle Valo 		if (skb->len % 2) {
4112be45b66SKalle Valo 			*mic = skb->data[skb->len - 1];
4122be45b66SKalle Valo 			mic++;
4132be45b66SKalle Valo 		}
4142be45b66SKalle Valo 
4152be45b66SKalle Valo 		orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
4162be45b66SKalle Valo 			    eh->h_dest, eh->h_source, 0 /* priority */,
4172be45b66SKalle Valo 			    skb->data + ETH_HLEN,
4182be45b66SKalle Valo 			    len, mic);
4192be45b66SKalle Valo 	}
4202be45b66SKalle Valo 
4212be45b66SKalle Valo 	return 0;
4222be45b66SKalle Valo }
4232be45b66SKalle Valo EXPORT_SYMBOL(orinoco_process_xmit_skb);
4242be45b66SKalle Valo 
orinoco_xmit(struct sk_buff * skb,struct net_device * dev)4252be45b66SKalle Valo static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
4262be45b66SKalle Valo {
4272be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
4283a628204STobias Klauser 	struct net_device_stats *stats = &dev->stats;
4292be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
4302be45b66SKalle Valo 	int err = 0;
4312be45b66SKalle Valo 	u16 txfid = priv->txfid;
4322be45b66SKalle Valo 	int tx_control;
4332be45b66SKalle Valo 	unsigned long flags;
4342be45b66SKalle Valo 	u8 mic_buf[MICHAEL_MIC_LEN + 1];
4352be45b66SKalle Valo 
4362be45b66SKalle Valo 	if (!netif_running(dev)) {
4372be45b66SKalle Valo 		printk(KERN_ERR "%s: Tx on stopped device!\n",
4382be45b66SKalle Valo 		       dev->name);
4392be45b66SKalle Valo 		return NETDEV_TX_BUSY;
4402be45b66SKalle Valo 	}
4412be45b66SKalle Valo 
4422be45b66SKalle Valo 	if (netif_queue_stopped(dev)) {
4432be45b66SKalle Valo 		printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
4442be45b66SKalle Valo 		       dev->name);
4452be45b66SKalle Valo 		return NETDEV_TX_BUSY;
4462be45b66SKalle Valo 	}
4472be45b66SKalle Valo 
4482be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0) {
4492be45b66SKalle Valo 		printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
4502be45b66SKalle Valo 		       dev->name);
4512be45b66SKalle Valo 		return NETDEV_TX_BUSY;
4522be45b66SKalle Valo 	}
4532be45b66SKalle Valo 
4542be45b66SKalle Valo 	if (!netif_carrier_ok(dev) ||
4552be45b66SKalle Valo 	    (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
4562be45b66SKalle Valo 		/* Oops, the firmware hasn't established a connection,
4572be45b66SKalle Valo 		   silently drop the packet (this seems to be the
4582be45b66SKalle Valo 		   safest approach). */
4592be45b66SKalle Valo 		goto drop;
4602be45b66SKalle Valo 	}
4612be45b66SKalle Valo 
4622be45b66SKalle Valo 	/* Check packet length */
4632be45b66SKalle Valo 	if (skb->len < ETH_HLEN)
4642be45b66SKalle Valo 		goto drop;
4652be45b66SKalle Valo 
4662be45b66SKalle Valo 	tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
4672be45b66SKalle Valo 
4682be45b66SKalle Valo 	err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
4692be45b66SKalle Valo 				       &mic_buf[0]);
4702be45b66SKalle Valo 	if (err)
4712be45b66SKalle Valo 		goto drop;
4722be45b66SKalle Valo 
4732be45b66SKalle Valo 	if (priv->has_alt_txcntl) {
4742be45b66SKalle Valo 		/* WPA enabled firmwares have tx_cntl at the end of
4752be45b66SKalle Valo 		 * the 802.11 header.  So write zeroed descriptor and
4762be45b66SKalle Valo 		 * 802.11 header at the same time
4772be45b66SKalle Valo 		 */
4782be45b66SKalle Valo 		char desc[HERMES_802_3_OFFSET];
4792be45b66SKalle Valo 		__le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
4802be45b66SKalle Valo 
4812be45b66SKalle Valo 		memset(&desc, 0, sizeof(desc));
4822be45b66SKalle Valo 
4832be45b66SKalle Valo 		*txcntl = cpu_to_le16(tx_control);
4842be45b66SKalle Valo 		err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
4852be45b66SKalle Valo 					  txfid, 0);
4862be45b66SKalle Valo 		if (err) {
4872be45b66SKalle Valo 			if (net_ratelimit())
4882be45b66SKalle Valo 				printk(KERN_ERR "%s: Error %d writing Tx "
4892be45b66SKalle Valo 				       "descriptor to BAP\n", dev->name, err);
4902be45b66SKalle Valo 			goto busy;
4912be45b66SKalle Valo 		}
4922be45b66SKalle Valo 	} else {
4932be45b66SKalle Valo 		struct hermes_tx_descriptor desc;
4942be45b66SKalle Valo 
4952be45b66SKalle Valo 		memset(&desc, 0, sizeof(desc));
4962be45b66SKalle Valo 
4972be45b66SKalle Valo 		desc.tx_control = cpu_to_le16(tx_control);
4982be45b66SKalle Valo 		err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
4992be45b66SKalle Valo 					  txfid, 0);
5002be45b66SKalle Valo 		if (err) {
5012be45b66SKalle Valo 			if (net_ratelimit())
5022be45b66SKalle Valo 				printk(KERN_ERR "%s: Error %d writing Tx "
5032be45b66SKalle Valo 				       "descriptor to BAP\n", dev->name, err);
5042be45b66SKalle Valo 			goto busy;
5052be45b66SKalle Valo 		}
5062be45b66SKalle Valo 
5072be45b66SKalle Valo 		/* Clear the 802.11 header and data length fields - some
5082be45b66SKalle Valo 		 * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
5092be45b66SKalle Valo 		 * if this isn't done. */
5102be45b66SKalle Valo 		hermes_clear_words(hw, HERMES_DATA0,
5112be45b66SKalle Valo 				   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
5122be45b66SKalle Valo 	}
5132be45b66SKalle Valo 
5142be45b66SKalle Valo 	err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
5152be45b66SKalle Valo 				  txfid, HERMES_802_3_OFFSET);
5162be45b66SKalle Valo 	if (err) {
5172be45b66SKalle Valo 		printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
5182be45b66SKalle Valo 		       dev->name, err);
5192be45b66SKalle Valo 		goto busy;
5202be45b66SKalle Valo 	}
5212be45b66SKalle Valo 
5222be45b66SKalle Valo 	if (tx_control & HERMES_TXCTRL_MIC) {
5232be45b66SKalle Valo 		size_t offset = HERMES_802_3_OFFSET + skb->len;
5242be45b66SKalle Valo 		size_t len = MICHAEL_MIC_LEN;
5252be45b66SKalle Valo 
5262be45b66SKalle Valo 		if (offset % 2) {
5272be45b66SKalle Valo 			offset--;
5282be45b66SKalle Valo 			len++;
5292be45b66SKalle Valo 		}
5302be45b66SKalle Valo 		err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
5312be45b66SKalle Valo 					  txfid, offset);
5322be45b66SKalle Valo 		if (err) {
5332be45b66SKalle Valo 			printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
5342be45b66SKalle Valo 			       dev->name, err);
5352be45b66SKalle Valo 			goto busy;
5362be45b66SKalle Valo 		}
5372be45b66SKalle Valo 	}
5382be45b66SKalle Valo 
5392be45b66SKalle Valo 	/* Finally, we actually initiate the send */
5402be45b66SKalle Valo 	netif_stop_queue(dev);
5412be45b66SKalle Valo 
5422be45b66SKalle Valo 	err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
5432be45b66SKalle Valo 				txfid, NULL);
5442be45b66SKalle Valo 	if (err) {
5452be45b66SKalle Valo 		netif_start_queue(dev);
5462be45b66SKalle Valo 		if (net_ratelimit())
5472be45b66SKalle Valo 			printk(KERN_ERR "%s: Error %d transmitting packet\n",
5482be45b66SKalle Valo 				dev->name, err);
5492be45b66SKalle Valo 		goto busy;
5502be45b66SKalle Valo 	}
5512be45b66SKalle Valo 
5522be45b66SKalle Valo 	stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
5532be45b66SKalle Valo 	goto ok;
5542be45b66SKalle Valo 
5552be45b66SKalle Valo  drop:
5562be45b66SKalle Valo 	stats->tx_errors++;
5572be45b66SKalle Valo 	stats->tx_dropped++;
5582be45b66SKalle Valo 
5592be45b66SKalle Valo  ok:
5602be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
5612be45b66SKalle Valo 	dev_kfree_skb(skb);
5622be45b66SKalle Valo 	return NETDEV_TX_OK;
5632be45b66SKalle Valo 
5642be45b66SKalle Valo  busy:
5652be45b66SKalle Valo 	if (err == -EIO)
5662be45b66SKalle Valo 		schedule_work(&priv->reset_work);
5672be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
5682be45b66SKalle Valo 	return NETDEV_TX_BUSY;
5692be45b66SKalle Valo }
5702be45b66SKalle Valo 
__orinoco_ev_alloc(struct net_device * dev,struct hermes * hw)5712be45b66SKalle Valo static void __orinoco_ev_alloc(struct net_device *dev, struct hermes *hw)
5722be45b66SKalle Valo {
5732be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
5742be45b66SKalle Valo 	u16 fid = hermes_read_regn(hw, ALLOCFID);
5752be45b66SKalle Valo 
5762be45b66SKalle Valo 	if (fid != priv->txfid) {
5772be45b66SKalle Valo 		if (fid != DUMMY_FID)
5782be45b66SKalle Valo 			printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
5792be45b66SKalle Valo 			       dev->name, fid);
5802be45b66SKalle Valo 		return;
5812be45b66SKalle Valo 	}
5822be45b66SKalle Valo 
5832be45b66SKalle Valo 	hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
5842be45b66SKalle Valo }
5852be45b66SKalle Valo 
__orinoco_ev_tx(struct net_device * dev,struct hermes * hw)5862be45b66SKalle Valo static void __orinoco_ev_tx(struct net_device *dev, struct hermes *hw)
5872be45b66SKalle Valo {
5883a628204STobias Klauser 	dev->stats.tx_packets++;
5892be45b66SKalle Valo 
5902be45b66SKalle Valo 	netif_wake_queue(dev);
5912be45b66SKalle Valo 
5922be45b66SKalle Valo 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
5932be45b66SKalle Valo }
5942be45b66SKalle Valo 
__orinoco_ev_txexc(struct net_device * dev,struct hermes * hw)5952be45b66SKalle Valo static void __orinoco_ev_txexc(struct net_device *dev, struct hermes *hw)
5962be45b66SKalle Valo {
5973a628204STobias Klauser 	struct net_device_stats *stats = &dev->stats;
5982be45b66SKalle Valo 	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
5992be45b66SKalle Valo 	u16 status;
6002be45b66SKalle Valo 	struct hermes_txexc_data hdr;
6012be45b66SKalle Valo 	int err = 0;
6022be45b66SKalle Valo 
6032be45b66SKalle Valo 	if (fid == DUMMY_FID)
6042be45b66SKalle Valo 		return; /* Nothing's really happened */
6052be45b66SKalle Valo 
6062be45b66SKalle Valo 	/* Read part of the frame header - we need status and addr1 */
6072be45b66SKalle Valo 	err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
6082be45b66SKalle Valo 				 sizeof(struct hermes_txexc_data),
6092be45b66SKalle Valo 				 fid, 0);
6102be45b66SKalle Valo 
6112be45b66SKalle Valo 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
6122be45b66SKalle Valo 	stats->tx_errors++;
6132be45b66SKalle Valo 
6142be45b66SKalle Valo 	if (err) {
6152be45b66SKalle Valo 		printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
6162be45b66SKalle Valo 		       "(FID=%04X error %d)\n",
6172be45b66SKalle Valo 		       dev->name, fid, err);
6182be45b66SKalle Valo 		return;
6192be45b66SKalle Valo 	}
6202be45b66SKalle Valo 
6212be45b66SKalle Valo 	DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
6222be45b66SKalle Valo 	      err, fid);
6232be45b66SKalle Valo 
6242be45b66SKalle Valo 	/* We produce a TXDROP event only for retry or lifetime
6252be45b66SKalle Valo 	 * exceeded, because that's the only status that really mean
6262be45b66SKalle Valo 	 * that this particular node went away.
6272be45b66SKalle Valo 	 * Other errors means that *we* screwed up. - Jean II */
6282be45b66SKalle Valo 	status = le16_to_cpu(hdr.desc.status);
6292be45b66SKalle Valo 	if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
6302be45b66SKalle Valo 		union iwreq_data	wrqu;
6312be45b66SKalle Valo 
6322be45b66SKalle Valo 		/* Copy 802.11 dest address.
6332be45b66SKalle Valo 		 * We use the 802.11 header because the frame may
6342be45b66SKalle Valo 		 * not be 802.3 or may be mangled...
6352be45b66SKalle Valo 		 * In Ad-Hoc mode, it will be the node address.
6362be45b66SKalle Valo 		 * In managed mode, it will be most likely the AP addr
6372be45b66SKalle Valo 		 * User space will figure out how to convert it to
6382be45b66SKalle Valo 		 * whatever it needs (IP address or else).
6392be45b66SKalle Valo 		 * - Jean II */
6402be45b66SKalle Valo 		memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
6412be45b66SKalle Valo 		wrqu.addr.sa_family = ARPHRD_ETHER;
6422be45b66SKalle Valo 
6432be45b66SKalle Valo 		/* Send event to user space */
6442be45b66SKalle Valo 		wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
6452be45b66SKalle Valo 	}
6462be45b66SKalle Valo 
6472be45b66SKalle Valo 	netif_wake_queue(dev);
6482be45b66SKalle Valo }
6492be45b66SKalle Valo 
orinoco_tx_timeout(struct net_device * dev,unsigned int txqueue)6500290bd29SMichael S. Tsirkin void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue)
6512be45b66SKalle Valo {
6522be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
6533a628204STobias Klauser 	struct net_device_stats *stats = &dev->stats;
6542be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
6552be45b66SKalle Valo 
6562be45b66SKalle Valo 	printk(KERN_WARNING "%s: Tx timeout! "
6572be45b66SKalle Valo 	       "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
6582be45b66SKalle Valo 	       dev->name, hermes_read_regn(hw, ALLOCFID),
6592be45b66SKalle Valo 	       hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
6602be45b66SKalle Valo 
6612be45b66SKalle Valo 	stats->tx_errors++;
6622be45b66SKalle Valo 
6632be45b66SKalle Valo 	schedule_work(&priv->reset_work);
6642be45b66SKalle Valo }
6652be45b66SKalle Valo EXPORT_SYMBOL(orinoco_tx_timeout);
6662be45b66SKalle Valo 
6672be45b66SKalle Valo /********************************************************************/
6682be45b66SKalle Valo /* Rx path (data frames)                                            */
6692be45b66SKalle Valo /********************************************************************/
6702be45b66SKalle Valo 
6712be45b66SKalle Valo /* Does the frame have a SNAP header indicating it should be
6722be45b66SKalle Valo  * de-encapsulated to Ethernet-II? */
is_ethersnap(void * _hdr)6732be45b66SKalle Valo static inline int is_ethersnap(void *_hdr)
6742be45b66SKalle Valo {
6752be45b66SKalle Valo 	u8 *hdr = _hdr;
6762be45b66SKalle Valo 
6772be45b66SKalle Valo 	/* We de-encapsulate all packets which, a) have SNAP headers
6782be45b66SKalle Valo 	 * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
6792be45b66SKalle Valo 	 * and where b) the OUI of the SNAP header is 00:00:00 or
6802be45b66SKalle Valo 	 * 00:00:f8 - we need both because different APs appear to use
6812be45b66SKalle Valo 	 * different OUIs for some reason */
6822be45b66SKalle Valo 	return (memcmp(hdr, &encaps_hdr, 5) == 0)
6832be45b66SKalle Valo 		&& ((hdr[5] == 0x00) || (hdr[5] == 0xf8));
6842be45b66SKalle Valo }
6852be45b66SKalle Valo 
orinoco_spy_gather(struct net_device * dev,u_char * mac,int level,int noise)6862be45b66SKalle Valo static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
6872be45b66SKalle Valo 				      int level, int noise)
6882be45b66SKalle Valo {
6892be45b66SKalle Valo 	struct iw_quality wstats;
6902be45b66SKalle Valo 	wstats.level = level - 0x95;
6912be45b66SKalle Valo 	wstats.noise = noise - 0x95;
6922be45b66SKalle Valo 	wstats.qual = (level > noise) ? (level - noise) : 0;
6932be45b66SKalle Valo 	wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
6942be45b66SKalle Valo 	/* Update spy records */
6952be45b66SKalle Valo 	wireless_spy_update(dev, mac, &wstats);
6962be45b66SKalle Valo }
6972be45b66SKalle Valo 
orinoco_stat_gather(struct net_device * dev,struct sk_buff * skb,struct hermes_rx_descriptor * desc)6982be45b66SKalle Valo static void orinoco_stat_gather(struct net_device *dev,
6992be45b66SKalle Valo 				struct sk_buff *skb,
7002be45b66SKalle Valo 				struct hermes_rx_descriptor *desc)
7012be45b66SKalle Valo {
7022be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
7032be45b66SKalle Valo 
7042be45b66SKalle Valo 	/* Using spy support with lots of Rx packets, like in an
7052be45b66SKalle Valo 	 * infrastructure (AP), will really slow down everything, because
7062be45b66SKalle Valo 	 * the MAC address must be compared to each entry of the spy list.
7072be45b66SKalle Valo 	 * If the user really asks for it (set some address in the
7082be45b66SKalle Valo 	 * spy list), we do it, but he will pay the price.
7092be45b66SKalle Valo 	 * Note that to get here, you need both WIRELESS_SPY
7102be45b66SKalle Valo 	 * compiled in AND some addresses in the list !!!
7112be45b66SKalle Valo 	 */
7122be45b66SKalle Valo 	/* Note : gcc will optimise the whole section away if
7132be45b66SKalle Valo 	 * WIRELESS_SPY is not defined... - Jean II */
7142be45b66SKalle Valo 	if (SPY_NUMBER(priv)) {
7152be45b66SKalle Valo 		orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
7162be45b66SKalle Valo 				   desc->signal, desc->silence);
7172be45b66SKalle Valo 	}
7182be45b66SKalle Valo }
7192be45b66SKalle Valo 
7202be45b66SKalle Valo /*
7212be45b66SKalle Valo  * orinoco_rx_monitor - handle received monitor frames.
7222be45b66SKalle Valo  *
7232be45b66SKalle Valo  * Arguments:
7242be45b66SKalle Valo  *	dev		network device
7252be45b66SKalle Valo  *	rxfid		received FID
7262be45b66SKalle Valo  *	desc		rx descriptor of the frame
7272be45b66SKalle Valo  *
7282be45b66SKalle Valo  * Call context: interrupt
7292be45b66SKalle Valo  */
orinoco_rx_monitor(struct net_device * dev,u16 rxfid,struct hermes_rx_descriptor * desc)7302be45b66SKalle Valo static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
7312be45b66SKalle Valo 			       struct hermes_rx_descriptor *desc)
7322be45b66SKalle Valo {
7332be45b66SKalle Valo 	u32 hdrlen = 30;	/* return full header by default */
7342be45b66SKalle Valo 	u32 datalen = 0;
7352be45b66SKalle Valo 	u16 fc;
7362be45b66SKalle Valo 	int err;
7372be45b66SKalle Valo 	int len;
7382be45b66SKalle Valo 	struct sk_buff *skb;
7392be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
7403a628204STobias Klauser 	struct net_device_stats *stats = &dev->stats;
7412be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
7422be45b66SKalle Valo 
7432be45b66SKalle Valo 	len = le16_to_cpu(desc->data_len);
7442be45b66SKalle Valo 
7452be45b66SKalle Valo 	/* Determine the size of the header and the data */
7462be45b66SKalle Valo 	fc = le16_to_cpu(desc->frame_ctl);
7472be45b66SKalle Valo 	switch (fc & IEEE80211_FCTL_FTYPE) {
7482be45b66SKalle Valo 	case IEEE80211_FTYPE_DATA:
7492be45b66SKalle Valo 		if ((fc & IEEE80211_FCTL_TODS)
7502be45b66SKalle Valo 		    && (fc & IEEE80211_FCTL_FROMDS))
7512be45b66SKalle Valo 			hdrlen = 30;
7522be45b66SKalle Valo 		else
7532be45b66SKalle Valo 			hdrlen = 24;
7542be45b66SKalle Valo 		datalen = len;
7552be45b66SKalle Valo 		break;
7562be45b66SKalle Valo 	case IEEE80211_FTYPE_MGMT:
7572be45b66SKalle Valo 		hdrlen = 24;
7582be45b66SKalle Valo 		datalen = len;
7592be45b66SKalle Valo 		break;
7602be45b66SKalle Valo 	case IEEE80211_FTYPE_CTL:
7612be45b66SKalle Valo 		switch (fc & IEEE80211_FCTL_STYPE) {
7622be45b66SKalle Valo 		case IEEE80211_STYPE_PSPOLL:
7632be45b66SKalle Valo 		case IEEE80211_STYPE_RTS:
7642be45b66SKalle Valo 		case IEEE80211_STYPE_CFEND:
7652be45b66SKalle Valo 		case IEEE80211_STYPE_CFENDACK:
7662be45b66SKalle Valo 			hdrlen = 16;
7672be45b66SKalle Valo 			break;
7682be45b66SKalle Valo 		case IEEE80211_STYPE_CTS:
7692be45b66SKalle Valo 		case IEEE80211_STYPE_ACK:
7702be45b66SKalle Valo 			hdrlen = 10;
7712be45b66SKalle Valo 			break;
7722be45b66SKalle Valo 		}
7732be45b66SKalle Valo 		break;
7742be45b66SKalle Valo 	default:
7752be45b66SKalle Valo 		/* Unknown frame type */
7762be45b66SKalle Valo 		break;
7772be45b66SKalle Valo 	}
7782be45b66SKalle Valo 
7792be45b66SKalle Valo 	/* sanity check the length */
7802be45b66SKalle Valo 	if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
7812be45b66SKalle Valo 		printk(KERN_DEBUG "%s: oversized monitor frame, "
7822be45b66SKalle Valo 		       "data length = %d\n", dev->name, datalen);
7832be45b66SKalle Valo 		stats->rx_length_errors++;
7842be45b66SKalle Valo 		goto update_stats;
7852be45b66SKalle Valo 	}
7862be45b66SKalle Valo 
7872be45b66SKalle Valo 	skb = dev_alloc_skb(hdrlen + datalen);
7882be45b66SKalle Valo 	if (!skb) {
7892be45b66SKalle Valo 		printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
7902be45b66SKalle Valo 		       dev->name);
7912be45b66SKalle Valo 		goto update_stats;
7922be45b66SKalle Valo 	}
7932be45b66SKalle Valo 
7942be45b66SKalle Valo 	/* Copy the 802.11 header to the skb */
79559ae1d12SJohannes Berg 	skb_put_data(skb, &(desc->frame_ctl), hdrlen);
7962be45b66SKalle Valo 	skb_reset_mac_header(skb);
7972be45b66SKalle Valo 
7982be45b66SKalle Valo 	/* If any, copy the data from the card to the skb */
7992be45b66SKalle Valo 	if (datalen > 0) {
8002be45b66SKalle Valo 		err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
8012be45b66SKalle Valo 					 ALIGN(datalen, 2), rxfid,
8022be45b66SKalle Valo 					 HERMES_802_2_OFFSET);
8032be45b66SKalle Valo 		if (err) {
8042be45b66SKalle Valo 			printk(KERN_ERR "%s: error %d reading monitor frame\n",
8052be45b66SKalle Valo 			       dev->name, err);
8062be45b66SKalle Valo 			goto drop;
8072be45b66SKalle Valo 		}
8082be45b66SKalle Valo 	}
8092be45b66SKalle Valo 
8102be45b66SKalle Valo 	skb->dev = dev;
8112be45b66SKalle Valo 	skb->ip_summed = CHECKSUM_NONE;
8122be45b66SKalle Valo 	skb->pkt_type = PACKET_OTHERHOST;
8132be45b66SKalle Valo 	skb->protocol = cpu_to_be16(ETH_P_802_2);
8142be45b66SKalle Valo 
8152be45b66SKalle Valo 	stats->rx_packets++;
8162be45b66SKalle Valo 	stats->rx_bytes += skb->len;
8172be45b66SKalle Valo 
8182be45b66SKalle Valo 	netif_rx(skb);
8192be45b66SKalle Valo 	return;
8202be45b66SKalle Valo 
8212be45b66SKalle Valo  drop:
8222be45b66SKalle Valo 	dev_kfree_skb_irq(skb);
8232be45b66SKalle Valo  update_stats:
8242be45b66SKalle Valo 	stats->rx_errors++;
8252be45b66SKalle Valo 	stats->rx_dropped++;
8262be45b66SKalle Valo }
8272be45b66SKalle Valo 
__orinoco_ev_rx(struct net_device * dev,struct hermes * hw)8282be45b66SKalle Valo void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw)
8292be45b66SKalle Valo {
8302be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
8313a628204STobias Klauser 	struct net_device_stats *stats = &dev->stats;
8322be45b66SKalle Valo 	struct iw_statistics *wstats = &priv->wstats;
8332be45b66SKalle Valo 	struct sk_buff *skb = NULL;
8342be45b66SKalle Valo 	u16 rxfid, status;
8352be45b66SKalle Valo 	int length;
8362be45b66SKalle Valo 	struct hermes_rx_descriptor *desc;
8372be45b66SKalle Valo 	struct orinoco_rx_data *rx_data;
8382be45b66SKalle Valo 	int err;
8392be45b66SKalle Valo 
8402be45b66SKalle Valo 	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
8412be45b66SKalle Valo 	if (!desc)
8422be45b66SKalle Valo 		goto update_stats;
8432be45b66SKalle Valo 
8442be45b66SKalle Valo 	rxfid = hermes_read_regn(hw, RXFID);
8452be45b66SKalle Valo 
8462be45b66SKalle Valo 	err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
8472be45b66SKalle Valo 				 rxfid, 0);
8482be45b66SKalle Valo 	if (err) {
8492be45b66SKalle Valo 		printk(KERN_ERR "%s: error %d reading Rx descriptor. "
8502be45b66SKalle Valo 		       "Frame dropped.\n", dev->name, err);
8512be45b66SKalle Valo 		goto update_stats;
8522be45b66SKalle Valo 	}
8532be45b66SKalle Valo 
8542be45b66SKalle Valo 	status = le16_to_cpu(desc->status);
8552be45b66SKalle Valo 
8562be45b66SKalle Valo 	if (status & HERMES_RXSTAT_BADCRC) {
8572be45b66SKalle Valo 		DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
8582be45b66SKalle Valo 		      dev->name);
8592be45b66SKalle Valo 		stats->rx_crc_errors++;
8602be45b66SKalle Valo 		goto update_stats;
8612be45b66SKalle Valo 	}
8622be45b66SKalle Valo 
8632be45b66SKalle Valo 	/* Handle frames in monitor mode */
8642be45b66SKalle Valo 	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
8652be45b66SKalle Valo 		orinoco_rx_monitor(dev, rxfid, desc);
8662be45b66SKalle Valo 		goto out;
8672be45b66SKalle Valo 	}
8682be45b66SKalle Valo 
8692be45b66SKalle Valo 	if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
8702be45b66SKalle Valo 		DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
8712be45b66SKalle Valo 		      dev->name);
8722be45b66SKalle Valo 		wstats->discard.code++;
8732be45b66SKalle Valo 		goto update_stats;
8742be45b66SKalle Valo 	}
8752be45b66SKalle Valo 
8762be45b66SKalle Valo 	length = le16_to_cpu(desc->data_len);
8772be45b66SKalle Valo 
8782be45b66SKalle Valo 	/* Sanity checks */
8792be45b66SKalle Valo 	if (length < 3) { /* No for even an 802.2 LLC header */
8802be45b66SKalle Valo 		/* At least on Symbol firmware with PCF we get quite a
8812be45b66SKalle Valo 		   lot of these legitimately - Poll frames with no
8822be45b66SKalle Valo 		   data. */
8832be45b66SKalle Valo 		goto out;
8842be45b66SKalle Valo 	}
8852be45b66SKalle Valo 	if (length > IEEE80211_MAX_DATA_LEN) {
8862be45b66SKalle Valo 		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
8872be45b66SKalle Valo 		       dev->name, length);
8882be45b66SKalle Valo 		stats->rx_length_errors++;
8892be45b66SKalle Valo 		goto update_stats;
8902be45b66SKalle Valo 	}
8912be45b66SKalle Valo 
8922be45b66SKalle Valo 	/* Payload size does not include Michael MIC. Increase payload
8932be45b66SKalle Valo 	 * size to read it together with the data. */
8942be45b66SKalle Valo 	if (status & HERMES_RXSTAT_MIC)
8952be45b66SKalle Valo 		length += MICHAEL_MIC_LEN;
8962be45b66SKalle Valo 
8972be45b66SKalle Valo 	/* We need space for the packet data itself, plus an ethernet
8982be45b66SKalle Valo 	   header, plus 2 bytes so we can align the IP header on a
8992be45b66SKalle Valo 	   32bit boundary, plus 1 byte so we can read in odd length
9002be45b66SKalle Valo 	   packets from the card, which has an IO granularity of 16
9012be45b66SKalle Valo 	   bits */
9022be45b66SKalle Valo 	skb = dev_alloc_skb(length + ETH_HLEN + 2 + 1);
9032be45b66SKalle Valo 	if (!skb) {
9042be45b66SKalle Valo 		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
9052be45b66SKalle Valo 		       dev->name);
9062be45b66SKalle Valo 		goto update_stats;
9072be45b66SKalle Valo 	}
9082be45b66SKalle Valo 
9092be45b66SKalle Valo 	/* We'll prepend the header, so reserve space for it.  The worst
9102be45b66SKalle Valo 	   case is no decapsulation, when 802.3 header is prepended and
9112be45b66SKalle Valo 	   nothing is removed.  2 is for aligning the IP header.  */
9122be45b66SKalle Valo 	skb_reserve(skb, ETH_HLEN + 2);
9132be45b66SKalle Valo 
9142be45b66SKalle Valo 	err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
9152be45b66SKalle Valo 				 ALIGN(length, 2), rxfid,
9162be45b66SKalle Valo 				 HERMES_802_2_OFFSET);
9172be45b66SKalle Valo 	if (err) {
9182be45b66SKalle Valo 		printk(KERN_ERR "%s: error %d reading frame. "
9192be45b66SKalle Valo 		       "Frame dropped.\n", dev->name, err);
9202be45b66SKalle Valo 		goto drop;
9212be45b66SKalle Valo 	}
9222be45b66SKalle Valo 
9232be45b66SKalle Valo 	/* Add desc and skb to rx queue */
9242be45b66SKalle Valo 	rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
9252be45b66SKalle Valo 	if (!rx_data)
9262be45b66SKalle Valo 		goto drop;
9272be45b66SKalle Valo 
9282be45b66SKalle Valo 	rx_data->desc = desc;
9292be45b66SKalle Valo 	rx_data->skb = skb;
9302be45b66SKalle Valo 	list_add_tail(&rx_data->list, &priv->rx_list);
9312be45b66SKalle Valo 	tasklet_schedule(&priv->rx_tasklet);
9322be45b66SKalle Valo 
9332be45b66SKalle Valo 	return;
9342be45b66SKalle Valo 
9352be45b66SKalle Valo drop:
9362be45b66SKalle Valo 	dev_kfree_skb_irq(skb);
9372be45b66SKalle Valo update_stats:
9382be45b66SKalle Valo 	stats->rx_errors++;
9392be45b66SKalle Valo 	stats->rx_dropped++;
9402be45b66SKalle Valo out:
9412be45b66SKalle Valo 	kfree(desc);
9422be45b66SKalle Valo }
9432be45b66SKalle Valo EXPORT_SYMBOL(__orinoco_ev_rx);
9442be45b66SKalle Valo 
orinoco_rx(struct net_device * dev,struct hermes_rx_descriptor * desc,struct sk_buff * skb)9452be45b66SKalle Valo static void orinoco_rx(struct net_device *dev,
9462be45b66SKalle Valo 		       struct hermes_rx_descriptor *desc,
9472be45b66SKalle Valo 		       struct sk_buff *skb)
9482be45b66SKalle Valo {
9492be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
9503a628204STobias Klauser 	struct net_device_stats *stats = &dev->stats;
9512be45b66SKalle Valo 	u16 status, fc;
9522be45b66SKalle Valo 	int length;
9532be45b66SKalle Valo 	struct ethhdr *hdr;
9542be45b66SKalle Valo 
9552be45b66SKalle Valo 	status = le16_to_cpu(desc->status);
9562be45b66SKalle Valo 	length = le16_to_cpu(desc->data_len);
9572be45b66SKalle Valo 	fc = le16_to_cpu(desc->frame_ctl);
9582be45b66SKalle Valo 
9592be45b66SKalle Valo 	/* Calculate and check MIC */
9602be45b66SKalle Valo 	if (status & HERMES_RXSTAT_MIC) {
9612be45b66SKalle Valo 		struct orinoco_tkip_key *key;
9622be45b66SKalle Valo 		int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
9632be45b66SKalle Valo 			      HERMES_MIC_KEY_ID_SHIFT);
9642be45b66SKalle Valo 		u8 mic[MICHAEL_MIC_LEN];
9652be45b66SKalle Valo 		u8 *rxmic;
9662be45b66SKalle Valo 		u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
9672be45b66SKalle Valo 			desc->addr3 : desc->addr2;
9682be45b66SKalle Valo 
9692be45b66SKalle Valo 		/* Extract Michael MIC from payload */
9702be45b66SKalle Valo 		rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
9712be45b66SKalle Valo 
9722be45b66SKalle Valo 		skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
9732be45b66SKalle Valo 		length -= MICHAEL_MIC_LEN;
9742be45b66SKalle Valo 
9752be45b66SKalle Valo 		key = (struct orinoco_tkip_key *) priv->keys[key_id].key;
9762be45b66SKalle Valo 
9772be45b66SKalle Valo 		if (!key) {
9782be45b66SKalle Valo 			printk(KERN_WARNING "%s: Received encrypted frame from "
9792be45b66SKalle Valo 			       "%pM using key %i, but key is not installed\n",
9802be45b66SKalle Valo 			       dev->name, src, key_id);
9812be45b66SKalle Valo 			goto drop;
9822be45b66SKalle Valo 		}
9832be45b66SKalle Valo 
9842be45b66SKalle Valo 		orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src,
9852be45b66SKalle Valo 			    0, /* priority or QoS? */
9862be45b66SKalle Valo 			    skb->data, skb->len, &mic[0]);
9872be45b66SKalle Valo 
9882be45b66SKalle Valo 		if (memcmp(mic, rxmic,
9892be45b66SKalle Valo 			   MICHAEL_MIC_LEN)) {
9902be45b66SKalle Valo 			union iwreq_data wrqu;
9912be45b66SKalle Valo 			struct iw_michaelmicfailure wxmic;
9922be45b66SKalle Valo 
9932be45b66SKalle Valo 			printk(KERN_WARNING "%s: "
9942be45b66SKalle Valo 			       "Invalid Michael MIC in data frame from %pM, "
9952be45b66SKalle Valo 			       "using key %i\n",
9962be45b66SKalle Valo 			       dev->name, src, key_id);
9972be45b66SKalle Valo 
9982be45b66SKalle Valo 			/* TODO: update stats */
9992be45b66SKalle Valo 
10002be45b66SKalle Valo 			/* Notify userspace */
10012be45b66SKalle Valo 			memset(&wxmic, 0, sizeof(wxmic));
10022be45b66SKalle Valo 			wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
10032be45b66SKalle Valo 			wxmic.flags |= (desc->addr1[0] & 1) ?
10042be45b66SKalle Valo 				IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
10052be45b66SKalle Valo 			wxmic.src_addr.sa_family = ARPHRD_ETHER;
10062be45b66SKalle Valo 			memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
10072be45b66SKalle Valo 
10082be45b66SKalle Valo 			(void) orinoco_hw_get_tkip_iv(priv, key_id,
10092be45b66SKalle Valo 						      &wxmic.tsc[0]);
10102be45b66SKalle Valo 
10112be45b66SKalle Valo 			memset(&wrqu, 0, sizeof(wrqu));
10122be45b66SKalle Valo 			wrqu.data.length = sizeof(wxmic);
10132be45b66SKalle Valo 			wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
10142be45b66SKalle Valo 					    (char *) &wxmic);
10152be45b66SKalle Valo 
10162be45b66SKalle Valo 			goto drop;
10172be45b66SKalle Valo 		}
10182be45b66SKalle Valo 	}
10192be45b66SKalle Valo 
10202be45b66SKalle Valo 	/* Handle decapsulation
10212be45b66SKalle Valo 	 * In most cases, the firmware tell us about SNAP frames.
10222be45b66SKalle Valo 	 * For some reason, the SNAP frames sent by LinkSys APs
10232be45b66SKalle Valo 	 * are not properly recognised by most firmwares.
10242be45b66SKalle Valo 	 * So, check ourselves */
10252be45b66SKalle Valo 	if (length >= ENCAPS_OVERHEAD &&
10262be45b66SKalle Valo 	    (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
10272be45b66SKalle Valo 	     ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
10282be45b66SKalle Valo 	     is_ethersnap(skb->data))) {
10292be45b66SKalle Valo 		/* These indicate a SNAP within 802.2 LLC within
10302be45b66SKalle Valo 		   802.11 frame which we'll need to de-encapsulate to
10312be45b66SKalle Valo 		   the original EthernetII frame. */
1032d58ff351SJohannes Berg 		hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
10332be45b66SKalle Valo 	} else {
10342be45b66SKalle Valo 		/* 802.3 frame - prepend 802.3 header as is */
1035d58ff351SJohannes Berg 		hdr = skb_push(skb, ETH_HLEN);
10362be45b66SKalle Valo 		hdr->h_proto = htons(length);
10372be45b66SKalle Valo 	}
10382be45b66SKalle Valo 	memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
10392be45b66SKalle Valo 	if (fc & IEEE80211_FCTL_FROMDS)
10402be45b66SKalle Valo 		memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
10412be45b66SKalle Valo 	else
10422be45b66SKalle Valo 		memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
10432be45b66SKalle Valo 
10442be45b66SKalle Valo 	skb->protocol = eth_type_trans(skb, dev);
10452be45b66SKalle Valo 	skb->ip_summed = CHECKSUM_NONE;
10462be45b66SKalle Valo 	if (fc & IEEE80211_FCTL_TODS)
10472be45b66SKalle Valo 		skb->pkt_type = PACKET_OTHERHOST;
10482be45b66SKalle Valo 
10492be45b66SKalle Valo 	/* Process the wireless stats if needed */
10502be45b66SKalle Valo 	orinoco_stat_gather(dev, skb, desc);
10512be45b66SKalle Valo 
10522be45b66SKalle Valo 	/* Pass the packet to the networking stack */
10532be45b66SKalle Valo 	netif_rx(skb);
10542be45b66SKalle Valo 	stats->rx_packets++;
10552be45b66SKalle Valo 	stats->rx_bytes += length;
10562be45b66SKalle Valo 
10572be45b66SKalle Valo 	return;
10582be45b66SKalle Valo 
10592be45b66SKalle Valo  drop:
10602be45b66SKalle Valo 	dev_kfree_skb(skb);
10612be45b66SKalle Valo 	stats->rx_errors++;
10622be45b66SKalle Valo 	stats->rx_dropped++;
10632be45b66SKalle Valo }
10642be45b66SKalle Valo 
orinoco_rx_isr_tasklet(struct tasklet_struct * t)10657433c969SAllen Pais static void orinoco_rx_isr_tasklet(struct tasklet_struct *t)
10662be45b66SKalle Valo {
10677433c969SAllen Pais 	struct orinoco_private *priv = from_tasklet(priv, t, rx_tasklet);
10682be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
10692be45b66SKalle Valo 	struct orinoco_rx_data *rx_data, *temp;
10702be45b66SKalle Valo 	struct hermes_rx_descriptor *desc;
10712be45b66SKalle Valo 	struct sk_buff *skb;
10722be45b66SKalle Valo 	unsigned long flags;
10732be45b66SKalle Valo 
10742be45b66SKalle Valo 	/* orinoco_rx requires the driver lock, and we also need to
10752be45b66SKalle Valo 	 * protect priv->rx_list, so just hold the lock over the
10762be45b66SKalle Valo 	 * lot.
10772be45b66SKalle Valo 	 *
10782be45b66SKalle Valo 	 * If orinoco_lock fails, we've unplugged the card. In this
10792be45b66SKalle Valo 	 * case just abort. */
10802be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
10812be45b66SKalle Valo 		return;
10822be45b66SKalle Valo 
10832be45b66SKalle Valo 	/* extract desc and skb from queue */
10842be45b66SKalle Valo 	list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
10852be45b66SKalle Valo 		desc = rx_data->desc;
10862be45b66SKalle Valo 		skb = rx_data->skb;
10872be45b66SKalle Valo 		list_del(&rx_data->list);
10882be45b66SKalle Valo 		kfree(rx_data);
10892be45b66SKalle Valo 
10902be45b66SKalle Valo 		orinoco_rx(dev, desc, skb);
10912be45b66SKalle Valo 
10922be45b66SKalle Valo 		kfree(desc);
10932be45b66SKalle Valo 	}
10942be45b66SKalle Valo 
10952be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
10962be45b66SKalle Valo }
10972be45b66SKalle Valo 
10982be45b66SKalle Valo /********************************************************************/
10992be45b66SKalle Valo /* Rx path (info frames)                                            */
11002be45b66SKalle Valo /********************************************************************/
11012be45b66SKalle Valo 
print_linkstatus(struct net_device * dev,u16 status)11022be45b66SKalle Valo static void print_linkstatus(struct net_device *dev, u16 status)
11032be45b66SKalle Valo {
11042be45b66SKalle Valo 	char *s;
11052be45b66SKalle Valo 
11062be45b66SKalle Valo 	if (suppress_linkstatus)
11072be45b66SKalle Valo 		return;
11082be45b66SKalle Valo 
11092be45b66SKalle Valo 	switch (status) {
11102be45b66SKalle Valo 	case HERMES_LINKSTATUS_NOT_CONNECTED:
11112be45b66SKalle Valo 		s = "Not Connected";
11122be45b66SKalle Valo 		break;
11132be45b66SKalle Valo 	case HERMES_LINKSTATUS_CONNECTED:
11142be45b66SKalle Valo 		s = "Connected";
11152be45b66SKalle Valo 		break;
11162be45b66SKalle Valo 	case HERMES_LINKSTATUS_DISCONNECTED:
11172be45b66SKalle Valo 		s = "Disconnected";
11182be45b66SKalle Valo 		break;
11192be45b66SKalle Valo 	case HERMES_LINKSTATUS_AP_CHANGE:
11202be45b66SKalle Valo 		s = "AP Changed";
11212be45b66SKalle Valo 		break;
11222be45b66SKalle Valo 	case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
11232be45b66SKalle Valo 		s = "AP Out of Range";
11242be45b66SKalle Valo 		break;
11252be45b66SKalle Valo 	case HERMES_LINKSTATUS_AP_IN_RANGE:
11262be45b66SKalle Valo 		s = "AP In Range";
11272be45b66SKalle Valo 		break;
11282be45b66SKalle Valo 	case HERMES_LINKSTATUS_ASSOC_FAILED:
11292be45b66SKalle Valo 		s = "Association Failed";
11302be45b66SKalle Valo 		break;
11312be45b66SKalle Valo 	default:
11322be45b66SKalle Valo 		s = "UNKNOWN";
11332be45b66SKalle Valo 	}
11342be45b66SKalle Valo 
11352be45b66SKalle Valo 	printk(KERN_DEBUG "%s: New link status: %s (%04x)\n",
11362be45b66SKalle Valo 	       dev->name, s, status);
11372be45b66SKalle Valo }
11382be45b66SKalle Valo 
11392be45b66SKalle Valo /* Search scan results for requested BSSID, join it if found */
orinoco_join_ap(struct work_struct * work)11402be45b66SKalle Valo static void orinoco_join_ap(struct work_struct *work)
11412be45b66SKalle Valo {
11422be45b66SKalle Valo 	struct orinoco_private *priv =
11432be45b66SKalle Valo 		container_of(work, struct orinoco_private, join_work);
11442be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
11452be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
11462be45b66SKalle Valo 	int err;
11472be45b66SKalle Valo 	unsigned long flags;
11482be45b66SKalle Valo 	struct join_req {
11492be45b66SKalle Valo 		u8 bssid[ETH_ALEN];
11502be45b66SKalle Valo 		__le16 channel;
11512be45b66SKalle Valo 	} __packed req;
11522be45b66SKalle Valo 	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
11532be45b66SKalle Valo 	struct prism2_scan_apinfo *atom = NULL;
11542be45b66SKalle Valo 	int offset = 4;
11552be45b66SKalle Valo 	int found = 0;
11562be45b66SKalle Valo 	u8 *buf;
11572be45b66SKalle Valo 	u16 len;
11582be45b66SKalle Valo 
11592be45b66SKalle Valo 	/* Allocate buffer for scan results */
11602be45b66SKalle Valo 	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
11612be45b66SKalle Valo 	if (!buf)
11622be45b66SKalle Valo 		return;
11632be45b66SKalle Valo 
11642be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
11652be45b66SKalle Valo 		goto fail_lock;
11662be45b66SKalle Valo 
11672be45b66SKalle Valo 	/* Sanity checks in case user changed something in the meantime */
11682be45b66SKalle Valo 	if (!priv->bssid_fixed)
11692be45b66SKalle Valo 		goto out;
11702be45b66SKalle Valo 
11712be45b66SKalle Valo 	if (strlen(priv->desired_essid) == 0)
11722be45b66SKalle Valo 		goto out;
11732be45b66SKalle Valo 
11742be45b66SKalle Valo 	/* Read scan results from the firmware */
11752be45b66SKalle Valo 	err = hw->ops->read_ltv(hw, USER_BAP,
11762be45b66SKalle Valo 				HERMES_RID_SCANRESULTSTABLE,
11772be45b66SKalle Valo 				MAX_SCAN_LEN, &len, buf);
11782be45b66SKalle Valo 	if (err) {
11792be45b66SKalle Valo 		printk(KERN_ERR "%s: Cannot read scan results\n",
11802be45b66SKalle Valo 		       dev->name);
11812be45b66SKalle Valo 		goto out;
11822be45b66SKalle Valo 	}
11832be45b66SKalle Valo 
11842be45b66SKalle Valo 	len = HERMES_RECLEN_TO_BYTES(len);
11852be45b66SKalle Valo 
11862be45b66SKalle Valo 	/* Go through the scan results looking for the channel of the AP
11872be45b66SKalle Valo 	 * we were requested to join */
11882be45b66SKalle Valo 	for (; offset + atom_len <= len; offset += atom_len) {
11892be45b66SKalle Valo 		atom = (struct prism2_scan_apinfo *) (buf + offset);
11902be45b66SKalle Valo 		if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
11912be45b66SKalle Valo 			found = 1;
11922be45b66SKalle Valo 			break;
11932be45b66SKalle Valo 		}
11942be45b66SKalle Valo 	}
11952be45b66SKalle Valo 
11962be45b66SKalle Valo 	if (!found) {
11972be45b66SKalle Valo 		DEBUG(1, "%s: Requested AP not found in scan results\n",
11982be45b66SKalle Valo 		      dev->name);
11992be45b66SKalle Valo 		goto out;
12002be45b66SKalle Valo 	}
12012be45b66SKalle Valo 
12022be45b66SKalle Valo 	memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
12032be45b66SKalle Valo 	req.channel = atom->channel;	/* both are little-endian */
12042be45b66SKalle Valo 	err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
12052be45b66SKalle Valo 				  &req);
12062be45b66SKalle Valo 	if (err)
12072be45b66SKalle Valo 		printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
12082be45b66SKalle Valo 
12092be45b66SKalle Valo  out:
12102be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
12112be45b66SKalle Valo 
12122be45b66SKalle Valo  fail_lock:
12132be45b66SKalle Valo 	kfree(buf);
12142be45b66SKalle Valo }
12152be45b66SKalle Valo 
12162be45b66SKalle Valo /* Send new BSSID to userspace */
orinoco_send_bssid_wevent(struct orinoco_private * priv)12172be45b66SKalle Valo static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
12182be45b66SKalle Valo {
12192be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
12202be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
12212be45b66SKalle Valo 	union iwreq_data wrqu;
12222be45b66SKalle Valo 	int err;
12232be45b66SKalle Valo 
12242be45b66SKalle Valo 	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
12252be45b66SKalle Valo 				ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
12262be45b66SKalle Valo 	if (err != 0)
12272be45b66SKalle Valo 		return;
12282be45b66SKalle Valo 
12292be45b66SKalle Valo 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
12302be45b66SKalle Valo 
12312be45b66SKalle Valo 	/* Send event to user space */
12322be45b66SKalle Valo 	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
12332be45b66SKalle Valo }
12342be45b66SKalle Valo 
orinoco_send_assocreqie_wevent(struct orinoco_private * priv)12352be45b66SKalle Valo static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
12362be45b66SKalle Valo {
12372be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
12382be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
12392be45b66SKalle Valo 	union iwreq_data wrqu;
12402be45b66SKalle Valo 	int err;
12412be45b66SKalle Valo 	u8 buf[88];
12422be45b66SKalle Valo 	u8 *ie;
12432be45b66SKalle Valo 
12442be45b66SKalle Valo 	if (!priv->has_wpa)
12452be45b66SKalle Valo 		return;
12462be45b66SKalle Valo 
12472be45b66SKalle Valo 	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
12482be45b66SKalle Valo 				sizeof(buf), NULL, &buf);
12492be45b66SKalle Valo 	if (err != 0)
12502be45b66SKalle Valo 		return;
12512be45b66SKalle Valo 
12522be45b66SKalle Valo 	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
12532be45b66SKalle Valo 	if (ie) {
12542be45b66SKalle Valo 		int rem = sizeof(buf) - (ie - &buf[0]);
12552be45b66SKalle Valo 		wrqu.data.length = ie[1] + 2;
12562be45b66SKalle Valo 		if (wrqu.data.length > rem)
12572be45b66SKalle Valo 			wrqu.data.length = rem;
12582be45b66SKalle Valo 
12592be45b66SKalle Valo 		if (wrqu.data.length)
12602be45b66SKalle Valo 			/* Send event to user space */
12612be45b66SKalle Valo 			wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
12622be45b66SKalle Valo 	}
12632be45b66SKalle Valo }
12642be45b66SKalle Valo 
orinoco_send_assocrespie_wevent(struct orinoco_private * priv)12652be45b66SKalle Valo static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
12662be45b66SKalle Valo {
12672be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
12682be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
12692be45b66SKalle Valo 	union iwreq_data wrqu;
12702be45b66SKalle Valo 	int err;
12712be45b66SKalle Valo 	u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
12722be45b66SKalle Valo 	u8 *ie;
12732be45b66SKalle Valo 
12742be45b66SKalle Valo 	if (!priv->has_wpa)
12752be45b66SKalle Valo 		return;
12762be45b66SKalle Valo 
12772be45b66SKalle Valo 	err = hw->ops->read_ltv(hw, USER_BAP,
12782be45b66SKalle Valo 				HERMES_RID_CURRENT_ASSOC_RESP_INFO,
12792be45b66SKalle Valo 				sizeof(buf), NULL, &buf);
12802be45b66SKalle Valo 	if (err != 0)
12812be45b66SKalle Valo 		return;
12822be45b66SKalle Valo 
12832be45b66SKalle Valo 	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
12842be45b66SKalle Valo 	if (ie) {
12852be45b66SKalle Valo 		int rem = sizeof(buf) - (ie - &buf[0]);
12862be45b66SKalle Valo 		wrqu.data.length = ie[1] + 2;
12872be45b66SKalle Valo 		if (wrqu.data.length > rem)
12882be45b66SKalle Valo 			wrqu.data.length = rem;
12892be45b66SKalle Valo 
12902be45b66SKalle Valo 		if (wrqu.data.length)
12912be45b66SKalle Valo 			/* Send event to user space */
12922be45b66SKalle Valo 			wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
12932be45b66SKalle Valo 	}
12942be45b66SKalle Valo }
12952be45b66SKalle Valo 
orinoco_send_wevents(struct work_struct * work)12962be45b66SKalle Valo static void orinoco_send_wevents(struct work_struct *work)
12972be45b66SKalle Valo {
12982be45b66SKalle Valo 	struct orinoco_private *priv =
12992be45b66SKalle Valo 		container_of(work, struct orinoco_private, wevent_work);
13002be45b66SKalle Valo 	unsigned long flags;
13012be45b66SKalle Valo 
13022be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
13032be45b66SKalle Valo 		return;
13042be45b66SKalle Valo 
13052be45b66SKalle Valo 	orinoco_send_assocreqie_wevent(priv);
13062be45b66SKalle Valo 	orinoco_send_assocrespie_wevent(priv);
13072be45b66SKalle Valo 	orinoco_send_bssid_wevent(priv);
13082be45b66SKalle Valo 
13092be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
13102be45b66SKalle Valo }
13112be45b66SKalle Valo 
qbuf_scan(struct orinoco_private * priv,void * buf,int len,int type)13122be45b66SKalle Valo static void qbuf_scan(struct orinoco_private *priv, void *buf,
13132be45b66SKalle Valo 		      int len, int type)
13142be45b66SKalle Valo {
13152be45b66SKalle Valo 	struct orinoco_scan_data *sd;
13162be45b66SKalle Valo 	unsigned long flags;
13172be45b66SKalle Valo 
13182be45b66SKalle Valo 	sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
13192be45b66SKalle Valo 	if (!sd)
13202be45b66SKalle Valo 		return;
13212be45b66SKalle Valo 
13222be45b66SKalle Valo 	sd->buf = buf;
13232be45b66SKalle Valo 	sd->len = len;
13242be45b66SKalle Valo 	sd->type = type;
13252be45b66SKalle Valo 
13262be45b66SKalle Valo 	spin_lock_irqsave(&priv->scan_lock, flags);
13272be45b66SKalle Valo 	list_add_tail(&sd->list, &priv->scan_list);
13282be45b66SKalle Valo 	spin_unlock_irqrestore(&priv->scan_lock, flags);
13292be45b66SKalle Valo 
13302be45b66SKalle Valo 	schedule_work(&priv->process_scan);
13312be45b66SKalle Valo }
13322be45b66SKalle Valo 
qabort_scan(struct orinoco_private * priv)13332be45b66SKalle Valo static void qabort_scan(struct orinoco_private *priv)
13342be45b66SKalle Valo {
13352be45b66SKalle Valo 	struct orinoco_scan_data *sd;
13362be45b66SKalle Valo 	unsigned long flags;
13372be45b66SKalle Valo 
13382be45b66SKalle Valo 	sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
13392be45b66SKalle Valo 	if (!sd)
13402be45b66SKalle Valo 		return;
13412be45b66SKalle Valo 
13422be45b66SKalle Valo 	sd->len = -1; /* Abort */
13432be45b66SKalle Valo 
13442be45b66SKalle Valo 	spin_lock_irqsave(&priv->scan_lock, flags);
13452be45b66SKalle Valo 	list_add_tail(&sd->list, &priv->scan_list);
13462be45b66SKalle Valo 	spin_unlock_irqrestore(&priv->scan_lock, flags);
13472be45b66SKalle Valo 
13482be45b66SKalle Valo 	schedule_work(&priv->process_scan);
13492be45b66SKalle Valo }
13502be45b66SKalle Valo 
orinoco_process_scan_results(struct work_struct * work)13512be45b66SKalle Valo static void orinoco_process_scan_results(struct work_struct *work)
13522be45b66SKalle Valo {
13532be45b66SKalle Valo 	struct orinoco_private *priv =
13542be45b66SKalle Valo 		container_of(work, struct orinoco_private, process_scan);
13552be45b66SKalle Valo 	struct orinoco_scan_data *sd, *temp;
13562be45b66SKalle Valo 	unsigned long flags;
13572be45b66SKalle Valo 	void *buf;
13582be45b66SKalle Valo 	int len;
13592be45b66SKalle Valo 	int type;
13602be45b66SKalle Valo 
13612be45b66SKalle Valo 	spin_lock_irqsave(&priv->scan_lock, flags);
13622be45b66SKalle Valo 	list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
13632be45b66SKalle Valo 
13642be45b66SKalle Valo 		buf = sd->buf;
13652be45b66SKalle Valo 		len = sd->len;
13662be45b66SKalle Valo 		type = sd->type;
13672be45b66SKalle Valo 
13682be45b66SKalle Valo 		list_del(&sd->list);
13692be45b66SKalle Valo 		spin_unlock_irqrestore(&priv->scan_lock, flags);
13702be45b66SKalle Valo 		kfree(sd);
13712be45b66SKalle Valo 
13722be45b66SKalle Valo 		if (len > 0) {
13732be45b66SKalle Valo 			if (type == HERMES_INQ_CHANNELINFO)
13742be45b66SKalle Valo 				orinoco_add_extscan_result(priv, buf, len);
13752be45b66SKalle Valo 			else
13762be45b66SKalle Valo 				orinoco_add_hostscan_results(priv, buf, len);
13772be45b66SKalle Valo 
13782be45b66SKalle Valo 			kfree(buf);
13792be45b66SKalle Valo 		} else {
13802be45b66SKalle Valo 			/* Either abort or complete the scan */
13812be45b66SKalle Valo 			orinoco_scan_done(priv, (len < 0));
13822be45b66SKalle Valo 		}
13832be45b66SKalle Valo 
13842be45b66SKalle Valo 		spin_lock_irqsave(&priv->scan_lock, flags);
13852be45b66SKalle Valo 	}
13862be45b66SKalle Valo 	spin_unlock_irqrestore(&priv->scan_lock, flags);
13872be45b66SKalle Valo }
13882be45b66SKalle Valo 
__orinoco_ev_info(struct net_device * dev,struct hermes * hw)13892be45b66SKalle Valo void __orinoco_ev_info(struct net_device *dev, struct hermes *hw)
13902be45b66SKalle Valo {
13912be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
13922be45b66SKalle Valo 	u16 infofid;
13932be45b66SKalle Valo 	struct {
13942be45b66SKalle Valo 		__le16 len;
13952be45b66SKalle Valo 		__le16 type;
13962be45b66SKalle Valo 	} __packed info;
13972be45b66SKalle Valo 	int len, type;
13982be45b66SKalle Valo 	int err;
13992be45b66SKalle Valo 
14002be45b66SKalle Valo 	/* This is an answer to an INQUIRE command that we did earlier,
14012be45b66SKalle Valo 	 * or an information "event" generated by the card
14022be45b66SKalle Valo 	 * The controller return to us a pseudo frame containing
14032be45b66SKalle Valo 	 * the information in question - Jean II */
14042be45b66SKalle Valo 	infofid = hermes_read_regn(hw, INFOFID);
14052be45b66SKalle Valo 
14062be45b66SKalle Valo 	/* Read the info frame header - don't try too hard */
14072be45b66SKalle Valo 	err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
14082be45b66SKalle Valo 				 infofid, 0);
14092be45b66SKalle Valo 	if (err) {
14102be45b66SKalle Valo 		printk(KERN_ERR "%s: error %d reading info frame. "
14112be45b66SKalle Valo 		       "Frame dropped.\n", dev->name, err);
14122be45b66SKalle Valo 		return;
14132be45b66SKalle Valo 	}
14142be45b66SKalle Valo 
14152be45b66SKalle Valo 	len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
14162be45b66SKalle Valo 	type = le16_to_cpu(info.type);
14172be45b66SKalle Valo 
14182be45b66SKalle Valo 	switch (type) {
14192be45b66SKalle Valo 	case HERMES_INQ_TALLIES: {
14202be45b66SKalle Valo 		struct hermes_tallies_frame tallies;
14212be45b66SKalle Valo 		struct iw_statistics *wstats = &priv->wstats;
14222be45b66SKalle Valo 
14232be45b66SKalle Valo 		if (len > sizeof(tallies)) {
14242be45b66SKalle Valo 			printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
14252be45b66SKalle Valo 			       dev->name, len);
14262be45b66SKalle Valo 			len = sizeof(tallies);
14272be45b66SKalle Valo 		}
14282be45b66SKalle Valo 
14292be45b66SKalle Valo 		err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
14302be45b66SKalle Valo 					 infofid, sizeof(info));
14312be45b66SKalle Valo 		if (err)
14322be45b66SKalle Valo 			break;
14332be45b66SKalle Valo 
14342be45b66SKalle Valo 		/* Increment our various counters */
14352be45b66SKalle Valo 		/* wstats->discard.nwid - no wrong BSSID stuff */
14362be45b66SKalle Valo 		wstats->discard.code +=
14372be45b66SKalle Valo 			le16_to_cpu(tallies.RxWEPUndecryptable);
14382be45b66SKalle Valo 		if (len == sizeof(tallies))
14392be45b66SKalle Valo 			wstats->discard.code +=
14402be45b66SKalle Valo 				le16_to_cpu(tallies.RxDiscards_WEPICVError) +
14412be45b66SKalle Valo 				le16_to_cpu(tallies.RxDiscards_WEPExcluded);
14422be45b66SKalle Valo 		wstats->discard.misc +=
14432be45b66SKalle Valo 			le16_to_cpu(tallies.TxDiscardsWrongSA);
14442be45b66SKalle Valo 		wstats->discard.fragment +=
14452be45b66SKalle Valo 			le16_to_cpu(tallies.RxMsgInBadMsgFragments);
14462be45b66SKalle Valo 		wstats->discard.retries +=
14472be45b66SKalle Valo 			le16_to_cpu(tallies.TxRetryLimitExceeded);
14482be45b66SKalle Valo 		/* wstats->miss.beacon - no match */
14492be45b66SKalle Valo 	}
14502be45b66SKalle Valo 	break;
14512be45b66SKalle Valo 	case HERMES_INQ_LINKSTATUS: {
14522be45b66SKalle Valo 		struct hermes_linkstatus linkstatus;
14532be45b66SKalle Valo 		u16 newstatus;
14542be45b66SKalle Valo 		int connected;
14552be45b66SKalle Valo 
14562be45b66SKalle Valo 		if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
14572be45b66SKalle Valo 			break;
14582be45b66SKalle Valo 
14592be45b66SKalle Valo 		if (len != sizeof(linkstatus)) {
14602be45b66SKalle Valo 			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
14612be45b66SKalle Valo 			       dev->name, len);
14622be45b66SKalle Valo 			break;
14632be45b66SKalle Valo 		}
14642be45b66SKalle Valo 
14652be45b66SKalle Valo 		err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
14662be45b66SKalle Valo 					 infofid, sizeof(info));
14672be45b66SKalle Valo 		if (err)
14682be45b66SKalle Valo 			break;
14692be45b66SKalle Valo 		newstatus = le16_to_cpu(linkstatus.linkstatus);
14702be45b66SKalle Valo 
14712be45b66SKalle Valo 		/* Symbol firmware uses "out of range" to signal that
14722be45b66SKalle Valo 		 * the hostscan frame can be requested.  */
14732be45b66SKalle Valo 		if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
14742be45b66SKalle Valo 		    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
14752be45b66SKalle Valo 		    priv->has_hostscan && priv->scan_request) {
14762be45b66SKalle Valo 			hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
14772be45b66SKalle Valo 			break;
14782be45b66SKalle Valo 		}
14792be45b66SKalle Valo 
14802be45b66SKalle Valo 		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
14812be45b66SKalle Valo 			|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
14822be45b66SKalle Valo 			|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
14832be45b66SKalle Valo 
14842be45b66SKalle Valo 		if (connected)
14852be45b66SKalle Valo 			netif_carrier_on(dev);
14862be45b66SKalle Valo 		else if (!ignore_disconnect)
14872be45b66SKalle Valo 			netif_carrier_off(dev);
14882be45b66SKalle Valo 
14892be45b66SKalle Valo 		if (newstatus != priv->last_linkstatus) {
14902be45b66SKalle Valo 			priv->last_linkstatus = newstatus;
14912be45b66SKalle Valo 			print_linkstatus(dev, newstatus);
14922be45b66SKalle Valo 			/* The info frame contains only one word which is the
14932be45b66SKalle Valo 			 * status (see hermes.h). The status is pretty boring
14942be45b66SKalle Valo 			 * in itself, that's why we export the new BSSID...
14952be45b66SKalle Valo 			 * Jean II */
14962be45b66SKalle Valo 			schedule_work(&priv->wevent_work);
14972be45b66SKalle Valo 		}
14982be45b66SKalle Valo 	}
14992be45b66SKalle Valo 	break;
15002be45b66SKalle Valo 	case HERMES_INQ_SCAN:
15012be45b66SKalle Valo 		if (!priv->scan_request && priv->bssid_fixed &&
15022be45b66SKalle Valo 		    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
15032be45b66SKalle Valo 			schedule_work(&priv->join_work);
15042be45b66SKalle Valo 			break;
15052be45b66SKalle Valo 		}
150607a297a9SGustavo A. R. Silva 		fallthrough;
15072be45b66SKalle Valo 	case HERMES_INQ_HOSTSCAN:
15082be45b66SKalle Valo 	case HERMES_INQ_HOSTSCAN_SYMBOL: {
15092be45b66SKalle Valo 		/* Result of a scanning. Contains information about
15102be45b66SKalle Valo 		 * cells in the vicinity - Jean II */
15112be45b66SKalle Valo 		unsigned char *buf;
15122be45b66SKalle Valo 
15132be45b66SKalle Valo 		/* Sanity check */
15142be45b66SKalle Valo 		if (len > 4096) {
15152be45b66SKalle Valo 			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
15162be45b66SKalle Valo 			       dev->name, len);
15172be45b66SKalle Valo 			qabort_scan(priv);
15182be45b66SKalle Valo 			break;
15192be45b66SKalle Valo 		}
15202be45b66SKalle Valo 
15212be45b66SKalle Valo 		/* Allocate buffer for results */
15222be45b66SKalle Valo 		buf = kmalloc(len, GFP_ATOMIC);
15232be45b66SKalle Valo 		if (buf == NULL) {
15242be45b66SKalle Valo 			/* No memory, so can't printk()... */
15252be45b66SKalle Valo 			qabort_scan(priv);
15262be45b66SKalle Valo 			break;
15272be45b66SKalle Valo 		}
15282be45b66SKalle Valo 
15292be45b66SKalle Valo 		/* Read scan data */
15302be45b66SKalle Valo 		err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
15312be45b66SKalle Valo 					 infofid, sizeof(info));
15322be45b66SKalle Valo 		if (err) {
15332be45b66SKalle Valo 			kfree(buf);
15342be45b66SKalle Valo 			qabort_scan(priv);
15352be45b66SKalle Valo 			break;
15362be45b66SKalle Valo 		}
15372be45b66SKalle Valo 
15382be45b66SKalle Valo #ifdef ORINOCO_DEBUG
15392be45b66SKalle Valo 		{
15402be45b66SKalle Valo 			int	i;
15412be45b66SKalle Valo 			printk(KERN_DEBUG "Scan result [%02X", buf[0]);
15422be45b66SKalle Valo 			for (i = 1; i < (len * 2); i++)
15432be45b66SKalle Valo 				printk(":%02X", buf[i]);
15442be45b66SKalle Valo 			printk("]\n");
15452be45b66SKalle Valo 		}
15462be45b66SKalle Valo #endif	/* ORINOCO_DEBUG */
15472be45b66SKalle Valo 
15482be45b66SKalle Valo 		qbuf_scan(priv, buf, len, type);
15492be45b66SKalle Valo 	}
15502be45b66SKalle Valo 	break;
15512be45b66SKalle Valo 	case HERMES_INQ_CHANNELINFO:
15522be45b66SKalle Valo 	{
15532be45b66SKalle Valo 		struct agere_ext_scan_info *bss;
15542be45b66SKalle Valo 
15552be45b66SKalle Valo 		if (!priv->scan_request) {
15562be45b66SKalle Valo 			printk(KERN_DEBUG "%s: Got chaninfo without scan, "
15572be45b66SKalle Valo 			       "len=%d\n", dev->name, len);
15582be45b66SKalle Valo 			break;
15592be45b66SKalle Valo 		}
15602be45b66SKalle Valo 
15612be45b66SKalle Valo 		/* An empty result indicates that the scan is complete */
15622be45b66SKalle Valo 		if (len == 0) {
15632be45b66SKalle Valo 			qbuf_scan(priv, NULL, len, type);
15642be45b66SKalle Valo 			break;
15652be45b66SKalle Valo 		}
15662be45b66SKalle Valo 
15672be45b66SKalle Valo 		/* Sanity check */
15682be45b66SKalle Valo 		else if (len < (offsetof(struct agere_ext_scan_info,
15692be45b66SKalle Valo 					   data) + 2)) {
15702be45b66SKalle Valo 			/* Drop this result now so we don't have to
15712be45b66SKalle Valo 			 * keep checking later */
15722be45b66SKalle Valo 			printk(KERN_WARNING
15732be45b66SKalle Valo 			       "%s: Ext scan results too short (%d bytes)\n",
15742be45b66SKalle Valo 			       dev->name, len);
15752be45b66SKalle Valo 			break;
15762be45b66SKalle Valo 		}
15772be45b66SKalle Valo 
15782be45b66SKalle Valo 		bss = kmalloc(len, GFP_ATOMIC);
15792be45b66SKalle Valo 		if (bss == NULL)
15802be45b66SKalle Valo 			break;
15812be45b66SKalle Valo 
15822be45b66SKalle Valo 		/* Read scan data */
15832be45b66SKalle Valo 		err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
15842be45b66SKalle Valo 					 infofid, sizeof(info));
15852be45b66SKalle Valo 		if (err)
15862be45b66SKalle Valo 			kfree(bss);
15872be45b66SKalle Valo 		else
15882be45b66SKalle Valo 			qbuf_scan(priv, bss, len, type);
15892be45b66SKalle Valo 
15902be45b66SKalle Valo 		break;
15912be45b66SKalle Valo 	}
15922be45b66SKalle Valo 	case HERMES_INQ_SEC_STAT_AGERE:
15932be45b66SKalle Valo 		/* Security status (Agere specific) */
15942be45b66SKalle Valo 		/* Ignore this frame for now */
15952be45b66SKalle Valo 		if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
15962be45b66SKalle Valo 			break;
159707a297a9SGustavo A. R. Silva 		fallthrough;
15982be45b66SKalle Valo 	default:
15992be45b66SKalle Valo 		printk(KERN_DEBUG "%s: Unknown information frame received: "
16002be45b66SKalle Valo 		       "type 0x%04x, length %d\n", dev->name, type, len);
16012be45b66SKalle Valo 		/* We don't actually do anything about it */
16022be45b66SKalle Valo 		break;
16032be45b66SKalle Valo 	}
16042be45b66SKalle Valo }
16052be45b66SKalle Valo EXPORT_SYMBOL(__orinoco_ev_info);
16062be45b66SKalle Valo 
__orinoco_ev_infdrop(struct net_device * dev,struct hermes * hw)16072be45b66SKalle Valo static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw)
16082be45b66SKalle Valo {
16092be45b66SKalle Valo 	if (net_ratelimit())
16102be45b66SKalle Valo 		printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
16112be45b66SKalle Valo }
16122be45b66SKalle Valo 
16132be45b66SKalle Valo /********************************************************************/
16142be45b66SKalle Valo /* Internal hardware control routines                               */
16152be45b66SKalle Valo /********************************************************************/
16162be45b66SKalle Valo 
__orinoco_up(struct orinoco_private * priv)16172be45b66SKalle Valo static int __orinoco_up(struct orinoco_private *priv)
16182be45b66SKalle Valo {
16192be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
16202be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
16212be45b66SKalle Valo 	int err;
16222be45b66SKalle Valo 
16232be45b66SKalle Valo 	netif_carrier_off(dev); /* just to make sure */
16242be45b66SKalle Valo 
16252be45b66SKalle Valo 	err = __orinoco_commit(priv);
16262be45b66SKalle Valo 	if (err) {
16272be45b66SKalle Valo 		printk(KERN_ERR "%s: Error %d configuring card\n",
16282be45b66SKalle Valo 		       dev->name, err);
16292be45b66SKalle Valo 		return err;
16302be45b66SKalle Valo 	}
16312be45b66SKalle Valo 
16322be45b66SKalle Valo 	/* Fire things up again */
16332be45b66SKalle Valo 	hermes_set_irqmask(hw, ORINOCO_INTEN);
16342be45b66SKalle Valo 	err = hermes_enable_port(hw, 0);
16352be45b66SKalle Valo 	if (err) {
16362be45b66SKalle Valo 		printk(KERN_ERR "%s: Error %d enabling MAC port\n",
16372be45b66SKalle Valo 		       dev->name, err);
16382be45b66SKalle Valo 		return err;
16392be45b66SKalle Valo 	}
16402be45b66SKalle Valo 
16412be45b66SKalle Valo 	netif_start_queue(dev);
16422be45b66SKalle Valo 
16432be45b66SKalle Valo 	return 0;
16442be45b66SKalle Valo }
16452be45b66SKalle Valo 
__orinoco_down(struct orinoco_private * priv)16462be45b66SKalle Valo static int __orinoco_down(struct orinoco_private *priv)
16472be45b66SKalle Valo {
16482be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
16492be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
16502be45b66SKalle Valo 	int err;
16512be45b66SKalle Valo 
16522be45b66SKalle Valo 	netif_stop_queue(dev);
16532be45b66SKalle Valo 
16542be45b66SKalle Valo 	if (!priv->hw_unavailable) {
16552be45b66SKalle Valo 		if (!priv->broken_disableport) {
16562be45b66SKalle Valo 			err = hermes_disable_port(hw, 0);
16572be45b66SKalle Valo 			if (err) {
16582be45b66SKalle Valo 				/* Some firmwares (e.g. Intersil 1.3.x) seem
16592be45b66SKalle Valo 				 * to have problems disabling the port, oh
16602be45b66SKalle Valo 				 * well, too bad. */
16612be45b66SKalle Valo 				printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
16622be45b66SKalle Valo 				       dev->name, err);
16632be45b66SKalle Valo 				priv->broken_disableport = 1;
16642be45b66SKalle Valo 			}
16652be45b66SKalle Valo 		}
16662be45b66SKalle Valo 		hermes_set_irqmask(hw, 0);
16672be45b66SKalle Valo 		hermes_write_regn(hw, EVACK, 0xffff);
16682be45b66SKalle Valo 	}
16692be45b66SKalle Valo 
16702be45b66SKalle Valo 	orinoco_scan_done(priv, true);
16712be45b66SKalle Valo 
16722be45b66SKalle Valo 	/* firmware will have to reassociate */
16732be45b66SKalle Valo 	netif_carrier_off(dev);
16742be45b66SKalle Valo 	priv->last_linkstatus = 0xffff;
16752be45b66SKalle Valo 
16762be45b66SKalle Valo 	return 0;
16772be45b66SKalle Valo }
16782be45b66SKalle Valo 
orinoco_reinit_firmware(struct orinoco_private * priv)16792be45b66SKalle Valo static int orinoco_reinit_firmware(struct orinoco_private *priv)
16802be45b66SKalle Valo {
16812be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
16822be45b66SKalle Valo 	int err;
16832be45b66SKalle Valo 
16842be45b66SKalle Valo 	err = hw->ops->init(hw);
16852be45b66SKalle Valo 	if (priv->do_fw_download && !err) {
16862be45b66SKalle Valo 		err = orinoco_download(priv);
16872be45b66SKalle Valo 		if (err)
16882be45b66SKalle Valo 			priv->do_fw_download = 0;
16892be45b66SKalle Valo 	}
16902be45b66SKalle Valo 	if (!err)
16912be45b66SKalle Valo 		err = orinoco_hw_allocate_fid(priv);
16922be45b66SKalle Valo 
16932be45b66SKalle Valo 	return err;
16942be45b66SKalle Valo }
16952be45b66SKalle Valo 
16962be45b66SKalle Valo static int
__orinoco_set_multicast_list(struct net_device * dev)16972be45b66SKalle Valo __orinoco_set_multicast_list(struct net_device *dev)
16982be45b66SKalle Valo {
16992be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
17002be45b66SKalle Valo 	int err = 0;
17012be45b66SKalle Valo 	int promisc, mc_count;
17022be45b66SKalle Valo 
17032be45b66SKalle Valo 	/* The Hermes doesn't seem to have an allmulti mode, so we go
17042be45b66SKalle Valo 	 * into promiscuous mode and let the upper levels deal. */
17052be45b66SKalle Valo 	if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
17062be45b66SKalle Valo 	    (netdev_mc_count(dev) > MAX_MULTICAST(priv))) {
17072be45b66SKalle Valo 		promisc = 1;
17082be45b66SKalle Valo 		mc_count = 0;
17092be45b66SKalle Valo 	} else {
17102be45b66SKalle Valo 		promisc = 0;
17112be45b66SKalle Valo 		mc_count = netdev_mc_count(dev);
17122be45b66SKalle Valo 	}
17132be45b66SKalle Valo 
17142be45b66SKalle Valo 	err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc);
17152be45b66SKalle Valo 
17162be45b66SKalle Valo 	return err;
17172be45b66SKalle Valo }
17182be45b66SKalle Valo 
17192be45b66SKalle Valo /* This must be called from user context, without locks held - use
17202be45b66SKalle Valo  * schedule_work() */
orinoco_reset(struct work_struct * work)17212be45b66SKalle Valo void orinoco_reset(struct work_struct *work)
17222be45b66SKalle Valo {
17232be45b66SKalle Valo 	struct orinoco_private *priv =
17242be45b66SKalle Valo 		container_of(work, struct orinoco_private, reset_work);
17252be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
17262be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
17272be45b66SKalle Valo 	int err;
17282be45b66SKalle Valo 	unsigned long flags;
17292be45b66SKalle Valo 
17302be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
17312be45b66SKalle Valo 		/* When the hardware becomes available again, whatever
17322be45b66SKalle Valo 		 * detects that is responsible for re-initializing
17332be45b66SKalle Valo 		 * it. So no need for anything further */
17342be45b66SKalle Valo 		return;
17352be45b66SKalle Valo 
17362be45b66SKalle Valo 	netif_stop_queue(dev);
17372be45b66SKalle Valo 
17382be45b66SKalle Valo 	/* Shut off interrupts.  Depending on what state the hardware
17392be45b66SKalle Valo 	 * is in, this might not work, but we'll try anyway */
17402be45b66SKalle Valo 	hermes_set_irqmask(hw, 0);
17412be45b66SKalle Valo 	hermes_write_regn(hw, EVACK, 0xffff);
17422be45b66SKalle Valo 
17432be45b66SKalle Valo 	priv->hw_unavailable++;
17442be45b66SKalle Valo 	priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
17452be45b66SKalle Valo 	netif_carrier_off(dev);
17462be45b66SKalle Valo 
17472be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
17482be45b66SKalle Valo 
17492be45b66SKalle Valo 	/* Scanning support: Notify scan cancellation */
17502be45b66SKalle Valo 	orinoco_scan_done(priv, true);
17512be45b66SKalle Valo 
17522be45b66SKalle Valo 	if (priv->hard_reset) {
17532be45b66SKalle Valo 		err = (*priv->hard_reset)(priv);
17542be45b66SKalle Valo 		if (err) {
17552be45b66SKalle Valo 			printk(KERN_ERR "%s: orinoco_reset: Error %d "
17562be45b66SKalle Valo 			       "performing hard reset\n", dev->name, err);
17572be45b66SKalle Valo 			goto disable;
17582be45b66SKalle Valo 		}
17592be45b66SKalle Valo 	}
17602be45b66SKalle Valo 
17612be45b66SKalle Valo 	err = orinoco_reinit_firmware(priv);
17622be45b66SKalle Valo 	if (err) {
17632be45b66SKalle Valo 		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
17642be45b66SKalle Valo 		       dev->name, err);
17652be45b66SKalle Valo 		goto disable;
17662be45b66SKalle Valo 	}
17672be45b66SKalle Valo 
17682be45b66SKalle Valo 	/* This has to be called from user context */
17692be45b66SKalle Valo 	orinoco_lock_irq(priv);
17702be45b66SKalle Valo 
17712be45b66SKalle Valo 	priv->hw_unavailable--;
17722be45b66SKalle Valo 
17732be45b66SKalle Valo 	/* priv->open or priv->hw_unavailable might have changed while
17742be45b66SKalle Valo 	 * we dropped the lock */
17752be45b66SKalle Valo 	if (priv->open && (!priv->hw_unavailable)) {
17762be45b66SKalle Valo 		err = __orinoco_up(priv);
17772be45b66SKalle Valo 		if (err) {
17782be45b66SKalle Valo 			printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
17792be45b66SKalle Valo 			       dev->name, err);
17802be45b66SKalle Valo 		} else
1781860e9538SFlorian Westphal 			netif_trans_update(dev);
17822be45b66SKalle Valo 	}
17832be45b66SKalle Valo 
17842be45b66SKalle Valo 	orinoco_unlock_irq(priv);
17852be45b66SKalle Valo 
17862be45b66SKalle Valo 	return;
17872be45b66SKalle Valo  disable:
17882be45b66SKalle Valo 	hermes_set_irqmask(hw, 0);
17892be45b66SKalle Valo 	netif_device_detach(dev);
17902be45b66SKalle Valo 	printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
17912be45b66SKalle Valo }
17922be45b66SKalle Valo 
__orinoco_commit(struct orinoco_private * priv)17932be45b66SKalle Valo static int __orinoco_commit(struct orinoco_private *priv)
17942be45b66SKalle Valo {
17952be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
17962be45b66SKalle Valo 	int err = 0;
17972be45b66SKalle Valo 
17982be45b66SKalle Valo 	/* If we've called commit, we are reconfiguring or bringing the
17992be45b66SKalle Valo 	 * interface up. Maintaining countermeasures across this would
18002be45b66SKalle Valo 	 * be confusing, so note that we've disabled them. The port will
18012be45b66SKalle Valo 	 * be enabled later in orinoco_commit or __orinoco_up. */
18022be45b66SKalle Valo 	priv->tkip_cm_active = 0;
18032be45b66SKalle Valo 
18042be45b66SKalle Valo 	err = orinoco_hw_program_rids(priv);
18052be45b66SKalle Valo 
18062be45b66SKalle Valo 	/* FIXME: what about netif_tx_lock */
18072be45b66SKalle Valo 	(void) __orinoco_set_multicast_list(dev);
18082be45b66SKalle Valo 
18092be45b66SKalle Valo 	return err;
18102be45b66SKalle Valo }
18112be45b66SKalle Valo 
18122be45b66SKalle Valo /* Ensures configuration changes are applied. May result in a reset.
18132be45b66SKalle Valo  * The caller should hold priv->lock
18142be45b66SKalle Valo  */
orinoco_commit(struct orinoco_private * priv)18152be45b66SKalle Valo int orinoco_commit(struct orinoco_private *priv)
18162be45b66SKalle Valo {
18172be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
18182be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
18192be45b66SKalle Valo 	int err;
18202be45b66SKalle Valo 
18212be45b66SKalle Valo 	if (priv->broken_disableport) {
18222be45b66SKalle Valo 		schedule_work(&priv->reset_work);
18232be45b66SKalle Valo 		return 0;
18242be45b66SKalle Valo 	}
18252be45b66SKalle Valo 
18262be45b66SKalle Valo 	err = hermes_disable_port(hw, 0);
18272be45b66SKalle Valo 	if (err) {
18282be45b66SKalle Valo 		printk(KERN_WARNING "%s: Unable to disable port "
18292be45b66SKalle Valo 		       "while reconfiguring card\n", dev->name);
18302be45b66SKalle Valo 		priv->broken_disableport = 1;
18312be45b66SKalle Valo 		goto out;
18322be45b66SKalle Valo 	}
18332be45b66SKalle Valo 
18342be45b66SKalle Valo 	err = __orinoco_commit(priv);
18352be45b66SKalle Valo 	if (err) {
18362be45b66SKalle Valo 		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
18372be45b66SKalle Valo 		       dev->name);
18382be45b66SKalle Valo 		goto out;
18392be45b66SKalle Valo 	}
18402be45b66SKalle Valo 
18412be45b66SKalle Valo 	err = hermes_enable_port(hw, 0);
18422be45b66SKalle Valo 	if (err) {
18432be45b66SKalle Valo 		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
18442be45b66SKalle Valo 		       dev->name);
18452be45b66SKalle Valo 		goto out;
18462be45b66SKalle Valo 	}
18472be45b66SKalle Valo 
18482be45b66SKalle Valo  out:
18492be45b66SKalle Valo 	if (err) {
18502be45b66SKalle Valo 		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
18512be45b66SKalle Valo 		schedule_work(&priv->reset_work);
18522be45b66SKalle Valo 		err = 0;
18532be45b66SKalle Valo 	}
18542be45b66SKalle Valo 	return err;
18552be45b66SKalle Valo }
18562be45b66SKalle Valo 
18572be45b66SKalle Valo /********************************************************************/
18582be45b66SKalle Valo /* Interrupt handler                                                */
18592be45b66SKalle Valo /********************************************************************/
18602be45b66SKalle Valo 
__orinoco_ev_tick(struct net_device * dev,struct hermes * hw)18612be45b66SKalle Valo static void __orinoco_ev_tick(struct net_device *dev, struct hermes *hw)
18622be45b66SKalle Valo {
18632be45b66SKalle Valo 	printk(KERN_DEBUG "%s: TICK\n", dev->name);
18642be45b66SKalle Valo }
18652be45b66SKalle Valo 
__orinoco_ev_wterr(struct net_device * dev,struct hermes * hw)18662be45b66SKalle Valo static void __orinoco_ev_wterr(struct net_device *dev, struct hermes *hw)
18672be45b66SKalle Valo {
18682be45b66SKalle Valo 	/* This seems to happen a fair bit under load, but ignoring it
18692be45b66SKalle Valo 	   seems to work fine...*/
18702be45b66SKalle Valo 	printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
18712be45b66SKalle Valo 	       dev->name);
18722be45b66SKalle Valo }
18732be45b66SKalle Valo 
orinoco_interrupt(int irq,void * dev_id)18742be45b66SKalle Valo irqreturn_t orinoco_interrupt(int irq, void *dev_id)
18752be45b66SKalle Valo {
18762be45b66SKalle Valo 	struct orinoco_private *priv = dev_id;
18772be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
18782be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
18792be45b66SKalle Valo 	int count = MAX_IRQLOOPS_PER_IRQ;
18802be45b66SKalle Valo 	u16 evstat, events;
18812be45b66SKalle Valo 	/* These are used to detect a runaway interrupt situation.
18822be45b66SKalle Valo 	 *
18832be45b66SKalle Valo 	 * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
18842be45b66SKalle Valo 	 * we panic and shut down the hardware
18852be45b66SKalle Valo 	 */
18862be45b66SKalle Valo 	/* jiffies value the last time we were called */
18872be45b66SKalle Valo 	static int last_irq_jiffy; /* = 0 */
18882be45b66SKalle Valo 	static int loops_this_jiffy; /* = 0 */
18892be45b66SKalle Valo 	unsigned long flags;
18902be45b66SKalle Valo 
18912be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0) {
18922be45b66SKalle Valo 		/* If hw is unavailable - we don't know if the irq was
18932be45b66SKalle Valo 		 * for us or not */
18942be45b66SKalle Valo 		return IRQ_HANDLED;
18952be45b66SKalle Valo 	}
18962be45b66SKalle Valo 
18972be45b66SKalle Valo 	evstat = hermes_read_regn(hw, EVSTAT);
18982be45b66SKalle Valo 	events = evstat & hw->inten;
18992be45b66SKalle Valo 	if (!events) {
19002be45b66SKalle Valo 		orinoco_unlock(priv, &flags);
19012be45b66SKalle Valo 		return IRQ_NONE;
19022be45b66SKalle Valo 	}
19032be45b66SKalle Valo 
19042be45b66SKalle Valo 	if (jiffies != last_irq_jiffy)
19052be45b66SKalle Valo 		loops_this_jiffy = 0;
19062be45b66SKalle Valo 	last_irq_jiffy = jiffies;
19072be45b66SKalle Valo 
19082be45b66SKalle Valo 	while (events && count--) {
19092be45b66SKalle Valo 		if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
19102be45b66SKalle Valo 			printk(KERN_WARNING "%s: IRQ handler is looping too "
19112be45b66SKalle Valo 			       "much! Resetting.\n", dev->name);
19122be45b66SKalle Valo 			/* Disable interrupts for now */
19132be45b66SKalle Valo 			hermes_set_irqmask(hw, 0);
19142be45b66SKalle Valo 			schedule_work(&priv->reset_work);
19152be45b66SKalle Valo 			break;
19162be45b66SKalle Valo 		}
19172be45b66SKalle Valo 
19182be45b66SKalle Valo 		/* Check the card hasn't been removed */
19192be45b66SKalle Valo 		if (!hermes_present(hw)) {
19202be45b66SKalle Valo 			DEBUG(0, "orinoco_interrupt(): card removed\n");
19212be45b66SKalle Valo 			break;
19222be45b66SKalle Valo 		}
19232be45b66SKalle Valo 
19242be45b66SKalle Valo 		if (events & HERMES_EV_TICK)
19252be45b66SKalle Valo 			__orinoco_ev_tick(dev, hw);
19262be45b66SKalle Valo 		if (events & HERMES_EV_WTERR)
19272be45b66SKalle Valo 			__orinoco_ev_wterr(dev, hw);
19282be45b66SKalle Valo 		if (events & HERMES_EV_INFDROP)
19292be45b66SKalle Valo 			__orinoco_ev_infdrop(dev, hw);
19302be45b66SKalle Valo 		if (events & HERMES_EV_INFO)
19312be45b66SKalle Valo 			__orinoco_ev_info(dev, hw);
19322be45b66SKalle Valo 		if (events & HERMES_EV_RX)
19332be45b66SKalle Valo 			__orinoco_ev_rx(dev, hw);
19342be45b66SKalle Valo 		if (events & HERMES_EV_TXEXC)
19352be45b66SKalle Valo 			__orinoco_ev_txexc(dev, hw);
19362be45b66SKalle Valo 		if (events & HERMES_EV_TX)
19372be45b66SKalle Valo 			__orinoco_ev_tx(dev, hw);
19382be45b66SKalle Valo 		if (events & HERMES_EV_ALLOC)
19392be45b66SKalle Valo 			__orinoco_ev_alloc(dev, hw);
19402be45b66SKalle Valo 
19412be45b66SKalle Valo 		hermes_write_regn(hw, EVACK, evstat);
19422be45b66SKalle Valo 
19432be45b66SKalle Valo 		evstat = hermes_read_regn(hw, EVSTAT);
19442be45b66SKalle Valo 		events = evstat & hw->inten;
19452be45b66SKalle Valo 	}
19462be45b66SKalle Valo 
19472be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
19482be45b66SKalle Valo 	return IRQ_HANDLED;
19492be45b66SKalle Valo }
19502be45b66SKalle Valo EXPORT_SYMBOL(orinoco_interrupt);
19512be45b66SKalle Valo 
19522be45b66SKalle Valo /********************************************************************/
19532be45b66SKalle Valo /* Power management                                                 */
19542be45b66SKalle Valo /********************************************************************/
19552be45b66SKalle Valo #if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
orinoco_pm_notifier(struct notifier_block * notifier,unsigned long pm_event,void * unused)19562be45b66SKalle Valo static int orinoco_pm_notifier(struct notifier_block *notifier,
19572be45b66SKalle Valo 			       unsigned long pm_event,
19582be45b66SKalle Valo 			       void *unused)
19592be45b66SKalle Valo {
19602be45b66SKalle Valo 	struct orinoco_private *priv = container_of(notifier,
19612be45b66SKalle Valo 						    struct orinoco_private,
19622be45b66SKalle Valo 						    pm_notifier);
19632be45b66SKalle Valo 
19642be45b66SKalle Valo 	/* All we need to do is cache the firmware before suspend, and
19652be45b66SKalle Valo 	 * release it when we come out.
19662be45b66SKalle Valo 	 *
19672be45b66SKalle Valo 	 * Only need to do this if we're downloading firmware. */
19682be45b66SKalle Valo 	if (!priv->do_fw_download)
19692be45b66SKalle Valo 		return NOTIFY_DONE;
19702be45b66SKalle Valo 
19712be45b66SKalle Valo 	switch (pm_event) {
19722be45b66SKalle Valo 	case PM_HIBERNATION_PREPARE:
19732be45b66SKalle Valo 	case PM_SUSPEND_PREPARE:
19742be45b66SKalle Valo 		orinoco_cache_fw(priv, 0);
19752be45b66SKalle Valo 		break;
19762be45b66SKalle Valo 
19772be45b66SKalle Valo 	case PM_POST_RESTORE:
19782be45b66SKalle Valo 		/* Restore from hibernation failed. We need to clean
19792be45b66SKalle Valo 		 * up in exactly the same way, so fall through. */
19802be45b66SKalle Valo 	case PM_POST_HIBERNATION:
19812be45b66SKalle Valo 	case PM_POST_SUSPEND:
19822be45b66SKalle Valo 		orinoco_uncache_fw(priv);
19832be45b66SKalle Valo 		break;
19842be45b66SKalle Valo 
19852be45b66SKalle Valo 	case PM_RESTORE_PREPARE:
19862be45b66SKalle Valo 	default:
19872be45b66SKalle Valo 		break;
19882be45b66SKalle Valo 	}
19892be45b66SKalle Valo 
19902be45b66SKalle Valo 	return NOTIFY_DONE;
19912be45b66SKalle Valo }
19922be45b66SKalle Valo 
orinoco_register_pm_notifier(struct orinoco_private * priv)19932be45b66SKalle Valo static void orinoco_register_pm_notifier(struct orinoco_private *priv)
19942be45b66SKalle Valo {
19952be45b66SKalle Valo 	priv->pm_notifier.notifier_call = orinoco_pm_notifier;
19962be45b66SKalle Valo 	register_pm_notifier(&priv->pm_notifier);
19972be45b66SKalle Valo }
19982be45b66SKalle Valo 
orinoco_unregister_pm_notifier(struct orinoco_private * priv)19992be45b66SKalle Valo static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
20002be45b66SKalle Valo {
20012be45b66SKalle Valo 	unregister_pm_notifier(&priv->pm_notifier);
20022be45b66SKalle Valo }
20032be45b66SKalle Valo #else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
20042be45b66SKalle Valo #define orinoco_register_pm_notifier(priv) do { } while (0)
20052be45b66SKalle Valo #define orinoco_unregister_pm_notifier(priv) do { } while (0)
20062be45b66SKalle Valo #endif
20072be45b66SKalle Valo 
20082be45b66SKalle Valo /********************************************************************/
20092be45b66SKalle Valo /* Initialization                                                   */
20102be45b66SKalle Valo /********************************************************************/
20112be45b66SKalle Valo 
orinoco_init(struct orinoco_private * priv)20122be45b66SKalle Valo int orinoco_init(struct orinoco_private *priv)
20132be45b66SKalle Valo {
20142be45b66SKalle Valo 	struct device *dev = priv->dev;
20152be45b66SKalle Valo 	struct wiphy *wiphy = priv_to_wiphy(priv);
20162be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
20172be45b66SKalle Valo 	int err = 0;
20182be45b66SKalle Valo 
20192be45b66SKalle Valo 	/* No need to lock, the hw_unavailable flag is already set in
20202be45b66SKalle Valo 	 * alloc_orinocodev() */
20212be45b66SKalle Valo 	priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
20222be45b66SKalle Valo 
20232be45b66SKalle Valo 	/* Initialize the firmware */
20242be45b66SKalle Valo 	err = hw->ops->init(hw);
20252be45b66SKalle Valo 	if (err != 0) {
20262be45b66SKalle Valo 		dev_err(dev, "Failed to initialize firmware (err = %d)\n",
20272be45b66SKalle Valo 			err);
20282be45b66SKalle Valo 		goto out;
20292be45b66SKalle Valo 	}
20302be45b66SKalle Valo 
20312be45b66SKalle Valo 	err = determine_fw_capabilities(priv, wiphy->fw_version,
20322be45b66SKalle Valo 					sizeof(wiphy->fw_version),
20332be45b66SKalle Valo 					&wiphy->hw_version);
20342be45b66SKalle Valo 	if (err != 0) {
20352be45b66SKalle Valo 		dev_err(dev, "Incompatible firmware, aborting\n");
20362be45b66SKalle Valo 		goto out;
20372be45b66SKalle Valo 	}
20382be45b66SKalle Valo 
20392be45b66SKalle Valo 	if (priv->do_fw_download) {
20402be45b66SKalle Valo #ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
20412be45b66SKalle Valo 		orinoco_cache_fw(priv, 0);
20422be45b66SKalle Valo #endif
20432be45b66SKalle Valo 
20442be45b66SKalle Valo 		err = orinoco_download(priv);
20452be45b66SKalle Valo 		if (err)
20462be45b66SKalle Valo 			priv->do_fw_download = 0;
20472be45b66SKalle Valo 
20482be45b66SKalle Valo 		/* Check firmware version again */
20492be45b66SKalle Valo 		err = determine_fw_capabilities(priv, wiphy->fw_version,
20502be45b66SKalle Valo 						sizeof(wiphy->fw_version),
20512be45b66SKalle Valo 						&wiphy->hw_version);
20522be45b66SKalle Valo 		if (err != 0) {
20532be45b66SKalle Valo 			dev_err(dev, "Incompatible firmware, aborting\n");
20542be45b66SKalle Valo 			goto out;
20552be45b66SKalle Valo 		}
20562be45b66SKalle Valo 	}
20572be45b66SKalle Valo 
20582be45b66SKalle Valo 	if (priv->has_port3)
20592be45b66SKalle Valo 		dev_info(dev, "Ad-hoc demo mode supported\n");
20602be45b66SKalle Valo 	if (priv->has_ibss)
20612be45b66SKalle Valo 		dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
20622be45b66SKalle Valo 	if (priv->has_wep)
20632be45b66SKalle Valo 		dev_info(dev, "WEP supported, %s-bit key\n",
20642be45b66SKalle Valo 			 priv->has_big_wep ? "104" : "40");
20652be45b66SKalle Valo 	if (priv->has_wpa) {
20662be45b66SKalle Valo 		dev_info(dev, "WPA-PSK supported\n");
20672be45b66SKalle Valo 		if (orinoco_mic_init(priv)) {
20682be45b66SKalle Valo 			dev_err(dev, "Failed to setup MIC crypto algorithm. "
20692be45b66SKalle Valo 				"Disabling WPA support\n");
20702be45b66SKalle Valo 			priv->has_wpa = 0;
20712be45b66SKalle Valo 		}
20722be45b66SKalle Valo 	}
20732be45b66SKalle Valo 
20742be45b66SKalle Valo 	err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
20752be45b66SKalle Valo 	if (err)
20762be45b66SKalle Valo 		goto out;
20772be45b66SKalle Valo 
20782be45b66SKalle Valo 	err = orinoco_hw_allocate_fid(priv);
20792be45b66SKalle Valo 	if (err) {
20802be45b66SKalle Valo 		dev_err(dev, "Failed to allocate NIC buffer!\n");
20812be45b66SKalle Valo 		goto out;
20822be45b66SKalle Valo 	}
20832be45b66SKalle Valo 
20842be45b66SKalle Valo 	/* Set up the default configuration */
20852be45b66SKalle Valo 	priv->iw_mode = NL80211_IFTYPE_STATION;
20862be45b66SKalle Valo 	/* By default use IEEE/IBSS ad-hoc mode if we have it */
20872be45b66SKalle Valo 	priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
20882be45b66SKalle Valo 	set_port_type(priv);
20892be45b66SKalle Valo 	priv->channel = 0; /* use firmware default */
20902be45b66SKalle Valo 
20912be45b66SKalle Valo 	priv->promiscuous = 0;
20922be45b66SKalle Valo 	priv->encode_alg = ORINOCO_ALG_NONE;
20932be45b66SKalle Valo 	priv->tx_key = 0;
20942be45b66SKalle Valo 	priv->wpa_enabled = 0;
20952be45b66SKalle Valo 	priv->tkip_cm_active = 0;
20962be45b66SKalle Valo 	priv->key_mgmt = 0;
20972be45b66SKalle Valo 	priv->wpa_ie_len = 0;
20982be45b66SKalle Valo 	priv->wpa_ie = NULL;
20992be45b66SKalle Valo 
21002be45b66SKalle Valo 	if (orinoco_wiphy_register(wiphy)) {
21012be45b66SKalle Valo 		err = -ENODEV;
21022be45b66SKalle Valo 		goto out;
21032be45b66SKalle Valo 	}
21042be45b66SKalle Valo 
21052be45b66SKalle Valo 	/* Make the hardware available, as long as it hasn't been
21062be45b66SKalle Valo 	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
21072be45b66SKalle Valo 	orinoco_lock_irq(priv);
21082be45b66SKalle Valo 	priv->hw_unavailable--;
21092be45b66SKalle Valo 	orinoco_unlock_irq(priv);
21102be45b66SKalle Valo 
21112be45b66SKalle Valo 	dev_dbg(dev, "Ready\n");
21122be45b66SKalle Valo 
21132be45b66SKalle Valo  out:
21142be45b66SKalle Valo 	return err;
21152be45b66SKalle Valo }
21162be45b66SKalle Valo EXPORT_SYMBOL(orinoco_init);
21172be45b66SKalle Valo 
21182be45b66SKalle Valo static const struct net_device_ops orinoco_netdev_ops = {
21192be45b66SKalle Valo 	.ndo_open		= orinoco_open,
21202be45b66SKalle Valo 	.ndo_stop		= orinoco_stop,
21212be45b66SKalle Valo 	.ndo_start_xmit		= orinoco_xmit,
21222be45b66SKalle Valo 	.ndo_set_rx_mode	= orinoco_set_multicast_list,
21232be45b66SKalle Valo 	.ndo_change_mtu		= orinoco_change_mtu,
21242be45b66SKalle Valo 	.ndo_set_mac_address	= eth_mac_addr,
21252be45b66SKalle Valo 	.ndo_validate_addr	= eth_validate_addr,
21262be45b66SKalle Valo 	.ndo_tx_timeout		= orinoco_tx_timeout,
21272be45b66SKalle Valo };
21282be45b66SKalle Valo 
21292be45b66SKalle Valo /* Allocate private data.
21302be45b66SKalle Valo  *
21312be45b66SKalle Valo  * This driver has a number of structures associated with it
21322be45b66SKalle Valo  *  netdev - Net device structure for each network interface
21332be45b66SKalle Valo  *  wiphy - structure associated with wireless phy
21342be45b66SKalle Valo  *  wireless_dev (wdev) - structure for each wireless interface
21352be45b66SKalle Valo  *  hw - structure for hermes chip info
21362be45b66SKalle Valo  *  card - card specific structure for use by the card driver
21372be45b66SKalle Valo  *         (airport, orinoco_cs)
21382be45b66SKalle Valo  *  priv - orinoco private data
21392be45b66SKalle Valo  *  device - generic linux device structure
21402be45b66SKalle Valo  *
21412be45b66SKalle Valo  *  +---------+    +---------+
21422be45b66SKalle Valo  *  |  wiphy  |    | netdev  |
21432be45b66SKalle Valo  *  | +-------+    | +-------+
21442be45b66SKalle Valo  *  | | priv  |    | | wdev  |
21452be45b66SKalle Valo  *  | | +-----+    +-+-------+
21462be45b66SKalle Valo  *  | | | hw  |
21472be45b66SKalle Valo  *  | +-+-----+
21482be45b66SKalle Valo  *  | | card  |
21492be45b66SKalle Valo  *  +-+-------+
21502be45b66SKalle Valo  *
21512be45b66SKalle Valo  * priv has a link to netdev and device
21522be45b66SKalle Valo  * wdev has a link to wiphy
21532be45b66SKalle Valo  */
21542be45b66SKalle Valo struct orinoco_private
alloc_orinocodev(int sizeof_card,struct device * device,int (* hard_reset)(struct orinoco_private *),int (* stop_fw)(struct orinoco_private *,int))21552be45b66SKalle Valo *alloc_orinocodev(int sizeof_card,
21562be45b66SKalle Valo 		  struct device *device,
21572be45b66SKalle Valo 		  int (*hard_reset)(struct orinoco_private *),
21582be45b66SKalle Valo 		  int (*stop_fw)(struct orinoco_private *, int))
21592be45b66SKalle Valo {
21602be45b66SKalle Valo 	struct orinoco_private *priv;
21612be45b66SKalle Valo 	struct wiphy *wiphy;
21622be45b66SKalle Valo 
21632be45b66SKalle Valo 	/* allocate wiphy
21642be45b66SKalle Valo 	 * NOTE: We only support a single virtual interface
21652be45b66SKalle Valo 	 *       but this may change when monitor mode is added
21662be45b66SKalle Valo 	 */
21672be45b66SKalle Valo 	wiphy = wiphy_new(&orinoco_cfg_ops,
21682be45b66SKalle Valo 			  sizeof(struct orinoco_private) + sizeof_card);
21692be45b66SKalle Valo 	if (!wiphy)
21702be45b66SKalle Valo 		return NULL;
21712be45b66SKalle Valo 
21722be45b66SKalle Valo 	priv = wiphy_priv(wiphy);
21732be45b66SKalle Valo 	priv->dev = device;
21742be45b66SKalle Valo 
21752be45b66SKalle Valo 	if (sizeof_card)
21762be45b66SKalle Valo 		priv->card = (void *)((unsigned long)priv
21772be45b66SKalle Valo 				      + sizeof(struct orinoco_private));
21782be45b66SKalle Valo 	else
21792be45b66SKalle Valo 		priv->card = NULL;
21802be45b66SKalle Valo 
21812be45b66SKalle Valo 	orinoco_wiphy_init(wiphy);
21822be45b66SKalle Valo 
21832be45b66SKalle Valo #ifdef WIRELESS_SPY
21842be45b66SKalle Valo 	priv->wireless_data.spy_data = &priv->spy_data;
21852be45b66SKalle Valo #endif
21862be45b66SKalle Valo 
21872be45b66SKalle Valo 	/* Set up default callbacks */
21882be45b66SKalle Valo 	priv->hard_reset = hard_reset;
21892be45b66SKalle Valo 	priv->stop_fw = stop_fw;
21902be45b66SKalle Valo 
21912be45b66SKalle Valo 	spin_lock_init(&priv->lock);
21922be45b66SKalle Valo 	priv->open = 0;
21932be45b66SKalle Valo 	priv->hw_unavailable = 1; /* orinoco_init() must clear this
21942be45b66SKalle Valo 				   * before anything else touches the
21952be45b66SKalle Valo 				   * hardware */
21962be45b66SKalle Valo 	INIT_WORK(&priv->reset_work, orinoco_reset);
21972be45b66SKalle Valo 	INIT_WORK(&priv->join_work, orinoco_join_ap);
21982be45b66SKalle Valo 	INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
21992be45b66SKalle Valo 
22002be45b66SKalle Valo 	INIT_LIST_HEAD(&priv->rx_list);
22017433c969SAllen Pais 	tasklet_setup(&priv->rx_tasklet, orinoco_rx_isr_tasklet);
22022be45b66SKalle Valo 
22032be45b66SKalle Valo 	spin_lock_init(&priv->scan_lock);
22042be45b66SKalle Valo 	INIT_LIST_HEAD(&priv->scan_list);
22052be45b66SKalle Valo 	INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
22062be45b66SKalle Valo 
22072be45b66SKalle Valo 	priv->last_linkstatus = 0xffff;
22082be45b66SKalle Valo 
22092be45b66SKalle Valo #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
22102be45b66SKalle Valo 	priv->cached_pri_fw = NULL;
22112be45b66SKalle Valo 	priv->cached_fw = NULL;
22122be45b66SKalle Valo #endif
22132be45b66SKalle Valo 
22142be45b66SKalle Valo 	/* Register PM notifiers */
22152be45b66SKalle Valo 	orinoco_register_pm_notifier(priv);
22162be45b66SKalle Valo 
22172be45b66SKalle Valo 	return priv;
22182be45b66SKalle Valo }
22192be45b66SKalle Valo EXPORT_SYMBOL(alloc_orinocodev);
22202be45b66SKalle Valo 
22212be45b66SKalle Valo /* We can only support a single interface. We provide a separate
22222be45b66SKalle Valo  * function to set it up to distinguish between hardware
22232be45b66SKalle Valo  * initialisation and interface setup.
22242be45b66SKalle Valo  *
22252be45b66SKalle Valo  * The base_addr and irq parameters are passed on to netdev for use
22262be45b66SKalle Valo  * with SIOCGIFMAP.
22272be45b66SKalle Valo  */
orinoco_if_add(struct orinoco_private * priv,unsigned long base_addr,unsigned int irq,const struct net_device_ops * ops)22282be45b66SKalle Valo int orinoco_if_add(struct orinoco_private *priv,
22292be45b66SKalle Valo 		   unsigned long base_addr,
22302be45b66SKalle Valo 		   unsigned int irq,
22312be45b66SKalle Valo 		   const struct net_device_ops *ops)
22322be45b66SKalle Valo {
22332be45b66SKalle Valo 	struct wiphy *wiphy = priv_to_wiphy(priv);
22342be45b66SKalle Valo 	struct wireless_dev *wdev;
22352be45b66SKalle Valo 	struct net_device *dev;
22362be45b66SKalle Valo 	int ret;
22372be45b66SKalle Valo 
22382be45b66SKalle Valo 	dev = alloc_etherdev(sizeof(struct wireless_dev));
22392be45b66SKalle Valo 
22402be45b66SKalle Valo 	if (!dev)
22412be45b66SKalle Valo 		return -ENOMEM;
22422be45b66SKalle Valo 
22432be45b66SKalle Valo 	/* Initialise wireless_dev */
22442be45b66SKalle Valo 	wdev = netdev_priv(dev);
22452be45b66SKalle Valo 	wdev->wiphy = wiphy;
22462be45b66SKalle Valo 	wdev->iftype = NL80211_IFTYPE_STATION;
22472be45b66SKalle Valo 
22482be45b66SKalle Valo 	/* Setup / override net_device fields */
22492be45b66SKalle Valo 	dev->ieee80211_ptr = wdev;
22502be45b66SKalle Valo 	dev->watchdog_timeo = HZ; /* 1 second timeout */
22512be45b66SKalle Valo 	dev->wireless_handlers = &orinoco_handler_def;
22522be45b66SKalle Valo #ifdef WIRELESS_SPY
22532be45b66SKalle Valo 	dev->wireless_data = &priv->wireless_data;
22542be45b66SKalle Valo #endif
22552be45b66SKalle Valo 	/* Default to standard ops if not set */
22562be45b66SKalle Valo 	if (ops)
22572be45b66SKalle Valo 		dev->netdev_ops = ops;
22582be45b66SKalle Valo 	else
22592be45b66SKalle Valo 		dev->netdev_ops = &orinoco_netdev_ops;
22602be45b66SKalle Valo 
22612be45b66SKalle Valo 	/* we use the default eth_mac_addr for setting the MAC addr */
22622be45b66SKalle Valo 
22632be45b66SKalle Valo 	/* Reserve space in skb for the SNAP header */
22642be45b66SKalle Valo 	dev->needed_headroom = ENCAPS_OVERHEAD;
22652be45b66SKalle Valo 
22662be45b66SKalle Valo 	netif_carrier_off(dev);
22672be45b66SKalle Valo 
2268*708884e7SJakub Kicinski 	eth_hw_addr_set(dev, wiphy->perm_addr);
22692be45b66SKalle Valo 
22702be45b66SKalle Valo 	dev->base_addr = base_addr;
22712be45b66SKalle Valo 	dev->irq = irq;
22722be45b66SKalle Valo 
22739c22b4a3SJarod Wilson 	dev->min_mtu = ORINOCO_MIN_MTU;
22749c22b4a3SJarod Wilson 	dev->max_mtu = ORINOCO_MAX_MTU;
22759c22b4a3SJarod Wilson 
22762be45b66SKalle Valo 	SET_NETDEV_DEV(dev, priv->dev);
22772be45b66SKalle Valo 	ret = register_netdev(dev);
22782be45b66SKalle Valo 	if (ret)
22792be45b66SKalle Valo 		goto fail;
22802be45b66SKalle Valo 
22812be45b66SKalle Valo 	priv->ndev = dev;
22822be45b66SKalle Valo 
22832be45b66SKalle Valo 	/* Report what we've done */
2284bea35f90SColin Ian King 	dev_dbg(priv->dev, "Registered interface %s.\n", dev->name);
22852be45b66SKalle Valo 
22862be45b66SKalle Valo 	return 0;
22872be45b66SKalle Valo 
22882be45b66SKalle Valo  fail:
22892be45b66SKalle Valo 	free_netdev(dev);
22902be45b66SKalle Valo 	return ret;
22912be45b66SKalle Valo }
22922be45b66SKalle Valo EXPORT_SYMBOL(orinoco_if_add);
22932be45b66SKalle Valo 
orinoco_if_del(struct orinoco_private * priv)22942be45b66SKalle Valo void orinoco_if_del(struct orinoco_private *priv)
22952be45b66SKalle Valo {
22962be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
22972be45b66SKalle Valo 
22982be45b66SKalle Valo 	unregister_netdev(dev);
22992be45b66SKalle Valo 	free_netdev(dev);
23002be45b66SKalle Valo }
23012be45b66SKalle Valo EXPORT_SYMBOL(orinoco_if_del);
23022be45b66SKalle Valo 
free_orinocodev(struct orinoco_private * priv)23032be45b66SKalle Valo void free_orinocodev(struct orinoco_private *priv)
23042be45b66SKalle Valo {
23052be45b66SKalle Valo 	struct wiphy *wiphy = priv_to_wiphy(priv);
23062be45b66SKalle Valo 	struct orinoco_rx_data *rx_data, *temp;
23072be45b66SKalle Valo 	struct orinoco_scan_data *sd, *sdtemp;
23082be45b66SKalle Valo 
23092be45b66SKalle Valo 	/* If the tasklet is scheduled when we call tasklet_kill it
23102be45b66SKalle Valo 	 * will run one final time. However the tasklet will only
23112be45b66SKalle Valo 	 * drain priv->rx_list if the hw is still available. */
23122be45b66SKalle Valo 	tasklet_kill(&priv->rx_tasklet);
23132be45b66SKalle Valo 
23142be45b66SKalle Valo 	/* Explicitly drain priv->rx_list */
23152be45b66SKalle Valo 	list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
23162be45b66SKalle Valo 		list_del(&rx_data->list);
23172be45b66SKalle Valo 
23182be45b66SKalle Valo 		dev_kfree_skb(rx_data->skb);
23192be45b66SKalle Valo 		kfree(rx_data->desc);
23202be45b66SKalle Valo 		kfree(rx_data);
23212be45b66SKalle Valo 	}
23222be45b66SKalle Valo 
23232be45b66SKalle Valo 	cancel_work_sync(&priv->process_scan);
23242be45b66SKalle Valo 	/* Explicitly drain priv->scan_list */
23252be45b66SKalle Valo 	list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
23262be45b66SKalle Valo 		list_del(&sd->list);
23272be45b66SKalle Valo 
23282be45b66SKalle Valo 		if (sd->len > 0)
23292be45b66SKalle Valo 			kfree(sd->buf);
23302be45b66SKalle Valo 		kfree(sd);
23312be45b66SKalle Valo 	}
23322be45b66SKalle Valo 
23332be45b66SKalle Valo 	orinoco_unregister_pm_notifier(priv);
23342be45b66SKalle Valo 	orinoco_uncache_fw(priv);
23352be45b66SKalle Valo 
23362be45b66SKalle Valo 	priv->wpa_ie_len = 0;
23372be45b66SKalle Valo 	kfree(priv->wpa_ie);
23382be45b66SKalle Valo 	orinoco_mic_free(priv);
23392be45b66SKalle Valo 	wiphy_free(wiphy);
23402be45b66SKalle Valo }
23412be45b66SKalle Valo EXPORT_SYMBOL(free_orinocodev);
23422be45b66SKalle Valo 
orinoco_up(struct orinoco_private * priv)23432be45b66SKalle Valo int orinoco_up(struct orinoco_private *priv)
23442be45b66SKalle Valo {
23452be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
23462be45b66SKalle Valo 	unsigned long flags;
23472be45b66SKalle Valo 	int err;
23482be45b66SKalle Valo 
23492be45b66SKalle Valo 	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
23502be45b66SKalle Valo 
23512be45b66SKalle Valo 	err = orinoco_reinit_firmware(priv);
23522be45b66SKalle Valo 	if (err) {
23532be45b66SKalle Valo 		printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
23542be45b66SKalle Valo 		       dev->name, err);
23552be45b66SKalle Valo 		goto exit;
23562be45b66SKalle Valo 	}
23572be45b66SKalle Valo 
23582be45b66SKalle Valo 	netif_device_attach(dev);
23592be45b66SKalle Valo 	priv->hw_unavailable--;
23602be45b66SKalle Valo 
23612be45b66SKalle Valo 	if (priv->open && !priv->hw_unavailable) {
23622be45b66SKalle Valo 		err = __orinoco_up(priv);
23632be45b66SKalle Valo 		if (err)
23642be45b66SKalle Valo 			printk(KERN_ERR "%s: Error %d restarting card\n",
23652be45b66SKalle Valo 			       dev->name, err);
23662be45b66SKalle Valo 	}
23672be45b66SKalle Valo 
23682be45b66SKalle Valo exit:
23692be45b66SKalle Valo 	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
23702be45b66SKalle Valo 
23712be45b66SKalle Valo 	return 0;
23722be45b66SKalle Valo }
23732be45b66SKalle Valo EXPORT_SYMBOL(orinoco_up);
23742be45b66SKalle Valo 
orinoco_down(struct orinoco_private * priv)23752be45b66SKalle Valo void orinoco_down(struct orinoco_private *priv)
23762be45b66SKalle Valo {
23772be45b66SKalle Valo 	struct net_device *dev = priv->ndev;
23782be45b66SKalle Valo 	unsigned long flags;
23792be45b66SKalle Valo 	int err;
23802be45b66SKalle Valo 
23812be45b66SKalle Valo 	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
23822be45b66SKalle Valo 	err = __orinoco_down(priv);
23832be45b66SKalle Valo 	if (err)
23842be45b66SKalle Valo 		printk(KERN_WARNING "%s: Error %d downing interface\n",
23852be45b66SKalle Valo 		       dev->name, err);
23862be45b66SKalle Valo 
23872be45b66SKalle Valo 	netif_device_detach(dev);
23882be45b66SKalle Valo 	priv->hw_unavailable++;
23892be45b66SKalle Valo 	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
23902be45b66SKalle Valo }
23912be45b66SKalle Valo EXPORT_SYMBOL(orinoco_down);
23922be45b66SKalle Valo 
23932be45b66SKalle Valo /********************************************************************/
23942be45b66SKalle Valo /* Module initialization                                            */
23952be45b66SKalle Valo /********************************************************************/
23962be45b66SKalle Valo 
23972be45b66SKalle Valo /* Can't be declared "const" or the whole __initdata section will
23982be45b66SKalle Valo  * become const */
23992be45b66SKalle Valo static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
24002be45b66SKalle Valo 	" (David Gibson <hermes@gibson.dropbear.id.au>, "
24012be45b66SKalle Valo 	"Pavel Roskin <proski@gnu.org>, et al)";
24022be45b66SKalle Valo 
init_orinoco(void)24032be45b66SKalle Valo static int __init init_orinoco(void)
24042be45b66SKalle Valo {
24052be45b66SKalle Valo 	printk(KERN_DEBUG "%s\n", version);
24062be45b66SKalle Valo 	return 0;
24072be45b66SKalle Valo }
24082be45b66SKalle Valo 
exit_orinoco(void)24092be45b66SKalle Valo static void __exit exit_orinoco(void)
24102be45b66SKalle Valo {
24112be45b66SKalle Valo }
24122be45b66SKalle Valo 
24132be45b66SKalle Valo module_init(init_orinoco);
24142be45b66SKalle Valo module_exit(exit_orinoco);
2415