From: Denis Vlasenko <vda@ilport.com.ua>

> > Attached is a patch which updates acx. All your changes are
> > included too. allyesconfig build is fixed by unifying
> > PCI and USB modules into one. 'acx_debug' parameter is renamed back
> > to just 'debug' (because all previous versions used it and
> > we don't want to add to user confusion).
> >
> > Please apply.
> >
> > Signed-off-by: Denis Vlasenko <vda@ilport.com.ua>
>
> I missed a spy_offset fix. Updated patch is attached.
> Also it is at
> http://195.66.192.167/linux/acx_patches/linux-2.6.13-mm2acx-2.patch.bz2

Oh no. Yes. I forgot to remove some standalone build aids.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 dev/null                                |    4 
 drivers/net/wireless/Makefile           |    2 
 drivers/net/wireless/tiacx/Changelog    |   62 
 drivers/net/wireless/tiacx/Kconfig      |   30 
 drivers/net/wireless/tiacx/Makefile     |    8 
 drivers/net/wireless/tiacx/acx_config.h |    6 
 drivers/net/wireless/tiacx/acx_func.h   |  178 
 drivers/net/wireless/tiacx/acx_inline.h |    2 
 drivers/net/wireless/tiacx/acx_struct.h |  514 +-
 drivers/net/wireless/tiacx/conv.c       |    6 
 drivers/net/wireless/tiacx/helper.c     | 3888 +----------------
 drivers/net/wireless/tiacx/helper2.c    | 6980 +++++++++++++++++++++++---------
 drivers/net/wireless/tiacx/ioctl.c      |   77 
 drivers/net/wireless/tiacx/pci.c        | 1056 ++--
 drivers/net/wireless/tiacx/setrate.c    |    2 
 drivers/net/wireless/tiacx/usb.c        |  663 ---
 drivers/net/wireless/tiacx/wlan.c       |   17 
 drivers/net/wireless/tiacx/wlan_mgmt.h  |    7 
 18 files changed, 6697 insertions(+), 6805 deletions(-)

diff -puN drivers/net/wireless/Makefile~acx-update drivers/net/wireless/Makefile
--- 25/drivers/net/wireless/Makefile~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/Makefile	Fri Sep  9 17:28:49 2005
@@ -33,7 +33,7 @@ obj-$(CONFIG_PCI_ATMEL)         += atmel
 obj-$(CONFIG_PCMCIA_ATMEL)      += atmel_cs.o
 
 obj-$(CONFIG_PRISM54)		+= prism54/
-obj-$(CONFIG_TIACX)		+= tiacx/
+obj-$(CONFIG_ACX)		+= tiacx/
 obj-$(CONFIG_HOSTAP)		+= hostap/
 
 # 16-bit wireless PCMCIA client drivers
diff -puN drivers/net/wireless/tiacx/acx_config.h~acx-update drivers/net/wireless/tiacx/acx_config.h
--- 25/drivers/net/wireless/tiacx/acx_config.h~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/acx_config.h	Fri Sep  9 17:28:49 2005
@@ -1,4 +1,4 @@
-#define WLAN_RELEASE "v0.3.0"
+#define WLAN_RELEASE "v0.3.4"
 
 /* set to 0 if you don't want any debugging code to be compiled in */
 /* set to 1 if you want some debugging */
@@ -38,3 +38,7 @@
 /* normal (use when bug-free) */
 #define DO_LOCKING 1
 /* else locking is disabled! */
+
+/* 0 - normal mode */
+/* 1 - development/debug: probe for IEs on modprobe */
+#define CMD_DISCOVERY 0
diff -puN drivers/net/wireless/tiacx/acx_func.h~acx-update drivers/net/wireless/tiacx/acx_func.h
--- 25/drivers/net/wireless/tiacx/acx_func.h~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/acx_func.h	Fri Sep  9 17:28:49 2005
@@ -273,8 +273,7 @@ has_only_one_bit(u16 v)
 **
 ** Thus *all* code is either protected by sem or lock, or both.
 **
-** Code which must not run concurrently with IRQ takes lock
-** (since sem is already taken it runs under sem+lock then).
+** Code which must not run concurrently with IRQ takes lock.
 ** Such code is marked with _l_.
 **
 ** This results in the following rules of thumb useful in code review:
@@ -290,8 +289,7 @@ has_only_one_bit(u16 v)
 */
 
 /* These functions *must* be inline or they will break horribly on SPARC, due
- * to its weird semantics for save/restore flags. extern inline should prevent
- * the kernel from linking or module from loading if they are not inlined. */
+ * to its weird semantics for save/restore flags */
 
 #if defined(PARANOID_LOCKING) /* Lock debugging */
 
@@ -302,24 +300,24 @@ void acx_up_debug(wlandevice_t *priv, co
 void acx_lock_unhold(void);
 void acx_sem_unhold(void);
 
-extern inline void
+static inline void
 acx_lock_helper(wlandevice_t *priv, unsigned long *fp, const char* where)
 {
 	acx_lock_debug(priv, where);
 	spin_lock_irqsave(&priv->lock, *fp);
 }
-extern inline void
+static inline void
 acx_unlock_helper(wlandevice_t *priv, unsigned long *fp, const char* where)
 {
 	acx_unlock_debug(priv, where);
 	spin_unlock_irqrestore(&priv->lock, *fp);
 }
-extern inline void
+static inline void
 acx_down_helper(wlandevice_t *priv, const char* where)
 {
 	acx_down_debug(priv, where);
 }
-extern inline void
+static inline void
 acx_up_helper(wlandevice_t *priv, const char* where)
 {
 	acx_up_debug(priv, where);
@@ -358,9 +356,17 @@ acx_up_helper(wlandevice_t *priv, const 
 */
 #define acx_netdev_priv(dev) (void *)((dev)->priv)
 
+/* Can race with rx path (which is not protected by sem):
+** rx -> process_[re]assocresp() -> set_status(ASSOCIATED) -> wake_queue()
+** Can race with tx_complete IRQ:
+** IRQ -> acx_l_clean_tx_desc -> acx_wake_queue
+** Review carefully all callsites */
 static inline void
 acx_stop_queue(netdevice_t *dev, const char *msg)
 {
+	if(netif_queue_stopped(dev))
+		return;
+
 	netif_stop_queue(dev);
 	if (msg)
 		acxlog(L_BUFT, "tx: stop queue %s\n", msg);
@@ -404,51 +410,66 @@ acx_carrier_on(netdevice_t *dev, const c
 		acxlog(L_BUFT, "tx: carrier on %s\n", msg);
 }
 
+/* This function does not need locking UNLESS you call it
+** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
+** wake queue. This can race with stop_queue elsewhere. */
+void acx_set_status(wlandevice_t *priv, u16 status);
+
 
 /***********************************************************************
 ** Communication with firmware
 */
-/* in 1/100 of ms */
-#define CMD_TIMEOUT_MS(n)	((n)*100)
+#define CMD_TIMEOUT_MS(n)	(n)
 #define ACX_CMD_TIMEOUT_DEFAULT	CMD_TIMEOUT_MS(50)
 
 #if ACX_DEBUG
 
 /* We want to log cmd names */
-
-int acx_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd,
-		void *pcmdparam, unsigned paramlen, unsigned timeout,
-		const char* cmdstr);
+int acxpci_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
+int acxusb_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
+static inline int
+acx_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr)
+{
+	if (IS_PCI(priv))
+		return acxpci_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
+	return acxusb_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
+}
 #define acx_s_issue_cmd(priv,cmd,param,len) \
-	acx_s_issue_cmd_timeo_debug(priv,cmd,param,len, \
-				ACX_CMD_TIMEOUT_DEFAULT,#cmd)
+	acx_s_issue_cmd_timeo_debug(priv,cmd,param,len,ACX_CMD_TIMEOUT_DEFAULT,#cmd)
 #define acx_s_issue_cmd_timeo(priv,cmd,param,len,timeo) \
-	acx_s_issue_cmd_timeo_debug(priv,cmd,param,len, \
-				timeo,#cmd)
-int acx_s_configure_debug(wlandevice_t *priv, void *pdr,
-		int type, const char* str);
+	acx_s_issue_cmd_timeo_debug(priv,cmd,param,len,timeo,#cmd)
+int acx_s_configure_debug(wlandevice_t *priv, void *pdr, int type, const char* str);
 #define acx_s_configure(priv,pdr,type) \
 	acx_s_configure_debug(priv,pdr,type,#type)
-int acx_s_interrogate_debug(wlandevice_t *priv, void *pdr,
-		int type, const char* str);
+int acx_s_interrogate_debug(wlandevice_t *priv, void *pdr, int type, const char* str);
 #define acx_s_interrogate(priv,pdr,type) \
 	acx_s_interrogate_debug(priv,pdr,type,#type)
 
 #else
 
-int acx_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd,
-		void *pcmdparam, unsigned paramlen, unsigned timeout);
+int acxpci_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout);
+int acxusb_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout);
+static inline int
+acx_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd,	void *param, unsigned len, unsigned timeout)
+{
+	if (IS_PCI(priv))
+		return acxpci_s_issue_cmd_timeo(priv, cmd, param, len, timeout);
+	return acxusb_s_issue_cmd_timeo(priv, cmd, param, len, timeout);
+}
 static inline int
 acx_s_issue_cmd(wlandevice_t *priv, unsigned cmd, void *param, unsigned len)
 {
-	return acx_s_issue_cmd_timeo(priv, cmd, param, len,
-			ACX_CMD_TIMEOUT_DEFAULT);
+	if (IS_PCI(priv))
+		return acxpci_s_issue_cmd_timeo(priv, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
+	return acxusb_s_issue_cmd_timeo(priv, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
 }
 int acx_s_configure(wlandevice_t *priv, void *pdr, int type);
 int acx_s_interrogate(wlandevice_t *priv, void *pdr, int type);
 
 #endif
 
+/***********************************************************************
+*/
 void acx_s_cmd_join_bssid(wlandevice_t *priv, const u8 *bssid);
 void acx_s_cmd_start_scan(wlandevice_t *priv);
 int acx111_s_get_feature_config(wlandevice_t *priv,
@@ -476,22 +497,14 @@ acx111_s_feature_set(wlandevice_t *priv,
 /***********************************************************************
 ** Ioctls
 */
-int acx_ioctl_dbg_get_io(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra);
-int acx_ioctl_dbg_set_io(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra);
-int acx111_ioctl_info(
+int
+acx111pci_ioctl_info(
 	struct net_device *dev,
 	struct iw_request_info *info,
 	struct iw_param *vwrq,
 	char *extra);
-int acx100_ioctl_set_phy_amp_bias(
+int
+acx100pci_ioctl_set_phy_amp_bias(
 	struct net_device *dev,
 	struct iw_request_info *info,
 	struct iw_param *vwrq,
@@ -501,14 +514,32 @@ int acx100_ioctl_set_phy_amp_bias(
 /***********************************************************************
 ** Unsorted yet :)
 */
+int acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf);
+int acxusb_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf);
+static inline int
+acx_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
+{
+	if (IS_PCI(priv))
+		return acxpci_s_read_phy_reg(priv, reg, charbuf);
+	return acxusb_s_read_phy_reg(priv, reg, charbuf);
+}
+
+int acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value);
+int acxusb_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value);
+static inline int
+acx_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
+{
+	if (IS_PCI(priv))
+		return acxpci_s_write_phy_reg(priv, reg, value);
+	return acxusb_s_write_phy_reg(priv, reg, value);
+}
+
 void acx_s_msleep(int ms);
 int acx_s_init_mac(netdevice_t *dev);
 void acx_set_reg_domain(wlandevice_t *priv, unsigned char reg_dom_id);
-void acx_set_timer(wlandevice_t *priv, u32 time);
+void acx_set_timer(wlandevice_t *priv, int timeout_us);
 void acx_update_capabilities(wlandevice_t *priv);
 int acx_read_eeprom_offset(wlandevice_t *priv, u32 addr, u8 *charbuf);
-int acx_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf);
-int acx_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value);
 void acx_s_start(wlandevice_t *priv);
 #if USE_FW_LOADER_26
 firmware_image_t *acx_s_read_fw(struct device *dev, const char *file, u32 *size);
@@ -533,7 +564,6 @@ void acx_l_sta_list_init(wlandevice_t *p
 client_t *acx_l_sta_list_get(wlandevice_t *priv, const u8 *address);
 void acx_l_sta_list_del(wlandevice_t *priv, client_t *clt);
 
-void acx_set_status(wlandevice_t *priv, u16 status);
 int acx_l_rx_ieee802_11_frame(wlandevice_t *priv, rxbuffer_t *rxbuf);
 int acx_l_transmit_disassoc(wlandevice_t *priv, client_t *clt);
 void acx_i_timer(unsigned long a);
@@ -548,7 +578,7 @@ acx_get_wlan_hdr(wlandevice_t *priv, con
 		return (wlan_hdr_t*)&rxbuf->hdr_a3;
 
 	/* take into account phy header in front of packet */
-	if (CHIPTYPE_ACX111 == priv->chip_type)
+	if (IS_ACX111(priv))
 		return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 8);
 
 	return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 4);
@@ -569,10 +599,36 @@ u8 acx_signal_determine_quality(u8 signa
 void acx_l_process_rxbuf(wlandevice_t *priv, rxbuffer_t *rxbuf);
 void acx_l_process_rx_desc(wlandevice_t *priv);
 
-tx_t* acx_l_alloc_tx(wlandevice_t *priv);
-void* acx_l_get_txbuf(tx_t *tx_opaque);
-/* Misnamed. submit_prepared_tx() */
-void acx_l_dma_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len);
+tx_t* acxpci_l_alloc_tx(wlandevice_t *priv);
+tx_t* acxusb_l_alloc_tx(wlandevice_t *priv);
+static inline tx_t*
+acx_l_alloc_tx(wlandevice_t *priv)
+{
+	if (IS_PCI(priv))
+		return acxpci_l_alloc_tx(priv);
+	return acxusb_l_alloc_tx(priv);
+}
+
+void* acxpci_l_get_txbuf(tx_t *tx_opaque);
+void* acxusb_l_get_txbuf(tx_t *tx_opaque);
+static inline void*
+acx_l_get_txbuf(wlandevice_t *priv, tx_t *tx_opaque)
+{
+	if (IS_PCI(priv))
+		return acxpci_l_get_txbuf(tx_opaque);
+	return acxusb_l_get_txbuf(tx_opaque);
+}
+
+void acxpci_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len);
+void acxusb_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len);
+static inline void
+acx_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len)
+{
+	if (IS_PCI(priv))
+		acxpci_l_tx_data(priv, tx_opaque, len);
+	else
+		acxusb_l_tx_data(priv, tx_opaque, len);
+}
 
 void acx_dump_bytes(const void *, int);
 void acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr);
@@ -591,13 +647,27 @@ static inline const char* acx_get_packet
 #else
 const char* acx_get_packet_type_string(u16 fc);
 #endif
+const char* acx_cmd_status_str(unsigned int state);
 
 int acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev);
-void acx_free_desc_queues(TIWLAN_DC *pDc);
+void acx_free_desc_queues(wlandevice_t *priv);
 
-#ifdef ACX_PCI
-int acx_s_create_tx_host_desc_queue(TIWLAN_DC *pDc);
-int acx_s_create_rx_host_desc_queue(TIWLAN_DC *pDc);
-void acx_s_create_tx_desc_queue(TIWLAN_DC *pDc);
-void acx_create_rx_desc_queue(TIWLAN_DC *pDc);
-#endif
+int acx_s_create_hostdesc_queues(wlandevice_t *priv);
+void acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start);
+
+int acx_s_set_tx_level(wlandevice_t *priv, u8 level_dbm);
+int acx100_s_init_wep(wlandevice_t *priv);
+int acx100_s_init_packet_templates(wlandevice_t *priv);
+int acx111_s_init_packet_templates(wlandevice_t *priv);
+
+void great_inquisistor(wlandevice_t *priv);
+
+char* acxpci_s_proc_diag_output(char *p, wlandevice_t *priv);
+int acx_proc_eeprom_output(char *p, wlandevice_t *priv);
+void acx_set_interrupt_mask(wlandevice_t *priv);
+int acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm);
+
+int __init acxpci_e_init_module(void);
+int __init acxusb_e_init_module(void);
+void __exit acxpci_e_cleanup_module(void);
+void __exit acxusb_e_cleanup_module(void);
diff -puN drivers/net/wireless/tiacx/acx_inline.h~acx-update drivers/net/wireless/tiacx/acx_inline.h
--- 25/drivers/net/wireless/tiacx/acx_inline.h~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/acx_inline.h	Fri Sep  9 17:28:49 2005
@@ -116,4 +116,4 @@ acx_write_flush(wlandevice_t *priv)
 
 #endif
 
-#endif /* CONFIG_TIACX_PCI */
+#endif /* ACX_PCI */
diff -puN drivers/net/wireless/tiacx/acx_struct.h~acx-update drivers/net/wireless/tiacx/acx_struct.h
--- 25/drivers/net/wireless/tiacx/acx_struct.h~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/acx_struct.h	Fri Sep  9 17:28:49 2005
@@ -40,7 +40,6 @@ typedef struct rxdesc rxdesc_t;
 typedef struct txdesc txdesc_t;
 typedef struct rxhostdesc rxhostdesc_t;
 typedef struct txhostdesc txhostdesc_t;
-typedef struct TIWLAN_DC TIWLAN_DC;
 
 
 /***********************************************************************
@@ -115,6 +114,33 @@ enum { acx_debug = 0 };
 #define CHIPTYPE_ACX100		1
 #define CHIPTYPE_ACX111		2
 
+#define IS_ACX100(priv)	((priv)->chip_type == CHIPTYPE_ACX100)
+#define IS_ACX111(priv)	((priv)->chip_type == CHIPTYPE_ACX111)
+
+/* Supported interfaces */
+#define DEVTYPE_PCI		0
+#define DEVTYPE_USB		1
+
+#if defined(CONFIG_ACX_PCI)
+ #if !defined(CONFIG_ACX_USB)
+  #define IS_PCI(priv)	1
+ #else
+  #define IS_PCI(priv)	((priv)->dev_type == DEVTYPE_PCI)
+ #endif
+#else
+ #define IS_PCI(priv)	0
+#endif
+
+#if defined(CONFIG_ACX_USB)
+ #if !defined(CONFIG_ACX_PCI)
+  #define IS_USB(priv)	1
+ #else
+  #define IS_USB(priv)	((priv)->dev_type == DEVTYPE_USB)
+ #endif
+#else
+ #define IS_USB(priv)	0
+#endif
+
 /* Driver defaults */
 #define DEFAULT_DTIM_INTERVAL	10
 /* used to be 2048, but FreeBSD driver changed it to 4096 to work properly
@@ -154,7 +180,7 @@ enum { acx_debug = 0 };
 #define ACX1xx_CMD_CONFIG_TIM		0x0a
 #define ACX1xx_CMD_JOIN			0x0b
 #define ACX1xx_CMD_WEP_MGMT		0x0c
-#if OLD_FIRMWARE_VERSIONS
+#ifdef OLD_FIRMWARE_VERSIONS
 #define ACX100_CMD_HALT			0x0e	/* mapped to unknownCMD in FW150 */
 #else
 #define ACX1xx_CMD_MEM_READ		0x0d
@@ -182,111 +208,152 @@ enum { acx_debug = 0 };
 #define ACX_AFTER_IRQ_RESTART_SCAN	0x40
 
 
-/*============================================================================*
- * Record ID Constants                                                        *
- *============================================================================*/
+/***********************************************************************
+** Interrogate/Configure cmd constants
+**
+** NB: length includes JUST the data part of the IE
+** (does not include size of the (type,len) pair)
+**
+** TODO: seems that acx100, acx100usb, acx111 have some differences,
+** fix code with regard to this!
+*/
+
+#define DEF_IE(name, val, len) enum { ACX##name=val, ACX##name##_LEN=len }
 
 /* Information Elements: Network Parameters, Static Configuration Entities */
 /* these are handled by real_cfgtable in firmware "Rev 1.5.0" (FW150) */
-#define ACX1xx_IE_UNKNOWN_00			0x0000	/* mapped to cfgInvalid in FW150 */
-#define ACX100_IE_ACX_TIMER			0x0001
-#define ACX1xx_IE_POWER_MGMT			0x0002
-#define ACX1xx_IE_QUEUE_CONFIG			0x0003
-#define ACX100_IE_BLOCK_SIZE			0x0004
-#define ACX1xx_IE_MEMORY_CONFIG_OPTIONS		0x0005
-#define ACX1xx_IE_RATE_FALLBACK			0x0006
-#define ACX100_IE_WEP_OPTIONS			0x0007
-#define ACX111_IE_RADIO_BAND			0x0007
-#define ACX1xx_IE_MEMORY_MAP			0x0008	/* huh? */
-#define ACX100_IE_SSID				0x0008	/* huh? */
-#define ACX1xx_IE_SCAN_STATUS			0x0009	/* mapped to cfgInvalid in FW150 */
-#define ACX1xx_IE_ASSOC_ID			0x000a
-#define ACX1xx_IE_UNKNOWN_0B			0x000b	/* mapped to cfgInvalid in FW150 */
-#define ACX100_IE_UNKNOWN_0C			0x000c	/* very small implementation in FW150! */
-#define ACX111_IE_CONFIG_OPTIONS		0x000c
-#define ACX1xx_IE_FWREV				0x000d
-#define ACX1xx_IE_FCS_ERROR_COUNT		0x000e
-#define ACX1xx_IE_MEDIUM_USAGE			0x000f
-#define ACX1xx_IE_RXCONFIG			0x0010
-#define ACX100_IE_UNKNOWN_11			0x0011	/* NONBINARY: large implementation in FW150! link quality readings or so? */
-#define ACX111_IE_QUEUE_THRESH			0x0011
-#define ACX100_IE_UNKNOWN_12			0x0012	/* NONBINARY: VERY large implementation in FW150!! */
-#define ACX111_IE_BSS_POWER_SAVE		0x0012
-#define ACX1xx_IE_FIRMWARE_STATISTICS		0x0013
-#define ACX1xx_IE_FEATURE_CONFIG		0x0015
-#define ACX111_IE_KEY_CHOOSE			0x0016	/* for rekeying */
-#define ACX1xx_IE_DOT11_STATION_ID		0x1001
-#define ACX100_IE_DOT11_UNKNOWN_1002		0x1002	/* mapped to cfgInvalid in FW150 */
-#define ACX111_IE_DOT11_FRAG_THRESH		0x1002	/* mapped to cfgInvalid in FW150 */
-#define ACX100_IE_DOT11_BEACON_PERIOD		0x1003	/* mapped to cfgInvalid in FW150 */
-#define ACX1xx_IE_DOT11_DTIM_PERIOD		0x1004	/* mapped to cfgInvalid in FW150 */
-#define ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT	0x1005
-#define ACX1xx_IE_DOT11_LONG_RETRY_LIMIT	0x1006
-#define ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE	0x1007 /* configure default keys */
-#define ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME	0x1008
-#define ACX1xx_IE_DOT11_GROUP_ADDR		0x1009
-#define ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN	0x100a
-#define ACX1xx_IE_DOT11_CURRENT_ANTENNA		0x100b
-#define ACX1xx_IE_DOT11_UNKNOWN_100C		0x100c	/* mapped to cfgInvalid in FW150 */
-#define ACX1xx_IE_DOT11_TX_POWER_LEVEL		0x100d
-#define ACX1xx_IE_DOT11_CURRENT_CCA_MODE	0x100e
-#define ACX100_IE_DOT11_ED_THRESHOLD		0x100f
-#define ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET	0x1010	/* set default key ID */
-#define ACX100_IE_DOT11_UNKNOWN_1011		0x1011	/* mapped to cfgInvalid in FW150 */
-#define ACX100_IE_DOT11_UNKNOWN_1012		0x1012	/* mapped to cfgInvalid in FW150 */
-#define ACX100_IE_DOT11_UNKNOWN_1013		0x1013	/* mapped to cfgInvalid in FW150 */
-
-/*--- Configuration RID Lengths: Network Params, Static Config Entities -----*/
-/* This is the length of JUST the DATA part of the RID (does not include the
- * len or code fields) */
-
-/* TODO: fill in the rest of these */
-#define ACX100_IE_ACX_TIMER_LEN				0x10
-#define ACX1xx_IE_POWER_MGMT_LEN			0x06
-#define ACX1xx_IE_QUEUE_CONFIG_LEN			0x1c
-#define ACX100_IE_BLOCK_SIZE_LEN			0x02
-#define ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN		0x14
-#define ACX1xx_IE_RATE_FALLBACK_LEN			0x01
-#define ACX100_IE_WEP_OPTIONS_LEN			0x03
-#define ACX1xx_IE_MEMORY_MAP_LEN			0x28
-#define ACX100_IE_SSID_LEN				0x20
-#define ACX1xx_IE_SCAN_STATUS_LEN			0x04
-#define ACX1xx_IE_ASSOC_ID_LEN				0x02
-#define ACX1xx_IE_CONFIG_OPTIONS_LEN			0x14c
-#define ACX1xx_IE_FWREV_LEN				0x18
-#define ACX1xx_IE_FCS_ERROR_COUNT_LEN			0x04
-#define ACX1xx_IE_MEDIUM_USAGE_LEN			0x08
-#define ACX1xx_IE_RXCONFIG_LEN				0x04
-#define ACX1xx_IE_FIRMWARE_STATISTICS_LEN		0x9c
-#define ACX1xx_IE_FEATURE_CONFIG_LEN			0x08
-#define ACX111_IE_KEY_CHOOSE_LEN			0x04	/* really 4?? */
-#define ACX1xx_IE_DOT11_STATION_ID_LEN			0x06
-#define ACX100_IE_DOT11_BEACON_PERIOD_LEN		0x02
-#define ACX1xx_IE_DOT11_DTIM_PERIOD_LEN			0x01
-#define ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN		0x01
-#define ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN		0x01
-#define ACX100_IE_DOT11_WEP_DEFAULT_KEY_LEN		0x20
-#define ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN	0x04
-#define ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN		0x02
-
+DEF_IE(1xx_IE_UNKNOWN_00		,0x0000, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_ACX_TIMER			,0x0001, 0x10);
+DEF_IE(1xx_IE_POWER_MGMT		,0x0002, 0x06);
+DEF_IE(1xx_IE_QUEUE_CONFIG		,0x0003, 0x1c);
+DEF_IE(100_IE_BLOCK_SIZE		,0x0004, 0x02);
+DEF_IE(1xx_IE_MEMORY_CONFIG_OPTIONS	,0x0005, 0x14);
+DEF_IE(1xx_IE_RATE_FALLBACK		,0x0006, 0x01);
+DEF_IE(100_IE_WEP_OPTIONS		,0x0007, 0x03);
+DEF_IE(111_IE_RADIO_BAND		,0x0007, -1);
+DEF_IE(1xx_IE_MEMORY_MAP		,0x0008, 0x28); /* huh? */
+DEF_IE(100_IE_SSID			,0x0008, 0x20); /* huh? */
+DEF_IE(1xx_IE_SCAN_STATUS		,0x0009, 0x04); /* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_ASSOC_ID			,0x000a, 0x02);
+DEF_IE(1xx_IE_UNKNOWN_0B		,0x000b, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_UNKNOWN_0C		,0x000c, -1);	/* very small implementation in FW150! */
+DEF_IE(111_IE_CONFIG_OPTIONS		,0x000c, 0x14c);
+DEF_IE(1xx_IE_FWREV			,0x000d, 0x18);
+DEF_IE(1xx_IE_FCS_ERROR_COUNT		,0x000e, 0x04);
+DEF_IE(1xx_IE_MEDIUM_USAGE		,0x000f, 0x08);
+DEF_IE(1xx_IE_RXCONFIG			,0x0010, 0x04);
+DEF_IE(100_IE_UNKNOWN_11		,0x0011, -1);	/* NONBINARY: large implementation in FW150! link quality readings or so? */
+DEF_IE(111_IE_QUEUE_THRESH		,0x0011, -1);
+DEF_IE(100_IE_UNKNOWN_12		,0x0012, -1);	/* NONBINARY: VERY large implementation in FW150!! */
+DEF_IE(111_IE_BSS_POWER_SAVE		,0x0012, -1);
+DEF_IE(1xx_IE_FIRMWARE_STATISTICS	,0x0013, 0x9c);
+DEF_IE(1xx_IE_FEATURE_CONFIG		,0x0015, 0x08);
+DEF_IE(111_IE_KEY_CHOOSE		,0x0016, 0x04);	/* for rekeying. really len=4?? */
+DEF_IE(1xx_IE_DOT11_STATION_ID		,0x1001, 0x06);
+DEF_IE(100_IE_DOT11_UNKNOWN_1002	,0x1002, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(111_IE_DOT11_FRAG_THRESH		,0x1002, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_DOT11_BEACON_PERIOD	,0x1003, 0x02);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_DOT11_DTIM_PERIOD		,0x1004, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_DOT11_SHORT_RETRY_LIMIT	,0x1005, 0x01);
+DEF_IE(1xx_IE_DOT11_LONG_RETRY_LIMIT	,0x1006, 0x01);
+DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE	,0x1007, 0x20);	/* configure default keys */
+DEF_IE(1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME	,0x1008, 0x04);
+DEF_IE(1xx_IE_DOT11_GROUP_ADDR		,0x1009, -1);
+DEF_IE(1xx_IE_DOT11_CURRENT_REG_DOMAIN	,0x100a, 0x02);
 #ifdef ACX_USB
-#define ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN		0x02
+DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA	,0x100b, 0x01);
 #else
-#define ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN		0x01
+DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA	,0x100b, 0x02);
 #endif
-
-#define ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN		0x01
-
+DEF_IE(1xx_IE_DOT11_UNKNOWN_100C	,0x100c, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_DOT11_TX_POWER_LEVEL	,0x100d, 0x01);
 #ifdef ACX_USB
-#define ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN		0x02
+DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE	,0x100e, 0x01);
 #else
-#define ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN		0x01
+DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE	,0x100e, 0x02);
 #endif
-
 //USB doesn't return anything - len==0?!
-#define ACX100_IE_DOT11_ED_THRESHOLD_LEN		0x04
-
-#define ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN		0x01
+DEF_IE(100_IE_DOT11_ED_THRESHOLD	,0x100f, 0x04);
+DEF_IE(1xx_IE_DOT11_WEP_DEFAULT_KEY_SET	,0x1010, 0x01);	/* set default key ID */
+DEF_IE(100_IE_DOT11_UNKNOWN_1011	,0x1011, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_DOT11_UNKNOWN_1012	,0x1012, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_DOT11_UNKNOWN_1013	,0x1013, -1);	/* mapped to cfgInvalid in FW150 */
+
+#if 0
+/* Experimentally obtained on PCI acx111 Xterasys XN-2522g, fw 1.2.1.34
+** -1 means that fw returned 'invalid IE'
+** 0400 0800 nnnn... are test read contents: u16 type, u16 len, data
+** (AA are poison bytes marking bytes not written by fw) */
+DEF_IE(111_IE_INVAL_00,		0x0000, -1);
+DEF_IE(111_IE_INVAL_01,		0x0001, -1);
+DEF_IE(111_IE_POWER_MGMT,	0x0002, 12);
+/* write only, variable len: 12 + rxqueue_cnt*8 + txqueue_cnt*4: */
+DEF_IE(111_IE_MEMORY_CONFIG,	0x0003, 24);
+DEF_IE(111_IE_BLOCK_SIZE,	0x0004, 8); /* 04000800 AA00AAAA AAAAAAAA */
+/* variable len: 8 + rxqueue_cnt*8 + txqueue_cnt*8: */
+DEF_IE(111_IE_QUEUE_HEAD,	0x0005, 24);
+DEF_IE(111_IE_RATE_FALLBACK,	0x0006, 1);
+/* acx100 name:WEP_OPTIONS */
+/* said to have len:1 (not true, actually returns 12 bytes): */
+DEF_IE(111_IE_RADIO_BAND,	0x0007, 12); /* 07000C00 AAAA1F00 FF03AAAA AAAAAAAA */
+DEF_IE(111_IE_MEMORY_MAP,	0x0008, 48);
+/* said to have len:4, but gives INVAL on read: */
+DEF_IE(111_IE_SCAN_STATUS,	0x0009, -1);
+DEF_IE(111_IE_ASSOC_ID,		0x000a, 2);
+/* write only, len is not known: */
+DEF_IE(111_IE_UNKNOWN_0B,	0x000b, 0);
+/* read only, variable len. I see 67 byte reads: */
+DEF_IE(111_IE_CONFIG_OPTIONS,	0x000c, 67); /* 0C004300 01160500 ... */
+DEF_IE(111_IE_FWREV,		0x000d, 24);
+DEF_IE(111_IE_FCS_ERROR_COUNT,	0x000e, 4);
+DEF_IE(111_IE_MEDIUM_USAGE,	0x000f, 8);
+DEF_IE(111_IE_RXCONFIG,		0x0010, 4);
+DEF_IE(111_IE_QUEUE_THRESH,	0x0011, 12);
+DEF_IE(111_IE_BSS_POWER_SAVE,	0x0012, 1);
+/* read only, variable len. I see 240 byte reads: */
+DEF_IE(111_IE_FIRMWARE_STATISTICS, 0x0013, 240); /* 1300F000 00000000 ... */
+/* said to have len=17. looks like fw pads it to 20: */
+DEF_IE(111_IE_INT_CONFIG,	0x0014, 20); /* 14001400 00000000 00000000 00000000 00000000 00000000 */
+DEF_IE(111_IE_FEATURE_CONFIG,	0x0015, 8);
+/* said to be name:KEY_INDICATOR, len:4, but gives INVAL on read: */
+DEF_IE(111_IE_KEY_CHOOSE,	0x0016, -1);
+/* said to have len:4, but in fact returns 8: */
+DEF_IE(111_IE_MAX_USB_XFR,	0x0017, 8); /* 17000800 00014000 00000000 */
+DEF_IE(111_IE_INVAL_18,		0x0018, -1);
+DEF_IE(111_IE_INVAL_19,		0x0019, -1);
+/* undoc but returns something: */
+/* huh, fw indicates len=20 but uses 4 more bytes in buffer??? */
+DEF_IE(111_IE_UNKNOWN_1A,	0x001A, 20); /* 1A001400 AA00AAAA 0000020F FF030000 00020000 00000007 04000000 */
+
+DEF_IE(111_IE_DOT11_INVAL_0000,			0x1000, -1);
+DEF_IE(111_IE_DOT11_STATION_ID,			0x1001, 6);
+DEF_IE(111_IE_DOT11_FRAG_THRESH,		0x1002, 2);
+/* acx100 only? gives INVAL on read: */
+DEF_IE(111_IE_DOT11_BEACON_PERIOD,		0x1003, -1);
+/* said to be MAX_RECV_MSDU_LIFETIME: */
+DEF_IE(111_IE_DOT11_DTIM_PERIOD,		0x1004, 4);
+DEF_IE(111_IE_DOT11_SHORT_RETRY_LIMIT,		0x1005, 1);
+DEF_IE(111_IE_DOT11_LONG_RETRY_LIMIT,		0x1006, 1);
+/* acx100 only? gives INVAL on read: */
+DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_WRITE,	0x1007, -1);
+DEF_IE(111_IE_DOT11_MAX_XMIT_MSDU_LIFETIME,	0x1008, 4);
+/* undoc but returns something. maybe it's 2 multicast MACs to listen to? */
+DEF_IE(111_IE_DOT11_GROUP_ADDR,			0x1009, 12); /* 09100C00 00000000 00000000 00000000 */
+DEF_IE(111_IE_DOT11_CURRENT_REG_DOMAIN,		0x100a, 1);
+DEF_IE(111_IE_DOT11_CURRENT_ANTENNA,		0x100b, 2);
+DEF_IE(111_IE_DOT11_INVAL_100C,			0x100c, -1);
+DEF_IE(111_IE_DOT11_TX_POWER_LEVEL,		0x100d, 1);
+/* said to have len=1 but gives INVAL on read: */
+DEF_IE(111_IE_DOT11_CURRENT_CCA_MODE,		0x100e, -1);
+/* said to have len=4 but gives INVAL on read: */
+DEF_IE(111_IE_DOT11_ED_THRESHOLD,		0x100f, -1);
+/* set default key ID. write only: */
+DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_SET,	0x1010, 1);
+/* undoc but returns something: */
+DEF_IE(111_IE_DOT11_UNKNOWN_1011,		0x1011, 1); /* 11100100 20 */
+DEF_IE(111_IE_DOT11_INVAL_1012,			0x1012, -1);
+DEF_IE(111_IE_DOT11_INVAL_1013,			0x1013, -1);
+#endif
 
 
 /*============================================================================*
@@ -550,7 +617,7 @@ struct client {
  * Attempts to use acx_ptr without macros result in compile-time errors */
 
 typedef struct {
-	u32	v;
+	u32	v ACX_PACKED;
 } acx_ptr;
 
 #if ACX_DEBUG
@@ -652,6 +719,67 @@ typedef struct {
 #define HOST_INT_FCS_THRESHOLD	0x4000
 #define HOST_INT_UNKNOWN	0x8000
 
+/* Outside of "#ifdef PCI" because USB needs to know sizeof()
+** of txdesc and rxdesc: */
+struct txdesc {
+	acx_ptr	pNextDesc ACX_PACKED;	/* pointer to next txdesc */
+	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
+	acx_ptr	AcxMemPtr ACX_PACKED;			/* 0x08 */
+	u32	tx_time ACX_PACKED;			/* 0x0c */
+	u16	total_length ACX_PACKED;		/* 0x10 */
+	u16	Reserved ACX_PACKED;			/* 0x12 */
+	/* the following 16 bytes do not change when acx100 owns the descriptor */
+	/* we need to add a union here with a *fixed* size of 16,
+	 * since ptrlen AMD64 (8) != ptrlen x86 (4) */
+	union {						/* 0x14 */
+		struct {
+			struct client *txc ACX_PACKED;
+			struct txhostdesc *host_desc ACX_PACKED;
+		} s ACX_PACKED;
+		u32	dummy[4] ACX_PACKED;
+	} fixed_size ACX_PACKED;
+	u8	Ctl_8 ACX_PACKED;			/* 0x24, 8bit value */
+	u8	Ctl2_8 ACX_PACKED;			/* 0x25, 8bit value */
+	u8	error ACX_PACKED;			/* 0x26 */
+	u8	ack_failures ACX_PACKED;		/* 0x27 */
+	u8	rts_failures ACX_PACKED;		/* 0x28 */
+	u8	rts_ok ACX_PACKED;			/* 0x29 */
+	union {
+		struct {
+			u8	rate ACX_PACKED;	/* 0x2a */
+			u8	queue_ctrl ACX_PACKED;	/* 0x2b */
+		} r1 ACX_PACKED;
+		struct {
+			u16	rate111 ACX_PACKED;	/* 0x2a */
+		} r2 ACX_PACKED;
+	} u ACX_PACKED;
+	u32	queue_info ACX_PACKED;			/* 0x2c (acx100, reserved on acx111) */
+};		/* size : 48 = 0x30 */
+/* NB: acx111 txdesc structure is 4 byte larger */
+/* All these 4 extra bytes are reserved. tx alloc code takes them into account */
+
+struct rxdesc {
+	acx_ptr	pNextDesc ACX_PACKED;			/* 0x00 */
+	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
+	acx_ptr	ACXMemPtr ACX_PACKED;			/* 0x08 */
+	u32	rx_time ACX_PACKED;			/* 0x0c */
+	u16	total_length ACX_PACKED;		/* 0x10 */
+	u16	WEP_length ACX_PACKED;			/* 0x12 */
+	u32	WEP_ofs ACX_PACKED;			/* 0x14 */
+
+/* the following 16 bytes do not change when acx100 owns the descriptor */
+	u8	driverWorkspace[16] ACX_PACKED;		/* 0x18 */
+
+	u8	Ctl_8 ACX_PACKED;
+	u8	rate ACX_PACKED;
+	u8	error ACX_PACKED;
+	u8	SNR ACX_PACKED;				/* Signal-to-Noise Ratio */
+	u8	RxLevel ACX_PACKED;
+	u8	queue_ctrl ACX_PACKED;
+	u16	unknown ACX_PACKED;
+	u32	unknown2 ACX_PACKED;
+};		/* size 52 = 0x34 */
+
 #ifdef ACX_PCI
 
 /* Register I/O offsets */
@@ -731,43 +859,6 @@ struct txhostdesc {
 	u8	*data ACX_PACKED;
 };
 
-struct txdesc {
-	acx_ptr	pNextDesc ACX_PACKED;	/* pointer to next txdesc */
-	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
-	acx_ptr	AcxMemPtr ACX_PACKED;			/* 0x08 */
-	u32	tx_time ACX_PACKED;			/* 0x0c */
-	u16	total_length ACX_PACKED;		/* 0x10 */
-	u16	Reserved ACX_PACKED;			/* 0x12 */
-	/* the following 16 bytes do not change when acx100 owns the descriptor */
-	/* we need to add a union here with a *fixed* size of 16,
-	 * since ptrlen AMD64 (8) != ptrlen x86 (4) */
-	union {						/* 0x14 */
-		struct {
-			struct client *txc ACX_PACKED;
-			struct txhostdesc *host_desc ACX_PACKED;
-		} s ACX_PACKED;
-		u32	dummy[4] ACX_PACKED;
-	} fixed_size ACX_PACKED;
-	u8	Ctl_8 ACX_PACKED;			/* 0x24, 8bit value */
-	u8	Ctl2_8 ACX_PACKED;			/* 0x25, 8bit value */
-	u8	error ACX_PACKED;			/* 0x26 */
-	u8	ack_failures ACX_PACKED;		/* 0x27 */
-	u8	rts_failures ACX_PACKED;		/* 0x28 */
-	u8	rts_ok ACX_PACKED;			/* 0x29 */
-	union {
-		struct {
-			u8	rate ACX_PACKED;	/* 0x2a */
-			u8	queue_ctrl ACX_PACKED;	/* 0x2b */
-		} r1 ACX_PACKED;
-		struct {
-			u16	rate111 ACX_PACKED;	/* 0x2a */
-		} r2 ACX_PACKED;
-	} u ACX_PACKED;
-	u32	queue_info ACX_PACKED;			/* 0x2c (acx100, reserved on acx111) */
-};		/* size : 48 = 0x30 */
-/* NB: acx111 txdesc structure is 4 byte larger */
-/* All these 4 extra bytes are reserved. tx alloc code takes them into account */
-
 struct rxhostdesc {
 	acx_ptr	data_phy ACX_PACKED;			/* 0x00 [rxbuffer_t *] */
 	u16	data_offset ACX_PACKED;			/* 0x04 */
@@ -781,73 +872,14 @@ struct rxhostdesc {
 	rxbuffer_t *data ACX_PACKED;
 };
 
-struct rxdesc {
-	acx_ptr	pNextDesc ACX_PACKED;			/* 0x00 */
-	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
-	acx_ptr	ACXMemPtr ACX_PACKED;			/* 0x08 */
-	u32	rx_time ACX_PACKED;			/* 0x0c */
-	u16	total_length ACX_PACKED;		/* 0x10 */
-	u16	WEP_length ACX_PACKED;			/* 0x12 */
-	u32	WEP_ofs ACX_PACKED;			/* 0x14 */
-
-/* the following 16 bytes do not change when acx100 owns the descriptor */
-	u8	driverWorkspace[16] ACX_PACKED;		/* 0x18 */
-
-	u8	Ctl_8 ACX_PACKED;
-	u8	rate ACX_PACKED;
-	u8	error ACX_PACKED;
-	u8	SNR ACX_PACKED;				/* Signal-to-Noise Ratio */
-	u8	RxLevel ACX_PACKED;
-	u8	queue_ctrl ACX_PACKED;
-	u16	unknown ACX_PACKED;
-	u32	unknown2 ACX_PACKED;
-};		/* size 52 = 0x34 */
-
-//TODO: incorporate into wlandevice_t
-struct TIWLAN_DC {
-	wlandevice_t	*priv;
-	/* pointer to the beginning of the card's tx queue pool.
-	   it is relative to the internal memory mapping of the card! */
-	u32		ui32ACXTxQueueStart;
-	/* pointer to the beginning of the card's rx queue pool.
-	   it is relative to the internal memory mapping of the card! */
-	u32		ui32ACXRxQueueStart;
-	/* pointers to tx buffers, tx host descriptors (in host memory)
-	** and tx descrs in device memory */
-	u8		*pTxBufferPool;
-	txhostdesc_t	*pTxHostDescQPool;
-	txdesc_t	*pTxDescQPool;	/* points to PCI-mapped memory */
-	/* same for rx */
-	rxbuffer_t	*pRxBufferPool;
-	rxhostdesc_t	*pRxHostDescQPool;
-	rxdesc_t	*pRxDescQPool;
-	/* physical addresses of above host memory areas */
-	dma_addr_t	RxBufferPoolPhyAddr;
-	dma_addr_t	RxHostDescQPoolPhyAddr;
-	dma_addr_t	TxBufferPoolPhyAddr;
-	dma_addr_t	TxHostDescQPoolPhyAddr;
-	/* sizes of above host memory areas */
-	unsigned int	TxBufferPoolSize;
-	unsigned int	TxHostDescQPoolSize;
-	unsigned int	RxBufferPoolSize;
-	unsigned int	RxHostDescQPoolSize;
-
-	unsigned int	TxDescrSize;		/* size per tx descr; ACX111 = ACX100 + 4 */
-	unsigned int	tx_pool_count;		/* indicates # of ring buffer pool entries */
-	unsigned int	tx_head;		/* current ring buffer pool member index */
-	unsigned int	tx_tail;
-	unsigned int	rx_pool_count;
-	unsigned int	rx_tail;
-};
-
 /* figure out tx descriptor pointer, depending on different acx100 or acx111
  * tx descriptor length */
-#define GET_TX_DESC_PTR(dc, index) \
-	(struct txdesc *) (((u8 *)(dc)->pTxDescQPool) + ((index) * (dc)->TxDescrSize))
-#define GET_NEXT_TX_DESC_PTR(dc, tx_desc) \
-	(struct txdesc *) (((u8 *)(tx_desc)) + (dc)->TxDescrSize)
+#define GET_TX_DESC_PTR(priv, index) \
+	(struct txdesc *) (((u8 *)(priv)->pTxDescQPool) + ((index) * (priv)->TxDescrSize))
+#define GET_NEXT_TX_DESC_PTR(priv, tx_desc) \
+	(struct txdesc *) (((u8 *)(tx_desc)) + (priv)->TxDescrSize)
 
-#endif /* CONFIG_TIACX_PCI */
+#endif /* ACX_PCI */
 
 /***************************************************************
 ** USB structures and constants
@@ -903,7 +935,7 @@ typedef struct usb_tx {
 	usb_txbuffer_t	bulkout;
 } usb_tx_t;
 
-#endif /* CONFIG_TIACX_USB */
+#endif /* ACX_USB */
 
 
 /*============================================================================*
@@ -967,6 +999,7 @@ struct wlandevice {
 
 	/*** Hardware identification ***/
 	const char	*chip_name;
+	u8		dev_type;
 	u8		chip_type;
 	u8		form_factor;
 	u8		radio_type;
@@ -1055,8 +1088,8 @@ struct wlandevice {
 
 	u8		tx_disabled;
 	u8		tx_level_dbm;
-	u8		tx_level_val;
-	u8		tx_level_auto;		/* whether to do automatic power adjustment */
+	/* u8		tx_level_val; */
+	/* u8		tx_level_auto;		whether to do automatic power adjustment */
 
 	unsigned long	recalib_time_last_success;
 	unsigned long	recalib_time_last_attempt;
@@ -1100,6 +1133,7 @@ struct wlandevice {
 	u16		rx_config_2;
 	u32		tx_cnt_done;
 	u16		memblocksize;
+//TODO: rename: xxQueueXx -> xxdesc_xx
 	u32		RxQueueCnt;
 	u32		TxQueueCnt;
 	u32		TxQueueFree;
@@ -1108,12 +1142,44 @@ struct wlandevice {
 	u8		dtim_interval;
 
 /*** PCI/USB/... must be last or else hw agnostic code breaks horribly ***/
+	rxhostdesc_t	*RxHostDescPoolStart; /* hack to let common code compile */
 
 	/*** PCI stuff ***/
 #ifdef ACX_PCI
-	TIWLAN_DC	dc;
-	/* Same as dc.pRxHostDescQPool, but possibly aligned to 4 bytes: */
-	rxhostdesc_t	*RxHostDescPoolStart;
+//TODO: horribly long, Pascal-like names
+//Make up our mind on "Queue? Pool? Desc?" usage and rename:
+//Xx[Host]DescQPool[PhyAddr/Size] -> xx[host]desc_start[_phy], xx[host]desc_size
+//XxBufferPool[PhyAddr/Size] -> xxbuf_start[_phy], xxbuf_size
+//xx_pool_count -> xxdesc_count
+	/* pointers to tx buffers, tx host descriptors (in host memory)
+	** and tx descrs in device memory */
+	u8		*pTxBufferPool;
+	txhostdesc_t	*pTxHostDescQPool;
+	txdesc_t	*pTxDescQPool;	/* points to PCI-mapped memory */
+	/* same for rx */
+	rxbuffer_t	*pRxBufferPool;
+	rxhostdesc_t	*pRxHostDescQPool;
+	rxdesc_t	*pRxDescQPool;
+	/* physical addresses of above host memory areas */
+	dma_addr_t	RxBufferPoolPhyAddr;
+	dma_addr_t	RxHostDescQPoolPhyAddr;
+	dma_addr_t	TxBufferPoolPhyAddr;
+	dma_addr_t	TxHostDescQPoolPhyAddr;
+	/* sizes of above host memory areas */
+	unsigned int	TxBufferPoolSize;
+	unsigned int	TxHostDescQPoolSize;
+	unsigned int	RxBufferPoolSize;
+	unsigned int	RxHostDescQPoolSize;
+
+	unsigned int	TxDescrSize;		/* size per tx descr; ACX111 = ACX100 + 4 */
+	unsigned int	tx_pool_count;		/* indicates # of ring buffer pool entries */
+	unsigned int	tx_head;		/* current ring buffer pool member index */
+	unsigned int	tx_tail;
+	unsigned int	rx_pool_count;
+	unsigned int	rx_tail;
+	/* Same as pRxHostDescQPool, but possibly aligned to 4 bytes: */
+//TODO: rename: xxPoolStart -> xx_start
+	/* rxhostdesc_t	*RxHostDescPoolStart; hack to let common code compile */
 
 	u8		need_radio_fw;
 	u8		irqs_active;	/* whether irq sending is activated */
@@ -1294,21 +1360,22 @@ typedef struct acx100_ie_memblocksize {
 	u16	size ACX_PACKED;
 } acx100_ie_memblocksize_t;
 
+//TODO: Make up our mind on "Queue? Pool? Desc?" usage and rename
 typedef struct acx100_ie_queueconfig {
 	u16	type ACX_PACKED;
 	u16	len ACX_PACKED;
 	u32	AreaSize ACX_PACKED;
 	u32	RxQueueStart ACX_PACKED;
-	u8	QueueOptions ACX_PACKED; /* queue options */
-	u8	NumTxQueues ACX_PACKED;	 /* # tx queues */
+	u8	QueueOptions ACX_PACKED;
+	u8	NumTxQueues ACX_PACKED;
 	u8	NumRxDesc ACX_PACKED;	 /* for USB only */
-	u8	padf2 ACX_PACKED;	 /* # rx buffers */
+	u8	pad1 ACX_PACKED;
 	u32	QueueEnd ACX_PACKED;
 	u32	HostQueueEnd ACX_PACKED; /* QueueEnd2 */
 	u32	TxQueueStart ACX_PACKED;
 	u8	TxQueuePri ACX_PACKED;
 	u8	NumTxDesc ACX_PACKED;
-	u16	pad ACX_PACKED;
+	u16	pad2 ACX_PACKED;
 } acx100_ie_queueconfig_t;
 
 typedef struct acx111_ie_queueconfig {
@@ -1328,7 +1395,7 @@ typedef struct acx100_ie_memconfigoption
 	u16	type ACX_PACKED;
 	u16	len ACX_PACKED;
 	u32	DMA_config ACX_PACKED;
-	u32	pRxHostDesc ACX_PACKED;
+	acx_ptr	pRxHostDesc ACX_PACKED;
 	u32	rx_mem ACX_PACKED;
 	u32	tx_mem ACX_PACKED;
 	u16	RxBlockNum ACX_PACKED;
@@ -1364,6 +1431,7 @@ typedef struct acx111_ie_memoryconfig {
 	/* end of tx1 block */
 } acx111_ie_memoryconfig_t;
 
+//TODO: Make up our mind on "Queue? Pool? Desc?" usage and rename
 typedef struct acx_ie_memmap {
 	u16	type ACX_PACKED;
 	u16	len ACX_PACKED;
@@ -1379,6 +1447,7 @@ typedef struct acx_ie_memmap {
 	u32	PoolEnd ACX_PACKED;
 } acx_ie_memmap_t;
 
+//TODO: rename to acx_ie_xxxx
 typedef struct ACX111FeatureConfig {
 	u16	type ACX_PACKED;
 	u16	len ACX_PACKED;
@@ -1386,16 +1455,13 @@ typedef struct ACX111FeatureConfig {
 	u32	data_flow_options ACX_PACKED;
 } ACX111FeatureConfig_t;
 
+//TODO: rename to acx_ie_xxxx
 typedef struct ACX111TxLevel {
 	u16	type ACX_PACKED;
 	u16	len ACX_PACKED;
 	u8	level ACX_PACKED;
 } ACX111TxLevel_t;
 
-////typedef struct associd {
-////	u16	vala ACX_PACKED;
-////} associd_t;
-
 #define PS_CFG_ENABLE		0x80
 #define PS_CFG_PENDING		0x40 /* status flag when entering PS */
 #define PS_CFG_WAKEUP_MODE_MASK	0x07
@@ -1584,6 +1650,11 @@ typedef struct acx_template_proberesp {
 #define acx_template_beacon_t acx_template_proberesp_t
 #define acx_template_beacon acx_template_proberesp
 
+typedef struct acx_template_nullframe {
+	u16	size ACX_PACKED;
+	struct wlan_hdr_a3 hdr ACX_PACKED;
+} acx_template_nullframe_t;
+
 
 /*
 ** JOIN command structure
@@ -1649,18 +1720,13 @@ typedef struct mem_read_write {
 	u32	data ACX_PACKED;
 } mem_read_write_t;
 
-typedef struct acxp80211_nullframe {
-	u16	size ACX_PACKED;
-	struct wlan_hdr_a3 hdr ACX_PACKED;
-} acxp80211_nullframe_t;
-
-typedef struct {
+typedef struct firmware_image {
 	u32	chksum ACX_PACKED;
 	u32	size ACX_PACKED;
 	u8	data[1] ACX_PACKED; /* the byte array of the actual firmware... */
 } firmware_image_t;
 
-typedef struct {
+typedef struct acx_cmd_radioinit {
 	u32	offset ACX_PACKED;
 	u32	len ACX_PACKED;
 } acx_cmd_radioinit_t;
@@ -1716,7 +1782,6 @@ typedef struct acx_ie_generic {
 	u16	len ACX_PACKED;
 	union {
 		/* struct wep wp ACX_PACKED; */
-		////struct associd asid ACX_PACKED;
 		/* Association ID IE: just a 16bit value: */
 		u16	aid;
 		/* UNUSED? struct defaultkey dkey ACX_PACKED; */
@@ -1798,6 +1863,11 @@ typedef struct acx111_ie_configoption {
 extern const u8 bitpos2ratebyte[];
 extern const u8 bitpos2rate100[];
 
+extern const u8 reg_domain_ids[];
+extern const u8 reg_domain_ids_len;
+
 extern const struct iw_handler_def acx_ioctl_handler_def;
 
+extern char *firmware_dir;
+
 #define MINFREE_TX 3
diff -puN drivers/net/wireless/tiacx/Changelog~acx-update drivers/net/wireless/tiacx/Changelog
--- 25/drivers/net/wireless/tiacx/Changelog~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/Changelog	Fri Sep  9 17:28:49 2005
@@ -1,16 +1,64 @@
+[20050905]
+* TIWLAN_DC is dead, ui32ACX[TR]xQueueStart is dead
+* massive mucking with PCI and USB resulting in:
+  acx_pci.o + acx_usb.o = acx.o  ;)
+  Why? Here's why:
+    text    data     bss     dec     hex filename
+  116199     452      40  116691   1c7d3 acx.o
+  103435     244      20  103699   19513 acx_pci.o
+   81732     196      32   81960   14028 acx_usb.o
+* helper.c is PCI/USB independent now. It was the last one.
+* both modular and non-modular builds, PCI, USB, PCI+USB,
+  seem to compile successfully!
+* version bump to 0.3.4
+
+[20050904]
+* acx_stop_queue() locking reviewed and mostly fixed
+* 2.4isms in USB code are officially dead
+* added debug stuff for discovering interrogate/configure IEs
+* version bump to 0.3.3
+
+[20050903]
+* locking bug on error path fixed
+* issue_cmd() logging made more sane
+* issue_cmd() callers may abstain from printing issue_cmd() errors:
+  issue_cmd() itself gives enough info
+* version bump to 0.3.2
+
+[20050902]
+* kill bogus configure() call in acx100_s_create_dma_regions()
+
+[20050901]
+* acx100_s_create_dma_regions: hopefully fixed for USB
+  (problem found with help of Carlos Martin <carlosmn@gmail.com> - thanks!)
+* a load of cleanups:
+* acx_s_create_tx_desc_queue -> acx_create_tx_desc_queue
+  (it doesn't sleep)
+* struct acxp80211_nullframe -> acx_template_nullframe
+* xXBUFFERCOUNT_ACXnn -> xXBUFCNT_ACXnn
+* xXBUFFERCOUNT_USB -> USB_xXBUFCNT: these are _unrelated_ to xXBUFCNT_ACXnn,
+  should have visibly different names
+* TODOs added (we have a few really Pascalish/Windowish names,
+  and some misleading ones)
+* version bump to 0.3.1
+
+[20050830]
+* finally kill warning about acx_s_activate_power_save_mode()
+* struct acx100_ie_memconfigoption: convert pRxHostDesc to acx_ptr type
+* massive move of device-independent code from helper.c to helper2.c
+
+[20050829]
+* dummy handler for NONERP EID (47) added
+
 [20050823]
 * driver submitted for kernel inclusion
-* modules and config entries got TI prefix added to their names
 * #defines renamed: CONFIG_ACX_{PCI,USB} -> ACX_{PCI,USB}
   (needed for correct compilation of two modules from the same source)
-* debug module parameter renamed to acx_debug (name clash in
-  non-modular build)
-* ACX_DEBUG lowered to 1, PARANOID_LOCKING is off by default now
 * version bump to 0.3.0
 * sizes:
    text    data     bss     dec     hex filename
-  78242     264       8   78514   132b2 drivers/net/wireless/tiacx/tiacx_pci.o
-  60622     208      20   60850    edb2 drivers/net/wireless/tiacx/tiacx_usb.o
+  78242     264       8   78514   132b2 drivers/net/wireless/acx/acx_pci.o
+  60622     208      20   60850    edb2 drivers/net/wireless/acx/acx_usb.o
 
 [20050822]
 * idma.c is incorporated into helper.c
@@ -43,7 +91,7 @@
 [20050814]
 * Auto rate was reset to lowest rate by scanning code
   (AP beacons did it every tenth of a second!). Fixed.
-* USB rx is no longer uses PCI-style rx descriptor ring.
+* USB rx no longer uses PCI-style rx descriptor ring.
   tx ring elimination needs 'single-descriptor' setup
   to be developed for acx100 (patch exists for acx111).
 * Very strange sem locking problems are reported on amd64.
diff -puN drivers/net/wireless/tiacx/conv.c~acx-update drivers/net/wireless/tiacx/conv.c
--- 25/drivers/net/wireless/tiacx/conv.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/conv.c	Fri Sep  9 17:28:49 2005
@@ -249,7 +249,7 @@ acx_l_ether_to_txbuf(wlandevice_t *priv,
 	MAC_COPY(w_hdr->a3, a3);
 	w_hdr->seq = 0;
 
-#if DEBUG_CONVERT
+#ifdef DEBUG_CONVERT
 	if (acx_debug & L_DATA) {
 		printk("original eth frame [%d]: ", skb->len);
 		acx_dump_bytes(skb->data, skb->len);
@@ -327,7 +327,7 @@ acx_rxbuf_to_ether(wlandevice_t *priv, r
 		saddr = w_hdr->a4;
 	}
 
-	if ((WF_FC_ISWEPi & fc) && (CHIPTYPE_ACX100 == priv->chip_type)) {
+	if ((WF_FC_ISWEPi & fc) && IS_ACX100(priv)) {
 		/* chop off the IV+ICV WEP header and footer */
 		acxlog(L_DATA | L_DEBUG, "rx: WEP packet, "
 			"chopping off IV and ICV\n");
@@ -502,7 +502,7 @@ acx_rxbuf_to_ether(wlandevice_t *priv, r
 	skb->dev = priv->netdev;
 	skb->protocol = eth_type_trans(skb, priv->netdev);
 
-#if DEBUG_CONVERT
+#ifdef DEBUG_CONVERT
 	if (acx_debug & L_DATA) {
 		printk("p802.11 frame [%d]: ", RXBUF_BYTES_RCVD(rxbuf));
 		acx_dump_bytes(w_hdr, RXBUF_BYTES_RCVD(rxbuf));
diff -puN drivers/net/wireless/tiacx/helper2.c~acx-update drivers/net/wireless/tiacx/helper2.c
--- 25/drivers/net/wireless/tiacx/helper2.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/helper2.c	Fri Sep  9 17:28:49 2005
@@ -37,6 +37,7 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/netdevice.h>
@@ -76,902 +77,1343 @@ static int acx_l_transmit_authen3(wlande
 static int acx_l_transmit_authen4(wlandevice_t *priv, const wlan_fr_authen_t *req);
 static int acx_l_transmit_assoc_req(wlandevice_t *priv);
 
-static void acx_s_activate_power_save_mode(wlandevice_t *priv, /*@unused@*/ int vala);
+
+/***********************************************************************
+*/
+#if ACX_DEBUG
+unsigned int acx_debug = L_ASSOC|L_INIT;
+#endif
+#if USE_FW_LOADER_LEGACY
+char *firmware_dir;
+#endif
+#if SEPARATE_DRIVER_INSTANCES
+int card;
+#endif
+
+/* introduced earlier than 2.6.10, but takes more memory, so don't use it
+ * if there's no compile warning by kernel */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
+
+#if ACX_DEBUG
+/* parameter is 'debug', corresponding var is acx_debug */
+module_param_named(debug, acx_debug, uint, 0);
+#endif
+#if USE_FW_LOADER_LEGACY
+module_param(firmware_dir, charp, 0);
+#endif
+
+#else
+
+#if ACX_DEBUG
+/* doh, 2.6.x screwed up big time: here the define has its own ";"
+ * ("double ; detected"), yet in 2.4.x it DOESN'T (the sane thing to do),
+ * grrrrr! */
+MODULE_PARM(acx_debug, "i");
+#endif
+#if USE_FW_LOADER_LEGACY
+MODULE_PARM(firmware_dir, "s");
+#endif
+
+#endif
+
+#if ACX_DEBUG
+MODULE_PARM_DESC(debug, "Debug level mask (see L_xxx constants)");
+#endif
+#if USE_FW_LOADER_LEGACY
+MODULE_PARM_DESC(firmware_dir, "Directory to load acx100 firmware files from");
+#endif
+#if SEPARATE_DRIVER_INSTANCES
+MODULE_PARM(card, "i");
+MODULE_PARM_DESC(card, "Associate only with card-th acx100 card from this driver instance");
+#endif
+
+/* Shoundn't be needed now, acx.firmware_dir= should work */
+#if 0 /* USE_FW_LOADER_LEGACY */
+static int __init acx_get_firmware_dir(const char *str)
+{
+	/* I've seen other drivers just pass the string pointer,
+	 * so hopefully that's safe */
+	firmware_dir = str;
+	return OK;
+}
+__setup("acx_firmware_dir=", acx_get_firmware_dir);
+#endif
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("Dual MPL/GPL");
+#endif
+/* USB had this: MODULE_AUTHOR("Martin Wawro <martin.wawro AT uni-dortmund.de>"); */
+MODULE_AUTHOR("ACX100 Open Source Driver development team");
+MODULE_DESCRIPTION("Driver for TI ACX1xx based wireless cards (CardBus/PCI/USB)");
 
 
 /***********************************************************************
 */
-const char*
-acx_get_status_name(u16 status)
+
+/* minutes to wait until next radio recalibration: */
+#define RECALIB_PAUSE	5
+
+const u8 reg_domain_ids[] =
+	{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41, 0x51 };
+/* stupid workaround for the fact that in C the size of an external array
+ * cannot be determined from within a second file */
+const u8 reg_domain_ids_len = sizeof(reg_domain_ids);
+const u16 reg_domain_channel_masks[] =
+	{ 0x07ff, 0x07ff, 0x1fff, 0x0600, 0x1e00, 0x2000, 0x3fff, 0x01fc };
+
+
+/***********************************************************************
+** Debugging support
+*/
+#ifdef PARANOID_LOCKING
+static unsigned max_lock_time;
+static unsigned max_sem_time;
+
+void
+acx_lock_unhold() { max_lock_time = 0; }
+void
+acx_sem_unhold() { max_sem_time = 0; }
+
+static inline const char*
+sanitize_str(const char *s)
 {
-	static const char * const str[] = {
-		"STOPPED", "SCANNING", "WAIT_AUTH",
-		"AUTHENTICATED", "ASSOCIATED", "INVALID??"
-	};
-	return str[(status < VEC_SIZE(str)) ? status : VEC_SIZE(str)-1];
+	const char* t = strrchr(s, '/');
+	if (t) return t + 1;
+	return s;
+}
+
+void
+acx_lock_debug(wlandevice_t *priv, const char* where)
+{
+	int count = 100*1000*1000;
+	where = sanitize_str(where);
+	while (--count) {
+		if (!spin_is_locked(&priv->lock)) break;
+		cpu_relax();
+	}
+	if (!count) {
+		printk(KERN_EMERG "LOCKUP: already taken at %s!\n", priv->last_lock);
+		BUG();
+	}
+	priv->last_lock = where;
+	rdtscl(priv->lock_time);
+}
+void
+acx_unlock_debug(wlandevice_t *priv, const char* where)
+{
+#ifdef SMP
+	if (!spin_is_locked(&priv->lock)) {
+		where = sanitize_str(where);
+		printk(KERN_EMERG "STRAY UNLOCK at %s!\n", where);
+		BUG();
+	}
+#endif
+	if (acx_debug & L_LOCK) {
+		unsigned diff;
+		rdtscl(diff);
+		diff -= priv->lock_time;
+		if (diff > max_lock_time) {
+			where = sanitize_str(where);
+			printk("max lock hold time %d CPU ticks from %s "
+				"to %s\n", diff, priv->last_lock, where);
+			max_lock_time = diff;
+		}
+	}
+}
+void
+acx_down_debug(wlandevice_t *priv, const char* where)
+{
+	int sem_count;
+	int count = 5000/5;
+	where = sanitize_str(where);
+
+	while (--count) {
+		sem_count = atomic_read(&priv->sem.count);
+		if (sem_count) break;
+		msleep(5);
+	}
+	if (!count) {
+		printk(KERN_EMERG "D STATE at %s! last sem at %s\n",
+			where, priv->last_sem);
+		dump_stack();
+	}
+	priv->last_sem = where;
+	priv->sem_time = jiffies;
+	down(&priv->sem);
+	if (acx_debug & L_LOCK) {
+		printk("%s: sem_down %d -> %d\n",
+			where, sem_count, atomic_read(&priv->sem.count));
+	}
+}
+void
+acx_up_debug(wlandevice_t *priv, const char* where)
+{
+	int sem_count = atomic_read(&priv->sem.count);
+	if (sem_count) {
+		where = sanitize_str(where);
+		printk(KERN_EMERG "STRAY UP at %s! sem.count=%d\n", where, sem_count);
+		dump_stack();
+	}
+	if (acx_debug & L_LOCK) {
+		unsigned diff = jiffies - priv->sem_time;
+		if (diff > max_sem_time) {
+			where = sanitize_str(where);
+			printk("max sem hold time %d jiffies from %s "
+				"to %s\n", diff, priv->last_sem, where);
+			max_sem_time = diff;
+		}
+	}
+	up(&priv->sem);
+	if (acx_debug & L_LOCK) {
+		where = sanitize_str(where);
+		printk("%s: sem_up %d -> %d\n",
+			where, sem_count, atomic_read(&priv->sem.count));
+	}
 }
+#endif /* PARANOID_LOCKING */
 
 
-/*----------------------------------------------------------------
-* acx_l_sta_list_init
-*----------------------------------------------------------------*/
+/***********************************************************************
+*/
+#if ACX_DEBUG > 1
+
+static int acx_debug_func_indent;
+#define DEBUG_TSC 0
+#define FUNC_INDENT_INCREMENT 2
+
+#if DEBUG_TSC
+#define TIMESTAMP(d) unsigned long d; rdtscl(d)
+#else
+#define TIMESTAMP(d) unsigned long d = jiffies
+#endif
+
+static const char
+spaces[] = "          " "          "; /* Nx10 spaces */
+
 void
-acx_l_sta_list_init(wlandevice_t *priv)
+log_fn_enter(const char *funcname)
 {
-	FN_ENTER;
-	memset(priv->sta_hash_tab, 0, sizeof(priv->sta_hash_tab));
-	memset(priv->sta_list, 0, sizeof(priv->sta_list));
-	FN_EXIT0;
+	int indent;
+	TIMESTAMP(d);
+
+	indent = acx_debug_func_indent;
+	if (indent >= sizeof(spaces))
+		indent = sizeof(spaces)-1;
+
+	printk("%08lx %s==> %s\n",
+		d,
+		spaces + (sizeof(spaces)-1) - indent,
+		funcname
+	);
+
+	acx_debug_func_indent += FUNC_INDENT_INCREMENT;
 }
+void
+log_fn_exit(const char *funcname)
+{
+	int indent;
+	TIMESTAMP(d);
 
+	acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
 
-/*----------------------------------------------------------------
-* acx_l_sta_list_get_from_hash
-*----------------------------------------------------------------*/
-static inline client_t*
-acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address)
+	indent = acx_debug_func_indent;
+	if (indent >= sizeof(spaces))
+		indent = sizeof(spaces)-1;
+
+	printk("%08lx %s<== %s\n",
+		d,
+		spaces + (sizeof(spaces)-1) - indent,
+		funcname
+	);
+}
+void
+log_fn_exit_v(const char *funcname, int v)
 {
-	return priv->sta_hash_tab[address[5] % VEC_SIZE(priv->sta_hash_tab)];
+	int indent;
+	TIMESTAMP(d);
+
+	acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
+
+	indent = acx_debug_func_indent;
+	if (indent >= sizeof(spaces))
+		indent = sizeof(spaces)-1;
+
+	printk("%08lx %s<== %s: %08X\n",
+		d,
+		spaces + (sizeof(spaces)-1) - indent,
+		funcname,
+		v
+	);
 }
+#endif /* ACX_DEBUG > 1 */
 
 
-/*----------------------------------------------------------------
-* acx_l_sta_list_get
-*----------------------------------------------------------------*/
-client_t*
-acx_l_sta_list_get(wlandevice_t *priv, const u8 *address)
+/***********************************************************************
+** Basically a msleep with logging
+*/
+void
+acx_s_msleep(int ms)
 {
-	client_t *client;
 	FN_ENTER;
-	client = acx_l_sta_list_get_from_hash(priv, address);
-	while (client) {
-		if (mac_is_equal(address, client->address)) {
-			client->mtime = jiffies;
-			break;
-		}
-		client = client->next;
-	}
+	msleep(ms);
 	FN_EXIT0;
-	return client;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_sta_list_del
-*----------------------------------------------------------------*/
-void
-acx_l_sta_list_del(wlandevice_t *priv, client_t *victim)
+/***********************************************************************
+** acx_get_packet_type_string
+*/
+#if ACX_DEBUG
+const char*
+acx_get_packet_type_string(u16 fc)
 {
-	client_t *client, *next;
+	static const char * const mgmt_arr[] = {
+		"MGMT/AssocReq", "MGMT/AssocResp", "MGMT/ReassocReq",
+		"MGMT/ReassocResp", "MGMT/ProbeReq", "MGMT/ProbeResp",
+		"MGMT/UNKNOWN", "MGMT/UNKNOWN", "MGMT/Beacon", "MGMT/ATIM",
+		"MGMT/Disassoc", "MGMT/Authen", "MGMT/Deauthen"
+	};
+	static const char * const ctl_arr[] = {
+		"CTL/PSPoll", "CTL/RTS", "CTL/CTS", "CTL/Ack", "CTL/CFEnd",
+		"CTL/CFEndCFAck"
+	};
+	static const char * const data_arr[] = {
+		"DATA/DataOnly", "DATA/Data CFAck", "DATA/Data CFPoll",
+		"DATA/Data CFAck/CFPoll", "DATA/Null", "DATA/CFAck",
+		"DATA/CFPoll", "DATA/CFAck/CFPoll"
+	};
+	const char *str = "UNKNOWN";
+	u8 fstype = (WF_FC_FSTYPE & fc) >> 4;
+	u8 ctl;
 
-	client = acx_l_sta_list_get_from_hash(priv, victim->address);
-	next = client;
-	/* tricky. next = client on first iteration only,
-	** on all other iters next = client->next */
-	while (next) {
-		if (next == victim) {
-			client->next = victim->next;
-			/* Overkill */
-			memset(victim, 0, sizeof(*victim));
-			break;
-		}
-		client = next;
-		next = client->next;
+	FN_ENTER;
+	switch (WF_FC_FTYPE & fc) {
+	case WF_FTYPE_MGMT:
+		str = "MGMT/UNKNOWN";
+		if (fstype < VEC_SIZE(mgmt_arr))
+			str = mgmt_arr[fstype];
+		break;
+	case WF_FTYPE_CTL:
+		ctl = fstype - 0x0a;
+		str = "CTL/UNKNOWN";
+		if (ctl < VEC_SIZE(ctl_arr))
+			str = ctl_arr[ctl];
+		break;
+	case WF_FTYPE_DATA:
+		str = "DATA/UNKNOWN";
+		if (fstype < VEC_SIZE(data_arr))
+			str = data_arr[fstype];
+		break;
 	}
+	FN_EXIT0;
+	return str;
 }
+#endif
 
 
-/*----------------------------------------------------------------
-* acx_l_sta_list_alloc
-*
-* Never fails - will evict oldest client if needed
-*----------------------------------------------------------------*/
-static client_t*
-acx_l_sta_list_alloc(wlandevice_t *priv)
+/***********************************************************************
+** acx_cmd_status_str
+*/
+const char*
+acx_cmd_status_str(unsigned int state)
 {
-	int i;
-	unsigned long age, oldest_age;
-	client_t *client, *oldest;
+	static const char * const cmd_error_strings[] = {
+		"Idle",
+		"Success",
+		"Unknown Command",
+		"Invalid Information Element",
+		"Channel rejected",
+		"Channel invalid in current regulatory domain",
+		"MAC invalid",
+		"Command rejected (read-only information element)",
+		"Command rejected",
+		"Already asleep",
+		"TX in progress",
+		"Already awake",
+		"Write only",
+		"RX in progress",
+		"Invalid parameter",
+		"Scan in progress",
+		"Failed"
+	};
+	return state < VEC_SIZE(cmd_error_strings) ?
+			cmd_error_strings[state] : "UNKNOWN REASON";
+}
 
-	FN_ENTER;
 
-	oldest = &priv->sta_list[0];
-	oldest_age = 0;
-	for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-		client = &priv->sta_list[i];
+/***********************************************************************
+** maps acx111 tx descr rate field to acx100 one
+*/
+const u8
+bitpos2rate100[] = {
+	RATE100_1	,/* 0 */
+	RATE100_2	,/* 1 */
+	RATE100_5	,/* 2 */
+	RATE100_2	,/* 3, should not happen */
+	RATE100_2	,/* 4, should not happen */
+	RATE100_11	,/* 5 */
+	RATE100_2	,/* 6, should not happen */
+	RATE100_2	,/* 7, should not happen */
+	RATE100_22	,/* 8 */
+	RATE100_2	,/* 9, should not happen */
+	RATE100_2	,/* 10, should not happen */
+	RATE100_2	,/* 11, should not happen */
+	RATE100_2	,/* 12, should not happen */
+	RATE100_2	,/* 13, should not happen */
+	RATE100_2	,/* 14, should not happen */
+	RATE100_2	,/* 15, should not happen */
+};
 
-		if (!client->used) {
-			goto found;
-		} else {
-			age = jiffies - client->mtime;
-			if (oldest_age < age) {
-				oldest_age = age;
-				oldest = client;
-			}
-		}
-	}
-	acx_l_sta_list_del(priv, oldest);
-	client = oldest;
-found:
-	memset(client, 0, sizeof(*client));
-	FN_EXIT0;
-	return client;
+u8
+acx_rate111to100(u16 r) {
+	return bitpos2rate100[highest_bit(r)];
 }
 
 
 /*----------------------------------------------------------------
-* acx_l_sta_list_add
-*
-* Never fails - will evict oldest client if needed
+* acx_l_rxmonitor
+* Called from IRQ context only
 *----------------------------------------------------------------*/
-/* In case we will reimplement it differently... */
-#define STA_LIST_ADD_CAN_FAIL 0
-
-static client_t*
-acx_l_sta_list_add(wlandevice_t *priv, const u8 *address)
+static void
+acx_l_rxmonitor(wlandevice_t *priv, const rxbuffer_t *rxbuf)
 {
-	client_t *client;
-	int index;
+	wlansniffrm_t *msg;
+	struct sk_buff *skb;
+	void *datap;
+	unsigned int skb_len;
+	int payload_offset;
 
 	FN_ENTER;
 
-	client = acx_l_sta_list_alloc(priv);
+	/* we are in big luck: the acx100 doesn't modify any of the fields */
+	/* in the 802.11 frame. just pass this packet into the PF_PACKET */
+	/* subsystem. yeah. */
+	payload_offset = ((u8*)acx_get_wlan_hdr(priv, rxbuf) - (u8*)rxbuf);
+	skb_len = RXBUF_BYTES_USED(rxbuf) - payload_offset;
+
+	/* sanity check */
+	if (skb_len > (WLAN_A4FR_MAXLEN_WEP)) {
+		printk("monitor mode panic: oversized frame!\n");
+		goto end;
+	}
 
-	client->mtime = jiffies;
-	MAC_COPY(client->address, address);
-	client->used = CLIENT_EXIST_1;
-	client->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
-	client->auth_step = 1;
-	/* give some tentative peer rate values
-	** (needed because peer may do auth without probing us first,
-	** thus we'll have no idea of peer's ratevector yet).
-	** Will be overwritten by scanning or assoc code */
-	client->rate_cap = priv->rate_basic;
-	client->rate_cfg = priv->rate_basic;
-	client->rate_cur = 1 << lowest_bit(priv->rate_basic);
+	if (priv->netdev->type == ARPHRD_IEEE80211_PRISM)
+		skb_len += sizeof(*msg);
 
-	index = address[5] % VEC_SIZE(priv->sta_hash_tab);
-	client->next = priv->sta_hash_tab[index];
-	priv->sta_hash_tab[index] = client;
+	/* allocate skb */
+	skb = dev_alloc_skb(skb_len);
+	if (!skb) {
+		printk("%s: no memory for skb (%u bytes)\n",
+				priv->netdev->name, skb_len);
+		goto end;
+	}
 
-	acxlog_mac(L_ASSOC, "sta_list_add: sta=", address, "\n");
+	skb_put(skb, skb_len);
+
+		/* when in raw 802.11 mode, just copy frame as-is */
+	if (priv->netdev->type == ARPHRD_IEEE80211)
+		datap = skb->data;
+	else { /* otherwise, emulate prism header */
+		msg = (wlansniffrm_t*)skb->data;
+		datap = msg + 1;
+
+		msg->msgcode = WLANSNIFFFRM;
+		msg->msglen = sizeof(*msg);
+		strncpy(msg->devname, priv->netdev->name, sizeof(msg->devname)-1);
+		msg->devname[sizeof(msg->devname)-1] = '\0';
+
+		msg->hosttime.did = WLANSNIFFFRM_hosttime;
+		msg->hosttime.status = WLANITEM_STATUS_data_ok;
+		msg->hosttime.len = 4;
+		msg->hosttime.data = jiffies;
+
+		msg->mactime.did = WLANSNIFFFRM_mactime;
+		msg->mactime.status = WLANITEM_STATUS_data_ok;
+		msg->mactime.len = 4;
+		msg->mactime.data = rxbuf->time;
+
+		msg->channel.did = WLANSNIFFFRM_channel;
+		msg->channel.status = WLANITEM_STATUS_data_ok;
+		msg->channel.len = 4;
+		msg->channel.data = priv->channel;
+
+		msg->rssi.did = WLANSNIFFFRM_rssi;
+		msg->rssi.status = WLANITEM_STATUS_no_value;
+		msg->rssi.len = 4;
+		msg->rssi.data = 0;
+
+		msg->sq.did = WLANSNIFFFRM_sq;
+		msg->sq.status = WLANITEM_STATUS_no_value;
+		msg->sq.len = 4;
+		msg->sq.data = 0;
+
+		msg->signal.did = WLANSNIFFFRM_signal;
+		msg->signal.status = WLANITEM_STATUS_data_ok;
+		msg->signal.len = 4;
+		msg->signal.data = rxbuf->phy_snr;
+
+		msg->noise.did = WLANSNIFFFRM_noise;
+		msg->noise.status = WLANITEM_STATUS_data_ok;
+		msg->noise.len = 4;
+		msg->noise.data = rxbuf->phy_level;
+
+		msg->rate.did = WLANSNIFFFRM_rate;
+		msg->rate.status = WLANITEM_STATUS_data_ok;
+		msg->rate.len = 4;
+		msg->rate.data = rxbuf->phy_plcp_signal / 5;
+
+		msg->istx.did = WLANSNIFFFRM_istx;
+		msg->istx.status = WLANITEM_STATUS_data_ok;
+		msg->istx.len = 4;
+		msg->istx.data = 0;	/* tx=0: it's not a tx packet */
+
+		skb_len -= sizeof(*msg);
+
+		msg->frmlen.did = WLANSNIFFFRM_signal;
+		msg->frmlen.status = WLANITEM_STATUS_data_ok;
+		msg->frmlen.len = 4;
+		msg->frmlen.data = skb_len;
+	}
+
+	memcpy(datap, ((unsigned char*)rxbuf)+payload_offset, skb_len);
+
+	skb->dev = priv->netdev;
+	skb->dev->last_rx = jiffies;
+
+	skb->mac.raw = skb->data;
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_80211_RAW);
+	netif_rx(skb);
 
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += skb->len;
+end:
 	FN_EXIT0;
-	return client;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_sta_list_get_or_add
-*
-* Never fails - will evict oldest client if needed
-*----------------------------------------------------------------*/
-static client_t*
-acx_l_sta_list_get_or_add(wlandevice_t *priv, const u8 *address)
+/***********************************************************************
+** Calculate level like the feb 2003 windows driver seems to do
+*/
+u8
+acx_signal_to_winlevel(u8 rawlevel)
 {
-	client_t *client = acx_l_sta_list_get(priv, address);
-	if (!client)
-		client = acx_l_sta_list_add(priv, address);
-	return client;
-}
+	/* u8 winlevel = (u8) (0.5 + 0.625 * rawlevel); */
+	u8 winlevel = ((4 + (rawlevel * 5)) / 8);
 
+	if (winlevel > 100)
+		winlevel = 100;
+	return winlevel;
+}
 
-/*----------------------------------------------------------------
-* acx_set_status
-*
-* This function is called in many atomic regions, must not sleep
-*----------------------------------------------------------------*/
-void
-acx_set_status(wlandevice_t *priv, u16 new_status)
+u8
+acx_signal_determine_quality(u8 signal, u8 noise)
 {
-#define QUEUE_OPEN_AFTER_ASSOC 1 /* this really seems to be needed now */
-	u16 old_status = priv->status;
+	int qual;
 
-	FN_ENTER;
+	qual = (((signal - 30) * 100 / 70) + (100 - noise * 4)) / 2;
 
-	acxlog(L_ASSOC, "%s(%d):%s\n",
-	       __func__, new_status, acx_get_status_name(new_status));
+	if (qual > 100)
+		return 100;
+	if (qual < 0)
+		return 0;
+	return qual;
+}
 
-#if WIRELESS_EXT > 13 /* wireless_send_event() and SIOCGIWSCAN */
-	/* wireless_send_event never sleeps */
-	if (ACX_STATUS_4_ASSOCIATED == new_status) {
-		union iwreq_data wrqu;
 
-		wrqu.data.length = 0;
-		wrqu.data.flags = 0;
-		wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+/***********************************************************************
+** acx_l_process_rxbuf
+**
+** NB: used by USB code also
+*/
+void
+acx_l_process_rxbuf(wlandevice_t *priv, rxbuffer_t *rxbuf)
+{
+	struct wlan_hdr *hdr;
+	unsigned int buf_len;
+	unsigned int qual;
+	u16 fc;
 
-		wrqu.data.length = 0;
-		wrqu.data.flags = 0;
-		MAC_COPY(wrqu.ap_addr.sa_data, priv->bssid);
-		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-		wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+	hdr = acx_get_wlan_hdr(priv, rxbuf);
+	/* length of frame from control field to last byte of FCS */
+	buf_len = RXBUF_BYTES_RCVD(rxbuf);
+	fc = le16_to_cpu(hdr->fc);
+
+	if ( ((WF_FC_FSTYPE & fc) != WF_FSTYPE_BEACON)
+	  || (acx_debug & L_XFER_BEACON)
+	) {
+		acxlog(L_XFER|L_DATA, "rx: %s "
+			"time %u len %u signal %u SNR %u macstat %02X "
+			"phystat %02X phyrate %u status %u\n",
+			acx_get_packet_type_string(fc),
+			le32_to_cpu(rxbuf->time),
+			buf_len,
+			acx_signal_to_winlevel(rxbuf->phy_level),
+			acx_signal_to_winlevel(rxbuf->phy_snr),
+			rxbuf->mac_status,
+			rxbuf->phy_stat_baseband,
+			rxbuf->phy_plcp_signal,
+			priv->status);
+	}
+
+	if (unlikely(acx_debug & L_DATA)) {
+		printk("rx: 802.11 buf[%u]: ", buf_len);
+		acx_dump_bytes(hdr, buf_len);
+	}
+
+	/* FIXME: should check for Rx errors (rxbuf->mac_status?
+	 * discard broken packets - but NOT for monitor!)
+	 * and update Rx packet statistics here */
+
+	if (unlikely(priv->mode == ACX_MODE_MONITOR)) {
+		acx_l_rxmonitor(priv, rxbuf);
+	} else if (likely(buf_len >= WLAN_HDR_A3_LEN)) {
+		acx_l_rx_ieee802_11_frame(priv, rxbuf);
 	} else {
-		union iwreq_data wrqu;
-
-		/* send event with empty BSSID to indicate we're not associated */
-		MAC_ZERO(wrqu.ap_addr.sa_data);
-		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-		wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+		acxlog(L_DEBUG | L_XFER | L_DATA,
+		       "rx: NOT receiving packet (%s): "
+		       "size too small (%u)\n",
+		       acx_get_packet_type_string(fc),
+		       buf_len);
+	}
+
+	/* Now check Rx quality level, AFTER processing packet.
+	 * I tried to figure out how to map these levels to dBm
+	 * values, but for the life of me I really didn't
+	 * manage to get it. Either these values are not meant to
+	 * be expressed in dBm, or it's some pretty complicated
+	 * calculation. */
+
+#ifdef FROM_SCAN_SOURCE_ONLY
+	/* only consider packets originating from the MAC
+	 * address of the device that's managing our BSSID.
+	 * Disable it for now, since it removes information (levels
+	 * from different peers) and slows the Rx path. */
+	if (priv->ap_client
+	 && mac_is_equal(hdr->a2, priv->ap_client->address)) {
+#endif
+		priv->wstats.qual.level = acx_signal_to_winlevel(rxbuf->phy_level);
+		priv->wstats.qual.noise = acx_signal_to_winlevel(rxbuf->phy_snr);
+#ifndef OLD_QUALITY
+		qual = acx_signal_determine_quality(priv->wstats.qual.level,
+				priv->wstats.qual.noise);
+#else
+		qual = (priv->wstats.qual.noise <= 100) ?
+				100 - priv->wstats.qual.noise : 0;
+#endif
+		priv->wstats.qual.qual = qual;
+		priv->wstats.qual.updated = 7; /* all 3 indicators updated */
+#ifdef FROM_SCAN_SOURCE_ONLY
 	}
 #endif
+}
 
-	priv->status = new_status;
 
-	switch (new_status) {
-	case ACX_STATUS_1_SCANNING:
-		priv->scan_retries = 0;
-		/* 2.5s initial scan time
-		 * (used to be 1.5s, but failed to find WEP APs!) */
-		acx_set_timer(priv, 1000000);
-		break;
-	case ACX_STATUS_2_WAIT_AUTH:
-	case ACX_STATUS_3_AUTHENTICATED:
-		priv->auth_or_assoc_retries = 0;
-		acx_set_timer(priv, 1500000); /* 1.5 s */
-		break;
-	}
+/***********************************************************************
+*/
+const char*
+acx_get_status_name(u16 status)
+{
+	static const char * const str[] = {
+		"STOPPED", "SCANNING", "WAIT_AUTH",
+		"AUTHENTICATED", "ASSOCIATED", "INVALID??"
+	};
+	return str[(status < VEC_SIZE(str)) ? status : VEC_SIZE(str)-1];
+}
 
-#if QUEUE_OPEN_AFTER_ASSOC
-	if (new_status == ACX_STATUS_4_ASSOCIATED)	{
-		if (old_status < ACX_STATUS_4_ASSOCIATED) {
-			/* ah, we're newly associated now,
-			 * so let's indicate carrier */
-			acx_carrier_on(priv->netdev, "after association");
-			acx_wake_queue(priv->netdev, "after association");
-		}
-	} else {
-		/* not associated any more, so let's kill carrier */
-		if (old_status >= ACX_STATUS_4_ASSOCIATED) {
-			acx_carrier_off(priv->netdev, "after losing association");
-			acx_stop_queue(priv->netdev, "after losing association");
-		}
+
+/***********************************************************************
+*/
+void
+acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr)
+{
+	acxlog(L_ASSOC, "acx: unknown EID %d in mgmt frame at offset %d\n",
+				ie_ptr->eid, (int) ((u8*)ie_ptr - (u8*)hdr));
+	if (acx_debug & (L_DATA|L_ASSOC)) {
+		printk("frame (%s): ",
+			acx_get_packet_type_string(le16_to_cpu(hdr->fc)));
+		acx_dump_bytes(hdr, len);
 	}
-#endif
-	FN_EXIT0;
 }
 
 
-/*------------------------------------------------------------------------------
- * acx_i_timer
- *
- * Fires up periodically. Used to kick scan/auth/assoc if something goes wrong
- *----------------------------------------------------------------------------*/
+/***********************************************************************
+*/
+#if ACX_DEBUG
 void
-acx_i_timer(unsigned long address)
+acx_dump_bytes(const void *data, int num)
+{
+	const u8* ptr = (const u8*)data;
+
+	if (num <= 0) {
+		printk("\n");
+		return;
+	}
+
+	while (num >= 16) {
+		printk( "%02X %02X %02X %02X %02X %02X %02X %02X "
+			"%02X %02X %02X %02X %02X %02X %02X %02X\n",
+			ptr[0], ptr[1], ptr[2], ptr[3],
+			ptr[4], ptr[5], ptr[6], ptr[7],
+			ptr[8], ptr[9], ptr[10], ptr[11],
+			ptr[12], ptr[13], ptr[14], ptr[15]);
+		num -= 16;
+		ptr += 16;
+	}
+	if (num > 0) {
+		while (--num > 0)
+			printk("%02X ", *ptr++);
+		printk("%02X\n", *ptr);
+	}
+}
+#endif
+
+
+/*----------------------------------------------------------------
+* acx_i_start_xmit
+*
+* Called by network core. Can be called outside of process context.
+*----------------------------------------------------------------*/
+int
+acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev)
 {
+	wlandevice_t *priv = acx_netdev_priv(dev);
+	tx_t *tx;
+	void *txbuf;
 	unsigned long flags;
-	wlandevice_t *priv = (wlandevice_t *)address;
+	int txresult = NOT_OK;
+	int len;
 
 	FN_ENTER;
 
+	if (unlikely(!skb)) {
+		/* indicate success */
+		txresult = OK;
+		goto end_no_unlock;
+	}
+	if (unlikely(!priv)) {
+		goto end_no_unlock;
+	}
+
 	acx_lock(priv, flags);
 
-	acxlog(L_DEBUG|L_ASSOC, "%s: priv->status=%d (%s)\n",
-		__func__, priv->status, acx_get_status_name(priv->status));
+	if (unlikely(!(priv->dev_state_mask & ACX_STATE_IFACE_UP))) {
+		goto end;
+	}
+	if (unlikely(priv->mode == ACX_MODE_OFF)) {
+		goto end;
+	}
+	if (unlikely(acx_queue_stopped(dev))) {
+		acxlog(L_DEBUG, "%s: called when queue stopped\n", __func__);
+		goto end;
+	}
+	if (unlikely(ACX_STATUS_4_ASSOCIATED != priv->status)) {
+		acxlog(L_XFER, "trying to xmit, but not associated yet: "
+			"aborting...\n");
+		/* silently drop the packet, since we're not connected yet */
+		txresult = OK;
+		/* ...but indicate an error nevertheless */
+		priv->stats.tx_errors++;
+		goto end;
+	}
 
-	switch (priv->status) {
-	case ACX_STATUS_1_SCANNING:
-		/* was set to 0 by set_status() */
-		if (++priv->scan_retries < 7) {
-			acx_set_timer(priv, 1000000);
-			/* used to interrogate for scan status.
-			** We rely on SCAN_COMPLETE IRQ instead */
-			acxlog(L_ASSOC, "continuing scan (%d sec)\n",
-					priv->scan_retries);
-		} else {
-			acxlog(L_ASSOC, "stopping scan\n");
-			/* send stop_scan cmd when we leave the interrupt context,
-			 * and make a decision what to do next (COMPLETE_SCAN) */
-			acx_schedule_after_interrupt_task(priv,
-				ACX_AFTER_IRQ_CMD_STOP_SCAN + ACX_AFTER_IRQ_COMPLETE_SCAN);
-		}
-		break;
-	case ACX_STATUS_2_WAIT_AUTH:
-		/* was set to 0 by set_status() */
-		if (++priv->auth_or_assoc_retries < 10) {
-			acxlog(L_ASSOC, "resend authen1 request (attempt %d)\n",
-					priv->auth_or_assoc_retries + 1);
-			acx_l_transmit_authen1(priv);
-		} else {
-			/* time exceeded: fall back to scanning mode */
-			acxlog(L_ASSOC,
-			       "authen1 request reply timeout, giving up\n");
-			/* we are a STA, need to find AP anyhow */
-			acx_set_status(priv, ACX_STATUS_1_SCANNING);
-			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
-		}
-		/* used to be 1500000, but some other driver uses 2.5s */
-		acx_set_timer(priv, 2500000);
-		break;
-	case ACX_STATUS_3_AUTHENTICATED:
-		/* was set to 0 by set_status() */
-		if (++priv->auth_or_assoc_retries < 10) {
-			acxlog(L_ASSOC,	"resend assoc request (attempt %d)\n",
-					priv->auth_or_assoc_retries + 1);
-			acx_l_transmit_assoc_req(priv);
-		} else {
-			/* time exceeded: give up */
-			acxlog(L_ASSOC,
-				"association request reply timeout, giving up\n");
-			/* we are a STA, need to find AP anyhow */
-			acx_set_status(priv, ACX_STATUS_1_SCANNING);
-			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
-		}
-		acx_set_timer(priv, 2500000); /* see above */
-		break;
-	case ACX_STATUS_4_ASSOCIATED:
-	default:
-		break;
+	tx = acx_l_alloc_tx(priv);
+	if (unlikely(!tx)) {
+		printk("%s: start_xmit: txdesc ring is full, dropping tx\n",
+			dev->name);
+		txresult = NOT_OK;
+		goto end;
+	}
+
+	txbuf = acx_l_get_txbuf(priv, tx);
+	if (!txbuf) {
+		/* Card was removed */
+		txresult = NOT_OK;
+		goto end;
+	}
+	len = acx_l_ether_to_txbuf(priv, txbuf, skb);
+	if (len < 0) {
+		/* Error in packet conversion */
+		txresult = NOT_OK;
+		goto end;
 	}
+	acx_l_tx_data(priv, tx, len);
+	dev->trans_start = jiffies;
+
+	txresult = OK;
+	priv->stats.tx_packets++;
+	priv->stats.tx_bytes += skb->len;
 
+end:
 	acx_unlock(priv, flags);
 
-	FN_EXIT0;
+end_no_unlock:
+	if ((txresult == OK) && skb)
+		dev_kfree_skb_any(skb);
+
+	FN_EXIT1(txresult);
+	return txresult;
 }
 
 
-/*------------------------------------------------------------------------------
- * acx_set_timer
- *
- * Sets the 802.11 state management timer's timeout.
- *----------------------------------------------------------------------------*/
-void
-acx_set_timer(wlandevice_t *priv, u32 timeout)
+/***********************************************************************
+** Interrogate/configure commands
+*/
+static const u16
+CtlLength[] = {
+	0,
+	ACX100_IE_ACX_TIMER_LEN,
+	ACX1xx_IE_POWER_MGMT_LEN,
+	ACX1xx_IE_QUEUE_CONFIG_LEN,
+	ACX100_IE_BLOCK_SIZE_LEN,
+	ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN,
+	ACX1xx_IE_RATE_FALLBACK_LEN,
+	ACX100_IE_WEP_OPTIONS_LEN,
+	ACX1xx_IE_MEMORY_MAP_LEN, /*	ACX1xx_IE_SSID_LEN, */
+	0,
+	ACX1xx_IE_ASSOC_ID_LEN,
+	0,
+	ACX111_IE_CONFIG_OPTIONS_LEN,
+	ACX1xx_IE_FWREV_LEN,
+	ACX1xx_IE_FCS_ERROR_COUNT_LEN,
+	ACX1xx_IE_MEDIUM_USAGE_LEN,
+	ACX1xx_IE_RXCONFIG_LEN,
+	0,
+	0,
+	ACX1xx_IE_FIRMWARE_STATISTICS_LEN,
+	0,
+	ACX1xx_IE_FEATURE_CONFIG_LEN,
+	ACX111_IE_KEY_CHOOSE_LEN,
+};
+
+static const u16
+CtlLengthDot11[] = {
+	0,
+	ACX1xx_IE_DOT11_STATION_ID_LEN,
+	0,
+	ACX100_IE_DOT11_BEACON_PERIOD_LEN,
+	ACX1xx_IE_DOT11_DTIM_PERIOD_LEN,
+	ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN,
+	ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN,
+	ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE_LEN,
+	ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN,
+	0,
+	ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN,
+	ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN,
+	0,
+	ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN,
+	ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN,
+	ACX100_IE_DOT11_ED_THRESHOLD_LEN,
+	ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN,
+	0,
+	0,
+	0,
+};
+
+#undef FUNC
+#define FUNC "configure"
+#if !ACX_DEBUG
+int
+acx_s_configure(wlandevice_t *priv, void *pdr, int type)
 {
-	FN_ENTER;
+#else
+int
+acx_s_configure_debug(wlandevice_t *priv, void *pdr, int type, const char* typestr)
+{
+#endif
+	u16 len;
+	int res;
 
-	acxlog(L_DEBUG|L_IRQ, "%s(%u ms)\n", __func__, timeout/1000);
-	if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
-		printk("attempt to set the timer "
-			"when the card interface is not up!\n");
-		goto end;
+	/* TODO implement and check other acx111 commands */
+	if (IS_ACX111(priv) && (type == ACX1xx_IE_DOT11_CURRENT_ANTENNA)) {
+		/* acx111 has differing struct size */
+		acxlog(L_CTL, FUNC"(%s) is not supported "
+			"under acx111 (yet)\n", typestr);
+		return NOT_OK;
 	}
 
-	/* first check if the timer was already initialized, THEN modify it */
-	if (priv->mgmt_timer.function) {
-		mod_timer(&priv->mgmt_timer,
-				jiffies + (timeout * HZ / 1000000));
+	if (type < 0x1000)
+		len = CtlLength[type];
+	else
+		len = CtlLengthDot11[type - 0x1000];
+
+	acxlog(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
+	if (unlikely(!len)) {
+		acxlog(L_DEBUG, "zero-length type %s?!\n", typestr);
+	}
+
+	((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
+	((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
+	res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIGURE, pdr, len + 4);
+	if (OK != res) {
+#if ACX_DEBUG
+		printk("%s: "FUNC"(type:%s) FAILED\n", priv->netdev->name, typestr);
+#else
+		printk("%s: "FUNC"(type:0x%X) FAILED\n", priv->netdev->name, type);
+#endif
+		/* dump_stack() is already done in issue_cmd() */
 	}
-end:
-	FN_EXIT0;
+	return res;
 }
 
-
-/*------------------------------------------------------------------------------
- * acx_l_rx_ieee802_11_frame
- *
- * Called from IRQ context only
- * STATUS: FINISHED, UNVERIFIED.
- *----------------------------------------------------------------------------*/
+#undef FUNC
+#define FUNC "interrogate"
+#if !ACX_DEBUG
 int
-acx_l_rx_ieee802_11_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
+acx_s_interrogate(wlandevice_t *priv, void *pdr, int type)
 {
-	unsigned int ftype, fstype;
-	const wlan_hdr_t *hdr;
-	int result = NOT_OK;
+#else
+int
+acx_s_interrogate_debug(wlandevice_t *priv, void *pdr, int type,
+		const char* typestr)
+{
+#endif
+	u16 len;
+	int res;
 
-	FN_ENTER;
+	if (type < 0x1000)
+		len = CtlLength[type];
+	else
+		len = CtlLengthDot11[type-0x1000];
+	acxlog(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
+
+	((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
+	((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
+	res = acx_s_issue_cmd(priv, ACX1xx_CMD_INTERROGATE, pdr, len + 4);
+	if (OK != res) {
+#if ACX_DEBUG
+		printk("%s: "FUNC"(type:%s) FAILED\n", priv->netdev->name, typestr);
+#else
+		printk("%s: "FUNC"(type:0x%X) FAILED\n", priv->netdev->name, type);
+#endif
+		/* dump_stack() is already done in issue_cmd() */
+	}
+	return res;
+}
 
-	hdr = acx_get_wlan_hdr(priv, rxbuf);
+#if CMD_DISCOVERY
+void
+great_inquisistor(wlandevice_t *priv)
+{
+	static struct {
+		u16	type ACX_PACKED;
+		u16	len ACX_PACKED;
+		/* 0x200 was too large here: */
+		u8	data[0x100 - 4] ACX_PACKED;
+	} ie;
+	u16 type;
 
-	/* see IEEE 802.11-1999.pdf chapter 7 "MAC frame formats" */
-	if ((hdr->fc & WF_FC_PVERi) != 0) {
-		printk_ratelimited(KERN_INFO "rx: unsupported 802.11 protocol\n");
-		goto end;
+	FN_ENTER;
+
+	/* 0..0x20, 0x1000..0x1020 */
+	for (type = 0; type <= 0x1020; type++) {
+		if (type == 0x21)
+			type = 0x1000;
+		ie.type = cpu_to_le16(type);
+		ie.len = cpu_to_le16(sizeof(ie) - 4);
+		acx_s_issue_cmd(priv, ACX1xx_CMD_INTERROGATE, &ie, sizeof(ie));
 	}
+	FN_EXIT0;
+}
+#endif
 
-	ftype = hdr->fc & WF_FC_FTYPEi;
-	fstype = hdr->fc & WF_FC_FSTYPEi;
+/***********************************************************************
+** acx_l_update_ratevector
+**
+** Updates priv->rate_supported[_len] according to rate_{basic,oper}
+*/
+const u8
+bitpos2ratebyte[] = {
+	DOT11RATEBYTE_1,
+	DOT11RATEBYTE_2,
+	DOT11RATEBYTE_5_5,
+	DOT11RATEBYTE_6_G,
+	DOT11RATEBYTE_9_G,
+	DOT11RATEBYTE_11,
+	DOT11RATEBYTE_12_G,
+	DOT11RATEBYTE_18_G,
+	DOT11RATEBYTE_22,
+	DOT11RATEBYTE_24_G,
+	DOT11RATEBYTE_36_G,
+	DOT11RATEBYTE_48_G,
+	DOT11RATEBYTE_54_G,
+};
 
-	switch (ftype) {
-	/* check data frames first, for speed */
-	case WF_FTYPE_DATAi:
-		switch (fstype) {
-		case WF_FSTYPE_DATAONLYi:
-		/* FIXME: will fail if two peers send 2 streams of DUPs */
-			if (priv->dup_count
-			 && time_after(jiffies, priv->dup_msg_expiry)) {
-				printk(KERN_INFO "%s: rx: %d DUPs received in 10 secs\n",
-					priv->netdev->name, priv->dup_count);
-				priv->dup_count = 0;
-			}
-			if (unlikely(hdr->seq == priv->last_seq_ctrl)) {
-				if (!priv->dup_count++)
-					priv->dup_msg_expiry = jiffies + 10*HZ;
-				/* simply discard it and indicate error */
-				priv->stats.rx_errors++;
-				break;
-			}
-			priv->last_seq_ctrl = hdr->seq; /* le_to_cpu? */
+void
+acx_l_update_ratevector(wlandevice_t *priv)
+{
+	u16 bcfg = priv->rate_basic;
+	u16 ocfg = priv->rate_oper;
+	u8 *supp = priv->rate_supported;
+	const u8 *dot11 = bitpos2ratebyte;
 
-			/* TODO:
-			if (WF_FC_FROMTODSi == (hdr->fc & WF_FC_FROMTODSi)) {
-				result = acx_l_process_data_frame_wds(priv, rxbuf);
-				break;
-			}
-			*/
+	FN_ENTER;
 
-			switch (priv->mode) {
-			case ACX_MODE_3_AP:
-				result = acx_l_process_data_frame_master(priv, rxbuf);
-				break;
-			case ACX_MODE_0_ADHOC:
-			case ACX_MODE_2_STA:
-				result = acx_l_process_data_frame_client(priv, rxbuf);
-				break;
+	while (ocfg) {
+		if (ocfg & 1) {
+			*supp = *dot11;
+			if (bcfg & 1) {
+				*supp |= 0x80;
 			}
-		case WF_FSTYPE_DATA_CFACKi:
-		case WF_FSTYPE_DATA_CFPOLLi:
-		case WF_FSTYPE_DATA_CFACK_CFPOLLi:
-		case WF_FSTYPE_CFPOLLi:
-		case WF_FSTYPE_CFACK_CFPOLLi:
-		/*   see above.
-			acx_process_class_frame(priv, rxbuf, 3); */
-			break;
-		case WF_FSTYPE_NULLi:
-			/* acx_l_process_NULL_frame(priv, rxbuf, 3); */
-			break;
-		/* FIXME: same here, see above */
-		case WF_FSTYPE_CFACKi:
-		default:
-			break;
+			supp++;
 		}
-		break;
-	case WF_FTYPE_MGMTi:
-		result = acx_l_process_mgmt_frame(priv, rxbuf);
-		break;
-	case WF_FTYPE_CTLi:
-		if (fstype == WF_FSTYPE_PSPOLLi)
-			result = OK;
-		/*   this call is irrelevant, since
-		 *   acx_process_class_frame is a stub, so return
-		 *   immediately instead.
-		 * return acx_process_class_frame(priv, rxbuf, 3); */
-		break;
-	default:
-		break;
+		dot11++;
+		ocfg >>= 1;
+		bcfg >>= 1;
 	}
-end:
-	FN_EXIT1(result);
-	return result;
+	priv->rate_supported_len = supp - priv->rate_supported;
+	if (acx_debug & L_ASSOC) {
+		printk("new ratevector: ");
+		acx_dump_bytes(priv->rate_supported, priv->rate_supported_len);
+	}
+	FN_EXIT0;
 }
 
 
 /*----------------------------------------------------------------
-* acx_l_transmit_assocresp
-*
-* We are an AP here
+* acx_l_sta_list_init
 *----------------------------------------------------------------*/
-static const u8
-dot11ratebyte[] = {
-	DOT11RATEBYTE_1,
-	DOT11RATEBYTE_2,
-	DOT11RATEBYTE_5_5,
-	DOT11RATEBYTE_6_G,
-	DOT11RATEBYTE_9_G,
-	DOT11RATEBYTE_11,
-	DOT11RATEBYTE_12_G,
-	DOT11RATEBYTE_18_G,
-	DOT11RATEBYTE_22,
-	DOT11RATEBYTE_24_G,
-	DOT11RATEBYTE_36_G,
-	DOT11RATEBYTE_48_G,
-	DOT11RATEBYTE_54_G,
-};
-
-static int
-find_pos(const u8 *p, int size, u8 v)
+void
+acx_l_sta_list_init(wlandevice_t *priv)
 {
-	int i;
-	for (i = 0; i < size; i++)
-		if (p[i] == v)
-			return i;
-	/* printk a message about strange byte? */
-	return 0;
+	FN_ENTER;
+	memset(priv->sta_hash_tab, 0, sizeof(priv->sta_hash_tab));
+	memset(priv->sta_list, 0, sizeof(priv->sta_list));
+	FN_EXIT0;
 }
 
-static void
-add_bits_to_ratemasks(u8* ratevec, int len, u16* brate, u16* orate)
+
+/*----------------------------------------------------------------
+* acx_l_sta_list_get_from_hash
+*----------------------------------------------------------------*/
+static inline client_t*
+acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address)
 {
-	while (len--) {
-		int n = 1 << find_pos(dot11ratebyte,
-				sizeof(dot11ratebyte), *ratevec & 0x7f);
-		if (*ratevec & 0x80)
-			*brate |= n;
-		*orate |= n;
-		ratevec++;
-	}
+	return priv->sta_hash_tab[address[5] % VEC_SIZE(priv->sta_hash_tab)];
 }
 
-static int
-acx_l_transmit_assocresp(wlandevice_t *priv, const wlan_fr_assocreq_t *req)
-{
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct assocresp_frame_body *body;
-	u8 *p;
-	const u8 *da;
-	/* const u8 *sa; */
-	const u8 *bssid;
-	client_t *clt;
 
+/*----------------------------------------------------------------
+* acx_l_sta_list_get
+*----------------------------------------------------------------*/
+client_t*
+acx_l_sta_list_get(wlandevice_t *priv, const u8 *address)
+{
+	client_t *client;
 	FN_ENTER;
-
-	/* sa = req->hdr->a1; */
-	da = req->hdr->a2;
-	bssid = req->hdr->a3;
-
-	clt = acx_l_sta_list_get(priv, da);
-	if (!clt)
-		goto ok;
-
-	/* Assoc without auth is a big no-no */
-	/* Let's be liberal: if already assoc'ed STA sends assoc req again,
-	** we won't be rude */
-	if (clt->used != CLIENT_AUTHENTICATED_2
-	 && clt->used != CLIENT_ASSOCIATED_3) {
-		acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
-		goto bad;
-	}
-
-	clt->used = CLIENT_ASSOCIATED_3;
-
-	if (clt->aid == 0) {
-		clt->aid = ++priv->aid;
+	client = acx_l_sta_list_get_from_hash(priv, address);
+	while (client) {
+		if (mac_is_equal(address, client->address)) {
+			client->mtime = jiffies;
+			break;
+		}
+		client = client->next;
 	}
-	clt->cap_info = ieee2host16(*(req->cap_info));
-	/* We cheat here a bit. We don't really care which rates are flagged
-	** as basic by the client, so we stuff them in single ratemask */
-	clt->rate_cap = 0;
-	if (req->supp_rates)
-		add_bits_to_ratemasks(req->supp_rates->rates,
-			req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
-	if (req->ext_rates)
-		add_bits_to_ratemasks(req->ext_rates->rates,
-			req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
-	/* We can check that client supports all basic rates,
-	** and deny assoc if not. But let's be liberal, right? ;) */
-	clt->rate_cfg = clt->rate_cap & priv->rate_oper;
-	if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
-	clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
-	clt->fallback_count = clt->stepup_count = 0;
-	clt->ignore_count = 16;
-
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto bad;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto bad;
-	body = (void*)(head + 1);
+	FN_EXIT0;
+	return client;
+}
 
-	head->fc = WF_FSTYPE_ASSOCRESPi;
-	head->dur = req->hdr->dur;
-	MAC_COPY(head->da, da);
-	/* MAC_COPY(head->sa, sa); */
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, bssid);
-	head->seq = req->hdr->seq;
 
-	body->cap_info = host2ieee16(priv->capabilities);
-	body->status = host2ieee16(0);
-	body->aid = host2ieee16(clt->aid);
-	p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
-							priv->rate_supported);
-	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
-							priv->rate_supported);
+/*----------------------------------------------------------------
+* acx_l_sta_list_del
+*----------------------------------------------------------------*/
+void
+acx_l_sta_list_del(wlandevice_t *priv, client_t *victim)
+{
+	client_t *client, *next;
 
-	acx_l_dma_tx_data(priv, tx, p - (u8*)head);
-ok:
-	FN_EXIT1(OK);
-	return OK;
-bad:
-	FN_EXIT1(NOT_OK);
-	return NOT_OK;
+	client = acx_l_sta_list_get_from_hash(priv, victim->address);
+	next = client;
+	/* tricky. next = client on first iteration only,
+	** on all other iters next = client->next */
+	while (next) {
+		if (next == victim) {
+			client->next = victim->next;
+			/* Overkill */
+			memset(victim, 0, sizeof(*victim));
+			break;
+		}
+		client = next;
+		next = client->next;
+	}
 }
 
 
 /*----------------------------------------------------------------
-* acx_l_transmit_reassocresp
-
-You may be wondering, just like me, what a hell is ReAuth.
-In practice it was seen sent by STA when STA feels like losing connection.
+* acx_l_sta_list_alloc
+*
+* Never fails - will evict oldest client if needed
+*----------------------------------------------------------------*/
+static client_t*
+acx_l_sta_list_alloc(wlandevice_t *priv)
+{
+	int i;
+	unsigned long age, oldest_age;
+	client_t *client, *oldest;
 
-[802.11]
+	FN_ENTER;
 
-5.4.2.3 Reassociation
+	oldest = &priv->sta_list[0];
+	oldest_age = 0;
+	for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
+		client = &priv->sta_list[i];
 
-Association is sufficient for no-transition message delivery between
-IEEE 802.11 stations. Additional functionality is needed to support
-BSS-transition mobility. The additional required functionality
-is provided by the reassociation service. Reassociation is a DSS.
-The reassociation service is invoked to ÒmoveÓ a current association
-from one AP to another. This keeps the DS informed of the current
-mapping between AP and STA as the station moves from BSS to BSS within
-an ESS. Reassociation also enables changing association attributes
-of an established association while the STA remains associated with
-the same AP. Reassociation is always initiated by the mobile STA.
+		if (!client->used) {
+			goto found;
+		} else {
+			age = jiffies - client->mtime;
+			if (oldest_age < age) {
+				oldest_age = age;
+				oldest = client;
+			}
+		}
+	}
+	acx_l_sta_list_del(priv, oldest);
+	client = oldest;
+found:
+	memset(client, 0, sizeof(*client));
+	FN_EXIT0;
+	return client;
+}
 
-5.4.3.1 Authentication
-...
-A STA may be authenticated with many other STAs at any given instant.
 
-5.4.3.1.1 Preauthentication
+/*----------------------------------------------------------------
+* acx_l_sta_list_add
+*
+* Never fails - will evict oldest client if needed
+*----------------------------------------------------------------*/
+/* In case we will reimplement it differently... */
+#define STA_LIST_ADD_CAN_FAIL 0
 
-Because the authentication process could be time-consuming (depending
-on the authentication protocol in use), the authentication service can
-be invoked independently of the association service. Preauthentication
-is typically done by a STA while it is already associated with an AP
-(with which it previously authenticated). IEEE 802.11 does not require
-that STAs preauthenticate with APs. However, authentication is required
-before an association can be established. If the authentication is left
-until reassociation time, this may impact the speed with which a STA can
-reassociate between APs, limiting BSS-transition mobility performance.
-The use of preauthentication takes the authentication service overhead
-out of the time-critical reassociation process.
+static client_t*
+acx_l_sta_list_add(wlandevice_t *priv, const u8 *address)
+{
+	client_t *client;
+	int index;
 
-5.7.3 Reassociation
+	FN_ENTER;
 
-For a STA to reassociate, the reassociation service causes the following
-message to occur:
+	client = acx_l_sta_list_alloc(priv);
 
-  Reassociation request
+	client->mtime = jiffies;
+	MAC_COPY(client->address, address);
+	client->used = CLIENT_EXIST_1;
+	client->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
+	client->auth_step = 1;
+	/* give some tentative peer rate values
+	** (needed because peer may do auth without probing us first,
+	** thus we'll have no idea of peer's ratevector yet).
+	** Will be overwritten by scanning or assoc code */
+	client->rate_cap = priv->rate_basic;
+	client->rate_cfg = priv->rate_basic;
+	client->rate_cur = 1 << lowest_bit(priv->rate_basic);
 
-* Message type: Management
-* Message subtype: Reassociation request
-* Information items:
-  - IEEE address of the STA
-  - IEEE address of the AP with which the STA will reassociate
-  - IEEE address of the AP with which the STA is currently associated
-  - ESSID
-* Direction of message: From STA to 'new' AP
+	index = address[5] % VEC_SIZE(priv->sta_hash_tab);
+	client->next = priv->sta_hash_tab[index];
+	priv->sta_hash_tab[index] = client;
 
-The address of the current AP is included for efficiency. The inclusion
-of the current AP address facilitates MAC reassociation to be independent
-of the DS implementation.
+	acxlog_mac(L_ASSOC, "sta_list_add: sta=", address, "\n");
 
-  Reassociation response
-* Message type: Management
-* Message subtype: Reassociation response
-* Information items:
-  - Result of the requested reassociation. (success/failure)
-  - If the reassociation is successful, the response shall include the AID.
-* Direction of message: From AP to STA
+	FN_EXIT0;
+	return client;
+}
 
-7.2.3.6 Reassociation Request frame format
 
-The frame body of a management frame of subtype Reassociation Request
-contains the information shown in Table 9.
+/*----------------------------------------------------------------
+* acx_l_sta_list_get_or_add
+*
+* Never fails - will evict oldest client if needed
+*----------------------------------------------------------------*/
+static client_t*
+acx_l_sta_list_get_or_add(wlandevice_t *priv, const u8 *address)
+{
+	client_t *client = acx_l_sta_list_get(priv, address);
+	if (!client)
+		client = acx_l_sta_list_add(priv, address);
+	return client;
+}
 
-Table 9 Reassociation Request frame body
-Order Information
-1 Capability information
-2 Listen interval
-3 Current AP address
-4 SSID
-5 Supported rates
 
-7.2.3.7 Reassociation Response frame format
+/***********************************************************************
+** acx_set_status
+**
+** This function is called in many atomic regions, must not sleep
+**
+** This function does not need locking UNLESS you call it
+** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
+** wake queue. This can race with stop_queue elsewhere.
+** See acx_stop_queue comment. */
+void
+acx_set_status(wlandevice_t *priv, u16 new_status)
+{
+#define QUEUE_OPEN_AFTER_ASSOC 1 /* this really seems to be needed now */
+	u16 old_status = priv->status;
 
-The frame body of a management frame of subtype Reassociation Response
-contains the information shown in Table 10.
+	FN_ENTER;
 
-Table 10 Reassociation Response frame body
-Order Information
-1 Capability information
-2 Status code
-3 Association ID (AID)
-4 Supported rates
+	acxlog(L_ASSOC, "%s(%d):%s\n",
+	       __func__, new_status, acx_get_status_name(new_status));
 
-*----------------------------------------------------------------*/
-static int
-acx_l_transmit_reassocresp(wlandevice_t *priv, const wlan_fr_reassocreq_t *req)
-{
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct reassocresp_frame_body *body;
-	u8 *p;
-	const u8 *da;
-	/* const u8 *sa; */
-	const u8 *bssid;
-	client_t *clt;
+#if WIRELESS_EXT > 13 /* wireless_send_event() and SIOCGIWSCAN */
+	/* wireless_send_event never sleeps */
+	if (ACX_STATUS_4_ASSOCIATED == new_status) {
+		union iwreq_data wrqu;
 
-	FN_ENTER;
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
 
-	/* sa = req->hdr->a1; */
-	da = req->hdr->a2;
-	bssid = req->hdr->a3;
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		MAC_COPY(wrqu.ap_addr.sa_data, priv->bssid);
+		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+		wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+	} else {
+		union iwreq_data wrqu;
 
-	/* Must be already authenticated, so it must be in the list */
-	clt = acx_l_sta_list_get(priv, da);
-	if (!clt)
-		goto ok;
+		/* send event with empty BSSID to indicate we're not associated */
+		MAC_ZERO(wrqu.ap_addr.sa_data);
+		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+		wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+	}
+#endif
 
-	/* Assoc without auth is a big no-no */
-	/* Already assoc'ed STAs sending ReAssoc req are ok per 802.11 */
-	if (clt->used != CLIENT_AUTHENTICATED_2
-	 && clt->used != CLIENT_ASSOCIATED_3) {
-		acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
-		goto bad;
+	priv->status = new_status;
+
+	switch (new_status) {
+	case ACX_STATUS_1_SCANNING:
+		priv->scan_retries = 0;
+		/* 1.0 s initial scan time */
+		acx_set_timer(priv, 1000000);
+		break;
+	case ACX_STATUS_2_WAIT_AUTH:
+	case ACX_STATUS_3_AUTHENTICATED:
+		priv->auth_or_assoc_retries = 0;
+		acx_set_timer(priv, 1500000); /* 1.5 s */
+		break;
 	}
 
-	clt->used = CLIENT_ASSOCIATED_3;
-	if (clt->aid == 0) {
-		clt->aid = ++priv->aid;
+#if QUEUE_OPEN_AFTER_ASSOC
+	if (new_status == ACX_STATUS_4_ASSOCIATED)	{
+		if (old_status < ACX_STATUS_4_ASSOCIATED) {
+			/* ah, we're newly associated now,
+			 * so let's indicate carrier */
+			acx_carrier_on(priv->netdev, "after association");
+			acx_wake_queue(priv->netdev, "after association");
+		}
+	} else {
+		/* not associated any more, so let's kill carrier */
+		if (old_status >= ACX_STATUS_4_ASSOCIATED) {
+			acx_carrier_off(priv->netdev, "after losing association");
+			acx_stop_queue(priv->netdev, "after losing association");
+		}
 	}
-	if (req->cap_info)
-		clt->cap_info = ieee2host16(*(req->cap_info));
-	/* We cheat here a bit. We don't really care which rates are flagged
-	** as basic by the client, so we stuff them in single ratemask */
-	clt->rate_cap = 0;
-	if (req->supp_rates)
-		add_bits_to_ratemasks(req->supp_rates->rates,
-			req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
-	if (req->ext_rates)
-		add_bits_to_ratemasks(req->ext_rates->rates,
-			req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
-	/* We can check that client supports all basic rates,
-	** and deny assoc if not. But let's be liberal, right? ;) */
-	clt->rate_cfg = clt->rate_cap & priv->rate_oper;
-	if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
-	clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
-	clt->fallback_count = clt->stepup_count = 0;
-	clt->ignore_count = 16;
+#endif
+	FN_EXIT0;
+}
 
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto ok;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto ok;
-	body = (void*)(head + 1);
 
-	head->fc = WF_FSTYPE_REASSOCRESPi;
-	head->dur = req->hdr->dur;
-	MAC_COPY(head->da, da);
-	/* MAC_COPY(head->sa, sa); */
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, bssid);
-	head->seq = req->hdr->seq;
-
-	/* IEs: 1. caps */
-	body->cap_info = host2ieee16(priv->capabilities);
-	/* 2. status code */
-	body->status = host2ieee16(0);
-	/* 3. AID */
-	body->aid = host2ieee16(clt->aid);
-	/* 4. supp rates */
-	p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
-							priv->rate_supported);
-	/* 5. ext supp rates */
-	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
-							priv->rate_supported);
-
-	acx_l_dma_tx_data(priv, tx, p - (u8*)head);
-ok:
-	FN_EXIT1(OK);
-	return OK;
-bad:
-	FN_EXIT1(NOT_OK);
-	return NOT_OK;
-}
-
-
-/*----------------------------------------------------------------
-* acx_l_process_disassoc_from_sta
-*----------------------------------------------------------------*/
-static void
-acx_l_process_disassoc_from_sta(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
-{
-	const u8 *ta;
-	client_t *clt;
-
-	FN_ENTER;
-
-	ta = req->hdr->a2;
-	clt = acx_l_sta_list_get(priv, ta);
-	if (!clt)
-		goto end;
-
-	if (clt->used != CLIENT_ASSOCIATED_3
-	 && clt->used != CLIENT_AUTHENTICATED_2) {
-		/* it's disassociating, but it's
-		** not even authenticated! Let it know that */
-		acxlog_mac(L_ASSOC|L_XFER, "peer ", ta, "has sent disassoc "
-			"req but it is not even auth'ed! sending deauth\n");
-		acx_l_transmit_deauthen(priv, ta,
-			WLAN_MGMT_REASON_CLASS2_NONAUTH);
-		clt->used = CLIENT_EXIST_1;
-	} else {
-		/* mark it as auth'ed only */
-		clt->used = CLIENT_AUTHENTICATED_2;
-	}
-end:
-	FN_EXIT0;
-}
-
-
-/*----------------------------------------------------------------
-* acx_l_process_deauthen_from_sta
-*----------------------------------------------------------------*/
-static void
-acx_l_process_deauth_from_sta(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
-{
-	const wlan_hdr_t *hdr;
-	client_t *client;
+/*------------------------------------------------------------------------------
+ * acx_i_timer
+ *
+ * Fires up periodically. Used to kick scan/auth/assoc if something goes wrong
+ *----------------------------------------------------------------------------*/
+void
+acx_i_timer(unsigned long address)
+{
+	unsigned long flags;
+	wlandevice_t *priv = (wlandevice_t *)address;
 
 	FN_ENTER;
 
-	hdr = req->hdr;
+	acx_lock(priv, flags);
 
-	if (acx_debug & L_ASSOC) {
-		acx_print_mac("DEAUTHEN priv->addr=", priv->dev_addr, " ");
-		acx_print_mac("a1", hdr->a1, " ");
-		acx_print_mac("a2", hdr->a2, " ");
-		acx_print_mac("a3", hdr->a3, " ");
-		acx_print_mac("priv->bssid", priv->bssid, "\n");
-	}
+	acxlog(L_DEBUG|L_ASSOC, "%s: priv->status=%d (%s)\n",
+		__func__, priv->status, acx_get_status_name(priv->status));
 
-	if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
-		goto end;
+	switch (priv->status) {
+	case ACX_STATUS_1_SCANNING:
+		/* was set to 0 by set_status() */
+		if (++priv->scan_retries < 7) {
+			acx_set_timer(priv, 1000000);
+			/* used to interrogate for scan status.
+			** We rely on SCAN_COMPLETE IRQ instead */
+			acxlog(L_ASSOC, "continuing scan (%d sec)\n",
+					priv->scan_retries);
+		} else {
+			acxlog(L_ASSOC, "stopping scan\n");
+			/* send stop_scan cmd when we leave the interrupt context,
+			 * and make a decision what to do next (COMPLETE_SCAN) */
+			acx_schedule_after_interrupt_task(priv,
+				ACX_AFTER_IRQ_CMD_STOP_SCAN + ACX_AFTER_IRQ_COMPLETE_SCAN);
+		}
+		break;
+	case ACX_STATUS_2_WAIT_AUTH:
+		/* was set to 0 by set_status() */
+		if (++priv->auth_or_assoc_retries < 10) {
+			acxlog(L_ASSOC, "resend authen1 request (attempt %d)\n",
+					priv->auth_or_assoc_retries + 1);
+			acx_l_transmit_authen1(priv);
+		} else {
+			/* time exceeded: fall back to scanning mode */
+			acxlog(L_ASSOC,
+			       "authen1 request reply timeout, giving up\n");
+			/* we are a STA, need to find AP anyhow */
+			acx_set_status(priv, ACX_STATUS_1_SCANNING);
+			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
+		}
+		/* used to be 1500000, but some other driver uses 2.5s */
+		acx_set_timer(priv, 2500000);
+		break;
+	case ACX_STATUS_3_AUTHENTICATED:
+		/* was set to 0 by set_status() */
+		if (++priv->auth_or_assoc_retries < 10) {
+			acxlog(L_ASSOC,	"resend assoc request (attempt %d)\n",
+					priv->auth_or_assoc_retries + 1);
+			acx_l_transmit_assoc_req(priv);
+		} else {
+			/* time exceeded: give up */
+			acxlog(L_ASSOC,
+				"association request reply timeout, giving up\n");
+			/* we are a STA, need to find AP anyhow */
+			acx_set_status(priv, ACX_STATUS_1_SCANNING);
+			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
+		}
+		acx_set_timer(priv, 2500000); /* see above */
+		break;
+	case ACX_STATUS_4_ASSOCIATED:
+	default:
+		break;
 	}
 
-	acxlog_mac(L_DEBUG, "STA ", hdr->a2, " sent us deauthen packet\n");
+	acx_unlock(priv, flags);
 
-	client = acx_l_sta_list_get(priv, hdr->a2);
-	if (!client) {
-		goto end;
-	}
-	client->used = CLIENT_EXIST_1;
-end:
 	FN_EXIT0;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_process_disassoc_from_ap
-*----------------------------------------------------------------*/
-static void
-acx_l_process_disassoc_from_ap(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
+/*------------------------------------------------------------------------------
+ * acx_set_timer
+ *
+ * Sets the 802.11 state management timer's timeout.
+ *----------------------------------------------------------------------------*/
+void
+acx_set_timer(wlandevice_t *priv, int timeout_us)
 {
 	FN_ENTER;
 
-	if (!priv->ap_client) {
-		/* Hrm, we aren't assoc'ed yet anyhow... */
+	acxlog(L_DEBUG|L_IRQ, "%s(%u ms)\n", __func__, timeout_us/1000);
+	if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
+		printk("attempt to set the timer "
+			"when the card interface is not up!\n");
 		goto end;
 	}
-	if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
-		/* TODO: send a deauth... */
-		acx_l_transmit_deauthen(priv, priv->bssid,
-				WLAN_MGMT_REASON_DEAUTH_LEAVING);
-		/* Start scan anew */
-		SET_BIT(priv->set_mask, GETSET_RESCAN);
-		acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
-	}
-end:
-	FN_EXIT0;
-}
-
-
-/*----------------------------------------------------------------
-* acx_l_process_deauth_from_ap
-*----------------------------------------------------------------*/
-static void
-acx_l_process_deauth_from_ap(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
-{
-	FN_ENTER;
 
-	if (!priv->ap_client) {
-		/* Hrm, we aren't assoc'ed yet anyhow... */
-		goto end;
-	}
-	/* Chk: is ta is verified to be from our AP? */
-	if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
-		acxlog(L_DEBUG, "AP sent us deauth packet\n");
-		/* not needed: acx_set_status(priv, ACX_STATUS_1_SCANNING) */
-		SET_BIT(priv->set_mask, GETSET_RESCAN);
-		acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+	/* first check if the timer was already initialized, THEN modify it */
+	if (priv->mgmt_timer.function) {
+		mod_timer(&priv->mgmt_timer,
+				jiffies + (timeout_us * HZ / 1000000));
 	}
 end:
 	FN_EXIT0;
@@ -979,1444 +1421,4192 @@ end:
 
 
 /*------------------------------------------------------------------------------
- * acx_l_rx
- *
- * The end of the Rx path. Pulls data from a rxhostdesc into a socket
- * buffer and feeds it to the network stack via netif_rx().
+ * acx_l_rx_ieee802_11_frame
  *
- * Arguments:
- *	rxdesc:	the rxhostdesc to pull the data from
- *	priv:	the acx100 private struct of the interface
+ * Called from IRQ context only
  *----------------------------------------------------------------------------*/
-void
-acx_l_rx(wlandevice_t *priv, rxbuffer_t *rxbuf)
-{
-	FN_ENTER;
-	if (likely(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
-		struct sk_buff *skb;
-		skb = acx_rxbuf_to_ether(priv, rxbuf);
-		if (likely(skb)) {
-			netif_rx(skb);
-			priv->netdev->last_rx = jiffies;
-			priv->stats.rx_packets++;
-			priv->stats.rx_bytes += skb->len;
-		}
-	}
-	FN_EXIT0;
-}
-
-
-/*----------------------------------------------------------------
-* acx_l_process_data_frame_master
-*----------------------------------------------------------------*/
-static int
-acx_l_process_data_frame_master(wlandevice_t *priv, rxbuffer_t *rxbuf)
+int
+acx_l_rx_ieee802_11_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
 {
-	struct wlan_hdr *hdr;
-	struct tx *tx;
-	void *txbuf;
-	int len;
+	unsigned int ftype, fstype;
+	const wlan_hdr_t *hdr;
 	int result = NOT_OK;
 
 	FN_ENTER;
 
 	hdr = acx_get_wlan_hdr(priv, rxbuf);
 
-	switch (WF_FC_FROMTODSi & hdr->fc) {
-	case 0:
-	case WF_FC_FROMDSi:
-		acxlog(L_DEBUG, "ap->sta or adhoc->adhoc data frame ignored\n");
-		goto done;
-	case WF_FC_TODSi:
-		break;
-	default: /* WF_FC_FROMTODSi */
-		acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
-		goto done;
+	/* see IEEE 802.11-1999.pdf chapter 7 "MAC frame formats" */
+	if ((hdr->fc & WF_FC_PVERi) != 0) {
+		printk_ratelimited(KERN_INFO "rx: unsupported 802.11 protocol\n");
+		goto end;
 	}
 
-	/* check if it is our BSSID, if not, leave */
-	if (!mac_is_equal(priv->bssid, hdr->a1)) {
-		goto done;
-	}
+	ftype = hdr->fc & WF_FC_FTYPEi;
+	fstype = hdr->fc & WF_FC_FSTYPEi;
 
-	if (mac_is_equal(priv->dev_addr, hdr->a3)) {
-		/* this one is for us */
-		acx_l_rx(priv, rxbuf);
-	} else {
-		if (mac_is_bcast(hdr->a3)) {
-			/* this one is bcast, rx it too */
-			acx_l_rx(priv, rxbuf);
-		}
-		tx = acx_l_alloc_tx(priv);
-		if (!tx) {
-			goto fail;
-		}
-		/* repackage, tx, and hope it someday reaches its destination */
-		/* order is important, we do it in-place */
-		MAC_COPY(hdr->a1, hdr->a3);
-		MAC_COPY(hdr->a3, hdr->a2);
-		MAC_COPY(hdr->a2, priv->bssid);
-		/* To_DS = 0, From_DS = 1 */
-		hdr->fc = WF_FC_FROMDSi + WF_FTYPE_DATAi;
+	switch (ftype) {
+	/* check data frames first, for speed */
+	case WF_FTYPE_DATAi:
+		switch (fstype) {
+		case WF_FSTYPE_DATAONLYi:
+		/* FIXME: will fail if two peers send 2 streams of DUPs */
+			if (priv->dup_count
+			 && time_after(jiffies, priv->dup_msg_expiry)) {
+				printk(KERN_INFO "%s: rx: %d DUPs received in 10 secs\n",
+					priv->netdev->name, priv->dup_count);
+				priv->dup_count = 0;
+			}
+			if (unlikely(hdr->seq == priv->last_seq_ctrl)) {
+				if (!priv->dup_count++)
+					priv->dup_msg_expiry = jiffies + 10*HZ;
+				/* simply discard it and indicate error */
+				priv->stats.rx_errors++;
+				break;
+			}
+			priv->last_seq_ctrl = hdr->seq; /* le_to_cpu? */
 
-		len = RXBUF_BYTES_RCVD(rxbuf);
-		txbuf = acx_l_get_txbuf(tx);
-		if (txbuf) {
-			memcpy(txbuf, &rxbuf->hdr_a3, len);
-			acx_l_dma_tx_data(priv, tx, len);
+			/* TODO:
+			if (WF_FC_FROMTODSi == (hdr->fc & WF_FC_FROMTODSi)) {
+				result = acx_l_process_data_frame_wds(priv, rxbuf);
+				break;
+			}
+			*/
+
+			switch (priv->mode) {
+			case ACX_MODE_3_AP:
+				result = acx_l_process_data_frame_master(priv, rxbuf);
+				break;
+			case ACX_MODE_0_ADHOC:
+			case ACX_MODE_2_STA:
+				result = acx_l_process_data_frame_client(priv, rxbuf);
+				break;
+			}
+		case WF_FSTYPE_DATA_CFACKi:
+		case WF_FSTYPE_DATA_CFPOLLi:
+		case WF_FSTYPE_DATA_CFACK_CFPOLLi:
+		case WF_FSTYPE_CFPOLLi:
+		case WF_FSTYPE_CFACK_CFPOLLi:
+		/*   see above.
+			acx_process_class_frame(priv, rxbuf, 3); */
+			break;
+		case WF_FSTYPE_NULLi:
+			/* acx_l_process_NULL_frame(priv, rxbuf, 3); */
+			break;
+		/* FIXME: same here, see above */
+		case WF_FSTYPE_CFACKi:
+		default:
+			break;
 		}
+		break;
+	case WF_FTYPE_MGMTi:
+		result = acx_l_process_mgmt_frame(priv, rxbuf);
+		break;
+	case WF_FTYPE_CTLi:
+		if (fstype == WF_FSTYPE_PSPOLLi)
+			result = OK;
+		/*   this call is irrelevant, since
+		 *   acx_process_class_frame is a stub, so return
+		 *   immediately instead.
+		 * return acx_process_class_frame(priv, rxbuf, 3); */
+		break;
+	default:
+		break;
 	}
-done:
-	result = OK;
-fail:
+end:
 	FN_EXIT1(result);
 	return result;
 }
 
 
 /*----------------------------------------------------------------
-* acx_l_process_data_frame_client
+* acx_l_transmit_assocresp
+*
+* We are an AP here
 *----------------------------------------------------------------*/
+static const u8
+dot11ratebyte[] = {
+	DOT11RATEBYTE_1,
+	DOT11RATEBYTE_2,
+	DOT11RATEBYTE_5_5,
+	DOT11RATEBYTE_6_G,
+	DOT11RATEBYTE_9_G,
+	DOT11RATEBYTE_11,
+	DOT11RATEBYTE_12_G,
+	DOT11RATEBYTE_18_G,
+	DOT11RATEBYTE_22,
+	DOT11RATEBYTE_24_G,
+	DOT11RATEBYTE_36_G,
+	DOT11RATEBYTE_48_G,
+	DOT11RATEBYTE_54_G,
+};
+
 static int
-acx_l_process_data_frame_client(wlandevice_t *priv, rxbuffer_t *rxbuf)
+find_pos(const u8 *p, int size, u8 v)
 {
-	const u8 *da, *bssid;
-	const wlan_hdr_t *hdr;
-	netdevice_t *dev = priv->netdev;
-	int result = NOT_OK;
+	int i;
+	for (i = 0; i < size; i++)
+		if (p[i] == v)
+			return i;
+	/* printk a message about strange byte? */
+	return 0;
+}
 
-	FN_ENTER;
+static void
+add_bits_to_ratemasks(u8* ratevec, int len, u16* brate, u16* orate)
+{
+	while (len--) {
+		int n = 1 << find_pos(dot11ratebyte,
+				sizeof(dot11ratebyte), *ratevec & 0x7f);
+		if (*ratevec & 0x80)
+			*brate |= n;
+		*orate |= n;
+		ratevec++;
+	}
+}
 
-	if (ACX_STATUS_4_ASSOCIATED != priv->status) goto drop;
+static int
+acx_l_transmit_assocresp(wlandevice_t *priv, const wlan_fr_assocreq_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct assocresp_frame_body *body;
+	u8 *p;
+	const u8 *da;
+	/* const u8 *sa; */
+	const u8 *bssid;
+	client_t *clt;
 
-	hdr = acx_get_wlan_hdr(priv, rxbuf);
+	FN_ENTER;
 
-	switch (WF_FC_FROMTODSi & hdr->fc) {
-	case 0:
-		if (priv->mode != ACX_MODE_0_ADHOC) {
-			acxlog(L_DEBUG, "adhoc->adhoc data frame ignored\n");
-			goto drop;
-		}
-		bssid = hdr->a3;
-		break;
-	case WF_FC_FROMDSi:
-		if (priv->mode != ACX_MODE_2_STA) {
-			acxlog(L_DEBUG, "ap->sta data frame ignored\n");
-			goto drop;
-		}
-		bssid = hdr->a2;
-		break;
-	case WF_FC_TODSi:
-		acxlog(L_DEBUG, "sta->ap data frame ignored\n");
-		goto drop;
-	default: /* WF_FC_FROMTODSi: wds->wds */
-		acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
-		goto drop;
-	}
+	/* sa = req->hdr->a1; */
+	da = req->hdr->a2;
+	bssid = req->hdr->a3;
 
-	da = hdr->a1;
+	clt = acx_l_sta_list_get(priv, da);
+	if (!clt)
+		goto ok;
 
-	if (unlikely(acx_debug & L_DEBUG)) {
-		acx_print_mac("rx: da=", da, "");
-		acx_print_mac(" bssid=", bssid, "");
-		acx_print_mac(" priv->bssid=", priv->bssid, "");
-		acx_print_mac(" priv->addr=", priv->dev_addr, "\n");
+	/* Assoc without auth is a big no-no */
+	/* Let's be liberal: if already assoc'ed STA sends assoc req again,
+	** we won't be rude */
+	if (clt->used != CLIENT_AUTHENTICATED_2
+	 && clt->used != CLIENT_ASSOCIATED_3) {
+		acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
+		goto bad;
 	}
 
-	/* promiscuous mode --> receive all packets */
-	if (unlikely(dev->flags & IFF_PROMISC))
-		goto process;
+	clt->used = CLIENT_ASSOCIATED_3;
 
-	/* FIRST, check if it is our BSSID */
-	if (!mac_is_equal(priv->bssid, bssid)) {
-		/* is not our BSSID, so bail out */
-		goto drop;
+	if (clt->aid == 0) {
+		clt->aid = ++priv->aid;
 	}
+	clt->cap_info = ieee2host16(*(req->cap_info));
+	/* We cheat here a bit. We don't really care which rates are flagged
+	** as basic by the client, so we stuff them in single ratemask */
+	clt->rate_cap = 0;
+	if (req->supp_rates)
+		add_bits_to_ratemasks(req->supp_rates->rates,
+			req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
+	if (req->ext_rates)
+		add_bits_to_ratemasks(req->ext_rates->rates,
+			req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
+	/* We can check that client supports all basic rates,
+	** and deny assoc if not. But let's be liberal, right? ;) */
+	clt->rate_cfg = clt->rate_cap & priv->rate_oper;
+	if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
+	clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
+	clt->fallback_count = clt->stepup_count = 0;
+	clt->ignore_count = 16;
 
-	/* then, check if it is our address */
-	if (mac_is_equal(priv->dev_addr, da)) {
-		goto process;
-	}
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto bad;
+	body = (void*)(head + 1);
 
-	/* then, check if it is broadcast */
-	if (mac_is_bcast(da)) {
-		goto process;
-	}
+	head->fc = WF_FSTYPE_ASSOCRESPi;
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, da);
+	/* MAC_COPY(head->sa, sa); */
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, bssid);
+	head->seq = req->hdr->seq;
 
-	if (mac_is_mcast(da)) {
-		/* unconditionally receive all multicasts */
-		if (dev->flags & IFF_ALLMULTI)
-			goto process;
+	body->cap_info = host2ieee16(priv->capabilities);
+	body->status = host2ieee16(0);
+	body->aid = host2ieee16(clt->aid);
+	p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
+							priv->rate_supported);
+	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
+							priv->rate_supported);
 
-		/* FIXME: check against the list of
-		 * multicast addresses that are configured
-		 * for the interface (ifconfig) */
-		acxlog(L_XFER, "FIXME: multicast packet, need to check "
-			"against a list of multicast addresses "
-			"(to be created!); accepting packet for now\n");
-		/* for now, just accept it here */
-		goto process;
-	}
+	acx_l_tx_data(priv, tx, p - (u8*)head);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
 
-	acxlog(L_DEBUG, "rx: foreign packet, dropping\n");
+
+/*----------------------------------------------------------------
+* acx_l_transmit_reassocresp
+
+You may be wondering, just like me, what a hell is ReAuth.
+In practice it was seen sent by STA when STA feels like losing connection.
+
+[802.11]
+
+5.4.2.3 Reassociation
+
+Association is sufficient for no-transition message delivery between
+IEEE 802.11 stations. Additional functionality is needed to support
+BSS-transition mobility. The additional required functionality
+is provided by the reassociation service. Reassociation is a DSS.
+The reassociation service is invoked to ÒmoveÓ a current association
+from one AP to another. This keeps the DS informed of the current
+mapping between AP and STA as the station moves from BSS to BSS within
+an ESS. Reassociation also enables changing association attributes
+of an established association while the STA remains associated with
+the same AP. Reassociation is always initiated by the mobile STA.
+
+5.4.3.1 Authentication
+...
+A STA may be authenticated with many other STAs at any given instant.
+
+5.4.3.1.1 Preauthentication
+
+Because the authentication process could be time-consuming (depending
+on the authentication protocol in use), the authentication service can
+be invoked independently of the association service. Preauthentication
+is typically done by a STA while it is already associated with an AP
+(with which it previously authenticated). IEEE 802.11 does not require
+that STAs preauthenticate with APs. However, authentication is required
+before an association can be established. If the authentication is left
+until reassociation time, this may impact the speed with which a STA can
+reassociate between APs, limiting BSS-transition mobility performance.
+The use of preauthentication takes the authentication service overhead
+out of the time-critical reassociation process.
+
+5.7.3 Reassociation
+
+For a STA to reassociate, the reassociation service causes the following
+message to occur:
+
+  Reassociation request
+
+* Message type: Management
+* Message subtype: Reassociation request
+* Information items:
+  - IEEE address of the STA
+  - IEEE address of the AP with which the STA will reassociate
+  - IEEE address of the AP with which the STA is currently associated
+  - ESSID
+* Direction of message: From STA to 'new' AP
+
+The address of the current AP is included for efficiency. The inclusion
+of the current AP address facilitates MAC reassociation to be independent
+of the DS implementation.
+
+  Reassociation response
+* Message type: Management
+* Message subtype: Reassociation response
+* Information items:
+  - Result of the requested reassociation. (success/failure)
+  - If the reassociation is successful, the response shall include the AID.
+* Direction of message: From AP to STA
+
+7.2.3.6 Reassociation Request frame format
+
+The frame body of a management frame of subtype Reassociation Request
+contains the information shown in Table 9.
+
+Table 9 Reassociation Request frame body
+Order Information
+1 Capability information
+2 Listen interval
+3 Current AP address
+4 SSID
+5 Supported rates
+
+7.2.3.7 Reassociation Response frame format
+
+The frame body of a management frame of subtype Reassociation Response
+contains the information shown in Table 10.
+
+Table 10 Reassociation Response frame body
+Order Information
+1 Capability information
+2 Status code
+3 Association ID (AID)
+4 Supported rates
+
+*----------------------------------------------------------------*/
+static int
+acx_l_transmit_reassocresp(wlandevice_t *priv, const wlan_fr_reassocreq_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct reassocresp_frame_body *body;
+	u8 *p;
+	const u8 *da;
+	/* const u8 *sa; */
+	const u8 *bssid;
+	client_t *clt;
+
+	FN_ENTER;
+
+	/* sa = req->hdr->a1; */
+	da = req->hdr->a2;
+	bssid = req->hdr->a3;
+
+	/* Must be already authenticated, so it must be in the list */
+	clt = acx_l_sta_list_get(priv, da);
+	if (!clt)
+		goto ok;
+
+	/* Assoc without auth is a big no-no */
+	/* Already assoc'ed STAs sending ReAssoc req are ok per 802.11 */
+	if (clt->used != CLIENT_AUTHENTICATED_2
+	 && clt->used != CLIENT_ASSOCIATED_3) {
+		acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
+		goto bad;
+	}
+
+	clt->used = CLIENT_ASSOCIATED_3;
+	if (clt->aid == 0) {
+		clt->aid = ++priv->aid;
+	}
+	if (req->cap_info)
+		clt->cap_info = ieee2host16(*(req->cap_info));
+	/* We cheat here a bit. We don't really care which rates are flagged
+	** as basic by the client, so we stuff them in single ratemask */
+	clt->rate_cap = 0;
+	if (req->supp_rates)
+		add_bits_to_ratemasks(req->supp_rates->rates,
+			req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
+	if (req->ext_rates)
+		add_bits_to_ratemasks(req->ext_rates->rates,
+			req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
+	/* We can check that client supports all basic rates,
+	** and deny assoc if not. But let's be liberal, right? ;) */
+	clt->rate_cfg = clt->rate_cap & priv->rate_oper;
+	if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
+	clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
+	clt->fallback_count = clt->stepup_count = 0;
+	clt->ignore_count = 16;
+
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto ok;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto ok;
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_REASSOCRESPi;
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, da);
+	/* MAC_COPY(head->sa, sa); */
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, bssid);
+	head->seq = req->hdr->seq;
+
+	/* IEs: 1. caps */
+	body->cap_info = host2ieee16(priv->capabilities);
+	/* 2. status code */
+	body->status = host2ieee16(0);
+	/* 3. AID */
+	body->aid = host2ieee16(clt->aid);
+	/* 4. supp rates */
+	p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
+							priv->rate_supported);
+	/* 5. ext supp rates */
+	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
+							priv->rate_supported);
+
+	acx_l_tx_data(priv, tx, p - (u8*)head);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_disassoc_from_sta
+*----------------------------------------------------------------*/
+static void
+acx_l_process_disassoc_from_sta(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
+{
+	const u8 *ta;
+	client_t *clt;
+
+	FN_ENTER;
+
+	ta = req->hdr->a2;
+	clt = acx_l_sta_list_get(priv, ta);
+	if (!clt)
+		goto end;
+
+	if (clt->used != CLIENT_ASSOCIATED_3
+	 && clt->used != CLIENT_AUTHENTICATED_2) {
+		/* it's disassociating, but it's
+		** not even authenticated! Let it know that */
+		acxlog_mac(L_ASSOC|L_XFER, "peer ", ta, "has sent disassoc "
+			"req but it is not even auth'ed! sending deauth\n");
+		acx_l_transmit_deauthen(priv, ta,
+			WLAN_MGMT_REASON_CLASS2_NONAUTH);
+		clt->used = CLIENT_EXIST_1;
+	} else {
+		/* mark it as auth'ed only */
+		clt->used = CLIENT_AUTHENTICATED_2;
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_deauthen_from_sta
+*----------------------------------------------------------------*/
+static void
+acx_l_process_deauth_from_sta(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
+{
+	const wlan_hdr_t *hdr;
+	client_t *client;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if (acx_debug & L_ASSOC) {
+		acx_print_mac("DEAUTHEN priv->addr=", priv->dev_addr, " ");
+		acx_print_mac("a1", hdr->a1, " ");
+		acx_print_mac("a2", hdr->a2, " ");
+		acx_print_mac("a3", hdr->a3, " ");
+		acx_print_mac("priv->bssid", priv->bssid, "\n");
+	}
+
+	if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
+		goto end;
+	}
+
+	acxlog_mac(L_DEBUG, "STA ", hdr->a2, " sent us deauthen packet\n");
+
+	client = acx_l_sta_list_get(priv, hdr->a2);
+	if (!client) {
+		goto end;
+	}
+	client->used = CLIENT_EXIST_1;
+end:
+	FN_EXIT0;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_disassoc_from_ap
+*----------------------------------------------------------------*/
+static void
+acx_l_process_disassoc_from_ap(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
+{
+	FN_ENTER;
+
+	if (!priv->ap_client) {
+		/* Hrm, we aren't assoc'ed yet anyhow... */
+		goto end;
+	}
+	if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
+		/* TODO: send a deauth... */
+		acx_l_transmit_deauthen(priv, priv->bssid,
+				WLAN_MGMT_REASON_DEAUTH_LEAVING);
+		/* Start scan anew */
+		SET_BIT(priv->set_mask, GETSET_RESCAN);
+		acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_deauth_from_ap
+*----------------------------------------------------------------*/
+static void
+acx_l_process_deauth_from_ap(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
+{
+	FN_ENTER;
+
+	if (!priv->ap_client) {
+		/* Hrm, we aren't assoc'ed yet anyhow... */
+		goto end;
+	}
+	/* Chk: is ta is verified to be from our AP? */
+	if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
+		acxlog(L_DEBUG, "AP sent us deauth packet\n");
+		/* not needed: acx_set_status(priv, ACX_STATUS_1_SCANNING) */
+		SET_BIT(priv->set_mask, GETSET_RESCAN);
+		acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/*------------------------------------------------------------------------------
+ * acx_l_rx
+ *
+ * The end of the Rx path. Pulls data from a rxhostdesc into a socket
+ * buffer and feeds it to the network stack via netif_rx().
+ *
+ * Arguments:
+ *	rxdesc:	the rxhostdesc to pull the data from
+ *	priv:	the acx100 private struct of the interface
+ *----------------------------------------------------------------------------*/
+void
+acx_l_rx(wlandevice_t *priv, rxbuffer_t *rxbuf)
+{
+	FN_ENTER;
+	if (likely(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
+		struct sk_buff *skb;
+		skb = acx_rxbuf_to_ether(priv, rxbuf);
+		if (likely(skb)) {
+			netif_rx(skb);
+			priv->netdev->last_rx = jiffies;
+			priv->stats.rx_packets++;
+			priv->stats.rx_bytes += skb->len;
+		}
+	}
+	FN_EXIT0;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_data_frame_master
+*----------------------------------------------------------------*/
+static int
+acx_l_process_data_frame_master(wlandevice_t *priv, rxbuffer_t *rxbuf)
+{
+	struct wlan_hdr *hdr;
+	struct tx *tx;
+	void *txbuf;
+	int len;
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	hdr = acx_get_wlan_hdr(priv, rxbuf);
+
+	switch (WF_FC_FROMTODSi & hdr->fc) {
+	case 0:
+	case WF_FC_FROMDSi:
+		acxlog(L_DEBUG, "ap->sta or adhoc->adhoc data frame ignored\n");
+		goto done;
+	case WF_FC_TODSi:
+		break;
+	default: /* WF_FC_FROMTODSi */
+		acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
+		goto done;
+	}
+
+	/* check if it is our BSSID, if not, leave */
+	if (!mac_is_equal(priv->bssid, hdr->a1)) {
+		goto done;
+	}
+
+	if (mac_is_equal(priv->dev_addr, hdr->a3)) {
+		/* this one is for us */
+		acx_l_rx(priv, rxbuf);
+	} else {
+		if (mac_is_bcast(hdr->a3)) {
+			/* this one is bcast, rx it too */
+			acx_l_rx(priv, rxbuf);
+		}
+		tx = acx_l_alloc_tx(priv);
+		if (!tx) {
+			goto fail;
+		}
+		/* repackage, tx, and hope it someday reaches its destination */
+		/* order is important, we do it in-place */
+		MAC_COPY(hdr->a1, hdr->a3);
+		MAC_COPY(hdr->a3, hdr->a2);
+		MAC_COPY(hdr->a2, priv->bssid);
+		/* To_DS = 0, From_DS = 1 */
+		hdr->fc = WF_FC_FROMDSi + WF_FTYPE_DATAi;
+
+		len = RXBUF_BYTES_RCVD(rxbuf);
+		txbuf = acx_l_get_txbuf(priv, tx);
+		if (txbuf) {
+			memcpy(txbuf, &rxbuf->hdr_a3, len);
+			acx_l_tx_data(priv, tx, len);
+		}
+	}
+done:
+	result = OK;
+fail:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_data_frame_client
+*----------------------------------------------------------------*/
+static int
+acx_l_process_data_frame_client(wlandevice_t *priv, rxbuffer_t *rxbuf)
+{
+	const u8 *da, *bssid;
+	const wlan_hdr_t *hdr;
+	netdevice_t *dev = priv->netdev;
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	if (ACX_STATUS_4_ASSOCIATED != priv->status) goto drop;
+
+	hdr = acx_get_wlan_hdr(priv, rxbuf);
+
+	switch (WF_FC_FROMTODSi & hdr->fc) {
+	case 0:
+		if (priv->mode != ACX_MODE_0_ADHOC) {
+			acxlog(L_DEBUG, "adhoc->adhoc data frame ignored\n");
+			goto drop;
+		}
+		bssid = hdr->a3;
+		break;
+	case WF_FC_FROMDSi:
+		if (priv->mode != ACX_MODE_2_STA) {
+			acxlog(L_DEBUG, "ap->sta data frame ignored\n");
+			goto drop;
+		}
+		bssid = hdr->a2;
+		break;
+	case WF_FC_TODSi:
+		acxlog(L_DEBUG, "sta->ap data frame ignored\n");
+		goto drop;
+	default: /* WF_FC_FROMTODSi: wds->wds */
+		acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
+		goto drop;
+	}
+
+	da = hdr->a1;
+
+	if (unlikely(acx_debug & L_DEBUG)) {
+		acx_print_mac("rx: da=", da, "");
+		acx_print_mac(" bssid=", bssid, "");
+		acx_print_mac(" priv->bssid=", priv->bssid, "");
+		acx_print_mac(" priv->addr=", priv->dev_addr, "\n");
+	}
+
+	/* promiscuous mode --> receive all packets */
+	if (unlikely(dev->flags & IFF_PROMISC))
+		goto process;
+
+	/* FIRST, check if it is our BSSID */
+	if (!mac_is_equal(priv->bssid, bssid)) {
+		/* is not our BSSID, so bail out */
+		goto drop;
+	}
+
+	/* then, check if it is our address */
+	if (mac_is_equal(priv->dev_addr, da)) {
+		goto process;
+	}
+
+	/* then, check if it is broadcast */
+	if (mac_is_bcast(da)) {
+		goto process;
+	}
+
+	if (mac_is_mcast(da)) {
+		/* unconditionally receive all multicasts */
+		if (dev->flags & IFF_ALLMULTI)
+			goto process;
+
+		/* FIXME: check against the list of
+		 * multicast addresses that are configured
+		 * for the interface (ifconfig) */
+		acxlog(L_XFER, "FIXME: multicast packet, need to check "
+			"against a list of multicast addresses "
+			"(to be created!); accepting packet for now\n");
+		/* for now, just accept it here */
+		goto process;
+	}
+
+	acxlog(L_DEBUG, "rx: foreign packet, dropping\n");
 	goto drop;
 process:
 	/* receive packet */
 	acx_l_rx(priv, rxbuf);
 
-	result = OK;
-drop:
-	FN_EXIT1(result);
-	return result;
-}
+	result = OK;
+drop:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_mgmt_frame
+*
+* Theory of operation: mgmt packet gets parsed (to make it easy
+* to access variable-sized IEs), results stored in 'parsed'.
+* Then we react to the packet.
+* NB: wlan_mgmt_decode_XXX are dev-independent (shoudnt have been named acx_XXX)
+*----------------------------------------------------------------*/
+typedef union parsed_mgmt_req {
+	wlan_fr_mgmt_t mgmt;
+	wlan_fr_assocreq_t assocreq;
+	wlan_fr_reassocreq_t reassocreq;
+	wlan_fr_assocresp_t assocresp;
+	wlan_fr_reassocresp_t reassocresp;
+	wlan_fr_beacon_t beacon;
+	wlan_fr_disassoc_t disassoc;
+	wlan_fr_authen_t authen;
+	wlan_fr_deauthen_t deauthen;
+	wlan_fr_proberesp_t proberesp;
+} parsed_mgmt_req_t;
+
+void BUG_excessive_stack_usage(void);
+
+static int
+acx_l_process_mgmt_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
+{
+	parsed_mgmt_req_t parsed;	/* takes ~100 bytes of stack */
+	wlan_hdr_t *hdr;
+	int adhoc, sta_scan, sta, ap;
+	int len;
+
+	if (sizeof(parsed) > 256)
+		BUG_excessive_stack_usage();
+
+	FN_ENTER;
+
+	hdr = acx_get_wlan_hdr(priv, rxbuf);
+
+	/* Management frames never have these set */
+	if (WF_FC_FROMTODSi & hdr->fc) {
+		FN_EXIT1(NOT_OK);
+		return NOT_OK;
+	}
+
+	len = RXBUF_BYTES_RCVD(rxbuf);
+	if (WF_FC_ISWEPi & hdr->fc)
+		len -= 0x10;
+
+	adhoc = (priv->mode == ACX_MODE_0_ADHOC);
+	sta_scan = ((priv->mode == ACX_MODE_2_STA)
+		 && (priv->status != ACX_STATUS_4_ASSOCIATED));
+	sta = ((priv->mode == ACX_MODE_2_STA)
+	    && (priv->status == ACX_STATUS_4_ASSOCIATED));
+	ap = (priv->mode == ACX_MODE_3_AP);
+
+	switch (WF_FC_FSTYPEi & hdr->fc) {
+	/* beacons first, for speed */
+	case WF_FSTYPE_BEACONi:
+		memset(&parsed.beacon, 0, sizeof(parsed.beacon));
+		parsed.beacon.hdr = hdr;
+		parsed.beacon.len = len;
+		if (acx_debug & L_DATA) {
+			printk("BCN len:%d fc:%04X dur:%04X seq:%04X\n",
+			       len, hdr->fc, hdr->dur, hdr->seq);
+			acx_print_mac("BCN a1:", hdr->a1, "\n");
+			acx_print_mac("BCN a2:", hdr->a2, "\n");
+			acx_print_mac("BCN a3:", hdr->a3, "\n");
+		}
+		wlan_mgmt_decode_beacon(&parsed.beacon);
+		/* beacon and probe response are very similar, so... */
+		acx_l_process_probe_response(priv, &parsed.beacon, rxbuf);
+		break;
+	case WF_FSTYPE_ASSOCREQi:
+		if (!ap)
+			break;
+		memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
+		parsed.assocreq.hdr = hdr;
+		parsed.assocreq.len = len;
+		wlan_mgmt_decode_assocreq(&parsed.assocreq);
+		if (mac_is_equal(hdr->a1, priv->bssid)
+		 && mac_is_equal(hdr->a3, priv->bssid)) {
+			acx_l_transmit_assocresp(priv, &parsed.assocreq);
+		}
+		break;
+	case WF_FSTYPE_REASSOCREQi:
+		if (!ap)
+			break;
+		memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
+		parsed.assocreq.hdr = hdr;
+		parsed.assocreq.len = len;
+		wlan_mgmt_decode_assocreq(&parsed.assocreq);
+		/* reassocreq and assocreq are equivalent */
+		acx_l_transmit_reassocresp(priv, &parsed.reassocreq);
+		break;
+	case WF_FSTYPE_ASSOCRESPi:
+		if (!sta_scan)
+			break;
+		memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
+		parsed.assocresp.hdr = hdr;
+		parsed.assocresp.len = len;
+		wlan_mgmt_decode_assocresp(&parsed.assocresp);
+		acx_l_process_assocresp(priv, &parsed.assocresp);
+		break;
+	case WF_FSTYPE_REASSOCRESPi:
+		if (!sta_scan)
+			break;
+		memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
+		parsed.assocresp.hdr = hdr;
+		parsed.assocresp.len = len;
+		wlan_mgmt_decode_assocresp(&parsed.assocresp);
+		acx_l_process_reassocresp(priv, &parsed.reassocresp);
+		break;
+	case WF_FSTYPE_PROBEREQi:
+		if (ap || adhoc) {
+			/* FIXME: since we're supposed to be an AP,
+			** we need to return a Probe Response packet.
+			** Currently firmware is doing it for us,
+			** but firmware is buggy! See comment elsewhere --vda */
+		}
+		break;
+	case WF_FSTYPE_PROBERESPi:
+		memset(&parsed.proberesp, 0, sizeof(parsed.proberesp));
+		parsed.proberesp.hdr = hdr;
+		parsed.proberesp.len = len;
+		wlan_mgmt_decode_proberesp(&parsed.proberesp);
+		acx_l_process_probe_response(priv, &parsed.proberesp, rxbuf);
+		break;
+	case 6:
+	case 7:
+		/* exit */
+		break;
+	case WF_FSTYPE_ATIMi:
+		/* exit */
+		break;
+	case WF_FSTYPE_DISASSOCi:
+		if (!sta && !ap)
+			break;
+		memset(&parsed.disassoc, 0, sizeof(parsed.disassoc));
+		parsed.disassoc.hdr = hdr;
+		parsed.disassoc.len = len;
+		wlan_mgmt_decode_disassoc(&parsed.disassoc);
+		if (sta)
+			acx_l_process_disassoc_from_ap(priv, &parsed.disassoc);
+		else
+			acx_l_process_disassoc_from_sta(priv, &parsed.disassoc);
+		break;
+	case WF_FSTYPE_AUTHENi:
+		if (!sta_scan && !ap)
+			break;
+		memset(&parsed.authen, 0, sizeof(parsed.authen));
+		parsed.authen.hdr = hdr;
+		parsed.authen.len = len;
+		wlan_mgmt_decode_authen(&parsed.authen);
+		acx_l_process_authen(priv, &parsed.authen);
+		break;
+	case WF_FSTYPE_DEAUTHENi:
+		if (!sta && !ap)
+			break;
+		memset(&parsed.deauthen, 0, sizeof(parsed.deauthen));
+		parsed.deauthen.hdr = hdr;
+		parsed.deauthen.len = len;
+		wlan_mgmt_decode_deauthen(&parsed.deauthen);
+		if (sta)
+			acx_l_process_deauth_from_ap(priv, &parsed.deauthen);
+		else
+			acx_l_process_deauth_from_sta(priv, &parsed.deauthen);
+		break;
+	}
+
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+#ifdef UNUSED
+/*----------------------------------------------------------------
+* acx_process_class_frame
+*
+* Called from IRQ context only
+*----------------------------------------------------------------*/
+static int
+acx_process_class_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
+{
+	return OK;
+}
+#endif
+
+
+/*----------------------------------------------------------------
+* acx_l_process_NULL_frame
+*----------------------------------------------------------------*/
+#ifdef BOGUS_ITS_NOT_A_NULL_FRAME_HANDLER_AT_ALL
+static int
+acx_l_process_NULL_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
+{
+	const signed char *esi;
+	const u8 *ebx;
+	const wlan_hdr_t *hdr;
+	const client_t *client;
+	int result = NOT_OK;
+
+	hdr = acx_get_wlan_hdr(priv, rxbuf);
+
+	switch (WF_FC_FROMTODSi & hdr->fc) {
+	case 0:
+		esi = hdr->a1;
+		ebx = hdr->a2;
+		break;
+	case WF_FC_FROMDSi:
+		esi = hdr->a1;
+		ebx = hdr->a3;
+		break;
+	case WF_FC_TODSi:
+		esi = hdr->a1;
+		ebx = hdr->a2;
+		break;
+	default: /* WF_FC_FROMTODSi */
+		esi = hdr->a1; /* added by me! --vda */
+		ebx = hdr->a2;
+	}
+
+	if (esi[0x0] < 0) {
+		result = OK;
+		goto done;
+	}
+
+	client = acx_l_sta_list_get(priv, ebx);
+	if (client)
+		result = NOT_OK;
+	else {
+#ifdef IS_IT_BROKEN
+		acxlog(L_DEBUG | L_XFER, "<transmit_deauth 7>\n");
+		acx_l_transmit_deauthen(priv, ebx,
+			WLAN_MGMT_REASON_CLASS2_NONAUTH);
+#else
+		acxlog(L_DEBUG, "received NULL frame from unknown client! "
+			"We really shouldn't send deauthen here, right?\n");
+#endif
+		result = OK;
+	}
+done:
+	return result;
+}
+#endif
+
+
+/*----------------------------------------------------------------
+* acx_l_process_probe_response
+*----------------------------------------------------------------*/
+static int
+acx_l_process_probe_response(wlandevice_t *priv, wlan_fr_proberesp_t *req,
+			const rxbuffer_t *rxbuf)
+{
+	struct client *bss;
+	wlan_hdr_t *hdr;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if (mac_is_equal(hdr->a3, priv->dev_addr)) {
+		acxlog(L_ASSOC, "huh, scan found our own MAC!?\n");
+		goto ok; /* just skip this one silently */
+	}
+
+	bss = acx_l_sta_list_get_or_add(priv, hdr->a2);
+
+	/* NB: be careful modifying bss data! It may be one
+	** of already known clients (like our AP is we are a STA)
+	** Thus do not blindly modify e.g. current ratemask! */
+
+	if (STA_LIST_ADD_CAN_FAIL && !bss) {
+		/* uh oh, we found more sites/stations than we can handle with
+		 * our current setup: pull the emergency brake and stop scanning! */
+		acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_STOP_SCAN);
+		/* TODO: a nice comment what below call achieves --vda */
+		acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
+		goto ok;
+	}
+	/* NB: get_or_add already filled bss->address = hdr->a2 */
+	MAC_COPY(bss->bssid, hdr->a3);
+
+	/* copy the ESSID element */
+	if (req->ssid && req->ssid->len <= IW_ESSID_MAX_SIZE) {
+		bss->essid_len = req->ssid->len;
+		memcpy(bss->essid, req->ssid->ssid, req->ssid->len);
+		bss->essid[req->ssid->len] = '\0';
+	} else {
+		/* Either no ESSID IE or oversized one */
+		printk("%s: received packet has bogus ESSID\n",
+						    priv->netdev->name);
+	}
+
+	if (req->ds_parms)
+		bss->channel = req->ds_parms->curr_ch;
+	if (req->cap_info)
+		bss->cap_info = ieee2host16(*req->cap_info);
+
+	bss->sir = acx_signal_to_winlevel(rxbuf->phy_level);
+	bss->snr = acx_signal_to_winlevel(rxbuf->phy_snr);
+
+	bss->rate_cap = 0;	/* operational mask */
+	bss->rate_bas = 0;	/* basic mask */
+	if (req->supp_rates)
+		add_bits_to_ratemasks(req->supp_rates->rates,
+			req->supp_rates->len, &bss->rate_bas, &bss->rate_cap);
+	if (req->ext_rates)
+		add_bits_to_ratemasks(req->ext_rates->rates,
+			req->ext_rates->len, &bss->rate_bas, &bss->rate_cap);
+	/* Fix up any possible bogosity - code elsewhere
+	 * is not expecting empty masks */
+	if (!bss->rate_cap)
+		bss->rate_cap = priv->rate_basic;
+	if (!bss->rate_bas)
+		bss->rate_bas = 1 << lowest_bit(bss->rate_cap);
+	if (!bss->rate_cur)
+		bss->rate_cur = 1 << lowest_bit(bss->rate_bas);
+
+	/* People moan about this being too noisy at L_ASSOC */
+	acxlog(L_DEBUG,
+		"found %s: ESSID='%s' ch=%d "
+		"BSSID="MACSTR" caps=0x%04X SIR=%d SNR=%d\n",
+		(bss->cap_info & WF_MGMT_CAP_IBSS) ? "Ad-Hoc peer" : "AP",
+		bss->essid, bss->channel, MAC(bss->bssid), bss->cap_info,
+		bss->sir, bss->snr);
+ok:
+	FN_EXIT0;
+	return OK;
+}
+
+
+/*----------------------------------------------------------------
+* get_status_string
+*----------------------------------------------------------------*/
+static const char*
+get_status_string(unsigned int status)
+{
+	/* A bit shortened, but hopefully still understandable */
+	static const char * const status_str[] = {
+	/* 0 */	"Successful",
+	/* 1 */	"Unspecified failure",
+	/* 2 */	"reserved",
+	/* 3 */	"reserved",
+	/* 4 */	"reserved",
+	/* 5 */	"reserved",
+	/* 6 */	"reserved",
+	/* 7 */	"reserved",
+	/* 8 */	"reserved",
+	/* 9 */	"reserved",
+	/*10 */	"Cannot support all requested capabilities in Capability Information field",
+	/*11 */	"Reassoc denied (reason outside of 802.11b scope)",
+	/*12 */	"Assoc denied (reason outside of 802.11b scope), maybe MAC filtering by peer?",
+	/*13 */	"Responding station doesnt support specified auth algorithm",
+	/*14 */	"Auth rejected: wrong transaction sequence number",
+	/*15 */	"Auth rejected: challenge failure",
+	/*16 */	"Auth rejected: timeout for next frame in sequence",
+	/*17 */	"Assoc denied: too many STAs on this AP",
+	/*18 */	"Assoc denied: requesting STA doesnt support all data rates in basic set",
+	/*19 */	"Assoc denied: requesting STA doesnt support Short Preamble",
+	/*20 */	"Assoc denied: requesting STA doesnt support PBCC Modulation",
+	/*21 */	"Assoc denied: requesting STA doesnt support Channel Agility"
+	/*22 */	"reserved",
+	/*23 */	"reserved",
+	/*24 */	"reserved",
+	/*25 */	"Assoc denied: requesting STA doesnt support Short Slot Time",
+	/*26 */	"Assoc denied: requesting STA doesnt support DSSS-OFDM"
+	};
+
+	return status_str[status < VEC_SIZE(status_str) ? status : 2];
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_assocresp
+*----------------------------------------------------------------*/
+static int
+acx_l_process_assocresp(wlandevice_t *priv, const wlan_fr_assocresp_t *req)
+{
+	const wlan_hdr_t *hdr;
+	int res = OK;
+
+	FN_ENTER;
+	hdr = req->hdr;
+
+	if ((ACX_MODE_2_STA == priv->mode)
+	 && mac_is_equal(priv->dev_addr, hdr->a1)) {
+		u16 st = ieee2host16(*(req->status));
+		if (WLAN_MGMT_STATUS_SUCCESS == st) {
+			priv->aid = ieee2host16(*(req->aid));
+			/* tell the card we are associated when we are out of interrupt context */
+			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_ASSOCIATE);
+		} else {
+
+			/* TODO: we shall delete peer from sta_list, and try other candidates... */
+
+			printk("%s: association FAILED: peer sent "
+				"response code %d (%s)\n",
+				priv->netdev->name, st, get_status_string(st));
+			res = NOT_OK;
+		}
+	}
+
+	FN_EXIT1(res);
+	return res;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_reassocresp
+*----------------------------------------------------------------*/
+static int
+acx_l_process_reassocresp(wlandevice_t *priv, const wlan_fr_reassocresp_t *req)
+{
+	const wlan_hdr_t *hdr;
+	int result = NOT_OK;
+	u16 st;
+
+	FN_ENTER;
+	hdr = req->hdr;
+
+	if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
+		goto end;
+	}
+	st = ieee2host16(*(req->status));
+	if (st == WLAN_MGMT_STATUS_SUCCESS) {
+		acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
+		result = OK;
+	} else {
+		printk("%s: reassociation FAILED: peer sent "
+			"response code %d (%s)\n",
+			priv->netdev->name, st, get_status_string(st));
+	}
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_process_authen
+*
+* Called only in STA_SCAN or AP mode
+*----------------------------------------------------------------*/
+static int
+acx_l_process_authen(wlandevice_t *priv, const wlan_fr_authen_t *req)
+{
+	const wlan_hdr_t *hdr;
+	client_t *clt;
+	wlan_ie_challenge_t *chal;
+	u16 alg, seq, status;
+	int ap, result;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if (acx_debug & L_ASSOC) {
+		acx_print_mac("AUTHEN priv->addr=", priv->dev_addr, " ");
+		acx_print_mac("a1=", hdr->a1, " ");
+		acx_print_mac("a2=", hdr->a2, " ");
+		acx_print_mac("a3=", hdr->a3, " ");
+		acx_print_mac("priv->bssid=", priv->bssid, "\n");
+	}
+
+	/* TODO: move first check up in caller chain,
+	** it's not auth specific */
+	if (!mac_is_equal(priv->dev_addr, hdr->a1)
+	 || !mac_is_equal(priv->bssid, hdr->a3)) {
+		result = OK;
+		goto end;
+	}
+
+	alg = ieee2host16(*(req->auth_alg));
+	seq = ieee2host16(*(req->auth_seq));
+	status = ieee2host16(*(req->status));
+
+	ap = (priv->mode == ACX_MODE_3_AP);
+
+	if (priv->auth_alg <= 1) {
+		if (priv->auth_alg != alg) {
+			acxlog(L_ASSOC, "authentication algorithm mismatch: "
+				"want: %d, req: %d\n", priv->auth_alg, alg);
+			result = NOT_OK;
+			goto end;
+		}
+	}
+	acxlog(L_ASSOC, "algorithm is ok\n");
+
+	if (ap) {
+		clt = acx_l_sta_list_get_or_add(priv, hdr->a2);
+		if (STA_LIST_ADD_CAN_FAIL && !clt) {
+			acxlog(L_ASSOC, "could not allocate room for client\n");
+			result = NOT_OK;
+			goto end;
+		}
+	} else {
+		clt = priv->ap_client;
+		if (!mac_is_equal(clt->address, hdr->a2)) {
+			printk("%s: malformed auth frame from AP?!\n",
+					priv->netdev->name);
+			result = NOT_OK;
+			goto end;
+		}
+	}
+
+	/* now check which step in the authentication sequence we are
+	 * currently in, and act accordingly */
+	acxlog(L_ASSOC, "acx_process_authen auth seq step %d\n", seq);
+	switch (seq) {
+	case 1:
+		if (!ap)
+			break;
+		acx_l_transmit_authen2(priv, req, clt);
+		break;
+	case 2:
+		if (ap)
+			break;
+		if (status == WLAN_MGMT_STATUS_SUCCESS) {
+			if (alg == WLAN_AUTH_ALG_OPENSYSTEM) {
+				acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
+				acx_l_transmit_assoc_req(priv);
+			} else
+			if (alg == WLAN_AUTH_ALG_SHAREDKEY) {
+				acx_l_transmit_authen3(priv, req);
+			}
+		} else {
+			printk("%s: auth FAILED: peer sent "
+				"response code %d (%s), "
+				"still waiting for authentication\n",
+				priv->netdev->name,
+				status,	get_status_string(status));
+			acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
+		}
+		break;
+	case 3:
+		if (!ap)
+			break;
+		if ((clt->auth_alg != WLAN_AUTH_ALG_SHAREDKEY)
+		 || (alg != WLAN_AUTH_ALG_SHAREDKEY)
+		 || (clt->auth_step != 2))
+			break;
+		chal = req->challenge;
+		if (!chal
+		 || memcmp(chal->challenge, clt->challenge_text, WLAN_CHALLENGE_LEN)
+		 || (chal->eid != WLAN_EID_CHALLENGE)
+		 || (chal->len != WLAN_CHALLENGE_LEN)
+		)
+			break;
+		acx_l_transmit_authen4(priv, req);
+		MAC_COPY(clt->address, hdr->a2);
+		clt->used = CLIENT_AUTHENTICATED_2;
+		clt->auth_step = 4;
+		clt->seq = ieee2host16(hdr->seq);
+		break;
+	case 4:
+		if (ap)
+			break;
+		/* ok, we're through: we're authenticated. Woohoo!! */
+		acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
+		acxlog(L_ASSOC, "Authenticated!\n");
+		/* now that we're authenticated, request association */
+		acx_l_transmit_assoc_req(priv);
+		break;
+	}
+	result = NOT_OK;
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/*----------------------------------------------------------------
+* acx_gen_challenge
+*----------------------------------------------------------------*/
+static void
+acx_gen_challenge(wlan_ie_challenge_t* d)
+{
+	FN_ENTER;
+	d->eid = WLAN_EID_CHALLENGE;
+	d->len = WLAN_CHALLENGE_LEN;
+	get_random_bytes(d->challenge, WLAN_CHALLENGE_LEN);
+	FN_EXIT0;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_transmit_deauthen
+*----------------------------------------------------------------*/
+static int
+acx_l_transmit_deauthen(wlandevice_t *priv, const u8 *addr, u16 reason)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct deauthen_frame_body *body;
+
+	FN_ENTER;
+
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto bad;
+	body = (void*)(head + 1);
+
+	head->fc = (WF_FTYPE_MGMTi | WF_FSTYPE_DEAUTHENi);
+	head->dur = 0;
+	MAC_COPY(head->da, addr);
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, priv->bssid);
+	head->seq = 0;
+
+	acxlog(L_DEBUG | L_ASSOC | L_XFER,
+		"sending deauthen to "MACSTR" for %d\n",
+		MAC(addr), reason);
+
+	body->reason = host2ieee16(reason);
+
+	/* body is fixed size here, but beware of cutting-and-pasting this -
+	** do not use sizeof(*body) for variable sized mgmt packets! */
+	acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
+
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_transmit_authen1
+*----------------------------------------------------------------*/
+static int
+acx_l_transmit_authen1(wlandevice_t *priv)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+
+	FN_ENTER;
+
+	acxlog(L_ASSOC, "Sending authentication1 request, "
+		"awaiting response!\n");
+
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto bad;
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_AUTHENi;
+	head->dur = host2ieee16(0x8000);
+	MAC_COPY(head->da, priv->bssid);
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, priv->bssid);
+	head->seq = 0;
+
+	body->auth_alg = host2ieee16(priv->auth_alg);
+	body->auth_seq = host2ieee16(1);
+	body->status = host2ieee16(0);
+
+	acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
+
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_transmit_authen2
+*----------------------------------------------------------------*/
+static int
+acx_l_transmit_authen2(wlandevice_t *priv, const wlan_fr_authen_t *req,
+		      client_t *clt)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+	unsigned int packet_len;
+
+	FN_ENTER;
+
+	if (!clt)
+		goto ok;
+
+	MAC_COPY(clt->address, req->hdr->a2);
+#ifdef UNUSED
+	clt->ps = ((WF_FC_PWRMGTi & req->hdr->fc) != 0);
+#endif
+	clt->auth_alg = ieee2host16(*(req->auth_alg));
+	clt->auth_step = 2;
+	clt->seq = ieee2host16(req->hdr->seq);
+
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto bad;
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, req->hdr->a2);
+	/* MAC_COPY(head->sa, req->hdr->a1); */
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, req->hdr->a3);
+	head->seq = req->hdr->seq;
+
+	/* already in IEEE format, no endianness conversion */
+	body->auth_alg = *(req->auth_alg);
+	body->auth_seq = host2ieee16(2);
+	body->status = host2ieee16(0);
+
+	packet_len = WLAN_HDR_A3_LEN + 2 + 2 + 2;
+	if (ieee2host16(*(req->auth_alg)) == WLAN_AUTH_ALG_OPENSYSTEM) {
+		clt->used = CLIENT_AUTHENTICATED_2;
+	} else {	/* shared key */
+		acx_gen_challenge(&body->challenge);
+		memcpy(&clt->challenge_text, body->challenge.challenge, WLAN_CHALLENGE_LEN);
+		packet_len += 2 + 2 + 2 + 1+1+WLAN_CHALLENGE_LEN;
+	}
+
+	acxlog_mac(L_ASSOC | L_XFER,
+		"transmit_auth2: BSSID=", head->bssid, "\n");
+
+	acx_l_tx_data(priv, tx, packet_len);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_transmit_authen3
+*----------------------------------------------------------------*/
+static int
+acx_l_transmit_authen3(wlandevice_t *priv, const wlan_fr_authen_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+	unsigned int packet_len;
+
+	FN_ENTER;
+
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto ok;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto ok;
+	body = (void*)(head + 1);
+
+	head->fc = WF_FC_ISWEPi + WF_FSTYPE_AUTHENi;
+	/* FIXME: is this needed?? authen4 does it...
+	head->dur = req->hdr->dur;
+	head->seq = req->hdr->seq;
+	*/
+	MAC_COPY(head->da, priv->bssid);
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, priv->bssid);
+
+	/* already in IEEE format, no endianness conversion */
+	body->auth_alg = *(req->auth_alg);
+	body->auth_seq = host2ieee16(3);
+	body->status = host2ieee16(0);
+	memcpy(&body->challenge, req->challenge, req->challenge->len + 2);
+	packet_len = WLAN_HDR_A3_LEN + 8 + req->challenge->len;
+
+	acxlog(L_ASSOC | L_XFER, "transmit_authen3!\n");
+
+	acx_l_tx_data(priv, tx, packet_len);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_transmit_authen4
+*----------------------------------------------------------------*/
+static int
+acx_l_transmit_authen4(wlandevice_t *priv, const wlan_fr_authen_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+
+	FN_ENTER;
+
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto ok;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto ok;
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, req->hdr->a2);
+	/* MAC_COPY(head->sa, req->hdr->a1); */
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, req->hdr->a3);
+	head->seq = req->hdr->seq;
+
+	/* already in IEEE format, no endianness conversion */
+	body->auth_alg = *(req->auth_alg);
+	body->auth_seq = host2ieee16(4);
+	body->status = host2ieee16(0);
+
+	acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_transmit_assoc_req
+*
+* priv->ap_client is a current candidate AP here
+*----------------------------------------------------------------*/
+static int
+acx_l_transmit_assoc_req(wlandevice_t *priv)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	u8 *body, *p, *prate;
+	unsigned int packet_len;
+	u16 cap;
+
+	FN_ENTER;
+
+	acxlog(L_ASSOC, "sending association request, "
+			"awaiting response. NOT ASSOCIATED YET\n");
+	tx = acx_l_alloc_tx(priv);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(priv, tx);
+	if (!head)
+		goto bad;
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_ASSOCREQi;
+	head->dur = host2ieee16(0x8000);
+	MAC_COPY(head->da, priv->bssid);
+	MAC_COPY(head->sa, priv->dev_addr);
+	MAC_COPY(head->bssid, priv->bssid);
+	head->seq = 0;
+
+	p = body;
+	/* now start filling the AssocReq frame body */
+
+	/* since this assoc request will most likely only get
+	 * sent in the STA to AP case (and not when Ad-Hoc IBSS),
+	 * the cap combination indicated here will thus be
+	 * WF_MGMT_CAP_ESSi *always* (no IBSS ever)
+	 * The specs are more than non-obvious on all that:
+	 *
+	 * 802.11 7.3.1.4 Capability Information field
+	** APs set the ESS subfield to 1 and the IBSS subfield to 0 within
+	** Beacon or Probe Response management frames. STAs within an IBSS
+	** set the ESS subfield to 0 and the IBSS subfield to 1 in transmitted
+	** Beacon or Probe Response management frames
+	**
+	** APs set the Privacy subfield to 1 within transmitted Beacon,
+	** Probe Response, Association Response, and Reassociation Response
+	** if WEP is required for all data type frames within the BSS.
+	** STAs within an IBSS set the Privacy subfield to 1 in Beacon
+	** or Probe Response management frames if WEP is required
+	** for all data type frames within the IBSS */
+
+	/* note that returning 0 will be refused by several APs...
+	 * (so this indicates that you're probably supposed to
+	 * "confirm" the ESS mode) */
+	cap = WF_MGMT_CAP_ESSi;
+
+	/* this one used to be a check on wep_restricted,
+	 * but more likely it's wep_enabled instead */
+	if (priv->wep_enabled)
+		SET_BIT(cap, WF_MGMT_CAP_PRIVACYi);
+
+	/* Probably we can just set these always, because our hw is
+	** capable of shortpre and PBCC --vda */
+	/* only ask for short preamble if the peer station supports it */
+	if (priv->ap_client->cap_info & WF_MGMT_CAP_SHORT)
+		SET_BIT(cap, WF_MGMT_CAP_SHORTi);
+	/* only ask for PBCC support if the peer station supports it */
+	if (priv->ap_client->cap_info & WF_MGMT_CAP_PBCC)
+		SET_BIT(cap, WF_MGMT_CAP_PBCCi);
+
+	/* IEs: 1. caps */
+	*(u16*)p = cap;	p += 2;
+	/* 2. listen interval */
+	*(u16*)p = host2ieee16(priv->listen_interval); p += 2;
+	/* 3. ESSID */
+	p = wlan_fill_ie_ssid(p,
+			strlen(priv->essid_for_assoc), priv->essid_for_assoc);
+	/* 4. supp rates */
+	prate = p;
+	p = wlan_fill_ie_rates(p,
+			priv->rate_supported_len, priv->rate_supported);
+	/* 5. ext supp rates */
+	p = wlan_fill_ie_rates_ext(p,
+			priv->rate_supported_len, priv->rate_supported);
+
+	if (acx_debug & L_DEBUG) {
+		printk("association: rates element\n");
+		acx_dump_bytes(prate, p - prate);
+	}
+
+	/* calculate lengths */
+	packet_len = WLAN_HDR_A3_LEN + (p - body);
+
+	acxlog(L_ASSOC, "association: requesting caps 0x%04X, ESSID '%s'\n",
+		cap, priv->essid_for_assoc);
+
+	acx_l_tx_data(priv, tx, packet_len);
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/*----------------------------------------------------------------
+* acx_l_transmit_disassoc
+*
+* FIXME: looks like incomplete implementation of a helper:
+* acx_l_transmit_disassoc(priv, clt) - kick this client (we're an AP)
+* acx_l_transmit_disassoc(priv, NULL) - leave BSSID (we're a STA)
+*----------------------------------------------------------------*/
+#ifdef BROKEN
+int
+acx_l_transmit_disassoc(wlandevice_t *priv, client_t *clt)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct disassoc_frame_body *body;
+
+	FN_ENTER;
+/*	if (clt != NULL) { */
+		tx = acx_l_alloc_tx(priv);
+		if (!tx)
+			goto bad;
+		head = acx_l_get_txbuf(priv, tx);
+		if (!head)
+			goto bad;
+		body = (void*)(head + 1);
+
+/*		clt->used = CLIENT_AUTHENTICATED_2; - not (yet?) associated */
+
+		head->fc = WF_FSTYPE_DISASSOCi;
+		head->dur = 0;
+		/* huh? It muchly depends on whether we're STA or AP...
+		** sta->ap: da=bssid, sa=own, bssid=bssid
+		** ap->sta: da=sta, sa=bssid, bssid=bssid. FIXME! */
+		MAC_COPY(head->da, priv->bssid);
+		MAC_COPY(head->sa, priv->dev_addr);
+		MAC_COPY(head->bssid, priv->dev_addr);
+		head->seq = 0;
+
+		/* "Class 3 frame received from nonassociated station." */
+		body->reason = host2ieee16(7);
+
+		/* fixed size struct, ok to sizeof */
+		acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
+/*	} */
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+#endif
+
+
+/*----------------------------------------------------------------
+* acx_s_complete_scan
+*
+* Called either from after_interrupt_task() if:
+* 1) there was Scan_Complete IRQ, or
+* 2) scanning expired in timer()
+* We need to decide which ESS or IBSS to join.
+* Iterates thru priv->sta_list:
+*	if priv->ap is not bcast, will join only specified
+*	ESS or IBSS with this bssid
+*	checks peers' caps for ESS/IBSS bit
+*	checks peers' SSID, allows exact match or hidden SSID
+* If station to join is chosen:
+*	points priv->ap_client to the chosen struct client
+*	sets priv->essid_for_assoc for future assoc attempt
+* Auth/assoc is not yet performed
+* Returns OK if there is no need to restart scan
+*----------------------------------------------------------------*/
+int
+acx_s_complete_scan(wlandevice_t *priv)
+{
+	struct client *bss;
+	unsigned long flags;
+	u16 needed_cap;
+	int i;
+	int idx_found = -1;
+	int result = OK;
+
+	FN_ENTER;
+
+	switch (priv->mode) {
+	case ACX_MODE_0_ADHOC:
+		needed_cap = WF_MGMT_CAP_IBSS; /* 2, we require Ad-Hoc */
+		break;
+	case ACX_MODE_2_STA:
+		needed_cap = WF_MGMT_CAP_ESS; /* 1, we require Managed */
+		break;
+	default:
+		printk("acx: driver bug: mode=%d in complete_scan()\n", priv->mode);
+		dump_stack();
+		goto end;
+	}
+
+	acx_lock(priv, flags);
+
+	/* TODO: sta_iterator hiding implementation would be nice here... */
+
+	for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
+		bss = &priv->sta_list[i];
+		if (!bss->used) continue;
+
+		acxlog(L_ASSOC, "Scan Table: SSID='%s' CH=%d SIR=%d SNR=%d\n",
+			bss->essid, bss->channel, bss->sir, bss->snr);
+
+		if (!mac_is_bcast(priv->ap))
+			if (!mac_is_equal(bss->bssid, priv->ap))
+				continue; /* keep looking */
+
+		/* broken peer with no mode flags set? */
+		if (unlikely(!(bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)))) {
+			printk("%s: strange peer "MACSTR" found with "
+				"neither ESS (AP) nor IBSS (Ad-Hoc) "
+				"capability - skipped\n",
+				priv->netdev->name, MAC(bss->address));
+			continue;
+		}
+		acxlog(L_ASSOC, "peer_cap 0x%04X, needed_cap 0x%04X\n",
+		       bss->cap_info, needed_cap);
+
+		/* does peer station support what we need? */
+		if ((bss->cap_info & needed_cap) != needed_cap)
+			continue; /* keep looking */
+
+		/* strange peer with NO basic rates?! */
+		if (unlikely(!bss->rate_bas)) {
+			printk("%s: strange peer "MACSTR" with empty rate set "
+				"- skipped\n",
+				priv->netdev->name, MAC(bss->address));
+			continue;
+		}
+
+		/* do we support all basic rates of this peer? */
+		if ((bss->rate_bas & priv->rate_oper) != bss->rate_bas)	{
+/* we probably need to have all rates as operational rates,
+   even in case of an 11M-only configuration */
+#ifdef THIS_IS_TROUBLESOME
+			printk("%s: peer "MACSTR": incompatible basic rates "
+				"(AP requests 0x%04X, we have 0x%04X) "
+				"- skipped\n",
+				priv->netdev->name, MAC(bss->address),
+				bss->rate_bas, priv->rate_oper);
+			continue;
+#else
+			printk("%s: peer "MACSTR": incompatible basic rates "
+				"(AP requests 0x%04X, we have 0x%04X). "
+				"Considering anyway...\n",
+				priv->netdev->name, MAC(bss->address),
+				bss->rate_bas, priv->rate_oper);
+#endif
+		}
+
+		if ( !(priv->reg_dom_chanmask & (1<<(bss->channel-1))) ) {
+			printk("%s: warning: peer "MACSTR" is on channel %d "
+				"outside of channel range of current "
+				"regulatory domain - couldn't join "
+				"even if other settings match. "
+				"You might want to adapt your config\n",
+				priv->netdev->name, MAC(bss->address),
+				bss->channel);
+			continue; /* keep looking */
+		}
+
+		if (!priv->essid_active || !strcmp(bss->essid, priv->essid)) {
+			acxlog(L_ASSOC,
+			       "found station with matching ESSID! ('%s' "
+			       "station, '%s' config)\n",
+			       bss->essid,
+			       (priv->essid_active) ? priv->essid : "[any]");
+			/* TODO: continue looking for peer with better SNR */
+			bss->used = CLIENT_JOIN_CANDIDATE;
+			idx_found = i;
+
+			/* stop searching if this station is
+			 * on the current channel, otherwise
+			 * keep looking for an even better match */
+			if (bss->channel == priv->channel)
+				break;
+		} else
+		if (!bss->essid[0]
+		 || ((' ' == bss->essid[0]) && !bss->essid[1])
+		) {
+			/* hmm, station with empty or single-space SSID:
+			 * using hidden SSID broadcast?
+			 */
+			/* This behaviour is broken: which AP from zillion
+			** of APs with hidden SSID you'd try?
+			** We should use Probe requests to get Probe responses
+			** and check for real SSID (are those never hidden?) */
+			bss->used = CLIENT_JOIN_CANDIDATE;
+			if (idx_found == -1)
+				idx_found = i;
+			acxlog(L_ASSOC, "found station with empty or "
+				"single-space (hidden) SSID, considering "
+				"for assoc attempt\n");
+			/* ...and keep looking for better matches */
+		} else {
+			acxlog(L_ASSOC, "ESSID doesn't match! ('%s' "
+				"station, '%s' config)\n",
+				bss->essid,
+				(priv->essid_active) ? priv->essid : "[any]");
+		}
+	}
+
+	/* TODO: iterate thru join candidates instead */
+	/* TODO: rescan if not associated within some timeout */
+	if (idx_found != -1) {
+		char *essid_src;
+		size_t essid_len;
 
+		bss = &priv->sta_list[idx_found];
+		priv->ap_client = bss;
 
-/*----------------------------------------------------------------
-* acx_l_process_mgmt_frame
-*
-* Theory of operation: mgmt packet gets parsed (to make it easy
-* to access variable-sized IEs), results stored in 'parsed'.
-* Then we react to the packet.
-* NB: wlan_mgmt_decode_XXX are dev-independent (shoudnt have been named acx_XXX)
-*----------------------------------------------------------------*/
-typedef union parsed_mgmt_req {
-	wlan_fr_mgmt_t mgmt;
-	wlan_fr_assocreq_t assocreq;
-	wlan_fr_reassocreq_t reassocreq;
-	wlan_fr_assocresp_t assocresp;
-	wlan_fr_reassocresp_t reassocresp;
-	wlan_fr_beacon_t beacon;
-	wlan_fr_disassoc_t disassoc;
-	wlan_fr_authen_t authen;
-	wlan_fr_deauthen_t deauthen;
-	wlan_fr_proberesp_t proberesp;
-} parsed_mgmt_req_t;
+		if (bss->essid[0] == '\0') {
+			/* if the ESSID of the station we found is empty
+			 * (no broadcast), then use user configured ESSID
+			 * instead */
+			essid_src = priv->essid;
+			essid_len = priv->essid_len;
+		} else {
+			essid_src = bss->essid;
+			essid_len = strlen(bss->essid);
+		}
 
-extern void BUG_excessive_stack_usage(void);
+		acx_update_capabilities(priv);
 
-static int
-acx_l_process_mgmt_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
-{
-	parsed_mgmt_req_t parsed;	/* takes ~100 bytes of stack */
-	wlan_hdr_t *hdr;
-	int adhoc, sta_scan, sta, ap;
-	int len;
+		memcpy(priv->essid_for_assoc, essid_src, essid_len);
+		priv->essid_for_assoc[essid_len] = '\0';
+		priv->channel = bss->channel;
+		MAC_COPY(priv->bssid, bss->bssid);
 
-	if (sizeof(parsed) > 256) BUG_excessive_stack_usage();
+		bss->rate_cfg = (bss->rate_cap & priv->rate_oper);
+		bss->rate_cur = 1 << lowest_bit(bss->rate_cfg);
+		bss->rate_100 = acx_rate111to100(bss->rate_cur);
 
-	FN_ENTER;
+		acxlog_mac(L_ASSOC,
+			"matching station found: ", priv->bssid, ", joining\n");
 
-	hdr = acx_get_wlan_hdr(priv, rxbuf);
+		/* TODO: do we need to switch to the peer's channel first? */
 
-	/* Management frames never have these set */
-	if (WF_FC_FROMTODSi & hdr->fc) {
-		FN_EXIT1(NOT_OK);
-		return NOT_OK;
+		if (ACX_MODE_0_ADHOC == priv->mode) {
+			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
+		} else {
+			acx_l_transmit_authen1(priv);
+			acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
+		}
+	} else { /* idx_found == -1 */
+		/* uh oh, no station found in range */
+		if (ACX_MODE_0_ADHOC == priv->mode) {
+			printk("%s: no matching station found in range, "
+				"generating our own IBSS instead\n",
+				priv->netdev->name);
+			/* we do it hostap way: */
+			MAC_COPY(priv->bssid, priv->dev_addr);
+			priv->bssid[0] |= 0x02; /* 'local assigned addr' bit */
+			/* add IBSS bit to our caps... */
+			acx_update_capabilities(priv);
+			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
+			/* In order to cmd_join be called below */
+			idx_found = 0;
+		} else {
+			/* we shall scan again, AP can be
+			** just temporarily powered off */
+			acxlog(L_ASSOC,
+				"no matching station found in range yet\n");
+			acx_set_status(priv, ACX_STATUS_1_SCANNING);
+			result = NOT_OK;
+		}
 	}
 
-	len = RXBUF_BYTES_RCVD(rxbuf);
-	if (WF_FC_ISWEPi & hdr->fc)
-		len -= 0x10;
+	acx_unlock(priv, flags);
 
-	adhoc = (priv->mode == ACX_MODE_0_ADHOC);
-	sta_scan = ((priv->mode == ACX_MODE_2_STA)
-		 && (priv->status != ACX_STATUS_4_ASSOCIATED));
-	sta = ((priv->mode == ACX_MODE_2_STA)
-	    && (priv->status == ACX_STATUS_4_ASSOCIATED));
-	ap = (priv->mode == ACX_MODE_3_AP);
+	if (idx_found != -1) {
+		if (ACX_MODE_0_ADHOC == priv->mode) {
+			/* need to update channel in beacon template */
+			SET_BIT(priv->set_mask, SET_TEMPLATES);
+			if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
+				acx_s_update_card_settings(priv, 0, 0);
+		}
+		/* Inform firmware on our decision to start or join BSS */
+		acx_s_cmd_join_bssid(priv, priv->bssid);
+	}
 
-	switch (WF_FC_FSTYPEi & hdr->fc) {
-	/* beacons first, for speed */
-	case WF_FSTYPE_BEACONi:
-		memset(&parsed.beacon, 0, sizeof(parsed.beacon));
-		parsed.beacon.hdr = hdr;
-		parsed.beacon.len = len;
-		if (acx_debug & L_DATA) {
-			printk("BCN len:%d fc:%04X dur:%04X seq:%04X\n",
-			       len, hdr->fc, hdr->dur, hdr->seq);
-			acx_print_mac("BCN a1:", hdr->a1, "\n");
-			acx_print_mac("BCN a2:", hdr->a2, "\n");
-			acx_print_mac("BCN a3:", hdr->a3, "\n");
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_s_read_fw
+**
+** Loads a firmware image
+**
+** Returns:
+**  0				unable to load file
+**  pointer to firmware		success
+*/
+#if USE_FW_LOADER_26
+firmware_image_t*
+acx_s_read_fw(struct device *dev, const char *file, u32 *size)
+#else
+#undef acx_s_read_fw
+firmware_image_t*
+acx_s_read_fw(const char *file, u32 *size)
+#endif
+{
+	firmware_image_t *res;
+
+#if USE_FW_LOADER_LEGACY
+	mm_segment_t orgfs;
+	unsigned long page;
+	char *buffer;
+	struct file *inf;
+	int retval;
+	int offset;
+	char *filename;
+#endif
+
+#if USE_FW_LOADER_26
+	const struct firmware *fw_entry;
+
+	res = NULL;
+	acxlog(L_DEBUG, "requesting firmware image '%s'\n", file);
+	if (!request_firmware(&fw_entry, file, dev)) {
+		*size = 8;
+		if (fw_entry->size >= 8)
+			*size = 8 + le32_to_cpu(*(u32 *)(fw_entry->data + 4));
+		if (fw_entry->size != *size) {
+			printk("acx: firmware size does not match "
+				"firmware header: %d != %d, "
+				"aborting fw upload\n",
+				(int) fw_entry->size, (int) *size);
+			goto release_ret;
 		}
-		wlan_mgmt_decode_beacon(&parsed.beacon);
-		/* beacon and probe response are very similar, so... */
-		acx_l_process_probe_response(priv, &parsed.beacon, rxbuf);
-		break;
-	case WF_FSTYPE_ASSOCREQi:
-		if (!ap)
-			break;
-		memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
-		parsed.assocreq.hdr = hdr;
-		parsed.assocreq.len = len;
-		wlan_mgmt_decode_assocreq(&parsed.assocreq);
-		if (mac_is_equal(hdr->a1, priv->bssid)
-		 && mac_is_equal(hdr->a3, priv->bssid)) {
-			acx_l_transmit_assocresp(priv, &parsed.assocreq);
+		res = vmalloc(*size);
+		if (!res) {
+			printk("acx: no memory for firmware "
+				"(%u bytes)\n", *size);
+			goto release_ret;
 		}
-		break;
-	case WF_FSTYPE_REASSOCREQi:
-		if (!ap)
-			break;
-		memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
-		parsed.assocreq.hdr = hdr;
-		parsed.assocreq.len = len;
-		wlan_mgmt_decode_assocreq(&parsed.assocreq);
-		/* reassocreq and assocreq are equivalent */
-		acx_l_transmit_reassocresp(priv, &parsed.reassocreq);
-		break;
-	case WF_FSTYPE_ASSOCRESPi:
-		if (!sta_scan)
-			break;
-		memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
-		parsed.assocresp.hdr = hdr;
-		parsed.assocresp.len = len;
-		wlan_mgmt_decode_assocresp(&parsed.assocresp);
-		acx_l_process_assocresp(priv, &parsed.assocresp);
-		break;
-	case WF_FSTYPE_REASSOCRESPi:
-		if (!sta_scan)
-			break;
-		memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
-		parsed.assocresp.hdr = hdr;
-		parsed.assocresp.len = len;
-		wlan_mgmt_decode_assocresp(&parsed.assocresp);
-		acx_l_process_reassocresp(priv, &parsed.reassocresp);
-		break;
-	case WF_FSTYPE_PROBEREQi:
-		if (ap || adhoc) {
-			/* FIXME: since we're supposed to be an AP,
-			** we need to return a Probe Response packet.
-			** Currently firmware is doing it for us,
-			** but firmware is buggy! See comment elsewhere --vda */
+		memcpy(res, fw_entry->data, fw_entry->size);
+release_ret:
+		release_firmware(fw_entry);
+		return res;
+	}
+	printk("acx: firmware image '%s' was not provided. "
+		"Check your hotplug scripts\n", file);
+#endif
+
+#if USE_FW_LOADER_LEGACY
+	printk("acx: firmware upload via firmware_dir module parameter "
+		"is deprecated. Switch to using hotplug\n");
+
+	res = NULL;
+	orgfs = get_fs(); /* store original fs */
+	set_fs(KERNEL_DS);
+
+	/* Read in whole file then check the size */
+	page = __get_free_page(GFP_KERNEL);
+	if (unlikely(0 == page)) {
+		printk("acx: no memory for firmware upload\n");
+		goto fail;
+	}
+
+	filename = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (unlikely(!filename)) {
+		printk("acx: no memory for firmware upload\n");
+		goto fail;
+	}
+	if (!firmware_dir) {
+		firmware_dir = "/usr/share/acx";
+		acxlog(L_DEBUG, "no firmware directory specified "
+			"via module parameter firmware_dir, "
+			"using default %s\n", firmware_dir);
+	}
+	snprintf(filename, PATH_MAX, "%s/%s", firmware_dir, file);
+	acxlog(L_DEBUG, "reading firmware image '%s'\n", filename);
+
+	buffer = (char*)page;
+
+	/* Note that file must be given as absolute path:
+	 * a relative path works on first loading,
+	 * but any subsequent firmware loading during card
+	 * eject/insert will fail, most likely since the first
+	 * module loading happens in user space (and thus
+	 * filp_open can figure out the absolute path from a
+	 * relative path) whereas the card reinsert processing
+	 * probably happens in kernel space where you don't have
+	 * a current directory to be able to figure out an
+	 * absolute path from a relative path... */
+	inf = filp_open(filename, O_RDONLY, 0);
+	kfree(filename);
+	if (OK != IS_ERR(inf)) {
+		const char *err;
+
+		switch (-PTR_ERR(inf)) {
+			case 2: err = "file not found";
+				break;
+			default:
+				err = "unknown error";
+				break;
 		}
-		break;
-	case WF_FSTYPE_PROBERESPi:
-		memset(&parsed.proberesp, 0, sizeof(parsed.proberesp));
-		parsed.proberesp.hdr = hdr;
-		parsed.proberesp.len = len;
-		wlan_mgmt_decode_proberesp(&parsed.proberesp);
-		acx_l_process_probe_response(priv, &parsed.proberesp, rxbuf);
-		break;
-	case 6:
-	case 7:
-		/* exit */
-		break;
-	case WF_FSTYPE_ATIMi:
-		/* exit */
-		break;
-	case WF_FSTYPE_DISASSOCi:
-		if (!sta && !ap)
-			break;
-		memset(&parsed.disassoc, 0, sizeof(parsed.disassoc));
-		parsed.disassoc.hdr = hdr;
-		parsed.disassoc.len = len;
-		wlan_mgmt_decode_disassoc(&parsed.disassoc);
-		if (sta)
-			acx_l_process_disassoc_from_ap(priv, &parsed.disassoc);
-		else
-			acx_l_process_disassoc_from_sta(priv, &parsed.disassoc);
-		break;
-	case WF_FSTYPE_AUTHENi:
-		if (!sta_scan && !ap)
-			break;
-		memset(&parsed.authen, 0, sizeof(parsed.authen));
-		parsed.authen.hdr = hdr;
-		parsed.authen.len = len;
-		wlan_mgmt_decode_authen(&parsed.authen);
-		acx_l_process_authen(priv, &parsed.authen);
-		break;
-	case WF_FSTYPE_DEAUTHENi:
-		if (!sta && !ap)
-			break;
-		memset(&parsed.deauthen, 0, sizeof(parsed.deauthen));
-		parsed.deauthen.hdr = hdr;
-		parsed.deauthen.len = len;
-		wlan_mgmt_decode_deauthen(&parsed.deauthen);
-		if (sta)
-			acx_l_process_deauth_from_ap(priv, &parsed.deauthen);
-		else
-			acx_l_process_deauth_from_sta(priv, &parsed.deauthen);
-		break;
+		printk("acx: error %ld trying to open file '%s': %s\n",
+					-PTR_ERR(inf), file, err);
+		goto fail;
+	}
+
+	if (unlikely((NULL == inf->f_op) || (NULL == inf->f_op->read))) {
+		printk("acx: %s does not have a read method?!\n", file);
+		goto fail_close;
+	}
+
+	offset = 0;
+	do {
+		retval = inf->f_op->read(inf, buffer, PAGE_SIZE, &inf->f_pos);
+
+		if (unlikely(0 > retval)) {
+			printk("acx: error %d reading file '%s'\n",
+							-retval, file);
+			vfree(res);
+			res = NULL;
+		} else if (0 == retval) {
+			if (0 == offset) {
+				printk("acx: firmware image file "
+					"'%s' is empty?!\n", file);
+			}
+		} else if (0 < retval) {
+			/* allocate result buffer here if needed,
+			 * since we don't want to waste resources/time
+			 * (in case file opening/reading fails)
+			 * by doing allocation in front of the loop instead. */
+			if (NULL == res) {
+				*size = 8 + le32_to_cpu(*(u32 *)(4 + buffer));
+
+				res = vmalloc(*size);
+				if (NULL == res) {
+					printk("acx: unable to "
+						"allocate %u bytes for "
+						"firmware module upload\n",
+						*size);
+					goto fail_close;
+				}
+				acxlog(L_DEBUG, "allocated %u bytes "
+					"for firmware module loading\n",
+					*size);
+			}
+			if ((unlikely(offset + retval > *size))) {
+				printk("acx: ERROR: allocation "
+					"was less than firmware image size?!\n");
+				goto fail_close;
+			}
+			memcpy((u8*)res + offset, buffer, retval);
+			offset += retval;
+		}
+	} while (0 < retval);
+
+fail_close:
+	retval = filp_close(inf, NULL);
+
+	if (unlikely(retval)) {
+		printk("acx: error %d closing file '%s'\n", -retval, file);
+	}
+
+	if (unlikely((NULL != res) && (offset != le32_to_cpu(res->size) + 8))) {
+		printk("acx: firmware is reporting a different size "
+			"(0x%08X; 0x%08X was read)\n",
+			le32_to_cpu(res->size) + 8, offset);
+		vfree(res);
+		res = NULL;
 	}
 
-	FN_EXIT1(OK);
-	return OK;
+fail:
+	if (page)
+		free_page(page);
+	set_fs(orgfs);
+#endif
+
+	/* checksum will be verified in write_fw, so don't bother here */
+	return res;
 }
 
 
-#if UNUSED
+#ifdef POWER_SAVE_80211
 /*----------------------------------------------------------------
-* acx_process_class_frame
-*
-* Called from IRQ context only
+* acx_s_activate_power_save_mode
 *----------------------------------------------------------------*/
-static int
-acx_process_class_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
+static void
+acx_s_activate_power_save_mode(wlandevice_t *priv)
 {
-	return OK;
+	acx100_ie_powermgmt_t pm;
+
+	FN_ENTER;
+
+	acx_s_interrogate(priv, &pm, ACX1xx_IE_POWER_MGMT);
+	if (pm.wakeup_cfg != 0x81)
+		goto end;
+
+	pm.wakeup_cfg = 0;
+	pm.options = 0;
+	pm.hangover_period = 0;
+	acx_s_configure(priv, &pm, ACX1xx_IE_POWER_MGMT);
+end:
+	FN_EXIT0;
 }
 #endif
 
 
-/*----------------------------------------------------------------
-* acx_l_process_NULL_frame
-*----------------------------------------------------------------*/
-#if BOGUS_ITS_NOT_A_NULL_FRAME_HANDLER_AT_ALL
-static int
-acx_l_process_NULL_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
+/***********************************************************************
+** acx_s_set_wepkey
+*/
+static void
+acx100_s_set_wepkey(wlandevice_t *priv)
 {
-	const signed char *esi;
-	const u8 *ebx;
-	const wlan_hdr_t *hdr;
-	const client_t *client;
-	int result = NOT_OK;
+	ie_dot11WEPDefaultKey_t dk;
+	int i;
 
-	hdr = acx_get_wlan_hdr(priv, rxbuf);
+	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
+		if (priv->wep_keys[i].size != 0) {
+			acxlog(L_INIT, "setting WEP key: %d with "
+				"total size: %d\n", i, (int) priv->wep_keys[i].size);
+			dk.action = 1;
+			dk.keySize = priv->wep_keys[i].size;
+			dk.defaultKeyNum = i;
+			memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
+			acx_s_configure(priv, &dk, ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE);
+		}
+	}
+}
 
-	switch (WF_FC_FROMTODSi & hdr->fc) {
-	case 0:
-		esi = hdr->a1;
-		ebx = hdr->a2;
-		break;
-	case WF_FC_FROMDSi:
-		esi = hdr->a1;
-		ebx = hdr->a3;
-		break;
-	case WF_FC_TODSi:
-		esi = hdr->a1;
-		ebx = hdr->a2;
-		break;
-	default: /* WF_FC_FROMTODSi */
-		esi = hdr->a1; /* added by me! --vda */
-		ebx = hdr->a2;
+static void
+acx111_s_set_wepkey(wlandevice_t *priv)
+{
+	acx111WEPDefaultKey_t dk;
+	int i;
+
+	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
+		if (priv->wep_keys[i].size != 0) {
+			acxlog(L_INIT, "setting WEP key: %d with "
+				"total size: %d\n", i, (int) priv->wep_keys[i].size);
+			memset(&dk, 0, sizeof(dk));
+			dk.action = cpu_to_le16(1); /* "add key"; yes, that's a 16bit value */
+			dk.keySize = priv->wep_keys[i].size;
+
+			/* are these two lines necessary? */
+			dk.type = 0;              /* default WEP key */
+			dk.index = 0;             /* ignored when setting default key */
+
+			dk.defaultKeyNum = i;
+			memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
+			acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &dk, sizeof(dk));
+		}
 	}
+}
 
-	if (esi[0x0] < 0) {
-		result = OK;
-		goto done;
+static void
+acx_s_set_wepkey(wlandevice_t *priv)
+{
+	if (IS_ACX111(priv))
+		acx111_s_set_wepkey(priv);
+	else
+		acx100_s_set_wepkey(priv);
+}
+
+
+/***********************************************************************
+** acx100_s_init_wep
+**
+** FIXME: this should probably be moved into the new card settings
+** management, but since we're also modifying the memory map layout here
+** due to the WEP key space we want, we should take care...
+*/
+int
+acx100_s_init_wep(wlandevice_t *priv)
+{
+/*	int i;
+	acx100_cmd_wep_mgmt_t wep_mgmt;           size = 37 bytes */
+	acx100_ie_wep_options_t options;
+	ie_dot11WEPDefaultKeyID_t dk;
+	acx_ie_memmap_t pt;
+	int res = NOT_OK;
+
+	FN_ENTER;
+
+	if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		goto fail;
 	}
 
-	client = acx_l_sta_list_get(priv, ebx);
-	if (client)
-		result = NOT_OK;
-	else {
-#if IS_IT_BROKEN
-		acxlog(L_DEBUG | L_XFER, "<transmit_deauth 7>\n");
-		acx_l_transmit_deauthen(priv, ebx,
-			WLAN_MGMT_REASON_CLASS2_NONAUTH /* 6 */);
-#else
-		acxlog(L_DEBUG, "received NULL frame from unknown client! "
-			"We really shouldn't send deauthen here, right?\n");
-#endif
-		result = OK;
+	acxlog(L_DEBUG, "CodeEnd:%X\n", pt.CodeEnd);
+
+	pt.WEPCacheStart = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
+	pt.WEPCacheEnd   = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
+
+	if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		goto fail;
 	}
-done:
+
+	/* let's choose maximum setting: 4 default keys, plus 10 other keys: */
+	options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
+	options.WEPOption = 0x00;
+
+	acxlog(L_ASSOC, "%s: writing WEP options\n", __func__);
+	acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
+
+	acx100_s_set_wepkey(priv);
+
+	if (priv->wep_keys[priv->wep_current_index].size != 0) {
+		acxlog(L_ASSOC, "setting active default WEP key number: %d\n",
+				priv->wep_current_index);
+		dk.KeyID = priv->wep_current_index;
+		acx_s_configure(priv, &dk, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); /* 0x1010 */
+	}
+	/* FIXME!!! wep_key_struct is filled nowhere! But priv
+	 * is initialized to 0, and we don't REALLY need those keys either */
+/*		for (i = 0; i < 10; i++) {
+		if (priv->wep_key_struct[i].len != 0) {
+			MAC_COPY(wep_mgmt.MacAddr, priv->wep_key_struct[i].addr);
+			wep_mgmt.KeySize = cpu_to_le16(priv->wep_key_struct[i].len);
+			memcpy(&wep_mgmt.Key, priv->wep_key_struct[i].key, le16_to_cpu(wep_mgmt.KeySize));
+			wep_mgmt.Action = cpu_to_le16(1);
+			acxlog(L_ASSOC, "writing WEP key %d (len %d)\n", i, le16_to_cpu(wep_mgmt.KeySize));
+			if (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &wep_mgmt, sizeof(wep_mgmt))) {
+				priv->wep_key_struct[i].index = i;
+			}
+		}
+	} */
+
+	/* now retrieve the updated WEPCacheEnd pointer... */
+	if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		printk("%s: ACX1xx_IE_MEMORY_MAP read #2 FAILED\n",
+				priv->netdev->name);
+		goto fail;
+	}
+	/* ...and tell it to start allocating templates at that location */
+	/* (no endianness conversion needed) */
+	pt.PacketTemplateStart = pt.WEPCacheEnd;
+
+	if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		printk("%s: ACX1xx_IE_MEMORY_MAP write #2 FAILED\n",
+				priv->netdev->name);
+		goto fail;
+	}
+	res = OK;
+
+fail:
+	FN_EXIT1(res);
+	return res;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_s_init_max_null_data_template(wlandevice_t *priv)
+{
+	struct acx_template_nullframe b;
+	int result;
+
+	FN_ENTER;
+	memset(&b, 0, sizeof(b));
+	b.size = cpu_to_le16(sizeof(b) - 2);
+	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_NULL_DATA, &b, sizeof(b));
+	FN_EXIT1(result);
 	return result;
 }
-#endif
 
 
-/*----------------------------------------------------------------
-* acx_l_process_probe_response
-*----------------------------------------------------------------*/
+/***********************************************************************
+** acx_s_init_max_beacon_template
+*/
 static int
-acx_l_process_probe_response(wlandevice_t *priv, wlan_fr_proberesp_t *req,
-			const rxbuffer_t *rxbuf)
+acx_s_init_max_beacon_template(wlandevice_t *priv)
 {
-	struct client *bss;
-	wlan_hdr_t *hdr;
+	struct acx_template_beacon b;
+	int result;
 
 	FN_ENTER;
+	memset(&b, 0, sizeof(b));
+	b.size = cpu_to_le16(sizeof(b) - 2);
+	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &b, sizeof(b));
 
-	hdr = req->hdr;
+	FN_EXIT1(result);
+	return result;
+}
 
-	if (mac_is_equal(hdr->a3, priv->dev_addr)) {
-		acxlog(L_ASSOC, "huh, scan found our own MAC!?\n");
-		goto ok; /* just skip this one silently */
-	}
+/***********************************************************************
+** acx_s_init_max_tim_template
+*/
+static int
+acx_s_init_max_tim_template(wlandevice_t *priv)
+{
+	acx_template_tim_t t;
 
-	bss = acx_l_sta_list_get_or_add(priv, hdr->a2);
+	memset(&t, 0, sizeof(t));
+	t.size = cpu_to_le16(sizeof(t) - 2);
+	return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
+}
 
-	/* NB: be careful modifying bss data! It may be one
-	** of already known clients (like our AP is we are a STA)
-	** Thus do not blindly modify e.g. current ratemask! */
 
-	if (STA_LIST_ADD_CAN_FAIL && !bss) {
-		/* uh oh, we found more sites/stations than we can handle with
-		 * our current setup: pull the emergency brake and stop scanning! */
-		acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_STOP_SCAN);
-		/* TODO: a nice comment what below call achieves --vda */
-		acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
-		goto ok;
-	}
-	/* NB: get_or_add already filled bss->address = hdr->a2 */
-	MAC_COPY(bss->bssid, hdr->a3);
+/***********************************************************************
+** acx_s_init_max_probe_response_template
+*/
+static int
+acx_s_init_max_probe_response_template(wlandevice_t *priv)
+{
+	struct acx_template_proberesp pr;
 
-	/* copy the ESSID element */
-	if (req->ssid && req->ssid->len <= IW_ESSID_MAX_SIZE) {
-		bss->essid_len = req->ssid->len;
-		memcpy(bss->essid, req->ssid->ssid, req->ssid->len);
-		bss->essid[req->ssid->len] = '\0';
-	} else {
-		/* Either no ESSID IE or oversized one */
-		printk("%s: received packet has bogus ESSID\n",
-						    priv->netdev->name);
-	}
+	memset(&pr, 0, sizeof(pr));
+	pr.size = cpu_to_le16(sizeof(pr) - 2);
 
-	if (req->ds_parms)
-		bss->channel = req->ds_parms->curr_ch;
-	if (req->cap_info)
-		bss->cap_info = ieee2host16(*req->cap_info);
+	return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, sizeof(pr));
+}
 
-	bss->sir = acx_signal_to_winlevel(rxbuf->phy_level);
-	bss->snr = acx_signal_to_winlevel(rxbuf->phy_snr);
 
-	bss->rate_cap = 0;	/* operational mask */
-	bss->rate_bas = 0;	/* basic mask */
-	if (req->supp_rates)
-		add_bits_to_ratemasks(req->supp_rates->rates,
-			req->supp_rates->len, &bss->rate_bas, &bss->rate_cap);
-	if (req->ext_rates)
-		add_bits_to_ratemasks(req->ext_rates->rates,
-			req->ext_rates->len, &bss->rate_bas, &bss->rate_cap);
-	/* Fix up any possible bogosity - code elsewhere
-	 * is not expecting empty masks */
-	if (!bss->rate_cap)
-		bss->rate_cap = priv->rate_basic;
-	if (!bss->rate_bas)
-		bss->rate_bas = 1 << lowest_bit(bss->rate_cap);
-	if (!bss->rate_cur)
-		bss->rate_cur = 1 << lowest_bit(bss->rate_bas);
+/***********************************************************************
+** acx_s_init_max_probe_request_template
+*/
+static int
+acx_s_init_max_probe_request_template(wlandevice_t *priv)
+{
+	union {
+		acx100_template_probereq_t p100;
+		acx111_template_probereq_t p111;
+	} pr;
+	int res;
 
-	/* People moan about this being too noisy at L_ASSOC */
-	acxlog(L_DEBUG,
-		"found %s: ESSID='%s' ch=%d "
-		"BSSID="MACSTR" caps=0x%04X SIR=%d SNR=%d\n",
-		(bss->cap_info & WF_MGMT_CAP_IBSS) ? "Ad-Hoc peer" : "AP",
-		bss->essid, bss->channel, MAC(bss->bssid), bss->cap_info,
-		bss->sir, bss->snr);
-ok:
-	FN_EXIT0;
-	return OK;
+	FN_ENTER;
+	memset(&pr, 0, sizeof(pr));
+	pr.p100.size = cpu_to_le16(sizeof(pr) - 2);
+	res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &pr, sizeof(pr));
+	FN_EXIT1(res);
+	return res;
 }
 
 
-/*----------------------------------------------------------------
-* get_status_string
-*----------------------------------------------------------------*/
-static const char*
-get_status_string(unsigned int status)
+/***********************************************************************
+** acx_s_set_tim_template
+**
+** In full blown driver we will regularly update partial virtual bitmap
+** by calling this function
+** (it can be done by irq handler on each DTIM irq or by timer...)
+
+[802.11 7.3.2.6] TIM information element:
+- 1 EID
+- 1 Length
+1 1 DTIM Count
+    indicates how many beacons (including this) appear before next DTIM
+    (0=this one is a DTIM)
+2 1 DTIM Period
+    number of beacons between successive DTIMs
+    (0=reserved, 1=all TIMs are DTIMs, 2=every other, etc)
+3 1 Bitmap Control
+    bit0: Traffic Indicator bit associated with Assoc ID 0 (Bcast AID?)
+    set to 1 in TIM elements with a value of 0 in the DTIM Count field
+    when one or more broadcast or multicast frames are buffered at the AP.
+    bit1-7: Bitmap Offset (logically Bitmap_Offset = Bitmap_Control & 0xFE).
+4 n Partial Virtual Bitmap
+    Visible part of traffic-indication bitmap.
+    Full bitmap consists of 2008 bits (251 octets) such that bit number N
+    (0<=N<=2007) in the bitmap corresponds to bit number (N mod 8)
+    in octet number N/8 where the low-order bit of each octet is bit0,
+    and the high order bit is bit7.
+    Each set bit in virtual bitmap corresponds to traffic buffered by AP
+    for a specific station (with corresponding AID?).
+    Partial Virtual Bitmap shows a part of bitmap which has non-zero.
+    Bitmap Offset is a number of skipped zero octets (see above).
+    'Missing' octets at the tail are also assumed to be zero.
+    Example: Length=6, Bitmap_Offset=2, Partial_Virtual_Bitmap=55 55 55
+    This means that traffic-indication bitmap is:
+    00000000 00000000 01010101 01010101 01010101 00000000 00000000...
+    (is bit0 in the map is always 0 and real value is in Bitmap Control bit0?)
+*/
+static int
+acx_s_set_tim_template(wlandevice_t *priv)
 {
-	/* A bit shortened, but hopefully still understandable */
-	static const char * const status_str[] = {
-	/* 0 */	"Successful",
-	/* 1 */	"Unspecified failure",
-	/* 2 */	"reserved",
-	/* 3 */	"reserved",
-	/* 4 */	"reserved",
-	/* 5 */	"reserved",
-	/* 6 */	"reserved",
-	/* 7 */	"reserved",
-	/* 8 */	"reserved",
-	/* 9 */	"reserved",
-	/*10 */	"Cannot support all requested capabilities in Capability Information field",
-	/*11 */	"Reassoc denied (reason outside of 802.11b scope)",
-	/*12 */	"Assoc denied (reason outside of 802.11b scope), maybe MAC filtering by peer?",
-	/*13 */	"Responding station doesnt support specified auth algorithm",
-	/*14 */	"Auth rejected: wrong transaction sequence number",
-	/*15 */	"Auth rejected: challenge failure",
-	/*16 */	"Auth rejected: timeout for next frame in sequence",
-	/*17 */	"Assoc denied: too many STAs on this AP",
-	/*18 */	"Assoc denied: requesting STA doesnt support all data rates in basic set",
-	/*19 */	"Assoc denied: requesting STA doesnt support Short Preamble",
-	/*20 */	"Assoc denied: requesting STA doesnt support PBCC Modulation",
-	/*21 */	"Assoc denied: requesting STA doesnt support Channel Agility"
-	/*22 */	"reserved",
-	/*23 */	"reserved",
-	/*24 */	"reserved",
-	/*25 */	"Assoc denied: requesting STA doesnt support Short Slot Time",
-	/*26 */	"Assoc denied: requesting STA doesnt support DSSS-OFDM"
-	};
+/* For now, configure smallish test bitmap, all zero ("no pending data") */
+	enum { bitmap_size = 5 };
 
-	return status_str[status < VEC_SIZE(status_str) ? status : 2];
+	acx_template_tim_t t;
+	int result;
+
+	FN_ENTER;
+
+	memset(&t, 0, sizeof(t));
+	t.size = 5 + bitmap_size; /* eid+len+count+period+bmap_ctrl + bmap */
+	t.tim_eid = WLAN_EID_TIM;
+	t.len = 3 + bitmap_size; /* count+period+bmap_ctrl + bmap */
+	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
+	FN_EXIT1(result);
+	return result;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_process_assocresp
-*----------------------------------------------------------------*/
+/***********************************************************************
+** acx_fill_beacon_or_proberesp_template
+**
+** For frame format info, please see 802.11-1999.pdf item 7.2.3.9 and below!!
+**
+** WARNING/FIXME/TODO: this needs to be called (via SET_TEMPLATES) *whenever*
+** *any* of the parameters contained in it change!!!
+** fishy status fixed
+**
+** NB: we use the fact that
+** struct acx_template_proberesp and struct acx_template_beacon are the same
+** (well, almost...)
+**
+** [802.11] Beacon's body consist of these IEs:
+** 1 Timestamp
+** 2 Beacon interval
+** 3 Capability information
+** 4 SSID
+** 5 Supported rates (up to 8 rates)
+** 6 FH Parameter Set (frequency-hopping PHYs only)
+** 7 DS Parameter Set (direct sequence PHYs only)
+** 8 CF Parameter Set (only if PCF is supported)
+** 9 IBSS Parameter Set (ad-hoc only)
+**
+** Beacon only:
+** 10 TIM (AP only) (see 802.11 7.3.2.6)
+** 11 Country Information (802.11d)
+** 12 FH Parameters (802.11d)
+** 13 FH Pattern Table (802.11d)
+** ... (?!! did not yet find relevant PDF file... --vda)
+** 19 ERP Information (extended rate PHYs)
+** 20 Extended Supported Rates (if more than 8 rates)
+**
+** Proberesp only:
+** 10 Country information (802.11d)
+** 11 FH Parameters (802.11d)
+** 12 FH Pattern Table (802.11d)
+** 13-n Requested information elements (802.11d)
+** ????
+** 18 ERP Information (extended rate PHYs)
+** 19 Extended Supported Rates (if more than 8 rates)
+*/
 static int
-acx_l_process_assocresp(wlandevice_t *priv, const wlan_fr_assocresp_t *req)
+acx_fill_beacon_or_proberesp_template(wlandevice_t *priv,
+					struct acx_template_beacon *templ,
+					u16 fc /* in host order! */)
 {
-	const wlan_hdr_t *hdr;
-	int res = OK;
+	int len;
+	u8 *p;
 
 	FN_ENTER;
-	hdr = req->hdr;
-
-	if ((ACX_MODE_2_STA == priv->mode)
-	 && mac_is_equal(priv->dev_addr, hdr->a1)) {
-		u16 st = ieee2host16(*(req->status));
-		if (WLAN_MGMT_STATUS_SUCCESS == st) {
-			priv->aid = ieee2host16(*(req->aid));
-			/* tell the card we are associated when we are out of interrupt context */
-			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_ASSOCIATE);
-		} else {
 
-			/* TODO: we shall delete peer from sta_list, and try other candidates... */
+	memset(templ, 0, sizeof(*templ));
+	MAC_BCAST(templ->da);
+	MAC_COPY(templ->sa, priv->dev_addr);
+	MAC_COPY(templ->bssid, priv->bssid);
+
+	templ->beacon_interval = cpu_to_le16(priv->beacon_interval);
+	acx_update_capabilities(priv);
+	templ->cap = cpu_to_le16(priv->capabilities);
+
+	p = templ->variable;
+	p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
+	p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
+	p = wlan_fill_ie_ds_parms(p, priv->channel);
+	/* NB: should go AFTER tim, but acx seem to keep tim last always */
+	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
 
-			printk("%s: association FAILED: peer sent "
-				"response code %d (%s)\n",
-				priv->netdev->name, st, get_status_string(st));
-			res = NOT_OK;
-		}
+	switch (priv->mode) {
+	case ACX_MODE_0_ADHOC:
+		/* ATIM window */
+		p = wlan_fill_ie_ibss_parms(p, 0); break;
+	case ACX_MODE_3_AP:
+		/* TIM IE is set up as separate template */
+		break;
 	}
 
-	FN_EXIT1(res);
-	return res;
+	len = p - (u8*)templ;
+	templ->fc = cpu_to_le16(WF_FTYPE_MGMT | fc);
+	/* - 2: do not count 'u16 size' field */
+	templ->size = cpu_to_le16(len - 2);
+
+	FN_EXIT1(len);
+	return len;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_process_reassocresp
-*----------------------------------------------------------------*/
+/***********************************************************************
+** acx_s_set_beacon_template
+*/
 static int
-acx_l_process_reassocresp(wlandevice_t *priv, const wlan_fr_reassocresp_t *req)
+acx_s_set_beacon_template(wlandevice_t *priv)
 {
-	const wlan_hdr_t *hdr;
-	int result = 4;
-	u16 st;
+	struct acx_template_beacon bcn;
+	int len, result;
 
 	FN_ENTER;
-	hdr = req->hdr;
 
-	if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
-		result = 3;
-		goto end;
-	}
-	st = ieee2host16(*(req->status));
-	if (st == WLAN_MGMT_STATUS_SUCCESS) {
-		acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-	} else {
-		printk("%s: reassociation FAILED: peer sent "
-			"response code %d (%s)\n",
-			priv->netdev->name, st, get_status_string(st));
-	}
-	result = OK;
-end:
+	len = acx_fill_beacon_or_proberesp_template(priv, &bcn, WF_FSTYPE_BEACON);
+	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &bcn, len);
+
 	FN_EXIT1(result);
 	return result;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_process_authen
-*
-* Called only in STA_SCAN or AP mode
-*----------------------------------------------------------------*/
+/***********************************************************************
+** acx_s_set_probe_response_template
+*/
 static int
-acx_l_process_authen(wlandevice_t *priv, const wlan_fr_authen_t *req)
+acx_s_set_probe_response_template(wlandevice_t *priv)
 {
-	const wlan_hdr_t *hdr;
-	client_t *clt;
-	wlan_ie_challenge_t *chal;
-	u16 alg, seq, status;
-	int ap, result;
+	struct acx_template_proberesp pr;
+	int len, result;
 
 	FN_ENTER;
 
-	hdr = req->hdr;
+	len = acx_fill_beacon_or_proberesp_template(priv, &pr, WF_FSTYPE_PROBERESP);
+	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, len);
 
-	if (acx_debug & L_ASSOC) {
-		acx_print_mac("AUTHEN priv->addr=", priv->dev_addr, " ");
-		acx_print_mac("a1=", hdr->a1, " ");
-		acx_print_mac("a2=", hdr->a2, " ");
-		acx_print_mac("a3=", hdr->a3, " ");
-		acx_print_mac("priv->bssid=", priv->bssid, "\n");
-	}
+	FN_EXIT1(result);
+	return result;
+}
 
-	/* TODO: move first check up in caller chain,
-	** it's not auth specific */
-	if (!mac_is_equal(priv->dev_addr, hdr->a1)
-	 || !mac_is_equal(priv->bssid, hdr->a3)) {
-		result = OK;
-		goto end;
-	}
 
-	alg = ieee2host16(*(req->auth_alg));
-	seq = ieee2host16(*(req->auth_seq));
-	status = ieee2host16(*(req->status));
+/***********************************************************************
+** acx100_s_init_packet_templates()
+**
+** NOTE: order is very important here, to have a correct memory layout!
+** init templates: max Probe Request (station mode), max NULL data,
+** max Beacon, max TIM, max Probe Response.
+*/
+int
+acx100_s_init_packet_templates(wlandevice_t *priv)
+{
+	acx_ie_memmap_t mm;
+	int result = NOT_OK;
 
-	ap = (priv->mode == ACX_MODE_3_AP);
+	FN_ENTER;
 
-	if (priv->auth_alg <= 1) {
-		if (priv->auth_alg != alg) {
-			acxlog(L_ASSOC, "authentication algorithm mismatch: "
-				"want: %d, req: %d\n", priv->auth_alg, alg);
-			result = NOT_OK;
-			goto end;
-		}
-	}
-	acxlog(L_ASSOC, "algorithm is ok\n");
+	acxlog(L_DEBUG, "sizeof(memmap)=%d bytes\n", (int)sizeof(mm));
 
-	if (ap) {
-		clt = acx_l_sta_list_get_or_add(priv, hdr->a2);
-		if (STA_LIST_ADD_CAN_FAIL && !clt) {
-			acxlog(L_ASSOC, "could not allocate room for client\n");
-			result = NOT_OK;
-			goto end;
-		}
-	} else {
-		clt = priv->ap_client;
-		if (!mac_is_equal(clt->address, hdr->a2)) {
-			printk("%s: malformed auth frame from AP?!\n",
-					priv->netdev->name);
-			result = NOT_OK;
-			goto end;
-		}
+	/* acx100 still do not emit probe requests, thus this call
+	** is sourt of not needed. But we want it to work someday */
+	if (OK != acx_s_init_max_probe_request_template(priv))
+		goto failed;
+
+#ifdef NOT_WORKING_YET
+	/* FIXME: creating the NULL data template breaks
+	 * communication right now, needs further testing.
+	 * Also, need to set the template once we're joining a network. */
+	if (OK != acx_s_init_max_null_data_template(priv))
+		goto failed;
+#endif
+
+	if (OK != acx_s_init_max_beacon_template(priv))
+		goto failed;
+
+	/* TODO: beautify code by moving init_tim down just before set_tim */
+	if (OK != acx_s_init_max_tim_template(priv))
+		goto failed;
+
+	if (OK != acx_s_init_max_probe_response_template(priv))
+		goto failed;
+
+	if (OK != acx_s_set_tim_template(priv))
+		goto failed;
+
+	if (OK != acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
+		goto failed;
 	}
 
-	/* now check which step in the authentication sequence we are
-	 * currently in, and act accordingly */
-	acxlog(L_ASSOC, "acx_process_authen auth seq step %d\n", seq);
-	switch (seq) {
-	case 1:
-		if (!ap)
-			break;
-		acx_l_transmit_authen2(priv, req, clt);
-		break;
-	case 2:
-		if (ap)
-			break;
-		if (status == WLAN_MGMT_STATUS_SUCCESS) {
-			if (alg == WLAN_AUTH_ALG_OPENSYSTEM) {
-				acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
-				acx_l_transmit_assoc_req(priv);
-			} else
-			if (alg == WLAN_AUTH_ALG_SHAREDKEY) {
-				acx_l_transmit_authen3(priv, req);
-			}
-		} else {
-			printk("%s: auth FAILED: peer sent "
-				"response code %d (%s), "
-				"still waiting for authentication\n",
-				priv->netdev->name,
-				status,	get_status_string(status));
-			acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
-		}
-		break;
-	case 3:
-		if (!ap)
-			break;
-		if ((clt->auth_alg != WLAN_AUTH_ALG_SHAREDKEY)
-		 || (alg != WLAN_AUTH_ALG_SHAREDKEY)
-		 || (clt->auth_step != 2))
-			break;
-		chal = req->challenge;
-		if (!chal
-		 || memcmp(chal->challenge, clt->challenge_text, WLAN_CHALLENGE_LEN)
-		 || (chal->eid != WLAN_EID_CHALLENGE)
-		 || (chal->len != WLAN_CHALLENGE_LEN)
-		)
-			break;
-		acx_l_transmit_authen4(priv, req);
-		MAC_COPY(clt->address, hdr->a2);
-		clt->used = CLIENT_AUTHENTICATED_2;
-		clt->auth_step = 4;
-		clt->seq = ieee2host16(hdr->seq);
-		break;
-	case 4:
-		if (ap)
-			break;
-		/* ok, we're through: we're authenticated. Woohoo!! */
-		acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
-		acxlog(L_ASSOC, "Authenticated!\n");
-		/* now that we're authenticated, request association */
-		acx_l_transmit_assoc_req(priv);
-		break;
+	mm.QueueStart = cpu_to_le32(le32_to_cpu(mm.PacketTemplateEnd) + 4);
+	if (OK != acx_s_configure(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
+		goto failed;
 	}
-	result = NOT_OK;
-end:
+
+	result = OK;
+	goto success;
+
+failed:
+	acxlog(L_DEBUG | L_INIT,
+		/* "cb=0x%X\n" */
+		"pACXMemoryMap:\n"
+		".CodeStart=0x%X\n"
+		".CodeEnd=0x%X\n"
+		".WEPCacheStart=0x%X\n"
+		".WEPCacheEnd=0x%X\n"
+		".PacketTemplateStart=0x%X\n"
+		".PacketTemplateEnd=0x%X\n",
+		/* len, */
+		le32_to_cpu(mm.CodeStart),
+		le32_to_cpu(mm.CodeEnd),
+		le32_to_cpu(mm.WEPCacheStart),
+		le32_to_cpu(mm.WEPCacheEnd),
+		le32_to_cpu(mm.PacketTemplateStart),
+		le32_to_cpu(mm.PacketTemplateEnd));
+
+success:
+	FN_EXIT1(result);
+	return result;
+}
+
+int
+acx111_s_init_packet_templates(wlandevice_t *priv)
+{
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	acxlog(L_DEBUG | L_INIT, "initializing max packet templates\n");
+
+	if (OK != acx_s_init_max_probe_request_template(priv))
+		goto failed;
+
+	if (OK != acx_s_init_max_null_data_template(priv))
+		goto failed;
+
+	if (OK != acx_s_init_max_beacon_template(priv))
+		goto failed;
+
+	if (OK != acx_s_init_max_tim_template(priv))
+		goto failed;
+
+	if (OK != acx_s_init_max_probe_response_template(priv))
+		goto failed;
+
+	/* the other templates will be set later (acx_start) */
+	/*
+	if (OK != acx_s_set_tim_template(priv))
+		goto failed;*/
+
+	result = OK;
+	goto success;
+
+failed:
+	printk("%s: acx111_init_packet_templates() FAILED\n", priv->netdev->name);
+
+success:
 	FN_EXIT1(result);
 	return result;
 }
 
 
-/*----------------------------------------------------------------
-* acx_gen_challenge
-*----------------------------------------------------------------*/
-static void
-acx_gen_challenge(wlan_ie_challenge_t* d)
+/***********************************************************************
+*/
+static int
+acx100_s_set_probe_request_template(wlandevice_t *priv)
 {
+	struct acx100_template_probereq probereq;
+	char *p;
+	int res;
+	int frame_len;
+
 	FN_ENTER;
-	d->eid = WLAN_EID_CHALLENGE;
-	d->len = WLAN_CHALLENGE_LEN;
-	get_random_bytes(d->challenge, WLAN_CHALLENGE_LEN);
+
+	memset(&probereq, 0, sizeof(probereq));
+
+	probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
+	MAC_BCAST(probereq.da);
+	MAC_COPY(probereq.sa, priv->dev_addr);
+	MAC_BCAST(probereq.bssid);
+
+	probereq.beacon_interval = cpu_to_le16(priv->beacon_interval);
+	acx_update_capabilities(priv);
+	probereq.cap = cpu_to_le16(priv->capabilities);
+
+	p = probereq.variable;
+	acxlog(L_ASSOC, "SSID='%s' len=%d\n", priv->essid, priv->essid_len);
+	p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
+	p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
+	/* FIXME: should these be here or AFTER ds_parms? */
+	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
+	/* HUH?? who said it must be here? I've found nothing in 802.11! --vda*/
+	/* p = wlan_fill_ie_ds_parms(p, priv->channel); */
+	frame_len = p - (char*)&probereq;
+	probereq.size = frame_len - 2;
+
+	res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
+	FN_EXIT0;
+	return res;
+}
+
+static int
+acx111_s_set_probe_request_template(wlandevice_t *priv)
+{
+	struct acx111_template_probereq probereq;
+	char *p;
+	int res;
+	int frame_len;
+
+	FN_ENTER;
+
+	memset(&probereq, 0, sizeof(probereq));
+
+	probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
+	MAC_BCAST(probereq.da);
+	MAC_COPY(probereq.sa, priv->dev_addr);
+	MAC_BCAST(probereq.bssid);
+
+	p = probereq.variable;
+	p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
+	p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
+	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
+	frame_len = p - (char*)&probereq;
+	probereq.size = frame_len - 2;
+
+	res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
 	FN_EXIT0;
+	return res;
+}
+
+static int
+acx_s_set_probe_request_template(wlandevice_t *priv)
+{
+	if (IS_ACX111(priv)) {
+		return acx111_s_set_probe_request_template(priv);
+	} else {
+		return acx100_s_set_probe_request_template(priv);
+	}
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_transmit_deauthen
-* STATUS: should be ok, but UNVERIFIED.
-*----------------------------------------------------------------*/
-static int
-acx_l_transmit_deauthen(wlandevice_t *priv, const u8 *addr, u16 reason)
+/***********************************************************************
+*/
+int
+acx111_s_get_feature_config(wlandevice_t *priv,
+		u32 *feature_options, u32 *data_flow_options)
+{
+	struct ACX111FeatureConfig fc;
+
+	if (priv->chip_type != CHIPTYPE_ACX111) {
+		return NOT_OK;
+	}
+
+	memset(&fc, 0, sizeof(struct ACX111FeatureConfig));
+
+	if (OK != acx_s_interrogate(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
+		return NOT_OK;
+	}
+	acxlog(L_DEBUG,
+		"got Feature option:0x%X, DataFlow option: 0x%X\n",
+		fc.feature_options,
+		fc.data_flow_options);
+
+	if (feature_options)
+		*feature_options = le32_to_cpu(fc.feature_options);
+	if (data_flow_options)
+		*data_flow_options = le32_to_cpu(fc.data_flow_options);
+
+	return OK;
+}
+
+int
+acx111_s_set_feature_config(wlandevice_t *priv,
+	u32 feature_options, u32 data_flow_options,
+	unsigned int mode /* 0 == remove, 1 == add, 2 == set */)
 {
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct deauthen_frame_body *body;
+	struct ACX111FeatureConfig fc;
 
-	FN_ENTER;
+	if (priv->chip_type != CHIPTYPE_ACX111) {
+		return NOT_OK;
+	}
 
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto bad;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto bad;
-	body = (void*)(head + 1);
+	if ((mode < 0) || (mode > 2))
+		return NOT_OK;
 
-	head->fc = (WF_FTYPE_MGMTi | WF_FSTYPE_DEAUTHENi);
-	head->dur = 0;
-	MAC_COPY(head->da, addr);
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, priv->bssid);
-	head->seq = 0;
+	if (mode != 2)
+		/* need to modify old data */
+		acx111_s_get_feature_config(priv, &fc.feature_options, &fc.data_flow_options);
+	else {
+		/* need to set a completely new value */
+		fc.feature_options = 0;
+		fc.data_flow_options = 0;
+	}
 
-	acxlog(L_DEBUG | L_ASSOC | L_XFER,
-		"sending deauthen to "MACSTR" for %d\n",
-		MAC(addr), reason);
+	if (mode == 0) { /* remove */
+		CLEAR_BIT(fc.feature_options, cpu_to_le32(feature_options));
+		CLEAR_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
+	} else { /* add or set */
+		SET_BIT(fc.feature_options, cpu_to_le32(feature_options));
+		SET_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
+	}
 
-	body->reason = host2ieee16(reason);
+	acxlog(L_DEBUG,
+		"old: feature 0x%08X dataflow 0x%08X. mode: %u\n"
+		"new: feature 0x%08X dataflow 0x%08X\n",
+		feature_options, data_flow_options, mode,
+		le32_to_cpu(fc.feature_options),
+		le32_to_cpu(fc.data_flow_options));
 
-	/* body is fixed size here, but beware of cutting-and-pasting this -
-	** do not use sizeof(*body) for variable sized mgmt packets! */
-	acx_l_dma_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
+	if (OK != acx_s_configure(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
+		return NOT_OK;
+	}
 
-	FN_EXIT1(OK);
 	return OK;
-bad:
-	FN_EXIT1(NOT_OK);
-	return NOT_OK;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_transmit_authen1
-*----------------------------------------------------------------*/
-static int
-acx_l_transmit_authen1(wlandevice_t *priv)
+/***********************************************************************
+*/
+int
+acx_s_recalib_radio(wlandevice_t *priv)
 {
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct auth_frame_body *body;
+	if (IS_ACX111(priv)) {
+		acx111_cmd_radiocalib_t cal;
+
+		printk("%s: recalibrating radio\n", priv->netdev->name);
+		/* automatic recalibration, choose all methods: */
+		cal.methods = cpu_to_le32(0x8000000f);
+		/* automatic recalibration every 60 seconds (value in TUs)
+		 * FIXME: what is the firmware default here?? */
+		cal.interval = cpu_to_le32(58594);
+		return acx_s_issue_cmd_timeo(priv, ACX111_CMD_RADIOCALIB,
+			&cal, sizeof(cal), CMD_TIMEOUT_MS(100));
+	} else {
+		if (/* (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0)) &&
+		    (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0)) && */
+		    (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1)) &&
+		    (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1)) )
+			return OK;
+		return NOT_OK;
+	}
+}
+
+
+/***********************************************************************
+** acx_s_cmd_start_scan
+**
+** Issue scan command to the hardware
+*/
+static void
+acx100_s_scan_chan(wlandevice_t *priv)
+{
+	acx100_scan_t s;
 
 	FN_ENTER;
 
-	acxlog(L_ASSOC, "Sending authentication1 request, "
-		"awaiting response!\n");
+	memset(&s, 0, sizeof(s));
+	s.count = cpu_to_le16(priv->scan_count);
+	s.start_chan = cpu_to_le16(1);
+	s.flags = cpu_to_le16(0x8000);
+	s.max_rate = priv->scan_rate;
+	s.options = priv->scan_mode;
+	s.chan_duration = cpu_to_le16(priv->scan_duration);
+	s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
 
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto bad;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto bad;
-	body = (void*)(head + 1);
+	acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
+	FN_EXIT0;
+}
 
-	head->fc = WF_FSTYPE_AUTHENi;
-	head->dur = host2ieee16(0x8000);
-	MAC_COPY(head->da, priv->bssid);
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, priv->bssid);
-	head->seq = 0;
+static void
+acx111_s_scan_chan(wlandevice_t *priv)
+{
+	acx111_scan_t s;
 
-	body->auth_alg = host2ieee16(priv->auth_alg);
-	body->auth_seq = host2ieee16(1);
-	body->status = host2ieee16(0);
+	FN_ENTER;
 
-	acx_l_dma_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
+	memset(&s, 0, sizeof(s));
+	s.count = cpu_to_le16(priv->scan_count);
+	s.channel_list_select = 0; /* scan every allowed channel */
+	/*s.channel_list_select = 1;*/ /* scan given channels */
+	s.rate = priv->scan_rate;
+	s.options = priv->scan_mode;
+	s.chan_duration = cpu_to_le16(priv->scan_duration);
+	s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
+	/*s.modulation = 0x40;*/ /* long preamble? OFDM? -> only for active scan */
+	s.modulation = 0;
+	/*s.channel_list[0] = 6;
+	s.channel_list[1] = 4;*/
 
-	FN_EXIT1(OK);
-	return OK;
-bad:
-	FN_EXIT1(NOT_OK);
-	return NOT_OK;
+	acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
+	FN_EXIT0;
+}
+
+void
+acx_s_cmd_start_scan(wlandevice_t *priv)
+{
+	/* time_before check is 'just in case' thing */
+	if (!(priv->irq_status & HOST_INT_SCAN_COMPLETE)
+	 && time_before(jiffies, priv->scan_start + 10*HZ)
+	) {
+		acxlog(L_INIT, "start_scan: seems like previous scan "
+		"is still running. Not starting anew. Please report\n");
+		return;
+	}
+
+	acxlog(L_INIT, "starting radio scan\n");
+	/* remember that fw is commanded to do scan */
+	priv->scan_start = jiffies;
+	CLEAR_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
+	/* issue it */
+	if (IS_ACX100(priv)) {
+		acx100_s_scan_chan(priv);
+	} else {
+		acx111_s_scan_chan(priv);
+	}
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_transmit_authen2
-*----------------------------------------------------------------*/
-static int
-acx_l_transmit_authen2(wlandevice_t *priv, const wlan_fr_authen_t *req,
-		      client_t *clt)
+/***********************************************************************
+** acx_s_update_card_settings
+**
+** Applies accumulated changes in various priv->xxxx members
+** Called by ioctl commit handler, acx_start, acx_set_defaults,
+** acx_s_after_interrupt_task (if IRQ_CMD_UPDATE_CARD_CFG),
+*/
+static void
+acx111_s_sens_radio_16_17(wlandevice_t *priv)
 {
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct auth_frame_body *body;
-	unsigned int packet_len;
+	u32 feature1, feature2;
+
+	if ((priv->sensitivity < 1) || (priv->sensitivity > 3)) {
+		printk("%s: invalid sensitivity setting (1..3), "
+			"setting to 1\n", priv->netdev->name);
+		priv->sensitivity = 1;
+	}
+	acx111_s_get_feature_config(priv, &feature1, &feature2);
+	CLEAR_BIT(feature1, FEATURE1_LOW_RX|FEATURE1_EXTRA_LOW_RX);
+	if (priv->sensitivity > 1)
+		SET_BIT(feature1, FEATURE1_LOW_RX);
+	if (priv->sensitivity > 2)
+		SET_BIT(feature1, FEATURE1_EXTRA_LOW_RX);
+	acx111_s_feature_set(priv, feature1, feature2);
+}
+
+void
+acx_s_update_card_settings(wlandevice_t *priv, int get_all, int set_all)
+{
+	unsigned long flags;
+	unsigned int start_scan = 0;
+	int i;
 
 	FN_ENTER;
 
-	if (!clt)
-		goto ok;
+	if (get_all)
+		SET_BIT(priv->get_mask, GETSET_ALL);
+	if (set_all)
+		SET_BIT(priv->set_mask, GETSET_ALL);
+	/* Why not just set masks to 0xffffffff? We can get rid of GETSET_ALL */
+
+	acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X\n",
+			priv->get_mask, priv->set_mask);
+
+	/* Track dependencies betweed various settings */
+
+	if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_WEP)) {
+		acxlog(L_INIT, "important setting has been changed. "
+			"Need to update packet templates, too\n");
+		SET_BIT(priv->set_mask, SET_TEMPLATES);
+	}
+	if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
+		/* This will actually tune RX/TX to the channel */
+		SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX);
+		switch (priv->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_3_AP:
+			/* Beacons contain channel# - update them */
+			SET_BIT(priv->set_mask, SET_TEMPLATES);
+		}
+		switch (priv->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			start_scan = 1;
+		}
+	}
 
-	MAC_COPY(clt->address, req->hdr->a2);
-#if UNUSED
-	clt->ps = ((WF_FC_PWRMGTi & req->hdr->fc) != 0);
+	/* Apply settings */
+
+#ifdef WHY_SHOULD_WE_BOTHER /* imagine we were just powered off */
+	/* send a disassoc request in case it's required */
+	if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_CHANNEL|GETSET_WEP|GETSET_ALL)) {
+		if (ACX_MODE_2_STA == priv->mode) {
+			if (ACX_STATUS_4_ASSOCIATED == priv->status) {
+				acxlog(L_ASSOC, "we were ASSOCIATED - "
+					"sending disassoc request\n");
+				acx_lock(priv, flags);
+				acx_l_transmit_disassoc(priv, NULL);
+				/* FIXME: deauth? */
+				acx_unlock(priv, flags);
+			}
+			/* need to reset some other stuff as well */
+			acxlog(L_DEBUG, "resetting bssid\n");
+			MAC_ZERO(priv->bssid);
+			SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST);
+			/* FIXME: should start scanning */
+			start_scan = 1;
+		}
+	}
 #endif
-	clt->auth_alg = ieee2host16(*(req->auth_alg));
-	clt->auth_step = 2;
-	clt->seq = ieee2host16(req->hdr->seq);
 
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto bad;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto bad;
-	body = (void*)(head + 1);
+	if (priv->get_mask & (GETSET_STATION_ID|GETSET_ALL)) {
+		u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
+		const u8 *paddr;
+
+		acx_s_interrogate(priv, &stationID, ACX1xx_IE_DOT11_STATION_ID);
+		paddr = &stationID[4];
+		for (i = 0; i < ETH_ALEN; i++) {
+			/* we copy the MAC address (reversed in
+			 * the card) to the netdevice's MAC
+			 * address, and on ifup it will be
+			 * copied into iwpriv->dev_addr */
+			priv->netdev->dev_addr[ETH_ALEN - 1 - i] = paddr[i];
+		}
+		CLEAR_BIT(priv->get_mask, GETSET_STATION_ID);
+	}
 
-	head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
-	head->dur = req->hdr->dur;
-	MAC_COPY(head->da, req->hdr->a2);
-	/* MAC_COPY(head->sa, req->hdr->a1); */
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, req->hdr->a3);
-	head->seq = req->hdr->seq;
+	if (priv->get_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
+		if ((RADIO_RFMD_11 == priv->radio_type)
+		|| (RADIO_MAXIM_0D == priv->radio_type)
+		|| (RADIO_RALINK_15 == priv->radio_type)) {
+			acx_s_read_phy_reg(priv, 0x30, &priv->sensitivity);
+		} else {
+			acxlog(L_INIT, "don't know how to get sensitivity "
+				"for radio type 0x%02X\n", priv->radio_type);
+			priv->sensitivity = 0;
+		}
+		acxlog(L_INIT, "got sensitivity value %u\n", priv->sensitivity);
 
-	/* already in IEEE format, no endianness conversion */
-	body->auth_alg = *(req->auth_alg);
-	body->auth_seq = host2ieee16(2);
-	body->status = host2ieee16(0);
+		CLEAR_BIT(priv->get_mask, GETSET_SENSITIVITY);
+	}
 
-	packet_len = WLAN_HDR_A3_LEN + 2 + 2 + 2;
-	if (ieee2host16(*(req->auth_alg)) == WLAN_AUTH_ALG_OPENSYSTEM) {
-		clt->used = CLIENT_AUTHENTICATED_2;
-	} else {	/* shared key */
-		acx_gen_challenge(&body->challenge);
-		memcpy(&clt->challenge_text, body->challenge.challenge, WLAN_CHALLENGE_LEN);
-		packet_len += 2 + 2 + 2 + 1+1+WLAN_CHALLENGE_LEN;
+	if (priv->get_mask & (GETSET_ANTENNA|GETSET_ALL)) {
+		u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
+
+		memset(antenna, 0, sizeof(antenna));
+		acx_s_interrogate(priv, antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
+		priv->antenna = antenna[4];
+		acxlog(L_INIT, "got antenna value 0x%02X\n", priv->antenna);
+		CLEAR_BIT(priv->get_mask, GETSET_ANTENNA);
 	}
 
-	acxlog_mac(L_ASSOC | L_XFER,
-		"transmit_auth2: BSSID=", head->bssid, "\n");
+	if (priv->get_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
+		if (IS_ACX100(priv))	{
+			u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
 
-	acx_l_dma_tx_data(priv, tx, packet_len);
-ok:
-	FN_EXIT1(OK);
-	return OK;
-bad:
-	FN_EXIT1(NOT_OK);
-	return NOT_OK;
-}
+			memset(ed_threshold, 0, sizeof(ed_threshold));
+			acx_s_interrogate(priv, ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
+			priv->ed_threshold = ed_threshold[4];
+		} else {
+			acxlog(L_INIT, "acx111 doesn't support ED\n");
+			priv->ed_threshold = 0;
+		}
+		acxlog(L_INIT, "got Energy Detect (ED) threshold %u\n", priv->ed_threshold);
+		CLEAR_BIT(priv->get_mask, GETSET_ED_THRESH);
+	}
 
+	if (priv->get_mask & (GETSET_CCA|GETSET_ALL)) {
+		if (IS_ACX100(priv))	{
+			u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
 
-/*----------------------------------------------------------------
-* acx_l_transmit_authen3
-*----------------------------------------------------------------*/
-static int
-acx_l_transmit_authen3(wlandevice_t *priv, const wlan_fr_authen_t *req)
-{
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct auth_frame_body *body;
-	unsigned int packet_len;
+			memset(cca, 0, sizeof(priv->cca));
+			acx_s_interrogate(priv, cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
+			priv->cca = cca[4];
+		} else {
+			acxlog(L_INIT, "acx111 doesn't support CCA\n");
+			priv->cca = 0;
+		}
+		acxlog(L_INIT, "got Channel Clear Assessment (CCA) value %u\n", priv->cca);
+		CLEAR_BIT(priv->get_mask, GETSET_CCA);
+	}
 
-	FN_ENTER;
+	if (priv->get_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
+		acx_ie_generic_t dom;
 
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto ok;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto ok;
-	body = (void*)(head + 1);
+		acx_s_interrogate(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
+		priv->reg_dom_id = dom.m.bytes[0];
+		/* FIXME: should also set chanmask somehow */
+		acxlog(L_INIT, "got regulatory domain 0x%02X\n", priv->reg_dom_id);
+		CLEAR_BIT(priv->get_mask, GETSET_REG_DOMAIN);
+	}
+
+	if (priv->set_mask & (GETSET_STATION_ID|GETSET_ALL)) {
+		u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
+		u8 *paddr;
+
+		paddr = &stationID[4];
+		for (i = 0; i < ETH_ALEN; i++) {
+			/* copy the MAC address we obtained when we noticed
+			 * that the ethernet iface's MAC changed
+			 * to the card (reversed in
+			 * the card!) */
+			paddr[i] = priv->dev_addr[ETH_ALEN - 1 - i];
+		}
+		acx_s_configure(priv, &stationID, ACX1xx_IE_DOT11_STATION_ID);
+		CLEAR_BIT(priv->set_mask, GETSET_STATION_ID);
+	}
 
-	head->fc = WF_FC_ISWEPi + WF_FSTYPE_AUTHENi;
-	/* FIXME: is this needed?? authen4 does it...
-	head->dur = req->hdr->dur;
-	head->seq = req->hdr->seq;
-	*/
-	MAC_COPY(head->da, priv->bssid);
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, priv->bssid);
+	if (priv->set_mask & (SET_TEMPLATES|GETSET_ALL)) {
+		acxlog(L_INIT, "updating packet templates\n");
+		/* Doesn't work for acx100, do it only for acx111 for now */
+		if (IS_ACX111(priv)) {
+			switch (priv->mode) {
+			case ACX_MODE_0_ADHOC:
+			case ACX_MODE_2_STA:
+				if (OK != acx_s_set_probe_request_template(priv))
+					acxlog(L_INIT, "acx_set_probe_request_template FAILED\n");
+			}
+		}
+		switch (priv->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_3_AP:
+			/* FIXME: why only for AP? STA need probe req templates... */
+			if (OK != acx_s_set_beacon_template(priv))
+				acxlog(L_INIT, "acx_set_beacon_template FAILED\n");
+			if (OK != acx_s_set_tim_template(priv))
+				acxlog(L_INIT, "acx_set_tim_template FAILED\n");
+			/* BTW acx111 firmware would not send probe responses
+			** if probe request does not have all basic rates flagged
+			** by 0x80! Thus firmware does not conform to 802.11,
+			** it should ignore 0x80 bit in ratevector from STA.
+			** We can 'fix' it by not using this template and
+			** sending probe responses by hand. TODO --vda */
+			if (OK != acx_s_set_probe_response_template(priv))
+				acxlog(L_INIT, "acx_set_probe_response_template FAILED\n");
+		}
+		/* Needed if generated frames are to be emitted at different tx rate now */
+		acxlog(L_IRQ, "redoing cmd_join_bssid() after template cfg\n");
+		acx_s_cmd_join_bssid(priv, priv->bssid);
+		CLEAR_BIT(priv->set_mask, SET_TEMPLATES);
+	}
+	if (priv->set_mask & (SET_STA_LIST|GETSET_ALL)) {
+		/* TODO insert a sweet if here */
+		acx_lock(priv, flags);
+		acx_l_sta_list_init(priv);
+		CLEAR_BIT(priv->set_mask, SET_STA_LIST);
+		acx_unlock(priv, flags);
+	}
+	if (priv->set_mask & (SET_RATE_FALLBACK|GETSET_ALL)) {
+		u8 rate[4 + ACX1xx_IE_RATE_FALLBACK_LEN];
+
+		/* configure to not do fallbacks when not in auto rate mode */
+		rate[4] = (priv->rate_auto) ? /* priv->txrate_fallback_retries */ 1 : 0;
+		acxlog(L_INIT, "updating Tx fallback to %u retries\n", rate[4]);
+		acx_s_configure(priv, &rate, ACX1xx_IE_RATE_FALLBACK);
+		CLEAR_BIT(priv->set_mask, SET_RATE_FALLBACK);
+	}
+	if (priv->set_mask & (GETSET_TXPOWER|GETSET_ALL)) {
+		acxlog(L_INIT, "updating transmit power: %u dBm\n",
+					priv->tx_level_dbm);
+		acx_s_set_tx_level(priv, priv->tx_level_dbm);
+		CLEAR_BIT(priv->set_mask, GETSET_TXPOWER);
+	}
+
+	if (priv->set_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
+		acxlog(L_INIT, "updating sensitivity value: %u\n",
+					priv->sensitivity);
+		switch (priv->radio_type) {
+		case RADIO_RFMD_11:
+		case RADIO_MAXIM_0D:
+		case RADIO_RALINK_15:
+			acx_s_write_phy_reg(priv, 0x30, priv->sensitivity);
+			break;
+		case RADIO_RADIA_16:
+		case RADIO_UNKNOWN_17:
+			acx111_s_sens_radio_16_17(priv);
+			break;
+		default:
+			acxlog(L_INIT, "don't know how to modify sensitivity "
+				"for radio type 0x%02X\n", priv->radio_type);
+		}
+		CLEAR_BIT(priv->set_mask, GETSET_SENSITIVITY);
+	}
 
-	/* already in IEEE format, no endianness conversion */
-	body->auth_alg = *(req->auth_alg);
-	body->auth_seq = host2ieee16(3);
-	body->status = host2ieee16(0);
-	memcpy(&body->challenge, req->challenge, req->challenge->len + 2);
-	packet_len = WLAN_HDR_A3_LEN + 8 + req->challenge->len;
+	if (priv->set_mask & (GETSET_ANTENNA|GETSET_ALL)) {
+		/* antenna */
+		u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
+
+		memset(antenna, 0, sizeof(antenna));
+		antenna[4] = priv->antenna;
+		acxlog(L_INIT, "updating antenna value: 0x%02X\n",
+					priv->antenna);
+		acx_s_configure(priv, &antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
+		CLEAR_BIT(priv->set_mask, GETSET_ANTENNA);
+	}
+
+	if (priv->set_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
+		/* ed_threshold */
+		acxlog(L_INIT, "updating Energy Detect (ED) threshold: %u\n",
+					priv->ed_threshold);
+		if (IS_ACX100(priv)) {
+			u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
+
+			memset(ed_threshold, 0, sizeof(ed_threshold));
+			ed_threshold[4] = priv->ed_threshold;
+			acx_s_configure(priv, &ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
+		}
+		else
+			acxlog(L_INIT, "ACX111 doesn't support ED!\n");
+		CLEAR_BIT(priv->set_mask, GETSET_ED_THRESH);
+	}
 
-	acxlog(L_ASSOC | L_XFER, "transmit_authen3!\n");
+	if (priv->set_mask & (GETSET_CCA|GETSET_ALL)) {
+		/* CCA value */
+		acxlog(L_INIT, "updating Channel Clear Assessment "
+				"(CCA) value: 0x%02X\n", priv->cca);
+		if (IS_ACX100(priv))	{
+			u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
+
+			memset(cca, 0, sizeof(cca));
+			cca[4] = priv->cca;
+			acx_s_configure(priv, &cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
+		}
+		else
+			acxlog(L_INIT, "acx111 doesn't support CCA!\n");
+		CLEAR_BIT(priv->set_mask, GETSET_CCA);
+	}
 
-	acx_l_dma_tx_data(priv, tx, packet_len);
-ok:
-	FN_EXIT1(OK);
-	return OK;
-}
+	if (priv->set_mask & (GETSET_LED_POWER|GETSET_ALL)) {
+		/* Enable Tx */
+		acxlog(L_INIT, "updating power LED status: %u\n", priv->led_power);
+
+		acx_lock(priv, flags);
+		if (IS_PCI(priv))
+			acx_l_power_led(priv, priv->led_power);
+		CLEAR_BIT(priv->set_mask, GETSET_LED_POWER);
+		acx_unlock(priv, flags);
+	}
+
+/* this seems to cause Tx lockup after some random time (Tx error 0x20),
+ * so let's disable it for now until further investigation */
+/* Maybe fixed now after locking is fixed. Need to retest */
+#ifdef POWER_SAVE_80211
+	if (priv->set_mask & (GETSET_POWER_80211|GETSET_ALL)) {
+		acx100_ie_powermgmt_t pm;
+
+		/* change 802.11 power save mode settings */
+		acxlog(L_INIT, "updating 802.11 power save mode settings: "
+			"wakeup_cfg 0x%02X, listen interval %u, "
+			"options 0x%02X, hangover period %u, "
+			"enhanced_ps_transition_time %d\n",
+			priv->ps_wakeup_cfg, priv->ps_listen_interval,
+			priv->ps_options, priv->ps_hangover_period,
+			priv->ps_enhanced_transition_time);
+		acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
+		acxlog(L_INIT, "Previous PS mode settings: wakeup_cfg 0x%02X, "
+			"listen interval %u, options 0x%02X, "
+			"hangover period %u, "
+			"enhanced_ps_transition_time %d\n",
+			pm.wakeup_cfg, pm.listen_interval, pm.options,
+			pm.hangover_period, pm.enhanced_ps_transition_time);
+		pm.wakeup_cfg = priv->ps_wakeup_cfg;
+		pm.listen_interval = priv->ps_listen_interval;
+		pm.options = priv->ps_options;
+		pm.hangover_period = priv->ps_hangover_period;
+		pm.enhanced_ps_transition_time = cpu_to_le16(priv->ps_enhanced_transition_time);
+		acx_s_configure(priv, &pm, ACX100_IE_POWER_MGMT);
+		acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
+		acxlog(L_INIT, "wakeup_cfg: 0x%02X\n", pm.wakeup_cfg);
+		acx_s_msleep(40);
+		acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
+		acxlog(L_INIT, "power save mode change %s\n",
+			(pm.wakeup_cfg & PS_CFG_PENDING) ? "FAILED" : "was successful");
+		/* FIXME: maybe verify via PS_CFG_PENDING bit here
+		 * that power save mode change was successful. */
+		/* FIXME: we shouldn't trigger a scan immediately after
+		 * fiddling with power save mode (since the firmware is sending
+		 * a NULL frame then). Does this need locking?? */
+		CLEAR_BIT(priv->set_mask, GETSET_POWER_80211);
+	}
+#endif
+
+	if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
+		/* channel */
+		acxlog(L_INIT, "updating channel to: %u\n", priv->channel);
+		CLEAR_BIT(priv->set_mask, GETSET_CHANNEL);
+	}
 
+	if (priv->set_mask & (GETSET_TX|GETSET_ALL)) {
+		/* set Tx */
+		acxlog(L_INIT, "updating: %s Tx\n",
+				priv->tx_disabled ? "disable" : "enable");
+		if (priv->tx_disabled)
+			acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
+			/*                                                 ^ */
+			/* FIXME: this used to be 1, but since we don't transfer a parameter... */
+		else
+			acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1);
+		CLEAR_BIT(priv->set_mask, GETSET_TX);
+	}
 
-/*----------------------------------------------------------------
-* acx_l_transmit_authen4
-*----------------------------------------------------------------*/
-static int
-acx_l_transmit_authen4(wlandevice_t *priv, const wlan_fr_authen_t *req)
-{
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct auth_frame_body *body;
+	if (priv->set_mask & (GETSET_RX|GETSET_ALL)) {
+		/* Enable Rx */
+		acxlog(L_INIT, "updating: enable Rx on channel: %u\n",
+				priv->channel);
+		acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1);
+		CLEAR_BIT(priv->set_mask, GETSET_RX);
+	}
+
+	if (priv->set_mask & (GETSET_RETRY|GETSET_ALL)) {
+		u8 short_retry[4 + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN];
+		u8 long_retry[4 + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN];
+
+		acxlog(L_INIT, "updating short retry limit: %u, long retry limit: %u\n",
+					priv->short_retry, priv->long_retry);
+		short_retry[0x4] = priv->short_retry;
+		long_retry[0x4] = priv->long_retry;
+		acx_s_configure(priv, &short_retry, ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT);
+		acx_s_configure(priv, &long_retry, ACX1xx_IE_DOT11_LONG_RETRY_LIMIT);
+		CLEAR_BIT(priv->set_mask, GETSET_RETRY);
+	}
+
+	if (priv->set_mask & (SET_MSDU_LIFETIME|GETSET_ALL)) {
+		u8 xmt_msdu_lifetime[4 + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN];
+
+		acxlog(L_INIT, "updating tx MSDU lifetime: %u\n",
+					priv->msdu_lifetime);
+		*(u32 *)&xmt_msdu_lifetime[4] = cpu_to_le32((u32)priv->msdu_lifetime);
+		acx_s_configure(priv, &xmt_msdu_lifetime, ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME);
+		CLEAR_BIT(priv->set_mask, SET_MSDU_LIFETIME);
+	}
+
+	if (priv->set_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
+		/* reg_domain */
+		acx_ie_generic_t dom;
+		unsigned mask;
+
+		acxlog(L_INIT, "updating regulatory domain: 0x%02X\n",
+					priv->reg_dom_id);
+		for (i = 0; i < sizeof(reg_domain_ids); i++)
+			if (reg_domain_ids[i] == priv->reg_dom_id)
+				break;
 
-	FN_ENTER;
+		if (sizeof(reg_domain_ids) == i) {
+			acxlog(L_INIT, "Invalid or unsupported regulatory "
+				"domain 0x%02X specified, falling back to "
+				"FCC (USA)! Please report if this sounds "
+				"fishy!\n", priv->reg_dom_id);
+			i = 0;
+			priv->reg_dom_id = reg_domain_ids[i];
+		}
+
+		priv->reg_dom_chanmask = reg_domain_channel_masks[i];
+		dom.m.bytes[0] = priv->reg_dom_id;
+		acx_s_configure(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
+
+		mask = (1 << (priv->channel - 1));
+		if (!(priv->reg_dom_chanmask & mask)) {
+		/* hmm, need to adjust our channel to reside within domain */
+			mask = 1;
+			for (i = 1; i <= 14; i++) {
+				if (priv->reg_dom_chanmask & mask) {
+					printk("%s: adjusting "
+						"selected channel from %d "
+						"to %d due to new regulatory "
+						"domain\n", priv->netdev->name,
+						priv->channel, i);
+					priv->channel = i;
+					break;
+				}
+				mask <<= 1;
+			}
+		}
+		CLEAR_BIT(priv->set_mask, GETSET_REG_DOMAIN);
+	}
 
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto ok;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto ok;
-	body = (void*)(head + 1);
+	if (priv->set_mask & (GETSET_MODE|GETSET_ALL)) {
+		priv->netdev->type = ARPHRD_ETHER;
 
-	head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
-	head->dur = req->hdr->dur;
-	MAC_COPY(head->da, req->hdr->a2);
-	/* MAC_COPY(head->sa, req->hdr->a1); */
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, req->hdr->a3);
-	head->seq = req->hdr->seq;
+		switch (priv->mode) {
+		case ACX_MODE_3_AP:
 
-	/* already in IEEE format, no endianness conversion */
-	body->auth_alg = *(req->auth_alg);
-	body->auth_seq = host2ieee16(4);
-	body->status = host2ieee16(0);
+			acx_lock(priv, flags);
+			acx_l_sta_list_init(priv);
+			priv->aid = 0;
+			priv->ap_client = NULL;
+			MAC_COPY(priv->bssid, priv->dev_addr);
+			/* this basically says "we're connected" */
+			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
+			acx_unlock(priv, flags);
 
-	acx_l_dma_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
-ok:
-	FN_EXIT1(OK);
-	return OK;
-}
+			acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
+			/* start sending beacons */
+			acx_s_cmd_join_bssid(priv, priv->bssid);
+			break;
+		case ACX_MODE_MONITOR:
+			/* TODO: what exactly do we want here? */
+			/* priv->netdev->type = ARPHRD_ETHER; */
+			/* priv->netdev->type = ARPHRD_IEEE80211; */
+			priv->netdev->type = ARPHRD_IEEE80211_PRISM;
+			acx111_s_feature_on(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
+			/* this stops beacons */
+			acx_s_cmd_join_bssid(priv, priv->bssid);
+			/* this basically says "we're connected" */
+			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
+			SET_BIT(priv->set_mask, SET_RXCONFIG|SET_WEP_OPTIONS);
+			break;
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
+			priv->aid = 0;
+			priv->ap_client = NULL;
+			/* we want to start looking for peer or AP */
+			start_scan = 1;
+			break;
+		case ACX_MODE_OFF:
+			/* TODO: disable RX/TX, stop any scanning activity etc: */
+			/* priv->tx_disabled = 1; */
+			/* SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX); */
+
+			/* This stops beacons (invalid macmode...) */
+			acx_s_cmd_join_bssid(priv, priv->bssid);
+			acx_set_status(priv, ACX_STATUS_0_STOPPED);
+			break;
+		}
+		CLEAR_BIT(priv->set_mask, GETSET_MODE);
+	}
 
+	if (priv->set_mask & (SET_RXCONFIG|GETSET_ALL)) {
+		acx_s_initialize_rx_config(priv);
+		CLEAR_BIT(priv->set_mask, SET_RXCONFIG);
+	}
 
-/*----------------------------------------------------------------
-* acx_l_transmit_assoc_req
-*
-* priv->ap_client is a current candidate AP here
-*----------------------------------------------------------------*/
-static int
-acx_l_transmit_assoc_req(wlandevice_t *priv)
-{
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	u8 *body, *p, *prate;
-	unsigned int packet_len;
-	u16 cap;
+	if (priv->set_mask & (GETSET_RESCAN|GETSET_ALL)) {
+		switch (priv->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			start_scan = 1;
+			break;
+		}
+		CLEAR_BIT(priv->set_mask, GETSET_RESCAN);
+	}
 
-	FN_ENTER;
+	if (priv->set_mask & (GETSET_WEP|GETSET_ALL)) {
+		/* encode */
 
-	acxlog(L_ASSOC, "sending association request, "
-			"awaiting response. NOT ASSOCIATED YET\n");
-	tx = acx_l_alloc_tx(priv);
-	if (!tx)
-		goto bad;
-	head = acx_l_get_txbuf(tx);
-	if (!head)
-		goto bad;
-	body = (void*)(head + 1);
+		ie_dot11WEPDefaultKeyID_t dkey;
+#ifdef DEBUG_WEP
+		struct {
+			u16 type ACX_PACKED;
+			u16 len ACX_PACKED;
+			u8  val ACX_PACKED;
+		} keyindic;
+#endif
+		acxlog(L_INIT, "updating WEP key settings\n");
 
-	head->fc = WF_FSTYPE_ASSOCREQi;
-	head->dur = host2ieee16(0x8000);
-	MAC_COPY(head->da, priv->bssid);
-	MAC_COPY(head->sa, priv->dev_addr);
-	MAC_COPY(head->bssid, priv->bssid);
-	head->seq = 0;
+		acx_s_set_wepkey(priv);
 
-	p = body;
-	/* now start filling the AssocReq frame body */
+		dkey.KeyID = priv->wep_current_index;
+		acxlog(L_INIT, "setting WEP key %u as default\n", dkey.KeyID);
+		acx_s_configure(priv, &dkey, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET);
+#ifdef DEBUG_WEP
+		keyindic.val = 3;
+		acx_s_configure(priv, &keyindic, ACX111_IE_KEY_CHOOSE);
+#endif
+		start_scan = 1;
+		CLEAR_BIT(priv->set_mask, GETSET_WEP);
+	}
 
-	/* since this assoc request will most likely only get
-	 * sent in the STA to AP case (and not when Ad-Hoc IBSS),
-	 * the cap combination indicated here will thus be
-	 * WF_MGMT_CAP_ESSi *always* (no IBSS ever)
-	 * The specs are more than non-obvious on all that:
-	 *
-	 * 802.11 7.3.1.4 Capability Information field
-	** APs set the ESS subfield to 1 and the IBSS subfield to 0 within
-	** Beacon or Probe Response management frames. STAs within an IBSS
-	** set the ESS subfield to 0 and the IBSS subfield to 1 in transmitted
-	** Beacon or Probe Response management frames
-	**
-	** APs set the Privacy subfield to 1 within transmitted Beacon,
-	** Probe Response, Association Response, and Reassociation Response
-	** if WEP is required for all data type frames within the BSS.
-	** STAs within an IBSS set the Privacy subfield to 1 in Beacon
-	** or Probe Response management frames if WEP is required
-	** for all data type frames within the IBSS */
+	if (priv->set_mask & (SET_WEP_OPTIONS|GETSET_ALL)) {
+		acx100_ie_wep_options_t options;
 
-	/* note that returning 0 will be refused by several APs...
-	 * (so this indicates that you're probably supposed to
-	 * "confirm" the ESS mode) */
-	cap = WF_MGMT_CAP_ESSi;
+		if (IS_ACX111(priv)) {
+			acxlog(L_DEBUG, "setting WEP Options for ACX111 is not supported\n");
+		} else {
+			acxlog(L_INIT, "setting WEP Options\n");
 
-	/* this one used to be a check on wep_restricted,
-	 * but more likely it's wep_enabled instead */
-	if (priv->wep_enabled)
-		SET_BIT(cap, WF_MGMT_CAP_PRIVACYi);
+			/* let's choose maximum setting: 4 default keys,
+			 * plus 10 other keys: */
+			options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
+			/* don't decrypt default key only,
+			 * don't override decryption: */
+			options.WEPOption = 0;
+			if (priv->mode == ACX_MODE_MONITOR) {
+				/* don't decrypt default key only,
+				 * override decryption mechanism: */
+				options.WEPOption = 2;
+			}
 
-	/* Probably we can just set these always, because our hw is
-	** capable of shortpre and PBCC --vda */
-	/* only ask for short preamble if the peer station supports it */
-	if (priv->ap_client->cap_info & WF_MGMT_CAP_SHORT)
-		SET_BIT(cap, WF_MGMT_CAP_SHORTi);
-	/* only ask for PBCC support if the peer station supports it */
-	if (priv->ap_client->cap_info & WF_MGMT_CAP_PBCC)
-		SET_BIT(cap, WF_MGMT_CAP_PBCCi);
+			acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
+		}
+		CLEAR_BIT(priv->set_mask, SET_WEP_OPTIONS);
+	}
 
-	/* IEs: 1. caps */
-	*(u16*)p = cap;	p += 2;
-	/* 2. listen interval */
-	*(u16*)p = host2ieee16(priv->listen_interval); p += 2;
-	/* 3. ESSID */
-	p = wlan_fill_ie_ssid(p,
-			strlen(priv->essid_for_assoc), priv->essid_for_assoc);
-	/* 4. supp rates */
-	prate = p;
-	p = wlan_fill_ie_rates(p,
-			priv->rate_supported_len, priv->rate_supported);
-	/* 5. ext supp rates */
-	p = wlan_fill_ie_rates_ext(p,
-			priv->rate_supported_len, priv->rate_supported);
+	/* Rescan was requested */
+	if (start_scan) {
+		switch (priv->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			/* We can avoid clearing list if join code
+			** will be a bit more clever about not picking
+			** 'bad' AP over and over again */
+			acx_lock(priv, flags);
+			priv->ap_client = NULL;
+			acx_l_sta_list_init(priv);
+			acx_set_status(priv, ACX_STATUS_1_SCANNING);
+			acx_unlock(priv, flags);
 
-	if (acx_debug & L_DEBUG) {
-		printk("association: rates element\n");
-		acx_dump_bytes(prate, p - prate);
+			acx_s_cmd_start_scan(priv);
+		}
 	}
 
-	/* calculate lengths */
-	packet_len = WLAN_HDR_A3_LEN + (p - body);
+	/* debug, rate, and nick don't need any handling */
+	/* what about sniffing mode?? */
 
-	acxlog(L_ASSOC, "association: requesting caps 0x%04X, ESSID '%s'\n",
-		cap, priv->essid_for_assoc);
+	acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X - after update\n",
+			priv->get_mask, priv->set_mask);
 
-	acx_l_dma_tx_data(priv, tx, packet_len);
-	FN_EXIT1(OK);
-	return OK;
-bad:
-	FN_EXIT1(NOT_OK);
-	return NOT_OK;
+/* end: */
+	FN_EXIT0;
 }
 
 
-/*----------------------------------------------------------------
-* acx_l_transmit_disassoc
-*
-* FIXME: looks like incomplete implementation of a helper:
-* acx_l_transmit_disassoc(priv, clt) - kick this client (we're an AP)
-* acx_l_transmit_disassoc(priv, NULL) - leave BSSID (we're a STA)
-*----------------------------------------------------------------*/
-int
-acx_l_transmit_disassoc(wlandevice_t *priv, client_t *clt)
+/***********************************************************************
+*/
+void
+acx_s_initialize_rx_config(wlandevice_t *priv)
 {
-	struct tx *tx;
-	struct wlan_hdr_mgmt *head;
-	struct disassoc_frame_body *body;
-
-	FN_ENTER;
-/*	if (clt != NULL) { */
-		tx = acx_l_alloc_tx(priv);
-		if (!tx)
-			goto bad;
-		head = acx_l_get_txbuf(tx);
-		if (!head)
-			goto bad;
-		body = (void*)(head + 1);
+	struct {
+		u16	id ACX_PACKED;
+		u16	len ACX_PACKED;
+		u16	rx_cfg1 ACX_PACKED;
+		u16	rx_cfg2 ACX_PACKED;
+	} cfg;
 
-/*		clt->used = CLIENT_AUTHENTICATED_2; - not (yet?) associated */
+	switch (priv->mode) {
+	case ACX_MODE_OFF:
+		priv->rx_config_1 = (u16) (0
+			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
+			/* | RX_CFG1_FILTER_SSID	*/
+			/* | RX_CFG1_FILTER_BCAST	*/
+			/* | RX_CFG1_RCV_MC_ADDR1	*/
+			/* | RX_CFG1_RCV_MC_ADDR0	*/
+			/* | RX_CFG1_FILTER_ALL_MULTI	*/
+			/* | RX_CFG1_FILTER_BSSID	*/
+			/* | RX_CFG1_FILTER_MAC		*/
+			/* | RX_CFG1_RCV_PROMISCUOUS	*/
+			/* | RX_CFG1_INCLUDE_FCS	*/
+			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
+			);
+		priv->rx_config_2 = (u16) (0
+			/*| RX_CFG2_RCV_ASSOC_REQ	*/
+			/*| RX_CFG2_RCV_AUTH_FRAMES	*/
+			/*| RX_CFG2_RCV_BEACON_FRAMES	*/
+			/*| RX_CFG2_RCV_CONTENTION_FREE	*/
+			/*| RX_CFG2_RCV_CTRL_FRAMES	*/
+			/*| RX_CFG2_RCV_DATA_FRAMES	*/
+			/*| RX_CFG2_RCV_BROKEN_FRAMES	*/
+			/*| RX_CFG2_RCV_MGMT_FRAMES	*/
+			/*| RX_CFG2_RCV_PROBE_REQ	*/
+			/*| RX_CFG2_RCV_PROBE_RESP	*/
+			/*| RX_CFG2_RCV_ACK_FRAMES	*/
+			/*| RX_CFG2_RCV_OTHER		*/
+			);
+		break;
+	case ACX_MODE_MONITOR:
+		priv->rx_config_1 = (u16) (0
+			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
+			/* | RX_CFG1_FILTER_SSID	*/
+			/* | RX_CFG1_FILTER_BCAST	*/
+			/* | RX_CFG1_RCV_MC_ADDR1	*/
+			/* | RX_CFG1_RCV_MC_ADDR0	*/
+			/* | RX_CFG1_FILTER_ALL_MULTI	*/
+			/* | RX_CFG1_FILTER_BSSID	*/
+			/* | RX_CFG1_FILTER_MAC		*/
+			| RX_CFG1_RCV_PROMISCUOUS
+			/* | RX_CFG1_INCLUDE_FCS	*/
+			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
+			);
+		priv->rx_config_2 = (u16) (0
+			| RX_CFG2_RCV_ASSOC_REQ
+			| RX_CFG2_RCV_AUTH_FRAMES
+			| RX_CFG2_RCV_BEACON_FRAMES
+			| RX_CFG2_RCV_CONTENTION_FREE
+			| RX_CFG2_RCV_CTRL_FRAMES
+			| RX_CFG2_RCV_DATA_FRAMES
+			| RX_CFG2_RCV_BROKEN_FRAMES
+			| RX_CFG2_RCV_MGMT_FRAMES
+			| RX_CFG2_RCV_PROBE_REQ
+			| RX_CFG2_RCV_PROBE_RESP
+			| RX_CFG2_RCV_ACK_FRAMES
+			| RX_CFG2_RCV_OTHER
+			);
+		break;
+	default:
+		priv->rx_config_1 = (u16) (0
+			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
+			/* | RX_CFG1_FILTER_SSID	*/
+			/* | RX_CFG1_FILTER_BCAST	*/
+			/* | RX_CFG1_RCV_MC_ADDR1	*/
+			/* | RX_CFG1_RCV_MC_ADDR0	*/
+			/* | RX_CFG1_FILTER_ALL_MULTI	*/
+			/* | RX_CFG1_FILTER_BSSID	*/
+			| RX_CFG1_FILTER_MAC
+			/* | RX_CFG1_RCV_PROMISCUOUS	*/
+			/* | RX_CFG1_INCLUDE_FCS	*/
+			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
+			);
+		priv->rx_config_2 = (u16) (0
+			| RX_CFG2_RCV_ASSOC_REQ
+			| RX_CFG2_RCV_AUTH_FRAMES
+			| RX_CFG2_RCV_BEACON_FRAMES
+			| RX_CFG2_RCV_CONTENTION_FREE
+			| RX_CFG2_RCV_CTRL_FRAMES
+			| RX_CFG2_RCV_DATA_FRAMES
+			/*| RX_CFG2_RCV_BROKEN_FRAMES	*/
+			| RX_CFG2_RCV_MGMT_FRAMES
+			| RX_CFG2_RCV_PROBE_REQ
+			| RX_CFG2_RCV_PROBE_RESP
+			/*| RX_CFG2_RCV_ACK_FRAMES	*/
+			| RX_CFG2_RCV_OTHER
+			);
+		break;
+	}
+#ifdef DEBUG_WEP
+	if (IS_ACX100(priv))
+		/* only ACX100 supports that */
+#endif
+		priv->rx_config_1 |= RX_CFG1_INCLUDE_RXBUF_HDR;
 
-		head->fc = WF_FSTYPE_DISASSOCi;
-		head->dur = 0;
-		/* huh? It muchly depends on whether we're STA or AP...
-		** sta->ap: da=bssid, sa=own, bssid=bssid
-		** ap->sta: da=sta, sa=bssid, bssid=bssid. FIXME! */
-		MAC_COPY(head->da, priv->bssid);
-		MAC_COPY(head->sa, priv->dev_addr);
-		MAC_COPY(head->bssid, priv->dev_addr);
-		head->seq = 0;
+	acxlog(L_INIT, "setting RXconfig to %04X:%04X\n",
+			priv->rx_config_1, priv->rx_config_2);
+	cfg.rx_cfg1 = cpu_to_le16(priv->rx_config_1);
+	cfg.rx_cfg2 = cpu_to_le16(priv->rx_config_2);
+	acx_s_configure(priv, &cfg, ACX1xx_IE_RXCONFIG);
+}
 
-		/* "Class 3 frame received from nonassociated station." */
-		body->reason = host2ieee16(7);
 
-		/* fixed size struct, ok to sizeof */
-		acx_l_dma_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
-/*	} */
-	FN_EXIT1(OK);
-	return OK;
-bad:
-	FN_EXIT1(NOT_OK);
-	return NOT_OK;
+/***********************************************************************
+** acx_schedule_after_interrupt_task
+**
+** Schedule the call of the after_interrupt method after leaving
+** the interrupt context.
+*/
+void
+acx_schedule_after_interrupt_task(wlandevice_t *priv, unsigned int set_flag)
+{
+	SET_BIT(priv->after_interrupt_jobs, set_flag);
+	SCHEDULE_WORK(&priv->after_interrupt_task);
 }
 
 
-/*----------------------------------------------------------------
-* acx_s_complete_scan
-*
-* Called either from after_interrupt_task() if:
-* 1) there was Scan_Complete IRQ, or
-* 2) scanning expired in timer()
-* We need to decide which ESS or IBSS to join.
-* Iterates thru priv->sta_list:
-*	if priv->ap is not bcast, will join only specified
-*	ESS or IBSS with this bssid
-*	checks peers' caps for ESS/IBSS bit
-*	checks peers' SSID, allows exact match or hidden SSID
-* If station to join is chosen:
-*	points priv->ap_client to the chosen struct client
-*	sets priv->essid_for_assoc for future assoc attempt
-* Auth/assoc is not yet performed
-* Returns OK if there is no need to restart scan
-*----------------------------------------------------------------*/
-int
-acx_s_complete_scan(wlandevice_t *priv)
+/***********************************************************************
+** Helper
+*/
+static void
+acx_s_after_interrupt_recalib(wlandevice_t *priv)
 {
-	struct client *bss;
-	unsigned long flags;
-	u16 needed_cap;
-	int i;
-	int idx_found = -1;
-	int result = OK;
+	int res;
+
+	/* this helps with ACX100 at least;
+	 * hopefully ACX111 also does a
+	 * recalibration here */
+
+	/* clear flag beforehand, since we want to make sure
+	 * it's cleared; then only set it again on specific circumstances */
+	CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
+
+	/* better wait a bit between recalibrations to
+	 * prevent overheating due to torturing the card
+	 * into working too long despite high temperature
+	 * (just a safety measure) */
+	if (priv->recalib_time_last_success
+	 && time_before(jiffies, priv->recalib_time_last_success
+					+ RECALIB_PAUSE * 60 * HZ)) {
+		priv->recalib_msg_ratelimit++;
+		if (priv->recalib_msg_ratelimit <= 5)
+			printk("%s: less than " STRING(RECALIB_PAUSE)
+				" minutes since last radio recalibration, "
+				"not recalibrating (maybe card is too hot?)\n",
+				priv->netdev->name);
+		if (priv->recalib_msg_ratelimit == 5)
+			printk("disabling above message\n");
+		return;
+	}
+
+	priv->recalib_msg_ratelimit = 0;
+
+	/* note that commands sometimes fail (card busy),
+	 * so only clear flag if we were fully successful */
+	res = acx_s_recalib_radio(priv);
+	if (res == OK) {
+		printk("%s: successfully recalibrated radio\n",
+						priv->netdev->name);
+		priv->recalib_time_last_success = jiffies;
+		priv->recalib_failure_count = 0;
+	} else {
+		/* failed: resubmit, but only limited
+		 * amount of times within some time range
+		 * to prevent endless loop */
+
+		priv->recalib_time_last_success = 0; /* we failed */
+
+		/* if some time passed between last
+		 * attempts, then reset failure retry counter
+		 * to be able to do next recalib attempt */
+		if (time_after(jiffies, priv->recalib_time_last_attempt + HZ))
+			priv->recalib_failure_count = 0;
+
+		if (++priv->recalib_failure_count <= 5) {
+			priv->recalib_time_last_attempt = jiffies;
+			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
+		}
+	}
+}
+
+/***********************************************************************
+** acx_e_after_interrupt_task
+*/
+static void
+acx_e_after_interrupt_task(void *data)
+{
+	netdevice_t *dev = (netdevice_t *) data;
+	wlandevice_t *priv;
 
 	FN_ENTER;
 
-	switch (priv->mode) {
-	case ACX_MODE_0_ADHOC:
-		needed_cap = WF_MGMT_CAP_IBSS; /* 2, we require Ad-Hoc */
-		break;
-	case ACX_MODE_2_STA:
-		needed_cap = WF_MGMT_CAP_ESS; /* 1, we require Managed */
-		break;
-	default:
-		printk("acx: driver bug: mode=%d in complete_scan()\n", priv->mode);
-		dump_stack();
-		goto end;
+	priv = (struct wlandevice *) dev->priv;
+
+	acx_sem_lock(priv);
+
+	if (!priv->after_interrupt_jobs)
+		goto end; /* no jobs to do */
+
+#if TX_CLEANUP_IN_SOFTIRQ
+	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_TX_CLEANUP) {
+		acx_lock(priv, flags);
+		acx_l_clean_tx_desc(priv);
+		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_TX_CLEANUP);
+		acx_unlock(priv, flags);
+	}
+#endif
+	/* we see lotsa tx errors */
+	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_RADIO_RECALIB) {
+		acx_s_after_interrupt_recalib(priv);
+	}
+
+	/* a poor interrupt code wanted to do update_card_settings() */
+	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_UPDATE_CARD_CFG) {
+		if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
+			acx_s_update_card_settings(priv, 0, 0);
+		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+	}
+
+	/* 1) we detected that no Scan_Complete IRQ came from fw, or
+	** 2) we found too many STAs */
+	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_STOP_SCAN) {
+		acxlog(L_IRQ, "sending a stop scan cmd...\n");
+		acx_s_issue_cmd(priv, ACX1xx_CMD_STOP_SCAN, NULL, 0);
+		/* HACK: set the IRQ bit, since we won't get a
+		 * scan complete IRQ any more on ACX111 (works on ACX100!),
+		 * since _we_, not a fw, have stopped the scan */
+		SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
+		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_STOP_SCAN);
+	}
+
+	/* either fw sent Scan_Complete or we detected that
+	** no Scan_Complete IRQ came from fw. Finish scanning,
+	** pick join partner if any */
+	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_COMPLETE_SCAN) {
+		if (priv->status == ACX_STATUS_1_SCANNING) {
+			if (OK != acx_s_complete_scan(priv)) {
+				SET_BIT(priv->after_interrupt_jobs,
+					ACX_AFTER_IRQ_RESTART_SCAN);
+			}
+		} else {
+			/* + scan kills current join status - restore it
+			**   (do we need it for STA?) */
+			/* + does it happen only with active scans?
+			**   active and passive scans? ALL scans including
+			**   background one? */
+			/* + was not verified that everything is restored
+			**   (but at least we start to emit beacons again) */
+			switch (priv->mode) {
+			case ACX_MODE_0_ADHOC:
+			case ACX_MODE_3_AP:
+				acxlog(L_IRQ, "redoing cmd_join_bssid() after scan\n");
+				acx_s_cmd_join_bssid(priv, priv->bssid);
+			}
+		}
+		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_COMPLETE_SCAN);
 	}
 
-	acx_lock(priv, flags);
+	/* STA auth or assoc timed out, start over again */
+	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_RESTART_SCAN) {
+		acxlog(L_IRQ, "sending a start_scan cmd...\n");
+		acx_s_cmd_start_scan(priv);
+		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_RESTART_SCAN);
+	}
+
+	/* whee, we got positive assoc response! 8) */
+	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_ASSOCIATE) {
+		acx_ie_generic_t pdr;
+		/* tiny race window exists, checking that we still a STA */
+		switch (priv->mode) {
+		case ACX_MODE_2_STA:
+			pdr.m.aid = cpu_to_le16(priv->aid);
+			acx_s_configure(priv, &pdr, ACX1xx_IE_ASSOC_ID);
+			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
+			acxlog(L_ASSOC | L_DEBUG, "ASSOCIATED!\n");
+			CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_ASSOCIATE);
+		}
+	}
+end:
+	acx_sem_unlock(priv);
+	FN_EXIT0;
+}
 
-	/* TODO: sta_iterator hiding implementation would be nice here... */
 
-	for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-		bss = &priv->sta_list[i];
-		if (!bss->used) continue;
+/***********************************************************************
+*/
+void
+acx_init_task_scheduler(wlandevice_t *priv)
+{
+	/* configure task scheduler */
+	INIT_WORK(&priv->after_interrupt_task, acx_e_after_interrupt_task, priv->netdev);
+}
 
-		acxlog(L_ASSOC, "Scan Table: SSID='%s' CH=%d SIR=%d SNR=%d\n",
-			bss->essid, bss->channel, bss->sir, bss->snr);
 
-		if (!mac_is_bcast(priv->ap))
-			if (!mac_is_equal(bss->bssid, priv->ap))
-				continue; /* keep looking */
+/***********************************************************************
+** acx_cmd_join_bssid
+**
+** Common code for both acx100 and acx111.
+*/
+/* NB: does NOT match RATE100_nn but matches ACX[111]_SCAN_RATE_n */
+static const u8
+bitpos2genframe_txrate[] = {
+	10,	/*  0.  1 Mbit/s */
+	20,	/*  1.  2 Mbit/s */
+	55,	/*  2.  5.5 Mbit/s */
+	0x0B,	/*  3.  6 Mbit/s */
+	0x0F,	/*  4.  9 Mbit/s */
+	110,	/*  5. 11 Mbit/s */
+	0x0A,	/*  6. 12 Mbit/s */
+	0x0E,	/*  7. 18 Mbit/s */
+	220,	/*  8. 22 Mbit/s */
+	0x09,	/*  9. 24 Mbit/s */
+	0x0D,	/* 10. 36 Mbit/s */
+	0x08,	/* 11. 48 Mbit/s */
+	0x0C,	/* 12. 54 Mbit/s */
+	10,	/* 13.  1 Mbit/s, should never happen */
+	10,	/* 14.  1 Mbit/s, should never happen */
+	10,	/* 15.  1 Mbit/s, should never happen */
+};
 
-		/* broken peer with no mode flags set? */
-		if (unlikely(!(bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)))) {
-			printk("%s: strange peer "MACSTR" found with "
-				"neither ESS (AP) nor IBSS (Ad-Hoc) "
-				"capability - skipped\n",
-				priv->netdev->name, MAC(bss->address));
-			continue;
-		}
-		acxlog(L_ASSOC, "peer_cap 0x%04X, needed_cap 0x%04X\n",
-		       bss->cap_info, needed_cap);
+/* Looks scary, eh?
+** Actually, each one compiled into one AND and one SHIFT,
+** 31 bytes in x86 asm (more if uints are replaced by u16/u8) */
+static unsigned int
+rate111to5bits(unsigned int rate)
+{
+	return (rate & 0x7)
+	| ( (rate & RATE111_11) / (RATE111_11/JOINBSS_RATES_11) )
+	| ( (rate & RATE111_22) / (RATE111_22/JOINBSS_RATES_22) )
+	;
+}
 
-		/* does peer station support what we need? */
-		if ((bss->cap_info & needed_cap) != needed_cap)
-			continue; /* keep looking */
+void BUG_joinbss_must_be_0x30_bytes_in_length(void);
 
-		/* strange peer with NO basic rates?! */
-		if (unlikely(!bss->rate_bas)) {
-			printk("%s: strange peer "MACSTR" with empty rate set "
-				"- skipped\n",
-				priv->netdev->name, MAC(bss->address));
-			continue;
-		}
+void
+acx_s_cmd_join_bssid(wlandevice_t *priv, const u8 *bssid)
+{
+	acx_joinbss_t tmp;
+	int dtim_interval;
+	int i;
 
-		/* do we support all basic rates of this peer? */
-		if ((bss->rate_bas & priv->rate_oper) != bss->rate_bas)	{
-/* we probably need to have all rates as operational rates,
-   even in case of an 11M-only configuration */
-#if THIS_IS_TROUBLESOME
-			printk("%s: peer "MACSTR": incompatible basic rates "
-				"(AP requests 0x%04X, we have 0x%04X) "
-				"- skipped\n",
-				priv->netdev->name, MAC(bss->address),
-				bss->rate_bas, priv->rate_oper);
-			continue;
-#else
-			printk("%s: peer "MACSTR": incompatible basic rates "
-				"(AP requests 0x%04X, we have 0x%04X). "
-				"Considering anyway...\n",
-				priv->netdev->name, MAC(bss->address),
-				bss->rate_bas, priv->rate_oper);
-#endif
-		}
+	/* compile-time check for proper size of fixed-size struct */
+	if (sizeof(acx_joinbss_t) != 0x30)
+		BUG_joinbss_must_be_0x30_bytes_in_length();
 
-		if ( !(priv->reg_dom_chanmask & (1<<(bss->channel-1))) ) {
-			printk("%s: warning: peer "MACSTR" is on channel %d "
-				"outside of channel range of current "
-				"regulatory domain - couldn't join "
-				"even if other settings match. "
-				"You might want to adapt your config\n",
-				priv->netdev->name, MAC(bss->address),
-				bss->channel);
-			continue; /* keep looking */
-		}
+	FN_ENTER;
 
-		if (!priv->essid_active || !strcmp(bss->essid, priv->essid)) {
-			acxlog(L_ASSOC,
-			       "found station with matching ESSID! ('%s' "
-			       "station, '%s' config)\n",
-			       bss->essid,
-			       (priv->essid_active) ? priv->essid : "[any]");
-			/* TODO: continue looking for peer with better SNR */
-			bss->used = CLIENT_JOIN_CANDIDATE;
-			idx_found = i;
+	dtim_interval =	(ACX_MODE_0_ADHOC == priv->mode) ?
+			1 : priv->dtim_interval;
 
-			/* stop searching if this station is
-			 * on the current channel, otherwise
-			 * keep looking for an even better match */
-			if (bss->channel == priv->channel)
-				break;
-		} else
-		if (!bss->essid[0]
-		 || ((' ' == bss->essid[0]) && !bss->essid[1])
-		) {
-			/* hmm, station with empty or single-space SSID:
-			 * using hidden SSID broadcast?
-			 */
-			/* This behaviour is broken: which AP from zillion
-			** of APs with hidden SSID you'd try?
-			** We should use Probe requests to get Probe responses
-			** and check for real SSID (are those never hidden?) */
-			bss->used = CLIENT_JOIN_CANDIDATE;
-			if (idx_found == -1)
-				idx_found = i;
-			acxlog(L_ASSOC, "found station with empty or "
-				"single-space (hidden) SSID, considering "
-				"for assoc attempt\n");
-			/* ...and keep looking for better matches */
-		} else {
-			acxlog(L_ASSOC, "ESSID doesn't match! ('%s' "
-				"station, '%s' config)\n",
-				bss->essid,
-				(priv->essid_active) ? priv->essid : "[any]");
-		}
+	memset(&tmp, 0, sizeof(tmp));
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		tmp.bssid[i] = bssid[ETH_ALEN-1 - i];
 	}
 
-	/* TODO: iterate thru join candidates instead */
-	/* TODO: rescan if not associated within some timeout */
-	if (idx_found != -1) {
-		char *essid_src;
-		size_t essid_len;
+	tmp.beacon_interval = cpu_to_le16(priv->beacon_interval);
+
+	/* basic rate set. Control frame responses (such as ACK or CTS frames)
+	** are sent with one of these rates */
+	if (IS_ACX111(priv)) {
+		/* It was experimentally determined that rates_basic
+		** can take 11g rates as well, not only rates
+		** defined with JOINBSS_RATES_BASIC111_nnn.
+		** Just use RATE111_nnn constants... */
+		tmp.u.acx111.dtim_interval = dtim_interval;
+		tmp.u.acx111.rates_basic = cpu_to_le16(priv->rate_basic);
+		acxlog(L_ASSOC, "%s rates_basic %04X, rates_supported %04X\n",
+			__func__, priv->rate_basic, priv->rate_oper);
+	} else {
+		tmp.u.acx100.dtim_interval = dtim_interval;
+		tmp.u.acx100.rates_basic = rate111to5bits(priv->rate_basic);
+		tmp.u.acx100.rates_supported = rate111to5bits(priv->rate_oper);
+		acxlog(L_ASSOC, "%s rates_basic %04X->%02X, "
+			"rates_supported %04X->%02X\n",
+			__func__,
+			priv->rate_basic, tmp.u.acx100.rates_basic,
+			priv->rate_oper, tmp.u.acx100.rates_supported);
+	}
+
+	/* Setting up how Beacon, Probe Response, RTS, and PS-Poll frames
+	** will be sent (rate/modulation/preamble) */
+	tmp.genfrm_txrate = bitpos2genframe_txrate[lowest_bit(priv->rate_basic)];
+	tmp.genfrm_mod_pre = 0; /* FIXME: was = priv->capab_short (which is always 0); */
+	/* we can use short pre *if* all peers can understand it */
+	/* FIXME #2: we need to correctly set PBCC/OFDM bits here too */
+
+	/* we switch fw to STA mode in MONITOR mode, it seems to be
+	** the only mode where fw does not emit beacons by itself
+	** but allows us to send anything (we really want to retain
+	** ability to tx arbitrary frames in MONITOR mode)
+	*/
+	tmp.macmode = (priv->mode != ACX_MODE_MONITOR ? priv->mode : ACX_MODE_2_STA);
+	tmp.channel = priv->channel;
+	tmp.essid_len = priv->essid_len;
+	/* NOTE: the code memcpy'd essid_len + 1 before, which is WRONG! */
+	memcpy(tmp.essid, priv->essid, tmp.essid_len);
+	acx_s_issue_cmd(priv, ACX1xx_CMD_JOIN, &tmp, tmp.essid_len + 0x11);
 
-		bss = &priv->sta_list[idx_found];
-		priv->ap_client = bss;
+	acxlog(L_ASSOC | L_DEBUG, "BSS_Type = %u\n", tmp.macmode);
+	acxlog_mac(L_ASSOC | L_DEBUG, "JoinBSSID MAC:", priv->bssid, "\n");
 
-		if (bss->essid[0] == '\0') {
-			/* if the ESSID of the station we found is empty
-			 * (no broadcast), then use user configured ESSID
-			 * instead */
-			essid_src = priv->essid;
-			essid_len = priv->essid_len;
-		} else {
-			essid_src = bss->essid;
-			essid_len = strlen(bss->essid);
-		}
+	acx_update_capabilities(priv);
+	FN_EXIT0;
+}
 
-		acx_update_capabilities(priv);
 
-		memcpy(priv->essid_for_assoc, essid_src, essid_len);
-		priv->essid_for_assoc[essid_len] = '\0';
-		priv->channel = bss->channel;
-		MAC_COPY(priv->bssid, bss->bssid);
+/***********************************************************************
+** acx_s_start
+*/
+void
+acx_s_start(wlandevice_t *priv)
+{
+	FN_ENTER;
 
-		bss->rate_cfg = (bss->rate_cap & priv->rate_oper);
-		bss->rate_cur = 1 << lowest_bit(bss->rate_cfg);
-		bss->rate_100 = acx_rate111to100(bss->rate_cur);
+	/*
+	 * Ok, now we do everything that can possibly be done with ioctl
+	 * calls to make sure that when it was called before the card
+	 * was up we get the changes asked for
+	 */
+
+	SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST|GETSET_WEP
+		|GETSET_TXPOWER|GETSET_ANTENNA|GETSET_ED_THRESH|GETSET_CCA
+		|GETSET_REG_DOMAIN|GETSET_MODE|GETSET_CHANNEL
+		|GETSET_TX|GETSET_RX);
 
-		acxlog_mac(L_ASSOC,
-			"matching station found: ", priv->bssid, ", joining\n");
+	acxlog(L_INIT, "updating initial settings on iface activation...\n");
+	acx_s_update_card_settings(priv, 0, 0);
 
-		/* TODO: do we need to switch to the peer's channel first? */
+	FN_EXIT0;
+}
 
-		if (ACX_MODE_0_ADHOC == priv->mode) {
-			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-		} else {
-			acx_l_transmit_authen1(priv);
-			acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
-		}
-	} else { /* idx_found == -1 */
-		/* uh oh, no station found in range */
-		if (ACX_MODE_0_ADHOC == priv->mode) {
-			printk("%s: no matching station found in range, "
-				"generating our own IBSS instead\n",
-				priv->netdev->name);
-			/* we do it hostap way: */
-			MAC_COPY(priv->bssid, priv->dev_addr);
-			priv->bssid[0] |= 0x02; /* 'local assigned addr' bit */
-			/* add IBSS bit to our caps... */
-			acx_update_capabilities(priv);
-			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-			/* In order to cmd_join be called below */
-			idx_found = 0;
-		} else {
-			/* we shall scan again, AP can be
-			** just temporarily powered off */
-			acxlog(L_ASSOC,
-				"no matching station found in range yet\n");
-			acx_set_status(priv, ACX_STATUS_1_SCANNING);
-			result = NOT_OK;
-		}
-	}
 
-	acx_unlock(priv, flags);
+/***********************************************************************
+** acx_update_capabilities
+*/
+void
+acx_update_capabilities(wlandevice_t *priv)
+{
+	u16 cap = 0;
 
-	if (idx_found != -1) {
-		if (ACX_MODE_0_ADHOC == priv->mode) {
-			/* need to update channel in beacon template */
-			SET_BIT(priv->set_mask, SET_TEMPLATES);
-			if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
-				acx_s_update_card_settings(priv, 0, 0);
-		}
-		/* Inform firmware on our decision to start or join BSS */
-		acx_s_cmd_join_bssid(priv, priv->bssid);
+	switch (priv->mode) {
+	case ACX_MODE_3_AP:
+		SET_BIT(cap, WF_MGMT_CAP_ESS); break;
+	case ACX_MODE_0_ADHOC:
+		SET_BIT(cap, WF_MGMT_CAP_IBSS); break;
+	/* other types of stations do not emit beacons */
 	}
 
-end:
-	FN_EXIT1(result);
-	return result;
+	if (priv->wep_restricted) {
+		SET_BIT(cap, WF_MGMT_CAP_PRIVACY);
+	}
+	if (priv->capab_short) {
+		SET_BIT(cap, WF_MGMT_CAP_SHORT);
+	}
+	if (priv->capab_pbcc) {
+		SET_BIT(cap, WF_MGMT_CAP_PBCC);
+	}
+	if (priv->capab_agility) {
+		SET_BIT(cap, WF_MGMT_CAP_AGILITY);
+	}
+	acxlog(L_DEBUG, "caps updated from 0x%04X to 0x%04X\n",
+				priv->capabilities, cap);
+	priv->capabilities = cap;
 }
 
+#ifdef UNUSED
+/***********************************************************************
+** FIXME: check whether this function is indeed acx111 only,
+** rename ALL relevant definitions to indicate actual card scope!
+*/
+void
+acx111_s_read_configoption(wlandevice_t *priv)
+{
+	acx111_ie_configoption_t co, co2;
+	int i;
+	const u8 *pEle;
 
-#if (POWER_SAVE_80211 == 0)
-/*----------------------------------------------------------------
-* acx_s_activate_power_save_mode
-*----------------------------------------------------------------*/
-static void
-acx_s_activate_power_save_mode(wlandevice_t *priv, /*@unused@*/ int vala)
+	if (OK != acx_s_interrogate(priv, &co, ACX111_IE_CONFIG_OPTIONS) ) {
+		return;
+	};
+	if (!(acx_debug & L_DEBUG))
+		return;
+
+	memcpy(&co2.configoption_fixed, &co.configoption_fixed,
+			sizeof(co.configoption_fixed));
+
+	pEle = (u8 *)&co.configoption_fixed + sizeof(co.configoption_fixed) - 4;
+
+	co2.antennas.type = pEle[0];
+	co2.antennas.len = pEle[1];
+	printk("AntennaID:%02X Len:%02X Data:",
+			co2.antennas.type, co2.antennas.len);
+	for (i = 0; i < pEle[1]; i++) {
+		co2.antennas.list[i] = pEle[i+2];
+		printk("%02X ", pEle[i+2]);
+	}
+	printk("\n");
+
+	pEle += pEle[1] + 2;
+	co2.power_levels.type = pEle[0];
+	co2.power_levels.len = pEle[1];
+	printk("PowerLevelID:%02X Len:%02X Data:",
+			co2.power_levels.type, co2.power_levels.len);
+	for (i = 0; i < pEle[1]*2; i++) {
+		co2.power_levels.list[i] = pEle[i+2];
+		printk("%02X ", pEle[i+2]);
+	}
+	printk("\n");
+
+	pEle += pEle[1]*2 + 2;
+	co2.data_rates.type = pEle[0];
+	co2.data_rates.len = pEle[1];
+	printk("DataRatesID:%02X Len:%02X Data:",
+			co2.data_rates.type, co2.data_rates.len);
+	for (i = 0; i < pEle[1]; i++) {
+		co2.data_rates.list[i] = pEle[i+2];
+		printk("%02X ", pEle[i+2]);
+	}
+	printk("\n");
+
+	pEle += pEle[1] + 2;
+	co2.domains.type = pEle[0];
+	co2.domains.len = pEle[1];
+	printk("DomainID:%02X Len:%02X Data:",
+			co2.domains.type, co2.domains.len);
+	for (i = 0; i < pEle[1]; i++) {
+		co2.domains.list[i] = pEle[i+2];
+		printk("%02X ", pEle[i+2]);
+	}
+	printk("\n");
+
+	pEle += pEle[1] + 2;
+	co2.product_id.type = pEle[0];
+	co2.product_id.len = pEle[1];
+	for (i = 0; i < pEle[1]; i++) {
+		co2.product_id.list[i] = pEle[i+2];
+	}
+	printk("ProductID:%02X Len:%02X Data:%.*s\n",
+			co2.product_id.type, co2.product_id.len,
+			co2.product_id.len, (char *)co2.product_id.list);
+
+	pEle += pEle[1] + 2;
+	co2.manufacturer.type = pEle[0];
+	co2.manufacturer.len = pEle[1];
+	for (i = 0; i < pEle[1]; i++) {
+		co2.manufacturer.list[i] = pEle[i+2];
+	}
+	printk("ManufacturerID:%02X Len:%02X Data:%.*s\n",
+			co2.manufacturer.type, co2.manufacturer.len,
+			co2.manufacturer.len, (char *)co2.manufacturer.list);
+/*
+	printk("EEPROM part:\n");
+	for (i=0; i<58; i++) {
+		printk("%02X =======>  0x%02X\n",
+			    i, (u8 *)co.configoption_fixed.NVSv[i-2]);
+	}
+*/
+}
+#endif
+
+
+/***********************************************************************
+** Not inlined: it's larger than it seems
+*/
+void
+acx_print_mac(const char *head, const u8 *mac, const char *tail)
 {
-	acx100_ie_powermgmt_t pm;
+	printk("%s"MACSTR"%s", head, MAC(mac), tail);
+}
 
-	FN_ENTER;
 
-	acx_s_interrogate(priv, &pm, ACX1xx_IE_POWER_MGMT);
-	if (pm.wakeup_cfg != 0x81)
-		goto end;
+/***********************************************************************
+*/
+static int __init
+acx_e_init_module(void)
+{
+	int r1,r2;
+	printk("acx: this driver is still EXPERIMENTAL\n"
+		"acx: reading README file and/or Craig's HOWTO is "
+		"recommended, visit http://acx100.sf.net in case "
+		"of further questions/discussion\n");
 
-	pm.wakeup_cfg = 0;
-	pm.options = 0;
-	pm.hangover_period = 0;
-	acx_s_configure(priv, &pm, ACX1xx_IE_POWER_MGMT);
-end:
-	FN_EXIT0;
+#if defined(CONFIG_ACX_PCI)
+	r1 = acxpci_e_init_module();
+#else
+	r1 = -EINVAL;
+#endif
+#if defined(CONFIG_ACX_USB)
+	r2 = acxusb_e_init_module();
+#else
+	r2 = -EINVAL;
+#endif
+	if (r2 && r1) /* both failed! */
+		return r2 ? r2 : r1;
+	/* return success if at least one succeeded */
+	return 0;
 }
+
+static void __exit
+acx_e_cleanup_module(void)
+{
+#if defined(CONFIG_ACX_PCI)
+	acxpci_e_cleanup_module();
+#endif
+#if defined(CONFIG_ACX_USB)
+	acxusb_e_cleanup_module();
 #endif
+}
+
+module_init(acx_e_init_module)
+module_exit(acx_e_cleanup_module)
diff -puN drivers/net/wireless/tiacx/helper.c~acx-update drivers/net/wireless/tiacx/helper.c
--- 25/drivers/net/wireless/tiacx/helper.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/helper.c	Fri Sep  9 17:28:49 2005
@@ -38,9 +38,6 @@
 #include <linux/timer.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
-#ifdef ACX_PCI
-#include <linux/pci.h>
-#endif
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
@@ -51,7 +48,6 @@
 #include <net/iw_handler.h>
 #endif
 #include <linux/pm.h>
-#include <linux/delay.h>
 
 #include "acx.h"
 
@@ -62,577 +58,44 @@
 /* Now that the pci_alloc_consistent() problem has been resolved,
  * feel free to modify buffer count for ACX100 to 32, too.
  * But it's not required since the card isn't too fast anyway */
-#define RXBUFFERCOUNT_ACX100 16
-#define TXBUFFERCOUNT_ACX100 16
+#define RXBUFCNT_ACX100 16
+#define TXBUFCNT_ACX100 16
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 53)
 /* dma_alloc_coherent() uses GFP_KERNEL, much less problematic than
  * the pci_alloc_consistent() used below using GFP_ATOMIC (quite often causes
  * a larger alloc to fail), so use less buffers there to be more successful */
-#define RXBUFFERCOUNT_ACX111 32
-#define TXBUFFERCOUNT_ACX111 32
-#else
-#define RXBUFFERCOUNT_ACX111 16
-#define TXBUFFERCOUNT_ACX111 16
-#endif
-#define TXBUFFERCOUNT_USB 10
-#define RXBUFFERCOUNT_USB 10
-
-
-/***********************************************************************
-*/
-
-/* minutes to wait until next radio recalibration: */
-#define RECALIB_PAUSE	5
-
-const u8 reg_domain_ids[] =
-	{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41, 0x51 };
-/* stupid workaround for the fact that in C the size of an external array
- * cannot be determined from within a second file */
-const u8 reg_domain_ids_len = sizeof(reg_domain_ids);
-const u16 reg_domain_channel_masks[] =
-	{ 0x07ff, 0x07ff, 0x1fff, 0x0600, 0x1e00, 0x2000, 0x3fff, 0x01fc };
-
-
-/***********************************************************************
-** Debugging support
-*/
-#ifdef PARANOID_LOCKING
-static unsigned max_lock_time;
-static unsigned max_sem_time;
-
-void
-acx_lock_unhold() { max_lock_time = 0; }
-void
-acx_sem_unhold() { max_sem_time = 0; }
-
-static inline const char*
-sanitize_str(const char *s)
-{
-	const char* t = strrchr(s, '/');
-	if (t) return t + 1;
-	return s;
-}
-
-void
-acx_lock_debug(wlandevice_t *priv, const char* where)
-{
-	int count = 100*1000*1000;
-	where = sanitize_str(where);
-	while (--count) {
-		if (!spin_is_locked(&priv->lock)) break;
-		cpu_relax();
-	}
-	if (!count) {
-		printk(KERN_EMERG "LOCKUP: already taken at %s!\n", priv->last_lock);
-		BUG();
-	}
-	priv->last_lock = where;
-	rdtscl(priv->lock_time);
-}
-void
-acx_unlock_debug(wlandevice_t *priv, const char* where)
-{
-	unsigned diff;
-#ifdef SMP
-	if (!spin_is_locked(&priv->lock)) {
-		where = sanitize_str(where);
-		printk(KERN_EMERG "STRAY UNLOCK at %s!\n", where);
-		BUG();
-	}
-#endif
-	rdtscl(diff);
-	diff -= priv->lock_time;
-	if (diff > max_lock_time) {
-		where = sanitize_str(where);
-		printk("max lock hold time %d CPU ticks "
-			"from %s to %s\n", diff, priv->last_lock, where);
-		max_lock_time = diff;
-	}
-}
-void
-acx_down_debug(wlandevice_t *priv, const char* where)
-{
-	int sem_count;
-	int count = 5000/5;
-	where = sanitize_str(where);
-
-	while (--count) {
-		sem_count = atomic_read(&priv->sem.count);
-		if (sem_count) break;
-		msleep(5);
-	}
-	if (!count) {
-		printk(KERN_EMERG "D STATE at %s! last sem at %s\n",
-			where, priv->last_sem);
-		dump_stack();
-	}
-	priv->last_sem = where;
-	priv->sem_time = jiffies;
-	down(&priv->sem);
-	if (acx_debug & L_LOCK) {
-		printk("%s: sem_down %d -> %d\n",
-			where, sem_count, atomic_read(&priv->sem.count));
-	}
-}
-void
-acx_up_debug(wlandevice_t *priv, const char* where)
-{
-	unsigned diff;
-	int sem_count = atomic_read(&priv->sem.count);
-	if (sem_count) {
-		where = sanitize_str(where);
-		printk(KERN_EMERG "STRAY UP at %s! sem.count=%d\n", where, sem_count);
-		dump_stack();
-	}
-	diff = jiffies - priv->sem_time;
-	if (diff > max_sem_time) {
-		where = sanitize_str(where);
-		printk("max sem hold time %d jiffies "
-			"from %s to %s\n", diff, priv->last_sem, where);
-		max_sem_time = diff;
-	}
-	up(&priv->sem);
-	if (acx_debug & L_LOCK) {
-		where = sanitize_str(where);
-		printk("%s: sem_up %d -> %d\n",
-			where, sem_count, atomic_read(&priv->sem.count));
-	}
-}
-#endif /* PARANOID_LOCKING */
-
-
-/***********************************************************************
-*/
-#if ACX_DEBUG > 1
-
-static int acx_debug_func_indent;
-#define DEBUG_TSC 0
-#define FUNC_INDENT_INCREMENT 2
-
-#if DEBUG_TSC
-#define TIMESTAMP(d) unsigned long d; rdtscl(d)
+#define RXBUFCNT_ACX111 32
+#define TXBUFCNT_ACX111 32
 #else
-#define TIMESTAMP(d) unsigned long d = jiffies
-#endif
-
-static const char
-spaces[] = "          " "          "; /* Nx10 spaces */
-
-void
-log_fn_enter(const char *funcname)
-{
-	int indent;
-	TIMESTAMP(d);
-
-	indent = acx_debug_func_indent;
-	if (indent >= sizeof(spaces))
-		indent = sizeof(spaces)-1;
-
-	printk("%08lx %s==> %s\n",
-		d,
-		spaces + (sizeof(spaces)-1) - indent,
-		funcname
-	);
-
-	acx_debug_func_indent += FUNC_INDENT_INCREMENT;
-}
-void
-log_fn_exit(const char *funcname)
-{
-	int indent;
-	TIMESTAMP(d);
-
-	acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
-
-	indent = acx_debug_func_indent;
-	if (indent >= sizeof(spaces))
-		indent = sizeof(spaces)-1;
-
-	printk("%08lx %s<== %s\n",
-		d,
-		spaces + (sizeof(spaces)-1) - indent,
-		funcname
-	);
-}
-void
-log_fn_exit_v(const char *funcname, int v)
-{
-	int indent;
-	TIMESTAMP(d);
-
-	acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
-
-	indent = acx_debug_func_indent;
-	if (indent >= sizeof(spaces))
-		indent = sizeof(spaces)-1;
-
-	printk("%08lx %s<== %s: %08X\n",
-		d,
-		spaces + (sizeof(spaces)-1) - indent,
-		funcname,
-		v
-	);
-}
-#endif /* ACX_DEBUG > 1 */
-
-
-/***********************************************************************
-** Basically a msleep with logging
-*/
-void
-acx_s_msleep(int ms)
-{
-	FN_ENTER;
-	msleep(ms);
-	FN_EXIT0;
-}
-
-
-/*----------------------------------------------------------------
-* acx_get_packet_type_string
-*----------------------------------------------------------------*/
-#if ACX_DEBUG
-const char*
-acx_get_packet_type_string(u16 fc)
-{
-	static const char * const mgmt_arr[] = {
-		"MGMT/AssocReq", "MGMT/AssocResp", "MGMT/ReassocReq",
-		"MGMT/ReassocResp", "MGMT/ProbeReq", "MGMT/ProbeResp",
-		"MGMT/UNKNOWN", "MGMT/UNKNOWN", "MGMT/Beacon", "MGMT/ATIM",
-		"MGMT/Disassoc", "MGMT/Authen", "MGMT/Deauthen"
-	};
-	static const char * const ctl_arr[] = {
-		"CTL/PSPoll", "CTL/RTS", "CTL/CTS", "CTL/Ack", "CTL/CFEnd",
-		"CTL/CFEndCFAck"
-	};
-	static const char * const data_arr[] = {
-		"DATA/DataOnly", "DATA/Data CFAck", "DATA/Data CFPoll",
-		"DATA/Data CFAck/CFPoll", "DATA/Null", "DATA/CFAck",
-		"DATA/CFPoll", "DATA/CFAck/CFPoll"
-	};
-	const char *str = "UNKNOWN";
-	u8 fstype = (WF_FC_FSTYPE & fc) >> 4;
-	u8 ctl;
-
-	FN_ENTER;
-	switch (WF_FC_FTYPE & fc) {
-	case WF_FTYPE_MGMT:
-		str = "MGMT/UNKNOWN";
-		if (fstype < VEC_SIZE(mgmt_arr))
-			str = mgmt_arr[fstype];
-		break;
-	case WF_FTYPE_CTL:
-		ctl = fstype - 0x0a;
-		str = "CTL/UNKNOWN";
-		if (ctl < VEC_SIZE(ctl_arr))
-			str = ctl_arr[ctl];
-		break;
-	case WF_FTYPE_DATA:
-		str = "DATA/UNKNOWN";
-		if (fstype < VEC_SIZE(data_arr))
-			str = data_arr[fstype];
-		break;
-	}
-	FN_EXIT0;
-	return str;
-}
-#endif
-
-
-/***********************************************************************
-** maps acx111 tx descr rate field to acx100 one
-*/
-const u8
-bitpos2rate100[] = {
-	RATE100_1	,/* 0 */
-	RATE100_2	,/* 1 */
-	RATE100_5	,/* 2 */
-	RATE100_2	,/* 3, should not happen */
-	RATE100_2	,/* 4, should not happen */
-	RATE100_11	,/* 5 */
-	RATE100_2	,/* 6, should not happen */
-	RATE100_2	,/* 7, should not happen */
-	RATE100_22	,/* 8 */
-	RATE100_2	,/* 9, should not happen */
-	RATE100_2	,/* 10, should not happen */
-	RATE100_2	,/* 11, should not happen */
-	RATE100_2	,/* 12, should not happen */
-	RATE100_2	,/* 13, should not happen */
-	RATE100_2	,/* 14, should not happen */
-	RATE100_2	,/* 15, should not happen */
-};
-
-u8
-acx_rate111to100(u16 r) {
-	return bitpos2rate100[highest_bit(r)];
-}
-
-
-/*----------------------------------------------------------------
-* acx_l_rxmonitor
-* Called from IRQ context only
-*----------------------------------------------------------------*/
-static void
-acx_l_rxmonitor(wlandevice_t *priv, const rxbuffer_t *rxbuf)
-{
-	wlansniffrm_t *msg;
-	struct sk_buff *skb;
-	void *datap;
-	unsigned int skb_len;
-	int payload_offset;
-
-	FN_ENTER;
-
-	/* we are in big luck: the acx100 doesn't modify any of the fields */
-	/* in the 802.11 frame. just pass this packet into the PF_PACKET */
-	/* subsystem. yeah. */
-#if 0
-	if (!(priv->rx_config_1 & RX_CFG1_INCLUDE_RXBUF_HDR)) {
-		printk("rx_config_1 is missing RX_CFG1_INCLUDE_RXBUF_HDR\n");
-		goto end;
-	}
+#define RXBUFCNT_ACX111 16
+#define TXBUFCNT_ACX111 16
 #endif
-	payload_offset = ((u8*)acx_get_wlan_hdr(priv, rxbuf) - (u8*)rxbuf);
-	skb_len = RXBUF_BYTES_USED(rxbuf) - payload_offset;
-
-	/* sanity check */
-	if (skb_len > (WLAN_A4FR_MAXLEN_WEP)) {
-		printk("monitor mode panic: oversized frame!\n");
-		goto end;
-	}
-
-	if (priv->netdev->type == ARPHRD_IEEE80211_PRISM)
-		skb_len += sizeof(*msg);
-
-	/* allocate skb */
-	skb = dev_alloc_skb(skb_len);
-	if (!skb) {
-		printk("%s: no memory for skb (%u bytes)\n",
-				priv->netdev->name, skb_len);
-		goto end;
-	}
-
-	skb_put(skb, skb_len);
-
-		/* when in raw 802.11 mode, just copy frame as-is */
-	if (priv->netdev->type == ARPHRD_IEEE80211)
-		datap = skb->data;
-	else { /* otherwise, emulate prism header */
-		msg = (wlansniffrm_t*)skb->data;
-		datap = msg + 1;
-
-		msg->msgcode = WLANSNIFFFRM;
-		msg->msglen = sizeof(*msg);
-		strncpy(msg->devname, priv->netdev->name, sizeof(msg->devname)-1);
-		msg->devname[sizeof(msg->devname)-1] = '\0';
-
-		msg->hosttime.did = WLANSNIFFFRM_hosttime;
-		msg->hosttime.status = WLANITEM_STATUS_data_ok;
-		msg->hosttime.len = 4;
-		msg->hosttime.data = jiffies;
-
-		msg->mactime.did = WLANSNIFFFRM_mactime;
-		msg->mactime.status = WLANITEM_STATUS_data_ok;
-		msg->mactime.len = 4;
-		msg->mactime.data = rxbuf->time;
-
-		msg->channel.did = WLANSNIFFFRM_channel;
-		msg->channel.status = WLANITEM_STATUS_data_ok;
-		msg->channel.len = 4;
-		msg->channel.data = priv->channel;
-
-		msg->rssi.did = WLANSNIFFFRM_rssi;
-		msg->rssi.status = WLANITEM_STATUS_no_value;
-		msg->rssi.len = 4;
-		msg->rssi.data = 0;
-
-		msg->sq.did = WLANSNIFFFRM_sq;
-		msg->sq.status = WLANITEM_STATUS_no_value;
-		msg->sq.len = 4;
-		msg->sq.data = 0;
-
-		msg->signal.did = WLANSNIFFFRM_signal;
-		msg->signal.status = WLANITEM_STATUS_data_ok;
-		msg->signal.len = 4;
-		msg->signal.data = rxbuf->phy_snr;
-
-		msg->noise.did = WLANSNIFFFRM_noise;
-		msg->noise.status = WLANITEM_STATUS_data_ok;
-		msg->noise.len = 4;
-		msg->noise.data = rxbuf->phy_level;
-
-		msg->rate.did = WLANSNIFFFRM_rate;
-		msg->rate.status = WLANITEM_STATUS_data_ok;
-		msg->rate.len = 4;
-		msg->rate.data = rxbuf->phy_plcp_signal/5;
-
-		msg->istx.did = WLANSNIFFFRM_istx;
-		msg->istx.status = WLANITEM_STATUS_data_ok;
-		msg->istx.len = 4;
-		msg->istx.data = 0;	/* tx=0: it's not a tx packet */
-
-		skb_len -= sizeof(*msg);
-
-		msg->frmlen.did = WLANSNIFFFRM_signal;
-		msg->frmlen.status = WLANITEM_STATUS_data_ok;
-		msg->frmlen.len = 4;
-		msg->frmlen.data = skb_len;
-	}
-
-	memcpy(datap, ((unsigned char*)rxbuf)+payload_offset, skb_len);
-
-	skb->dev = priv->netdev;
-	skb->dev->last_rx = jiffies;
-
-	skb->mac.raw = skb->data;
-	skb->ip_summed = CHECKSUM_NONE;
-	skb->pkt_type = PACKET_OTHERHOST;
-	skb->protocol = htons(ETH_P_80211_RAW);
-	netif_rx(skb);
-
-	priv->stats.rx_packets++;
-	priv->stats.rx_bytes += skb->len;
-end:
-	FN_EXIT0;
-}
-
-
-/***********************************************************************
-*/
-/*
- * Calculate level like the feb 2003 windows driver seems to do
- */
-u8
-acx_signal_to_winlevel(u8 rawlevel)
-{
-	/* u8 winlevel = (u8) (0.5 + 0.625 * rawlevel); */
-	u8 winlevel = ((4 + (rawlevel * 5)) / 8);
-
-	if (winlevel > 100)
-		winlevel = 100;
-	return winlevel;
-}
-
-u8
-acx_signal_determine_quality(u8 signal, u8 noise)
-{
-	int qual;
-
-	qual = (((signal - 30) * 100 / 70) + (100 - noise * 4)) / 2;
-
-	if (qual > 100)
-		return 100;
-	if (qual < 0)
-		return 0;
-	return qual;
-}
-
-
-/***************************************************************
-** acx_l_process_rxbuf
-**
-** NB: used by USB code also
-*/
-void
-acx_l_process_rxbuf(wlandevice_t *priv, rxbuffer_t *rxbuf)
-{
-	struct wlan_hdr *hdr;
-	unsigned int buf_len;
-	unsigned int qual;
-	u16 fc;
-
-	hdr = acx_get_wlan_hdr(priv, rxbuf);
-	/* length of frame from control field to last byte of FCS */
-	buf_len = RXBUF_BYTES_RCVD(rxbuf);
-	fc = le16_to_cpu(hdr->fc);
-
-	if ( ((WF_FC_FSTYPE & fc) != WF_FSTYPE_BEACON)
-	  || (acx_debug & L_XFER_BEACON)
-	) {
-		acxlog(L_XFER|L_DATA, "rx: %s "
-			"time %u len %u signal %u SNR %u macstat %02X "
-			"phystat %02X phyrate %u status %u\n",
-			acx_get_packet_type_string(fc),
-			le32_to_cpu(rxbuf->time),
-			buf_len,
-			acx_signal_to_winlevel(rxbuf->phy_level),
-			acx_signal_to_winlevel(rxbuf->phy_snr),
-			rxbuf->mac_status,
-			rxbuf->phy_stat_baseband,
-			rxbuf->phy_plcp_signal,
-			priv->status);
-	}
-
-	if (unlikely(acx_debug & L_DATA)) {
-		printk("rx: 802.11 buf[%u]: ", buf_len);
-		acx_dump_bytes(hdr, buf_len);
-	}
 
-	/* FIXME: should check for Rx errors (rxbuf->mac_status?
-	 * discard broken packets - but NOT for monitor!)
-	 * and update Rx packet statistics here */
-
-	if (unlikely(priv->mode == ACX_MODE_MONITOR)) {
-		acx_l_rxmonitor(priv, rxbuf);
-	} else if (likely(buf_len >= WLAN_HDR_A3_LEN)) {
-		acx_l_rx_ieee802_11_frame(priv, rxbuf);
-	} else {
-		acxlog(L_DEBUG | L_XFER | L_DATA,
-		       "rx: NOT receiving packet (%s): "
-		       "size too small (%u)\n",
-		       acx_get_packet_type_string(fc),
-		       buf_len);
-	}
-
-	/* Now check Rx quality level, AFTER processing packet.
-	 * I tried to figure out how to map these levels to dBm
-	 * values, but for the life of me I really didn't
-	 * manage to get it. Either these values are not meant to
-	 * be expressed in dBm, or it's some pretty complicated
-	 * calculation. */
-
-#if FROM_SCAN_SOURCE_ONLY
-	/* only consider packets originating from the MAC
-	 * address of the device that's managing our BSSID.
-	 * Disable it for now, since it removes information (levels
-	 * from different peers) and slows the Rx path. */
-	if (priv->ap_client
-	 && mac_is_equal(hdr->a2, priv->ap_client->address)) {
-#endif
-		priv->wstats.qual.level = acx_signal_to_winlevel(rxbuf->phy_level);
-		priv->wstats.qual.noise = acx_signal_to_winlevel(rxbuf->phy_snr);
-#ifndef OLD_QUALITY
-		qual = acx_signal_determine_quality(priv->wstats.qual.level,
-				priv->wstats.qual.noise);
-#else
-		qual = (priv->wstats.qual.noise <= 100) ?
-				100 - priv->wstats.qual.noise : 0;
-#endif
-		priv->wstats.qual.qual = qual;
-		priv->wstats.qual.updated = 7; /* all 3 indicators updated */
-#if FROM_SCAN_SOURCE_ONLY
-	}
-#endif
-}
+/* Probably a number of acx's itermediate buffers for USB transfers,
+** not to be confused with number of descriptors in tx/rx rings
+** (which are not directly accessible to host in USB devices) */
+#define USB_RXBUFCNT 10
+#define USB_TXBUFCNT 10
 
 
 /*----------------------------------------------------------------
 * acx100_s_init_memory_pools
-*
-* Comment:
-*	FIXME: This function still needs a cleanup
 *----------------------------------------------------------------*/
+void BUG_acx100_ie_memconfigoption_must_be_24_bytes_in_length(void);
+
 static int
 acx100_s_init_memory_pools(wlandevice_t *priv, const acx_ie_memmap_t *mmt)
 {
 	acx100_ie_memblocksize_t MemoryBlockSize;
 	acx100_ie_memconfigoption_t MemoryConfigOption;
-	u32 TotalMemoryBlocks;
+	int TotalMemoryBlocks;
+	int RxBlockNum;
+	int TotalRxBlockSize;
+	int TxBlockNum;
+	int TotalTxBlockSize;
 
-	u32 RxBlockNum;
-	u32 TotalRxBlockSize;
-	u32 TxBlockNum;
-	u32 TotalTxBlockSize;
+	if (sizeof(acx100_ie_memconfigoption_t) != 24)
+		BUG_acx100_ie_memconfigoption_must_be_24_bytes_in_length();
 
 	FN_ENTER;
 
@@ -643,7 +106,6 @@ acx100_s_init_memory_pools(wlandevice_t 
 
 	/* Then we alert the card to our decision of block size */
 	if (OK != acx_s_configure(priv, &MemoryBlockSize, ACX100_IE_BLOCK_SIZE)) {
-		printk("acx: MemoryBlockSizeWrite FAILED\n");
 		goto bad;
 	}
 
@@ -655,21 +117,25 @@ acx100_s_init_memory_pools(wlandevice_t 
 	acxlog(L_DEBUG, "TotalMemoryBlocks=%u (%u bytes)\n",
 		TotalMemoryBlocks, TotalMemoryBlocks*priv->memblocksize);
 
-	/* This one I have no idea on */
-	/* block-transfer=0x20000
-	 * indirect descriptors=0x10000
-	 */
-#ifdef ACX_USB
-	MemoryConfigOption.DMA_config = cpu_to_le32(0x20000);
-#else
-	MemoryConfigOption.DMA_config = cpu_to_le32(0x30000);
-
-	/* Declare start of the Rx host pool */
-//Should be of acx_ptr type, no?
-	MemoryConfigOption.pRxHostDesc = cpu_to_le32((u32)(long)priv->RxHostDescPoolStart);
-	acxlog(L_DEBUG, "pRxHostDesc 0x%08X, RxHostDescPoolStart 0x%p\n",
-		MemoryConfigOption.pRxHostDesc, priv->RxHostDescPoolStart);
-#endif
+	/* MemoryConfigOption.DMA_config bitmask:
+			// access to ACX memory is to be done:
+	0x00080000	//  using PCI conf space?!
+	0x00040000	//  using IO instructions?
+	0x00000000	//  using memory access instructions
+	0x00020000	// use local memory block linked list (else what?)
+	0x00010000	// use host indirect descriptors (else host must access ACX memory?)
+	*/
+	if (IS_PCI(priv)) {
+		MemoryConfigOption.DMA_config = cpu_to_le32(0x30000);
+		/* Declare start of the Rx host pool */
+//// this one comes from PCI hostdesc init:
+		MemoryConfigOption.pRxHostDesc = ptr2acx(priv->RxHostDescPoolStart);
+		acxlog(L_DEBUG, "pRxHostDesc 0x%08X, RxHostDescPoolStart 0x%p\n",
+				acx2cpu(MemoryConfigOption.pRxHostDesc),
+				priv->RxHostDescPoolStart);
+	} else {
+		MemoryConfigOption.DMA_config = cpu_to_le32(0x20000);
+	}
 
 	/* 50% of the allotment of memory blocks go to tx descriptors */
 	TxBlockNum = TotalMemoryBlocks / 2;
@@ -700,13 +166,11 @@ acx100_s_init_memory_pools(wlandevice_t 
 
 	/* alert the device to our decision */
 	if (OK != acx_s_configure(priv, &MemoryConfigOption, ACX1xx_IE_MEMORY_CONFIG_OPTIONS)) {
-		printk("acx: configure memory config options FAILED\n");
 		goto bad;
 	}
 
 	/* and tell the device to kick it into gear */
 	if (OK != acx_s_issue_cmd(priv, ACX100_CMD_INIT_MEMORY, NULL, 0)) {
-		printk("acx: init memory FAILED\n");
 		goto bad;
 	}
 	FN_EXIT1(OK);
@@ -723,116 +187,90 @@ bad:
 * Note that this fn messes up heavily with hardware, but we cannot
 * lock it (we need to sleep). Not a problem since IRQs can't happen
 *----------------------------------------------------------------*/
-void BUG_acx100_ie_queueconfig_t_must_be_0x20_bytes(void);
+void BUG_acx100_ie_queueconfig_t_must_be_0x20_bytes_in_length(void);
 
 int
 acx100_s_create_dma_regions(wlandevice_t *priv)
 {
-	acx100_ie_queueconfig_t qcfg;
-	acx_ie_memmap_t MemMap;
+	acx100_ie_queueconfig_t queueconf;
+	acx_ie_memmap_t memmap;
 	int res = NOT_OK;
-#ifdef ACX_PCI
-	struct TIWLAN_DC *pDc;
-	pDc = &priv->dc;
-	pDc->priv = priv;
-#endif
+	u32 tx_queue_start, rx_queue_start;
 
 	FN_ENTER;
 
 	/* read out the acx100 physical start address for the queues */
-	if (OK != acx_s_interrogate(priv, &MemMap, ACX1xx_IE_MEMORY_MAP)) {
-		printk("acx: ctlMemoryMapRead FAILED\n");
+	if (OK != acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
 		goto fail;
 	}
 
 	/* # of items in Rx and Tx queues */
-	priv->TxQueueCnt = TXBUFFERCOUNT_ACX100;
-	priv->RxQueueCnt = RXBUFFERCOUNT_ACX100;
+	priv->TxQueueCnt = TXBUFCNT_ACX100;
+	priv->RxQueueCnt = RXBUFCNT_ACX100;
 
-#ifdef ACX_USB
-	qcfg.NumTxDesc = TXBUFFERCOUNT_USB;
-	qcfg.NumRxDesc = RXBUFFERCOUNT_USB;
-#endif
+	tx_queue_start = le32_to_cpu(memmap.QueueStart);
+	rx_queue_start = tx_queue_start + TXBUFCNT_ACX100 * sizeof(txdesc_t);
 
-#ifdef ACX_PCI
-	/* calculate size of queues */
-	qcfg.AreaSize = cpu_to_le32(
-			(sizeof(struct txdesc) * TXBUFFERCOUNT_ACX100 +
-			 sizeof(struct rxdesc) * RXBUFFERCOUNT_ACX100 + 8)
-			);
-#endif
-	qcfg.NumTxQueues = 1;  /* number of tx queues */
+	acxlog(L_DEBUG, "initializing Queue Indicator\n");
 
-	/* sets the beginning of the tx descriptor queue */
-	qcfg.TxQueueStart = MemMap.QueueStart;
-	qcfg.TxQueuePri = 0;
-#ifdef ACX_PCI
-	pDc->ui32ACXTxQueueStart = le32_to_cpu(MemMap.QueueStart);
+	memset(&queueconf, 0, sizeof(queueconf));
 
-	/* sets the beginning of the rx descriptor queue, after the tx descrs */
-	pDc->ui32ACXRxQueueStart = pDc->ui32ACXTxQueueStart +
-				priv->TxQueueCnt * sizeof(txdesc_t);
-	qcfg.RxQueueStart = cpu_to_le32(pDc->ui32ACXRxQueueStart);
-#endif
-	qcfg.QueueOptions = 1;		/* auto reset descriptor */
+	/* Not needed for PCI, so we can avoid setting them altogether */
+	if (IS_USB(priv)) {
+		queueconf.NumTxDesc = USB_TXBUFCNT;
+		queueconf.NumRxDesc = USB_RXBUFCNT;
+	}
 
-#ifdef ACX_PCI
+	/* calculate size of queues */
+	queueconf.AreaSize = cpu_to_le32(
+			TXBUFCNT_ACX100 * sizeof(txdesc_t) +
+			RXBUFCNT_ACX100 * sizeof(rxdesc_t) + 8
+			);
+	queueconf.NumTxQueues = 1;  /* number of tx queues */
+	/* sets the beginning of the tx descriptor queue */
+	queueconf.TxQueueStart = memmap.QueueStart;
+	/* done by memset: queueconf.TxQueuePri = 0; */
+	queueconf.RxQueueStart = cpu_to_le32(rx_queue_start);
+	queueconf.QueueOptions = 1;		/* auto reset descriptor */
 	/* sets the end of the rx descriptor queue */
-	qcfg.QueueEnd = cpu_to_le32(pDc->ui32ACXRxQueueStart +
-				priv->RxQueueCnt * sizeof(struct rxdesc));
-#endif
-
+	queueconf.QueueEnd = cpu_to_le32(
+			rx_queue_start + RXBUFCNT_ACX100 * sizeof(rxdesc_t)
+			);
 	/* sets the beginning of the next queue */
-	qcfg.HostQueueEnd = cpu_to_le32(le32_to_cpu(qcfg.QueueEnd) + 8);
-
-	acxlog(L_DEBUG, "initializing Queue Indicator\n");
-
-	if (sizeof(qcfg) != 0x20)
-		BUG_acx100_ie_queueconfig_t_must_be_0x20_bytes();
-	if (OK != acx_s_configure(priv, &qcfg, ACX1xx_IE_QUEUE_CONFIG)) {
-		printk("acx: ctlQueueConfigurationWrite FAILED\n");
+	queueconf.HostQueueEnd = cpu_to_le32(le32_to_cpu(queueconf.QueueEnd) + 8);
+	if (sizeof(queueconf) != 0x20)
+		BUG_acx100_ie_queueconfig_t_must_be_0x20_bytes_in_length();
+	if (OK != acx_s_configure(priv, &queueconf, ACX1xx_IE_QUEUE_CONFIG)) {
 		goto fail;
 	}
 
-#ifdef ACX_PCI
-	if (OK != acx_s_create_tx_host_desc_queue(pDc)) {
-		printk("acx: create_tx_host_desc_queue FAILED\n");
-		goto fail;
-	}
-	if (OK != acx_s_create_rx_host_desc_queue(pDc)) {
-		printk("acx: create_rx_host_desc_queue FAILED\n");
-		goto fail;
+	if (IS_PCI(priv)) {
+	/* sets the beginning of the rx descriptor queue, after the tx descrs */
+		if (OK != acx_s_create_hostdesc_queues(priv))
+			goto fail;
+		acx_create_desc_queues(priv, tx_queue_start, rx_queue_start);
 	}
 
-	pDc->pTxDescQPool = NULL;
-	pDc->pRxDescQPool = NULL;
-
-	acx_s_create_tx_desc_queue(pDc);
-	acx_create_rx_desc_queue(pDc);
-#endif
-	if (OK != acx_s_interrogate(priv, &MemMap, ACX1xx_IE_MEMORY_MAP)) {
-		printk("acx: FAILED to read memory map\n");
+	if (OK != acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
 		goto fail;
 	}
 
-	/* FIXME: huh, why call ACX1xx_IE_MEMORY_MAP twice in the USB case?
-	   Is this needed?? */
-#ifdef ACX_USB
-	if (OK != acx_s_configure(priv, &MemMap, ACX1xx_IE_MEMORY_MAP)) {
-		printk("acx: FAILED to write memory map\n");
+/* [20050901] seems to be bogus. remove if no one complains */
+#if 0 /* #ifdef ACX_USB */
+	if (OK != acx_s_configure(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
 		goto fail;
 	}
 #endif
 
-	MemMap.PoolStart = cpu_to_le32((le32_to_cpu(MemMap.QueueEnd) + 0x1f + 4) & ~0x1f);
+	memmap.PoolStart = cpu_to_le32(
+			(le32_to_cpu(memmap.QueueEnd) + 4 + 0x1f) & ~0x1f
+			);
 
-	if (OK != acx_s_configure(priv, &MemMap, ACX1xx_IE_MEMORY_MAP)) {
-		printk("acx: ctlMemoryMapWrite FAILED\n");
+	if (OK != acx_s_configure(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
 		goto fail;
 	}
 
-	if (OK != acx100_s_init_memory_pools(priv, &MemMap)) {
-		printk("acx: acx100_init_memory_pools FAILED\n");
+	if (OK != acx100_s_init_memory_pools(priv, &memmap)) {
 		goto fail;
 	}
 
@@ -841,9 +279,8 @@ acx100_s_create_dma_regions(wlandevice_t
 
 fail:
 	acx_s_msleep(1000); /* ? */
-#ifdef ACX_PCI
-	acx_free_desc_queues(pDc);
-#endif
+	if (IS_PCI(priv))
+		acx_free_desc_queues(priv);
 end:
 	FN_EXIT1(res);
 	return res;
@@ -861,29 +298,21 @@ end:
 int
 acx111_s_create_dma_regions(wlandevice_t *priv)
 {
-#ifdef ACX_PCI
 	struct acx111_ie_memoryconfig memconf;
 	struct acx111_ie_queueconfig queueconf;
-	struct TIWLAN_DC *pDc;
+	u32 tx_queue_start, rx_queue_start;
 
 	FN_ENTER;
 
-	pDc = &priv->dc;
-	pDc->priv = priv;
-
 	/* Calculate memory positions and queue sizes */
 
-	priv->TxQueueCnt = TXBUFFERCOUNT_ACX111;
-	priv->RxQueueCnt = RXBUFFERCOUNT_ACX111;
+	priv->TxQueueCnt = TXBUFCNT_ACX111;
+	priv->RxQueueCnt = RXBUFCNT_ACX111;
 
 	/* Set up our host descriptor pool + data pool */
-	if (OK != acx_s_create_tx_host_desc_queue(pDc)) {
-		printk("acx: create_tx_host_desc_queue FAILED\n");
-		goto fail;
-	}
-	if (OK != acx_s_create_rx_host_desc_queue(pDc)) {
-		printk("acx: create_rx_host_desc_queue FAILED\n");
-		goto fail;
+	if (IS_PCI(priv)) {
+		if (OK != acx_s_create_hostdesc_queues(priv))
+			goto fail;
 	}
 
 	memset(&memconf, 0, sizeof(memconf));
@@ -907,12 +336,14 @@ acx111_s_create_dma_regions(wlandevice_t
 	 * (specified in units of 5%) */
 	memconf.fragmentation = ACX111_PERCENT(75);
 	/* Rx descriptor queue config */
-	memconf.rx_queue1_count_descs = RXBUFFERCOUNT_ACX111;
+	memconf.rx_queue1_count_descs = RXBUFCNT_ACX111;
 	memconf.rx_queue1_type = 7; /* must be set to 7 */
 	/* done by memset: memconf.rx_queue1_prio = 0; low prio */
-	memconf.rx_queue1_host_rx_start = cpu_to_le32(pDc->RxHostDescQPoolPhyAddr);
+//// this one comes from PCI hostdesc init. BUG! we need aligned one!
+///	memconf.rx_queue1_host_rx_start = cpu_to_le32(priv->RxHostDescQPoolPhyAddr);
+	memconf.rx_queue1_host_rx_start = cpu_to_le32(priv->RxHostDescPoolStart);
 	/* Tx descriptor queue config */
-	memconf.tx_queue1_count_descs = TXBUFFERCOUNT_ACX111;
+	memconf.tx_queue1_count_descs = TXBUFCNT_ACX111;
 	/* done by memset: memconf.tx_queue1_attributes = 0; lowest priority */
 
 	/* NB1: this looks wrong: (memconf,ACX1xx_IE_QUEUE_CONFIG),
@@ -920,491 +351,121 @@ acx111_s_create_dma_regions(wlandevice_t
 	** But it is actually correct wrt IE numbers.
 	** NB2: sizeof(memconf) == 28 == 0x1c but configure(ACX1xx_IE_QUEUE_CONFIG)
 	** writes 0x20 bytes (because same IE for acx100 uses struct acx100_ie_queueconfig
-	** wich is 4 bytes larger. what a mess...) */
+	** which is 4 bytes larger. what a mess. TODO: clean it up) */
 	if (OK != acx_s_configure(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG)) {
-		printk("acx: setting acx111_ie_memoryconfig FAILED\n");
 		goto fail;
 	}
 
-	/* read out queueconf */
-	if (OK != acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS)) {
-		printk("acx: read queuehead FAILED\n");
-	}
+	acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
 
-	pDc->ui32ACXRxQueueStart = le32_to_cpu(queueconf.rx1_queue_address);
-	pDc->ui32ACXTxQueueStart = le32_to_cpu(queueconf.tx1_queue_address);
+	tx_queue_start = le32_to_cpu(queueconf.tx1_queue_address);
+	rx_queue_start = le32_to_cpu(queueconf.rx1_queue_address);
 
 	acxlog(L_INIT, "dump queue head (from card):\n"
 		       "len: %u\n"
 		       "tx_memory_block_address: %X\n"
 		       "rx_memory_block_address: %X\n"
-		       "rx1_queue address: %X\n"
-		       "tx1_queue address: %X\n",
+		       "tx1_queue address: %X\n"
+		       "rx1_queue address: %X\n",
 		       le16_to_cpu(queueconf.len),
 		       le32_to_cpu(queueconf.tx_memory_block_address),
 		       le32_to_cpu(queueconf.rx_memory_block_address),
-		       pDc->ui32ACXRxQueueStart,
-		       pDc->ui32ACXTxQueueStart);
-	pDc->pRxDescQPool = (struct rxdesc *) ((u8 *)priv->iobase2 +
-				     pDc->ui32ACXRxQueueStart);
-
-	pDc->pTxDescQPool = (struct txdesc *) ((u8 *)priv->iobase2 +
-				     pDc->ui32ACXTxQueueStart);
-	acx_s_create_tx_desc_queue(pDc);
-	acx_create_rx_desc_queue(pDc);
+		       tx_queue_start,
+		       rx_queue_start);
+	if (IS_PCI(priv))
+		acx_create_desc_queues(priv, tx_queue_start, rx_queue_start);
 
 	FN_EXIT1(OK);
 	return OK;
-
 fail:
-	acx_free_desc_queues(pDc);
+	if (IS_PCI(priv))
+		acx_free_desc_queues(priv);
 
 	FN_EXIT1(NOT_OK);
-#endif /* CONFIG_TIACX_PCI */
 	return NOT_OK;
 }
 
 
-/***************************************************************
+#ifdef CONFIG_PROC_FS
+/***********************************************************************
+** /proc files
+*/
+/***********************************************************************
+** acx_l_proc_output
+** Generate content for our /proc entry
+**
+** Arguments:
+**	buf is a pointer to write output to
+**	priv is the usual pointer to our private struct wlandevice
+** Returns:
+**	number of bytes actually written to buf
+** Side effects:
+**	none
 */
-void
-acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr)
+static int
+acx_l_proc_output(char *buf, wlandevice_t *priv)
 {
-	acxlog(L_ASSOC, "acx: unknown EID %d in mgmt frame at offset %d\n",
-				ie_ptr->eid, (int) ((u8*)ie_ptr - (u8*)hdr));
-	if (acx_debug & (L_DATA|L_ASSOC)) {
-		printk("frame (%s): ",
-			acx_get_packet_type_string(le16_to_cpu(hdr->fc)));
-		acx_dump_bytes(hdr, len);
-	}
-}
+	char *p = buf;
+	int i;
 
+	FN_ENTER;
 
-/***************************************************************
-*/
-#if ACX_DEBUG
-void
-acx_dump_bytes(const void *data, int num)
-{
-	const u8* ptr = (const u8*)data;
+	p += sprintf(p,
+		"acx driver version:\t\t" WLAN_RELEASE "\n"
+		"Wireless extension version:\t" STRING(WIRELESS_EXT) "\n"
+		"chip name:\t\t\t%s (0x%08X)\n"
+		"radio type:\t\t\t0x%02X\n"
+		/* TODO: add radio type string from acx_display_hardware_details */
+		"form factor:\t\t\t0x%02X\n"
+		/* TODO: add form factor string from acx_display_hardware_details */
+		"EEPROM version:\t\t\t0x%02X\n"
+		"firmware version:\t\t%s (0x%08X)\n",
+		priv->chip_name, priv->firmware_id,
+		priv->radio_type,
+		priv->form_factor,
+		priv->eeprom_version,
+		priv->firmware_version, priv->firmware_numver);
 
-	if (num <= 0) {
-		printk("\n");
-		return;
+	for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
+		struct client *bss = &priv->sta_list[i];
+		if (!bss->used) continue;
+		p += sprintf(p, "BSS %u BSSID "MACSTR" ESSID %s channel %u "
+			"Cap 0x%X SIR %u SNR %u\n",
+			i, MAC(bss->bssid), (char*)bss->essid, bss->channel,
+			bss->cap_info, bss->sir, bss->snr);
 	}
+	p += sprintf(p, "status:\t\t\t%u (%s)\n",
+			priv->status, acx_get_status_name(priv->status));
+	/* TODO: add more interesting stuff (essid, ...) here */
 
-	while (num >= 16) {
-		printk( "%02X %02X %02X %02X %02X %02X %02X %02X "
-			"%02X %02X %02X %02X %02X %02X %02X %02X\n",
-			ptr[0], ptr[1], ptr[2], ptr[3],
-			ptr[4], ptr[5], ptr[6], ptr[7],
-			ptr[8], ptr[9], ptr[10], ptr[11],
-			ptr[12], ptr[13], ptr[14], ptr[15]);
-		num -= 16;
-		ptr += 16;
-	}
-	if (num > 0) {
-		while (--num > 0)
-			printk("%02X ", *ptr++);
-		printk("%02X\n", *ptr);
-	}
+	FN_EXIT1(p - buf);
+	return p - buf;
 }
-#endif
 
 
-/*----------------------------------------------------------------
-* acx_i_start_xmit
-*
-* Called by network core. Can be called outside of process context.
-*----------------------------------------------------------------*/
-int
-acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev)
+/***********************************************************************
+*/
+static int
+acx_s_proc_diag_output(char *buf, wlandevice_t *priv)
 {
-	wlandevice_t *priv = acx_netdev_priv(dev);
-	tx_t *tx;
-	void *txbuf;
+	char *p = buf;
+	fw_stats_t *fw_stats;
 	unsigned long flags;
-	int txresult = NOT_OK;
-	int len;
 
 	FN_ENTER;
 
-	if (unlikely(!skb)) {
-		/* indicate success */
-		txresult = OK;
-		goto end_no_unlock;
-	}
-	if (unlikely(!priv)) {
-		goto end_no_unlock;
+	fw_stats = kmalloc(sizeof(fw_stats_t), GFP_KERNEL);
+	if (!fw_stats) {
+		FN_EXIT1(0);
+		return 0;
 	}
+	memset(fw_stats, 0, sizeof(fw_stats_t));
 
-/* Example from tg3.c. Do we need to do this similarly?
-	local_irq_save(flags);
-	if (!spin_trylock(&tp->lock)) {
-		local_irq_restore(flags);
-		return NETDEV_TX_LOCKED;
-	}
-	...
-	mmiowb();
-	spin_unlock_irqrestore(&tp->lock, flags);
-*/
 	acx_lock(priv, flags);
 
-	if (unlikely(!(priv->dev_state_mask & ACX_STATE_IFACE_UP))) {
-		goto end;
-	}
-	if (unlikely(priv->mode == ACX_MODE_OFF)) {
-		goto end;
-	}
-	if (unlikely(acx_queue_stopped(dev))) {
-		acxlog(L_DEBUG, "%s: called when queue stopped\n", __func__);
-		goto end;
-	}
-	if (unlikely(ACX_STATUS_4_ASSOCIATED != priv->status)) {
-		acxlog(L_XFER, "trying to xmit, but not associated yet: "
-			"aborting...\n");
-		/* silently drop the packet, since we're not connected yet */
-		txresult = OK;
-		/* ...but indicate an error nevertheless */
-		priv->stats.tx_errors++;
-		goto end;
-	}
-
-#if 0
-	/* we're going to transmit now, so stop another packet from entering.
-	 * FIXME: most likely we shouldn't do it like that, but instead:
-	 * stop the queue during card init, then wake the queue once
-	 * we're associated to the network, then stop the queue whenever
-	 * we don't have any free Tx buffers left, and wake it again once a
-	 * Tx buffer becomes free again. And of course also stop the
-	 * queue once we lose association to the network (since it
-	 * doesn't make sense to allow more user packets if we can't
-	 * forward them to a network).
-	 * FIXME: Hmm, seems this is all wrong. We SHOULD leave the
-	 * queue open from the beginning (as long as we're not full,
-	 * and also even before we're even associated),
-	 * otherwise we'll get NETDEV WATCHDOG transmit timeouts... */
-	acx_stop_queue(dev, "during tx");
-#endif
-	tx = acx_l_alloc_tx(priv);
-	if (unlikely(!tx)) {
-		printk("%s: start_xmit: txdesc ring is full, dropping tx\n",
-			dev->name);
-		txresult = NOT_OK;
-		goto end;
-	}
-
-	txbuf = acx_l_get_txbuf(tx);
-	if (!txbuf) {
-		/* Card was removed */
-		txresult = NOT_OK;
-		goto end;
-	}
-	len = acx_l_ether_to_txbuf(priv, txbuf, skb);
-	if (len < 0) {
-		/* Error in packet conversion */
-		txresult = NOT_OK;
-		goto end;
-	}
-	acx_l_dma_tx_data(priv, tx, len);
-	dev->trans_start = jiffies;
-
-	txresult = OK;
-	priv->stats.tx_packets++;
-	priv->stats.tx_bytes += skb->len;
-
-end:
-	acx_unlock(priv, flags);
-
-end_no_unlock:
-	if ((txresult == OK) && skb)
-		dev_kfree_skb_any(skb);
-
-	FN_EXIT1(txresult);
-	return txresult;
-}
-
-
-/***********************************************************************
-** Interrogate/configure commands
-*/
-static const u16
-CtlLength[] = {
-	0,
-	ACX100_IE_ACX_TIMER_LEN,
-	ACX1xx_IE_POWER_MGMT_LEN,
-	ACX1xx_IE_QUEUE_CONFIG_LEN,
-	ACX100_IE_BLOCK_SIZE_LEN,
-	ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN,
-	ACX1xx_IE_RATE_FALLBACK_LEN,
-	ACX100_IE_WEP_OPTIONS_LEN,
-	ACX1xx_IE_MEMORY_MAP_LEN, /*	ACX1xx_IE_SSID_LEN, */
-	0,
-	ACX1xx_IE_ASSOC_ID_LEN,
-	0,
-	ACX1xx_IE_CONFIG_OPTIONS_LEN,
-	ACX1xx_IE_FWREV_LEN,
-	ACX1xx_IE_FCS_ERROR_COUNT_LEN,
-	ACX1xx_IE_MEDIUM_USAGE_LEN,
-	ACX1xx_IE_RXCONFIG_LEN,
-	0,
-	0,
-	ACX1xx_IE_FIRMWARE_STATISTICS_LEN,
-	0,
-	ACX1xx_IE_FEATURE_CONFIG_LEN,
-	ACX111_IE_KEY_CHOOSE_LEN,
-};
-
-static const u16
-CtlLengthDot11[] = {
-	0,
-	ACX1xx_IE_DOT11_STATION_ID_LEN,
-	0,
-	ACX100_IE_DOT11_BEACON_PERIOD_LEN,
-	ACX1xx_IE_DOT11_DTIM_PERIOD_LEN,
-	ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN,
-	ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN,
-	ACX100_IE_DOT11_WEP_DEFAULT_KEY_LEN,
-	ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN,
-	0,
-	ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN,
-	ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN,
-	0,
-	ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN,
-	ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN,
-	ACX100_IE_DOT11_ED_THRESHOLD_LEN,
-	ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN,
-	0,
-	0,
-	0,
-};
-
-
-#if !ACX_DEBUG
-int
-acx_s_configure(wlandevice_t *priv, void *pdr, int type)
-{
-#else
-int
-acx_s_configure_debug(wlandevice_t *priv, void *pdr, int type, const char* typestr)
-{
-#endif
-	u16 len;
-
-	/* TODO implement and check other acx111 commands */
-	if ((priv->chip_type == CHIPTYPE_ACX111)
-	 && (type == ACX1xx_IE_DOT11_CURRENT_ANTENNA)) {
-		/* acx111 has differing struct size */
-		acxlog(L_CTL, "Configure Command %s is not supported "
-			"under acx111 (yet)\n", typestr);
-		return NOT_OK;
-	}
-
-	if (type < 0x1000)
-		len = CtlLength[type];
-	else
-		len = CtlLengthDot11[type-0x1000];
-
-	acxlog(L_XFER, "configure(type:%s,len:%u)\n", typestr, len);
-	if (unlikely(!len)) {
-		acxlog(L_DEBUG, "zero-length type %s?!\n", typestr);
-	}
-
-	((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
-	((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
-	return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIGURE, pdr, len + 4);
-}
-
-#if !ACX_DEBUG
-int
-acx_s_interrogate(wlandevice_t *priv, void *pdr, int type)
-{
-#else
-int
-acx_s_interrogate_debug(wlandevice_t *priv, void *pdr, int type,
-		const char* typestr)
-{
-#endif
-	u16 len;
-
-	if (type < 0x1000)
-		len = CtlLength[type];
-	else
-		len = CtlLengthDot11[type-0x1000];
-
-	((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
-	((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
-
-	acxlog(L_CTL, "interrogate(type:%s,len:%u)\n", typestr, len);
-
-	return acx_s_issue_cmd(priv, ACX1xx_CMD_INTERROGATE, pdr, len + 4);
-}
-
-
-/***********************************************************************
-** acx_l_update_ratevector
-**
-** Updates priv->rate_supported[_len] according to rate_{basic,oper}
-*/
-const u8
-bitpos2ratebyte[] = {
-	DOT11RATEBYTE_1,
-	DOT11RATEBYTE_2,
-	DOT11RATEBYTE_5_5,
-	DOT11RATEBYTE_6_G,
-	DOT11RATEBYTE_9_G,
-	DOT11RATEBYTE_11,
-	DOT11RATEBYTE_12_G,
-	DOT11RATEBYTE_18_G,
-	DOT11RATEBYTE_22,
-	DOT11RATEBYTE_24_G,
-	DOT11RATEBYTE_36_G,
-	DOT11RATEBYTE_48_G,
-	DOT11RATEBYTE_54_G,
-};
-
-void
-acx_l_update_ratevector(wlandevice_t *priv)
-{
-	u16 bcfg = priv->rate_basic;
-	u16 ocfg = priv->rate_oper;
-	u8 *supp = priv->rate_supported;
-	const u8 *dot11 = bitpos2ratebyte;
-
-	FN_ENTER;
-
-	while (ocfg) {
-		if (ocfg & 1) {
-			*supp = *dot11;
-			if (bcfg & 1) {
-				*supp |= 0x80;
-			}
-			supp++;
-		}
-		dot11++;
-		ocfg >>= 1;
-		bcfg >>= 1;
-	}
-	priv->rate_supported_len = supp - priv->rate_supported;
-	if (acx_debug & L_ASSOC) {
-		printk("new ratevector: ");
-		acx_dump_bytes(priv->rate_supported, priv->rate_supported_len);
-	}
-	FN_EXIT0;
-}
-
-
-#ifdef CONFIG_PROC_FS
-/***********************************************************************
-** /proc files
-*/
-/***********************************************************************
-** acx_l_proc_output
-** Generate content for our /proc entry
-**
-** Arguments:
-**	buf is a pointer to write output to
-**	priv is the usual pointer to our private struct wlandevice
-** Returns:
-**	number of bytes actually written to buf
-** Side effects:
-**	none
-*/
-static int
-acx_l_proc_output(char *buf, wlandevice_t *priv)
-{
-	char *p = buf;
-	int i;
-
-	FN_ENTER;
-
-	p += sprintf(p,
-		"acx driver version:\t\t" WLAN_RELEASE "\n"
-		"Wireless extension version:\t" STRING(WIRELESS_EXT) "\n"
-		"chip name:\t\t\t%s (0x%08X)\n"
-		"radio type:\t\t\t0x%02X\n"
-		/* TODO: add radio type string from acx_display_hardware_details */
-		"form factor:\t\t\t0x%02X\n"
-		/* TODO: add form factor string from acx_display_hardware_details */
-		"EEPROM version:\t\t\t0x%02X\n"
-		"firmware version:\t\t%s (0x%08X)\n",
-		priv->chip_name, priv->firmware_id,
-		priv->radio_type,
-		priv->form_factor,
-		priv->eeprom_version,
-		priv->firmware_version, priv->firmware_numver);
-
-	for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-		struct client *bss = &priv->sta_list[i];
-		if (!bss->used) continue;
-		p += sprintf(p, "BSS %u BSSID "MACSTR" ESSID %s channel %u "
-			"Cap 0x%X SIR %u SNR %u\n",
-			i, MAC(bss->bssid), (char*)bss->essid, bss->channel,
-			bss->cap_info, bss->sir, bss->snr);
-	}
-	p += sprintf(p, "status:\t\t\t%u (%s)\n",
-			priv->status, acx_get_status_name(priv->status));
-	/* TODO: add more interesting stuff (essid, ...) here */
-
-	FN_EXIT1(p - buf);
-	return p - buf;
-}
-
-
-/***********************************************************************
-*/
-static int
-acx_s_proc_diag_output(char *buf, wlandevice_t *priv)
-{
-	char *p = buf;
-	fw_stats_t *fw_stats;
-	unsigned long flags;
-
-	FN_ENTER;
-
-	fw_stats = kmalloc(sizeof(fw_stats_t), GFP_KERNEL);
-	if (!fw_stats) {
-		FN_EXIT1(0);
-		return 0;
-	}
-	memset(fw_stats, 0, sizeof(fw_stats_t));
-
-	acx_lock(priv, flags);
+	if (IS_PCI(priv))
+		p = acxpci_s_proc_diag_output(p, priv);
 
-#ifdef ACX_PCI
-{
-	int i;
-	const char *rtl, *thd, *ttl;
-	const struct rxhostdesc *pRxDesc;
-	txdesc_t *pTxDesc;
-	TIWLAN_DC *pDc = &priv->dc;
-	p += sprintf(p, "** Rx buf **\n");
-	for (i = 0; i < pDc->rx_pool_count; i++) {
-		rtl = (i == pDc->rx_tail) ? " [tail]" : "";
-		pRxDesc = &pDc->pRxHostDescQPool[i];
-		if ((pRxDesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
-		 && (pRxDesc->Status & cpu_to_le32(BIT31)) )
-			p += sprintf(p, "%02u FULL%s\n", i, rtl);
-		else
-			p += sprintf(p, "%02u empty%s\n", i, rtl);
-	}
-	p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", priv->TxQueueFree,
-				acx_queue_stopped(priv->netdev) ? "STOPPED" : "running");
-	pTxDesc = pDc->pTxDescQPool;
-	for (i = 0; i < pDc->tx_pool_count; i++) {
-		thd = (i == pDc->tx_head) ? " [head]" : "";
-		ttl = (i == pDc->tx_tail) ? " [tail]" : "";
-		if (pTxDesc->Ctl_8 & DESC_CTL_ACXDONE)
-			p += sprintf(p, "%02u DONE   (%02X)%s%s\n", i, pTxDesc->Ctl_8, thd, ttl);
-		else
-		if (!(pTxDesc->Ctl_8 & DESC_CTL_HOSTOWN))
-			p += sprintf(p, "%02u TxWait (%02X)%s%s\n", i, pTxDesc->Ctl_8, thd, ttl);
-		else
-			p += sprintf(p, "%02u empty  (%02X)%s%s\n", i, pTxDesc->Ctl_8, thd, ttl);
-		pTxDesc = GET_NEXT_TX_DESC_PTR(pDc, pTxDesc);
-	}
-}
-#endif
 	p += sprintf(p,
 		"\n"
 		"** network status **\n"
@@ -1432,36 +493,13 @@ acx_s_proc_diag_output(char *buf, wlande
 	p += sprintf(p,
 		"\n"
 		"** PHY status **\n"
-		"tx_disabled %d, tx_level_dbm %d, tx_level_val %d, tx_level_auto %d\n"
+		"tx_disabled %d, tx_level_dbm %d\n" /* "tx_level_val %d, tx_level_auto %d\n" */
 		"sensitivity %d, antenna 0x%02X, ed_threshold %d, cca %d, preamble_mode %d\n"
 		"rts_threshold %d, short_retry %d, long_retry %d, msdu_lifetime %d, listen_interval %d, beacon_interval %d\n",
-		priv->tx_disabled, priv->tx_level_dbm, priv->tx_level_val, priv->tx_level_auto,
+		priv->tx_disabled, priv->tx_level_dbm, /* priv->tx_level_val, priv->tx_level_auto, */
 		priv->sensitivity, priv->antenna, priv->ed_threshold, priv->cca, priv->preamble_mode,
 		priv->rts_threshold, priv->short_retry, priv->long_retry, priv->msdu_lifetime, priv->listen_interval, priv->beacon_interval);
 
-#ifdef ACX_PCI
-{
-	TIWLAN_DC *pDc = &priv->dc;
-	p += sprintf(p,
-		"\n"
-		"** TIWLAN_DC **\n"
-		"ui32ACXTxQueueStart %u, ui32ACXRxQueueStart %u\n"
-		"pTxBufferPool %p, TxBufferPoolSize %u, TxBufferPoolPhyAddr %08llx\n"
-		"TxDescrSize %u, pTxDescQPool %p, tx_pool_count %u\n"
-		"pTxHostDescQPool %p, TxHostDescQPoolSize %u, TxHostDescQPoolPhyAddr %08llx\n"
-		"pRxDescQPool %p, rx_pool_count %d\n"
-		"pRxHostDescQPool %p, RxHostDescQPoolSize %u, RxHostDescQPoolPhyAddr %08llx\n"
-		"pRxBufferPool %p, RxBufferPoolSize %u, RxBufferPoolPhyAddr %08llx\n",
-		pDc->ui32ACXTxQueueStart, pDc->ui32ACXRxQueueStart,
-		pDc->pTxBufferPool, pDc->TxBufferPoolSize, (u64)pDc->TxBufferPoolPhyAddr,
-		pDc->TxDescrSize, pDc->pTxDescQPool, pDc->tx_pool_count,
-		pDc->pTxHostDescQPool, pDc->TxHostDescQPoolSize, (u64)pDc->TxHostDescQPoolPhyAddr,
-		pDc->pRxDescQPool, pDc->rx_pool_count,
-		pDc->pRxHostDescQPool, pDc->RxHostDescQPoolSize, (u64)pDc->RxHostDescQPoolPhyAddr,
-		pDc->pRxBufferPool, pDc->RxBufferPoolSize, (u64)pDc->RxBufferPoolPhyAddr);
-}
-#endif
-
 	acx_unlock(priv, flags);
 
 	if (OK != acx_s_interrogate(priv, fw_stats, ACX1xx_IE_FIRMWARE_STATISTICS))
@@ -1531,27 +569,6 @@ acx_s_proc_diag_output(char *buf, wlande
 /***********************************************************************
 */
 static int
-acx_proc_eeprom_output(char *buf, wlandevice_t *priv)
-{
-	char *p = buf;
-#ifdef ACX_PCI
-	int i;
-
-	FN_ENTER;
-
-	for (i = 0; i < 0x400; i++) {
-		acx_read_eeprom_offset(priv, i, p++);
-	}
-
-	FN_EXIT1(p - buf);
-#endif
-	return p - buf;
-}
-
-
-/***********************************************************************
-*/
-static int
 acx_s_proc_phy_output(char *buf, wlandevice_t *priv)
 {
 	char *p = buf;
@@ -1657,10 +674,13 @@ acx_e_read_proc_eeprom(char *buf, char *
 
 	FN_ENTER;
 
-	acx_sem_lock(priv);
 	/* fill buf */
-	length = acx_proc_eeprom_output(buf, priv);
-	acx_sem_unlock(priv);
+	length = 0;
+	if (IS_PCI(priv)) {
+		acx_sem_lock(priv);
+		length = acx_proc_eeprom_output(buf, priv);
+		acx_sem_unlock(priv);
+	}
 
 	/* housekeeping */
 	if (length <= offset + count)
@@ -1755,2250 +775,83 @@ acx_proc_unregister_entries(const struct
 
 
 /***********************************************************************
-** acx_s_read_fw
-**
-** Loads a firmware image
-**
-** Returns:
-**  0				unable to load file
-**  pointer to firmware		success
+** acx_s_set_defaults
+** Called from acx_s_init_mac
 */
-#if USE_FW_LOADER_26
-firmware_image_t*
-acx_s_read_fw(struct device *dev, const char *file, u32 *size)
-#else
-#undef acx_s_read_fw
-firmware_image_t*
-acx_s_read_fw(const char *file, u32 *size)
-#endif
+int
+acx_s_set_defaults(wlandevice_t *priv)
 {
-	firmware_image_t *res = NULL;
+	unsigned long flags;
 
-#if USE_FW_LOADER_LEGACY
-	mm_segment_t orgfs;
-	unsigned long page;
-	char *buffer;
-	struct file *inf;
-	int retval;
-	u32 offset = 0;
-	char *filename;
-#endif
+	FN_ENTER;
 
-#if USE_FW_LOADER_26
-	const struct firmware *fw_entry;
+	/* query some settings from the card.
+	 * NOTE: for some settings, e.g. CCA and ED (ACX100!), an initial
+	 * query is REQUIRED, otherwise the card won't work correctly!! */
+	priv->get_mask = GETSET_ANTENNA|GETSET_SENSITIVITY|GETSET_STATION_ID|GETSET_REG_DOMAIN;
+	/* Only ACX100 supports ED and CCA */
+	if (IS_ACX100(priv))
+		priv->get_mask |= GETSET_CCA|GETSET_ED_THRESH;
 
-	acxlog(L_DEBUG, "requesting firmware image '%s'\n", file);
-	if (!request_firmware(&fw_entry, file, dev)) {
-		*size = 8 + le32_to_cpu(*(u32 *)(fw_entry->data + 4));
-		if (fw_entry->size != *size) {
-			printk("acx: firmware size does not match "
-				"firmware header: %d != %d\n",
-				(int) fw_entry->size, (int) *size);
-		}
-		res = vmalloc(*size);
-		if (!res) {
-			printk("acx: no memory for firmware "
-				"(%u bytes)\n", *size);
-			return NULL;
-		}
-		memcpy(res, fw_entry->data, fw_entry->size);
-		release_firmware(fw_entry);
-		return res;
-	}
-	printk("acx: no firmware image was provided. "
-		"Check your hotplug scripts\n");
-#endif
+	acx_s_update_card_settings(priv, 0, 0);
 
-#if USE_FW_LOADER_LEGACY
-	printk("acx: firmware upload via firmware_dir module parameter "
-		"is deprecated. Switch to using hotplug\n");
-
-	orgfs = get_fs(); /* store original fs */
-	set_fs(KERNEL_DS);
-
-	/* Read in whole file then check the size */
-	page = __get_free_page(GFP_KERNEL);
-	if (unlikely(0 == page)) {
-		printk("acx: no memory for firmware upload\n");
-		goto fail;
-	}
+	acx_lock(priv, flags);
 
-	filename = kmalloc(PATH_MAX, GFP_KERNEL);
-	if (unlikely(!filename)) {
-		printk("acx: no memory for firmware upload\n");
-		goto fail;
-	}
-	if (!firmware_dir) {
-		firmware_dir = "/usr/share/acx";
-		acxlog(L_DEBUG, "no firmware directory specified "
-			"via module parameter firmware_dir, "
-			"using default %s\n", firmware_dir);
-	}
-	snprintf(filename, PATH_MAX, "%s/%s", firmware_dir, file);
-	acxlog(L_DEBUG, "reading firmware image '%s'\n", filename);
+	/* set our global interrupt mask */
+	if (IS_PCI(priv))
+		acx_set_interrupt_mask(priv);
 
-	buffer = (char*)page;
+	priv->led_power = 1; /* LED is active on startup */
+	priv->brange_max_quality = 60; /* LED blink max quality is 60 */
+	priv->brange_time_last_state_change = jiffies;
 
-	/* Note that file must be given as absolute path:
-	 * a relative path works on first loading,
-	 * but any subsequent firmware loading during card
-	 * eject/insert will fail, most likely since the first
-	 * module loading happens in user space (and thus
-	 * filp_open can figure out the absolute path from a
-	 * relative path) whereas the card reinsert processing
-	 * probably happens in kernel space where you don't have
-	 * a current directory to be able to figure out an
-	 * absolute path from a relative path... */
-	inf = filp_open(filename, O_RDONLY, 0);
-	kfree(filename);
-	if (OK != IS_ERR(inf)) {
-		const char *err;
-
-		switch (-PTR_ERR(inf)) {
-			case 2: err = "file not found";
-				break;
-			default:
-				err = "unknown error";
-				break;
-		}
-		printk("acx: error %ld trying to open file '%s': %s\n",
-					-PTR_ERR(inf), file, err);
-		goto fail;
-	}
+	/* copy the MAC address we just got from the card
+	 * into our MAC address used during current 802.11 session */
+	MAC_COPY(priv->dev_addr, priv->netdev->dev_addr);
+	sprintf(priv->essid, "STA%02X%02X%02X",
+		priv->dev_addr[3], priv->dev_addr[4], priv->dev_addr[5]);
+	priv->essid_len = sizeof("STAxxxxxx") - 1; /* make sure to adapt if changed above! */
+	priv->essid_active = 1;
 
-	if (unlikely((NULL == inf->f_op) || (NULL == inf->f_op->read))) {
-		printk("acx: %s does not have a read method?!\n", file);
-		goto fail_close;
-	}
+	/* we have a nick field to waste, so why not abuse it
+	 * to announce the driver version? ;-) */
+	strncpy(priv->nick, "acx " WLAN_RELEASE, IW_ESSID_MAX_SIZE);
 
-	offset = 0;
-	do {
-		retval = inf->f_op->read(inf, buffer, PAGE_SIZE, &inf->f_pos);
-
-		if (unlikely(0 > retval)) {
-			printk("acx: error %d reading file '%s'\n",
-							-retval, file);
-			vfree(res);
-			res = NULL;
-		} else if (0 == retval) {
-			if (0 == offset) {
-				printk("acx: firmware image file "
-					"'%s' is empty?!\n", file);
-			}
-		} else if (0 < retval) {
-			/* allocate result buffer here if needed,
-			 * since we don't want to waste resources/time
-			 * (in case file opening/reading fails)
-			 * by doing allocation in front of the loop instead. */
-			if (NULL == res) {
-				*size = 8 + le32_to_cpu(*(u32 *)(4 + buffer));
-
-				res = vmalloc(*size);
-				if (NULL == res) {
-					printk("acx: unable to "
-						"allocate %u bytes for "
-						"firmware module upload\n",
-						*size);
-					goto fail_close;
-				}
-				acxlog(L_DEBUG, "allocated %u bytes "
-					"for firmware module loading\n",
-					*size);
-			}
-			if ((unlikely(offset + retval > *size))) {
-				printk("acx: ERROR: allocation "
-					"was less than firmware image size?!\n");
-				goto fail_close;
-			}
-			memcpy((u8*)res + offset, buffer, retval);
-			offset += retval;
+	if (IS_PCI(priv)) {
+		if (IS_ACX111(priv)) {
+			/* Hope this is correct, only tested with domain 0x30 */
+			acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
+		} else if (priv->eeprom_version < 5) {
+			acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
+		} else {
+			acx_read_eeprom_offset(priv, 0x171, &priv->reg_dom_id);
 		}
-	} while (0 < retval);
-
-fail_close:
-	retval = filp_close(inf, NULL);
-
-	if (unlikely(retval)) {
-		printk("acx: error %d closing file '%s'\n", -retval, file);
 	}
 
-	if (unlikely((NULL != res) && (offset != le32_to_cpu(res->size) + 8))) {
-		printk("acx: firmware is reporting a different size "
-			"(0x%08X; 0x%08X was read)\n",
-			le32_to_cpu(res->size) + 8, offset);
-		vfree(res);
-		res = NULL;
+	priv->channel = 1;
+	/* 0xffff would be better, but then we won't get a "scan complete"
+	 * interrupt, so our current infrastructure will fail: */
+	priv->scan_count = 1;
+	priv->scan_mode = ACX_SCAN_OPT_PASSIVE;
+	/* Doesn't work for acx100, do it only for acx111 for now */
+	if (IS_ACX111(priv)) {
+		priv->scan_mode = ACX_SCAN_OPT_ACTIVE;
 	}
+	priv->scan_duration = 100;
+	priv->scan_probe_delay = 200;
+	priv->scan_rate = ACX_SCAN_RATE_1;
 
-fail:
-	if (page)
-		free_page(page);
-	set_fs(orgfs);
-#endif
+	priv->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
+	priv->preamble_mode = 2; /* auto */
+	priv->listen_interval = 100;
+	priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
+	priv->mode = ACX_MODE_OFF;
+	priv->dtim_interval = DEFAULT_DTIM_INTERVAL;
 
-	/* checksum will be verified in write_fw, so don't bother here */
-	return res;
-}
+	priv->msdu_lifetime = DEFAULT_MSDU_LIFETIME;
+	SET_BIT(priv->set_mask, SET_MSDU_LIFETIME);
 
-
-/***********************************************************************
-** acx_s_set_wepkey
-*/
-static void
-acx100_s_set_wepkey(wlandevice_t *priv)
-{
-	ie_dot11WEPDefaultKey_t dk;
-	int i;
-
-	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
-		if (priv->wep_keys[i].size != 0) {
-			acxlog(L_INIT, "setting WEP key: %d with "
-				"total size: %d\n", i, (int) priv->wep_keys[i].size);
-			dk.action = 1;
-			dk.keySize = priv->wep_keys[i].size;
-			dk.defaultKeyNum = i;
-			memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
-			acx_s_configure(priv, &dk, ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE);
-		}
-	}
-}
-
-static void
-acx111_s_set_wepkey(wlandevice_t *priv)
-{
-	acx111WEPDefaultKey_t dk;
-	int i;
-
-	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
-		if (priv->wep_keys[i].size != 0) {
-			acxlog(L_INIT, "setting WEP key: %d with "
-				"total size: %d\n", i, (int) priv->wep_keys[i].size);
-			memset(&dk, 0, sizeof(dk));
-			dk.action = cpu_to_le16(1); /* "add key"; yes, that's a 16bit value */
-			dk.keySize = priv->wep_keys[i].size;
-
-			/* are these two lines necessary? */
-			dk.type = 0;              /* default WEP key */
-			dk.index = 0;             /* ignored when setting default key */
-
-			dk.defaultKeyNum = i;
-			memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
-			acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &dk, sizeof(dk));
-		}
-	}
-}
-
-static void
-acx_s_set_wepkey(wlandevice_t *priv)
-{
-	if (priv->chip_type == CHIPTYPE_ACX111)
-		acx111_s_set_wepkey(priv);
-	else
-		acx100_s_set_wepkey(priv);
-}
-
-
-/***********************************************************************
-** acx100_s_init_wep
-**
-** FIXME: this should probably be moved into the new card settings
-** management, but since we're also modifying the memory map layout here
-** due to the WEP key space we want, we should take care...
-*/
-static int
-acx100_s_init_wep(wlandevice_t *priv)
-{
-/*	int i;
-	acx100_cmd_wep_mgmt_t wep_mgmt;           size = 37 bytes */
-	acx100_ie_wep_options_t options;
-	ie_dot11WEPDefaultKeyID_t dk;
-	acx_ie_memmap_t pt;
-	int res = NOT_OK;
-
-	FN_ENTER;
-
-	if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-		printk("%s: ctlMemoryMapRead failed\n", priv->netdev->name);
-		goto fail;
-	}
-
-	acxlog(L_DEBUG, "CodeEnd:%X\n", pt.CodeEnd);
-
-	pt.WEPCacheStart = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
-	pt.WEPCacheEnd   = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
-
-	if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-		printk("%s: ctlMemoryMapWrite FAILED\n", priv->netdev->name);
-		goto fail;
-	}
-
-	/* let's choose maximum setting: 4 default keys, plus 10 other keys: */
-	options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
-	options.WEPOption = 0x00;
-
-	acxlog(L_ASSOC, "%s: writing WEP options\n", __func__);
-	acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
-
-	acx100_s_set_wepkey(priv);
-
-	if (priv->wep_keys[priv->wep_current_index].size != 0) {
-		acxlog(L_ASSOC, "setting active default WEP key number: %d\n",
-				priv->wep_current_index);
-		dk.KeyID = priv->wep_current_index;
-		acx_s_configure(priv, &dk, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); /* 0x1010 */
-	}
-	/* FIXME!!! wep_key_struct is filled nowhere! But priv
-	 * is initialized to 0, and we don't REALLY need those keys either */
-/*		for (i = 0; i < 10; i++) {
-		if (priv->wep_key_struct[i].len != 0) {
-			MAC_COPY(wep_mgmt.MacAddr, priv->wep_key_struct[i].addr);
-			wep_mgmt.KeySize = cpu_to_le16(priv->wep_key_struct[i].len);
-			memcpy(&wep_mgmt.Key, priv->wep_key_struct[i].key, le16_to_cpu(wep_mgmt.KeySize));
-			wep_mgmt.Action = cpu_to_le16(1);
-			acxlog(L_ASSOC, "writing WEP key %d (len %d)\n", i, le16_to_cpu(wep_mgmt.KeySize));
-			if (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &wep_mgmt, sizeof(wep_mgmt))) {
-				priv->wep_key_struct[i].index = i;
-			}
-		}
-	} */
-
-	/* now retrieve the updated WEPCacheEnd pointer... */
-	if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-		printk("%s: ctlMemoryMapRead #2 FAILED\n", priv->netdev->name);
-		goto fail;
-	}
-	/* ...and tell it to start allocating templates at that location */
-	/* (no endianness conversion needed) */
-	pt.PacketTemplateStart = pt.WEPCacheEnd;
-
-	if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-		printk("%s: ctlMemoryMapWrite #2 FAILED\n", priv->netdev->name);
-		goto fail;
-	}
-	res = OK;
-
-fail:
-	FN_EXIT1(res);
-	return res;
-}
-
-
-/***********************************************************************
-*/
-static int
-acx_s_init_max_null_data_template(wlandevice_t *priv)
-{
-	struct acxp80211_nullframe b;
-	int result;
-
-	FN_ENTER;
-	memset(&b, 0, sizeof(b));
-	b.size = cpu_to_le16(sizeof(b) - 2);
-	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_NULL_DATA, &b, sizeof(b));
-	FN_EXIT1(result);
-	return result;
-}
-
-
-/***********************************************************************
-** acx_s_init_max_beacon_template
-*/
-static int
-acx_s_init_max_beacon_template(wlandevice_t *priv)
-{
-	struct acx_template_beacon b;
-	int result;
-
-	FN_ENTER;
-	memset(&b, 0, sizeof(b));
-	b.size = cpu_to_le16(sizeof(b) - 2);
-	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &b, sizeof(b));
-
-	FN_EXIT1(result);
-	return result;
-}
-
-/***********************************************************************
-** acx_s_init_max_tim_template
-*/
-static int
-acx_s_init_max_tim_template(wlandevice_t *priv)
-{
-	acx_template_tim_t t;
-
-	memset(&t, 0, sizeof(t));
-	t.size = cpu_to_le16(sizeof(t) - 2);
-	return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
-}
-
-
-/***********************************************************************
-** acx_s_init_max_probe_response_template
-*/
-static int
-acx_s_init_max_probe_response_template(wlandevice_t *priv)
-{
-	struct acx_template_proberesp pr;
-
-	memset(&pr, 0, sizeof(pr));
-	pr.size = cpu_to_le16(sizeof(pr) - 2);
-
-	return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, sizeof(pr));
-}
-
-
-/***********************************************************************
-** acx_s_init_max_probe_request_template
-*/
-static int
-acx_s_init_max_probe_request_template(wlandevice_t *priv)
-{
-	union {
-		acx100_template_probereq_t p100;
-		acx111_template_probereq_t p111;
-	} pr;
-	int res;
-
-	FN_ENTER;
-	memset(&pr, 0, sizeof(pr));
-	pr.p100.size = cpu_to_le16(sizeof(pr) - 2);
-	res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &pr, sizeof(pr));
-	FN_EXIT1(res);
-	return res;
-}
-
-
-/***********************************************************************
-** acx_s_set_tim_template
-**
-** In full blown driver we will regularly update partial virtual bitmap
-** by calling this function
-** (it can be done by irq handler on each DTIM irq or by timer...)
-
-[802.11 7.3.2.6] TIM information element:
-- 1 EID
-- 1 Length
-1 1 DTIM Count
-    indicates how many beacons (including this) appear before next DTIM
-    (0=this one is a DTIM)
-2 1 DTIM Period
-    number of beacons between successive DTIMs
-    (0=reserved, 1=all TIMs are DTIMs, 2=every other, etc)
-3 1 Bitmap Control
-    bit0: Traffic Indicator bit associated with Assoc ID 0 (Bcast AID?)
-    set to 1 in TIM elements with a value of 0 in the DTIM Count field
-    when one or more broadcast or multicast frames are buffered at the AP.
-    bit1-7: Bitmap Offset (logically Bitmap_Offset = Bitmap_Control & 0xFE).
-4 n Partial Virtual Bitmap
-    Visible part of traffic-indication bitmap.
-    Full bitmap consists of 2008 bits (251 octets) such that bit number N
-    (0<=N<=2007) in the bitmap corresponds to bit number (N mod 8)
-    in octet number N/8 where the low-order bit of each octet is bit0,
-    and the high order bit is bit7.
-    Each set bit in virtual bitmap corresponds to traffic buffered by AP
-    for a specific station (with corresponding AID?).
-    Partial Virtual Bitmap shows a part of bitmap which has non-zero.
-    Bitmap Offset is a number of skipped zero octets (see above).
-    'Missing' octets at the tail are also assumed to be zero.
-    Example: Length=6, Bitmap_Offset=2, Partial_Virtual_Bitmap=55 55 55
-    This means that traffic-indication bitmap is:
-    00000000 00000000 01010101 01010101 01010101 00000000 00000000...
-    (is bit0 in the map is always 0 and real value is in Bitmap Control bit0?)
-*/
-static int
-acx_s_set_tim_template(wlandevice_t *priv)
-{
-/* For now, configure smallish test bitmap, all zero ("no pending data") */
-	enum { bitmap_size = 5 };
-
-	acx_template_tim_t t;
-	int result;
-
-	FN_ENTER;
-
-	memset(&t, 0, sizeof(t));
-	t.size = 5 + bitmap_size; /* eid+len+count+period+bmap_ctrl + bmap */
-	t.tim_eid = WLAN_EID_TIM;
-	t.len = 3 + bitmap_size; /* count+period+bmap_ctrl + bmap */
-	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
-	FN_EXIT1(result);
-	return result;
-}
-
-
-/***********************************************************************
-** acx_fill_beacon_or_proberesp_template
-**
-** For frame format info, please see 802.11-1999.pdf item 7.2.3.9 and below!!
-**
-** STATUS: done
-** WARNING/FIXME/TODO: this needs to be called (via SET_TEMPLATES) *whenever*
-** *any* of the parameters contained in it change!!!
-** fishy status fixed
-**
-** NB: we use the fact that
-** struct acx_template_proberesp and struct acx_template_beacon are the same
-** (well, almost...)
-**
-** [802.11] Beacon's body consist of these IEs:
-** 1 Timestamp
-** 2 Beacon interval
-** 3 Capability information
-** 4 SSID
-** 5 Supported rates (up to 8 rates)
-** 6 FH Parameter Set (frequency-hopping PHYs only)
-** 7 DS Parameter Set (direct sequence PHYs only)
-** 8 CF Parameter Set (only if PCF is supported)
-** 9 IBSS Parameter Set (ad-hoc only)
-**
-** Beacon only:
-** 10 TIM (AP only) (see 802.11 7.3.2.6)
-** 11 Country Information (802.11d)
-** 12 FH Parameters (802.11d)
-** 13 FH Pattern Table (802.11d)
-** ... (?!! did not yet find relevant PDF file... --vda)
-** 19 ERP Information (extended rate PHYs)
-** 20 Extended Supported Rates (if more than 8 rates)
-**
-** Proberesp only:
-** 10 Country information (802.11d)
-** 11 FH Parameters (802.11d)
-** 12 FH Pattern Table (802.11d)
-** 13-n Requested information elements (802.11d)
-** ????
-** 18 ERP Information (extended rate PHYs)
-** 19 Extended Supported Rates (if more than 8 rates)
-*/
-static int
-acx_fill_beacon_or_proberesp_template(wlandevice_t *priv,
-					struct acx_template_beacon *templ,
-					u16 fc /* in host order! */)
-{
-	int len;
-	u8 *p;
-
-	FN_ENTER;
-
-	memset(templ, 0, sizeof(*templ));
-	MAC_BCAST(templ->da);
-	MAC_COPY(templ->sa, priv->dev_addr);
-	MAC_COPY(templ->bssid, priv->bssid);
-
-	templ->beacon_interval = cpu_to_le16(priv->beacon_interval);
-	acx_update_capabilities(priv);
-	templ->cap = cpu_to_le16(priv->capabilities);
-
-	p = templ->variable;
-	p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
-	p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
-	p = wlan_fill_ie_ds_parms(p, priv->channel);
-	/* NB: should go AFTER tim, but acx seem to keep tim last always */
-	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
-
-	switch (priv->mode) {
-	case ACX_MODE_0_ADHOC:
-		/* ATIM window */
-		p = wlan_fill_ie_ibss_parms(p, 0); break;
-	case ACX_MODE_3_AP:
-		/* TIM IE is set up as separate template */
-		break;
-	}
-
-	len = p - (u8*)templ;
-	templ->fc = cpu_to_le16(WF_FTYPE_MGMT | fc);
-	/* - 2: do not count 'u16 size' field */
-	templ->size = cpu_to_le16(len - 2);
-
-	FN_EXIT1(len);
-	return len;
-}
-
-
-/***********************************************************************
-** acx_s_set_beacon_template
-*/
-static int
-acx_s_set_beacon_template(wlandevice_t *priv)
-{
-	struct acx_template_beacon bcn;
-	int len, result;
-
-	FN_ENTER;
-
-	len = acx_fill_beacon_or_proberesp_template(priv, &bcn, WF_FSTYPE_BEACON);
-	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &bcn, len);
-
-	FN_EXIT1(result);
-	return result;
-}
-
-
-/***********************************************************************
-** acx_s_set_probe_response_template
-*/
-static int
-acx_s_set_probe_response_template(wlandevice_t *priv)
-{
-	struct acx_template_proberesp pr;
-	int len, result;
-
-	FN_ENTER;
-
-	len = acx_fill_beacon_or_proberesp_template(priv, &pr, WF_FSTYPE_PROBERESP);
-	result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, len);
-
-	FN_EXIT1(result);
-	return result;
-}
-
-
-/***********************************************************************
-** acx100_s_init_packet_templates()
-**
-** NOTE: order is very important here, to have a correct memory layout!
-** init templates: max Probe Request (station mode), max NULL data,
-** max Beacon, max TIM, max Probe Response.
-**
-** acxInitPacketTemplates()
-** STATUS: almost ok, except for struct definitions.
-*/
-static int
-acx100_s_init_packet_templates(wlandevice_t *priv)
-{
-	acx_ie_memmap_t mm;
-	int result = NOT_OK;
-
-	FN_ENTER;
-
-	acxlog(L_DEBUG, "sizeof(memmap)=%d bytes\n", (int)sizeof(mm));
-
-	/* acx100 still do not emit probe requests, thus this call
-	** is sourt of not needed. But we want it to work someday */
-	if (OK != acx_s_init_max_probe_request_template(priv))
-		goto failed;
-
-#if NOT_WORKING_YET
-	/* FIXME: creating the NULL data template breaks
-	 * communication right now, needs further testing.
-	 * Also, need to set the template once we're joining a network. */
-	if (OK != acx_s_init_max_null_data_template(priv))
-		goto failed;
-#endif
-
-	if (OK != acx_s_init_max_beacon_template(priv))
-		goto failed;
-
-	/* TODO: beautify code by moving init_tim down just before set_tim */
-	if (OK != acx_s_init_max_tim_template(priv))
-		goto failed;
-
-	if (OK != acx_s_init_max_probe_response_template(priv))
-		goto failed;
-
-	if (OK != acx_s_set_tim_template(priv))
-		goto failed;
-
-	if (OK != acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
-		printk("%s: memmap req FAILED\n", priv->netdev->name);
-		goto failed;
-	}
-
-	mm.QueueStart = cpu_to_le32(le32_to_cpu(mm.PacketTemplateEnd) + 4);
-	if (OK != acx_s_configure(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
-		printk("%s: memmap cfg FAILED\n", priv->netdev->name);
-		goto failed;
-	}
-
-	result = OK;
-	goto success;
-
-failed:
-	acxlog(L_DEBUG | L_INIT,
-		/* "cb=0x%X\n" */
-		"pACXMemoryMap:\n"
-		".CodeStart=0x%X\n"
-		".CodeEnd=0x%X\n"
-		".WEPCacheStart=0x%X\n"
-		".WEPCacheEnd=0x%X\n"
-		".PacketTemplateStart=0x%X\n"
-		".PacketTemplateEnd=0x%X\n",
-		/* len, */
-		le32_to_cpu(mm.CodeStart),
-		le32_to_cpu(mm.CodeEnd),
-		le32_to_cpu(mm.WEPCacheStart),
-		le32_to_cpu(mm.WEPCacheEnd),
-		le32_to_cpu(mm.PacketTemplateStart),
-		le32_to_cpu(mm.PacketTemplateEnd));
-
-success:
-	FN_EXIT1(result);
-	return result;
-}
-
-static int
-acx111_s_init_packet_templates(wlandevice_t *priv)
-{
-	int result = NOT_OK;
-
-	FN_ENTER;
-
-	acxlog(L_DEBUG | L_INIT, "initializing max packet templates\n");
-
-	if (OK != acx_s_init_max_probe_request_template(priv))
-		goto failed;
-
-	if (OK != acx_s_init_max_null_data_template(priv))
-		goto failed;
-
-	if (OK != acx_s_init_max_beacon_template(priv))
-		goto failed;
-
-	if (OK != acx_s_init_max_tim_template(priv))
-		goto failed;
-
-	if (OK != acx_s_init_max_probe_response_template(priv))
-		goto failed;
-
-	/* the other templates will be set later (acx_start) */
-	/*
-	if (OK != acx_s_set_tim_template(priv))
-		goto failed;*/
-
-	result = OK;
-	goto success;
-
-failed:
-	printk("%s: acx111_init_packet_templates() FAILED\n", priv->netdev->name);
-
-success:
-	FN_EXIT1(result);
-	return result;
-}
-
-
-/***********************************************************************
-*/
-static int
-acx100_s_set_probe_request_template(wlandevice_t *priv)
-{
-	struct acx100_template_probereq probereq;
-	char *p;
-	int res;
-	int frame_len;
-
-	FN_ENTER;
-
-	memset(&probereq, 0, sizeof(probereq));
-
-	probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
-	MAC_BCAST(probereq.da);
-	MAC_COPY(probereq.sa, priv->dev_addr);
-	MAC_BCAST(probereq.bssid);
-
-	probereq.beacon_interval = cpu_to_le16(priv->beacon_interval);
-	acx_update_capabilities(priv);
-	probereq.cap = cpu_to_le16(priv->capabilities);
-
-	p = probereq.variable;
-	acxlog(L_ASSOC, "SSID='%s' len=%d\n", priv->essid, priv->essid_len);
-	p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
-	p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
-	/* FIXME: should these be here or AFTER ds_parms? */
-	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
-	/* HUH?? who said it must be here? I've found nothing in 802.11! --vda*/
-	/* p = wlan_fill_ie_ds_parms(p, priv->channel); */
-	frame_len = p - (char*)&probereq;
-	probereq.size = frame_len - 2;
-
-	res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
-	FN_EXIT0;
-	return res;
-}
-
-static int
-acx111_s_set_probe_request_template(wlandevice_t *priv)
-{
-	struct acx111_template_probereq probereq;
-	char *p;
-	int res;
-	int frame_len;
-
-	FN_ENTER;
-
-	memset(&probereq, 0, sizeof(probereq));
-
-	probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
-	MAC_BCAST(probereq.da);
-	MAC_COPY(probereq.sa, priv->dev_addr);
-	MAC_BCAST(probereq.bssid);
-
-	p = probereq.variable;
-	p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
-	p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
-	p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
-	frame_len = p - (char*)&probereq;
-	probereq.size = frame_len - 2;
-
-	res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
-	FN_EXIT0;
-	return res;
-}
-
-static int
-acx_s_set_probe_request_template(wlandevice_t *priv)
-{
-	if (priv->chip_type == CHIPTYPE_ACX111) {
-		return acx111_s_set_probe_request_template(priv);
-	} else {
-		return acx100_s_set_probe_request_template(priv);
-	}
-}
-
-
-/***********************************************************************
-** FIXME: this should be solved in a general way for all radio types
-** by decoding the radio firmware module,
-** since it probably has some standard structure describing how to
-** set the power level of the radio module which it controls.
-** Or maybe not, since the radio module probably has a function interface
-** instead which then manages Tx level programming :-\
-*/
-static int
-acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
-{
-	/* since it can be assumed that at least the Maxim radio has a
-	 * maximum power output of 20dBm and since it also can be
-	 * assumed that these values drive the DAC responsible for
-	 * setting the linear Tx level, I'd guess that these values
-	 * should be the corresponding linear values for a dBm value,
-	 * in other words: calculate the values from that formula:
-	 * Y [dBm] = 10 * log (X [mW])
-	 * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
-	 * and you're done...
-	 * Hopefully that's ok, but you never know if we're actually
-	 * right... (especially since Windows XP doesn't seem to show
-	 * actual Tx dBm values :-P) */
-#ifdef ACX_PCI
-	/* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the
-	 * values are EXACTLY mW!!! Not sure about RFMD and others,
-	 * though... */
-	static const u8 dbm2val_maxim[21] = {
-		63, 63, 63, 62,
-		61, 61, 60, 60,
-		59, 58, 57, 55,
-		53, 50, 47, 43,
-		38, 31, 23, 13,
-		0
-	};
-	static const u8 dbm2val_rfmd[21] = {
-		 0,  0,  0,  1,
-		 2,  2,  3,  3,
-		 4,  5,  6,  8,
-		10, 13, 16, 20,
-		25, 32, 41, 50,
-		63
-	};
-	const u8 *table;
-
-	switch (priv->radio_type) {
-		case RADIO_MAXIM_0D:
-			table = &dbm2val_maxim[0];
-			break;
-		case RADIO_RFMD_11:
-		case RADIO_RALINK_15:
-			table = &dbm2val_rfmd[0];
-			break;
-		default:
-			printk("%s: unknown/unsupported radio type, "
-				"cannot modify tx power level yet!\n",
-					priv->netdev->name);
-			return NOT_OK;
-	}
-	printk("%s: changing radio power level to %u dBm (%u)\n",
-			priv->netdev->name, level_dbm, table[level_dbm]);
-	acx_s_write_phy_reg(priv, 0x11, table[level_dbm]);
-#endif
-	return OK;
-}
-
-static int
-acx111_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
-{
-	struct ACX111TxLevel tx_level;
-
-	/* my acx111 card has two power levels in its configoptions (== EEPROM):
-	 * 1 (30mW) [15dBm]
-	 * 2 (10mW) [10dBm]
-	 * For now, just assume all other acx111 cards have the same.
-	 * Ideally we would query it here, but we first need a
-	 * standard way to query individual configoptions easily. */
-	if (level_dbm <= 12) {
-		tx_level.level = 2; /* 10 dBm */
-		priv->tx_level_dbm = 10;
-	} else {
-		tx_level.level = 1; /* 15 dBm */
-		priv->tx_level_dbm = 15;
-	}
-	if (level_dbm != priv->tx_level_dbm)
-		acxlog(L_INIT, "ACX111 firmware has specific "
-			"power levels only: adjusted %d dBm to %d dBm!\n",
-			level_dbm, priv->tx_level_dbm);
-
-	if (OK != acx_s_configure(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL)) {
-		printk("%s: error setting acx111 tx level\n", priv->netdev->name);
-		return NOT_OK;
-	}
-	return OK;
-}
-
-static int
-acx_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
-{
-	if (priv->chip_type == CHIPTYPE_ACX111) {
-		return acx111_s_set_tx_level(priv, level_dbm);
-	}
-	return acx100_s_set_tx_level(priv, level_dbm);
-}
-
-
-/***********************************************************************
-*/
-#ifdef UNUSED
-/* Returns the current tx level (ACX111) */
-static u8
-acx111_s_get_tx_level(wlandevice_t *priv)
-{
-	struct ACX111TxLevel tx_level;
-
-	tx_level.level = 0;
-	if (OK != acx_s_interrogate(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL)) {
-		printk("%s: error getting acx111 tx level\n", priv->netdev->name);
-	}
-	return tx_level.level;
-}
-#endif
-
-
-/***********************************************************************
-*/
-int
-acx111_s_get_feature_config(wlandevice_t *priv,
-		u32 *feature_options, u32 *data_flow_options)
-{
-	struct ACX111FeatureConfig fc;
-
-	if (priv->chip_type != CHIPTYPE_ACX111) {
-		return NOT_OK;
-	}
-
-	memset(&fc, 0, sizeof(struct ACX111FeatureConfig));
-
-	if (OK != acx_s_interrogate(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
-		printk("%s: error reading feature config\n",
-						priv->netdev->name);
-		return NOT_OK;
-	}
-	acxlog(L_DEBUG,
-		"got Feature option:0x%X, DataFlow option: 0x%X\n",
-		fc.feature_options,
-		fc.data_flow_options);
-
-	if (feature_options)
-		*feature_options = le32_to_cpu(fc.feature_options);
-	if (data_flow_options)
-		*data_flow_options = le32_to_cpu(fc.data_flow_options);
-
-	return OK;
-}
-
-int
-acx111_s_set_feature_config(wlandevice_t *priv,
-	u32 feature_options, u32 data_flow_options,
-	unsigned int mode /* 0 == remove, 1 == add, 2 == set */)
-{
-	struct ACX111FeatureConfig fc;
-
-	if (priv->chip_type != CHIPTYPE_ACX111) {
-		return NOT_OK;
-	}
-
-	if ((mode < 0) || (mode > 2))
-		return NOT_OK;
-
-	if (mode != 2)
-		/* need to modify old data */
-		acx111_s_get_feature_config(priv, &fc.feature_options, &fc.data_flow_options);
-	else {
-		/* need to set a completely new value */
-		fc.feature_options = 0;
-		fc.data_flow_options = 0;
-	}
-
-	if (mode == 0) { /* remove */
-		CLEAR_BIT(fc.feature_options, cpu_to_le32(feature_options));
-		CLEAR_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
-	} else { /* add or set */
-		SET_BIT(fc.feature_options, cpu_to_le32(feature_options));
-		SET_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
-	}
-
-	acxlog(L_DEBUG,
-		"old: feature 0x%08X dataflow 0x%08X. mode: %u\n"
-		"new: feature 0x%08X dataflow 0x%08X\n",
-		feature_options, data_flow_options, mode,
-		le32_to_cpu(fc.feature_options),
-		le32_to_cpu(fc.data_flow_options));
-
-	if (OK != acx_s_configure(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
-		printk("%s: error setting feature config\n", priv->netdev->name);
-		return NOT_OK;
-	}
-
-	return OK;
-}
-
-
-/***********************************************************************
-*/
-int
-acx_s_recalib_radio(wlandevice_t *priv)
-{
-	if (CHIPTYPE_ACX111 == priv->chip_type) {
-		acx111_cmd_radiocalib_t cal;
-
-		printk("%s: recalibrating radio\n", priv->netdev->name);
-		/* automatic recalibration, choose all methods: */
-		cal.methods = cpu_to_le32(0x8000000f);
-		/* automatic recalibration every 60 seconds (value in TUs)
-		 * FIXME: what is the firmware default here?? */
-		cal.interval = cpu_to_le32(58594);
-		return acx_s_issue_cmd_timeo(priv, ACX111_CMD_RADIOCALIB,
-			&cal, sizeof(cal), CMD_TIMEOUT_MS(100));
-	} else {
-		if (/* (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0)) &&
-		    (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0)) && */
-		    (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1)) &&
-		    (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1)) )
-			return OK;
-		return NOT_OK;
-	}
-}
-
-
-/***********************************************************************
-** acx_s_cmd_start_scan
-**
-** Issue scan command to the hardware
-*/
-static void
-acx100_s_scan_chan(wlandevice_t *priv)
-{
-	acx100_scan_t s;
-
-	FN_ENTER;
-
-	memset(&s, 0, sizeof(s));
-	s.count = cpu_to_le16(priv->scan_count);
-	s.start_chan = cpu_to_le16(1);
-	s.flags = cpu_to_le16(0x8000);
-	s.max_rate = priv->scan_rate;
-	s.options = priv->scan_mode;
-	s.chan_duration = cpu_to_le16(priv->scan_duration);
-	s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
-
-	acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
-	FN_EXIT0;
-}
-
-static void
-acx111_s_scan_chan(wlandevice_t *priv)
-{
-	acx111_scan_t s;
-
-	FN_ENTER;
-
-	memset(&s, 0, sizeof(s));
-	s.count = cpu_to_le16(priv->scan_count);
-	s.channel_list_select = 0; /* scan every allowed channel */
-	/*s.channel_list_select = 1;*/ /* scan given channels */
-	s.rate = priv->scan_rate;
-	s.options = priv->scan_mode;
-	s.chan_duration = cpu_to_le16(priv->scan_duration);
-	s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
-	/*s.modulation = 0x40;*/ /* long preamble? OFDM? -> only for active scan */
-	s.modulation = 0;
-	/*s.channel_list[0] = 6;
-	s.channel_list[1] = 4;*/
-
-	acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
-	FN_EXIT0;
-}
-
-void
-acx_s_cmd_start_scan(wlandevice_t *priv)
-{
-	/* time_before check is 'just in case' thing */
-	if (!(priv->irq_status & HOST_INT_SCAN_COMPLETE)
-	 && time_before(jiffies, priv->scan_start + 10*HZ)
-	) {
-		acxlog(L_INIT, "start_scan: seems like previous scan "
-		"is still running. Not starting anew. Please report\n");
-		return;
-	}
-
-	acxlog(L_INIT, "starting radio scan\n");
-	/* remember that fw is commanded to do scan */
-	priv->scan_start = jiffies;
-	CLEAR_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
-	/* issue it */
-	if (priv->chip_type == CHIPTYPE_ACX100) {
-		acx100_s_scan_chan(priv);
-	} else {
-		acx111_s_scan_chan(priv);
-	}
-}
-
-
-/***********************************************************************
-** acx_s_update_card_settings
-**
-** Applies accumulated changes in various priv->xxxx members
-** Called by ioctl commit handler, acx_start, acx_set_defaults,
-** acx_s_after_interrupt_task (if IRQ_CMD_UPDATE_CARD_CFG),
-*/
-static void
-acx111_s_sens_radio_16_17(wlandevice_t *priv)
-{
-	u32 feature1, feature2;
-
-	if ((priv->sensitivity < 1) || (priv->sensitivity > 3)) {
-		printk("%s: invalid sensitivity setting (1..3), "
-			"setting to 1\n", priv->netdev->name);
-		priv->sensitivity = 1;
-	}
-	acx111_s_get_feature_config(priv, &feature1, &feature2);
-	CLEAR_BIT(feature1, FEATURE1_LOW_RX|FEATURE1_EXTRA_LOW_RX);
-	if (priv->sensitivity > 1)
-		SET_BIT(feature1, FEATURE1_LOW_RX);
-	if (priv->sensitivity > 2)
-		SET_BIT(feature1, FEATURE1_EXTRA_LOW_RX);
-	acx111_s_feature_set(priv, feature1, feature2);
-}
-
-void
-acx_s_update_card_settings(wlandevice_t *priv, int get_all, int set_all)
-{
-	unsigned long flags;
-	unsigned int start_scan = 0;
-	int i;
-
-	FN_ENTER;
-
-	if (get_all)
-		SET_BIT(priv->get_mask, GETSET_ALL);
-	if (set_all)
-		SET_BIT(priv->set_mask, GETSET_ALL);
-	/* Why not just set masks to 0xffffffff? We can get rid of GETSET_ALL */
-
-	acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X\n",
-			priv->get_mask, priv->set_mask);
-
-	/* Track dependencies betweed various settings */
-
-	if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_WEP)) {
-		acxlog(L_INIT, "important setting has been changed. "
-			"Need to update packet templates, too\n");
-		SET_BIT(priv->set_mask, SET_TEMPLATES);
-	}
-	if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
-		/* This will actually tune RX/TX to the channel */
-		SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX);
-		switch (priv->mode) {
-		case ACX_MODE_0_ADHOC:
-		case ACX_MODE_3_AP:
-			/* Beacons contain channel# - update them */
-			SET_BIT(priv->set_mask, SET_TEMPLATES);
-		}
-		switch (priv->mode) {
-		case ACX_MODE_0_ADHOC:
-		case ACX_MODE_2_STA:
-			start_scan = 1;
-		}
-	}
-
-	/* Apply settings */
-
-#ifdef WHY_SHOULD_WE_BOTHER /* imagine we were just powered off */
-	/* send a disassoc request in case it's required */
-	if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_CHANNEL|GETSET_WEP|GETSET_ALL)) {
-		if (ACX_MODE_2_STA == priv->mode) {
-			if (ACX_STATUS_4_ASSOCIATED == priv->status) {
-				acxlog(L_ASSOC, "we were ASSOCIATED - "
-					"sending disassoc request\n");
-				acx_lock(priv, flags);
-				acx_l_transmit_disassoc(priv, NULL);
-				/* FIXME: deauth? */
-				acx_unlock(priv, flags);
-			}
-			/* need to reset some other stuff as well */
-			acxlog(L_DEBUG, "resetting bssid\n");
-			MAC_ZERO(priv->bssid);
-			SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST);
-			/* FIXME: should start scanning */
-			start_scan = 1;
-		}
-	}
-#endif
-
-	if (priv->get_mask & (GETSET_STATION_ID|GETSET_ALL)) {
-		u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
-		const u8 *paddr;
-
-		acx_s_interrogate(priv, &stationID, ACX1xx_IE_DOT11_STATION_ID);
-		paddr = &stationID[4];
-		for (i = 0; i < ETH_ALEN; i++) {
-			/* we copy the MAC address (reversed in
-			 * the card) to the netdevice's MAC
-			 * address, and on ifup it will be
-			 * copied into iwpriv->dev_addr */
-			priv->netdev->dev_addr[ETH_ALEN - 1 - i] = paddr[i];
-		}
-		CLEAR_BIT(priv->get_mask, GETSET_STATION_ID);
-	}
-
-	if (priv->get_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
-		if ((RADIO_RFMD_11 == priv->radio_type)
-		|| (RADIO_MAXIM_0D == priv->radio_type)
-		|| (RADIO_RALINK_15 == priv->radio_type)) {
-			acx_s_read_phy_reg(priv, 0x30, &priv->sensitivity);
-		} else {
-			acxlog(L_INIT, "don't know how to get sensitivity "
-				"for radio type 0x%02X\n", priv->radio_type);
-			priv->sensitivity = 0;
-		}
-		acxlog(L_INIT, "got sensitivity value %u\n", priv->sensitivity);
-
-		CLEAR_BIT(priv->get_mask, GETSET_SENSITIVITY);
-	}
-
-	if (priv->get_mask & (GETSET_ANTENNA|GETSET_ALL)) {
-		u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
-
-		memset(antenna, 0, sizeof(antenna));
-		acx_s_interrogate(priv, antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
-		priv->antenna = antenna[4];
-		acxlog(L_INIT, "got antenna value 0x%02X\n", priv->antenna);
-		CLEAR_BIT(priv->get_mask, GETSET_ANTENNA);
-	}
-
-	if (priv->get_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
-		if (priv->chip_type == CHIPTYPE_ACX100)	{
-			u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
-
-			memset(ed_threshold, 0, sizeof(ed_threshold));
-			acx_s_interrogate(priv, ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
-			priv->ed_threshold = ed_threshold[4];
-		} else {
-			acxlog(L_INIT, "acx111 doesn't support ED\n");
-			priv->ed_threshold = 0;
-		}
-		acxlog(L_INIT, "got Energy Detect (ED) threshold %u\n", priv->ed_threshold);
-		CLEAR_BIT(priv->get_mask, GETSET_ED_THRESH);
-	}
-
-	if (priv->get_mask & (GETSET_CCA|GETSET_ALL)) {
-		if (priv->chip_type == CHIPTYPE_ACX100)	{
-			u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
-
-			memset(cca, 0, sizeof(priv->cca));
-			acx_s_interrogate(priv, cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
-			priv->cca = cca[4];
-		} else {
-			acxlog(L_INIT, "acx111 doesn't support CCA\n");
-			priv->cca = 0;
-		}
-		acxlog(L_INIT, "got Channel Clear Assessment (CCA) value %u\n", priv->cca);
-		CLEAR_BIT(priv->get_mask, GETSET_CCA);
-	}
-
-	if (priv->get_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
-		acx_ie_generic_t dom;
-
-		acx_s_interrogate(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
-		priv->reg_dom_id = dom.m.bytes[0];
-		/* FIXME: should also set chanmask somehow */
-		acxlog(L_INIT, "got regulatory domain 0x%02X\n", priv->reg_dom_id);
-		CLEAR_BIT(priv->get_mask, GETSET_REG_DOMAIN);
-	}
-
-	if (priv->set_mask & (GETSET_STATION_ID|GETSET_ALL)) {
-		u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
-		u8 *paddr;
-
-		paddr = &stationID[4];
-		for (i = 0; i < ETH_ALEN; i++) {
-			/* copy the MAC address we obtained when we noticed
-			 * that the ethernet iface's MAC changed
-			 * to the card (reversed in
-			 * the card!) */
-			paddr[i] = priv->dev_addr[ETH_ALEN - 1 - i];
-		}
-		acx_s_configure(priv, &stationID, ACX1xx_IE_DOT11_STATION_ID);
-		CLEAR_BIT(priv->set_mask, GETSET_STATION_ID);
-	}
-
-	if (priv->set_mask & (SET_TEMPLATES|GETSET_ALL)) {
-		acxlog(L_INIT, "updating packet templates\n");
-		/* Doesn't work for acx100, do it only for acx111 for now */
-		if (priv->chip_type == CHIPTYPE_ACX111) {
-			switch (priv->mode) {
-			case ACX_MODE_0_ADHOC:
-			case ACX_MODE_2_STA:
-				if (OK != acx_s_set_probe_request_template(priv))
-					acxlog(L_INIT, "acx_set_probe_request_template FAILED\n");
-			}
-		}
-		switch (priv->mode) {
-		case ACX_MODE_0_ADHOC:
-		case ACX_MODE_3_AP:
-			/* FIXME: why only for AP? STA need probe req templates... */
-			if (OK != acx_s_set_beacon_template(priv))
-				acxlog(L_INIT, "acx_set_beacon_template FAILED\n");
-			if (OK != acx_s_set_tim_template(priv))
-				acxlog(L_INIT, "acx_set_tim_template FAILED\n");
-			/* BTW acx111 firmware would not send probe responses
-			** if probe request does not have all basic rates flagged
-			** by 0x80! Thus firmware does not conform to 802.11,
-			** it should ignore 0x80 bit in ratevector from STA.
-			** We can 'fix' it by not using this template and
-			** sending probe responses by hand. TODO --vda */
-			if (OK != acx_s_set_probe_response_template(priv))
-				acxlog(L_INIT, "acx_set_probe_response_template FAILED\n");
-		}
-		/* Needed if generated frames are to be emitted at different tx rate now */
-		acxlog(L_IRQ, "redoing cmd_join_bssid() after template cfg\n");
-		acx_s_cmd_join_bssid(priv, priv->bssid);
-		CLEAR_BIT(priv->set_mask, SET_TEMPLATES);
-	}
-	if (priv->set_mask & (SET_STA_LIST|GETSET_ALL)) {
-		/* TODO insert a sweet if here */
-		acx_lock(priv, flags);
-		acx_l_sta_list_init(priv);
-		CLEAR_BIT(priv->set_mask, SET_STA_LIST);
-		acx_unlock(priv, flags);
-	}
-	if (priv->set_mask & (SET_RATE_FALLBACK|GETSET_ALL)) {
-		u8 rate[4 + ACX1xx_IE_RATE_FALLBACK_LEN];
-
-		/* configure to not do fallbacks when not in auto rate mode */
-		rate[4] = (priv->rate_auto) ? /* priv->txrate_fallback_retries */ 1 : 0;
-		acxlog(L_INIT, "updating Tx fallback to %u retries\n", rate[4]);
-		acx_s_configure(priv, &rate, ACX1xx_IE_RATE_FALLBACK);
-		CLEAR_BIT(priv->set_mask, SET_RATE_FALLBACK);
-	}
-	if (priv->set_mask & (GETSET_TXPOWER|GETSET_ALL)) {
-		acxlog(L_INIT, "updating transmit power: %u dBm\n",
-					priv->tx_level_dbm);
-		acx_s_set_tx_level(priv, priv->tx_level_dbm);
-		CLEAR_BIT(priv->set_mask, GETSET_TXPOWER);
-	}
-
-	if (priv->set_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
-		acxlog(L_INIT, "updating sensitivity value: %u\n",
-					priv->sensitivity);
-		switch (priv->radio_type) {
-		case RADIO_RFMD_11:
-		case RADIO_MAXIM_0D:
-		case RADIO_RALINK_15:
-			acx_s_write_phy_reg(priv, 0x30, priv->sensitivity);
-			break;
-		case RADIO_RADIA_16:
-		case RADIO_UNKNOWN_17:
-			acx111_s_sens_radio_16_17(priv);
-			break;
-		default:
-			acxlog(L_INIT, "don't know how to modify sensitivity "
-				"for radio type 0x%02X\n", priv->radio_type);
-		}
-		CLEAR_BIT(priv->set_mask, GETSET_SENSITIVITY);
-	}
-
-	if (priv->set_mask & (GETSET_ANTENNA|GETSET_ALL)) {
-		/* antenna */
-		u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
-
-		memset(antenna, 0, sizeof(antenna));
-		antenna[4] = priv->antenna;
-		acxlog(L_INIT, "updating antenna value: 0x%02X\n",
-					priv->antenna);
-		acx_s_configure(priv, &antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
-		CLEAR_BIT(priv->set_mask, GETSET_ANTENNA);
-	}
-
-	if (priv->set_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
-		/* ed_threshold */
-		acxlog(L_INIT, "updating Energy Detect (ED) threshold: %u\n",
-					priv->ed_threshold);
-		if (CHIPTYPE_ACX100 == priv->chip_type) {
-			u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
-
-			memset(ed_threshold, 0, sizeof(ed_threshold));
-			ed_threshold[4] = priv->ed_threshold;
-			acx_s_configure(priv, &ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
-		}
-		else
-			acxlog(L_INIT, "ACX111 doesn't support ED!\n");
-		CLEAR_BIT(priv->set_mask, GETSET_ED_THRESH);
-	}
-
-	if (priv->set_mask & (GETSET_CCA|GETSET_ALL)) {
-		/* CCA value */
-		acxlog(L_INIT, "updating Channel Clear Assessment "
-				"(CCA) value: 0x%02X\n", priv->cca);
-		if (CHIPTYPE_ACX100 == priv->chip_type)	{
-			u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
-
-			memset(cca, 0, sizeof(cca));
-			cca[4] = priv->cca;
-			acx_s_configure(priv, &cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
-		}
-		else
-			acxlog(L_INIT, "acx111 doesn't support CCA!\n");
-		CLEAR_BIT(priv->set_mask, GETSET_CCA);
-	}
-
-	if (priv->set_mask & (GETSET_LED_POWER|GETSET_ALL)) {
-		/* Enable Tx */
-		acxlog(L_INIT, "updating power LED status: %u\n", priv->led_power);
-
-		acx_lock(priv, flags);
-		acx_l_power_led(priv, priv->led_power);
-		CLEAR_BIT(priv->set_mask, GETSET_LED_POWER);
-		acx_unlock(priv, flags);
-	}
-
-/* this seems to cause Tx lockup after some random time (Tx error 0x20),
- * so let's disable it for now until further investigation */
-/* Maybe fixed now after locking is fixed. Need to retest */
-#if POWER_SAVE_80211
-	if (priv->set_mask & (GETSET_POWER_80211|GETSET_ALL)) {
-		acx100_ie_powermgmt_t pm;
-
-		/* change 802.11 power save mode settings */
-		acxlog(L_INIT, "updating 802.11 power save mode settings: "
-			"wakeup_cfg 0x%02X, listen interval %u, "
-			"options 0x%02X, hangover period %u, "
-			"enhanced_ps_transition_time %d\n",
-			priv->ps_wakeup_cfg, priv->ps_listen_interval,
-			priv->ps_options, priv->ps_hangover_period,
-			priv->ps_enhanced_transition_time);
-		acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
-		acxlog(L_INIT, "Previous PS mode settings: wakeup_cfg 0x%02X, "
-			"listen interval %u, options 0x%02X, "
-			"hangover period %u, "
-			"enhanced_ps_transition_time %d\n",
-			pm.wakeup_cfg, pm.listen_interval, pm.options,
-			pm.hangover_period, pm.enhanced_ps_transition_time);
-		pm.wakeup_cfg = priv->ps_wakeup_cfg;
-		pm.listen_interval = priv->ps_listen_interval;
-		pm.options = priv->ps_options;
-		pm.hangover_period = priv->ps_hangover_period;
-		pm.enhanced_ps_transition_time = cpu_to_le16(priv->ps_enhanced_transition_time);
-		acx_s_configure(priv, &pm, ACX100_IE_POWER_MGMT);
-		acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
-		acxlog(L_INIT, "wakeup_cfg: 0x%02X\n", pm.wakeup_cfg);
-		acx_s_msleep(40);
-		acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
-		acxlog(L_INIT, "power save mode change %s\n",
-			(pm.wakeup_cfg & PS_CFG_PENDING) ? "FAILED" : "was successful");
-		/* FIXME: maybe verify via PS_CFG_PENDING bit here
-		 * that power save mode change was successful. */
-		/* FIXME: we shouldn't trigger a scan immediately after
-		 * fiddling with power save mode (since the firmware is sending
-		 * a NULL frame then). Does this need locking?? */
-		CLEAR_BIT(priv->set_mask, GETSET_POWER_80211);
-	}
-#endif
-
-	if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
-		/* channel */
-		acxlog(L_INIT, "updating channel to: %u\n", priv->channel);
-		CLEAR_BIT(priv->set_mask, GETSET_CHANNEL);
-	}
-
-	if (priv->set_mask & (GETSET_TX|GETSET_ALL)) {
-		/* set Tx */
-		acxlog(L_INIT, "updating: %s Tx\n",
-				priv->tx_disabled ? "disable" : "enable");
-		if (priv->tx_disabled)
-			acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
-			/*                                                 ^ */
-			/* FIXME: this used to be 1, but since we don't transfer a parameter... */
-		else
-			acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1);
-		CLEAR_BIT(priv->set_mask, GETSET_TX);
-	}
-
-	if (priv->set_mask & (GETSET_RX|GETSET_ALL)) {
-		/* Enable Rx */
-		acxlog(L_INIT, "updating: enable Rx on channel: %u\n",
-				priv->channel);
-		acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1);
-		CLEAR_BIT(priv->set_mask, GETSET_RX);
-	}
-
-	if (priv->set_mask & (GETSET_RETRY|GETSET_ALL)) {
-		u8 short_retry[4 + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN];
-		u8 long_retry[4 + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN];
-
-		acxlog(L_INIT, "updating short retry limit: %u, long retry limit: %u\n",
-					priv->short_retry, priv->long_retry);
-		short_retry[0x4] = priv->short_retry;
-		long_retry[0x4] = priv->long_retry;
-		acx_s_configure(priv, &short_retry, ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT);
-		acx_s_configure(priv, &long_retry, ACX1xx_IE_DOT11_LONG_RETRY_LIMIT);
-		CLEAR_BIT(priv->set_mask, GETSET_RETRY);
-	}
-
-	if (priv->set_mask & (SET_MSDU_LIFETIME|GETSET_ALL)) {
-		u8 xmt_msdu_lifetime[4 + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN];
-
-		acxlog(L_INIT, "updating tx MSDU lifetime: %u\n",
-					priv->msdu_lifetime);
-		*(u32 *)&xmt_msdu_lifetime[4] = cpu_to_le32((u32)priv->msdu_lifetime);
-		acx_s_configure(priv, &xmt_msdu_lifetime, ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME);
-		CLEAR_BIT(priv->set_mask, SET_MSDU_LIFETIME);
-	}
-
-	if (priv->set_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
-		/* reg_domain */
-		acx_ie_generic_t dom;
-		unsigned mask;
-
-		acxlog(L_INIT, "updating regulatory domain: 0x%02X\n",
-					priv->reg_dom_id);
-		for (i = 0; i < sizeof(reg_domain_ids); i++)
-			if (reg_domain_ids[i] == priv->reg_dom_id)
-				break;
-
-		if (sizeof(reg_domain_ids) == i) {
-			acxlog(L_INIT, "Invalid or unsupported regulatory "
-				"domain 0x%02X specified, falling back to "
-				"FCC (USA)! Please report if this sounds "
-				"fishy!\n", priv->reg_dom_id);
-			i = 0;
-			priv->reg_dom_id = reg_domain_ids[i];
-		}
-
-		priv->reg_dom_chanmask = reg_domain_channel_masks[i];
-		dom.m.bytes[0] = priv->reg_dom_id;
-		acx_s_configure(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
-
-		mask = (1 << (priv->channel - 1));
-		if (!(priv->reg_dom_chanmask & mask)) {
-		/* hmm, need to adjust our channel to reside within domain */
-			mask = 1;
-			for (i = 1; i <= 14; i++) {
-				if (priv->reg_dom_chanmask & mask) {
-					printk("%s: adjusting "
-						"selected channel from %d "
-						"to %d due to new regulatory "
-						"domain\n", priv->netdev->name,
-						priv->channel, i);
-					priv->channel = i;
-					break;
-				}
-				mask <<= 1;
-			}
-		}
-		CLEAR_BIT(priv->set_mask, GETSET_REG_DOMAIN);
-	}
-
-	if (priv->set_mask & (GETSET_MODE|GETSET_ALL)) {
-		priv->netdev->type = ARPHRD_ETHER;
-
-		switch (priv->mode) {
-		case ACX_MODE_3_AP:
-
-			acx_lock(priv, flags);
-			acx_l_sta_list_init(priv);
-			priv->aid = 0;
-			priv->ap_client = NULL;
-			MAC_COPY(priv->bssid, priv->dev_addr);
-			/* this basically says "we're connected" */
-			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-			acx_unlock(priv, flags);
-
-			acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
-			/* start sending beacons */
-			acx_s_cmd_join_bssid(priv, priv->bssid);
-			break;
-		case ACX_MODE_MONITOR:
-			/* TODO: what exactly do we want here? */
-			/* priv->netdev->type = ARPHRD_ETHER; */
-			/* priv->netdev->type = ARPHRD_IEEE80211; */
-			priv->netdev->type = ARPHRD_IEEE80211_PRISM;
-			acx111_s_feature_on(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
-			/* this stops beacons */
-			acx_s_cmd_join_bssid(priv, priv->bssid);
-			/* this basically says "we're connected" */
-			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-			SET_BIT(priv->set_mask, SET_RXCONFIG|SET_WEP_OPTIONS);
-			break;
-		case ACX_MODE_0_ADHOC:
-		case ACX_MODE_2_STA:
-			acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
-			priv->aid = 0;
-			priv->ap_client = NULL;
-			/* we want to start looking for peer or AP */
-			start_scan = 1;
-			break;
-		case ACX_MODE_OFF:
-			/* TODO: disable RX/TX, stop any scanning activity etc: */
-			/* priv->tx_disabled = 1; */
-			/* SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX); */
-
-			/* This stops beacons (invalid macmode...) */
-			acx_s_cmd_join_bssid(priv, priv->bssid);
-			acx_set_status(priv, ACX_STATUS_0_STOPPED);
-			break;
-		}
-		CLEAR_BIT(priv->set_mask, GETSET_MODE);
-	}
-
-	if (priv->set_mask & (SET_RXCONFIG|GETSET_ALL)) {
-		acx_s_initialize_rx_config(priv);
-		CLEAR_BIT(priv->set_mask, SET_RXCONFIG);
-	}
-
-	if (priv->set_mask & (GETSET_RESCAN|GETSET_ALL)) {
-		switch (priv->mode) {
-		case ACX_MODE_0_ADHOC:
-		case ACX_MODE_2_STA:
-			start_scan = 1;
-			break;
-		}
-		CLEAR_BIT(priv->set_mask, GETSET_RESCAN);
-	}
-
-	if (priv->set_mask & (GETSET_WEP|GETSET_ALL)) {
-		/* encode */
-
-		ie_dot11WEPDefaultKeyID_t dkey;
-#if DEBUG_WEP
-		struct {
-			u16 type ACX_PACKED;
-			u16 len ACX_PACKED;
-			u8  val ACX_PACKED;
-		} keyindic;
-#endif
-		acxlog(L_INIT, "updating WEP key settings\n");
-
-		acx_s_set_wepkey(priv);
-
-		dkey.KeyID = priv->wep_current_index;
-		acxlog(L_INIT, "setting WEP key %u as default\n", dkey.KeyID);
-		acx_s_configure(priv, &dkey, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET);
-#if DEBUG_WEP
-		keyindic.val = 3;
-		acx_s_configure(priv, &keyindic, ACX111_IE_KEY_CHOOSE);
-#endif
-		start_scan = 1;
-		CLEAR_BIT(priv->set_mask, GETSET_WEP);
-	}
-
-	if (priv->set_mask & (SET_WEP_OPTIONS|GETSET_ALL)) {
-		acx100_ie_wep_options_t options;
-
-		if (priv->chip_type == CHIPTYPE_ACX111) {
-			acxlog(L_DEBUG, "setting WEP Options for ACX111 is not supported\n");
-		} else {
-			acxlog(L_INIT, "setting WEP Options\n");
-
-			/* let's choose maximum setting: 4 default keys,
-			 * plus 10 other keys: */
-			options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
-			/* don't decrypt default key only,
-			 * don't override decryption: */
-			options.WEPOption = 0;
-			if (priv->mode == ACX_MODE_MONITOR) {
-				/* don't decrypt default key only,
-				 * override decryption mechanism: */
-				options.WEPOption = 2;
-			}
-
-			acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
-		}
-		CLEAR_BIT(priv->set_mask, SET_WEP_OPTIONS);
-	}
-
-	/* Rescan was requested */
-	if (start_scan) {
-		switch (priv->mode) {
-		case ACX_MODE_0_ADHOC:
-		case ACX_MODE_2_STA:
-			/* We can avoid clearing list if join code
-			** will be a bit more clever about not picking
-			** 'bad' AP over and over again */
-			acx_lock(priv, flags);
-			priv->ap_client = NULL;
-			acx_l_sta_list_init(priv);
-			acx_set_status(priv, ACX_STATUS_1_SCANNING);
-			acx_unlock(priv, flags);
-
-			acx_s_cmd_start_scan(priv);
-		}
-	}
-
-	/* debug, rate, and nick don't need any handling */
-	/* what about sniffing mode?? */
-
-	acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X - after update\n",
-			priv->get_mask, priv->set_mask);
-
-/* end: */
-	FN_EXIT0;
-}
-
-
-/***********************************************************************
-*/
-void
-acx_s_initialize_rx_config(wlandevice_t *priv)
-{
-	struct {
-		u16	id ACX_PACKED;
-		u16	len ACX_PACKED;
-		u16	rx_cfg1 ACX_PACKED;
-		u16	rx_cfg2 ACX_PACKED;
-	} cfg;
-
-	switch (priv->mode) {
-	case ACX_MODE_OFF:
-		priv->rx_config_1 = (u16) (0
-			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
-			/* | RX_CFG1_FILTER_SSID	*/
-			/* | RX_CFG1_FILTER_BCAST	*/
-			/* | RX_CFG1_RCV_MC_ADDR1	*/
-			/* | RX_CFG1_RCV_MC_ADDR0	*/
-			/* | RX_CFG1_FILTER_ALL_MULTI	*/
-			/* | RX_CFG1_FILTER_BSSID	*/
-			/* | RX_CFG1_FILTER_MAC		*/
-			/* | RX_CFG1_RCV_PROMISCUOUS	*/
-			/* | RX_CFG1_INCLUDE_FCS	*/
-			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
-			);
-		priv->rx_config_2 = (u16) (0
-			/*| RX_CFG2_RCV_ASSOC_REQ	*/
-			/*| RX_CFG2_RCV_AUTH_FRAMES	*/
-			/*| RX_CFG2_RCV_BEACON_FRAMES	*/
-			/*| RX_CFG2_RCV_CONTENTION_FREE	*/
-			/*| RX_CFG2_RCV_CTRL_FRAMES	*/
-			/*| RX_CFG2_RCV_DATA_FRAMES	*/
-			/*| RX_CFG2_RCV_BROKEN_FRAMES	*/
-			/*| RX_CFG2_RCV_MGMT_FRAMES	*/
-			/*| RX_CFG2_RCV_PROBE_REQ	*/
-			/*| RX_CFG2_RCV_PROBE_RESP	*/
-			/*| RX_CFG2_RCV_ACK_FRAMES	*/
-			/*| RX_CFG2_RCV_OTHER		*/
-			);
-		break;
-	case ACX_MODE_MONITOR:
-		priv->rx_config_1 = (u16) (0
-			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
-			/* | RX_CFG1_FILTER_SSID	*/
-			/* | RX_CFG1_FILTER_BCAST	*/
-			/* | RX_CFG1_RCV_MC_ADDR1	*/
-			/* | RX_CFG1_RCV_MC_ADDR0	*/
-			/* | RX_CFG1_FILTER_ALL_MULTI	*/
-			/* | RX_CFG1_FILTER_BSSID	*/
-			/* | RX_CFG1_FILTER_MAC		*/
-			| RX_CFG1_RCV_PROMISCUOUS
-			/* | RX_CFG1_INCLUDE_FCS	*/
-			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
-			);
-		priv->rx_config_2 = (u16) (0
-			| RX_CFG2_RCV_ASSOC_REQ
-			| RX_CFG2_RCV_AUTH_FRAMES
-			| RX_CFG2_RCV_BEACON_FRAMES
-			| RX_CFG2_RCV_CONTENTION_FREE
-			| RX_CFG2_RCV_CTRL_FRAMES
-			| RX_CFG2_RCV_DATA_FRAMES
-			| RX_CFG2_RCV_BROKEN_FRAMES
-			| RX_CFG2_RCV_MGMT_FRAMES
-			| RX_CFG2_RCV_PROBE_REQ
-			| RX_CFG2_RCV_PROBE_RESP
-			| RX_CFG2_RCV_ACK_FRAMES
-			| RX_CFG2_RCV_OTHER
-			);
-		break;
-	default:
-		priv->rx_config_1 = (u16) (0
-			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
-			/* | RX_CFG1_FILTER_SSID	*/
-			/* | RX_CFG1_FILTER_BCAST	*/
-			/* | RX_CFG1_RCV_MC_ADDR1	*/
-			/* | RX_CFG1_RCV_MC_ADDR0	*/
-			/* | RX_CFG1_FILTER_ALL_MULTI	*/
-			/* | RX_CFG1_FILTER_BSSID	*/
-			| RX_CFG1_FILTER_MAC
-			/* | RX_CFG1_RCV_PROMISCUOUS	*/
-			/* | RX_CFG1_INCLUDE_FCS	*/
-			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
-			);
-		priv->rx_config_2 = (u16) (0
-			| RX_CFG2_RCV_ASSOC_REQ
-			| RX_CFG2_RCV_AUTH_FRAMES
-			| RX_CFG2_RCV_BEACON_FRAMES
-			| RX_CFG2_RCV_CONTENTION_FREE
-			| RX_CFG2_RCV_CTRL_FRAMES
-			| RX_CFG2_RCV_DATA_FRAMES
-			/*| RX_CFG2_RCV_BROKEN_FRAMES	*/
-			| RX_CFG2_RCV_MGMT_FRAMES
-			| RX_CFG2_RCV_PROBE_REQ
-			| RX_CFG2_RCV_PROBE_RESP
-			/*| RX_CFG2_RCV_ACK_FRAMES	*/
-			| RX_CFG2_RCV_OTHER
-			);
-		break;
-	}
-#if DEBUG_WEP
-	if (CHIPTYPE_ACX100 == priv->chip_type)
-		/* only ACX100 supports that */
-#endif
-		priv->rx_config_1 |= RX_CFG1_INCLUDE_RXBUF_HDR;
-
-	acxlog(L_INIT, "setting RXconfig to %04X:%04X\n",
-			priv->rx_config_1, priv->rx_config_2);
-	cfg.rx_cfg1 = cpu_to_le16(priv->rx_config_1);
-	cfg.rx_cfg2 = cpu_to_le16(priv->rx_config_2);
-	acx_s_configure(priv, &cfg, ACX1xx_IE_RXCONFIG);
-}
-
-
-/***********************************************************************
-** acx_schedule_after_interrupt_task
-**
-** Schedule the call of the after_interrupt method after leaving
-** the interrupt context.
-*/
-void
-acx_schedule_after_interrupt_task(wlandevice_t *priv, unsigned int set_flag)
-{
-	SET_BIT(priv->after_interrupt_jobs, set_flag);
-	SCHEDULE_WORK(&priv->after_interrupt_task);
-}
-
-
-/***********************************************************************
-** Helper
-*/
-static void
-acx_s_after_interrupt_recalib(wlandevice_t *priv)
-{
-	int res;
-
-	/* this helps with ACX100 at least;
-	 * hopefully ACX111 also does a
-	 * recalibration here */
-
-	/* clear flag beforehand, since we want to make sure
-	 * it's cleared; then only set it again on specific circumstances */
-	CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-
-	/* better wait a bit between recalibrations to
-	 * prevent overheating due to torturing the card
-	 * into working too long despite high temperature
-	 * (just a safety measure) */
-	if (priv->recalib_time_last_success
-	 && time_before(jiffies, priv->recalib_time_last_success
-					+ RECALIB_PAUSE * 60 * HZ)) {
-		priv->recalib_msg_ratelimit++;
-		if (priv->recalib_msg_ratelimit <= 5)
-			printk("%s: less than " STRING(RECALIB_PAUSE)
-				" minutes since last radio recalibration, "
-				"not recalibrating (maybe card is too hot?)\n",
-				priv->netdev->name);
-		if (priv->recalib_msg_ratelimit == 5)
-			printk("disabling above message\n");
-		return;
-	}
-
-	priv->recalib_msg_ratelimit = 0;
-
-	/* note that commands sometimes fail (card busy),
-	 * so only clear flag if we were fully successful */
-	res = acx_s_recalib_radio(priv);
-	if (res == OK) {
-		printk("%s: successfully recalibrated radio\n",
-						priv->netdev->name);
-		priv->recalib_time_last_success = jiffies;
-		priv->recalib_failure_count = 0;
-	} else {
-		/* failed: resubmit, but only limited
-		 * amount of times within some time range
-		 * to prevent endless loop */
-
-		priv->recalib_time_last_success = 0; /* we failed */
-
-		/* if some time passed between last
-		 * attempts, then reset failure retry counter
-		 * to be able to do next recalib attempt */
-		if (time_after(jiffies, priv->recalib_time_last_attempt + HZ))
-			priv->recalib_failure_count = 0;
-
-		if (++priv->recalib_failure_count <= 5) {
-			priv->recalib_time_last_attempt = jiffies;
-			acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-		}
-	}
-}
-
-/***********************************************************************
-** acx_e_after_interrupt_task
-*/
-static void
-acx_e_after_interrupt_task(void *data)
-{
-	netdevice_t *dev = (netdevice_t *) data;
-	wlandevice_t *priv;
-
-	FN_ENTER;
-
-	priv = (struct wlandevice *) dev->priv;
-
-	acx_sem_lock(priv);
-
-	if (!priv->after_interrupt_jobs)
-		goto end; /* no jobs to do */
-
-#if TX_CLEANUP_IN_SOFTIRQ
-	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_TX_CLEANUP) {
-		acx_lock(priv, flags);
-		acx_l_clean_tx_desc(priv);
-		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_TX_CLEANUP);
-		acx_unlock(priv, flags);
-	}
-#endif
-	/* we see lotsa tx errors */
-	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_RADIO_RECALIB) {
-		acx_s_after_interrupt_recalib(priv);
-	}
-
-	/* a poor interrupt code wanted to do update_card_settings() */
-	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_UPDATE_CARD_CFG) {
-		if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
-			acx_s_update_card_settings(priv, 0, 0);
-		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
-	}
-
-	/* 1) we detected that no Scan_Complete IRQ came from fw, or
-	** 2) we found too many STAs */
-	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_STOP_SCAN) {
-		acxlog(L_IRQ, "sending a stop scan cmd...\n");
-		acx_s_issue_cmd(priv, ACX1xx_CMD_STOP_SCAN, NULL, 0);
-		/* HACK: set the IRQ bit, since we won't get a
-		 * scan complete IRQ any more on ACX111 (works on ACX100!),
-		 * since _we_, not a fw, have stopped the scan */
-		SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
-		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_STOP_SCAN);
-	}
-
-	/* either fw sent Scan_Complete or we detected that
-	** no Scan_Complete IRQ came from fw. Finish scanning,
-	** pick join partner if any */
-	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_COMPLETE_SCAN) {
-		if (priv->status == ACX_STATUS_1_SCANNING) {
-			if (OK != acx_s_complete_scan(priv)) {
-				SET_BIT(priv->after_interrupt_jobs,
-					ACX_AFTER_IRQ_RESTART_SCAN);
-			}
-		} else {
-			/* + scan kills current join status - restore it
-			**   (do we need it for STA?) */
-			/* + does it happen only with active scans?
-			**   active and passive scans? ALL scans including
-			**   background one? */
-			/* + was not verified that everything is restored
-			**   (but at least we start to emit beacons again) */
-			switch (priv->mode) {
-			case ACX_MODE_0_ADHOC:
-			case ACX_MODE_3_AP:
-				acxlog(L_IRQ, "redoing cmd_join_bssid() after scan\n");
-				acx_s_cmd_join_bssid(priv, priv->bssid);
-			}
-		}
-		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_COMPLETE_SCAN);
-	}
-
-	/* STA auth or assoc timed out, start over again */
-	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_RESTART_SCAN) {
-		acxlog(L_IRQ, "sending a start_scan cmd...\n");
-		acx_s_cmd_start_scan(priv);
-		CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_RESTART_SCAN);
-	}
-
-	/* whee, we got positive assoc response! 8) */
-	if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_ASSOCIATE) {
-		acx_ie_generic_t pdr;
-		/* tiny race window exists, checking that we still a STA */
-		switch (priv->mode) {
-		case ACX_MODE_2_STA:
-			pdr.m.aid = cpu_to_le16(priv->aid);
-			acx_s_configure(priv, &pdr, ACX1xx_IE_ASSOC_ID);
-			acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-			acxlog(L_ASSOC | L_DEBUG, "ASSOCIATED!\n");
-			CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_ASSOCIATE);
-		}
-	}
-end:
-	acx_sem_unlock(priv);
-	FN_EXIT0;
-}
-
-
-/***********************************************************************
-*/
-void
-acx_init_task_scheduler(wlandevice_t *priv)
-{
-	/* configure task scheduler */
-	INIT_WORK(&priv->after_interrupt_task, acx_e_after_interrupt_task, priv->netdev);
-}
-
-
-/***********************************************************************
-** acx_cmd_join_bssid
-**
-** Common code for both acx100 and acx111.
-*/
-/* NB: does NOT match RATE100_nn but matches ACX[111]_SCAN_RATE_n */
-static const u8
-bitpos2genframe_txrate[] = {
-	10,	/*  0.  1 Mbit/s */
-	20,	/*  1.  2 Mbit/s */
-	55,	/*  2.  5.5 Mbit/s */
-	0x0B,	/*  3.  6 Mbit/s */
-	0x0F,	/*  4.  9 Mbit/s */
-	110,	/*  5. 11 Mbit/s */
-	0x0A,	/*  6. 12 Mbit/s */
-	0x0E,	/*  7. 18 Mbit/s */
-	220,	/*  8. 22 Mbit/s */
-	0x09,	/*  9. 24 Mbit/s */
-	0x0D,	/* 10. 36 Mbit/s */
-	0x08,	/* 11. 48 Mbit/s */
-	0x0C,	/* 12. 54 Mbit/s */
-	10,	/* 13.  1 Mbit/s, should never happen */
-	10,	/* 14.  1 Mbit/s, should never happen */
-	10,	/* 15.  1 Mbit/s, should never happen */
-};
-
-/* Looks scary, eh?
-** Actually, each one compiled into one AND and one SHIFT,
-** 31 bytes in x86 asm (more if uints are replaced by u16/u8) */
-static unsigned int
-rate111to5bits(unsigned int rate)
-{
-	return (rate & 0x7)
-	| ( (rate & RATE111_11) / (RATE111_11/JOINBSS_RATES_11) )
-	| ( (rate & RATE111_22) / (RATE111_22/JOINBSS_RATES_22) )
-	;
-}
-
-extern void BUG_joinbss_must_be_0x30_bytes_in_length(void);
-
-void
-acx_s_cmd_join_bssid(wlandevice_t *priv, const u8 *bssid)
-{
-	acx_joinbss_t tmp;
-	int dtim_interval;
-	int i;
-
-	/* compile-time check for proper size of fixed-size struct */
-	if (sizeof(acx_joinbss_t) != 0x30)
-		BUG_joinbss_must_be_0x30_bytes_in_length();
-
-	FN_ENTER;
-
-	dtim_interval =	(ACX_MODE_0_ADHOC == priv->mode) ?
-			1 : priv->dtim_interval;
-
-	memset(&tmp, 0, sizeof(tmp));
-
-	for (i = 0; i < ETH_ALEN; i++) {
-		tmp.bssid[i] = bssid[ETH_ALEN-1 - i];
-	}
-
-	tmp.beacon_interval = cpu_to_le16(priv->beacon_interval);
-
-	/* basic rate set. Control frame responses (such as ACK or CTS frames)
-	** are sent with one of these rates */
-	if (CHIPTYPE_ACX111 == priv->chip_type) {
-		/* It was experimentally determined that rates_basic
-		** can take 11g rates as well, not only rates
-		** defined with JOINBSS_RATES_BASIC111_nnn.
-		** Just use RATE111_nnn constants... */
-		tmp.u.acx111.dtim_interval = dtim_interval;
-		tmp.u.acx111.rates_basic = cpu_to_le16(priv->rate_basic);
-		acxlog(L_ASSOC, "%s rates_basic %04X, rates_supported %04X\n",
-			__func__, priv->rate_basic, priv->rate_oper);
-	} else {
-		tmp.u.acx100.dtim_interval = dtim_interval;
-		tmp.u.acx100.rates_basic = rate111to5bits(priv->rate_basic);
-		tmp.u.acx100.rates_supported = rate111to5bits(priv->rate_oper);
-		acxlog(L_ASSOC, "%s rates_basic %04X->%02X, "
-			"rates_supported %04X->%02X\n",
-			__func__,
-			priv->rate_basic, tmp.u.acx100.rates_basic,
-			priv->rate_oper, tmp.u.acx100.rates_supported);
-	}
-
-	/* Setting up how Beacon, Probe Response, RTS, and PS-Poll frames
-	** will be sent (rate/modulation/preamble) */
-	tmp.genfrm_txrate = bitpos2genframe_txrate[lowest_bit(priv->rate_basic)];
-	tmp.genfrm_mod_pre = 0; /* FIXME: was = priv->capab_short (which is always 0); */
-	/* we can use short pre *if* all peers can understand it */
-	/* FIXME #2: we need to correctly set PBCC/OFDM bits here too */
-
-	/* we switch fw to STA mode in MONITOR mode, it seems to be
-	** the only mode where fw does not emit beacons by itself
-	** but allows us to send anything (we really want to retain
-	** ability to tx arbitrary frames in MONITOR mode)
-	*/
-	tmp.macmode = (priv->mode != ACX_MODE_MONITOR ? priv->mode : ACX_MODE_2_STA);
-	tmp.channel = priv->channel;
-	tmp.essid_len = priv->essid_len;
-	/* NOTE: the code memcpy'd essid_len + 1 before, which is WRONG! */
-	memcpy(tmp.essid, priv->essid, tmp.essid_len);
-	acx_s_issue_cmd(priv, ACX1xx_CMD_JOIN, &tmp, tmp.essid_len + 0x11);
-
-	acxlog(L_ASSOC | L_DEBUG, "BSS_Type = %u\n", tmp.macmode);
-	acxlog_mac(L_ASSOC | L_DEBUG, "JoinBSSID MAC:", priv->bssid, "\n");
-
-	acx_update_capabilities(priv);
-	FN_EXIT0;
-}
-
-
-/***********************************************************************
-** acx_s_set_defaults
-** Called from acx_s_init_mac
-*/
-int
-acx_s_set_defaults(wlandevice_t *priv)
-{
-	unsigned long flags;
-
-	FN_ENTER;
-
-	/* query some settings from the card.
-	 * NOTE: for some settings, e.g. CCA and ED (ACX100!), an initial
-	 * query is REQUIRED, otherwise the card won't work correctly!! */
-	priv->get_mask = GETSET_ANTENNA|GETSET_SENSITIVITY|GETSET_STATION_ID|GETSET_REG_DOMAIN;
-	/* Only ACX100 supports ED and CCA */
-	if (CHIPTYPE_ACX100 == priv->chip_type)
-		priv->get_mask |= GETSET_CCA|GETSET_ED_THRESH;
-
-	acx_s_update_card_settings(priv, 0, 0);
-
-	acx_lock(priv, flags);
-
-#ifdef ACX_PCI
-	/* set our global interrupt mask */
-	if (priv->chip_type == CHIPTYPE_ACX111) {
-		priv->irq_mask = (u16) ~(0
-				/* | HOST_INT_RX_DATA        */
-				| HOST_INT_TX_COMPLETE
-				/* | HOST_INT_TX_XFER        */
-				| HOST_INT_RX_COMPLETE
-				/* | HOST_INT_DTIM           */
-				/* | HOST_INT_BEACON         */
-				/* | HOST_INT_TIMER          */
-				/* | HOST_INT_KEY_NOT_FOUND  */
-				| HOST_INT_IV_ICV_FAILURE
-				| HOST_INT_CMD_COMPLETE
-				| HOST_INT_INFO
-				/* | HOST_INT_OVERFLOW       */
-				/* | HOST_INT_PROCESS_ERROR  */
-				| HOST_INT_SCAN_COMPLETE
-				| HOST_INT_FCS_THRESHOLD
-				/* | HOST_INT_UNKNOWN        */
-				);
-		priv->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */
-	} else {
-		priv->irq_mask = (u16) ~(0
-				/* | HOST_INT_RX_DATA        */
-				| HOST_INT_TX_COMPLETE
-				/* | HOST_INT_TX_XFER        */
-				| HOST_INT_RX_COMPLETE
-				/* | HOST_INT_DTIM           */
-				/* | HOST_INT_BEACON         */
-				/* | HOST_INT_TIMER          */
-				/* | HOST_INT_KEY_NOT_FOUND  */
-				/* | HOST_INT_IV_ICV_FAILURE */
-				| HOST_INT_CMD_COMPLETE
-				| HOST_INT_INFO
-				/* | HOST_INT_OVERFLOW       */
-				/* | HOST_INT_PROCESS_ERROR  */
-				| HOST_INT_SCAN_COMPLETE
-				/* | HOST_INT_FCS_THRESHOLD  */
-				/* | HOST_INT_UNKNOWN        */
-				);
-		priv->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */
-	}
-#endif
-
-	priv->led_power = 1; /* LED is active on startup */
-	priv->brange_max_quality = 60; /* LED blink max quality is 60 */
-	priv->brange_time_last_state_change = jiffies;
-
-	/* copy the MAC address we just got from the card
-	 * into our MAC address used during current 802.11 session */
-	MAC_COPY(priv->dev_addr, priv->netdev->dev_addr);
-	sprintf(priv->essid, "STA%02X%02X%02X",
-		priv->dev_addr[3], priv->dev_addr[4], priv->dev_addr[5]);
-	priv->essid_len = sizeof("STAxxxxxx") - 1; /* make sure to adapt if changed above! */
-	priv->essid_active = 1;
-
-	/* we have a nick field to waste, so why not abuse it
-	 * to announce the driver version? ;-) */
-	strncpy(priv->nick, "acx " WLAN_RELEASE, IW_ESSID_MAX_SIZE);
-
-#ifdef ACX_PCI
-	if (priv->chip_type == CHIPTYPE_ACX111) {
-		/* Hope this is correct, only tested with domain 0x30 */
-		acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
-	} else if (priv->eeprom_version < 5) {
-		acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
-	} else {
-		acx_read_eeprom_offset(priv, 0x171, &priv->reg_dom_id);
-	}
-#endif
-
-	priv->channel = 1;
-	/* 0xffff would be better, but then we won't get a "scan complete"
-	 * interrupt, so our current infrastructure will fail: */
-	priv->scan_count = 1;
-	priv->scan_mode = ACX_SCAN_OPT_PASSIVE;
-	/* Doesn't work for acx100, do it only for acx111 for now */
-	if (priv->chip_type == CHIPTYPE_ACX111) {
-		priv->scan_mode = ACX_SCAN_OPT_ACTIVE;
-	}
-	priv->scan_duration = 100;
-	priv->scan_probe_delay = 200;
-	priv->scan_rate = ACX_SCAN_RATE_1;
-
-	priv->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
-	priv->preamble_mode = 2; /* auto */
-	priv->listen_interval = 100;
-	priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
-	priv->mode = ACX_MODE_OFF;
-	priv->dtim_interval = DEFAULT_DTIM_INTERVAL;
-
-	priv->msdu_lifetime = DEFAULT_MSDU_LIFETIME;
-	SET_BIT(priv->set_mask, SET_MSDU_LIFETIME);
-
-	priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
+	priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
 
 	/* use standard default values for retry limits */
 	priv->short_retry = 7; /* max. retries for (short) non-RTS packets */
@@ -4011,7 +864,7 @@ acx_s_set_defaults(wlandevice_t *priv)
 	priv->rate_bcast100 = RATE100_1;
 	priv->rate_basic = RATE111_1 | RATE111_2;
 	priv->rate_auto = 1;
-	if (priv->chip_type == CHIPTYPE_ACX111) {
+	if (IS_ACX111(priv)) {
 		priv->rate_oper = RATE111_ALL;
 	} else {
 		priv->rate_oper = RATE111_ACX100_COMPAT;
@@ -4031,7 +884,7 @@ acx_s_set_defaults(wlandevice_t *priv)
 	SET_BIT(priv->set_mask, SET_RXCONFIG);
 
 	/* set some more defaults */
-	if (priv->chip_type == CHIPTYPE_ACX111) {
+	if (IS_ACX111(priv)) {
 		/* 30mW (15dBm) is default, at least in my acx111 card: */
 		priv->tx_level_dbm = 15;
 	} else {
@@ -4040,10 +893,10 @@ acx_s_set_defaults(wlandevice_t *priv)
 		 * excessive Tx power damage!) */
 		priv->tx_level_dbm = 18;
 	}
-	priv->tx_level_auto = 1;
+	/* priv->tx_level_auto = 1; */
 	SET_BIT(priv->set_mask, GETSET_TXPOWER);
 
-	if (priv->chip_type == CHIPTYPE_ACX111) {
+	if (IS_ACX111(priv)) {
 		/* start with sensitivity level 1 out of 3: */
 		priv->sensitivity = 1;
 	}
@@ -4056,7 +909,7 @@ acx_s_set_defaults(wlandevice_t *priv)
 	priv->ps_options = 0;
 	priv->ps_hangover_period = 0;
 	priv->ps_enhanced_transition_time = 0;
-#if POWER_SAVE_80211
+#ifdef POWER_SAVE_80211
 	SET_BIT(priv->set_mask, GETSET_POWER_80211);
 #endif
 
@@ -4073,6 +926,69 @@ acx_s_set_defaults(wlandevice_t *priv)
 
 
 /***********************************************************************
+** FIXME: this should be solved in a general way for all radio types
+** by decoding the radio firmware module,
+** since it probably has some standard structure describing how to
+** set the power level of the radio module which it controls.
+** Or maybe not, since the radio module probably has a function interface
+** instead which then manages Tx level programming :-\
+*/
+static int
+acx111_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
+{
+	struct ACX111TxLevel tx_level;
+
+	/* my acx111 card has two power levels in its configoptions (== EEPROM):
+	 * 1 (30mW) [15dBm]
+	 * 2 (10mW) [10dBm]
+	 * For now, just assume all other acx111 cards have the same.
+	 * Ideally we would query it here, but we first need a
+	 * standard way to query individual configoptions easily. */
+	if (level_dbm <= 12) {
+		tx_level.level = 2; /* 10 dBm */
+		priv->tx_level_dbm = 10;
+	} else {
+		tx_level.level = 1; /* 15 dBm */
+		priv->tx_level_dbm = 15;
+	}
+	if (level_dbm != priv->tx_level_dbm)
+		acxlog(L_INIT, "ACX111 firmware has specific "
+			"power levels only: adjusted %d dBm to %d dBm!\n",
+			level_dbm, priv->tx_level_dbm);
+
+	return acx_s_configure(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
+}
+
+int
+acx_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
+{
+	if (IS_ACX111(priv)) {
+		return acx111_s_set_tx_level(priv, level_dbm);
+	}
+	if (IS_PCI(priv)) {
+		return acx100_s_set_tx_level(priv, level_dbm);
+	}
+	return OK;
+}
+
+
+/***********************************************************************
+*/
+#ifdef UNUSED
+/* Returns the current tx level (ACX111) */
+static u8
+acx111_s_get_tx_level(wlandevice_t *priv)
+{
+	struct ACX111TxLevel tx_level;
+
+	tx_level.level = 0;
+	acx_s_interrogate(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
+	return tx_level.level;
+}
+#endif
+
+
+/***********************************************************************
 ** acx_s_init_mac
 */
 int
@@ -4083,20 +999,18 @@ acx_s_init_mac(netdevice_t *dev)
 
 	FN_ENTER;
 
-#ifdef ACX_PCI
-	priv->memblocksize = 256; /* 256 is default */
-
-	acx_init_mboxes(priv);
-
-	/* try to load radio for both ACX100 and ACX111, since both
-	 * chips have at least some firmware versions making use of an
-	 * external radio module */
-	acx_s_upload_radio(priv);
-#else
-	priv->memblocksize = 128;
-#endif
+	if (IS_PCI(priv)) {
+		priv->memblocksize = 256; /* 256 is default */
+		acx_init_mboxes(priv);
+		/* try to load radio for both ACX100 and ACX111, since both
+		 * chips have at least some firmware versions making use of an
+		 * external radio module */
+		acx_s_upload_radio(priv);
+	} else {
+		priv->memblocksize = 128;
+	}
 
-	if (priv->chip_type == CHIPTYPE_ACX111) {
+	if (IS_ACX111(priv)) {
 		/* for ACX111, the order is different from ACX100
 		   1. init packet templates
 		   2. create station context and create dma regions
@@ -4110,7 +1024,7 @@ acx_s_init_mac(netdevice_t *dev)
 							dev->name);
 			goto fail;
 		}
-#if DEBUG_WEP
+#ifdef DEBUG_WEP
 		/* don't decrypt WEP in firmware */
 		if (OK != acx111_s_feature_on(priv, 0, FEATURE2_SNIFFER))
 			goto fail;
@@ -4136,169 +1050,3 @@ fail:
 	FN_EXIT1(result);
 	return result;
 }
-
-
-/***********************************************************************
-** acx_s_start
-*/
-void
-acx_s_start(wlandevice_t *priv)
-{
-	FN_ENTER;
-
-	/*
-	 * Ok, now we do everything that can possibly be done with ioctl
-	 * calls to make sure that when it was called before the card
-	 * was up we get the changes asked for
-	 */
-
-	SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST|GETSET_WEP
-		|GETSET_TXPOWER|GETSET_ANTENNA|GETSET_ED_THRESH|GETSET_CCA
-		|GETSET_REG_DOMAIN|GETSET_MODE|GETSET_CHANNEL
-		|GETSET_TX|GETSET_RX);
-
-	acxlog(L_INIT, "updating initial settings on iface activation...\n");
-	acx_s_update_card_settings(priv, 0, 0);
-
-	FN_EXIT0;
-}
-
-
-/***********************************************************************
-** acx_update_capabilities
-*/
-void
-acx_update_capabilities(wlandevice_t *priv)
-{
-	u16 cap = 0;
-
-	switch (priv->mode) {
-	case ACX_MODE_3_AP:
-		SET_BIT(cap, WF_MGMT_CAP_ESS); break;
-	case ACX_MODE_0_ADHOC:
-		SET_BIT(cap, WF_MGMT_CAP_IBSS); break;
-	/* other types of stations do not emit beacons */
-	}
-
-	if (priv->wep_restricted) {
-		SET_BIT(cap, WF_MGMT_CAP_PRIVACY);
-	}
-	if (priv->capab_short) {
-		SET_BIT(cap, WF_MGMT_CAP_SHORT);
-	}
-	if (priv->capab_pbcc) {
-		SET_BIT(cap, WF_MGMT_CAP_PBCC);
-	}
-	if (priv->capab_agility) {
-		SET_BIT(cap, WF_MGMT_CAP_AGILITY);
-	}
-	acxlog(L_DEBUG, "caps updated from 0x%04X to 0x%04X\n",
-				priv->capabilities, cap);
-	priv->capabilities = cap;
-}
-
-#ifdef UNUSED
-/***********************************************************************
-** FIXME: check whether this function is indeed acx111 only,
-** rename ALL relevant definitions to indicate actual card scope!
-*/
-void
-acx111_s_read_configoption(wlandevice_t *priv)
-{
-	acx111_ie_configoption_t co, co2;
-	int i;
-	const u8 *pEle;
-
-	if (OK != acx_s_interrogate(priv, &co, ACX111_IE_CONFIG_OPTIONS) ) {
-		printk("%s: reading ConfigOption FAILED\n", priv->netdev->name);
-		return;
-	};
-	if (!(acx_debug & L_DEBUG))
-		return;
-
-	memcpy(&co2.configoption_fixed, &co.configoption_fixed,
-			sizeof(co.configoption_fixed));
-
-	pEle = (u8 *)&co.configoption_fixed + sizeof(co.configoption_fixed) - 4;
-
-	co2.antennas.type = pEle[0];
-	co2.antennas.len = pEle[1];
-	printk("AntennaID:%02X Len:%02X Data:",
-			co2.antennas.type, co2.antennas.len);
-	for (i = 0; i < pEle[1]; i++) {
-		co2.antennas.list[i] = pEle[i+2];
-		printk("%02X ", pEle[i+2]);
-	}
-	printk("\n");
-
-	pEle += pEle[1] + 2;
-	co2.power_levels.type = pEle[0];
-	co2.power_levels.len = pEle[1];
-	printk("PowerLevelID:%02X Len:%02X Data:",
-			co2.power_levels.type, co2.power_levels.len);
-	for (i = 0; i < pEle[1]*2; i++) {
-		co2.power_levels.list[i] = pEle[i+2];
-		printk("%02X ", pEle[i+2]);
-	}
-	printk("\n");
-
-	pEle += pEle[1]*2 + 2;
-	co2.data_rates.type = pEle[0];
-	co2.data_rates.len = pEle[1];
-	printk("DataRatesID:%02X Len:%02X Data:",
-			co2.data_rates.type, co2.data_rates.len);
-	for (i = 0; i < pEle[1]; i++) {
-		co2.data_rates.list[i] = pEle[i+2];
-		printk("%02X ", pEle[i+2]);
-	}
-	printk("\n");
-
-	pEle += pEle[1] + 2;
-	co2.domains.type = pEle[0];
-	co2.domains.len = pEle[1];
-	printk("DomainID:%02X Len:%02X Data:",
-			co2.domains.type, co2.domains.len);
-	for (i = 0; i < pEle[1]; i++) {
-		co2.domains.list[i] = pEle[i+2];
-		printk("%02X ", pEle[i+2]);
-	}
-	printk("\n");
-
-	pEle += pEle[1] + 2;
-	co2.product_id.type = pEle[0];
-	co2.product_id.len = pEle[1];
-	for (i = 0; i < pEle[1]; i++) {
-		co2.product_id.list[i] = pEle[i+2];
-	}
-	printk("ProductID:%02X Len:%02X Data:%.*s\n",
-			co2.product_id.type, co2.product_id.len,
-			co2.product_id.len, (char *)co2.product_id.list);
-
-	pEle += pEle[1] + 2;
-	co2.manufacturer.type = pEle[0];
-	co2.manufacturer.len = pEle[1];
-	for (i = 0; i < pEle[1]; i++) {
-		co2.manufacturer.list[i] = pEle[i+2];
-	}
-	printk("ManufacturerID:%02X Len:%02X Data:%.*s\n",
-			co2.manufacturer.type, co2.manufacturer.len,
-			co2.manufacturer.len, (char *)co2.manufacturer.list);
-/*
-	printk("EEPROM part:\n");
-	for (i=0; i<58; i++) {
-		printk("%02X =======>  0x%02X\n",
-			    i, (u8 *)co.configoption_fixed.NVSv[i-2]);
-	}
-*/
-}
-#endif
-
-
-/***********************************************************************
-** Not inlined: it's larger than it seems
-*/
-void
-acx_print_mac(const char *head, const u8 *mac, const char *tail)
-{
-	printk("%s"MACSTR"%s", head, MAC(mac), tail);
-}
diff -puN drivers/net/wireless/tiacx/ioctl.c~acx-update drivers/net/wireless/tiacx/ioctl.c
--- 25/drivers/net/wireless/tiacx/ioctl.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/ioctl.c	Fri Sep  9 17:28:49 2005
@@ -232,7 +232,7 @@ acx_ioctl_get_name(
 	wlandevice_t *priv = acx_netdev_priv(dev);
 	static const char * const names[] = { "IEEE 802.11b+/g+", "IEEE 802.11b+" };
 
-	strcpy(cwrq, names[(CHIPTYPE_ACX111 == priv->chip_type) ? 0 : 1]);
+	strcpy(cwrq, names[IS_ACX111(priv) ? 0 : 1]);
 
 	return OK;
 }
@@ -354,6 +354,7 @@ acx_ioctl_set_mode(
 		goto end_unlock;
 	}
 
+	acxlog(L_ASSOC, "new priv->mode=%d\n", priv->mode);
 	SET_BIT(priv->set_mask, GETSET_MODE);
 	result = -EINPROGRESS;
 
@@ -446,9 +447,6 @@ acx_ioctl_get_sens(
  * acx_ioctl_set_ap
  *
  * Sets the MAC address of the AP to associate with
- *
- * Call context: Process
- * STATUS: NEW
  *----------------------------------------------------------------------------*/
 static int
 acx_ioctl_set_ap(
@@ -756,7 +754,7 @@ acx_ioctl_get_scan(
 	}
 #endif
 
-#if ENODATA_TO_BE_USED_AFTER_SCAN_ERROR_ONLY
+#ifdef ENODATA_TO_BE_USED_AFTER_SCAN_ERROR_ONLY
 	if (priv->bss_table_count == 0)	{
 		/* no stations found */
 		result = -ENODATA;
@@ -945,8 +943,7 @@ acx_ioctl_set_rate(
 		int i = VEC_SIZE(acx111_rate_tbl)-1;
 		if (vwrq->value == -1)
 			/* "iwconfig rate auto" --> choose highest */
-			vwrq->value = (CHIPTYPE_ACX100 == priv->chip_type) ?
-						22000000 : 54000000;
+			vwrq->value = IS_ACX100(priv) ?	22000000 : 54000000;
 		while (i >= 0) {
 			if (vwrq->value == acx111_rate_tbl[i]) {
 				txrate_cfg <<= i;
@@ -972,7 +969,7 @@ acx_ioctl_set_rate(
 		txrate_cfg = (txrate_cfg<<1)-1;
 	}
 
-	if (CHIPTYPE_ACX100 == priv->chip_type) {
+	if (IS_ACX100(priv)) {
 		txrate_cfg &= RATE111_ACX100_COMPAT;
 		if (!txrate_cfg) {
 			result = -ENOTSUPP; /* rate is not supported by acx100 */
@@ -994,7 +991,7 @@ acx_ioctl_set_rate(
 		priv->rate_basic &= RATE111_80211B_COMPAT;
 	}
 	priv->rate_bcast = 1 << lowest_bit(txrate_cfg);
-	if (CHIPTYPE_ACX100 == priv->chip_type)
+	if (IS_ACX100(priv))
 		priv->rate_bcast100 = acx_rate111to100(priv->rate_bcast);
 	acx_l_update_ratevector(priv);
 	acx_l_update_client_rates(priv, txrate_cfg);
@@ -1347,12 +1344,12 @@ acx_ioctl_set_txpow(
 			priv->tx_level_dbm = 0;
 			acxlog(L_IOCTL, "disable radio tx\n");
 		} else {
-			priv->tx_level_auto = 1;
+			/* priv->tx_level_auto = 1; */
 			acxlog(L_IOCTL, "set tx power auto (NIY)\n");
 		}
 	} else {
 		priv->tx_level_dbm = vwrq->value <= 20 ? vwrq->value : 20;
-		priv->tx_level_auto = 0;
+		/* priv->tx_level_auto = 0; */
 		acxlog(L_IOCTL, "set txpower=%d dBm\n", priv->tx_level_dbm);
 	}
 	SET_BIT(priv->set_mask, GETSET_TXPOWER);
@@ -1431,7 +1428,7 @@ acx_ioctl_get_range(
 		/* FIXME: lifetime ranges and orders of magnitude are strange?? */
 		range->max_r_time = 65535;
 
-		if (CHIPTYPE_ACX111 == priv->chip_type)
+		if (IS_ACX111(priv))
 			range->sensitivity = 3;
 		else
 			range->sensitivity = 255;
@@ -1466,8 +1463,6 @@ acx_ioctl_get_range(
 /*----------------------------------------------------------------
 * acx_ioctl_get_iw_priv
 *
-*
-* STATUS: FINISHED
 * Comment: I added the monitor mode and changed the stuff below
 * to look more like the orinoco driver
 *----------------------------------------------------------------*/
@@ -1676,8 +1671,6 @@ acx_ioctl_set_debug(
 /*----------------------------------------------------------------
 * acx_ioctl_list_reg_domain
 *----------------------------------------------------------------*/
-extern const u8 reg_domain_ids[];
-extern const u8 reg_domain_ids_len;
 static const char * const
 reg_domain_strings[] = {
 	" 1-11 FCC (USA)",
@@ -2030,7 +2023,7 @@ end:
 
 /*----------------------------------------------------------------
 * acx_ioctl_wlansniff
-* STATUS: NEW
+*
 * can we just remove this in favor of monitor mode? --vda
 *----------------------------------------------------------------*/
 static int
@@ -2094,6 +2087,7 @@ acx_ioctl_unknown11(
 	struct iw_param *vwrq,
 	char *extra)
 {
+#ifdef BROKEN
 	wlandevice_t *priv = acx_netdev_priv(dev);
 	unsigned long flags;
 	client_t client;
@@ -2109,6 +2103,8 @@ acx_ioctl_unknown11(
 	acx_sem_unlock(priv);
 
 	return result;
+#endif
+	return -EINVAL;
 }
 
 
@@ -2271,7 +2267,7 @@ acx_ioctl_set_rates(struct net_device *d
 	** For beacons, we probably shall use lowest basic rate
 	** because we want to reach all *potential* new peers too */
 	priv->rate_bcast = 1 << lowest_bit(brate);
-	if (CHIPTYPE_ACX100 == priv->chip_type)
+	if (IS_ACX100(priv))
 		priv->rate_bcast100 = acx_rate111to100(priv->rate_bcast);
 	priv->rate_auto = !has_only_one_bit(orate);
 	acx_l_update_client_rates(priv, orate);
@@ -2311,7 +2307,8 @@ acx_ioctl_get_phy_chan_busy_percentage(
 	acx_sem_lock(priv);
 
 	if (OK != acx_s_interrogate(priv, &usage, ACX1xx_IE_MEDIUM_USAGE))
-		return NOT_OK;
+		goto bad_unlock;
+
 	printk("%s: average busy percentage since last invocation: %d%% "
 		"(microseconds: %u of %u)\n",
 		dev->name,
@@ -2322,6 +2319,11 @@ acx_ioctl_get_phy_chan_busy_percentage(
 	acx_sem_unlock(priv);
 
 	return OK;
+
+bad_unlock:
+	acx_sem_unlock(priv);
+
+	return NOT_OK;
 }
 
 
@@ -2520,6 +2522,38 @@ acx100_ioctl_get_led_power(
 
 /***********************************************************************
 */
+static int
+acx111_ioctl_info(
+	struct net_device *dev,
+	struct iw_request_info *info,
+	struct iw_param *vwrq,
+	char *extra)
+{
+	if (!IS_PCI((wlandevice_t*)acx_netdev_priv(dev)))
+		return OK;
+	return acx111pci_ioctl_info(dev, info, vwrq, extra);
+}
+
+
+/***********************************************************************
+*/
+static int
+acx100_ioctl_set_phy_amp_bias(
+	struct net_device *dev,
+	struct iw_request_info *info,
+	struct iw_param *vwrq,
+	char *extra)
+{
+	if (!IS_PCI((wlandevice_t*)acx_netdev_priv(dev))) {
+		printk("acx: set_phy_amp_bias() is not supported on USB\n");
+		return OK;
+	}
+	return acx100pci_ioctl_set_phy_amp_bias(dev, info, vwrq, extra);
+}
+
+
+/***********************************************************************
+*/
 #if WIRELESS_EXT >= 13
 static const iw_handler acx_ioctl_handler[] =
 {
@@ -2617,8 +2651,6 @@ static const iw_handler acx_ioctl_privat
 [ACX100_IOCTL_TEST		- ACX100_IOCTL] = (iw_handler) acx_ioctl_unknown11,
 [ACX100_IOCTL_DBG_SET_MASKS	- ACX100_IOCTL] = (iw_handler) acx_ioctl_dbg_set_masks,
 [ACX111_IOCTL_INFO		- ACX100_IOCTL] = (iw_handler) acx111_ioctl_info,
-[ACX100_IOCTL_DBG_SET_IO	- ACX100_IOCTL] = (iw_handler) acx_ioctl_dbg_set_io,
-[ACX100_IOCTL_DBG_GET_IO	- ACX100_IOCTL] = (iw_handler) acx_ioctl_dbg_get_io,
 };
 
 const struct iw_handler_def acx_ioctl_handler_def =
@@ -2641,9 +2673,6 @@ const struct iw_handler_def acx_ioctl_ha
 /*----------------------------------------------------------------
 * acx_e_ioctl_old
 *
-*
-* STATUS: FINISHED
-*
 * Comment:
 * This is the *OLD* ioctl handler.
 * Make sure to not only place your additions here, but instead mainly
diff -puN drivers/net/wireless/tiacx/Kconfig~acx-update drivers/net/wireless/tiacx/Kconfig
--- 25/drivers/net/wireless/tiacx/Kconfig~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/Kconfig	Fri Sep  9 17:28:49 2005
@@ -1,6 +1,6 @@
-config TIACX
+config ACX
 	tristate "TI acx100/acx111 802.11b/g wireless chipsets"
-	depends on NET_RADIO && EXPERIMENTAL
+	depends on NET_RADIO && EXPERIMENTAL && FW_LOADER && (USB || PCI)
 	---help---
 	A driver for 802.11b/g wireless cards based on
 	Texas Instruments acx100 and acx111 chipsets.
@@ -35,25 +35,19 @@ config TIACX
 	Texas Instruments did not take part in development of this driver
 	in any way, shape or form.
 
-config TIACX_PCI
-	tristate "TI acx100/acx111 802.11b/g PCI"
-	depends on PCI && TIACX && FW_LOADER
-	---help---
-	A driver for PCI and CardBus incarnations of acx100 and acx111.
-
-	This driver is quite new and experimental.
+	The driver can be compiled as a module and will be named "acx".
 
-	The driver can be compiled as a module and will be named "tiacx_pci".
+config ACX_PCI
+	bool "TI acx100/acx111 802.11b/g PCI"
+	depends on PCI && ACX
+	---help---
+	Include PCI and CardBus support in acx.
 
-config TIACX_USB
-	tristate "TI acx100/acx111 802.11b/g USB"
-	depends on USB && TIACX && FW_LOADER && BROKEN
+config ACX_USB
+	bool "TI acx100/acx111 802.11b/g USB"
+	depends on USB && ACX && BROKEN
 	---help---
-	A driver for USB incarnation of acx100 and acx111.
+	Include USB support in acx.
 
 	There is only one currently known device in this category,
 	D-Link DWL-120+, but newer devices seem to be on the horizon.
-
-	This driver is quite new and experimental.
-
-	The driver can be compiled as a module and will be named "tiacx_usb".
diff -puN drivers/net/wireless/tiacx/Makefile~acx-update drivers/net/wireless/tiacx/Makefile
--- 25/drivers/net/wireless/tiacx/Makefile~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/Makefile	Fri Sep  9 17:28:49 2005
@@ -1,6 +1,6 @@
-tiacx_pci-objs := wlan.o conv.o helper2.o ioctl.o pci.o pci_helper.o
+obj-$(CONFIG_ACX) += acx.o
 
-tiacx_usb-objs := wlan.o conv.o helper2.o ioctl.o usb.o usb_helper.o
+acx-obj-$(CONFIG_ACX_PCI) += pci.o
+acx-obj-$(CONFIG_ACX_USB) += usb.o
 
-obj-$(CONFIG_TIACX_PCI) += tiacx_pci.o
-obj-$(CONFIG_TIACX_USB) += tiacx_usb.o
+acx-objs := wlan.o conv.o ioctl.o helper.o helper2.o $(acx-obj-y)
diff -puN drivers/net/wireless/tiacx/pci.c~acx-update drivers/net/wireless/tiacx/pci.c
--- 25/drivers/net/wireless/tiacx/pci.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/pci.c	Fri Sep  9 17:28:49 2005
@@ -56,16 +56,6 @@
 #include "acx.h"
 
 
-/********************************************************************/
-/* Module information                                               */
-/********************************************************************/
-MODULE_AUTHOR("The ACX100 Open Source Driver development team");
-MODULE_DESCRIPTION("Driver for TI ACX1xx based wireless cards (CardBus/PCI/USB)");
-#ifdef MODULE_LICENSE
-MODULE_LICENSE("Dual MPL/GPL");
-#endif
-
-
 /*================================================================*/
 /* Local Constants */
 #define PCI_TYPE		(PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
@@ -98,18 +88,6 @@ MODULE_LICENSE("Dual MPL/GPL");
 #define CARD_EEPROM_ID_SIZE 6
 #define MAX_IRQLOOPS_PER_JIFFY  (20000/HZ) /* a la orinoco.c */
 
-#if ACX_DEBUG
-unsigned int acx_debug = L_ASSOC|L_INIT;
-#endif
-
-#if SEPARATE_DRIVER_INSTANCES
-int card = 0;
-#endif /* SEPARATE_DRIVER_INSTANCES */
-
-#if USE_FW_LOADER_LEGACY
-char *firmware_dir;
-#endif
-
 static const char name_acx100[] = "ACX100";
 static const char name_tnetw1100a[] = "TNETW1100A";
 static const char name_tnetw1100b[] = "TNETW1100B";
@@ -158,7 +136,7 @@ static int acx_e_probe_pci(struct pci_de
 static void acx_e_remove_pci(struct pci_dev *pdev);
 
 #ifdef CONFIG_PM
-static int acx_e_suspend(struct pci_dev *pdev, u32 state);
+static int acx_e_suspend(struct pci_dev *pdev, pm_message_t state);
 static int acx_e_resume(struct pci_dev *pdev);
 #endif
 
@@ -209,7 +187,7 @@ typedef struct acx_device {
  * But if we want to register ALL kinds of devices in one global list,
  * then we need it and need to maintain it properly. */
 static struct acx_device root_acx_dev = {
-	.newest        = NULL,
+	.newest		= NULL,
 };
 DECLARE_MUTEX(root_acx_dev_sem);
 
@@ -391,13 +369,13 @@ end:
 
 
 /***********************************************************************
-** acx_s_read_phy_reg
+** acxpci_s_read_phy_reg
 **
 ** Messing with rx/tx disabling and enabling here
 ** (acx_write_reg32(priv, IO_ACX_ENABLE, 0b000000xx)) kills traffic
 */
 int
-acx_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
+acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
 {
 	int result = NOT_OK;
 	int count;
@@ -437,7 +415,7 @@ fail:
 /***********************************************************************
 */
 int
-acx_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
+acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
 {
 	FN_ENTER;
 
@@ -622,8 +600,8 @@ acx_s_upload_fw(wlandevice_t *priv)
 	/* Try combined, then main image */
 	priv->need_radio_fw = 0;
 	sprintf(filename, "tiacx1%02dc%02X",
-		(priv->chip_type == CHIPTYPE_ACX111)*11,
-		priv->radio_type);
+		IS_ACX111(priv)*11, priv->radio_type);
+
 	apfw_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
 	if (!apfw_image) {
 		priv->need_radio_fw = 1;
@@ -686,7 +664,7 @@ acx_s_upload_radio(wlandevice_t *priv)
 	offset = le32_to_cpu(mm.CodeEnd);
 
 	sprintf(filename, "tiacx1%02dr%02X",
-		(priv->chip_type == CHIPTYPE_ACX111)*11,
+		IS_ACX111(priv)*11,
 		priv->radio_type);
 	radio_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
 	if (!radio_image) {
@@ -726,9 +704,6 @@ acx_s_upload_radio(wlandevice_t *priv)
 		&radioinit, sizeof(radioinit), CMD_TIMEOUT_MS(1000));
 
 	res = acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
-	if (OK != res) {
-		printk("%s: error reading memory map\n", priv->netdev->name);
-	}
 fail:
 	FN_EXIT1(res);
 	return res;
@@ -810,36 +785,6 @@ acx_s_verify_init(wlandevice_t *priv)
 
 
 /***********************************************************************
-** acx_cmd_status_str
-*/
-static const char*
-acx_cmd_status_str(unsigned int state)
-{
-	static const char * const cmd_error_strings[] = {
-		"Idle",
-		"Success",
-		"Unknown Command",
-		"Invalid Information Element",
-		"Channel rejected",
-		"Channel invalid in current regulatory domain",
-		"MAC invalid",
-		"Command rejected (read-only information element)",
-		"Command rejected",
-		"Already asleep",
-		"TX in progress",
-		"Already awake",
-		"Write only",
-		"RX in progress",
-		"Invalid parameter",
-		"Scan in progress",
-		"Failed"
-	};
-	return state < VEC_SIZE(cmd_error_strings) ?
-			cmd_error_strings[state] : "UNKNOWN REASON";
-}
-
-
-/***********************************************************************
 ** A few low-level helpers
 **
 ** Note: these functions are not protected by lock
@@ -999,7 +944,7 @@ acx_s_reset_dev(netdevice_t *dev)
 		goto fail_unlock;
 	}
 
-#if WE_DONT_NEED_THAT_DO_WE
+#ifdef WE_DONT_NEED_THAT_DO_WE
 	if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 2) {
 		/* eCPU most likely means "embedded CPU" */
 		msg = "eCPU did not start after boot from flash. ";
@@ -1044,7 +989,7 @@ acx_s_reset_dev(netdevice_t *dev)
 
 	acxlog(L_DEBUG, "eCPU has woken up, card is ready to be configured\n");
 
-	if (priv->chip_type == CHIPTYPE_ACX111) {
+	if (IS_ACX111(priv)) {
 		acxlog(L_DEBUG, "cleaning up cmd mailbox access area\n");
 		acx_write_cmd_status(priv, 0);
 		acx_read_cmd_status(priv);
@@ -1055,8 +1000,7 @@ acx_s_reset_dev(netdevice_t *dev)
 	}
 
 	/* TODO what is this one doing ?? adapt for acx111 */
-	if ((OK != acx_read_eeprom_area(priv))
-	 && (CHIPTYPE_ACX100 == priv->chip_type)) {
+	if ((OK != acx_read_eeprom_area(priv)) && IS_ACX100(priv)) {
 		/* does "CIS" mean "Card Information Structure"?
 		 * If so, then this would be a PCMCIA message...
 		 */
@@ -1123,43 +1067,49 @@ acx_init_mboxes(wlandevice_t *priv)
 
 #if !ACX_DEBUG
 int
-acx_s_issue_cmd_timeo(
+acxpci_s_issue_cmd_timeo(
 	wlandevice_t *priv,
 	unsigned int cmd,
-	void *pcmdparam,
-	unsigned paramlen,
+	void *buffer,
+	unsigned buflen,
 	unsigned timeout)
 {
 #else
 int
-acx_s_issue_cmd_timeo_debug(
+acxpci_s_issue_cmd_timeo_debug(
 	wlandevice_t *priv,
 	unsigned cmd,
-	void *pcmdparam,
-	unsigned paramlen,
+	void *buffer,
+	unsigned buflen,
 	unsigned timeout,
 	const char* cmdstr)
 {
 	unsigned long start = jiffies;
 #endif
+	const char *devname;
 	unsigned counter;
-	int result = NOT_OK;
 	u16 irqtype;
 	u16 cmd_status;
 
 	FN_ENTER;
 
-	acxlog(L_CTL, FUNC"(cmd:%s,timeout:%ums)\n", cmdstr, timeout/100);
+	devname = priv->netdev->name;
+	if (!devname || !devname[0])
+		devname = "acx";
+
+	acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,timeout:%ums,type:0x%04X)\n",
+		cmdstr, buflen, timeout,
+		buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
 
 	if (!(priv->dev_state_mask & ACX_STATE_FW_LOADED)) {
-		acxlog(L_CTL, "firmware not loaded yet, "
-				"cannot execute command!\n");
-		goto done;
+		printk("%s: "FUNC"(): firmware is not loaded yet, "
+			"cannot execute commands!\n", devname);
+		goto bad;
 	}
 
 	if ((acx_debug & L_DEBUG) && (cmd != ACX1xx_CMD_INTERROGATE)) {
-		printk("input pdr (len=%u):\n", paramlen);
-		acx_dump_bytes(pcmdparam, paramlen);
+		printk("input pdr (len=%u):\n", buflen);
+		acx_dump_bytes(buffer, buflen);
 	}
 
 	/* wait for firmware to become idle for our command submission */
@@ -1177,21 +1127,24 @@ acx_s_issue_cmd_timeo_debug(
 
 	if (!counter) {
 		/* the card doesn't get idle, we're in trouble */
-		printk("%s: trying to issue firmware command  "
-			"but Command Register is not IDLE: 0x%04X\n",
-			priv->netdev->name, priv->cmd_status);
-		goto done;
-	} else if (counter < 199) { /* if waited >0ms... */
-		acxlog(L_CTL|L_DEBUG, FUNC"(): waited for idle %dms. "
+		printk("%s: "FUNC"(): cmd_status is not IDLE: 0x%04X!=0\n",
+			devname, priv->cmd_status);
+		goto bad;
+	} else if (counter < 190) { /* if waited >10ms... */
+		acxlog(L_CTL|L_DEBUG, FUNC"(): waited for IDLE %dms. "
 			"Please report\n", 199 - counter);
 	}
 
 	/* now write the parameters of the command if needed */
-	if (pcmdparam && paramlen) {
+	if (buffer && buflen) {
 		/* if it's an INTERROGATE command, just pass the length
 		 * of parameters to read, as data */
-		memcpy(priv->cmd_area, pcmdparam,
-			(cmd == ACX1xx_CMD_INTERROGATE) ? 4 : paramlen);
+#if CMD_DISCOVERY
+		if (cmd == ACX1xx_CMD_INTERROGATE)
+			memset(priv->cmd_area, 0xAA, buflen);
+#endif
+		memcpy(priv->cmd_area, buffer,
+			(cmd == ACX1xx_CMD_INTERROGATE) ? 4 : buflen);
 	}
 	/* now write the actual command type */
 	priv->cmd_type = cmd;
@@ -1202,11 +1155,13 @@ acx_s_issue_cmd_timeo_debug(
 
 	/* wait for firmware to process command */
 
-	/* make sure we have at least *some* timeout value */
-	if (unlikely(timeout > 120000))
-		timeout = 120000;
-	timeout = ((timeout/100)-1) | 1; /* in ms, nonzero */
-	/* clear it. can be set only by IRQ handler: */
+	/* Ensure nonzero and not too large timeout.
+	** Also converts e.g. 100->99, 200->199
+	** which is nice but not essential */
+	timeout = (timeout-1) | 1;
+	if (unlikely(timeout > 1199))
+		timeout = 1199;
+	/* clear CMD_COMPLETE bit. can be set only by IRQ handler: */
 	priv->irq_status &= ~HOST_INT_CMD_COMPLETE;
 
 	/* we schedule away sometimes (timeout can be large) */
@@ -1215,7 +1170,8 @@ acx_s_issue_cmd_timeo_debug(
 		if (!priv->irqs_active) { /* IRQ disabled: poll */
 			irqtype = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
 			if (irqtype & HOST_INT_CMD_COMPLETE) {
-				acx_write_reg16(priv, IO_ACX_IRQ_ACK, HOST_INT_CMD_COMPLETE);
+				acx_write_reg16(priv, IO_ACX_IRQ_ACK,
+						HOST_INT_CMD_COMPLETE);
 				break;
 			}
 		} else { /* Wait when IRQ will set the bit */
@@ -1239,50 +1195,56 @@ acx_s_issue_cmd_timeo_debug(
 	acx_write_cmd_status(priv, 0);
 
 	if (!counter) {	/* timed out! */
-		printk("%s: "FUNC"(0x%04X) timed out %s for Cmd_Complete. "
-			"irq bits:0x%04X irq status:0x%04X timeout:%dms "
-			"cmd status:%d (%s). Bailing\n",
-			priv->netdev->name, cmd,
-			(priv->irqs_active) ? "waiting" : "polling",
+		printk("%s: "FUNC"(): timed out %s for CMD_COMPLETE. "
+			"irq bits:0x%04X irq_status:0x%04X timeout:%dms "
+			"cmd_status:%d (%s)\n",
+			devname, (priv->irqs_active) ? "waiting" : "polling",
 			irqtype, priv->irq_status, timeout,
 			cmd_status, acx_cmd_status_str(cmd_status));
-		if (acx_debug)
-			dump_stack();
-		goto done;
-	} else if (timeout - counter > 1) { /* if waited >1ms... */
-		acxlog(L_CTL|L_DEBUG, FUNC"(%s): %s for Cmd_Complete %dms. count:%d. "
-			"Please report\n", cmdstr,
+		goto bad;
+	} else if (timeout - counter > 30) { /* if waited >30ms... */
+		acxlog(L_CTL|L_DEBUG, FUNC"(): %s for CMD_COMPLETE %dms. "
+			"count:%d. Please report\n",
 			(priv->irqs_active) ? "waited" : "polled",
 			timeout - counter, counter);
 	}
 
 	if (1 != cmd_status) { /* it is not a 'Success' */
-		printk("%s: "FUNC"(0x%04X) FAILED: %d (%s). Took %dms of %d\n",
-			priv->netdev->name, cmd,
-			cmd_status, acx_cmd_status_str(cmd_status),
+		printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s). "
+			"Took %dms of %d\n",
+			devname, cmd_status, acx_cmd_status_str(cmd_status),
 			timeout - counter, timeout);
-		if (acx_debug & L_CTL)
-			dump_stack();
 		/* zero out result buffer */
-		if (pcmdparam && paramlen)
-			memset(pcmdparam, 0, paramlen);
-		goto done;
+		if (buffer && buflen)
+			memset(buffer, 0, buflen);
+		goto bad;
 	}
 
 	/* read in result parameters if needed */
-	if (pcmdparam && paramlen && (cmd == ACX1xx_CMD_INTERROGATE)) {
-		memcpy(pcmdparam, priv->cmd_area, paramlen);
+	if (buffer && buflen && (cmd == ACX1xx_CMD_INTERROGATE)) {
+		memcpy(buffer, priv->cmd_area, buflen);
 		if (acx_debug & L_DEBUG) {
-			printk("output pdr (len=%u): ", paramlen);
-			acx_dump_bytes(pcmdparam, paramlen);
+			printk("output buffer (len=%u): ", buflen);
+			acx_dump_bytes(buffer, buflen);
 		}
 	}
-	result = OK;
-done:
+/* ok: */
 	acxlog(L_CTL, FUNC"(%s): took %ld jiffies to complete\n",
-			 cmdstr, jiffies-start);
-	FN_EXIT1(result);
-	return result;
+			 cmdstr, jiffies - start);
+	FN_EXIT1(OK);
+	return OK;
+
+bad:
+	/* Give enough info so that callers can avoid
+	** printing their own diagnostic messages */
+#if ACX_DEBUG
+	printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
+#else
+	printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
+#endif
+	dump_stack();
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
 }
 
 
@@ -1333,7 +1295,7 @@ acx_s_get_firmware_version(wlandevice_t 
 				+ (hexarr[2] << 8) + hexarr[3]);
 		acxlog(L_DEBUG, "firmware_numver 0x%08X\n", priv->firmware_numver);
 	}
-	if (priv->chip_type == CHIPTYPE_ACX111) {
+	if (IS_ACX111(priv)) {
 		if (priv->firmware_numver == 0x00010011) {
 			/* This one does not survive floodpinging */
 			printk("acx: firmware '%s' is known to be buggy, "
@@ -1342,7 +1304,7 @@ acx_s_get_firmware_version(wlandevice_t 
 		if (priv->firmware_numver == 0x02030131) {
 			/* With this one, all rx packets look mangled
 			** Most probably we simply do not know how to use it
-			**  properly */
+			** properly */
 			printk("acx: firmware '%s' does not work well "
 				"with this driver\n", priv->firmware_version);
 		}
@@ -1582,14 +1544,13 @@ acx_s_device_chain_remove(struct net_dev
 }
 
 
-/*----------------------------------------------------------------
-* acx_free_desc_queues
-*
-*	Releases the queues that have been allocated, the
-*	others have been initialised to NULL in acx100.c so this
-*	function can be used if only part of the queues were
-*	allocated.
-*----------------------------------------------------------------*/
+/***********************************************************************
+** acx_free_desc_queues
+**
+** Releases the queues that have been allocated, the
+** others have been initialised to NULL so this
+** function can be used if only part of the queues were allocated.
+*/
 static inline void
 acx_free_coherent(struct pci_dev *hwdev, size_t size,
 			void *vaddr, dma_addr_t dma_handle)
@@ -1603,7 +1564,7 @@ acx_free_coherent(struct pci_dev *hwdev,
 }
 
 void
-acx_free_desc_queues(TIWLAN_DC *pDc)
+acx_free_desc_queues(wlandevice_t *priv)
 {
 #define ACX_FREE_QUEUE(size, ptr, phyaddr) \
 	if (ptr) { \
@@ -1614,17 +1575,17 @@ acx_free_desc_queues(TIWLAN_DC *pDc)
 
 	FN_ENTER;
 
-	ACX_FREE_QUEUE(pDc->TxHostDescQPoolSize, pDc->pTxHostDescQPool, pDc->TxHostDescQPoolPhyAddr);
-	ACX_FREE_QUEUE(pDc->TxBufferPoolSize, pDc->pTxBufferPool, pDc->TxBufferPoolPhyAddr);
+	ACX_FREE_QUEUE(priv->TxHostDescQPoolSize, priv->pTxHostDescQPool, priv->TxHostDescQPoolPhyAddr);
+	ACX_FREE_QUEUE(priv->TxBufferPoolSize, priv->pTxBufferPool, priv->TxBufferPoolPhyAddr);
 
-	pDc->pTxDescQPool = NULL;
-	pDc->tx_pool_count = 0;
+	priv->pTxDescQPool = NULL;
+	priv->tx_pool_count = 0;
 
-	ACX_FREE_QUEUE(pDc->RxHostDescQPoolSize, pDc->pRxHostDescQPool, pDc->RxHostDescQPoolPhyAddr);
-	ACX_FREE_QUEUE(pDc->RxBufferPoolSize, pDc->pRxBufferPool, pDc->RxBufferPoolPhyAddr);
+	ACX_FREE_QUEUE(priv->RxHostDescQPoolSize, priv->pRxHostDescQPool, priv->RxHostDescQPoolPhyAddr);
+	ACX_FREE_QUEUE(priv->RxBufferPoolSize, priv->pRxBufferPool, priv->RxBufferPoolPhyAddr);
 
-	pDc->pRxDescQPool = NULL;
-	pDc->rx_pool_count = 0;
+	priv->pRxDescQPool = NULL;
+	priv->rx_pool_count = 0;
 
 	FN_EXIT0;
 }
@@ -1647,7 +1608,7 @@ acx_s_delete_dma_regions(wlandevice_t *p
 	acx_s_msleep(100);
 
 	acx_lock(priv, flags);
-	acx_free_desc_queues(&priv->dc);
+	acx_free_desc_queues(priv);
 	acx_unlock(priv, flags);
 
 	FN_EXIT0;
@@ -1848,16 +1809,14 @@ acx_e_probe_pci(struct pci_dev *pdev, co
 	phymem1 = pci_resource_start(pdev, mem_region1);
 	phymem2 = pci_resource_start(pdev, mem_region2);
 
-	if (!request_mem_region
-	    (phymem1, pci_resource_len(pdev, mem_region1), "ACX1xx_1")) {
+	if (!request_mem_region(phymem1, pci_resource_len(pdev, mem_region1), "ACX1xx_1")) {
 		printk("acx: cannot reserve PCI memory region 1 (are you sure "
 			"you have CardBus support in kernel?)\n");
 		result = -EIO;
 		goto fail_request_mem_region1;
 	}
 
-	if (!request_mem_region
-	    (phymem2, pci_resource_len(pdev, mem_region2), "ACX1xx_2")) {
+	if (!request_mem_region(phymem2, pci_resource_len(pdev, mem_region2), "ACX1xx_2")) {
 		printk("acx: cannot reserve PCI memory region 2\n");
 		result = -EIO;
 		goto fail_request_mem_region2;
@@ -1912,6 +1871,7 @@ acx_e_probe_pci(struct pci_dev *pdev, co
 	/* acx_sem_lock(priv); */
 
 	priv->pdev = pdev;
+	priv->dev_type = DEVTYPE_PCI;
 	priv->chip_type = chip_type;
 	priv->chip_name = chip_name;
 	priv->io = (CHIPTYPE_ACX100 == chip_type) ? IO_ACX100 : IO_ACX111;
@@ -1960,7 +1920,6 @@ acx_e_probe_pci(struct pci_dev *pdev, co
 	acxlog(L_IRQ | L_INIT, "using IRQ %d\n", pdev->irq);
 
 	dev->irq = pdev->irq;
-	/* TODO this is maybe incompatible to ACX111 */
 	dev->base_addr = pci_resource_start(pdev, 0);
 
 	/* need to be able to restore PCI state after a suspend */
@@ -2001,7 +1960,7 @@ acx_e_probe_pci(struct pci_dev *pdev, co
 #endif
 	dev->set_multicast_list = &acx_i_set_multicast_list;
 	dev->tx_timeout = &acx_i_tx_timeout;
-	dev->watchdog_timeo = 4 * HZ;	/* 400 */
+	dev->watchdog_timeo = 4 * HZ;
 
 	/* ok, basic setup is finished, now start initialising the card */
 
@@ -2050,8 +2009,13 @@ acx_e_probe_pci(struct pci_dev *pdev, co
 	 * (in particular, on other CPUs), we only need to up the sem */
 	/* acx_sem_unlock(priv); */
 
-	printk("acx_pci module " WLAN_RELEASE " loaded successfully\n");
+	printk("acx: PCI module " WLAN_RELEASE " loaded successfully\n");
 	result = OK;
+
+#if CMD_DISCOVERY
+	great_inquisistor(priv);
+#endif
+
 	goto done;
 
 	/* error paths: undo everything in reverse order... */
@@ -2165,7 +2129,7 @@ acx_e_remove_pci(struct pci_dev *pdev)
 	 * For paranoid reasons we continue to follow the rules */
 	acx_sem_lock(priv);
 
-	if (priv->chip_type == CHIPTYPE_ACX100) {
+	if (IS_ACX100(priv)) {
 		mem_region1 = PCI_ACX100_REGION1;
 		mem_region2 = PCI_ACX100_REGION2;
 	} else {
@@ -2224,7 +2188,7 @@ end:
 #ifdef CONFIG_PM
 static int if_was_up = 0; /* FIXME: HACK, do it correctly sometime instead */
 static int
-acx_e_suspend(struct pci_dev *pdev, /*@unused@*/ u32 state)
+acx_e_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	wlandevice_t *priv = acx_netdev_priv(dev);
@@ -2377,7 +2341,10 @@ acx_s_down(netdevice_t *dev)
 
 	FN_ENTER;
 
-	acx_stop_queue(dev, "during close");
+	/* Disable IRQs first, so that IRQs cannot race with us */
+	acx_lock(priv, flags);
+	acx_l_disable_irq(priv);
+	acx_unlock(priv, flags);
 
 	/* we really don't want to have an asynchronous tasklet disturb us
 	** after something vital for its job has been shut down, so
@@ -2393,25 +2360,27 @@ acx_s_down(netdevice_t *dev)
 	** will sleep on sem forever, because it is taken by us!
 	** Work around that by temporary sem unlock.
 	** This will fail miserably if we'll be hit by concurrent
-	** iwconfig or something in between. TODO!
-	*/
+	** iwconfig or something in between. TODO! */
 	acx_sem_unlock(priv);
 	FLUSH_SCHEDULED_WORK();
 	acx_sem_lock(priv);
 
+	/* This is possible:
+	** FLUSH_SCHEDULED_WORK -> acx_e_after_interrupt_task ->
+	** -> set_status(ASSOCIATED) -> wake_queue()
+	** That's why we stop queue _after_ FLUSH_SCHEDULED_WORK
+	** lock/unlock is just paranoia, maybe not needed */
+	acx_lock(priv, flags);
+	acx_stop_queue(dev, "during close");
 	acx_set_status(priv, ACX_STATUS_0_STOPPED);
+	acx_unlock(priv, flags);
 
 	/* kernel/timer.c says it's illegal to del_timer_sync()
 	** a timer which restarts itself. We guarantee this cannot
 	** ever happen because acx_i_timer() never does this if
-	** status is ACX_STATUS_0_STOPPED
-	*/
+	** status is ACX_STATUS_0_STOPPED */
 	del_timer_sync(&priv->mgmt_timer);
 
-	acx_lock(priv, flags);
-	acx_l_disable_irq(priv);
-	acx_unlock(priv, flags);
-
 	FN_EXIT0;
 }
 
@@ -2585,7 +2554,7 @@ static struct net_device_stats*
 acx_e_get_stats(netdevice_t *dev)
 {
 	wlandevice_t *priv = acx_netdev_priv(dev);
-#if ANNOYING_GETS_CALLED_TOO_OFTEN
+#ifdef ANNOYING_GETS_CALLED_TOO_OFTEN
 	FN_ENTER;
 	FN_EXIT1((int)&priv->stats);
 #endif
@@ -2967,8 +2936,7 @@ none:
 void
 acx_l_power_led(wlandevice_t *priv, int enable)
 {
-	u16 gpio_pled =
-		(CHIPTYPE_ACX111 == priv->chip_type) ? 0x0040 : 0x0800;
+	u16 gpio_pled =	IS_ACX111(priv) ? 0x0040 : 0x0800;
 
 	/* A hack. Not moving message rate limiting to priv->xxx
 	 * (it's only a debug message after all) */
@@ -2991,135 +2959,9 @@ acx_l_power_led(wlandevice_t *priv, int 
 */
 
 /***********************************************************************
-** Ioctls for easy debug of I/O things
-*/
-/* specialized register io for debug purposes, see ioctl below */
-static inline u32
-_acx_read_reg32(wlandevice_t *priv, unsigned int offset)
-{
-#if ACX_IO_WIDTH == 32
-	return readl(priv->iobase + offset);
-#else
-	return readw(priv->iobase + offset)
-	    + (readw(priv->iobase + offset + 2) << 16);
-#endif
-}
-
-static inline void
-_acx_write_reg32(wlandevice_t *priv, unsigned int offset, u32 val)
-{
-#if ACX_IO_WIDTH == 32
-	writel(val, priv->iobase + offset);
-#else
-	writew(val & 0xffff, priv->iobase + offset);
-	writew(val >> 16, priv->iobase + offset + 2);
-#endif
-}
-
-int
-acx_ioctl_dbg_get_io(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra)
-{
-	int result = -EINVAL;
-#if ACX_DEBUG
-	wlandevice_t *priv = acx_netdev_priv(dev);
-	unsigned int *params = (unsigned int*)extra;
-
-	/* expected value order: DbgGetIO type address magic */
-
-	if (params[2] != 0x1234) {
-		acxlog(L_IOCTL, "wrong magic: 0x%04X doesn't match 0x%04X! "
-			"If you don't know what you're doing, then please "
-			"stop NOW, this can be DANGEROUS!\n",
-			params[2], 0x1234);
-		goto end;
-	}
-
-	switch (params[0]) {
-	case 0x0: /* Internal RAM */
-		acxlog(L_IOCTL, "sorry, access to internal RAM "
-			"is not implemented yet\n");
-		break;
-	case 0xffff: /* MAC registers */
-		acxlog(L_IOCTL, "value at register 0x%04X is 0x%08X\n",
-			params[1], _acx_read_reg32(priv, params[1]));
-		break;
-	case 0x81: /* PHY RAM table */
-		acxlog(L_IOCTL, "sorry, access to PHY RAM "
-			"is not implemented yet\n");
-		break;
-	case 0x82: /* PHY registers */
-		acxlog(L_IOCTL, "sorry, access to PHY registers "
-			"is not implemented yet\n");
-		break;
-	default:
-		acxlog(L_IOCTL, "Invalid I/O type specified, aborting!\n");
-		goto end;
-	}
-	result = OK;
-end:
-#endif /* ACX_DEBUG */
-	return result;
-}
-
-int
-acx_ioctl_dbg_set_io(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra)
-{
-	int result = -EINVAL;
-#if ACX_DEBUG
-	wlandevice_t *priv = acx_netdev_priv(dev);
-	int *params = (int*)extra;
-
-	/* expected value order: DbgSetIO type address value magic */
-
-	if (params[3] != 0x1234) {
-		acxlog(L_ANY, "wrong magic: 0x%04X doesn't match 0x%04X! "
-			"If you don't know what you're doing, then please "
-			"stop, this can be DANGEROUS!\n",
-			params[3], 0x1234);
-		goto end;
-	}
-
-	switch (params[0]) {
-	case 0x0: /* Internal RAM */
-		acxlog(L_IOCTL, "sorry, access to internal RAM "
-			"is not implemented yet\n");
-		break;
-	case 0xffff: /* MAC registers */
-		acxlog(L_IOCTL, "setting value at register 0x%04X "
-			"to 0x%08X\n", params[1], params[2]);
-		_acx_write_reg32(priv, params[1], params[2]);
-		break;
-	case 0x81: /* PHY RAM table */
-		acxlog(L_IOCTL, "sorry, access to PHY RAM "
-			"is not implemented yet\n");
-		break;
-	case 0x82: /* PHY registers */
-		acxlog(L_IOCTL, "sorry, access to PHY registers "
-			"is not implemented yet\n");
-		break;
-	default:
-		acxlog(L_ANY, "Invalid I/O type specified, aborting!\n");
-		goto end;
-	}
-	result = OK;
-end:
-#endif /* ACX_DEBUG */
-	return result;
-}
-
-
-/***********************************************************************
 */
 int
-acx111_ioctl_info(
+acx111pci_ioctl_info(
 	struct net_device *dev,
 	struct iw_request_info *info,
 	struct iw_param *vwrq,
@@ -3127,7 +2969,6 @@ acx111_ioctl_info(
 {
 #if ACX_DEBUG
 	wlandevice_t *priv = acx_netdev_priv(dev);
-	const TIWLAN_DC *pDc = &priv->dc;
 	const struct rxdesc *pRxDesc;
 	const struct rxhostdesc *rx_host_desc;
 	struct txdesc *tx_desc;
@@ -3155,46 +2996,29 @@ acx111_ioctl_info(
 
 	/* get Acx111 Memory Configuration */
 	memset(&memconf, 0, sizeof(memconf));
-
-	/* BTW, fails with 12 (Write only) error code --vda */
-	if (OK != acx_s_interrogate(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG)) {
-		printk("read memconf FAILED\n");
-	}
+	/* BTW, fails with 12 (Write only) error code.
+	** Retained for easy testing of issue_cmd error handling :) */
+	acx_s_interrogate(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG);
 
 	/* get Acx111 Queue Configuration */
 	memset(&queueconf, 0, sizeof(queueconf));
-
-	if (OK != acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS)) {
-		printk("read queuehead FAILED\n");
-	}
+	acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
 
 	/* get Acx111 Memory Map */
 	memset(memmap, 0, sizeof(memmap));
-
-	if (OK != acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
-		printk("read mem map FAILED\n");
-	}
+	acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP);
 
 	/* get Acx111 Rx Config */
 	memset(rxconfig, 0, sizeof(rxconfig));
-
-	if (OK != acx_s_interrogate(priv, &rxconfig, ACX1xx_IE_RXCONFIG)) {
-		printk("read rxconfig FAILED\n");
-	}
+	acx_s_interrogate(priv, &rxconfig, ACX1xx_IE_RXCONFIG);
 
 	/* get Acx111 fcs error count */
 	memset(fcserror, 0, sizeof(fcserror));
-
-	if (OK != acx_s_interrogate(priv, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT)) {
-		printk("read fcserror FAILED\n");
-	}
+	acx_s_interrogate(priv, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT);
 
 	/* get Acx111 rate fallback */
 	memset(ratefallback, 0, sizeof(ratefallback));
-
-	if (OK != acx_s_interrogate(priv, &ratefallback, ACX1xx_IE_RATE_FALLBACK)) {
-		printk("read ratefallback FAILED\n");
-	}
+	acx_s_interrogate(priv, &ratefallback, ACX1xx_IE_RATE_FALLBACK);
 
 	/* force occurrence of a beacon interrupt */
 	/* TODO: comment why is this necessary */
@@ -3300,10 +3124,10 @@ acx111_ioctl_info(
 	acx_lock(priv, flags);
 
 	/* dump acx111 internal rx descriptor ring buffer */
-	pRxDesc = pDc->pRxDescQPool;
+	pRxDesc = priv->pRxDescQPool;
 
 	/* loop over complete receive pool */
-	for (i = 0; i < pDc->rx_pool_count; i++) {
+	for (i = 0; i < priv->rx_pool_count; i++) {
 		printk("\ndump internal rxdesc %d:\n"
 			"mem pos %p\n"
 			"next 0x%X\n"
@@ -3325,10 +3149,10 @@ acx111_ioctl_info(
 
 	/* dump host rx descriptor ring buffer */
 
-	rx_host_desc = pDc->pRxHostDescQPool;
+	rx_host_desc = priv->pRxHostDescQPool;
 
 	/* loop over complete receive pool */
-	for (i = 0; i < pDc->rx_pool_count; i++) {
+	for (i = 0; i < priv->rx_pool_count; i++) {
 		printk("\ndump host rxdesc %d:\n"
 			"mem pos %p\n"
 			"buffer mem pos 0x%X\n"
@@ -3349,10 +3173,10 @@ acx111_ioctl_info(
 	}
 
 	/* dump acx111 internal tx descriptor ring buffer */
-	tx_desc = pDc->pTxDescQPool;
+	tx_desc = priv->pTxDescQPool;
 
 	/* loop over complete transmit pool */
-	for (i = 0; i < pDc->tx_pool_count; i++) {
+	for (i = 0; i < priv->tx_pool_count; i++) {
 		printk("\ndump internal txdesc %d:\n"
 			"size 0x%X\n"
 			"mem pos %p\n"
@@ -3374,15 +3198,15 @@ acx111_ioctl_info(
 			tx_desc->Ctl_8,
 			tx_desc->Ctl2_8, tx_desc->error,
 			tx_desc->u.r1.rate);
-		tx_desc = GET_NEXT_TX_DESC_PTR(pDc, tx_desc);
+		tx_desc = GET_NEXT_TX_DESC_PTR(priv, tx_desc);
 	}
 
 	/* dump host tx descriptor ring buffer */
 
-	tx_host_desc = pDc->pTxHostDescQPool;
+	tx_host_desc = priv->pTxHostDescQPool;
 
 	/* loop over complete host send pool */
-	for (i = 0; i < pDc->tx_pool_count * 2; i++) {
+	for (i = 0; i < priv->tx_pool_count * 2; i++) {
 		printk("\ndump host txdesc %d:\n"
 			"mem pos %p\n"
 			"buffer mem pos 0x%X\n"
@@ -3416,7 +3240,7 @@ end_ok:
 /***********************************************************************
 */
 int
-acx100_ioctl_set_phy_amp_bias(
+acx100pci_ioctl_set_phy_amp_bias(
 	struct net_device *dev,
 	struct iw_request_info *info,
 	struct iw_param *vwrq,
@@ -3463,19 +3287,18 @@ acx100_ioctl_set_phy_amp_bias(
 
 
 /***************************************************************
-** acx_l_alloc_tx
+** acxpci_l_alloc_tx
 ** Actually returns a txdesc_t* ptr
 */
 tx_t*
-acx_l_alloc_tx(wlandevice_t* priv)
+acxpci_l_alloc_tx(wlandevice_t* priv)
 {
-	struct TIWLAN_DC *pDc = &priv->dc;
 	struct txdesc *tx_desc;
 	u8 ctl8;
 
 	FN_ENTER;
 
-	tx_desc = GET_TX_DESC_PTR(pDc, pDc->tx_head);
+	tx_desc = GET_TX_DESC_PTR(priv, priv->tx_head);
 	/* why?! rmb(); */
 	ctl8 = tx_desc->Ctl_8;
 	if (unlikely(DESC_CTL_HOSTOWN != (ctl8 & DESC_CTL_DONE))) {
@@ -3493,7 +3316,7 @@ acx_l_alloc_tx(wlandevice_t* priv)
 	}
 
 	priv->TxQueueFree--;
-	acxlog(L_BUFT, "tx: got desc %u, %u remain\n", pDc->tx_head, priv->TxQueueFree);
+	acxlog(L_BUFT, "tx: got desc %u, %u remain\n", priv->tx_head, priv->TxQueueFree);
 
 /*
  * This comment is probably not entirely correct, needs further discussion
@@ -3514,7 +3337,7 @@ acx_l_alloc_tx(wlandevice_t* priv)
 	}
 
 	/* returning current descriptor, so advance to next free one */
-	pDc->tx_head = (pDc->tx_head + 1) % pDc->tx_pool_count;
+	priv->tx_head = (priv->tx_head + 1) % priv->tx_pool_count;
 end:
 	FN_EXIT0;
 
@@ -3525,24 +3348,29 @@ end:
 /***************************************************************
 */
 void*
-acx_l_get_txbuf(tx_t* tx_opaque)
+acxpci_l_get_txbuf(tx_t* tx_opaque)
 {
 	txhostdesc_t *hostdesc = ((txdesc_t*)tx_opaque)->fixed_size.s.host_desc;
 	/* FIXME: happens on card eject; better method? */
 	if (unlikely((long)-1 == (long)hostdesc))
 		return NULL;
+
+//amd64 crashes here:
+// CORRUPTION DETECTED! hostdesc=00ff81002e2d5000
+//                               ^^ ?? must be ff
+
 	return hostdesc->data;
 }
 
 
 /***************************************************************
-** acx_l_dma_tx_data
+** acxpci_l_tx_data
 **
 ** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
 ** Can be called from acx_i_start_xmit (data frames from net core).
 */
 void
-acx_l_dma_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int hostdesc_len)
+acxpci_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int hostdesc_len)
 {
 	struct txdesc *tx_desc = (struct txdesc*)tx_opaque;
 	struct txhostdesc *hostdesc;
@@ -3579,7 +3407,7 @@ acx_l_dma_tx_data(wlandevice_t *priv, tx
 	else
 		CLEAR_BIT(Ctl2_8, DESC_CTL2_RTS);
 
-#if DEBUG_WEP
+#ifdef DEBUG_WEP
 	if (priv->wep_enabled)
 		SET_BIT(Ctl2_8, DESC_CTL2_WEP);
 	else
@@ -3606,7 +3434,7 @@ acx_l_dma_tx_data(wlandevice_t *priv, tx
 	/* used in tx cleanup routine for auto rate and accounting: */
 	tx_desc->fixed_size.s.txc = clt;
 
-	if (CHIPTYPE_ACX111 == priv->chip_type) {
+	if (IS_ACX111(priv)) {
 		u16 rate_cur = clt ? clt->rate_cur : priv->rate_bcast;
 		/* note that if !tx_desc->do_auto, txrate->cur
 		** has only one nonzero bit */
@@ -3619,14 +3447,14 @@ acx_l_dma_tx_data(wlandevice_t *priv, tx
 			** Disabled for now --vda */
 			/*| ((peer->shortpre && txrate->cur!=RATE111_1) ? RATE111_SHORTPRE : 0) */
 			);
-#if TODO_FIGURE_OUT_WHEN_TO_SET_THIS
+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
 			/* should add this to rate111 above as necessary */
 			| (txrate->pbcc511 ? RATE111_PBCC511 : 0)
 #endif
 	} else { /* ACX100 */
 		u8 rate_100 = clt ? clt->rate_100 : priv->rate_bcast100;
 		tx_desc->u.r1.rate = rate_100;
-#if TODO_FIGURE_OUT_WHEN_TO_SET_THIS
+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
 		if (txrate->pbcc511) {
 			if (n == RATE100_5 || n == RATE100_11)
 				n |= RATE100_PBCC511;
@@ -3661,7 +3489,7 @@ acx_l_dma_tx_data(wlandevice_t *priv, tx
 	 * Do separate logs for acx100/111 to have human-readable rates */
 	if (unlikely(acx_debug & (L_XFER | L_DATA))) {
 		u16 fc = ((wlan_hdr_t*)hostdesc->data)->fc;
-		if (CHIPTYPE_ACX111 == priv->chip_type)
+		if (IS_ACX111(priv))
 			printk("tx: pkt (%s): len %d "
 				"rate %04X%s status %u\n",
 				acx_get_packet_type_string(le16_to_cpu(fc)),
@@ -3856,7 +3684,7 @@ acx_l_handle_txrate_auto(wlandevice_t *p
 
 	/* do some preparations, i.e. calculate the one rate that was
 	 * used to send this packet */
-	if (CHIPTYPE_ACX111 == priv->chip_type) {
+	if (IS_ACX111(priv)) {
 		sent_rate = 1 << highest_bit(rate111 & RATE111_ALL);
 	} else {
 		sent_rate = rate100to111(rate100);
@@ -3931,7 +3759,7 @@ acx_l_handle_txrate_auto(wlandevice_t *p
 	}
 
 	/* calculate acx100 style rate byte if needed */
-	if (CHIPTYPE_ACX100 == priv->chip_type) {
+	if (IS_ACX100(priv)) {
 		txc->rate_100 = bitpos2rate100[highest_bit(cur)];
 	}
 }
@@ -3941,21 +3769,22 @@ acx_l_handle_txrate_auto(wlandevice_t *p
 * acx_l_log_txbuffer
 *----------------------------------------------------------------*/
 #if !ACX_DEBUG
-static inline void acx_l_log_txbuffer(const TIWLAN_DC *pDc) {}
+static inline void acx_l_log_txbuffer(const wlandevice_t *priv) {}
 #else
 static void
-acx_l_log_txbuffer(const TIWLAN_DC *pDc)
+acx_l_log_txbuffer(const wlandevice_t *priv)
 {
 	txdesc_t *pTxDesc;
 	int i;
 
 	/* no FN_ENTER here, we don't want that */
 	/* no locks here, since it's entirely non-critical code */
-	pTxDesc = pDc->pTxDescQPool;
-	for (i = 0; i < pDc->tx_pool_count; i++) {
+	pTxDesc = priv->pTxDescQPool;
+	if (!pTxDesc) return;
+	for (i = 0; i < priv->tx_pool_count; i++) {
 		if ((pTxDesc->Ctl_8 & DESC_CTL_DONE) == DESC_CTL_DONE)
 			printk("tx: buf %d done\n", i);
-		pTxDesc = GET_NEXT_TX_DESC_PTR(pDc, pTxDesc);
+		pTxDesc = GET_NEXT_TX_DESC_PTR(priv, pTxDesc);
 	}
 }
 #endif
@@ -3985,7 +3814,6 @@ acx_l_log_txbuffer(const TIWLAN_DC *pDc)
 unsigned int
 acx_l_clean_tx_desc(wlandevice_t *priv)
 {
-	TIWLAN_DC *pDc = &priv->dc;
 	txdesc_t *pTxDesc;
 	struct client *txc;
 	unsigned int watch, finger;
@@ -3996,15 +3824,15 @@ acx_l_clean_tx_desc(wlandevice_t *priv)
 	FN_ENTER;
 
 	if (unlikely(acx_debug & L_DEBUG))
-		acx_l_log_txbuffer(pDc);
+		acx_l_log_txbuffer(priv);
 
-	acxlog(L_BUFT, "tx: cleaning up bufs from %u\n", pDc->tx_tail);
+	acxlog(L_BUFT, "tx: cleaning up bufs from %u\n", priv->tx_tail);
 
-	watch = pDc->tx_tail;
+	watch = priv->tx_tail;
 	finger = watch;
 
 	do {
-		pTxDesc = GET_TX_DESC_PTR(pDc, finger);
+		pTxDesc = GET_TX_DESC_PTR(priv, finger);
 
 		/* abort if txdesc is not marked as "Tx finished" and "owned" */
 		if ((pTxDesc->Ctl_8 & DESC_CTL_DONE) != DESC_CTL_DONE) {
@@ -4013,7 +3841,7 @@ acx_l_clean_tx_desc(wlandevice_t *priv)
 			 * So better stay around some more, unless
 			 * we already processed more descs than the ring
 			 * size. */
-			if ((num_cleaned == 0) && (num_processed < pDc->tx_pool_count))
+			if ((num_cleaned == 0) && (num_processed < priv->tx_pool_count))
 				goto next;
 			else
 				break;
@@ -4081,7 +3909,7 @@ acx_l_clean_tx_desc(wlandevice_t *priv)
 		if (unlikely(error))
 			acx_l_handle_tx_error(priv, error, finger);
 
-		if (CHIPTYPE_ACX111 == priv->chip_type)
+		if (IS_ACX111(priv))
 			acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u r111=%04X\n",
 				finger, ack_failures, rts_failures, rts_ok, r111);
 		else
@@ -4089,12 +3917,12 @@ acx_l_clean_tx_desc(wlandevice_t *priv)
 				finger, ack_failures, rts_failures, rts_ok, le16_to_cpu(r111) & 0xff);
 next:
 		/* update pointer for descr to be cleaned next */
-		finger = (finger + 1) % pDc->tx_pool_count;
+		finger = (finger + 1) % priv->tx_pool_count;
 		num_processed++;
 	} while (watch != finger);
 
 	/* remember last position */
-	pDc->tx_tail = finger;
+	priv->tx_tail = finger;
 end:
 	FN_EXIT1(num_cleaned);
 	return num_cleaned;
@@ -4105,14 +3933,13 @@ end:
 void
 acx_l_clean_tx_desc_emergency(wlandevice_t *priv)
 {
-	TIWLAN_DC *pDc = &priv->dc;
 	txdesc_t *pTxDesc;
 	unsigned int i;
 
 	FN_ENTER;
 
-	for (i = 0; i < pDc->tx_pool_count; i++) {
-		pTxDesc = GET_TX_DESC_PTR(pDc, i);
+	for (i = 0; i < priv->tx_pool_count; i++) {
+		pTxDesc = GET_TX_DESC_PTR(priv, i);
 
 		/* free it */
 		pTxDesc->ack_failures = 0;
@@ -4122,7 +3949,7 @@ acx_l_clean_tx_desc_emergency(wlandevice
 		pTxDesc->Ctl_8 = DESC_CTL_HOSTOWN;
 	}
 
-	priv->TxQueueFree = pDc->tx_pool_count;
+	priv->TxQueueFree = priv->tx_pool_count;
 
 	FN_EXIT0;
 }
@@ -4134,18 +3961,18 @@ acx_l_clean_tx_desc_emergency(wlandevice
 * Called from IRQ context only
 *----------------------------------------------------------------*/
 #if !ACX_DEBUG
-static inline void acx_l_log_rxbuffer(const TIWLAN_DC *pDc) {}
+static inline void acx_l_log_rxbuffer(const wlandevice_t *priv) {}
 #else
 static void
-acx_l_log_rxbuffer(const TIWLAN_DC *pDc)
+acx_l_log_rxbuffer(const wlandevice_t *priv)
 {
 	const struct rxhostdesc *pRxDesc;
 	int i;
 
 	/* no FN_ENTER here, we don't want that */
 
-	pRxDesc = pDc->pRxHostDescQPool;
-	for (i = 0; i < pDc->rx_pool_count; i++) {
+	pRxDesc = priv->pRxHostDescQPool;
+	for (i = 0; i < priv->rx_pool_count; i++) {
 		if ((pRxDesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
 		 && (pRxDesc->Status & cpu_to_le32(BIT31)))
 			printk("rx: buf %d full\n", i);
@@ -4164,27 +3991,25 @@ void
 acx_l_process_rx_desc(wlandevice_t *priv)
 {
 	struct rxhostdesc *RxHostPool;
-	TIWLAN_DC *pDc;
 	struct rxhostdesc *pRxHostDesc;
 	unsigned int curr_idx;
 	unsigned int count = 0;
 
 	FN_ENTER;
 
-	pDc = &priv->dc;
 	if (unlikely(acx_debug & L_BUFR)) {
-		acx_l_log_rxbuffer(pDc);
+		acx_l_log_rxbuffer(priv);
 	}
 
-	RxHostPool = pDc->pRxHostDescQPool;
+	RxHostPool = priv->pRxHostDescQPool;
 
 	/* First, have a loop to determine the first descriptor that's
 	 * full, just in case there's a mismatch between our current
 	 * rx_tail and the full descriptor we're supposed to handle. */
 	while (1) {
-		curr_idx = pDc->rx_tail;
-		pRxHostDesc = &RxHostPool[pDc->rx_tail];
-		pDc->rx_tail = (pDc->rx_tail + 1) % pDc->rx_pool_count;
+		curr_idx = priv->rx_tail;
+		pRxHostDesc = &RxHostPool[priv->rx_tail];
+		priv->rx_tail = (priv->rx_tail + 1) % priv->rx_pool_count;
 		rmb();
 		if ((pRxHostDesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
 		 && (pRxHostDesc->Status & cpu_to_le32(BIT31))) {
@@ -4192,7 +4017,7 @@ acx_l_process_rx_desc(wlandevice_t *priv
 			break;
 		}
 		count++;
-		if (unlikely(count > pDc->rx_pool_count)) {
+		if (unlikely(count > priv->rx_pool_count)) {
 			/* hmm, no luck: all descriptors empty, bail out */
 			goto end;
 		}
@@ -4201,7 +4026,7 @@ acx_l_process_rx_desc(wlandevice_t *priv
 	/* now process descriptors, starting with the first we figured out */
 	while (1) {
 		acxlog(L_BUFR, "%s: using curr_idx %u, rx_tail is now %u\n",
-				__func__, curr_idx, pDc->rx_tail);
+				__func__, curr_idx, priv->rx_tail);
 
 		/* FIXME: comment needed - why rmb()? */
 		rmb();
@@ -4215,8 +4040,8 @@ acx_l_process_rx_desc(wlandevice_t *priv
 		CLEAR_BIT(pRxHostDesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
 
 		/* ok, descriptor is handled, now check the next descriptor */
-		curr_idx = pDc->rx_tail;
-		pRxHostDesc = &RxHostPool[pDc->rx_tail];
+		curr_idx = priv->rx_tail;
+		pRxHostDesc = &RxHostPool[priv->rx_tail];
 
 		/* if next descriptor is empty, then bail out */
 		/* FIXME: is this check really entirely correct?? */
@@ -4227,7 +4052,7 @@ acx_l_process_rx_desc(wlandevice_t *priv
 		if (!(pRxHostDesc->Status & cpu_to_le32(BIT31)))
 			break;
 		else
-			pDc->rx_tail = (pDc->rx_tail + 1) % pDc->rx_pool_count;
+			priv->rx_tail = (priv->rx_tail + 1) % priv->rx_pool_count;
 	}
 end:
 	FN_EXIT0;
@@ -4267,11 +4092,10 @@ allocate(wlandevice_t *priv, size_t size
 }
 
 int
-acx_s_create_tx_host_desc_queue(TIWLAN_DC *pDc)
+acx_s_create_tx_host_desc_queue(wlandevice_t *priv)
 {
-	wlandevice_t *priv = pDc->priv;
-	struct txhostdesc *host_desc;
-	struct txhostdesc *host_desc_phy;
+	txhostdesc_t *host_desc;
+	txhostdesc_t *host_desc_phy;
 	u8 *frame_buffer;
 	u8 *frame_buffer_phy;
 	unsigned int align_offs, alignment;
@@ -4280,21 +4104,21 @@ acx_s_create_tx_host_desc_queue(TIWLAN_D
 	FN_ENTER;
 
 	/* allocate TX buffer */
-	pDc->TxBufferPoolSize = priv->TxQueueCnt * WLAN_A4FR_MAXLEN_WEP;
-	pDc->pTxBufferPool = allocate(priv, pDc->TxBufferPoolSize,
-			&pDc->TxBufferPoolPhyAddr, "pTxBufferPool");
-	if (!pDc->pTxBufferPool)
+	priv->TxBufferPoolSize = priv->TxQueueCnt * WLAN_A4FR_MAXLEN_WEP;
+	priv->pTxBufferPool = allocate(priv, priv->TxBufferPoolSize,
+			&priv->TxBufferPoolPhyAddr, "pTxBufferPool");
+	if (!priv->pTxBufferPool)
 		goto fail;
 
 	/* allocate the TX host descriptor queue pool */
-	pDc->TxHostDescQPoolSize = priv->TxQueueCnt * 2*sizeof(struct txhostdesc) + 3;
-	pDc->pTxHostDescQPool = allocate(priv, pDc->TxHostDescQPoolSize,
-			&pDc->TxHostDescQPoolPhyAddr, "pTxHostDescQPool");
-	if (!pDc->pTxHostDescQPool)
+	priv->TxHostDescQPoolSize = priv->TxQueueCnt * 2*sizeof(txhostdesc_t) + 3;
+	priv->pTxHostDescQPool = allocate(priv, priv->TxHostDescQPoolSize,
+			&priv->TxHostDescQPoolPhyAddr, "pTxHostDescQPool");
+	if (!priv->pTxHostDescQPool)
 		goto fail;
 
 	/* check for proper alignment of TX host descriptor pool */
-	alignment = (long) pDc->pTxHostDescQPool & 3;
+	alignment = (long) priv->pTxHostDescQPool & 3;
 	if (alignment) {
 		printk("acx: TxHostDescQPool is not aligned properly\n");
 		align_offs = 4 - alignment;
@@ -4317,10 +4141,10 @@ acx_s_create_tx_host_desc_queue(TIWLAN_D
 /* It is not known whether we need to have 'extra' second
 ** txhostdescs for acx100. Maybe it is acx111-only bug.
 */
-	host_desc = (struct txhostdesc *) ((u8 *) pDc->pTxHostDescQPool + align_offs);
-	host_desc_phy = (struct txhostdesc *) ((u8 *) pDc->TxHostDescQPoolPhyAddr + align_offs);
-	frame_buffer = (u8 *) pDc->pTxBufferPool;
-	frame_buffer_phy = (u8 *) pDc->TxBufferPoolPhyAddr;
+	host_desc = (txhostdesc_t *) ((u8 *) priv->pTxHostDescQPool + align_offs);
+	host_desc_phy = (txhostdesc_t *) ((u8 *) priv->TxHostDescQPoolPhyAddr + align_offs);
+	frame_buffer = (u8 *) priv->pTxBufferPool;
+	frame_buffer_phy = (u8 *) priv->TxBufferPoolPhyAddr;
 
 	for (i = 0; i < priv->TxQueueCnt*2; i++) {
 		if (!(i & 1)) {
@@ -4354,6 +4178,7 @@ acx_s_create_tx_host_desc_queue(TIWLAN_D
 	FN_EXIT1(OK);
 	return OK;
 fail:
+	printk("acx: create_tx_host_desc_queue FAILED\n");
 	/* dealloc will be done by free function on error case */
 	FN_EXIT1(NOT_OK);
 	return NOT_OK;
@@ -4368,40 +4193,38 @@ fail:
 #define RX_BUFFER_SIZE (sizeof(rxbuffer_t) + 32)
 
 int
-acx_s_create_rx_host_desc_queue(TIWLAN_DC *pDc)
+acx_s_create_rx_host_desc_queue(wlandevice_t *priv)
 {
-	wlandevice_t *priv = pDc->priv;
-	struct rxhostdesc *host_desc;
+	rxhostdesc_t *host_desc;
 	rxbuffer_t *data;
-	struct rxhostdesc *host_desc_phy;
+	rxhostdesc_t *host_desc_phy;
 	rxbuffer_t *data_phy;
 	unsigned int align_offs, alignment;
-	int result = NOT_OK;
 	int i;
 
 	FN_ENTER;
 
 	/* allocate the RX host descriptor queue pool */
-	pDc->RxHostDescQPoolSize = (priv->RxQueueCnt * sizeof(struct rxhostdesc)) + 0x3;
+	priv->RxHostDescQPoolSize = (priv->RxQueueCnt * sizeof(rxhostdesc_t)) + 0x3;
 
-	pDc->pRxHostDescQPool = allocate(priv, pDc->RxHostDescQPoolSize,
-			&pDc->RxHostDescQPoolPhyAddr, "pRxHostDescQPool");
-	if (!pDc->pRxHostDescQPool)
+	priv->pRxHostDescQPool = allocate(priv, priv->RxHostDescQPoolSize,
+			&priv->RxHostDescQPoolPhyAddr, "pRxHostDescQPool");
+	if (!priv->pRxHostDescQPool)
 		goto fail;
 
 	/* allocate Rx buffer pool which will be used by the acx
 	 * to store the whole content of the received frames in it */
-	pDc->RxBufferPoolSize = ( priv->RxQueueCnt * RX_BUFFER_SIZE );
-	pDc->pRxBufferPool = allocate(priv, pDc->RxBufferPoolSize,
-			&pDc->RxBufferPoolPhyAddr, "pRxBufferPool");
-	if (!pDc->pRxBufferPool)
+	priv->RxBufferPoolSize = ( priv->RxQueueCnt * RX_BUFFER_SIZE );
+	priv->pRxBufferPool = allocate(priv, priv->RxBufferPoolSize,
+			&priv->RxBufferPoolPhyAddr, "pRxBufferPool");
+	if (!priv->pRxBufferPool)
 		goto fail;
 
-	data = pDc->pRxBufferPool;
-	data_phy = (rxbuffer_t *) pDc->RxBufferPoolPhyAddr;
+	data = priv->pRxBufferPool;
+	data_phy = (rxbuffer_t *) priv->RxBufferPoolPhyAddr;
 
 	/* check for proper alignment of RX host descriptor pool */
-	alignment = (long) pDc->pRxHostDescQPool & 3;
+	alignment = (long) priv->pRxHostDescQPool & 3;
 	if (alignment) {
 		printk("acx: RxHostDescQPool is not aligned properly\n");
 		align_offs = 4 - alignment;
@@ -4409,8 +4232,8 @@ acx_s_create_rx_host_desc_queue(TIWLAN_D
 		align_offs = 0;
 	}
 
-	host_desc = (struct rxhostdesc *) ((u8 *) pDc->pRxHostDescQPool + align_offs);
-	host_desc_phy = (struct rxhostdesc *) ((u8 *) pDc->RxHostDescQPoolPhyAddr + align_offs);
+	host_desc = (rxhostdesc_t *) ((u8 *) priv->pRxHostDescQPool + align_offs);
+	host_desc_phy = (rxhostdesc_t *) ((u8 *) priv->RxHostDescQPoolPhyAddr + align_offs);
 	priv->RxHostDescPoolStart = host_desc_phy;
 
 	/* don't make any popular C programming pointer arithmetic mistakes
@@ -4431,88 +4254,100 @@ acx_s_create_rx_host_desc_queue(TIWLAN_D
 	host_desc->data_phy = ptr2acx(data_phy);
 	host_desc->length = cpu_to_le16(RX_BUFFER_SIZE);
 	CLEAR_BIT(host_desc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-	host_desc->desc_phy_next = ptr2acx((u8 *) pDc->RxHostDescQPoolPhyAddr + align_offs);
-	result = OK;
+	host_desc->desc_phy_next = ptr2acx((u8 *) priv->RxHostDescQPoolPhyAddr + align_offs);
+	FN_EXIT1(OK);
+	return OK;
 fail:
+	printk("acx: create_rx_host_desc_queue FAILED\n");
 	/* dealloc will be done by free function on error case */
-	FN_EXIT1(result);
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***************************************************************
+** acx_s_create_hostdesc_queues
+*/
+int
+acx_s_create_hostdesc_queues(wlandevice_t *priv)
+{
+	int result;
+	result = acx_s_create_tx_host_desc_queue(priv);
+	if (OK != result) return result;
+	result = acx_s_create_rx_host_desc_queue(priv);
 	return result;
 }
 
 
 /***************************************************************
-** acx_s_create_tx_desc_queue
+** acx_create_tx_desc_queue
 */
-extern void BUG_txdesc_must_be_0x30_bytes_in_length(void);
+void BUG_txdesc_must_be_0x30_bytes_in_length(void);
 
-void
-acx_s_create_tx_desc_queue(TIWLAN_DC *pDc)
+static void
+acx_create_tx_desc_queue(wlandevice_t *priv, u32 tx_queue_start)
 {
-	wlandevice_t *priv = pDc->priv;
-	struct txdesc *tx_desc;
-	struct txhostdesc *tx_hostdesc;
-	dma_addr_t hostmemptr; /* remains 0 in USB case */
+	txdesc_t *tx_desc;
+	txhostdesc_t *tx_hostdesc;
+	dma_addr_t hostmemptr;
 	u32 mem_offs;
 	int i;
 
 	FN_ENTER;
 
-	pDc->tx_pool_count = priv->TxQueueCnt;
+	priv->tx_pool_count = priv->TxQueueCnt;
 
-	pDc->TxDescrSize = sizeof(struct txdesc);
+	priv->TxDescrSize = sizeof(txdesc_t);
 
-	if (sizeof(struct txdesc) != 0x30)
+	if (sizeof(txdesc_t) != 0x30)
 		BUG_txdesc_must_be_0x30_bytes_in_length();
 
-	if (priv->chip_type == CHIPTYPE_ACX111) {
+	if (IS_ACX111(priv)) {
 		/* the acx111 txdesc is 4 bytes larger */
-		pDc->TxDescrSize = sizeof(struct txdesc)+4;
+		priv->TxDescrSize = sizeof(txdesc_t) + 4;
 	}
 
-	if (pDc->pTxDescQPool == NULL) { /* calculate it */
-		pDc->pTxDescQPool = (struct txdesc *) (priv->iobase2 +
-					     pDc->ui32ACXTxQueueStart);
-	}
+	priv->pTxDescQPool = (txdesc_t *) (priv->iobase2 + tx_queue_start);
 
-	acxlog(L_DEBUG, "priv->iobase2 = 0x%p\n"
-			"pDc->ui32ACXTxQueueStart = 0x%08X\n"
-			"pDc->pTxDescQPool = 0x%p\n",
+	acxlog(L_DEBUG, "priv->iobase2=%p\n"
+			"tx_queue_start=%08X\n"
+			"priv->pTxDescQPool=%p\n",
 			priv->iobase2,
-			pDc->ui32ACXTxQueueStart,
-			pDc->pTxDescQPool);
+			tx_queue_start,
+			priv->pTxDescQPool);
 
 	priv->TxQueueFree = priv->TxQueueCnt;
-	pDc->tx_head = 0;
-	pDc->tx_tail = 0;
-	tx_desc = pDc->pTxDescQPool;
-	mem_offs = pDc->ui32ACXTxQueueStart;
-	hostmemptr = pDc->TxHostDescQPoolPhyAddr;
-	tx_hostdesc = pDc->pTxHostDescQPool;
+	priv->tx_head = 0;
+	priv->tx_tail = 0;
+	tx_desc = priv->pTxDescQPool;
+	mem_offs = tx_queue_start;
+	hostmemptr = priv->TxHostDescQPoolPhyAddr;
+	tx_hostdesc = priv->pTxHostDescQPool;
 
-	if (CHIPTYPE_ACX111 == priv->chip_type) {
+	if (IS_ACX111(priv)) {
 		/* ACX111 has a preinitialized Tx buffer! */
 		/* loop over whole send pool */
 		/* FIXME: do we have to do the hostmemptr stuff here?? */
-		for (i = 0; i < pDc->tx_pool_count; i++) {
+		for (i = 0; i < priv->tx_pool_count; i++) {
 			tx_desc->HostMemPtr = ptr2acx(hostmemptr);
 			tx_desc->Ctl_8 = DESC_CTL_HOSTOWN;
 			tx_desc->fixed_size.s.host_desc = tx_hostdesc;
 
 			/* reserve two (hdr desc and payload desc) */
 			tx_hostdesc += 2;
-			hostmemptr += 2 * sizeof(struct txhostdesc);
-			tx_desc = (struct txdesc *)(((u8 *)tx_desc) + pDc->TxDescrSize);
+			hostmemptr += 2 * sizeof(txhostdesc_t);
+			tx_desc = (txdesc_t *)(((u8 *)tx_desc) + priv->TxDescrSize);
 		}
 
 	} else {
 		/* ACX100 Tx buffer needs to be initialized by us */
 		/* clear whole send pool */
-		memset(pDc->pTxDescQPool, 0, pDc->tx_pool_count * pDc->TxDescrSize);
+		memset(priv->pTxDescQPool, 0, priv->tx_pool_count * priv->TxDescrSize);
 
 		/* loop over whole send pool */
-		for (i = 0; i < pDc->tx_pool_count; i++) {
+		for (i = 0; i < priv->tx_pool_count; i++) {
 			acxlog(L_DEBUG, "configure card tx descriptor: 0x%p, "
-				"size: 0x%X\n", tx_desc, pDc->TxDescrSize);
+				"size: 0x%X\n", tx_desc, priv->TxDescrSize);
 
 			/* pointer to hostdesc memory */
 			/* FIXME: type-incorrect assignment, might cause trouble
@@ -4522,21 +4357,21 @@ acx_s_create_tx_desc_queue(TIWLAN_DC *pD
 			tx_desc->Ctl_8 = DESC_CTL_INIT;
 			tx_desc->Ctl2_8 = 0;
 			/* point to next txdesc */
-			tx_desc->pNextDesc = cpu2acx(mem_offs + pDc->TxDescrSize);
+			tx_desc->pNextDesc = cpu2acx(mem_offs + priv->TxDescrSize);
 			/* pointer to first txhostdesc */
 			tx_desc->fixed_size.s.host_desc = tx_hostdesc;
 
 			/* reserve two (hdr desc and payload desc) */
 			tx_hostdesc += 2;
-			hostmemptr += 2 * sizeof(struct txhostdesc);
+			hostmemptr += 2 * sizeof(txhostdesc_t);
 			/* go to the next one */
-			mem_offs += pDc->TxDescrSize;
-			tx_desc = (struct txdesc *)(((u8 *)tx_desc) + pDc->TxDescrSize);
+			mem_offs += priv->TxDescrSize;
+			tx_desc = (txdesc_t *)(((u8 *)tx_desc) + priv->TxDescrSize);
 		}
 		/* go back to the last one */
-		tx_desc = (struct txdesc *)(((u8 *)tx_desc) - pDc->TxDescrSize);
+		tx_desc = (txdesc_t *)(((u8 *)tx_desc) - priv->TxDescrSize);
 		/* and point to the first making it a ring buffer */
-		tx_desc->pNextDesc = cpu2acx(pDc->ui32ACXTxQueueStart);
+		tx_desc->pNextDesc = cpu2acx(tx_queue_start);
 	}
 	FN_EXIT0;
 }
@@ -4545,59 +4380,261 @@ acx_s_create_tx_desc_queue(TIWLAN_DC *pD
 /***************************************************************
 ** acx_create_rx_desc_queue
 */
-void
-acx_create_rx_desc_queue(TIWLAN_DC *pDc)
+static void
+acx_create_rx_desc_queue(wlandevice_t *priv, u32 rx_queue_start)
 {
-	wlandevice_t *priv = pDc->priv;
-	struct rxdesc *rx_desc;
+	rxdesc_t *rx_desc;
 	u32 mem_offs;
 	int i;
 
 	FN_ENTER;
 
-	pDc->rx_pool_count = priv->RxQueueCnt;
-	pDc->rx_tail = 0;
+	priv->rx_pool_count = priv->RxQueueCnt;
+	priv->rx_tail = 0;
 
 	/* ACX111 doesn't need any further config: preconfigures itself.
 	 * Simply print ring buffer for debugging */
-	if (CHIPTYPE_ACX111 == priv->chip_type) {
+	if (IS_ACX111(priv)) {
 		/* pRxDescQPool already set here */
-		rx_desc = pDc->pRxDescQPool;
-		for (i = 0; i < pDc->rx_pool_count; i++) {
+
+		priv->pRxDescQPool = (rxdesc_t *) ((u8 *)priv->iobase2 + rx_queue_start);
+
+		rx_desc = priv->pRxDescQPool;
+		for (i = 0; i < priv->rx_pool_count; i++) {
 			acxlog(L_DEBUG, "rx descriptor %d @ 0x%p\n", i, rx_desc);
-			rx_desc = pDc->pRxDescQPool = (struct rxdesc *)
+			rx_desc = priv->pRxDescQPool = (rxdesc_t *)
 				(priv->iobase2 + acx2cpu(rx_desc->pNextDesc));
 		}
 	} else {
 		/* we didn't pre-calculate pRxDescQPool in case of ACX100 */
 		/* pRxDescQPool should be right AFTER Tx pool */
-		pDc->pRxDescQPool = (struct rxdesc *)
-			((u8 *) pDc->pTxDescQPool + (priv->TxQueueCnt * sizeof(struct txdesc)));
+		priv->pRxDescQPool = (rxdesc_t *)
+			((u8 *) priv->pTxDescQPool + (priv->TxQueueCnt * sizeof(txdesc_t)));
+		/* NB: sizeof(txdesc_t) above is valid because we know
+		** we are in if(acx100) block. Beware of cut-n-pasting elsewhere!
+		** acx111's txdesc is larger! */
 
-		memset(pDc->pRxDescQPool, 0, pDc->rx_pool_count * sizeof(struct rxdesc));
+		memset(priv->pRxDescQPool, 0, priv->rx_pool_count * sizeof(rxdesc_t));
 
 		/* loop over whole receive pool */
-		rx_desc = pDc->pRxDescQPool;
-		mem_offs = pDc->ui32ACXRxQueueStart;
-		for (i = 0; i < pDc->rx_pool_count; i++) {
+		rx_desc = priv->pRxDescQPool;
+		mem_offs = rx_queue_start;
+		for (i = 0; i < priv->rx_pool_count; i++) {
 			acxlog(L_DEBUG, "rx descriptor @ 0x%p\n", rx_desc);
 			rx_desc->Ctl_8 = DESC_CTL_RECLAIM | DESC_CTL_AUTODMA;
 			/* point to next rxdesc */
-			rx_desc->pNextDesc = cpu2acx(mem_offs + sizeof(struct rxdesc));
+			rx_desc->pNextDesc = cpu2acx(mem_offs + sizeof(rxdesc_t));
 			/* go to the next one */
-			mem_offs += sizeof(struct rxdesc);
+			mem_offs += sizeof(rxdesc_t);
 			rx_desc++;
 		}
 		/* go to the last one */
 		rx_desc--;
 
 		/* and point to the first making it a ring buffer */
-		rx_desc->pNextDesc = cpu2acx(pDc->ui32ACXRxQueueStart);
+		rx_desc->pNextDesc = cpu2acx(rx_queue_start);
 	}
 	FN_EXIT0;
 }
 
 
+/***************************************************************
+** acx_create_desc_queues
+*/
+void
+acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start)
+{
+	acx_create_tx_desc_queue(priv, tx_queue_start);
+	acx_create_rx_desc_queue(priv, rx_queue_start);
+}
+
+
+/***************************************************************
+** acxpci_s_proc_diag_output
+*/
+char*
+acxpci_s_proc_diag_output(char *p, wlandevice_t *priv)
+{
+	const char *rtl, *thd, *ttl;
+	const rxhostdesc_t *pRxDesc;
+	const txdesc_t *pTxDesc;
+	int i;
+
+	FN_ENTER;
+
+	p += sprintf(p, "** Rx buf **\n");
+	for (i = 0; i < priv->rx_pool_count; i++) {
+		rtl = (i == priv->rx_tail) ? " [tail]" : "";
+		pRxDesc = &priv->pRxHostDescQPool[i];
+		if ((pRxDesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
+		 && (pRxDesc->Status & cpu_to_le32(BIT31)) )
+			p += sprintf(p, "%02u FULL%s\n", i, rtl);
+		else
+			p += sprintf(p, "%02u empty%s\n", i, rtl);
+	}
+	p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", priv->TxQueueFree,
+				acx_queue_stopped(priv->netdev) ? "STOPPED" : "running");
+	pTxDesc = priv->pTxDescQPool;
+	for (i = 0; i < priv->tx_pool_count; i++) {
+		thd = (i == priv->tx_head) ? " [head]" : "";
+		ttl = (i == priv->tx_tail) ? " [tail]" : "";
+		if (pTxDesc->Ctl_8 & DESC_CTL_ACXDONE)
+			p += sprintf(p, "%02u DONE   (%02X)%s%s\n", i, pTxDesc->Ctl_8, thd, ttl);
+		else
+		if (!(pTxDesc->Ctl_8 & DESC_CTL_HOSTOWN))
+			p += sprintf(p, "%02u TxWait (%02X)%s%s\n", i, pTxDesc->Ctl_8, thd, ttl);
+		else
+			p += sprintf(p, "%02u empty  (%02X)%s%s\n", i, pTxDesc->Ctl_8, thd, ttl);
+		pTxDesc = GET_NEXT_TX_DESC_PTR(priv, pTxDesc);
+	}
+	p += sprintf(p,
+		"\n"
+		"** PCI data **\n"
+		"pTxBufferPool %p, TxBufferPoolSize %u, TxBufferPoolPhyAddr %08llx\n"
+		"TxDescrSize %u, pTxDescQPool %p, tx_pool_count %u\n"
+		"pTxHostDescQPool %p, TxHostDescQPoolSize %u, TxHostDescQPoolPhyAddr %08llx\n"
+		"pRxDescQPool %p, rx_pool_count %d\n"
+		"pRxHostDescQPool %p, RxHostDescQPoolSize %u, RxHostDescQPoolPhyAddr %08llx\n"
+		"pRxBufferPool %p, RxBufferPoolSize %u, RxBufferPoolPhyAddr %08llx\n",
+		priv->pTxBufferPool, priv->TxBufferPoolSize, (u64)priv->TxBufferPoolPhyAddr,
+		priv->TxDescrSize, priv->pTxDescQPool, priv->tx_pool_count,
+		priv->pTxHostDescQPool, priv->TxHostDescQPoolSize, (u64)priv->TxHostDescQPoolPhyAddr,
+		priv->pRxDescQPool, priv->rx_pool_count,
+		priv->pRxHostDescQPool, priv->RxHostDescQPoolSize, (u64)priv->RxHostDescQPoolPhyAddr,
+		priv->pRxBufferPool, priv->RxBufferPoolSize, (u64)priv->RxBufferPoolPhyAddr);
+
+	return p;
+}
+
+
+/***********************************************************************
+*/
+int
+acx_proc_eeprom_output(char *buf, wlandevice_t *priv)
+{
+	char *p = buf;
+	int i;
+
+	FN_ENTER;
+
+	for (i = 0; i < 0x400; i++) {
+		acx_read_eeprom_offset(priv, i, p++);
+	}
+
+	FN_EXIT1(p - buf);
+	return p - buf;
+}
+
+
+/***********************************************************************
+*/
+void
+acx_set_interrupt_mask(wlandevice_t *priv)
+{
+	if (IS_ACX111(priv)) {
+		priv->irq_mask = (u16) ~(0
+				/* | HOST_INT_RX_DATA        */
+				| HOST_INT_TX_COMPLETE
+				/* | HOST_INT_TX_XFER        */
+				| HOST_INT_RX_COMPLETE
+				/* | HOST_INT_DTIM           */
+				/* | HOST_INT_BEACON         */
+				/* | HOST_INT_TIMER          */
+				/* | HOST_INT_KEY_NOT_FOUND  */
+				| HOST_INT_IV_ICV_FAILURE
+				| HOST_INT_CMD_COMPLETE
+				| HOST_INT_INFO
+				/* | HOST_INT_OVERFLOW       */
+				/* | HOST_INT_PROCESS_ERROR  */
+				| HOST_INT_SCAN_COMPLETE
+				| HOST_INT_FCS_THRESHOLD
+				/* | HOST_INT_UNKNOWN        */
+				);
+		priv->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */
+	} else {
+		priv->irq_mask = (u16) ~(0
+				/* | HOST_INT_RX_DATA        */
+				| HOST_INT_TX_COMPLETE
+				/* | HOST_INT_TX_XFER        */
+				| HOST_INT_RX_COMPLETE
+				/* | HOST_INT_DTIM           */
+				/* | HOST_INT_BEACON         */
+				/* | HOST_INT_TIMER          */
+				/* | HOST_INT_KEY_NOT_FOUND  */
+				/* | HOST_INT_IV_ICV_FAILURE */
+				| HOST_INT_CMD_COMPLETE
+				| HOST_INT_INFO
+				/* | HOST_INT_OVERFLOW       */
+				/* | HOST_INT_PROCESS_ERROR  */
+				| HOST_INT_SCAN_COMPLETE
+				/* | HOST_INT_FCS_THRESHOLD  */
+				/* | HOST_INT_UNKNOWN        */
+				);
+		priv->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */
+	}
+}
+
+
+/***********************************************************************
+*/
+int
+acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
+{
+	/* since it can be assumed that at least the Maxim radio has a
+	 * maximum power output of 20dBm and since it also can be
+	 * assumed that these values drive the DAC responsible for
+	 * setting the linear Tx level, I'd guess that these values
+	 * should be the corresponding linear values for a dBm value,
+	 * in other words: calculate the values from that formula:
+	 * Y [dBm] = 10 * log (X [mW])
+	 * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
+	 * and you're done...
+	 * Hopefully that's ok, but you never know if we're actually
+	 * right... (especially since Windows XP doesn't seem to show
+	 * actual Tx dBm values :-P) */
+
+	/* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the
+	 * values are EXACTLY mW!!! Not sure about RFMD and others,
+	 * though... */
+	static const u8 dbm2val_maxim[21] = {
+		63, 63, 63, 62,
+		61, 61, 60, 60,
+		59, 58, 57, 55,
+		53, 50, 47, 43,
+		38, 31, 23, 13,
+		0
+	};
+	static const u8 dbm2val_rfmd[21] = {
+		 0,  0,  0,  1,
+		 2,  2,  3,  3,
+		 4,  5,  6,  8,
+		10, 13, 16, 20,
+		25, 32, 41, 50,
+		63
+	};
+	const u8 *table;
+
+	switch (priv->radio_type) {
+		case RADIO_MAXIM_0D:
+			table = &dbm2val_maxim[0];
+			break;
+		case RADIO_RFMD_11:
+		case RADIO_RALINK_15:
+			table = &dbm2val_rfmd[0];
+			break;
+		default:
+			printk("%s: unknown/unsupported radio type, "
+				"cannot modify tx power level yet!\n",
+					priv->netdev->name);
+			return NOT_OK;
+	}
+	printk("%s: changing radio power level to %u dBm (%u)\n",
+			priv->netdev->name, level_dbm, table[level_dbm]);
+	acxpci_s_write_phy_reg(priv, 0x11, table[level_dbm]);
+	return OK;
+}
+
+
 /*----------------------------------------------------------------
 * acx_e_init_module
 *
@@ -4610,53 +4647,13 @@ acx_create_rx_desc_queue(TIWLAN_DC *pDc)
 * Call context:
 *	process thread (insmod or modprobe)
 ----------------------------------------------------------------*/
-/* introduced earlier than 2.6.10, but takes more memory, so don't use it
- * if there's no compile warning by kernel */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-
-#if ACX_DEBUG
-module_param(acx_debug, uint, 0);
-#endif
-#if USE_FW_LOADER_LEGACY
-module_param(firmware_dir, charp, 0);
-#endif
-
-#else
-
-#if ACX_DEBUG
-/* doh, 2.6.x screwed up big time: here the define has its own ";"
- * ("double ; detected"), yet in 2.4.x it DOESN'T (the sane thing to do),
- * grrrrr! */
-MODULE_PARM(debug, "i");
-#endif
-#if USE_FW_LOADER_LEGACY
-MODULE_PARM(firmware_dir, "s");
-#endif
-
-#endif
-
-MODULE_PARM_DESC(debug, "Debug level mask (see L_xxx constants)");
-#if USE_FW_LOADER_LEGACY
-MODULE_PARM_DESC(firmware_dir, "Directory to load acx100 firmware files from");
-#endif
-#if SEPARATE_DRIVER_INSTANCES
-MODULE_PARM(card, "i");
-MODULE_PARM_DESC(card, "Associate only with card-th acx100 card from this "
-				"driver instance");
-#endif /* SEPARATE_DRIVER_INSTANCES */
-
-static int __init
-acx_e_init_module(void)
+int __init
+acxpci_e_init_module(void)
 {
 	int res;
 
 	FN_ENTER;
 
-	printk("acx: this driver is still EXPERIMENTAL\n"
-	       "acx: reading README file and/or Craig's HOWTO is "
-	       "recommended, visit http://acx100.sf.net in case "
-	       "of further questions/discussion\n");
-
 #if (ACX_IO_WIDTH==32)
 	printk("acx: compiled to use 32bit I/O access. "
 		"I/O timing issues might occur, such as "
@@ -4671,7 +4668,7 @@ acx_e_init_module(void)
 #else
 	acxlog(L_INIT, "running on a BIG-ENDIAN CPU\n");
 #endif
-	acxlog(L_INIT, "acx_pci module " WLAN_RELEASE " initialized, "
+	acxlog(L_INIT, "PCI module " WLAN_RELEASE " initialized, "
 		"waiting for cards to probe...\n");
 
 	res = pci_module_init(&acx_pci_drv_id);
@@ -4689,8 +4686,8 @@ acx_e_init_module(void)
 * Call context:
 *	process thread
 ----------------------------------------------------------------*/
-static void __exit
-acx_e_cleanup_module(void)
+void __exit
+acxpci_e_cleanup_module(void)
 {
 	const struct net_device *dev;
 	unsigned long flags;
@@ -4718,7 +4715,7 @@ acx_e_cleanup_module(void)
 		acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
 		acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0);
 
-#if REDUNDANT
+#ifdef REDUNDANT
 		/* put the eCPU to sleep to save power
 		 * Halting is not possible currently,
 		 * since not supported by all firmware versions */
@@ -4731,7 +4728,7 @@ acx_e_cleanup_module(void)
 		acx_l_power_led(priv, 0);
 
 		/* stop our eCPU */
-		if (priv->chip_type == CHIPTYPE_ACX111) {
+		if (IS_ACX111(priv)) {
 			/* FIXME: does this actually keep halting the eCPU?
 			 * I don't think so...
 			 */
@@ -4760,18 +4757,3 @@ acx_e_cleanup_module(void)
 
 	FN_EXIT0;
 }
-
-module_init(acx_e_init_module)
-module_exit(acx_e_cleanup_module)
-
-#if USE_FW_LOADER_LEGACY
-static int __init acx_get_firmware_dir(const char *str)
-{
-	/* I've seen other drivers just pass the string pointer,
-	 * so hopefully that's safe */
-	firmware_dir = str;
-	return OK;
-}
-
-__setup("acx_firmware_dir=", acx_get_firmware_dir);
-#endif
diff -L drivers/net/wireless/tiacx/pci_helper.c -puN drivers/net/wireless/tiacx/pci_helper.c~acx-update /dev/null
--- 25/drivers/net/wireless/tiacx/pci_helper.c
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,2 +0,0 @@
-#define ACX_PCI 1
-#include "helper.c"
diff -puN drivers/net/wireless/tiacx/setrate.c~acx-update drivers/net/wireless/tiacx/setrate.c
--- 25/drivers/net/wireless/tiacx/setrate.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/setrate.c	Fri Sep  9 17:28:49 2005
@@ -82,7 +82,7 @@ get_modulation(int r_enum, char suffix) 
 	return -EINVAL;
 }
 
-#if UNUSED
+#ifdef UNUSED
 static int
 fill_ratevector(const char **pstr, u8 *vector, int size,
 		int (*supported)(int mbit, int mod, void *opaque), void *opaque, int or_mask)
diff -puN drivers/net/wireless/tiacx/usb.c~acx-update drivers/net/wireless/tiacx/usb.c
--- 25/drivers/net/wireless/tiacx/usb.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/usb.c	Fri Sep  9 17:28:49 2005
@@ -67,12 +67,6 @@
 
 #include "acx.h"
 
-
-/***********************************************************************
-** try to make it compile for both 2.4.x and 2.6.x kernels
-*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
-
 /* number of endpoints of an interface */
 #define NUM_EP(intf) (intf)->altsetting[0].desc.bNumEndpoints
 #define EP(intf, nr) (intf)->altsetting[0].endpoint[(nr)].desc
@@ -95,86 +89,6 @@ alloc_urb(int iso_pk, int mem_flags)
 	return usb_alloc_urb(iso_pk, mem_flags);
 }
 
-#else
-
-/* 2.4.x kernels */
-#define USB_24	1
-
-#define NUM_EP(intf) (intf)->altsetting[0].bNumEndpoints
-#define EP(intf, nr) (intf)->altsetting[0].endpoint[(nr)]
-
-#define GET_DEV(udev) usb_inc_dev_use((udev))
-#define PUT_DEV(udev) usb_dec_dev_use((udev))
-
-#ifndef SET_NETDEV_DEV
-#define SET_NETDEV_DEV(x, y)
-#endif
-#define SET_NETDEV_OWNER(ndev, owner) ndev->owner = owner
-
-#define ASYNC_UNLINK	USB_ASYNC_UNLINK
-#define QUEUE_BULK	USB_QUEUE_BULK
-#define ZERO_PACKET	USB_ZERO_PACKET
-
-static inline int
-submit_urb(struct urb *urb, int mem_flags)
-{
-	return usb_submit_urb(urb);
-}
-static inline struct urb*
-alloc_urb(int iso_pk, int mem_flags)
-{
-	return usb_alloc_urb(iso_pk);
-}
-
-static inline void
-usb_set_intfdata(struct usb_interface *intf, void *data)
-{
-}
-
-#endif /* #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) */
-
-
-/***********************************************************************
-** Module Stuff
-*/
-#if ACX_DEBUG
-unsigned int acx_debug = L_ASSOC|L_INIT;
-#endif
-
-#if USE_FW_LOADER_LEGACY
-char *firmware_dir;
-#endif
-
-#ifdef MODULE_LICENSE
-MODULE_LICENSE("Dual MPL/GPL");
-#endif
-MODULE_AUTHOR("Martin Wawro <martin.wawro AT uni-dortmund.de>");
-MODULE_DESCRIPTION("TI ACX100 WLAN USB Driver");
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-
-#if ACX_DEBUG
-module_param(acx_debug, uint, 0);
-#endif
-#if USE_FW_LOADER_LEGACY
-module_param(firmware_dir, charp, 0);
-#endif
-
-#else
-
-#if ACX_DEBUG
-MODULE_PARM(debug, "i");
-#endif
-#if USE_FW_LOADER_LEGACY
-MODULE_PARM(firmware_dir, "s");
-#endif
-
-#endif
-
-MODULE_PARM_DESC(debug, "Debug level mask: 0x0000 - 0x3fff");
-#if USE_FW_LOADER_LEGACY
-MODULE_PARM_DESC(firmware_dir, "Directory to load acx100 firmware files from");
-#endif
 
 /***********************************************************************
 */
@@ -193,17 +107,10 @@ MODULE_PARM_DESC(firmware_dir, "Director
 /***********************************************************************
 ** Prototypes
 */
-#if USB_24
-static void* acx100usb_e_probe(struct usb_device *, unsigned int, const struct usb_device_id *);
-static void acx100usb_e_disconnect(struct usb_device *, void *);
-static void acx100usb_i_complete_tx(struct urb *);
-static void acx100usb_i_complete_rx(struct urb *);
-#else
 static int acx100usb_e_probe(struct usb_interface *, const struct usb_device_id *);
 static void acx100usb_e_disconnect(struct usb_interface *);
 static void acx100usb_i_complete_tx(struct urb *, struct pt_regs *);
 static void acx100usb_i_complete_rx(struct urb *, struct pt_regs *);
-#endif
 static int acx100usb_e_open(struct net_device *);
 static int acx100usb_e_close(struct net_device *);
 static void acx100usb_i_set_rx_mode(struct net_device *);
@@ -220,11 +127,6 @@ static void acx100usb_i_tx_timeout(struc
 /* static void dump_device(struct usb_device *); */
 /* static void dump_device_descriptor(struct usb_device_descriptor *); */
 /* static void dump_config_descriptor(struct usb_config_descriptor *); */
-#if USB_24
-static void dump_endpoint_descriptor(struct usb_endpoint_descriptor *);
-static void dump_interface_descriptor(struct usb_interface_descriptor *);
-#endif
-
 
 /***********************************************************************
 ** Module Data
@@ -247,6 +149,7 @@ acx100usb_ids[] = {
 static struct usb_driver
 acx100usb_driver = {
 	.name = "acx_usb",
+	.owner = THIS_MODULE,
 	.probe = acx100usb_e_probe,
 	.disconnect = acx100usb_e_disconnect,
 	.id_table = acx100usb_ids
@@ -255,18 +158,38 @@ acx100usb_driver = {
 
 /***********************************************************************
 ** USB helper
+**
+** ldd3 ch13 says:
+** When the function is usb_kill_urb, the urb lifecycle is stopped. This
+** function is usually used when the device is disconnected from the system,
+** in the disconnect callback. For some drivers, the usb_unlink_urb function
+** should be used to tell the USB core to stop an urb. This function does not
+** wait for the urb to be fully stopped before returning to the caller.
+** This is useful for stoppingthe urb while in an interrupt handler or when
+** a spinlock is held, as waiting for a urb to fully stop requires the ability
+** for the USB core to put the calling process to sleep. This function requires
+** that the URB_ASYNC_UNLINK flag value be set in the urb that is being asked
+** to be stopped in order to work properly.
+**
+** In light of this, timeout is just for paranoid reasons...
 */
 static void
-acx_unlink_and_free_urb(struct urb* urb) {
+acx_unlink_and_free_urb(struct urb* urb)
+{
 	if (!urb)
 		return;
+
 	if (urb->status == -EINPROGRESS) {
+		int timeout = 10;
+
 		usb_unlink_urb(urb);
-//TODO: timeout!
-		while (urb->status == -EINPROGRESS) {
-			mdelay(2);
+		while (--timeout && urb->status == -EINPROGRESS) {
+			mdelay(1);
 		}
+		/* if (!timeout) then what?? */
 	}
+
+	/* just a refcounted kfree, safe undef lock */
 	usb_free_urb(urb);
 }
 
@@ -274,33 +197,6 @@ acx_unlink_and_free_urb(struct urb* urb)
 /***********************************************************************
 */
 #if ACX_DEBUG
-#if USB_24
-static char*
-acx100usb_pstatus(int val)
-{
-#define CASE(status)	case status: return ""#status""
-	switch (val) {
-		CASE(USB_ST_NOERROR);
-		CASE(USB_ST_CRC);
-		CASE(USB_ST_BITSTUFF);
-		CASE(USB_ST_DATAOVERRUN);
-		CASE(USB_ST_BUFFEROVERRUN);
-		CASE(USB_ST_BUFFERUNDERRUN);
-		CASE(USB_ST_SHORT_PACKET);
-		CASE(USB_ST_URB_KILLED);
-		CASE(USB_ST_URB_PENDING);
-		CASE(USB_ST_REMOVED);
-		CASE(USB_ST_TIMEOUT);
-		CASE(USB_ST_NOTSUPPORTED);
-		CASE(USB_ST_BANDWIDTH_ERROR);
-		CASE(USB_ST_URB_INVALID_ERROR);
-		CASE(USB_ST_URB_REQUEST_ERROR);
-		CASE(USB_ST_STALL);
-	default:
-		return "UNKNOWN";
-	}
-}
-#else
 static char*
 acx100usb_pstatus(int val)
 {
@@ -313,7 +209,6 @@ acx100usb_pstatus(int val)
 
 	return status;
 }
-#endif /* USB_24 */
 #endif /* ACX_DEBUG */
 
 
@@ -321,10 +216,10 @@ acx100usb_pstatus(int val)
 ** EEPROM and PHY read/write helpers
 */
 /***********************************************************************
-** acx_s_read_phy_reg
+** acxusb_s_read_phy_reg
 */
 int
-acx_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
+acxusb_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
 {
 	int result = NOT_OK;
 	mem_read_write_t mem;
@@ -348,7 +243,7 @@ fail:
 /***********************************************************************
 */
 int
-acx_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
+acxusb_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
 {
 	mem_read_write_t mem;
 
@@ -370,29 +265,33 @@ acx_s_write_phy_reg(wlandevice_t *priv, 
 ** acx_s_issue_cmd_timeo
 ** Excecutes a command in the command mailbox
 **
-** Arguments:
-**   *pcmdparam = an pointer to the data. The data mustn't include
-**                the 4 byte command header!
+** buffer = a pointer to the data.
+** The data must not include 4 byte command header
 */
+
+/* TODO: ideally we shall always know how much we need
+** and this shall be 0 */
+#define BOGUS_SAFETY_PADDING 0x40
+
 #undef FUNC
 #define FUNC "issue_cmd"
 
 #if !ACX_DEBUG
 int
-acx_s_issue_cmd_timeo(
+acxusb_s_issue_cmd_timeo(
 	wlandevice_t *priv,
 	unsigned cmd,
-	void *pdr,
-	unsigned paramlen,
+	void *buffer,
+	unsigned buflen,
 	unsigned timeout)
 {
 #else
 int
-acx_s_issue_cmd_timeo_debug(
+acxusb_s_issue_cmd_timeo_debug(
 	wlandevice_t *priv,
 	unsigned cmd,
-	void *pdr,
-	unsigned paramlen,
+	void *buffer,
+	unsigned buflen,
 	unsigned timeout,
 	const char* cmdstr)
 {
@@ -403,21 +302,27 @@ acx_s_issue_cmd_timeo_debug(
 	struct {
 		u16	cmd ACX_PACKED;
 		u16	status ACX_PACKED;
-		u8	data[3000]; //former boguspad. try [ACX100_USB_RWMEM_MAXLEN-4] later!
+		u8	data[1] ACX_PACKED;
 	} *loc;
+	const char *devname;
 	int acklen, blocklen, inpipe, outpipe;
+	int cmd_status;
 	int result;
 
 	FN_ENTER;
 
-	acxlog(L_CTL, FUNC"(cmd:%s,paramlen:%u,type:%d)\n",
-			cmdstr, paramlen,
-			pdr ? le16_to_cpu(((acx_ie_generic_t *)pdr)->type) : -1);
+	devname = priv->netdev->name;
+	if (!devname || !devname[0])
+		devname = "acx";
+
+	acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,type:0x%04X)\n",
+		cmdstr, buflen,
+		buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
 
-	loc = kmalloc(sizeof(*loc), GFP_KERNEL);
+	loc = kmalloc(buflen + 4 + BOGUS_SAFETY_PADDING, GFP_KERNEL);
 	if (!loc) {
-		printk("acx: "FUNC"() failed to alloc data buffer\n");
-		goto fail;
+		printk("%s: "FUNC"(): no memory for data buffer\n", devname);
+		goto bad;
 	}
 
 	/* get context from wlandevice */
@@ -427,26 +332,27 @@ acx_s_issue_cmd_timeo_debug(
 	loc->cmd = cpu_to_le16(cmd);
 	loc->status = 0;
 
-/* NB: paramlen == ((acx_ie_generic_t*)pdr)->len + 4 on entry
+/* NB: buflen == frmlen + 4
+**
+** Interrogate: write 8 bytes: (cmd,status,rid,frmlen), then
+**		read (cmd,status,rid,frmlen,data[frmlen]) back
 **
-** Interrogate: write 8-byte (cmd,status,rid,frmlen),
-**	read data[frmlen+8] back
 ** Configure: write (cmd,status,rid,frmlen,data[frmlen])
 **
 ** Possibly bogus special handling of ACX1xx_IE_SCAN_STATUS removed
 */
 
 	/* now write the parameters of the command if needed */
-	acklen = sizeof(loc->data);
-	blocklen = paramlen;
-	if (pdr && paramlen) {
+	acklen = buflen + 4 + BOGUS_SAFETY_PADDING;
+	blocklen = buflen;
+	if (buffer && buflen) {
 		/* if it's an INTERROGATE command, just pass the length
 		 * of parameters to read, as data */
 		if (cmd == ACX1xx_CMD_INTERROGATE) {
 			blocklen = 4;
-			acklen = paramlen + 4;
+			acklen = buflen + 4;
 		}
-		memcpy(loc->data, pdr, blocklen);
+		memcpy(loc->data, buffer, blocklen);
 	}
 	blocklen += 4; /* account for cmd,status */
 
@@ -469,13 +375,12 @@ acx_s_issue_cmd_timeo_debug(
 	);
 	acxlog(L_CTL, "wrote %d bytes\n", result);
 	if (result < 0) {
-		goto fail;
+		goto bad;
 	}
 
 	/* check for device acknowledge */
-	acxlog(L_CTL, "sending USB control msg (in) (acklen=%d) "
-		"sizeof(loc->data)=%d\n", acklen, (int) sizeof(loc->data));
-	loc->status = 0; /* delete old status flag -> set to fail */
+	acxlog(L_CTL, "sending USB control msg (in) (acklen=%d)\n", acklen);
+	loc->status = 0; /* delete old status flag -> set to IDLE */
 //shall we zero out the rest?
 	result = usb_control_msg(usbdev, inpipe,
 		ACX_USB_REQ_CMD, /* request */
@@ -486,14 +391,18 @@ acx_s_issue_cmd_timeo_debug(
 		acklen, /* size */
 		USB_CTRL_HARD_TIMEOUT /* timeout in ms */
 	);
-	acxlog(L_CTL, "read %d bytes\n", result);
 	if (result < 0) {
-		goto fail;
+		printk("%s: "FUNC"(): USB read error %d\n", devname, result);
+		goto bad;
+	}
+	if (acx_debug & L_CTL) {
+		printk("read %d bytes: ", result);
+		acx_dump_bytes(loc, result);
 	}
 
-//check for result==paramlen+4? Was seen:
+//check for result==buflen+4? Was seen:
 //interrogate(type:ACX100_IE_DOT11_ED_THRESHOLD,len:4)
-//issue_cmd(cmd:ACX1xx_CMD_INTERROGATE,paramlen:8,type:4111)
+//issue_cmd(cmd:ACX1xx_CMD_INTERROGATE,buflen:8,type:4111)
 //ctrl inpipe=0x80000280 outpipe=0x80000200
 //sending USB control msg (out) (blocklen=8)
 //01 00 00 00 0F 10 04 00
@@ -501,25 +410,31 @@ acx_s_issue_cmd_timeo_debug(
 //sending USB control msg (in) (acklen=12) sizeof(loc->data
 //read 4 bytes <==== MUST BE 12!!
 
-	if (le16_to_cpu(loc->status) != 1) {
-		printk("%s: warning: command returned status %u\n",
-			priv->netdev->name, le16_to_cpu(loc->status));
-	}
-	if ((cmd == ACX1xx_CMD_INTERROGATE) && pdr && paramlen) {
-		memcpy(pdr, loc->data, paramlen);
-		acxlog(L_CTL, "response frame: cmd=%u status=%u\n",
+	cmd_status = le16_to_cpu(loc->status);
+	if (cmd_status != 1) {
+		printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s)\n",
+			devname, cmd_status, acx_cmd_status_str(cmd_status));
+		/* TODO: goto bad; ? */
+	}
+	if ((cmd == ACX1xx_CMD_INTERROGATE) && buffer && buflen) {
+		memcpy(buffer, loc->data, buflen);
+		acxlog(L_CTL, "response frame: cmd=0x%04X status=%d\n",
 			le16_to_cpu(loc->cmd),
-			le16_to_cpu(loc->status));
-		if (acx_debug & L_DATA) {
-			printk("incoming bytes (%d):\n", paramlen);
-			acx_dump_bytes(pdr, paramlen);
-		}
+			cmd_status);
 	}
 	kfree(loc);
 	FN_EXIT1(OK);
 	return OK;
-fail:
+bad:
 	kfree(loc);
+	/* Give enough info so that callers can avoid
+	** printing their own diagnostic messages */
+#if ACX_DEBUG
+	printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
+#else
+	printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
+#endif
+	dump_stack();
 	FN_EXIT1(NOT_OK);
 	return NOT_OK;
 }
@@ -544,21 +459,10 @@ fail:
 **  In case this driver is able to handle one of the offered devices, it returns
 **  a non-null pointer to a driver context and thereby claims the device.
 */
-#if USB_24
-#define OUTOFMEM	NULL
-static void*
-acx100usb_e_probe(struct usb_device *usbdev, unsigned int ifNum,
-				const struct usb_device_id *devID)
-{
-	void *res = NULL;
-#else
-#define OUTOFMEM	-ENOMEM
 static int
 acx100usb_e_probe(struct usb_interface *intf, const struct usb_device_id *devID)
 {
 	struct usb_device *usbdev = interface_to_usbdev(intf);
-	int res = 0;
-#endif
 	wlandevice_t *priv = NULL;
 	struct net_device *dev = NULL;
 	struct usb_config_descriptor *config;
@@ -568,8 +472,9 @@ acx100usb_e_probe(struct usb_interface *
 #endif
 	struct usb_interface_descriptor *ifdesc;
 	const char* msg;
-	int i, numep;
-	int numconfigs, numfaces, result = 0;
+	int numconfigs, numfaces, numep;
+	int result = OK;
+	int i;
 
 	FN_ENTER;
 
@@ -585,11 +490,7 @@ acx100usb_e_probe(struct usb_interface *
 		** return a NULL
 		*/
 		acxlog(L_INIT, "finished booting, returning from probe()\n");
-#if USB_24
-		res = NULL;
-#else
-		res = 0; /* is that ok?? */
-#endif
+		result = OK; /* success */
 		goto end;
 	}
 
@@ -609,6 +510,7 @@ acx100usb_e_probe(struct usb_interface *
 		goto end_nomem;
 	}
 	memset(priv, 0, sizeof(wlandevice_t));
+	priv->dev_type = DEVTYPE_USB;
 	priv->chip_type = CHIPTYPE_ACX100;
 	/* FIXME: should be read from register (via firmware) using standard ACX code */
 	priv->radio_type = RADIO_MAXIM_0D;
@@ -627,21 +529,15 @@ acx100usb_e_probe(struct usb_interface *
 		printk("acx: number of configurations is %d, "
 			"this driver only knows how to handle 1, "
 			"be prepared for surprises\n", numconfigs);
-#if USB_24
-	config = usbdev->actconfig;
-#else
+
 	config = &usbdev->config->desc;
-#endif
 	numfaces = config->bNumInterfaces;
 	if (numfaces != 1)
 		printk("acx: number of interfaces is %d, "
 			"this driver only knows how to handle 1, "
 			"be prepared for surprises\n", numfaces);
-#if USB_24
-	ifdesc = config->interface->altsetting;
-#else
+
 	ifdesc = &intf->altsetting->desc;
-#endif
 	numep = ifdesc->bNumEndpoints;
 	acxlog(L_DEBUG, "# of endpoints: %d\n", numep);
 
@@ -722,10 +618,10 @@ acx100usb_e_probe(struct usb_interface *
 		msg = "acx: no memory for wlan device name\n";
 		goto end_nomem;
 	}
-#if USB_26
+
 	usb_set_intfdata(intf, priv);
 	SET_NETDEV_DEV(dev, &intf->dev);
-#endif
+
 	/* Register the network device */
 	acxlog(L_INIT, "registering network device\n");
 	result = register_netdev(dev);
@@ -740,12 +636,14 @@ acx100usb_e_probe(struct usb_interface *
 	}
 #endif
 
-	/* Everything went OK, we are happy now	*/
-#if USB_24
-	res = priv;
-#else
-	res = 0;
+	printk("acx: USB module " WLAN_RELEASE " loaded successfully\n");
+
+#if CMD_DISCOVERY
+	great_inquisistor(priv);
 #endif
+
+	/* Everything went OK, we are happy now	*/
+	result = OK;
 	goto end;
 
 end_nomem:
@@ -760,20 +658,17 @@ end_nomem:
 		}
 		kfree(priv);
 	}
-	res = OUTOFMEM;
+	result = -ENOMEM;
 	goto end;
 
 end_nodev:
 
-	/* no device we could handle, return NULL */
-#if USB_24
-	res = NULL;
-#else
-	res = -EIO;
-#endif
+	/* no device we could handle, return error. */
+	result = -EIO;
+
 end:
-	FN_EXIT1((int)res);
-	return res;
+	FN_EXIT1(result);
+	return result;
 }
 
 
@@ -789,32 +684,39 @@ end:
 **  network devices have to be taken down and all allocated memory has
 **  to be freed.
 */
-#if USB_24
-static void
-acx100usb_e_disconnect(struct usb_device *usbdev, void *devContext)
-{
-	wlandevice_t *priv = (wlandevice_t *)devContext;
-#else
 static void
 acx100usb_e_disconnect(struct usb_interface *intf)
 {
 	wlandevice_t *priv = usb_get_intfdata(intf);
-#endif
-	int i, result;
+	unsigned long flags;
+	int i;
+
+	FN_ENTER;
 
 	/* No WLAN device...no sense */
 	if (!priv)
-		return;
+		goto end;
 
+	/*
+	 * We get the sem *after* FLUSH to avoid a deadlock.
+	 * See pci.c:acx_s_down() for deails.
+	 */
+	FLUSH_SCHEDULED_WORK();
 	acx_sem_lock(priv);
 
+	acx_lock(priv, flags);
+
+	/* I wonder if above is enough to prevent tx/rx callbacks
+	** to start queue again? Like this:
+	** complete_rx -> acx_l_process_rxbuf -> associated -> acx_start_queue()
+	** Oh well... */
+
+	/* This device exists no more. */
+	usb_set_intfdata(intf, NULL);
+
 	/* stop the transmit queue */
 	if (priv->netdev) {
-		rtnl_lock();
-		if (!acx_queue_stopped(priv->netdev)) {
-			acx_stop_queue(priv->netdev, "on USB disconnect");
-		}
-		rtnl_unlock();
+		acx_stop_queue(priv->netdev, "on USB disconnect");
 #ifdef CONFIG_PROC_FS
 		acx_proc_unregister_entries(priv->netdev);
 #endif
@@ -826,11 +728,11 @@ acx100usb_e_disconnect(struct usb_interf
 		acx_unlink_and_free_urb(priv->usb_tx[i].urb);
 	}
 
+	acx_unlock(priv, flags);
+
 	/* Unregister the network devices */
 	if (priv->netdev) {
-		rtnl_lock();
-		result = unregister_netdevice(priv->netdev);
-		rtnl_unlock();
+		unregister_netdev(priv->netdev);
 		kfree(priv->netdev);
 	}
 
@@ -838,6 +740,8 @@ acx100usb_e_disconnect(struct usb_interf
 
 	/* finally free the WLAN device */
 	kfree(priv);
+end:
+	FN_EXIT0;
 }
 
 
@@ -869,6 +773,8 @@ acx100usb_boot(struct usb_device *usbdev
 	u32 size;
 	int result;
 
+	FN_ENTER;
+
 	usbbuf = kmalloc(ACX100_USB_RWMEM_MAXLEN, GFP_KERNEL);
 	if (!usbbuf) {
 		printk(KERN_ERR "acx: no memory for USB transfer buffer ("
@@ -962,6 +868,8 @@ acx100usb_boot(struct usb_device *usbdev
 end:
 	vfree(firmware);
 	kfree(usbbuf);
+
+	FN_EXIT1(result);
 	return result;
 }
 
@@ -979,6 +887,8 @@ acx100usb_e_init_network_device(struct n
 	int result = 0;
 	wlandevice_t *priv;
 
+	FN_ENTER;
+
 	/* Setup the device and stop the queue */
 	ether_setup(dev);
 	acx_stop_queue(dev, "on init");
@@ -1019,6 +929,7 @@ acx100usb_e_init_network_device(struct n
 end:
 	acx_sem_unlock(priv);
 
+	FN_EXIT1(result);
 	return result;
 }
 
@@ -1114,13 +1025,10 @@ acx100usb_l_poll_rx(wlandevice_t *priv, 
 		rxcon /* handler param */
 	);
 	rxurb->transfer_flags = ASYNC_UNLINK|QUEUE_BULK;
-#if USB_24
-	rxurb->timeout = 0;
-	rxurb->status = 0;
-#endif
+
 	/* ATOMIC: we may be called from complete_rx() usb callback */
 	errcode = submit_urb(rxurb, GFP_ATOMIC);
-	/* FIXME: evaluate the error code ! */
+	/* FIXME: evaluate the error code! */
 	acxlog(L_USBRXTX, "SUBMIT RX (%d) inpipe=0x%X size=%d errcode=%d\n",
 			number, inpipe, (int) RXBUFSIZE, errcode);
 
@@ -1141,13 +1049,8 @@ end:
 **  The received data is then committed to the network stack and the next
 **  USB receive is triggered.
 */
-#if USB_24
-static void
-acx100usb_i_complete_rx(struct urb *urb)
-#else
 static void
 acx100usb_i_complete_rx(struct urb *urb, struct pt_regs *regs)
-#endif
 {
 	wlandevice_t *priv;
 	rxbuffer_t *ptr;
@@ -1163,6 +1066,12 @@ acx100usb_i_complete_rx(struct urb *urb,
 	}
 
 	priv = ((acx_usb_bulk_context_t *)urb->context)->device;
+
+	acx_lock(priv, flags);
+
+	/* TODO: we maybe need to check whether urb was unlinked
+	** (happens on disconnect and close, see there). How? */
+
 	number = ((acx_usb_bulk_context_t *)urb->context)->number;
 	size = urb->actual_length;
 	remsize = size;
@@ -1170,8 +1079,6 @@ acx100usb_i_complete_rx(struct urb *urb,
 	acxlog(L_USBRXTX, "RETURN RX (%d) status=%d size=%d\n",
 				number, urb->status, size);
 
-	acx_lock(priv, flags);
-
 	inbuf = &priv->bulkins[number];
 	ptr = inbuf;
 
@@ -1338,14 +1245,12 @@ end:
 **   more data to send and invokes the Tx routines if this is the case.
 **   If there are no more occupied Tx descriptors, the Tx Mutex is unlocked
 **   and the network queue is switched back to life again.
+**
+** FIXME: unlike PCI code, we do not analyze tx rate used, retries, etc...
+** Thus we have no automatic rate control in USB!
 */
-#if USB_24
-static void
-acx100usb_i_complete_tx(struct urb *urb)
-#else
 static void
 acx100usb_i_complete_tx(struct urb *urb, struct pt_regs *regs)
-#endif
 {
 	wlandevice_t *priv;
 	usb_tx_t *tx;
@@ -1362,6 +1267,11 @@ acx100usb_i_complete_tx(struct urb *urb,
 	tx = (usb_tx_t *)urb->context;
 	priv = tx->priv;
 
+	acx_lock(priv, flags);
+
+	/* TODO: we maybe need to check whether urb was unlinked
+	** (happens on disconnect and close, see there). How? */
+
 	acxlog(L_USBRXTX, "RETURN TX (%p): status=%d size=%d\n",
 				tx, urb->status, urb->actual_length);
 
@@ -1377,12 +1287,11 @@ acx100usb_i_complete_tx(struct urb *urb,
 		/* FIXME: real error-handling code here please */
 	}
 
-	acx_lock(priv, flags);
-
 	/* free the URB and check for more data	*/
 	priv->usb_free_tx++;
 	tx->busy = 0;
 
+/* end_unlock: */
 	acx_unlock(priv, flags);
 end:
 	FN_EXIT0;
@@ -1391,24 +1300,19 @@ end:
 
 /***********************************************************************
 ** acx100usb_e_close():
-** Inputs:
-**    dev -> Pointer to network device structure
-************************************************************************
-** Returns:
-**  (int) 0 on success, or error-code
 **
-** Description:
-**  This function stops the network functionality of the interface (invoked
-**  when the user calls ifconfig <wlan> down). The tx queue is halted and
-**  the device is marked as down. In case there were any pending USB bulk
-**  transfers, these are unlinked (asynchronously). The module in-use count
-**  is also decreased in this function.
+** This function stops the network functionality of the interface (invoked
+** when the user calls ifconfig <wlan> down). The tx queue is halted and
+** the device is marked as down. In case there were any pending USB bulk
+** transfers, these are unlinked (asynchronously). The module in-use count
+** is also decreased in this function.
 */
 static int
 acx100usb_e_close(struct net_device *dev)
 {
 	wlandevice_t *priv;
-	int i, already_down;
+	unsigned long flags;
+	int i;
 
 	priv = dev->priv;
 	if (!priv) {
@@ -1425,40 +1329,29 @@ acx100usb_e_close(struct net_device *dev
 	unlock
 #endif
 
-	acx_sem_lock(priv);
-
-	/* stop the transmit queue */
-	if (!acx_queue_stopped(dev)) {
-		acx_stop_queue(dev, "on iface stop");
-	}
-
-//maybe LOCKING BUG, see pci.c if you wonder why
+	/*
+	 * We get the sem *after* FLUSH to avoid a deadlock.
+	 * See pci.c:acx_s_down() for deails.
+	 */
 	FLUSH_SCHEDULED_WORK();
+	acx_sem_lock(priv);
 
-	/* mark the device as DOWN */
-	if (priv->dev_state_mask & ACX_STATE_IFACE_UP) {
-		already_down = 0;
-		CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-	} else {
-		/* I don't think it can happen */
-		printk("acx: double down, please report!\n");
-		already_down = 1;
-	}
+	/* stop the transmit queue, mark the device as DOWN */
+	acx_lock(priv, flags);
+	acx_stop_queue(dev, "on iface stop");
+	CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
 
-	/* wait until all tx are out */
-#if 0
-	for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-		while (priv->usb_tx[i].urb->status == -EINPROGRESS) {
-			mdelay(5);
-		}
-	}
-#endif
+	/* I wonder if above is enough to prevent tx/rx callbacks
+	** to start queue again? Like this:
+	** complete_rx -> acx_l_process_rxbuf -> associated -> acx_start_queue()
+	** Oh well... */
 
 	/* stop pending rx/tx urb transfers */
 	for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
 		acx_unlink_and_free_urb(priv->bulkrx_urbs[i]);
 		acx_unlink_and_free_urb(priv->usb_tx[i].urb);
 	}
+	acx_unlock(priv, flags);
 
 	/* disable rx and tx */
 	acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
@@ -1470,20 +1363,20 @@ acx100usb_e_close(struct net_device *dev
 	acx_sem_unlock(priv);
 
 	/* decrease module-in-use count (if necessary) */
-	if (!already_down)
-		WLAN_MOD_DEC_USE_COUNT;
 
-	FN_EXIT1(0);
+	WLAN_MOD_DEC_USE_COUNT;
+
+	FN_EXIT0;
 	return 0;
 }
 
 
 /***************************************************************
-** acx_l_alloc_tx
+** acxusb_l_alloc_tx
 ** Actually returns a usb_tx_t* ptr
 */
 tx_t*
-acx_l_alloc_tx(wlandevice_t* priv)
+acxusb_l_alloc_tx(wlandevice_t* priv)
 {
 	int i;
 	usb_tx_t *tx = NULL;
@@ -1510,7 +1403,7 @@ acx_l_alloc_tx(wlandevice_t* priv)
 /***************************************************************
 */
 void*
-acx_l_get_txbuf(tx_t* tx_opaque)
+acxusb_l_get_txbuf(tx_t* tx_opaque)
 {
 	usb_tx_t* tx = (usb_tx_t*)tx_opaque;
 	return &tx->bulkout.data;
@@ -1518,13 +1411,13 @@ acx_l_get_txbuf(tx_t* tx_opaque)
 
 
 /***************************************************************
-** acx_l_dma_tx_data
+** acxusb_l_tx_data
 **
 ** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
 ** Can be called from acx_i_start_xmit (data frames from net core).
 */
 void
-acx_l_dma_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int wlanpkt_len)
+acxusb_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int wlanpkt_len)
 {
 	struct usb_device *usbdev;
 	struct urb* txurb;
@@ -1614,10 +1507,6 @@ acx_l_dma_tx_data(wlandevice_t *priv, tx
 	);
 
 	txurb->transfer_flags = ASYNC_UNLINK|QUEUE_BULK|ZERO_PACKET;
-#if USB_24
-	txurb->status = 0;
-	txurb->timeout = ACX100_USB_TX_TIMEOUT;
-#endif
 	ucode = submit_urb(txurb, GFP_ATOMIC);
 	acxlog(L_USBRXTX, "SUBMIT TX (%p): outpipe=0x%X buf=%p txsize=%d "
 		"errcode=%d\n", tx, outpipe, txbuf,
@@ -1655,6 +1544,8 @@ static struct iw_statistics*
 acx_e_get_wireless_stats(netdevice_t *dev)
 {
 	wlandevice_t *priv = acx_netdev_priv(dev);
+	FN_ENTER;
+	FN_EXIT0;
 	return &priv->wstats;
 }
 
@@ -1696,88 +1587,18 @@ acx100usb_i_tx_timeout(struct net_device
 
 
 /***********************************************************************
-** acx_l_power_led
-*/
-void
-acx_l_power_led(wlandevice_t *priv, int enable)
-{
-	acxlog(L_IOCTL, "acx: power_led() is not supported on USB\n");
-}
-
-
-/***********************************************************************
-** Ioctls
-*/
-
-/***********************************************************************
-** Ioctls for easy debug of I/O things (stubs only for USB)
-*/
-int
-acx_ioctl_dbg_get_io(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra)
-{
-	acxlog(L_IOCTL, "acx: dbg_get_io() is not supported on USB\n");
-	return -EINVAL;
-}
-
-int
-acx_ioctl_dbg_set_io(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra)
-{
-	acxlog(L_IOCTL, "acx: dbg_set_io() is not supported on USB\n");
-	return -EINVAL;
-}
-
-
-/***********************************************************************
-*/
-int
-acx111_ioctl_info(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra)
-{
-	return OK;
-}
-
-
-/***********************************************************************
-*/
-int
-acx100_ioctl_set_phy_amp_bias(
-	struct net_device *dev,
-	struct iw_request_info *info,
-	struct iw_param *vwrq,
-	char *extra)
-{
-	printk("acx: set_phy_amp_bias() is not supported on USB\n");
-	return OK;
-}
-
-
-/***********************************************************************
 ** init_module():
-** Inputs:
-**  <NONE>
-************************************************************************
-** Returns:
-**  (int) Errorcode on failure, 0 on success
 **
-** Description:
-**  This function is invoked upon loading of the kernel module. It registers
-**  itself at the kernel's USB subsystem.
+** This function is invoked upon loading of the kernel module.
+** It registers itself at the kernel's USB subsystem.
+**
+** Returns: Errorcode on failure, 0 on success
 */
-int
-init_module(void)
+int __init
+acxusb_e_init_module(void)
 {
-	printk(KERN_INFO "Initializing acx100 WLAN USB kernel module\n");
+	acxlog(L_INIT, "USB module " WLAN_RELEASE " initialized, "
+		"probing for devices...\n");
 	return usb_register(&acx100usb_driver);
 }
 
@@ -1785,18 +1606,14 @@ init_module(void)
 
 /***********************************************************************
 ** cleanup_module():
-** Inputs:
-**  <NONE>
-************************************************************************
-** Description:
-**  This function is invoked as last step of the module unloading. It simply
-**  deregisters this module at the kernel's USB subsystem.
+**
+** This function is invoked as last step of the module unloading. It simply
+** deregisters this module at the kernel's USB subsystem.
 */
-void
-cleanup_module()
+void __exit
+acxusb_e_cleanup_module()
 {
 	usb_deregister(&acx100usb_driver);
-	printk(KERN_INFO "Cleaning up acx100 WLAN USB kernel module\n");
 }
 
 
@@ -1805,7 +1622,7 @@ cleanup_module()
 */
 #if ACX_DEBUG
 
-#if UNUSED
+#ifdef UNUSED
 static void
 dump_device(struct usb_device *usbdev)
 {
@@ -1855,24 +1672,9 @@ dump_device(struct usb_device *usbdev)
 #endif
 	printk("  actconfig: %p\n", usbdev->actconfig);
 	dump_device_descriptor(&usbdev->descriptor);
-#if USB_24
-	cd = usbdev->actconfig;
-	dump_config_descriptor(cd);
-	{
-		struct usb_interface *ifc = cd->interface;
-		if (ifc) {
-			printk("iface: altsetting=%p act_altsetting=%d "
-				"num_altsetting=%d max_altsetting=%d\n",
-				ifc->altsetting, ifc->act_altsetting,
-				ifc->num_altsetting, ifc->max_altsetting);
-			dump_interface_descriptor(ifc->altsetting);
-			dump_endpoint_descriptor(ifc->altsetting->endpoint);
-		}
-	}
-#else
+
 	cd = &usbdev->config->desc;
 	dump_config_descriptor(cd);
-#endif
 }
 
 
@@ -1921,47 +1723,4 @@ dump_device_descriptor(struct usb_device
 }
 #endif /* UNUSED */
 
-
-/***********************************************************************
-*/
-#if USB_24
-static void
-dump_endpoint_descriptor(struct usb_endpoint_descriptor *ep)
-{
-	printk("Endpoint Descriptor:\n");
-	if (!ep) {
-		printk("NULL\n");
-		return;
-	}
-	printk("  bLength: %d (0x%X)\n", ep->bLength, ep->bLength);
-	printk("  bDescriptorType: %d (0x%X)\n", ep->bDescriptorType, ep->bDescriptorType);
-	printk("  bEndpointAddress: %d (0x%X)\n", ep->bEndpointAddress, ep->bEndpointAddress);
-	printk("  bmAttributes: 0x%X\n", ep->bmAttributes);
-	printk("  wMaxPacketSize: %d (0x%X)\n", ep->wMaxPacketSize, ep->wMaxPacketSize);
-	printk("  bInterval: %d (0x%X)\n", ep->bInterval, ep->bInterval);
-	printk("  bRefresh: %d (0x%X)\n", ep->bRefresh, ep->bRefresh);
-	printk("  bSyncAdrress: %d (0x%X)\n", ep->bSynchAddress, ep->bSynchAddress);
-}
-
-static void
-dump_interface_descriptor(struct usb_interface_descriptor *id)
-{
-	printk("Interface Descriptor:\n");
-	if (!id) {
-		printk("NULL\n");
-		return;
-	}
-	printk("  bLength: %d (0x%X)\n", id->bLength, id->bLength);
-	printk("  bDescriptorType: %d (0x%X)\n", id->bDescriptorType, id->bDescriptorType);
-	printk("  bInterfaceNumber: %d (0x%X)\n", id->bInterfaceNumber, id->bInterfaceNumber);
-	printk("  bAlternateSetting: %d (0x%X)\n", id->bAlternateSetting, id->bAlternateSetting);
-	printk("  bNumEndpoints: %d (0x%X)\n", id->bNumEndpoints, id->bNumEndpoints);
-	printk("  bInterfaceClass: %d (0x%X)\n", id->bInterfaceClass, id->bInterfaceClass);
-	printk("  bInterfaceSubClass: %d (0x%X)\n", id->bInterfaceSubClass, id->bInterfaceSubClass);
-	printk("  bInterfaceProtocol: %d (0x%X)\n", id->bInterfaceProtocol, id->bInterfaceProtocol);
-	printk("  iInterface: %d (0x%X)\n", id->iInterface, id->iInterface);
-	printk("  endpoint: 0x%X\n", (unsigned int)(id->endpoint));
-}
-#endif /* USB_24 */
-
 #endif /* ACX_DEBUG */
diff -L drivers/net/wireless/tiacx/usb_helper.c -puN drivers/net/wireless/tiacx/usb_helper.c~acx-update /dev/null
--- 25/drivers/net/wireless/tiacx/usb_helper.c
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,2 +0,0 @@
-#define ACX_USB 1
-#include "helper.c"
diff -puN drivers/net/wireless/tiacx/wlan.c~acx-update drivers/net/wireless/tiacx/wlan.c
--- 25/drivers/net/wireless/tiacx/wlan.c~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/wlan.c	Fri Sep  9 17:28:49 2005
@@ -124,23 +124,24 @@ wlan_mgmt_decode_beacon(wlan_fr_beacon_t
 		case WLAN_EID_ERP_INFO:
 			f->erp = (wlan_ie_erp_t *) ie_ptr;
 			break;
+		case WLAN_EID_NONERP:
+		/* was seen from WRT54GS with OpenWrt: 2F 01 07 */
+			break;
 		case WLAN_EID_GENERIC:
-		/* WPA:
+		/* WPA: hostap code:
 			if (pos[1] >= 4 &&
 				pos[2] == 0x00 && pos[3] == 0x50 &&
 				pos[4] == 0xf2 && pos[5] == 1) {
 				wpa = pos;
 				wpa_len = pos[1] + 2;
 			}
-		TI x4 mode: last byte is probably 0/1 - disabled/enabled
-			if (pos[1] == 4 &&
-				pos[2] == 0x80 && pos[3] == 0x00 &&
-				pos[4] == 0x28 && pos[5] == 0/1) {
-			}
+		TI x4 mode: seen DD 04 08 00 28 00
+		08 00 28 is TI's OUI
+		last byte is probably 0/1 - disabled/enabled
 		*/
 			break;
 		case WLAN_EID_RSN:
-		/*
+		/* hostap does something with it:
 			rsn = pos;
 			rsn_len = pos[1] + 2;
 		*/
@@ -154,7 +155,7 @@ wlan_mgmt_decode_beacon(wlan_fr_beacon_t
 }
 
 
-#if UNUSED
+#ifdef UNUSED
 void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t * f)
 {
 	f->type = WLAN_FSTYPE_ATIM;
diff -puN drivers/net/wireless/tiacx/wlan_mgmt.h~acx-update drivers/net/wireless/tiacx/wlan_mgmt.h
--- 25/drivers/net/wireless/tiacx/wlan_mgmt.h~acx-update	Fri Sep  9 17:28:49 2005
+++ 25-akpm/drivers/net/wireless/tiacx/wlan_mgmt.h	Fri Sep  9 17:28:49 2005
@@ -57,6 +57,7 @@
 #define WLAN_EID_CHALLENGE	16
 /*-- values 17-31 reserved for challenge text extension --*/
 #define WLAN_EID_ERP_INFO	42
+#define WLAN_EID_NONERP		47	/* was seen from WRT54GS with OpenWrt */
 #define WLAN_EID_RSN		48
 #define WLAN_EID_EXT_RATES	50
 #define WLAN_EID_GENERIC	221
@@ -72,7 +73,6 @@
 #define WLAN_EID_MEASURE_REPORT		39	/* 11H MeasurementReport */
 #define WLAN_EID_QUIET_ID		40	/* 11H Quiet */
 #define WLAN_EID_IBSS_DFS_ID		41	/* 11H IBSS_DFS */
-#define WLAN_EID_NONERP_ID		47
 #endif
 
 /*-- Reason Codes -------------------------------*/
@@ -109,9 +109,8 @@
 #define WLAN_AUTH_ALG_SHAREDKEY			1
 
 /*-- Management Frame Field Offsets -------------*/
-/* Note: Not all fields are listed because of variable lengths,   */
-/*       see the code in p80211.c to see how we search for fields */
-/* Note: These offsets are from the start of the frame data       */
+/* Note: Not all fields are listed because of variable lengths */
+/* Note: These offsets are from the start of the frame data */
 
 #define WLAN_BEACON_OFF_TS			0
 #define WLAN_BEACON_OFF_BCN_INT			8
_