acx100.sourceforge.net (Andreas Mohr ) -> -> Denis Vlasenko -> Jeff Garzik -> me Signed-off-by: Andrew Morton --- drivers/net/wireless/Kconfig | 2 drivers/net/wireless/Makefile | 2 drivers/net/wireless/tiacx/Changelog | 136 drivers/net/wireless/tiacx/Kconfig | 59 drivers/net/wireless/tiacx/Makefile | 6 drivers/net/wireless/tiacx/acx.h | 6 drivers/net/wireless/tiacx/acx_config.h | 40 drivers/net/wireless/tiacx/acx_func.h | 603 +++ drivers/net/wireless/tiacx/acx_inline.h | 119 drivers/net/wireless/tiacx/acx_struct.h | 1803 +++++++++++ drivers/net/wireless/tiacx/conv.c | 523 +++ drivers/net/wireless/tiacx/helper.c | 4304 +++++++++++++++++++++++++++ drivers/net/wireless/tiacx/helper2.c | 2422 +++++++++++++++ drivers/net/wireless/tiacx/ioctl.c | 3033 +++++++++++++++++++ drivers/net/wireless/tiacx/pci.c | 4777 +++++++++++++++++++++++++++++++ drivers/net/wireless/tiacx/pci_helper.c | 2 drivers/net/wireless/tiacx/setrate.c | 213 + drivers/net/wireless/tiacx/usb.c | 1967 ++++++++++++ drivers/net/wireless/tiacx/usb_helper.c | 2 drivers/net/wireless/tiacx/wlan.c | 391 ++ drivers/net/wireless/tiacx/wlan_compat.h | 331 ++ drivers/net/wireless/tiacx/wlan_hdr.h | 498 +++ drivers/net/wireless/tiacx/wlan_mgmt.h | 580 +++ 23 files changed, 21818 insertions(+), 1 deletion(-) diff -puN drivers/net/wireless/Kconfig~acx1xx-wireless-driver drivers/net/wireless/Kconfig --- devel/drivers/net/wireless/Kconfig~acx1xx-wireless-driver 2005-09-07 20:10:30.000000000 -0700 +++ devel-akpm/drivers/net/wireless/Kconfig 2005-09-07 20:10:30.000000000 -0700 @@ -477,6 +477,8 @@ config PRISM54 source "drivers/net/wireless/hostap/Kconfig" +source "drivers/net/wireless/tiacx/Kconfig" + # yes, this works even when no drivers are selected config NET_WIRELESS bool diff -puN drivers/net/wireless/Makefile~acx1xx-wireless-driver drivers/net/wireless/Makefile --- devel/drivers/net/wireless/Makefile~acx1xx-wireless-driver 2005-09-07 20:10:30.000000000 -0700 +++ devel-akpm/drivers/net/wireless/Makefile 2005-09-07 20:10:30.000000000 -0700 @@ -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_HOSTAP) += hostap/ # 16-bit wireless PCMCIA client drivers diff -puN /dev/null drivers/net/wireless/tiacx/acx_config.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/acx_config.h 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,40 @@ +#define WLAN_RELEASE "v0.3.0" + +/* set to 0 if you don't want any debugging code to be compiled in */ +/* set to 1 if you want some debugging */ +/* set to 2 if you want extensive debug log */ +#define ACX_DEBUG 1 + +/* assume 32bit I/O width + * (16bit is also compatible with Compact Flash) */ +#define ACX_IO_WIDTH 32 + +/* Set this to 1 if you want monitor mode to use + * phy header. Currently it is not useful anyway since we + * don't know what useful info (if any) is in phy header. + * If you want faster/smaller code, say 0 here */ +#define WANT_PHY_HDR 0 + +/* whether to do Tx descriptor cleanup in softirq (i.e. not in IRQ + * handler) or not. Note that doing it later does slightly increase + * system load, so still do that stuff in the IRQ handler for now, + * even if that probably means worse latency */ +#define TX_CLEANUP_IN_SOFTIRQ 0 + +/* set to 1 if you want to have 1 driver per card instead of 1 single driver + * managing all cards (of a particular bus type) in your system + * Useful e.g. if you need to reinitialize single cards from time to time + * LINUX 2.4.X ONLY!! (pci_for_each_dev()) Feel free to implement 2.6.x + * compatibility... */ +#define SEPARATE_DRIVER_INSTANCES 0 + +/* Undefine if you want out-of-line acx_r/w_regNN, + * define to "static inline" if you want them inlined */ +#define INLINE_IO static inline + +/* Locking: */ +/* very talkative */ +/* #define PARANOID_LOCKING 1 */ +/* normal (use when bug-free) */ +#define DO_LOCKING 1 +/* else locking is disabled! */ diff -puN /dev/null drivers/net/wireless/tiacx/acx_func.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/acx_func.h 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,603 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + + +/*********************************************************************** +** LOGGING +** +** - Avoid SHOUTING needlessly. Avoid excessive verbosity. +** Gradually remove messages which are old debugging aids. +** +** - Use printk() for messages which are to be always logged. +** Supply either 'acx:' or ':' prefix so that user +** can figure out who's speaking among other kernel chatter. +** acx: is for general issues (e.g. "acx: no firmware image!") +** while : is related to a particular device +** (think about multi-card setup). Double check that message +** is not confusing to the average user. +** +** - use printk KERN_xxx level only if message is not a WARNING +** but is INFO, ERR etc. +** +** - Use printk_ratelimited() for messages which may flood +** (e.g. "rx DUP pkt!"). +** +** - Use acxlog() for messages which may be omitted (and they +** _will_ be omitted in non-debug builds). Note that +** message levels may be disabled at compile-time selectively, +** thus select them wisely. Example: L_DEBUG is the lowest +** (most likely to be compiled out) -> use for less important stuff. +** +** - Do not print important stuff with acxlog(), or else people +** will never build non-debug driver. +** +** Style: +** hex: capital letters, zero filled (e.g. 0x02AC) +** str: dont start from capitals, no trailing periods ("tx: queue is stopped") +*/ +#if ACX_DEBUG > 1 + +void log_fn_enter(const char *funcname); +void log_fn_exit(const char *funcname); +void log_fn_exit_v(const char *funcname, int v); + +#define FN_ENTER \ + do { \ + if (unlikely(acx_debug & L_FUNC)) { \ + log_fn_enter(__func__); \ + } \ + } while (0) + +#define FN_EXIT1(v) \ + do { \ + if (unlikely(acx_debug & L_FUNC)) { \ + log_fn_exit_v(__func__, v); \ + } \ + } while (0) +#define FN_EXIT0 \ + do { \ + if (unlikely(acx_debug & L_FUNC)) { \ + log_fn_exit(__func__); \ + } \ + } while (0) + +#else + +#define FN_ENTER +#define FN_EXIT1(v) +#define FN_EXIT0 + +#endif /* ACX_DEBUG > 1 */ + + +#if ACX_DEBUG + +#define acxlog(chan, args...) \ + do { \ + if (acx_debug & (chan)) \ + printk(args); \ + } while (0) +#define printk_ratelimited(args...) printk(args) + +#else /* Non-debug build: */ + +#define acxlog(chan, args...) +/* Standard way of log flood prevention */ +#define printk_ratelimited(args...) \ +do { \ + if (printk_ratelimit()) \ + printk(args); \ +} while (0) + +#endif /* ACX_DEBUG */ + + +/* MAC logging code is big (relatively) */ +void acx_print_mac(const char *head, const u8 *mac, const char *tail); + +/* Optimized out to nothing in non-debug build */ +static inline void +acxlog_mac(int level, const char *head, const u8 *mac, const char *tail) +{ + if (acx_debug & level) { + acx_print_mac(head, mac, tail); + } +} + + +/*********************************************************************** +** Low-level io routines +*/ +#include "acx_inline.h" + + +/*********************************************************************** +** MAC address helpers +*/ +static inline void +MAC_COPY(u8 *mac, const u8 *src) +{ + *(u32*)mac = *(u32*)src; + ((u16*)mac)[2] = ((u16*)src)[2]; + /* kernel's memcpy will do the same: memcpy(dst, src, ETH_ALEN); */ +} + +static inline void +MAC_FILL(u8 *mac, u8 val) +{ + memset(mac, val, ETH_ALEN); +} + +static inline void +MAC_BCAST(u8 *mac) +{ + ((u16*)mac)[2] = *(u32*)mac = -1; +} + +static inline void +MAC_ZERO(u8 *mac) +{ + ((u16*)mac)[2] = *(u32*)mac = 0; +} + +static inline int +mac_is_equal(const u8 *a, const u8 *b) +{ + /* can't beat this */ + return memcmp(a, b, ETH_ALEN) == 0; +} + +static inline int +mac_is_bcast(const u8 *mac) +{ + /* AND together 4 first bytes with sign-entended 2 last bytes + ** Only bcast address gives 0xffffffff. +1 gives 0 */ + return ( *(s32*)mac & ((s16*)mac)[2] ) + 1 == 0; +} + +static inline int +mac_is_zero(const u8 *mac) +{ + return ( *(u32*)mac | ((u16*)mac)[2] ) == 0; +} + +static inline int +mac_is_directed(const u8 *mac) +{ + return (mac[0] & 1)==0; +} + +static inline int +mac_is_mcast(const u8 *mac) +{ + return (mac[0] & 1) && !mac_is_bcast(mac); +} + +#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X" +#define MAC(bytevector) \ + ((unsigned char *)bytevector)[0], \ + ((unsigned char *)bytevector)[1], \ + ((unsigned char *)bytevector)[2], \ + ((unsigned char *)bytevector)[3], \ + ((unsigned char *)bytevector)[4], \ + ((unsigned char *)bytevector)[5] + + +/*********************************************************************** +** Random helpers +*/ +#define TO_STRING(x) #x +#define STRING(x) TO_STRING(x) + +#define CLEAR_BIT(val, mask) ((val) &= ~(mask)) +#define SET_BIT(val, mask) ((val) |= (mask)) + +/* undefined if v==0 */ +static inline unsigned int +lowest_bit(u16 v) +{ + unsigned int n = 0; + while (!(v & 0xf)) { v>>=4; n+=4; } + while (!(v & 1)) { v>>=1; n++; } + return n; +} + +/* undefined if v==0 */ +static inline unsigned int +highest_bit(u16 v) +{ + unsigned int n = 0; + while (v>0xf) { v>>=4; n+=4; } + while (v>1) { v>>=1; n++; } + return n; +} + +/* undefined if v==0 */ +static inline int +has_only_one_bit(u16 v) +{ + return ((v-1) ^ v) >= v; +} + + +/*********************************************************************** +** LOCKING +** We have priv->sem and priv->lock. +** +** We employ following naming convention in order to get locking right: +** +** acx_e_xxxx - external entry points called from process context. +** It is okay to sleep. priv->sem is to be taken on entry. +** acx_i_xxxx - external entry points possibly called from atomic context. +** Sleeping is not allowed (and thus down(sem) is not legal!) +** acx_s_xxxx - potentially sleeping functions. Do not ever call under lock! +** acx_l_xxxx - functions which expect lock to be already taken. +** rest - non-sleeping functions which do not require locking +** but may be run inder lock +** +** Theory of operation: +** +** All process-context entry points (_e_ functions) take sem +** immediately. IRQ handler and other 'atomic-context' entry points +** (_i_ functions) take lock immediately on entry, but dont take sem +** because that might sleep. +** +** 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). +** Such code is marked with _l_. +** +** This results in the following rules of thumb useful in code review: +** +** + If a function calls _s_ fn, it must be an _s_ itself. +** + You can call _l_ fn only (a) from another _l_ fn +** or (b) from _s_, _e_ or _i_ fn by taking lock, calling _l_, +** and dropping lock. +** + All IRQ code runs under lock. +** + Any _s_ fn is running under sem. +** + Code under sem can race only with IRQ code. +** + Code under sem+lock cannot race with anything. +*/ + +/* 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. */ + +#if defined(PARANOID_LOCKING) /* Lock debugging */ + +void acx_lock_debug(wlandevice_t *priv, const char* where); +void acx_unlock_debug(wlandevice_t *priv, const char* where); +void acx_down_debug(wlandevice_t *priv, const char* where); +void acx_up_debug(wlandevice_t *priv, const char* where); +void acx_lock_unhold(void); +void acx_sem_unhold(void); + +extern 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 +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 +acx_down_helper(wlandevice_t *priv, const char* where) +{ + acx_down_debug(priv, where); +} +extern inline void +acx_up_helper(wlandevice_t *priv, const char* where) +{ + acx_up_debug(priv, where); +} +#define acx_lock(priv, flags) acx_lock_helper(priv, &(flags), __FILE__ ":" STRING(__LINE__)) +#define acx_unlock(priv, flags) acx_unlock_helper(priv, &(flags), __FILE__ ":" STRING(__LINE__)) +#define acx_sem_lock(priv) acx_down_helper(priv, __FILE__ ":" STRING(__LINE__)) +#define acx_sem_unlock(priv) acx_up_helper(priv, __FILE__ ":" STRING(__LINE__)) + +#elif defined(DO_LOCKING) + +#define acx_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) +#define acx_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) +#define acx_sem_lock(priv) down(&priv->sem) +#define acx_sem_unlock(priv) up(&priv->sem) +#define acx_lock_unhold() ((void)0) +#define acx_sem_unhold() ((void)0) + +#else /* no locking! :( */ + +#define acx_lock(priv, flags) ((void)0) +#define acx_unlock(priv, flags) ((void)0) +#define acx_sem_lock(priv) ((void)0) +#define acx_sem_unlock(priv) ((void)0) +#define acx_lock_unhold() ((void)0) +#define acx_sem_unhold() ((void)0) + +#endif + + +/*********************************************************************** +** transitional define (before we go towards a real netdev_priv() layout) +** DON'T erroneously use a netdev_priv() instead - it's different for now! +** +** BTW, the new netdev_priv() is available in >= 2.4.27, >= 2.6.3 +*/ +#define acx_netdev_priv(dev) (void *)((dev)->priv) + +static inline void +acx_stop_queue(netdevice_t *dev, const char *msg) +{ + netif_stop_queue(dev); + if (msg) + acxlog(L_BUFT, "tx: stop queue %s\n", msg); +} + +static inline int +acx_queue_stopped(netdevice_t *dev) +{ + return netif_queue_stopped(dev); +} + +static inline void +acx_start_queue(netdevice_t *dev, const char *msg) +{ + netif_start_queue(dev); + if (msg) + acxlog(L_BUFT, "tx: start queue %s\n", msg); +} + +static inline void +acx_wake_queue(netdevice_t *dev, const char *msg) +{ + netif_wake_queue(dev); + if (msg) + acxlog(L_BUFT, "tx: wake queue %s\n", msg); +} + +static inline void +acx_carrier_off(netdevice_t *dev, const char *msg) +{ + netif_carrier_off(dev); + if (msg) + acxlog(L_BUFT, "tx: carrier off %s\n", msg); +} + +static inline void +acx_carrier_on(netdevice_t *dev, const char *msg) +{ + netif_carrier_on(dev); + if (msg) + acxlog(L_BUFT, "tx: carrier on %s\n", msg); +} + + +/*********************************************************************** +** Communication with firmware +*/ +/* in 1/100 of ms */ +#define CMD_TIMEOUT_MS(n) ((n)*100) +#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); +#define acx_s_issue_cmd(priv,cmd,param,len) \ + 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); +#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); +#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); +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); +} +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, + u32 *feature_options, u32 *data_flow_options); +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 */); +static inline int +acx111_s_feature_off(wlandevice_t *priv, u32 f, u32 d) +{ + return acx111_s_set_feature_config(priv, f, d, 0); +} +static inline int +acx111_s_feature_on(wlandevice_t *priv, u32 f, u32 d) +{ + return acx111_s_set_feature_config(priv, f, d, 1); +} +static inline int +acx111_s_feature_set(wlandevice_t *priv, u32 f, u32 d) +{ + return acx111_s_set_feature_config(priv, f, d, 2); +} + + +/*********************************************************************** +** 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( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra); +int acx100_ioctl_set_phy_amp_bias( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra); + + +/*********************************************************************** +** Unsorted yet :) +*/ +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_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); +#else +firmware_image_t *acx_s_read_fw(const char *file, u32 *size); +#define acx_s_read_fw(dev, file, size) acx_s_read_fw(file, size) +#endif +void acx_s_initialize_rx_config(wlandevice_t *priv); +void acx_s_update_card_settings(wlandevice_t *priv, int get_all, int set_all); +void acx_init_task_scheduler(wlandevice_t *priv); +void acx_schedule_after_interrupt_task(wlandevice_t *priv, unsigned int set_flag); +int acx_s_upload_radio(wlandevice_t *priv); +void acx_read_configoption(wlandevice_t *priv); +int acx_proc_register_entries(const struct net_device *dev); +int acx_proc_unregister_entries(const struct net_device *dev); +void acx_l_update_ratevector(wlandevice_t *priv); + +int acx_s_recalib_radio(wlandevice_t *priv); +int acx_e_ioctl_old(netdevice_t *dev, struct ifreq *ifr, int cmd); + +void acx_l_sta_list_init(wlandevice_t *priv); +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); +int acx_s_complete_scan(wlandevice_t *priv); + +const char* acx_get_status_name(u16 status); + +static inline wlan_hdr_t* +acx_get_wlan_hdr(wlandevice_t *priv, const rxbuffer_t *rxbuf) +{ + if (!(priv->rx_config_1 & RX_CFG1_INCLUDE_PHY_HDR)) + return (wlan_hdr_t*)&rxbuf->hdr_a3; + + /* take into account phy header in front of packet */ + if (CHIPTYPE_ACX111 == priv->chip_type) + return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 8); + + return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 4); +} + +struct sk_buff *acx_rxbuf_to_ether(struct wlandevice *priv, rxbuffer_t *rxbuf); + +void acx_l_power_led(wlandevice_t *priv, int enable); + +int acx100_s_create_dma_regions(wlandevice_t *priv); +int acx111_s_create_dma_regions(wlandevice_t *priv); +unsigned int acx_l_clean_tx_desc(wlandevice_t *priv); +void acx_l_clean_tx_desc_emergency(wlandevice_t *priv); + +u8 acx_signal_to_winlevel(u8 rawlevel); +u8 acx_signal_determine_quality(u8 signal, u8 noise); + +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); + +void acx_dump_bytes(const void *, int); +void acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr); + +u8 acx_rate111to100(u16); +void acx_l_rx(wlandevice_t *priv, rxbuffer_t *rxbuf); + +void acx100usb_l_tx_data(wlandevice_t *priv, struct txdesc *desc); +int acx_s_set_defaults(wlandevice_t *priv); +void acx_init_mboxes(wlandevice_t *priv); + +int acx_l_ether_to_txbuf(wlandevice_t *priv, void *txbuf, const struct sk_buff *skb); + +#if !ACX_DEBUG +static inline const char* acx_get_packet_type_string(u16 fc) { return ""; } +#else +const char* acx_get_packet_type_string(u16 fc); +#endif + +int acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev); +void acx_free_desc_queues(TIWLAN_DC *pDc); + +#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 diff -puN /dev/null drivers/net/wireless/tiacx/acx.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/acx.h 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,6 @@ +#include "acx_config.h" +#include "wlan_compat.h" +#include "wlan_hdr.h" +#include "wlan_mgmt.h" +#include "acx_struct.h" +#include "acx_func.h" diff -puN /dev/null drivers/net/wireless/tiacx/acx_inline.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/acx_inline.h 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,119 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** This file expects INLINE_IO to be: +** a) #defined to 'static inline': will emit inlined functions (for .h file); +** or +** b) #defined to '': will emit non-inlined functions (for .c file); +** or +** c) not #defined at all: emit prototypes only +*/ +#ifdef ACX_PCI + +#ifndef INLINE_IO + +u32 acx_read_reg32(wlandevice_t *priv, unsigned int offset); +u16 acx_read_reg16(wlandevice_t *priv, unsigned int offset); +u8 acx_read_reg8(wlandevice_t *priv, unsigned int offset); +void acx_write_reg32(wlandevice_t *priv, unsigned int offset, u32 val); +void acx_write_reg16(wlandevice_t *priv, unsigned int offset, u16 val); +void acx_write_reg8(wlandevice_t *priv, unsigned int offset, u8 val); +void acx_write_flush(wlandevice_t *priv); + +#else + +#include /* readl() etc. */ + +INLINE_IO u32 +acx_read_reg32(wlandevice_t *priv, unsigned int offset) +{ +#if ACX_IO_WIDTH == 32 + return readl((u8 *)priv->iobase + priv->io[offset]); +#else + return readw((u8 *)priv->iobase + priv->io[offset]) + + (readw((u8 *)priv->iobase + priv->io[offset] + 2) << 16); +#endif +} + +INLINE_IO u16 +acx_read_reg16(wlandevice_t *priv, unsigned int offset) +{ + return readw((u8 *)priv->iobase + priv->io[offset]); +} + +INLINE_IO u8 +acx_read_reg8(wlandevice_t *priv, unsigned int offset) +{ + return readb((u8 *)priv->iobase + priv->io[offset]); +} + +INLINE_IO void +acx_write_reg32(wlandevice_t *priv, unsigned int offset, u32 val) +{ +#if ACX_IO_WIDTH == 32 + writel(val, (u8 *)priv->iobase + priv->io[offset]); +#else + writew(val & 0xffff, (u8 *)priv->iobase + priv->io[offset]); + writew(val >> 16, (u8 *)priv->iobase + priv->io[offset] + 2); +#endif +} + +INLINE_IO void +acx_write_reg16(wlandevice_t *priv, unsigned int offset, u16 val) +{ + writew(val, (u8 *)priv->iobase + priv->io[offset]); +} + +INLINE_IO void +acx_write_reg8(wlandevice_t *priv, unsigned int offset, u8 val) +{ + writeb(val, (u8 *)priv->iobase + priv->io[offset]); +} + +/* Handle PCI posting properly: + * Make sure that writes reach the adapter in case they require to be executed + * *before* the next write, by reading a random (and safely accessible) register. + * This call has to be made if there is no read following (which would flush the data + * to the adapter), yet the written data has to reach the adapter immediately. */ +INLINE_IO void +acx_write_flush(wlandevice_t *priv) +{ + /* readb(priv->iobase + priv->io[IO_ACX_INFO_MAILBOX_OFFS]); */ + /* faster version (accesses the first register, IO_ACX_SOFT_RESET, + * which should also be safe): */ + readb(priv->iobase); +} + +#endif + +#endif /* CONFIG_TIACX_PCI */ diff -puN /dev/null drivers/net/wireless/tiacx/acx_struct.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/acx_struct.h 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,1803 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** Forward declarations of types +*/ +typedef struct tx tx_t; +typedef struct wlandevice wlandevice_t; +typedef struct client client_t; +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; + + +/*********************************************************************** +** Debug / log functionality +*/ +enum { + L_LOCK = (ACX_DEBUG>1)*0x0001, /* locking debug log */ + L_INIT = (ACX_DEBUG>0)*0x0002, /* special card initialization logging */ + L_IRQ = (ACX_DEBUG>0)*0x0004, /* interrupt stuff */ + L_ASSOC = (ACX_DEBUG>0)*0x0008, /* assocation (network join) and station log */ + L_FUNC = (ACX_DEBUG>1)*0x0020, /* logging of function enter / leave */ + L_XFER = (ACX_DEBUG>1)*0x0080, /* logging of transfers and mgmt */ + L_DATA = (ACX_DEBUG>1)*0x0100, /* logging of transfer data */ + L_DEBUG = (ACX_DEBUG>1)*0x0200, /* log of debug info */ + L_IOCTL = (ACX_DEBUG>0)*0x0400, /* log ioctl calls */ + L_CTL = (ACX_DEBUG>1)*0x0800, /* log of low-level ctl commands */ + L_BUFR = (ACX_DEBUG>1)*0x1000, /* debug rx buffer mgmt (ring buffer etc.) */ + L_XFER_BEACON = (ACX_DEBUG>1)*0x2000, /* also log beacon packets */ + L_BUFT = (ACX_DEBUG>1)*0x4000, /* debug tx buffer mgmt (ring buffer etc.) */ + L_USBRXTX = (ACX_DEBUG>0)*0x8000, /* debug USB rx/tx operations */ + L_BUF = L_BUFR + L_BUFT, + L_ANY = 0xffff +}; + +#if ACX_DEBUG +extern unsigned int acx_debug; +#else +enum { acx_debug = 0 }; +#endif + + +/*============================================================================* + * Random helpers * + *============================================================================*/ +#define ACX_PACKED __WLAN_ATTRIB_PACK__ + +#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0])) + +/* Use worker_queues for 2.5/2.6 Kernels and queue tasks for 2.4 Kernels + (used for the 'bottom half' of the interrupt routine) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) +#include +/* #define NEWER_KERNELS_ONLY 1 */ +#define USE_WORKER_TASKS +#define WORK_STRUCT struct work_struct +#define SCHEDULE_WORK schedule_work +#define FLUSH_SCHEDULED_WORK flush_scheduled_work + +#else +#include +#define USE_QUEUE_TASKS +#define WORK_STRUCT struct tq_struct +#define SCHEDULE_WORK schedule_task +#define INIT_WORK(work, func, ndev) \ + do { \ + (work)->routine = (func); \ + (work)->data = (ndev); \ + } while (0) +#define FLUSH_SCHEDULED_WORK flush_scheduled_tasks + +#endif + + +/*============================================================================* + * Constants * + *============================================================================*/ +#define OK 0 +#define NOT_OK 1 + +/* The supported chip models (taken from pci_device_id.driver_data) */ +#define CHIPTYPE_ACX100 1 +#define CHIPTYPE_ACX111 2 + +/* Driver defaults */ +#define DEFAULT_DTIM_INTERVAL 10 +/* used to be 2048, but FreeBSD driver changed it to 4096 to work properly +** in noisy wlans */ +#define DEFAULT_MSDU_LIFETIME 4096 +#define DEFAULT_RTS_THRESHOLD 2312 /* max. size: disable RTS mechanism */ +#define DEFAULT_BEACON_INTERVAL 100 + +#define ACX100_BAP_DATALEN_MAX 4096 +#define ACX100_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */ +#define ACX100_RIDDATA_MAXLEN ACX100_RID_GUESSING_MAXLEN + +/* Support Constants */ +/* Radio type names, found in Win98 driver's TIACXLN.INF */ +#define RADIO_MAXIM_0D 0x0d +#define RADIO_RFMD_11 0x11 +#define RADIO_RALINK_15 0x15 +/* used in ACX111 cards (WG311v2, WL-121, ...): */ +#define RADIO_RADIA_16 0x16 +/* most likely *sometimes* used in ACX111 cards: */ +#define RADIO_UNKNOWN_17 0x17 +/* FwRad19.bin was found in a Safecom driver; must be an ACX111 radio: */ +#define RADIO_UNKNOWN_19 0x19 + +/* Controller Commands */ +/* can be found in table cmdTable in firmware "Rev. 1.5.0" (FW150) */ +#define ACX1xx_CMD_RESET 0x00 +#define ACX1xx_CMD_INTERROGATE 0x01 +#define ACX1xx_CMD_CONFIGURE 0x02 +#define ACX1xx_CMD_ENABLE_RX 0x03 +#define ACX1xx_CMD_ENABLE_TX 0x04 +#define ACX1xx_CMD_DISABLE_RX 0x05 +#define ACX1xx_CMD_DISABLE_TX 0x06 +#define ACX1xx_CMD_FLUSH_QUEUE 0x07 +#define ACX1xx_CMD_SCAN 0x08 +#define ACX1xx_CMD_STOP_SCAN 0x09 +#define ACX1xx_CMD_CONFIG_TIM 0x0a +#define ACX1xx_CMD_JOIN 0x0b +#define ACX1xx_CMD_WEP_MGMT 0x0c +#if OLD_FIRMWARE_VERSIONS +#define ACX100_CMD_HALT 0x0e /* mapped to unknownCMD in FW150 */ +#else +#define ACX1xx_CMD_MEM_READ 0x0d +#define ACX1xx_CMD_MEM_WRITE 0x0e +#endif +#define ACX1xx_CMD_SLEEP 0x0f +#define ACX1xx_CMD_WAKE 0x10 +#define ACX1xx_CMD_UNKNOWN_11 0x11 /* mapped to unknownCMD in FW150 */ +#define ACX100_CMD_INIT_MEMORY 0x12 +#define ACX1xx_CMD_CONFIG_BEACON 0x13 +#define ACX1xx_CMD_CONFIG_PROBE_RESPONSE 0x14 +#define ACX1xx_CMD_CONFIG_NULL_DATA 0x15 +#define ACX1xx_CMD_CONFIG_PROBE_REQUEST 0x16 +#define ACX1xx_CMD_TEST 0x17 +#define ACX1xx_CMD_RADIOINIT 0x18 +#define ACX111_CMD_RADIOCALIB 0x19 + +/* 'After Interrupt' Commands */ +#define ACX_AFTER_IRQ_CMD_STOP_SCAN 0x01 +#define ACX_AFTER_IRQ_CMD_ASSOCIATE 0x02 +#define ACX_AFTER_IRQ_CMD_RADIO_RECALIB 0x04 +#define ACX_AFTER_IRQ_UPDATE_CARD_CFG 0x08 +#define ACX_AFTER_IRQ_TX_CLEANUP 0x10 +#define ACX_AFTER_IRQ_COMPLETE_SCAN 0x20 +#define ACX_AFTER_IRQ_RESTART_SCAN 0x40 + + +/*============================================================================* + * Record ID Constants * + *============================================================================*/ + +/* 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 + +#ifdef ACX_USB +#define ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN 0x02 +#else +#define ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN 0x01 +#endif + +#define ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN 0x01 + +#ifdef ACX_USB +#define ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN 0x02 +#else +#define ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN 0x01 +#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 + + +/*============================================================================* + * Information Frames Structures * + *============================================================================*/ + +/* Used in beacon frames and the like */ +#define DOT11RATEBYTE_1 (1*2) +#define DOT11RATEBYTE_2 (2*2) +#define DOT11RATEBYTE_5_5 (5*2+1) +#define DOT11RATEBYTE_11 (11*2) +#define DOT11RATEBYTE_22 (22*2) +#define DOT11RATEBYTE_6_G (6*2) +#define DOT11RATEBYTE_9_G (9*2) +#define DOT11RATEBYTE_12_G (12*2) +#define DOT11RATEBYTE_18_G (18*2) +#define DOT11RATEBYTE_24_G (24*2) +#define DOT11RATEBYTE_36_G (36*2) +#define DOT11RATEBYTE_48_G (48*2) +#define DOT11RATEBYTE_54_G (54*2) +#define DOT11RATEBYTE_BASIC 0x80 /* flags rates included in basic rate set */ + + +/*********************************************************************** +** rxbuffer_t +** +** This is the format of rx data returned by acx +*/ + +/* I've hoped it's a 802.11 PHY header, but no... + * so far, I've seen on acx111: + * 0000 3a00 0000 0000 IBBS Beacons + * 0000 3c00 0000 0000 ESS Beacons + * 0000 2700 0000 0000 Probe requests + * --vda + */ +typedef struct phy_hdr { + u8 unknown[4] ACX_PACKED; + u8 acx111_unknown[4] ACX_PACKED; +} phy_hdr_t; + +/* seems to be a bit similar to hfa384x_rx_frame. + * These fields are still not quite obvious, though. + * Some seem to have different meanings... */ + +#define RXBUF_HDRSIZE 12 +#define PHY_HDR(rxbuf) ((phy_hdr_t*)&rxbuf->hdr_a3) +#define RXBUF_BYTES_RCVD(rxbuf) (le16_to_cpu(rxbuf->mac_cnt_rcvd) & 0xfff) +#define RXBUF_BYTES_USED(rxbuf) \ + ((le16_to_cpu(rxbuf->mac_cnt_rcvd) & 0xfff) + RXBUF_HDRSIZE) +/* +mac_cnt_rcvd: + 12 bits: length of frame from control field to last byte of FCS + 4 bits: reserved + +mac_cnt_mblks: + 6 bits: number of memory block used to store frame in adapter memory + 1 bit: Traffic Indicator bit in TIM of received Beacon was set + +mac_status: 1 byte (bitmap): + 7 Matching BSSID + 6 Matching SSID + 5 BDCST Address 1 field is a broadcast + 4 VBM received beacon frame has more than one set bit (?!) + 3 TIM Set bit representing this station is set in TIM of received beacon + 2 GROUP Address 1 is a multicast + 1 ADDR1 Address 1 matches our MAC + 0 FCSGD FSC is good + +phy_stat_baseband: 1 byte (bitmap): + 7 Preamble frame had a long preamble + 6 PLCP Error CRC16 error in PLCP header + 5 Unsup_Mod unsupported modulation + 4 Selected Antenna antenna 1 was used to receive this frame + 3 PBCC/CCK frame used: 1=PBCC, 0=CCK modulation + 2 OFDM frame used OFDM modulation + 1 TI Protection protection frame was detected + 0 Reserved + +phy_plcp_signal: 1 byte: + Receive PLCP Signal field from the Baseband Processor + +phy_level: 1 byte: + receive AGC gain level (can be used to measure receive signal strength) + +phy_snr: 1 byte: + estimated noise power of equalized receive signal + at input of FEC decoder (can be used to measure receive signal quality) + +time: 4 bytes: + timestamp sampled from either the Access Manager TSF counter + or free-running microsecond counter when the MAC receives + first byte of PLCP header. +*/ + +typedef struct rxbuffer { + u16 mac_cnt_rcvd ACX_PACKED; /* only 12 bits are len! (0xfff) */ + u8 mac_cnt_mblks ACX_PACKED; + u8 mac_status ACX_PACKED; + u8 phy_stat_baseband ACX_PACKED; /* bit 0x80: used LNA (Low-Noise Amplifier) */ + u8 phy_plcp_signal ACX_PACKED; + u8 phy_level ACX_PACKED; /* PHY stat */ + u8 phy_snr ACX_PACKED; /* PHY stat */ + u32 time ACX_PACKED; /* timestamp upon MAC rcv first byte */ +/* 4-byte (acx100) or 8-byte (acx111) phy header will be here +** if RX_CFG1_INCLUDE_PHY_HDR is in effect: +** phy_hdr_t phy */ + wlan_hdr_a3_t hdr_a3 ACX_PACKED; + /* maximally sized data part of wlan packet */ + u8 data_a3[WLAN_A4FR_MAXLEN_WEP - WLAN_HDR_A3_LEN] ACX_PACKED; + /* can add hdr/data_a4 if needed */ +} rxbuffer_t; + + +/*--- Firmware statistics ----------------------------------------------------*/ +typedef struct fw_stats { + u32 val0x0 ACX_PACKED; /* hdr; */ + u32 tx_desc_of ACX_PACKED; + u32 rx_oom ACX_PACKED; + u32 rx_hdr_of ACX_PACKED; + u32 rx_hdr_use_next ACX_PACKED; + u32 rx_dropped_frame ACX_PACKED; + u32 rx_frame_ptr_err ACX_PACKED; + u32 rx_xfr_hint_trig ACX_PACKED; + + u32 rx_dma_req ACX_PACKED; + u32 rx_dma_err ACX_PACKED; + u32 tx_dma_req ACX_PACKED; + u32 tx_dma_err ACX_PACKED; + + u32 cmd_cplt ACX_PACKED; + u32 fiq ACX_PACKED; + u32 rx_hdrs ACX_PACKED; + u32 rx_cmplt ACX_PACKED; + u32 rx_mem_of ACX_PACKED; + u32 rx_rdys ACX_PACKED; + u32 irqs ACX_PACKED; + u32 acx_trans_procs ACX_PACKED; + u32 decrypt_done ACX_PACKED; + u32 dma_0_done ACX_PACKED; + u32 dma_1_done ACX_PACKED; + u32 tx_exch_complet ACX_PACKED; + u32 commands ACX_PACKED; + u32 acx_rx_procs ACX_PACKED; + u32 hw_pm_mode_changes ACX_PACKED; + u32 host_acks ACX_PACKED; + u32 pci_pm ACX_PACKED; + u32 acm_wakeups ACX_PACKED; + + u32 wep_key_count ACX_PACKED; + u32 wep_default_key_count ACX_PACKED; + u32 dot11_def_key_mib ACX_PACKED; + u32 wep_key_not_found ACX_PACKED; + u32 wep_decrypt_fail ACX_PACKED; +} fw_stats_t; + +/* Firmware version struct */ + +typedef struct fw_ver { + u16 cmd ACX_PACKED; + u16 size ACX_PACKED; + char fw_id[20] ACX_PACKED; + u32 hw_id ACX_PACKED; +} fw_ver_t; + +#define FW_ID_SIZE 20 + + +/*--- WEP stuff --------------------------------------------------------------*/ +#define DOT11_MAX_DEFAULT_WEP_KEYS 4 +#define MAX_KEYLEN 32 + +#define HOSTWEP_DEFAULTKEY_MASK (BIT1 | BIT0) +#define HOSTWEP_DECRYPT BIT4 +#define HOSTWEP_ENCRYPT BIT5 +#define HOSTWEP_PRIVACYINVOKED BIT6 +#define HOSTWEP_EXCLUDEUNENCRYPTED BIT7 + +/* non-firmware struct, no packing necessary */ +typedef struct wep_key { + size_t size; /* most often used member first */ + u8 index; + u8 key[29]; + u16 strange_filler; +} wep_key_t; /* size = 264 bytes (33*8) */ +/* FIXME: We don't have size 264! Or is there 2 bytes beyond the key + * (strange_filler)? */ + +/* non-firmware struct, no packing necessary */ +typedef struct key_struct { + u8 addr[ETH_ALEN]; /* 0x00 */ + u16 filler1; /* 0x06 */ + u32 filler2; /* 0x08 */ + u32 index; /* 0x0c */ + u16 len; /* 0x10 */ + u8 key[29]; /* 0x12; is this long enough??? */ +} key_struct_t; /* size = 276. FIXME: where is the remaining space?? */ + + +/*--- Client (peer) info -----------------------------------------------------*/ +/* priv->sta_list[] is used for: +** accumulating and processing of scan results +** keeping client info in AP mode +** keeping AP info in STA mode (AP is the only one 'client') +** keeping peer info in ad-hoc mode +** non-firmware struct --> no packing necessary */ +enum { + CLIENT_EMPTY_SLOT_0 = 0, + CLIENT_EXIST_1 = 1, + CLIENT_AUTHENTICATED_2 = 2, + CLIENT_ASSOCIATED_3 = 3, + CLIENT_JOIN_CANDIDATE = 4 +}; +struct client { + struct client* next; + unsigned long mtime; /* last time we heard it, in jiffies */ + size_t essid_len; /* length of ESSID (without '\0') */ + u32 sir; /* Standard IR */ + u32 snr; /* Signal to Noise Ratio */ + u16 aid; /* association ID */ + u16 seq; /* from client's auth req */ + u16 auth_alg; /* from client's auth req */ + u16 cap_info; /* from client's assoc req */ + u16 rate_cap; /* what client supports (all rates) */ + u16 rate_bas; /* what client supports (basic rates) */ + u16 rate_cfg; /* what is allowed (by iwconfig etc) */ + u16 rate_cur; /* currently used rate mask */ + u8 rate_100; /* currently used rate byte (acx100 only) */ + u8 used; /* misnamed, more like 'status' */ + u8 address[ETH_ALEN]; + u8 bssid[ETH_ALEN]; /* ad-hoc hosts can have bssid != mac */ + u8 channel; + u8 auth_step; + u8 ignore_count; + u8 fallback_count; + u8 stepup_count; + char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID and trailing '\0' */ +/* FIXME: this one is too damn big */ + char challenge_text[WLAN_CHALLENGE_LEN]; +}; + + +/*============================================================================* + * Hardware structures * + *============================================================================*/ + +/* An opaque typesafe helper type + * + * Some hardware fields are actually pointers, + * but they have to remain u32, since using ptr instead + * (8 bytes on 64bit systems!) would disrupt the fixed descriptor + * format the acx firmware expects in the non-user area. + * Since we cannot cram an 8 byte ptr into 4 bytes, we need to + * enforce that pointed to data remains in low memory + * (address value needs to fit in 4 bytes) on 64bit systems. + * + * This is easy to get wrong, thus we are using a small struct + * and special macros to access it. Macros will check for + * attempts to overflow an acx_ptr with value > 0xffffffff. + * + * Attempts to use acx_ptr without macros result in compile-time errors */ + +typedef struct { + u32 v; +} acx_ptr; + +#if ACX_DEBUG +#define CHECK32(n) BUG_ON(sizeof(n)>4 && (long)(n)>0xffffff00) +#else +#define CHECK32(n) ((void)0) +#endif + +/* acx_ptr <-> integer conversion */ +#define cpu2acx(n) ({ CHECK32(n); ((acx_ptr){ .v = cpu_to_le32(n) }); }) +#define acx2cpu(a) (le32_to_cpu(a.v)) + +/* acx_ptr <-> pointer conversion */ +#define ptr2acx(p) ({ CHECK32(p); ((acx_ptr){ .v = cpu_to_le32((u32)(long)(p)) }); }) +#define acx2ptr(a) ((void*)le32_to_cpu(a.v)) + +/* Values for rate field (acx100 only) */ +#define RATE100_1 10 +#define RATE100_2 20 +#define RATE100_5 55 +#define RATE100_11 110 +#define RATE100_22 220 +/* This bit denotes use of PBCC: +** (PBCC encoding is usable with 11 and 22 Mbps speeds only) */ +#define RATE100_PBCC511 0x80 + +/* Bit values for rate111 field */ +#define RATE111_1 0x0001 /* DBPSK */ +#define RATE111_2 0x0002 /* DQPSK */ +#define RATE111_5 0x0004 /* CCK or PBCC */ +#define RATE111_6 0x0008 /* CCK-OFDM or OFDM */ +#define RATE111_9 0x0010 /* CCK-OFDM or OFDM */ +#define RATE111_11 0x0020 /* CCK or PBCC */ +#define RATE111_12 0x0040 /* CCK-OFDM or OFDM */ +#define RATE111_18 0x0080 /* CCK-OFDM or OFDM */ +#define RATE111_22 0x0100 /* PBCC */ +#define RATE111_24 0x0200 /* CCK-OFDM or OFDM */ +#define RATE111_36 0x0400 /* CCK-OFDM or OFDM */ +#define RATE111_48 0x0800 /* CCK-OFDM or OFDM */ +#define RATE111_54 0x1000 /* CCK-OFDM or OFDM */ +#define RATE111_RESERVED 0x2000 +#define RATE111_PBCC511 0x4000 /* PBCC mod at 5.5 or 11Mbit (else CCK) */ +#define RATE111_SHORTPRE 0x8000 /* short preamble */ +/* Special 'try everything' value */ +#define RATE111_ALL 0x1fff +/* These bits denote acx100 compatible settings */ +#define RATE111_ACX100_COMPAT 0x0127 +/* These bits denote 802.11b compatible settings */ +#define RATE111_80211B_COMPAT 0x0027 + +/* Descriptor Ctl field bits + * init value is 0x8e, "idle" value is 0x82 (in idle tx descs) + */ +#define DESC_CTL_SHORT_PREAMBLE 0x01 /* preamble type: 0 = long; 1 = short */ +#define DESC_CTL_FIRSTFRAG 0x02 /* this is the 1st frag of the frame */ +#define DESC_CTL_AUTODMA 0x04 +#define DESC_CTL_RECLAIM 0x08 /* ready to reuse */ +#define DESC_CTL_HOSTDONE 0x20 /* host has finished processing */ +#define DESC_CTL_ACXDONE 0x40 /* acx has finished processing */ +/* host owns the desc [has to be released last, AFTER modifying all other desc fields!] */ +#define DESC_CTL_HOSTOWN 0x80 + +#define DESC_CTL_INIT (DESC_CTL_HOSTOWN | DESC_CTL_RECLAIM | \ + DESC_CTL_AUTODMA | DESC_CTL_FIRSTFRAG) +#define DESC_CTL_DONE (DESC_CTL_ACXDONE | DESC_CTL_HOSTOWN) + +#define DESC_CTL_HOSTOWN_STR "80" +#define DESC_CTL_DONE_STR "C0" + +/* NB: some bits may be interesting for Monitor mode tx (aka Raw tx): */ +#define DESC_CTL2_SEQ 0x01 /* don't increase sequence field */ +#define DESC_CTL2_FCS 0x02 /* don't add the FCS */ +#define DESC_CTL2_MORE_FRAG 0x04 +#define DESC_CTL2_RETRY 0x08 /* don't increase retry field */ +#define DESC_CTL2_POWER 0x10 /* don't increase power mgmt. field */ +#define DESC_CTL2_RTS 0x20 /* do RTS/CTS magic before sending */ +#define DESC_CTL2_WEP 0x40 /* encrypt this frame */ +#define DESC_CTL2_DUR 0x80 /* don't increase duration field */ + +/*************************************************************** +** PCI structures +*/ +/* IRQ Constants +** (outside of "#ifdef PCI" because USB (mis)uses HOST_INT_SCAN_COMPLETE */ +#define HOST_INT_RX_DATA 0x0001 +#define HOST_INT_TX_COMPLETE 0x0002 +#define HOST_INT_TX_XFER 0x0004 +#define HOST_INT_RX_COMPLETE 0x0008 +#define HOST_INT_DTIM 0x0010 +#define HOST_INT_BEACON 0x0020 +#define HOST_INT_TIMER 0x0040 +#define HOST_INT_KEY_NOT_FOUND 0x0080 +#define HOST_INT_IV_ICV_FAILURE 0x0100 +#define HOST_INT_CMD_COMPLETE 0x0200 +#define HOST_INT_INFO 0x0400 +#define HOST_INT_OVERFLOW 0x0800 +#define HOST_INT_PROCESS_ERROR 0x1000 +#define HOST_INT_SCAN_COMPLETE 0x2000 +#define HOST_INT_FCS_THRESHOLD 0x4000 +#define HOST_INT_UNKNOWN 0x8000 + +#ifdef ACX_PCI + +/* Register I/O offsets */ +#define ACX100_EEPROM_ID_OFFSET 0x380 + +/* please add further ACX hardware register definitions only when + it turns out you need them in the driver, and please try to use + firmware functionality instead, since using direct I/O access instead + of letting the firmware do it might confuse the firmware's state + machine */ + +/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION +** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */ +enum { + IO_ACX_SOFT_RESET = 0, + + IO_ACX_SLV_MEM_ADDR, + IO_ACX_SLV_MEM_DATA, + IO_ACX_SLV_MEM_CTL, + IO_ACX_SLV_END_CTL, + + IO_ACX_FEMR, /* Function Event Mask */ + + IO_ACX_INT_TRIG, + IO_ACX_IRQ_MASK, + IO_ACX_IRQ_STATUS_NON_DES, + IO_ACX_IRQ_STATUS_CLEAR, /* CLEAR = clear on read */ + IO_ACX_IRQ_ACK, + IO_ACX_HINT_TRIG, + + IO_ACX_ENABLE, + + IO_ACX_EEPROM_CTL, + IO_ACX_EEPROM_ADDR, + IO_ACX_EEPROM_DATA, + IO_ACX_EEPROM_CFG, + + IO_ACX_PHY_ADDR, + IO_ACX_PHY_DATA, + IO_ACX_PHY_CTL, + + IO_ACX_GPIO_OE, + + IO_ACX_GPIO_OUT, + + IO_ACX_CMD_MAILBOX_OFFS, + IO_ACX_INFO_MAILBOX_OFFS, + IO_ACX_EEPROM_INFORMATION, + + IO_ACX_EE_START, + IO_ACX_SOR_CFG, + IO_ACX_ECPU_CTRL +}; +/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION +** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */ + +/* Values for IO_ACX_INT_TRIG register: */ +/* inform hw that rxdesc in queue needs processing */ +#define INT_TRIG_RXPRC 0x08 +/* inform hw that txdesc in queue needs processing */ +#define INT_TRIG_TXPRC 0x04 +/* ack that we received info from info mailbox */ +#define INT_TRIG_INFOACK 0x02 +/* inform hw that we have filled command mailbox */ +#define INT_TRIG_CMD 0x01 + +struct txhostdesc { + acx_ptr data_phy ACX_PACKED; /* 0x00 [u8 *] */ + u16 data_offset ACX_PACKED; /* 0x04 */ + u16 reserved ACX_PACKED; /* 0x06 */ + u16 Ctl_16 ACX_PACKED; /* 16bit value, endianness!! */ + u16 length ACX_PACKED; /* 0x0a */ + acx_ptr desc_phy_next ACX_PACKED; /* 0x0c [txhostdesc *] */ + acx_ptr pNext ACX_PACKED; /* 0x10 [txhostdesc *] */ + u32 Status ACX_PACKED; /* 0x14, unused on Tx */ +/* From here on you can use this area as you want (variable length, too!) */ + 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 */ + u16 reserved ACX_PACKED; /* 0x06 */ + u16 Ctl_16 ACX_PACKED; /* 0x08; 16bit value, endianness!! */ + u16 length ACX_PACKED; /* 0x0a */ + acx_ptr desc_phy_next ACX_PACKED; /* 0x0c [rxhostdesc_t *] */ + acx_ptr pNext ACX_PACKED; /* 0x10 [rxhostdesc_t *] */ + u32 Status ACX_PACKED; /* 0x14 */ +/* From here on you can use this area as you want (variable length, too!) */ + 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) + +#endif /* CONFIG_TIACX_PCI */ + +/*************************************************************** +** USB structures and constants +*/ +#ifdef ACX_USB + +/* Buffer size for fw upload */ +#define ACX100_USB_RWMEM_MAXLEN 2048 + +/* Should be sent to the ctrlout endpoint */ +#define ACX100_USB_ENBULKIN 6 + +/* The number of bulk URBs to use */ +#define ACX100_USB_NUM_BULK_URBS 8 + +/* Should be sent to the bulkout endpoint */ +#define ACX_USB_REQ_UPLOAD_FW 0x10 +#define ACX_USB_REQ_ACK_CS 0x11 +#define ACX_USB_REQ_CMD 0x12 + +/* Used for usb_txbuffer.desc field */ +#define USB_TXBUF_TXDESC 0xA +/* Used for usb_txbuffer.hostData field */ +#define USB_TXBUF_HD_ISDATA 0x10000 +#define USB_TXBUF_HD_DIRECTED 0x20000 +#define USB_TXBUF_HD_BROADCAST 0x40000 +/* Size of header (everything up to data[]) */ +#define USB_TXBUF_HDRSIZE 14 +typedef struct usb_txbuffer { + u16 desc ACX_PACKED; + u16 MPDUlen ACX_PACKED; + u8 index ACX_PACKED; + u8 txRate ACX_PACKED; + u32 hostData ACX_PACKED; + u8 ctrl1 ACX_PACKED; + u8 ctrl2 ACX_PACKED; + u16 dataLength ACX_PACKED; + /* wlan packet content is placed here: */ + u8 data[WLAN_A4FR_MAXLEN_WEP] ACX_PACKED; +} usb_txbuffer_t; + +typedef struct { + void *device; + int number; +} acx_usb_bulk_context_t; + +typedef struct usb_tx { + unsigned busy:1; + struct urb *urb; + wlandevice_t *priv; + client_t *txc; + /* actual USB bulk output data block is here: */ + usb_txbuffer_t bulkout; +} usb_tx_t; + +#endif /* CONFIG_TIACX_USB */ + + +/*============================================================================* + * Main acx per-device data structure (netdev->priv) * + *============================================================================*/ +#define ACX_STATE_FW_LOADED 0x01 +#define ACX_STATE_IFACE_UP 0x02 + +/* MAC mode (BSS type) defines + * Note that they shouldn't be redefined, since they are also used + * during communication with firmware */ +#define ACX_MODE_0_ADHOC 0 +#define ACX_MODE_1_UNUSED 1 +#define ACX_MODE_2_STA 2 +#define ACX_MODE_3_AP 3 +/* These are our own inventions. Sending these to firmware +** makes it stop emitting beacons, which is exactly what we want +** for these modes */ +#define ACX_MODE_MONITOR 0xfe +#define ACX_MODE_OFF 0xff +/* 'Submode': identifies exact status of ADHOC/STA host */ +#define ACX_STATUS_0_STOPPED 0 +#define ACX_STATUS_1_SCANNING 1 +#define ACX_STATUS_2_WAIT_AUTH 2 +#define ACX_STATUS_3_AUTHENTICATED 3 +#define ACX_STATUS_4_ASSOCIATED 4 + +/* FIXME: this should be named something like struct acx_priv (typedef'd to + * acx_priv_t) */ + +/* non-firmware struct, no packing necessary */ +struct wlandevice { + /*** Device chain ***/ + struct wlandevice *next; /* link for list of devices */ + + /*** Linux network device ***/ + struct net_device *netdev; /* pointer to linux netdevice */ + struct net_device *prev_nd; /* FIXME: We should not chain via our + * private struct wlandevice _and_ + * the struct net_device. */ + /*** Device statistics ***/ + struct net_device_stats stats; /* net device statistics */ +#ifdef WIRELESS_EXT + struct iw_statistics wstats; /* wireless statistics */ +#endif + /*** Power managment ***/ + struct pm_dev *pm; /* PM crap */ + + /*** Management timer ***/ + struct timer_list mgmt_timer; + + /*** Locking ***/ + struct semaphore sem; + spinlock_t lock; +#if defined(PARANOID_LOCKING) /* Lock debugging */ + const char *last_sem; + const char *last_lock; + unsigned long sem_time; + unsigned long lock_time; +#endif + + /*** Hardware identification ***/ + const char *chip_name; + u8 chip_type; + u8 form_factor; + u8 radio_type; + u8 eeprom_version; + + /*** Firmware identification ***/ + char firmware_version[FW_ID_SIZE+1]; + u32 firmware_numver; + u32 firmware_id; + + /*** Device state ***/ + u16 dev_state_mask; + u8 led_power; /* power LED status */ + u32 get_mask; /* mask of settings to fetch from the card */ + u32 set_mask; /* mask of settings to write to the card */ + + /* Barely used in USB case */ + u16 irq_status; + + u8 after_interrupt_jobs; /* mini job list for doing actions after an interrupt occurred */ + WORK_STRUCT after_interrupt_task; /* our task for after interrupt actions */ + + /*** scanning ***/ + u16 scan_count; /* number of times to do channel scan */ + u8 scan_mode; /* 0 == active, 1 == passive, 2 == background */ + u8 scan_rate; + u16 scan_duration; + u16 scan_probe_delay; +#if WIRELESS_EXT > 15 + struct iw_spy_data spy_data; /* FIXME: needs to be implemented! */ +#endif + + /*** Wireless network settings ***/ + /* copy of the device address (ifconfig hw ether) that we actually use + ** for 802.11; copied over from the network device's MAC address + ** (ifconfig) when it makes sense only */ + u8 dev_addr[MAX_ADDR_LEN]; + u8 bssid[ETH_ALEN]; /* the BSSID after having joined */ + u8 ap[ETH_ALEN]; /* The AP we want, FF:FF:FF:FF:FF:FF is any */ + u16 aid; /* The Association ID sent from the AP / last used AID if we're an AP */ + u16 mode; /* mode from iwconfig */ + u16 status; /* 802.11 association status */ + u8 essid_active; /* specific ESSID active, or select any? */ + u8 essid_len; /* to avoid dozens of strlen() */ + /* INCLUDES \0 termination for easy printf - but many places + ** simply want the string data memcpy'd plus a length indicator! + ** Keep that in mind... */ + char essid[IW_ESSID_MAX_SIZE+1]; + /* essid we are going to use for association, in case of "essid 'any'" + ** and in case of hidden ESSID (use configured ESSID then) */ + char essid_for_assoc[IW_ESSID_MAX_SIZE+1]; + char nick[IW_ESSID_MAX_SIZE+1]; /* see essid! */ + u8 channel; + u8 reg_dom_id; /* reg domain setting */ + u16 reg_dom_chanmask; + u16 auth_or_assoc_retries; + u16 scan_retries; + unsigned long scan_start; /* YES, jiffies is defined as "unsigned long" */ + + /* stations known to us (if we're an ap) */ + client_t sta_list[32]; /* tab is larger than list, so that */ + client_t *sta_hash_tab[64]; /* hash collisions are not likely */ + client_t *ap_client; /* this one is our AP (STA mode only) */ + + unsigned long dup_msg_expiry; + int dup_count; + u16 last_seq_ctrl; /* duplicate packet detection */ + + /* 802.11 power save mode */ + u8 ps_wakeup_cfg; + u8 ps_listen_interval; + u8 ps_options; + u8 ps_hangover_period; + u16 ps_enhanced_transition_time; + + /*** PHY settings ***/ + u8 fallback_threshold; + u8 stepup_threshold; + u16 rate_basic; + u16 rate_oper; + u16 rate_bcast; + u16 rate_bcast100; + u8 rate_auto; /* false if "iwconfig rate N" (WITHOUT 'auto'!) */ + u8 preamble_mode; /* 0 == Long Preamble, 1 == Short, 2 == Auto */ + u8 preamble_cur; + + u8 tx_disabled; + u8 tx_level_dbm; + 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; + int recalib_failure_count; + int recalib_msg_ratelimit; + int retry_errors_msg_ratelimit; + + unsigned long brange_time_last_state_change; /* time the power LED was last changed */ + u8 brange_last_state; /* last state of the LED */ + u8 brange_max_quality; /* maximum quality that equates to full speed */ + + u8 sensitivity; + u8 antenna; /* antenna settings */ + u8 ed_threshold; /* energy detect threshold */ + u8 cca; /* clear channel assessment */ + + u16 rts_threshold; + u32 short_retry; + u32 long_retry; + u16 msdu_lifetime; + u16 listen_interval; /* given in units of beacon interval */ + u32 beacon_interval; + + u16 capabilities; + u8 capab_short; + u8 capab_pbcc; + u8 capab_agility; + u8 rate_supported_len; + u8 rate_supported[13]; + + /*** Encryption settings (WEP) ***/ + u32 auth_alg; /* used in transmit_authen1 */ + u8 wep_enabled; + u8 wep_restricted; + u8 wep_current_index; + wep_key_t wep_keys[DOT11_MAX_DEFAULT_WEP_KEYS]; /* the default WEP keys */ + key_struct_t wep_key_struct[10]; + + /*** Card Rx/Tx management ***/ + u16 rx_config_1; + u16 rx_config_2; + u32 tx_cnt_done; + u16 memblocksize; + u32 RxQueueCnt; + u32 TxQueueCnt; + u32 TxQueueFree; + + /*** Unknown ***/ + u8 dtim_interval; + +/*** PCI/USB/... must be last or else hw agnostic code breaks horribly ***/ + + /*** PCI stuff ***/ +#ifdef ACX_PCI + TIWLAN_DC dc; + /* Same as dc.pRxHostDescQPool, but possibly aligned to 4 bytes: */ + rxhostdesc_t *RxHostDescPoolStart; + + u8 need_radio_fw; + u8 irqs_active; /* whether irq sending is activated */ + + const u16 *io; /* points to ACX100 or ACX111 I/O register address set */ + + struct pci_dev *pdev; + + unsigned long membase; + unsigned long membase2; + void *iobase; + void *iobase2; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) + /* 2.6.9-rc3-mm2 (2.6.9-bk4, too) introduced a shorter API version, + then it made its way into 2.6.10 */ + u32 pci_state[16]; /* saved PCI state for suspend/resume */ +#endif + u16 irq_mask; /* interrupt types to mask out (not wanted) with many IRQs activated */ + u16 irq_mask_off; /* interrupt types to mask out (not wanted) with IRQs off */ + unsigned int irq_loops_this_jiffy; + unsigned long irq_last_jiffies; + + /* command interface */ + void *cmd_area; /* points to PCI mapped memory */ + void *info_area; /* points to PCI mapped memory */ + u16 cmd_type; + u16 cmd_status; + u16 info_type; + u16 info_status; +#endif + + /*** USB stuff ***/ +#ifdef ACX_USB + struct usb_device *usbdev; + + rxbuffer_t rxtruncbuf; + /* TODO: convert (bulkins,bulkrx_urbs,rxcons) triple into + ** struct usb_rx (see struct usb_tx for an example) */ + rxbuffer_t bulkins[ACX100_USB_NUM_BULK_URBS]; + struct urb *bulkrx_urbs[ACX100_USB_NUM_BULK_URBS]; + /* Used by rx urb completion handler in order to find + ** corresponding priv/index pair */ + acx_usb_bulk_context_t rxcons[ACX100_USB_NUM_BULK_URBS]; + usb_tx_t usb_tx[ACX100_USB_NUM_BULK_URBS]; + + int bulkinep; /* bulk-in endpoint */ + int bulkoutep; /* bulk-out endpoint */ + int usb_free_tx; + int rxtruncsize; +#endif + +}; + +/* For use with ACX1xx_IE_RXCONFIG */ +/* bit description + * 13 include additional header (length etc.) *required* + * struct is defined in 'struct rxbuffer' + * is this bit acx100 only? does acx111 always put the header, + * and bit setting is irrelevant? --vda + * 10 receive frames only with SSID used in last join cmd + * 9 discard broadcast + * 8 receive packets for multicast address 1 + * 7 receive packets for multicast address 0 + * 6 discard all multicast packets + * 5 discard frames from foreign BSSID + * 4 discard frames with foreign destination MAC address + * 3 promiscuous mode (receive ALL frames, disable filter) + * 2 include FCS + * 1 include phy header + * 0 ??? + */ +#define RX_CFG1_INCLUDE_RXBUF_HDR 0x2000 /* ACX100 only */ +#define RX_CFG1_FILTER_SSID 0x0400 +#define RX_CFG1_FILTER_BCAST 0x0200 +#define RX_CFG1_RCV_MC_ADDR1 0x0100 +#define RX_CFG1_RCV_MC_ADDR0 0x0080 +#define RX_CFG1_FILTER_ALL_MULTI 0x0040 +#define RX_CFG1_FILTER_BSSID 0x0020 +#define RX_CFG1_FILTER_MAC 0x0010 +#define RX_CFG1_RCV_PROMISCUOUS 0x0008 +#define RX_CFG1_INCLUDE_FCS 0x0004 +#define RX_CFG1_INCLUDE_PHY_HDR (WANT_PHY_HDR ? 0x0002 : 0) +/* bit description + * 11 receive association requests etc. + * 10 receive authentication frames + * 9 receive beacon frames + * 8 receive contention free packets + * 7 receive control frames + * 6 receive data frames + * 5 receive broken frames + * 4 receive management frames + * 3 receive probe requests + * 2 receive probe responses + * 1 receive RTS/CTS/ACK frames + * 0 receive other + */ +#define RX_CFG2_RCV_ASSOC_REQ 0x0800 +#define RX_CFG2_RCV_AUTH_FRAMES 0x0400 +#define RX_CFG2_RCV_BEACON_FRAMES 0x0200 +#define RX_CFG2_RCV_CONTENTION_FREE 0x0100 +#define RX_CFG2_RCV_CTRL_FRAMES 0x0080 +#define RX_CFG2_RCV_DATA_FRAMES 0x0040 +#define RX_CFG2_RCV_BROKEN_FRAMES 0x0020 +#define RX_CFG2_RCV_MGMT_FRAMES 0x0010 +#define RX_CFG2_RCV_PROBE_REQ 0x0008 +#define RX_CFG2_RCV_PROBE_RESP 0x0004 +#define RX_CFG2_RCV_ACK_FRAMES 0x0002 +#define RX_CFG2_RCV_OTHER 0x0001 + +/* For use with ACX1xx_IE_FEATURE_CONFIG */ +#define FEATURE1_80MHZ_CLOCK 0x00000040L +#define FEATURE1_4X 0x00000020L +#define FEATURE1_LOW_RX 0x00000008L +#define FEATURE1_EXTRA_LOW_RX 0x00000001L + +#define FEATURE2_SNIFFER 0x00000080L +#define FEATURE2_NO_TXCRYPT 0x00000001L + +/*-- get and set mask values --*/ +#define GETSET_LED_POWER 0x00000001L +#define GETSET_STATION_ID 0x00000002L +#define SET_TEMPLATES 0x00000004L +#define SET_STA_LIST 0x00000008L +#define GETSET_TX 0x00000010L +#define GETSET_RX 0x00000020L +#define SET_RXCONFIG 0x00000040L +#define GETSET_ANTENNA 0x00000080L +#define GETSET_SENSITIVITY 0x00000100L +#define GETSET_TXPOWER 0x00000200L +#define GETSET_ED_THRESH 0x00000400L +#define GETSET_CCA 0x00000800L +#define GETSET_POWER_80211 0x00001000L +#define GETSET_RETRY 0x00002000L +#define GETSET_REG_DOMAIN 0x00004000L +#define GETSET_CHANNEL 0x00008000L +/* Used when ESSID changes etc and we need to scan for AP anew */ +#define GETSET_RESCAN 0x00010000L +#define GETSET_MODE 0x00020000L +#define GETSET_WEP 0x00040000L +#define SET_WEP_OPTIONS 0x00080000L +#define SET_MSDU_LIFETIME 0x00100000L +#define SET_RATE_FALLBACK 0x00200000L +#define GETSET_ALL 0x80000000L + + +/*============================================================================* + * Firmware loading * + *============================================================================*/ +/* Doh, 2.4.x also has CONFIG_FW_LOADER_MODULE + * (but doesn't have the new device model yet which we require!) + * FIXME: exact version that introduced new device handling? */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) +#define USE_FW_LOADER_26 1 +#define USE_FW_LOADER_LEGACY 0 +#else +#define USE_FW_LOADER_26 0 +#define USE_FW_LOADER_LEGACY 1 +#endif +#endif + +#if USE_FW_LOADER_26 +#include /* request_firmware() */ +#include /* struct pci_device */ +#endif + +#if USE_FW_LOADER_LEGACY +extern char *firmware_dir; +#endif + + +/*********************************************************************** +*/ +typedef struct acx100_ie_memblocksize { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u16 size ACX_PACKED; +} acx100_ie_memblocksize_t; + +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 NumRxDesc ACX_PACKED; /* for USB only */ + u8 padf2 ACX_PACKED; /* # rx buffers */ + 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; +} acx100_ie_queueconfig_t; + +typedef struct acx111_ie_queueconfig { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u32 tx_memory_block_address ACX_PACKED; + u32 rx_memory_block_address ACX_PACKED; + u32 rx1_queue_address ACX_PACKED; + u32 reserved1 ACX_PACKED; + u32 tx1_queue_address ACX_PACKED; + u8 tx1_attributes ACX_PACKED; + u16 reserved2 ACX_PACKED; + u8 reserved3 ACX_PACKED; +} acx111_ie_queueconfig_t; + +typedef struct acx100_ie_memconfigoption { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u32 DMA_config ACX_PACKED; + u32 pRxHostDesc ACX_PACKED; + u32 rx_mem ACX_PACKED; + u32 tx_mem ACX_PACKED; + u16 RxBlockNum ACX_PACKED; + u16 TxBlockNum ACX_PACKED; +} acx100_ie_memconfigoption_t; + +typedef struct acx111_ie_memoryconfig { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u16 no_of_stations ACX_PACKED; + u16 memory_block_size ACX_PACKED; + u8 tx_rx_memory_block_allocation ACX_PACKED; + u8 count_rx_queues ACX_PACKED; + u8 count_tx_queues ACX_PACKED; + u8 options ACX_PACKED; + u8 fragmentation ACX_PACKED; + u16 reserved1 ACX_PACKED; + u8 reserved2 ACX_PACKED; + + /* start of rx1 block */ + u8 rx_queue1_count_descs ACX_PACKED; + u8 rx_queue1_reserved1 ACX_PACKED; + u8 rx_queue1_type ACX_PACKED; /* must be set to 7 */ + u8 rx_queue1_prio ACX_PACKED; /* must be set to 0 */ + u32 rx_queue1_host_rx_start ACX_PACKED; + /* end of rx1 block */ + + /* start of tx1 block */ + u8 tx_queue1_count_descs ACX_PACKED; + u8 tx_queue1_reserved1 ACX_PACKED; + u8 tx_queue1_reserved2 ACX_PACKED; + u8 tx_queue1_attributes ACX_PACKED; + /* end of tx1 block */ +} acx111_ie_memoryconfig_t; + +typedef struct acx_ie_memmap { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u32 CodeStart ACX_PACKED; + u32 CodeEnd ACX_PACKED; + u32 WEPCacheStart ACX_PACKED; + u32 WEPCacheEnd ACX_PACKED; + u32 PacketTemplateStart ACX_PACKED; + u32 PacketTemplateEnd ACX_PACKED; + u32 QueueStart ACX_PACKED; + u32 QueueEnd ACX_PACKED; + u32 PoolStart ACX_PACKED; + u32 PoolEnd ACX_PACKED; +} acx_ie_memmap_t; + +typedef struct ACX111FeatureConfig { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u32 feature_options ACX_PACKED; + u32 data_flow_options ACX_PACKED; +} ACX111FeatureConfig_t; + +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 +#define PS_CFG_WAKEUP_BY_HOST 0x03 +#define PS_CFG_WAKEUP_EACH_ITVL 0x02 +#define PS_CFG_WAKEUP_ON_DTIM 0x01 +#define PS_CFG_WAKEUP_ALL_BEAC 0x00 + +/* Enhanced PS mode: sleep until Rx Beacon w/ the STA's AID bit set +** in the TIM; newer firmwares only(?) */ +#define PS_OPT_ENA_ENHANCED_PS 0x04 +#define PS_OPT_STILL_RCV_BCASTS 0x01 + +typedef struct acx100_ie_powermgmt { + u32 type ACX_PACKED; + u32 len ACX_PACKED; + u8 wakeup_cfg ACX_PACKED; + u8 listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */ + u8 options ACX_PACKED; + u8 hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */ + u16 enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */ +} acx100_ie_powermgmt_t; + +typedef struct acx111_ie_powermgmt { + u32 type ACX_PACKED; + u32 len ACX_PACKED; + u8 wakeup_cfg ACX_PACKED; + u8 listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */ + u8 options ACX_PACKED; + u8 hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */ + u32 beaconRxTime ACX_PACKED; + u32 enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */ +} acx111_ie_powermgmt_t; + + +/*********************************************************************** +** Commands and template structures +*/ + +/* +** SCAN command structure +** +** even though acx100 scan rates match RATE100 constants, +** acx111 ones do not match! Therefore we do not use RATE100 #defines */ +#define ACX_SCAN_RATE_1 10 +#define ACX_SCAN_RATE_2 20 +#define ACX_SCAN_RATE_5 55 +#define ACX_SCAN_RATE_11 110 +#define ACX_SCAN_RATE_22 220 +#define ACX_SCAN_OPT_ACTIVE 0x00 /* a bit mask */ +#define ACX_SCAN_OPT_PASSIVE 0x01 +/* Background scan: we go into Power Save mode (by transmitting +** NULL data frame to AP with the power mgmt bit set), do the scan, +** and then exit Power Save mode. A plus is that AP buffers frames +** for us while we do background scan. Thus we avoid frame losses. +** Background scan can be active or passive, just like normal one */ +#define ACX_SCAN_OPT_BACKGROUND 0x02 +typedef struct acx100_scan { + u16 count ACX_PACKED; /* number of scans to do, 0xffff == continuous */ + u16 start_chan ACX_PACKED; + u16 flags ACX_PACKED; /* channel list mask; 0x8000 == all channels? */ + u8 max_rate ACX_PACKED; /* max. probe rate */ + u8 options ACX_PACKED; /* bit mask, see defines above */ + u16 chan_duration ACX_PACKED; + u16 max_probe_delay ACX_PACKED; +} acx100_scan_t; /* length 0xc */ + +#define ACX111_SCAN_RATE_6 0x0B +#define ACX111_SCAN_RATE_9 0x0F +#define ACX111_SCAN_RATE_12 0x0A +#define ACX111_SCAN_RATE_18 0x0E +#define ACX111_SCAN_RATE_24 0x09 +#define ACX111_SCAN_RATE_36 0x0D +#define ACX111_SCAN_RATE_48 0x08 +#define ACX111_SCAN_RATE_54 0x0C +#define ACX111_SCAN_OPT_5GHZ 0x04 /* else 2.4GHZ */ +#define ACX111_SCAN_MOD_SHORTPRE 0x01 /* you can combine SHORTPRE and PBCC */ +#define ACX111_SCAN_MOD_PBCC 0x80 +#define ACX111_SCAN_MOD_OFDM 0x40 +typedef struct acx111_scan { + u16 count ACX_PACKED; /* number of scans to do */ + u8 channel_list_select ACX_PACKED; /* 0: scan all channels, 1: from chan_list only */ + u16 reserved1 ACX_PACKED; + u8 reserved2 ACX_PACKED; + u8 rate ACX_PACKED; /* rate for probe requests (if active scan) */ + u8 options ACX_PACKED; /* bit mask, see defines above */ + u16 chan_duration ACX_PACKED; /* min time to wait for reply on one channel (in TU) */ + /* (active scan only) (802.11 section 11.1.3.2.2) */ + u16 max_probe_delay ACX_PACKED; /* max time to wait for reply on one channel (active scan) */ + /* time to listen on a channel (passive scan) */ + u8 modulation ACX_PACKED; + u8 channel_list[26] ACX_PACKED; /* bits 7:0 first byte: channels 8:1 */ + /* bits 7:0 second byte: channels 16:9 */ + /* 26 bytes is enough to cover 802.11a */ +} acx111_scan_t; + + +/* +** Radio calibration command structure +*/ +typedef struct acx111_cmd_radiocalib { +/* 0x80000000 == automatic calibration by firmware, according to interval; + * bits 0..3: select calibration methods to go through: + * calib based on DC, AfeDC, Tx mismatch, Tx equilization */ + u32 methods ACX_PACKED; + u32 interval ACX_PACKED; +} acx111_cmd_radiocalib_t; + + +/* +** Packet template structures +** +** Packet templates store contents of Beacon, Probe response, Probe request, +** Null data frame, and TIM data frame. Firmware automatically transmits +** contents of template at appropriate time: +** - Beacon: when configured as AP or Ad-hoc +** - Probe response: when configured as AP or Ad-hoc, whenever +** a Probe request frame is received +** - Probe request: when host issues SCAN command (active) +** - Null data frame: when entering 802.11 power save mode +** - TIM data: at the end of Beacon frames (if no TIM template +** is configured, then transmits default TIM) +** NB: +** - size field must be set to size of actual template +** (NOT sizeof(struct) - templates are variable in length), +** size field is not itself counted. +** - members flagged with an asterisk must be initialized with host, +** rest must be zero filled. +** - variable length fields shown only in comments */ +typedef struct acx_template_tim { + u16 size ACX_PACKED; + u8 tim_eid ACX_PACKED; /* 00 1 TIM IE ID * */ + u8 len ACX_PACKED; /* 01 1 Length * */ + u8 dtim_cnt ACX_PACKED; /* 02 1 DTIM Count */ + u8 dtim_period ACX_PACKED; /* 03 1 DTIM Period */ + u8 bitmap_ctrl ACX_PACKED; /* 04 1 Bitmap Control * (except bit0) */ + /* 05 n Partial Virtual Bitmap * */ + u8 variable[0x100 - 1-1-1-1-1] ACX_PACKED; +} acx_template_tim_t; + +typedef struct acx100_template_probereq { + u16 size ACX_PACKED; + u16 fc ACX_PACKED; /* 00 2 fc */ + u16 dur ACX_PACKED; /* 02 2 Duration */ + u8 da[6] ACX_PACKED; /* 04 6 Destination Address * */ + u8 sa[6] ACX_PACKED; /* 0A 6 Source Address * */ + u8 bssid[6] ACX_PACKED; /* 10 6 BSSID * */ + u16 seq ACX_PACKED; /* 16 2 Sequence Control */ + u8 timestamp[8] ACX_PACKED;/* 18 8 Timestamp */ + u16 beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */ + u16 cap ACX_PACKED; /* 22 2 Capability Information * */ + /* 24 n SSID * */ + /* nn n Supported Rates * */ + u8 variable[0x44 - 2-2-6-6-6-2-8-2-2] ACX_PACKED; +} acx100_template_probereq_t; + +typedef struct acx111_template_probereq { + u16 size ACX_PACKED; + u16 fc ACX_PACKED; /* 00 2 fc * */ + u16 dur ACX_PACKED; /* 02 2 Duration */ + u8 da[6] ACX_PACKED; /* 04 6 Destination Address * */ + u8 sa[6] ACX_PACKED; /* 0A 6 Source Address * */ + u8 bssid[6] ACX_PACKED; /* 10 6 BSSID * */ + u16 seq ACX_PACKED; /* 16 2 Sequence Control */ + /* 18 n SSID * */ + /* nn n Supported Rates * */ + u8 variable[0x44 - 2-2-6-6-6-2] ACX_PACKED; +} acx111_template_probereq_t; + +typedef struct acx_template_proberesp { + u16 size ACX_PACKED; + u16 fc ACX_PACKED; /* 00 2 fc * (bits [15:12] and [10:8] per 802.11 section 7.1.3.1) */ + u16 dur ACX_PACKED; /* 02 2 Duration */ + u8 da[6] ACX_PACKED; /* 04 6 Destination Address */ + u8 sa[6] ACX_PACKED; /* 0A 6 Source Address */ + u8 bssid[6] ACX_PACKED; /* 10 6 BSSID */ + u16 seq ACX_PACKED; /* 16 2 Sequence Control */ + u8 timestamp[8] ACX_PACKED;/* 18 8 Timestamp */ + u16 beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */ + u16 cap ACX_PACKED; /* 22 2 Capability Information * */ + /* 24 n SSID * */ + /* nn n Supported Rates * */ + /* nn 1 DS Parameter Set * */ + u8 variable[0x54 - 2-2-6-6-6-2-8-2-2] ACX_PACKED; +} acx_template_proberesp_t; +#define acx_template_beacon_t acx_template_proberesp_t +#define acx_template_beacon acx_template_proberesp + + +/* +** JOIN command structure +** +** as opposed to acx100, acx111 dtim interval is AFTER rates_basic111. +** NOTE: took me about an hour to get !@#$%^& packing right --> struct packing is eeeeevil... */ +typedef struct acx_joinbss { + u8 bssid[ETH_ALEN] ACX_PACKED; + u16 beacon_interval ACX_PACKED; + union { + struct { + u8 dtim_interval ACX_PACKED; + u8 rates_basic ACX_PACKED; + u8 rates_supported ACX_PACKED; + } acx100 ACX_PACKED; + struct { + u16 rates_basic ACX_PACKED; + u8 dtim_interval ACX_PACKED; + } acx111 ACX_PACKED; + } u ACX_PACKED; + u8 genfrm_txrate ACX_PACKED; /* generated frame (bcn, proberesp, RTS, PSpoll) tx rate */ + u8 genfrm_mod_pre ACX_PACKED; /* generated frame modulation/preamble: + ** bit7: PBCC, bit6: OFDM (else CCK/DQPSK/DBPSK) + ** bit5: short pre */ + u8 macmode ACX_PACKED; /* BSS Type, must be one of ACX_MODE_xxx */ + u8 channel ACX_PACKED; + u8 essid_len ACX_PACKED; + char essid[IW_ESSID_MAX_SIZE] ACX_PACKED; +} acx_joinbss_t; + +#define JOINBSS_RATES_1 0x01 +#define JOINBSS_RATES_2 0x02 +#define JOINBSS_RATES_5 0x04 +#define JOINBSS_RATES_11 0x08 +#define JOINBSS_RATES_22 0x10 + +/* Looks like missing bits are used to indicate 11g rates! +** (it follows from the fact that constants below match 1:1 to RATE111_nn) +** This was actually seen! Look at that Assoc Request sent by acx111, +** it _does_ contain 11g rates in basic set: +01:30:20.070772 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1 +01:30:20.074425 Authentication (Open System)-1: Succesful +01:30:20.076539 Authentication (Open System)-2: +01:30:20.076620 Acknowledgment +01:30:20.088546 Assoc Request (xxx) [1.0* 2.0* 5.5* 6.0* 9.0* 11.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] +01:30:20.122413 Assoc Response AID(1) :: Succesful +01:30:20.122679 Acknowledgment +01:30:20.173204 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1 +*/ +#define JOINBSS_RATES_BASIC111_1 0x0001 +#define JOINBSS_RATES_BASIC111_2 0x0002 +#define JOINBSS_RATES_BASIC111_5 0x0004 +#define JOINBSS_RATES_BASIC111_11 0x0020 +#define JOINBSS_RATES_BASIC111_22 0x0100 + + +/*********************************************************************** +*/ +typedef struct mem_read_write { + u16 addr ACX_PACKED; + u16 type ACX_PACKED; /* 0x0 int. RAM / 0xffff MAC reg. / 0x81 PHY RAM / 0x82 PHY reg. */ + u32 len ACX_PACKED; + 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 { + 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 { + u32 offset ACX_PACKED; + u32 len ACX_PACKED; +} acx_cmd_radioinit_t; + +typedef struct acx100_ie_wep_options { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u16 NumKeys ACX_PACKED; /* max # of keys */ + u8 WEPOption ACX_PACKED; /* 0 == decrypt default key only, 1 == override decrypt */ + u8 Pad ACX_PACKED; /* used only for acx111 */ +} acx100_ie_wep_options_t; + +typedef struct ie_dot11WEPDefaultKey { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u8 action ACX_PACKED; + u8 keySize ACX_PACKED; + u8 defaultKeyNum ACX_PACKED; + u8 key[29] ACX_PACKED; /* check this! was Key[19]. */ +} ie_dot11WEPDefaultKey_t; + +typedef struct acx111WEPDefaultKey { + u8 MacAddr[ETH_ALEN] ACX_PACKED; + u16 action ACX_PACKED; /* NOTE: this is a u16, NOT a u8!! */ + u16 reserved ACX_PACKED; + u8 keySize ACX_PACKED; + u8 type ACX_PACKED; + u8 index ACX_PACKED; + u8 defaultKeyNum ACX_PACKED; + u8 counter[6] ACX_PACKED; + u8 key[32] ACX_PACKED; /* up to 32 bytes (for TKIP!) */ +} acx111WEPDefaultKey_t; + +typedef struct ie_dot11WEPDefaultKeyID { + u16 type ACX_PACKED; + u16 len ACX_PACKED; + u8 KeyID ACX_PACKED; +} ie_dot11WEPDefaultKeyID_t; + +typedef struct acx100_cmd_wep_mgmt { + u8 MacAddr[ETH_ALEN] ACX_PACKED; + u16 Action ACX_PACKED; + u16 KeySize ACX_PACKED; + u8 Key[29] ACX_PACKED; /* 29*8 == 232bits == WEP256 */ +} acx100_cmd_wep_mgmt_t; + +typedef struct defaultkey { + u8 num; +} defaultkey_t; + +typedef struct acx_ie_generic { + u16 type ACX_PACKED; + 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; */ + /* generic member for quick implementation of commands */ + u8 bytes[32] ACX_PACKED; + } m ACX_PACKED; +} acx_ie_generic_t; + +/* Config Option structs */ + +typedef struct co_antennas { + u8 type ACX_PACKED; + u8 len ACX_PACKED; + u8 list[2] ACX_PACKED; +} co_antennas_t; + +typedef struct co_powerlevels { + u8 type ACX_PACKED; + u8 len ACX_PACKED; + u16 list[8] ACX_PACKED; +} co_powerlevels_t; + +typedef struct co_datarates { + u8 type ACX_PACKED; + u8 len ACX_PACKED; + u8 list[8] ACX_PACKED; +} co_datarates_t; + +typedef struct co_domains { + u8 type ACX_PACKED; + u8 len ACX_PACKED; + u8 list[6] ACX_PACKED; +} co_domains_t; + +typedef struct co_product_id { + u8 type ACX_PACKED; + u8 len ACX_PACKED; + u8 list[128] ACX_PACKED; +} co_product_id_t; + +typedef struct co_manuf_id { + u8 type ACX_PACKED; + u8 len ACX_PACKED; + u8 list[128] ACX_PACKED; +} co_manuf_t; + +typedef struct co_fixed { + u8 type ACX_PACKED; + u8 len ACX_PACKED; + char NVSv[8] ACX_PACKED; + u8 MAC[6] ACX_PACKED; + u16 probe_delay ACX_PACKED; + u32 eof_memory ACX_PACKED; + u8 dot11CCAModes ACX_PACKED; + u8 dot11Diversity ACX_PACKED; + u8 dot11ShortPreambleOption ACX_PACKED; + u8 dot11PBCCOption ACX_PACKED; + u8 dot11ChannelAgility ACX_PACKED; + u8 dot11PhyType ACX_PACKED; +/* u8 dot11TempType ACX_PACKED; + u8 num_var ACX_PACKED; seems to be erased */ +} co_fixed_t; + + +typedef struct acx111_ie_configoption { + co_fixed_t configoption_fixed ACX_PACKED; + co_antennas_t antennas ACX_PACKED; + co_powerlevels_t power_levels ACX_PACKED; + co_datarates_t data_rates ACX_PACKED; + co_domains_t domains ACX_PACKED; + co_product_id_t product_id ACX_PACKED; + co_manuf_t manufacturer ACX_PACKED; +} acx111_ie_configoption_t; + + +/*============================================================================* + * Global data * + *============================================================================*/ +extern const u8 bitpos2ratebyte[]; +extern const u8 bitpos2rate100[]; + +extern const struct iw_handler_def acx_ioctl_handler_def; + +#define MINFREE_TX 3 diff -puN /dev/null drivers/net/wireless/tiacx/Changelog --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/Changelog 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,136 @@ +[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 + +[20050822] +* idma.c is incorporated into helper.c +* lots of cosmetic work: comments, struct member shuffling, + etc. TIWLAN_DC and other PCI data structs are #ifdef'ed + to be PCI-only. A few todos added. Extra #include's removed. +* added sem locking debug printout code (for amd64 debug) +* beacon tx rate and beacon ratevector is updated according to + "iwconfig rate" command immediately (required mode change before). + +[20050821] +* Switch to wrapper functions for dealing with "tx buffers" + (memory areas where we create packets for tx. For USB, it's just + a part of wlandevice_t, for PCI it's a DMAable buffer pointed to + by txhostdesc). +* Completely hide nature of PCI txdescs under opaque pointer type tx_t* +* acx_l_ether_to_txdesc -> acx_l_ether_to_txbuf, not using knowledge + of PCI txdesc anymore. +* Massive surgery on usb.c, cutting all paths into PCI code. +* PCI code moved to pci.c - USB don't need these pieces anymore +* acx111 and acx100 txhostdesc creation unified into single function + +[20050816] +* PCI code switched to single-txdesc scheme +* version bump to 0.2.5 + +[20050815] +* dev_kfree_skb -> dev_kfree_skb_any + +[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. + 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. + Code which misbehaves looks fine. I do not know what's going on. + Workaround: turn off preemption. + +[20050812] +* acx100 was failing to find out radio module #, + and wanted to load radio module 00. Must be fixed now. +* USB: more simplifications + +[20050810] +* USB: simplified command submission code, removed some + wlandevice_t fields (now unused) + +[20050808] +* USB changes: nuked global statics, simplified issue_cmd, + shortened wlandevice_t. Added some TODOs :) + +[20050807] +* restart scan if AP is not found +* remove use_eth_name parameter. It was deprecated +* disable legacy firmware loader for 2.6. Driver printed a warning + about need to switch to hotplug. +* WARNING: new names for firmware images! + Driver will try to load the following images: + PCI driver: + 'tiacxNNNcMM' (NNN=100/111, MM=radio module ID (in uppercase hex)): + combined firmware for specified chipset and radio. + failing that, it will try to load images named + 'tiacxNNN' (NNN=100/111): main firmware for specified chipset + and 'tiacxNNNrMM': corresponding radio module. + For example, my firmware is in file named 'tiacx111c16'. + Alternatively, I may remove it and use pair of files + 'tiacx111' and 'tiacx111r16' instead. + USB driver: loads image named 'tiacx100usb' + Hint: you can keep both old and new image names (via symlinks + or just by copying files) if you need to run older driver. +* fix "Debug: sleeping function called from invalid context..." for USB +* ACX_{PCI,USB} -> CONFIG_ACX_{PCI,USB} in preparation to 2.6 merge +* version bump to 0.2.4 + +[20050804] +* 'Fixed' deadlock on flush_scheduled_work (need a better fix eventually) +* We didn't completely disable IRQs on ifdown -> "Disabling IRQ#NN" + on second modprobe. Fixed. + +[20050802] +* removed some // comments in order to please Andreas +* moved a field to PCI-only part of wlandevice_t +* Random Version Bump (tm) to 0.2.3 +* no code changes + +[20050730] +* Basically just incorporating acx-20050722.acx100fixed.patch + This is a bit of a backward step, because instead of figuring out + why active scanning doesn't work for acx100, we just disable it. + acx100 owners encouraged to try to make it work + +[20050729] +* Added some IE IDs + +[20050726] +* added probe request config to acx100_s_init_packet_templates, + maybe acx100 is working now + +[20050721] +* del_timer_sync() sem lockup on SMP maybe fixed + +[20050720] +* lots of amd64 warnings fixed, thanks to Matan Peled + +[20050710] +* {tx,rx}hostdesc->desc_phy removed (was not used) +* netdev->type of ARPHRD_IEEE80211_PRISM was sticking forever + after monitor mode. Fixed +* monitor mode tx is working again +* rate reporting added in monitor mode packet header + +[20050709] +* moved PCI specific ioctls to pci.c +* ioctl.c is PCI/USB independent now + +[20050708] +* Fixed one apparent bug (wlandevice_t had different + layout for PCI and USB - conv.c would die horribly) +* Massive code shuffling with only trivial code changes. + Mostly sorting out PCI/USB stuff into relevant files. +* ihw.c eliminated +* helper2.c is PCI/USB independent now diff -puN /dev/null drivers/net/wireless/tiacx/conv.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/conv.c 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,523 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +#include +#include +#include +#include +#include +#include +#if WIRELESS_EXT >= 13 +#include +#endif + +#include "acx.h" + + +/*---------------------------------------------------------------- +* proto_is_stt +* +* Searches the 802.1h Selective Translation Table for a given +* protocol. +* +* Arguments: +* prottype protocol number (in host order) to search for. +* +* Returns: +* 1 - if the table is empty or a match is found. +* 0 - if the table is non-empty and a match is not found. +* +* Comment: +* Based largely on p80211conv.c of the linux-wlan-ng project +*----------------------------------------------------------------*/ +static inline int +proto_is_stt(unsigned int proto) +{ + /* Always return found for now. This is the behavior used by the */ + /* Zoom Win95 driver when 802.1h mode is selected */ + /* TODO: If necessary, add an actual search we'll probably + need this to match the CMAC's way of doing things. + Need to do some testing to confirm. + */ + + if (proto == 0x80f3) /* APPLETALK */ + return 1; + + return 0; +/* return ((prottype == ETH_P_AARP) || (prottype == ETH_P_IPX)); */ +} + +/* Helpers */ + +static inline void +store_llc_snap(struct wlan_llc *llc) +{ + llc->dsap = 0xaa; /* SNAP, see IEEE 802 */ + llc->ssap = 0xaa; + llc->ctl = 0x03; +} +static inline int +llc_is_snap(const struct wlan_llc *llc) +{ + return (llc->dsap == 0xaa) + && (llc->ssap == 0xaa) + && (llc->ctl == 0x03); +} +static inline void +store_oui_rfc1042(struct wlan_snap *snap) +{ + snap->oui[0] = 0; + snap->oui[1] = 0; + snap->oui[2] = 0; +} +static inline int +oui_is_rfc1042(const struct wlan_snap *snap) +{ + return (snap->oui[0] == 0) + && (snap->oui[1] == 0) + && (snap->oui[2] == 0); +} +static inline void +store_oui_8021h(struct wlan_snap *snap) +{ + snap->oui[0] = 0; + snap->oui[1] = 0; + snap->oui[2] = 0xf8; +} +static inline int +oui_is_8021h(const struct wlan_snap *snap) +{ + return (snap->oui[0] == 0) + && (snap->oui[1] == 0) + && (snap->oui[2] == 0xf8); +} + + +/*---------------------------------------------------------------- +* acx_l_ether_to_txbuf +* +* Uses the contents of the ether frame to build the elements of +* the 802.11 frame. +* +* We don't actually set up the frame header here. That's the +* MAC's job. We're only handling conversion of DIXII or 802.3+LLC +* frames to something that works with 802.11. +* +* Comment: +* Based largely on p80211conv.c of the linux-wlan-ng project +*----------------------------------------------------------------*/ +int +acx_l_ether_to_txbuf(wlandevice_t *priv, void *txbuf, const struct sk_buff *skb) +{ + struct wlan_hdr_a3 *w_hdr; + struct wlan_ethhdr *e_hdr; + struct wlan_llc *e_llc; + struct wlan_snap *e_snap; + const u8 *a1, *a3; + int header_len, payload_len; + int result = -1; + /* protocol type or data length, depending on whether + * DIX or 802.3 ethernet format */ + u16 proto; + u16 fc; + + FN_ENTER; + + if (unlikely(!skb->len)) { + acxlog(L_DEBUG, "zero-length skb!\n"); + goto end; + } + + w_hdr = (struct wlan_hdr_a3*)txbuf; + + switch (priv->mode) { + case ACX_MODE_MONITOR: + /* NB: one day we might want to play with DESC_CTL2_FCS + ** Will need to stop doing "- WLAN_CRC_LEN" here then */ + if (skb->len >= WLAN_A4FR_MAXLEN_WEP - WLAN_CRC_LEN) { + printk("%s: can't tx oversized frame (%d bytes)\n", + priv->netdev->name, skb->len); + goto end; + } + memcpy(w_hdr, skb->data, skb->len); + result = skb->len; + goto end; + } + + /* step 1: classify ether frame, DIX or 802.3? */ + e_hdr = (wlan_ethhdr_t *)skb->data; + proto = ntohs(e_hdr->type); + if (proto <= 1500) { + acxlog(L_DEBUG, "tx: 802.3 len: %d\n", skb->len); + /* codes <= 1500 reserved for 802.3 lengths */ + /* it's 802.3, pass ether payload unchanged, */ + /* trim off ethernet header and copy payload to tx_desc */ + header_len = WLAN_HDR_A3_LEN; + /* TODO: must be equal to skb->len - sizeof(wlan_ethhdr_t), no? */ + /* then we can do payload_len = ... after this big if() */ + payload_len = proto; + } else { + /* it's DIXII, time for some conversion */ + /* Create 802.11 packet. Header also contains llc and snap. */ + + acxlog(L_DEBUG, "tx: DIXII len: %d\n", skb->len); + + /* size of header is 802.11 header + llc + snap */ + header_len = WLAN_HDR_A3_LEN + sizeof(wlan_llc_t) + sizeof(wlan_snap_t); + /* llc is located behind the 802.11 header */ + e_llc = (wlan_llc_t*)(w_hdr + 1); + /* snap is located behind the llc */ + e_snap = (wlan_snap_t*)(e_llc + 1); + + /* setup the LLC header */ + store_llc_snap(e_llc); + + /* setup the SNAP header */ + e_snap->type = htons(proto); + if (proto_is_stt(proto)) { + store_oui_8021h(e_snap); + } else { + store_oui_rfc1042(e_snap); + } + /* trim off ethernet header and copy payload to tx_desc */ + payload_len = skb->len - sizeof(wlan_ethhdr_t); + } + /* TODO: can we just let acx DMA payload from skb instead? */ + memcpy((u8*)txbuf + header_len, skb->data + sizeof(wlan_ethhdr_t), payload_len); + payload_len += header_len; + result = payload_len; + + /* Set up the 802.11 header */ + switch (priv->mode) { + case ACX_MODE_0_ADHOC: + fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi); + a1 = e_hdr->daddr; + a3 = priv->bssid; + break; + case ACX_MODE_2_STA: + fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_TODSi); + a1 = priv->bssid; + a3 = e_hdr->daddr; + break; + case ACX_MODE_3_AP: + fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_FROMDSi); + a1 = e_hdr->daddr; + a3 = e_hdr->saddr; + break; + default: + printk("%s: error - converting eth to wlan in unknown mode\n", + priv->netdev->name); + result = -1; + goto end; + } + if (priv->wep_enabled) + SET_BIT(fc, WF_FC_ISWEPi); + + w_hdr->fc = fc; + w_hdr->dur = 0; + MAC_COPY(w_hdr->a1, a1); + MAC_COPY(w_hdr->a2, priv->dev_addr); + MAC_COPY(w_hdr->a3, a3); + w_hdr->seq = 0; + +#if DEBUG_CONVERT + if (acx_debug & L_DATA) { + printk("original eth frame [%d]: ", skb->len); + acx_dump_bytes(skb->data, skb->len); + printk("802.11 frame [%d]: ", payload_len); + acx_dump_bytes(w_hdr, payload_len); + } +#endif + +end: + FN_EXIT1(result); + return result; +} + + +/*---------------------------------------------------------------- +* acx_rxbuf_to_ether +* +* Uses the contents of a received 802.11 frame to build an ether +* frame. +* +* This function extracts the src and dest address from the 802.11 +* frame to use in the construction of the eth frame. +* +* Based largely on p80211conv.c of the linux-wlan-ng project +*----------------------------------------------------------------*/ +struct sk_buff* +acx_rxbuf_to_ether(wlandevice_t *priv, rxbuffer_t *rxbuf) +{ + struct wlan_hdr *w_hdr; + struct wlan_ethhdr *e_hdr; + struct wlan_llc *e_llc; + struct wlan_snap *e_snap; + struct sk_buff *skb; + const u8 *daddr; + const u8 *saddr; + const u8 *e_payload; + int buflen; + int payload_length; + unsigned int payload_offset; + u16 fc; + + FN_ENTER; + + /* This looks complex because it must handle possible + ** phy header in rxbuff */ + w_hdr = acx_get_wlan_hdr(priv, rxbuf); + payload_offset = WLAN_HDR_A3_LEN; /* it is relative to w_hdr */ + payload_length = RXBUF_BYTES_USED(rxbuf) /* entire rxbuff... */ + - ((u8*)w_hdr - (u8*)rxbuf) /* minus space before 802.11 frame */ + - WLAN_HDR_A3_LEN; /* minus 802.11 header */ + + /* setup some vars for convenience */ + fc = w_hdr->fc; + switch (WF_FC_FROMTODSi & fc) { + case 0: + daddr = w_hdr->a1; + saddr = w_hdr->a2; + break; + case WF_FC_FROMDSi: + daddr = w_hdr->a1; + saddr = w_hdr->a3; + break; + case WF_FC_TODSi: + daddr = w_hdr->a3; + saddr = w_hdr->a2; + break; + default: /* WF_FC_FROMTODSi */ + payload_offset += (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN); + payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN); + if (unlikely(0 > payload_length)) { + acxlog(L_DEBUG, "A4 frame too short!\n"); + goto ret_null; + } + daddr = w_hdr->a3; + saddr = w_hdr->a4; + } + + if ((WF_FC_ISWEPi & fc) && (CHIPTYPE_ACX100 == priv->chip_type)) { + /* chop off the IV+ICV WEP header and footer */ + acxlog(L_DATA | L_DEBUG, "rx: WEP packet, " + "chopping off IV and ICV\n"); + payload_length -= 8; + payload_offset += 4; + } + + e_hdr = (wlan_ethhdr_t*) ((u8*) w_hdr + payload_offset); + + e_llc = (wlan_llc_t*) e_hdr; + e_snap = (wlan_snap_t*) (e_llc+1); + e_payload = (u8*) (e_snap+1); + + acxlog(L_DATA, "rx: payload_offset %d, payload_length %d\n", + payload_offset, payload_length); + acxlog(L_XFER | L_DATA, + "rx: frame info: llc.dsap %X, llc.ssap %X, llc.ctl %X, " + "snap.oui %02X%02X%02X, snap.type %X\n", + e_llc->dsap, e_llc->ssap, + e_llc->ctl, e_snap->oui[0], + e_snap->oui[1], e_snap->oui[2], + e_snap->type); + + /* Test for the various encodings */ + if ((payload_length >= sizeof(wlan_ethhdr_t)) + && ((e_llc->dsap != 0xaa) || (e_llc->ssap != 0xaa)) + && ( (mac_is_equal(daddr, e_hdr->daddr)) + || (mac_is_equal(saddr, e_hdr->saddr)) + ) + ) { + acxlog(L_DEBUG | L_DATA, "rx: 802.3 ENCAP len: %d\n", payload_length); + /* 802.3 Encapsulated */ + /* Test for an overlength frame */ + + if (unlikely(payload_length > WLAN_MAX_ETHFRM_LEN)) { + /* A bogus length ethfrm has been encap'd. */ + /* Is someone trying an oflow attack? */ + printk("%s: rx: ENCAP frame too large (%d > %d)\n", + priv->netdev->name, payload_length, WLAN_MAX_ETHFRM_LEN); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length; + /* FIXME: implement skb ring buffer similar to + * xircom_tulip_cb.c? */ + /* Attempt to align IP header (14 bytes eth header + 2 = 16) */ + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* now copy the data from the 80211 frame */ + memcpy(skb->data, e_hdr, payload_length); /* copy the data */ + + } else if ( (payload_length >= sizeof(wlan_llc_t)+sizeof(wlan_snap_t)) + && llc_is_snap(e_llc) ) { + /* it's a SNAP */ + + if ( !oui_is_rfc1042(e_snap) + || (proto_is_stt(ieee2host16(e_snap->type)) /* && (ethconv == WLAN_ETHCONV_8021h) */)) { + acxlog(L_DEBUG | L_DATA, "rx: SNAP+RFC1042 len: %d\n", payload_length); + /* it's a SNAP + RFC1042 frame && protocol is in STT */ + /* build 802.3 + RFC1042 */ + + /* Test for an overlength frame */ + if (unlikely(payload_length + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN)) { + /* A bogus length ethfrm has been sent. */ + /* Is someone trying an oflow attack? */ + printk("%s: rx: SNAP frame too large (%d > %d)\n", + priv->netdev->name, + payload_length, WLAN_MAX_ETHFRM_LEN); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length + WLAN_ETHHDR_LEN; + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* create 802.3 header */ + e_hdr = (wlan_ethhdr_t*) skb->data; + MAC_COPY(e_hdr->daddr, daddr); + MAC_COPY(e_hdr->saddr, saddr); + e_hdr->type = htons(payload_length); + + /* Now copy the data from the 80211 frame. + Make room in front for the eth header, and keep the + llc and snap from the 802.11 payload */ + memcpy(skb->data + WLAN_ETHHDR_LEN, + e_llc, + payload_length); + + } else { + acxlog(L_DEBUG | L_DATA, "rx: 802.1h/RFC1042 len: %d\n", + payload_length); + /* it's an 802.1h frame (an RFC1042 && protocol is not in STT) */ + /* build a DIXII + RFC894 */ + + /* Test for an overlength frame */ + if (unlikely(payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t) + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN)) { + /* A bogus length ethfrm has been sent. */ + /* Is someone trying an oflow attack? */ + printk("%s: rx: DIXII frame too large (%d > %d)\n", + priv->netdev->name, + (int)(payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t)), + WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length + WLAN_ETHHDR_LEN + - sizeof(wlan_llc_t) - sizeof(wlan_snap_t); + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* create 802.3 header */ + e_hdr = (wlan_ethhdr_t *) skb->data; + MAC_COPY(e_hdr->daddr, daddr); + MAC_COPY(e_hdr->saddr, saddr); + e_hdr->type = e_snap->type; + + /* Now copy the data from the 80211 frame. + Make room in front for the eth header, and cut off the + llc and snap from the 802.11 payload */ + memcpy(skb->data + WLAN_ETHHDR_LEN, e_payload, + payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t)); + } + + } else { + acxlog(L_DEBUG | L_DATA, "rx: NON-ENCAP len: %d\n", payload_length); + /* any NON-ENCAP */ + /* it's a generic 80211+LLC or IPX 'Raw 802.3' */ + /* build an 802.3 frame */ + /* allocate space and setup hostbuf */ + + /* Test for an overlength frame */ + if (unlikely(payload_length + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN)) { + /* A bogus length ethfrm has been sent. */ + /* Is someone trying an oflow attack? */ + printk("%s: rx: OTHER frame too large (%d > %d)\n", + priv->netdev->name, payload_length, + WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length + WLAN_ETHHDR_LEN; + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* set up the 802.3 header */ + e_hdr = (wlan_ethhdr_t *) skb->data; + MAC_COPY(e_hdr->daddr, daddr); + MAC_COPY(e_hdr->saddr, saddr); + e_hdr->type = htons(payload_length); + + /* now copy the data from the 80211 frame */ + memcpy(skb->data + WLAN_ETHHDR_LEN, e_llc, payload_length); + } + + skb->dev = priv->netdev; + skb->protocol = eth_type_trans(skb, priv->netdev); + +#if 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)); + printk("eth frame [%d]: ", skb->len); + acx_dump_bytes(skb->data, skb->len); + } +#endif + + FN_EXIT0; + return skb; + +no_skb: + printk("%s: rx: no memory for skb (%d bytes)\n", + priv->netdev->name, buflen + 2); +ret_null: + FN_EXIT1((int)NULL); + return NULL; +} diff -puN /dev/null drivers/net/wireless/tiacx/helper2.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/net/wireless/tiacx/helper2.c 2005-09-07 20:10:30.000000000 -0700 @@ -0,0 +1,2422 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if WIRELESS_EXT >= 13 +#include +#endif /* WE >= 13 */ + +#include "acx.h" + + +/*********************************************************************** +*/ +static client_t *acx_l_sta_list_alloc(wlandevice_t *priv); +static client_t *acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address); + +static int acx_l_process_data_frame_master(wlandevice_t *priv, rxbuffer_t *rxbuf); +static int acx_l_process_data_frame_client(wlandevice_t *priv, rxbuffer_t *rxbuf); +/* static int acx_l_process_NULL_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala); */ +static int acx_l_process_mgmt_frame(wlandevice_t *priv, rxbuffer_t *rxbuf); +static void acx_l_process_disassoc_from_sta(wlandevice_t *priv, const wlan_fr_disassoc_t *req); +static void acx_l_process_disassoc_from_ap(wlandevice_t *priv, const wlan_fr_disassoc_t *req); +static void acx_l_process_deauth_from_sta(wlandevice_t *priv, const wlan_fr_deauthen_t *req); +static void acx_l_process_deauth_from_ap(wlandevice_t *priv, const wlan_fr_deauthen_t *req); +static int acx_l_process_probe_response(wlandevice_t *priv, wlan_fr_proberesp_t *req, const rxbuffer_t *rxbuf); +static int acx_l_process_assocresp(wlandevice_t *priv, const wlan_fr_assocresp_t *req); +static int acx_l_process_reassocresp(wlandevice_t *priv, const wlan_fr_reassocresp_t *req); +static int acx_l_process_authen(wlandevice_t *priv, const wlan_fr_authen_t *req); +static int acx_l_transmit_assocresp(wlandevice_t *priv, const wlan_fr_assocreq_t *req); +static int acx_l_transmit_reassocresp(wlandevice_t *priv, const wlan_fr_reassocreq_t *req); +static int acx_l_transmit_deauthen(wlandevice_t *priv, const u8 *addr, u16 reason); +static int acx_l_transmit_authen1(wlandevice_t *priv); +static int acx_l_transmit_authen2(wlandevice_t *priv, const wlan_fr_authen_t *req, client_t *clt); +static int acx_l_transmit_authen3(wlandevice_t *priv, const wlan_fr_authen_t *req); +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); + + +/*********************************************************************** +*/ +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]; +} + + +/*---------------------------------------------------------------- +* acx_l_sta_list_init +*----------------------------------------------------------------*/ +void +acx_l_sta_list_init(wlandevice_t *priv) +{ + FN_ENTER; + memset(priv->sta_hash_tab, 0, sizeof(priv->sta_hash_tab)); + memset(priv->sta_list, 0, sizeof(priv->sta_list)); + FN_EXIT0; +} + + +/*---------------------------------------------------------------- +* acx_l_sta_list_get_from_hash +*----------------------------------------------------------------*/ +static inline client_t* +acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address) +{ + return priv->sta_hash_tab[address[5] % VEC_SIZE(priv->sta_hash_tab)]; +} + + +/*---------------------------------------------------------------- +* acx_l_sta_list_get +*----------------------------------------------------------------*/ +client_t* +acx_l_sta_list_get(wlandevice_t *priv, const u8 *address) +{ + 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; + } + FN_EXIT0; + return client; +} + + +/*---------------------------------------------------------------- +* acx_l_sta_list_del +*----------------------------------------------------------------*/ +void +acx_l_sta_list_del(wlandevice_t *priv, client_t *victim) +{ + client_t *client, *next; + + 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_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; + + 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]; + + 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; +} + + +/*---------------------------------------------------------------- +* 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 + +static client_t* +acx_l_sta_list_add(wlandevice_t *priv, const u8 *address) +{ + client_t *client; + int index; + + FN_ENTER; + + client = acx_l_sta_list_alloc(priv); + + 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); + + index = address[5] % VEC_SIZE(priv->sta_hash_tab); + client->next = priv->sta_hash_tab[index]; + priv->sta_hash_tab[index] = client; + + acxlog_mac(L_ASSOC, "sta_list_add: sta=", address, "\n"); + + 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) +{ + client_t *client = acx_l_sta_list_get(priv, address); + if (!client) + client = acx_l_sta_list_add(priv, address); + return client; +} + + +/*---------------------------------------------------------------- +* acx_set_status +* +* This function is called in many atomic regions, must not sleep +*----------------------------------------------------------------*/ +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; + + FN_ENTER; + + acxlog(L_ASSOC, "%s(%d):%s\n", + __func__, new_status, acx_get_status_name(new_status)); + +#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); + + 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; + + /* 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 + + 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; + } + +#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"); + } + } +#endif + FN_EXIT0; +} + + +/*------------------------------------------------------------------------------ + * 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; + + acx_lock(priv, flags); + + acxlog(L_DEBUG|L_ASSOC, "%s: priv->status=%d (%s)\n", + __func__, priv->status, acx_get_status_name(priv->status)); + + 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; + } + + acx_unlock(priv, flags); + + FN_EXIT0; +} + + +/*------------------------------------------------------------------------------ + * acx_set_timer + * + * Sets the 802.11 state management timer's timeout. + *----------------------------------------------------------------------------*/ +void +acx_set_timer(wlandevice_t *priv, u32 timeout) +{ + FN_ENTER; + + 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; + } + + /* 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)); + } +end: + FN_EXIT0; +} + + +/*------------------------------------------------------------------------------ + * acx_l_rx_ieee802_11_frame + * + * Called from IRQ context only + * STATUS: FINISHED, UNVERIFIED. + *----------------------------------------------------------------------------*/ +int +acx_l_rx_ieee802_11_frame(wlandevice_t *priv, rxbuffer_t *rxbuf) +{ + unsigned int ftype, fstype; + const wlan_hdr_t *hdr; + int result = NOT_OK; + + FN_ENTER; + + hdr = acx_get_wlan_hdr(priv, rxbuf); + + /* 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; + } + + ftype = hdr->fc & WF_FC_FTYPEi; + fstype = hdr->fc & WF_FC_FSTYPEi; + + 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? */ + + /* 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_proce