[kernel] r10061 - in dists/trunk/linux-2.6/debian: . config patches/features patches/series

Maximilian Attems maks at alioth.debian.org
Sun Jan 6 23:52:40 UTC 2008


Author: maks
Date: Sun Jan  6 23:52:40 2008
New Revision: 10061

Log:
Add and enable ath5k.patch wireless driver for Atheros 5xxx cards.

tested by Stephen Gran <sgran at debian.org>


Added:
   dists/trunk/linux-2.6/debian/patches/features/ath5k.patch
Modified:
   dists/trunk/linux-2.6/debian/changelog
   dists/trunk/linux-2.6/debian/config/config
   dists/trunk/linux-2.6/debian/patches/series/1~experimental.1

Modified: dists/trunk/linux-2.6/debian/changelog
==============================================================================
--- dists/trunk/linux-2.6/debian/changelog	(original)
+++ dists/trunk/linux-2.6/debian/changelog	Sun Jan  6 23:52:40 2008
@@ -31,6 +31,7 @@
   * [amd64, i386] Enable CPU_IDLE for software-controlled idle pm.
   * [amd64, i386] Enable IT8712F_WDT, FB_EFI.
   * Add and enable at76.patch wireless driver for Atmel USB cards.
+  * Add and enable ath5k.patch wireless driver for Atheros 5xxx cards.
 
   [ Bastian Blank ]
   * [amd64, i386]: Set kernel architecture to x86.
@@ -51,7 +52,7 @@
   [ Frederik Schüler ]
   * Add GFS2 locking symbols export patch.
 
- -- maximilian attems <maks at debian.org>  Mon, 07 Jan 2008 00:46:11 +0100
+ -- maximilian attems <maks at debian.org>  Mon, 07 Jan 2008 00:49:41 +0100
 
 linux-2.6 (2.6.23-1~experimental.1) UNRELEASED; urgency=low
 

Modified: dists/trunk/linux-2.6/debian/config/config
==============================================================================
--- dists/trunk/linux-2.6/debian/config/config	(original)
+++ dists/trunk/linux-2.6/debian/config/config	Sun Jan  6 23:52:40 2008
@@ -939,6 +939,7 @@
 CONFIG_P54_USB=m
 CONFIG_P54_PCI=m
 CONFIG_USB_ATMEL=m
+CONFIG_ATH5K=m
 CONFIG_IWLWIFI=y
 # CONFIG_IWLWIFI_DEBUG is not set
 CONFIG_IWLWIFI_SENSITIVITY=y

Added: dists/trunk/linux-2.6/debian/patches/features/ath5k.patch
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/ath5k.patch	Sun Jan  6 23:52:40 2008
@@ -0,0 +1,17466 @@
+commit a09d1e8fd6aaea60578d2cee852ec476da3e6b66
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 03:11:48 2007 +0200
+
+    ath5k: Minor cleanups
+    
+    * Call set_txpower_limit directly
+    * Remove "partialy supported" mesage
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit b46b4130750fd0e37c677a12382ec679845b07ff
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 03:10:27 2007 +0200
+
+    ath5k: Update initvals.c from recent regdumps
+    
+    * Update initvals.c from recent regdumps.
+    * RF5413 and later have a different base address for pcdac table so update reg.h.
+    * Remove static pcdac tables, we'll come up with a better solution (works for me).
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 8d91d68029b494bbcc242633e5ce3fcfbcf10f0a
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 03:07:33 2007 +0200
+
+    ath5k: Fix support for RF2112A based b/g only cards
+    
+    * Fix support for 2112A based b/g only cards (turbog needs review).
+    * Enable a part of rf5112_rfregs code that commits x_gain for testing.
+    
+    Thanx to John who gave me his b/g card ;-)
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 3077d9ecc53b14d946cedd87317a5163e2a66dc9
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 03:03:01 2007 +0200
+
+    ath5k: Skip non-data queues for 5210 for now
+    
+    * Skip non-data tx queues on 5210, don't return -EINVAL since it breaks ifup. This is a temp mesure until we review tx queues etc in base.c. Note that 5210 will wake up and may even scan but needs some more work.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 528f1b9fa5d46d35ee076ec41860a74fb4d0a801
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 03:01:04 2007 +0200
+
+    ath5k: Reorder reset function to match regdumps
+    
+    * Modify reset function to match regdumps, we still have some things to fix.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 41cb0aa95ce0fcade56d267f3804284092360d24
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 02:58:57 2007 +0200
+
+    ath5k: Implement per-queue interrupts
+    
+    * Implement per-queue interrupt handling. For now treat TXDESC and TXEOL as INT_TX so we can handle them in base.c.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 8fb46b91e6ed72ccfefa6c3f4850b9b58c1463d1
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 02:55:52 2007 +0200
+
+    ath5k: Fix diversity
+    
+    * Fix diversity support
+    
+    We have to write all antenna information on AR5K_PHY_ANT_SWITCH_TABLE if antenna mode is not fixed.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit b6aa459673f61c1288acebec013905a7256f3a5a
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 02:53:18 2007 +0200
+
+    ath5k: Fix nic_wakeup for 5210
+    
+    * Reset PCI after chip reset for 5210 at nic_wakeup. This fixes the system hang during 5210 attach.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit a7da8f9d4b256c6014edfe63079c4220e9430e68
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Dec 16 02:47:55 2007 +0200
+
+    ath5k: Minor fixes inside base.c
+    
+    * Reorder some inline functions to silence compiler
+    * Stop passing 0xff.. for txpower during tx descriptor setup. Txpower is written in hw in 0.5dbm steps.
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 8e685b758aea2c0e82f41813690e229543af9622
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Fri Dec 14 18:48:57 2007 +0900
+
+    ath5k: avoid zero rates
+    
+    setting up tx descriptors with a rate of zero will put the HW into a mode where
+    it continously sends noise on the channel, thus blocking the whole channel.
+    since it is important to avoid this situation, add a WARN_ON in these cases,
+    even if we hope to never get bad rates from the rate control module.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit fc0374171b9f750790b88b795aac3becf4524a92
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Mon Dec 10 19:21:17 2007 +0900
+
+    ath5k: add debugfs entries for registers, tsf, beacon, reset
+    
+    i resend this patch to address jiris comments and with some small improvements.
+    this hopefully last version now returns NULL instead of 0 in reg_start() and
+    reg_next().
+    
+    'registers' prints the name and value of some registers. this should be adapted
+    to what we actually need later and is supposed to replace the hwdump facility i
+    removed in my earlier debugging changes.
+    
+    'tsf' prints the current HW TSF. writing "reset" into the file will reset the
+    TSF.
+    
+    'beacon' shows beacon relevant registers.  it is good for watching the beacon
+    timers with something like "watch -n0 cat /dbg/ath5k/phy0/beacon". writing
+    "enable" into the file will try to enable beacons by setting the flag
+    AR5K_BEACON_ENABLE, "disable" will disable that bit.
+    
+    'reset' can be used to trigger a HW reset, by writing "reset" into it.
+    
+    Changes-licensed-under: GPL
+    
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Acked-by: Luis R. Rodriguez <mgrof at winlab.rutgers.edu>
+    Acked-by: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 73a8222564a86bf9e38470dbfe44a4826c5d3a0a
+Author: Dave Young <hidave.darkstar at gmail.com>
+Date:   Fri Dec 7 10:12:58 2007 +0800
+
+    ath5k: fix 'static inline' build issues
+    
+    2.6.24-rc4-mm1 build failed at drivers/net/wireless/ath5k/base.c for some inline functions like this:
+    drivers/net/wireless/ath5k/base.c:292: sorry, unimplemented: inlining failed in call to 'ath5k_extend_tsf': function body not available
+    
+    fix it with adjust the order of inline function body.
+    
+    Signed-off-by: Dave Young <hidave.darkstar at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 1a54daf7f3963bd1c04cc28500f48280d6c8dcf3
+Author: Francesco Gringoli <francesco.gringoli at ing.unibs.it>
+Date:   Thu Nov 29 21:39:51 2007 +0100
+
+    ath5k: fix rx filters set up
+    
+    Hello,
+    
+    This simple patch adds pcap compatibility to ath5k code. In base.c
+    rx_filters are never refreshed when the state of the interface
+    changes. Now tcpdump captures everything in monitor mode when iface
+    is set to promisc.
+    
+    Signed-off-by: Francesco Gringoli <francesco.gringoli at ing.unibs.it>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 04f840943842a4870fd1ddd735140dd0ba73f984
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Fri Nov 30 11:26:37 2007 +0900
+
+    ath5k: export signal quality values
+    
+    store the last noise floor in ath5k_hw and report signal, noise and link
+    quality values to mac80211, which in turn makes them show up in iwconfig.
+    
+    ath5k.h, phy.c:
+    Changes-licensed-under: ISC
+    
+    base.c:
+    Changes-licensed-under: 3-clause-BSD
+    
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Acked-by: Nick Kossifidis <mickflemm at gmail.com>
+    Acked-by: Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 8003ffec8e1dca7224fd9e2a8adf8e887197c32c
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Fri Nov 30 11:26:36 2007 +0900
+
+    ath5k: full noise calibration also for rf511x
+    
+    also perform full noise calibration in ath5k_hw_rf511x_calibrate() instead of
+    just writing the bit.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Acked-by: Nick Kossifidis <mickflemm at gmail.com>
+    Acked-by: Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 335223282459681668ebb0247530020e777d84f5
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Fri Nov 30 11:26:35 2007 +0900
+
+    ath5k: fix noise floor calibration
+    
+    fix noise floor calibration by applying AR5K_PHY_NF_AVAL after
+    AR5K_PHY_NF_RVAL.  that way the XORed mask and value have the same length and
+    we get a reasonable noise value in -dBm.
+    
+    move duplicate noise floor calibration code from two different places into one
+    function ath5k_hw_noise_floor_calibration().
+    
+    the check for accepted noise_floor values (<= AR5K_TUNE_NOISE_FLOOR) should
+    only happen when we have an active reading and a converted value, so move it up
+    into the first if.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Acked-by: Nick Kossifidis <mickflemm at gmail.com>
+    Acked-by: Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 93be8761d08247a45a095b4d9ebdf16ba0c66b68
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Fri Nov 30 11:26:34 2007 +0900
+
+    ath5k: more consistent debugging
+    
+    * move all debugging functions to new files debug.c and debug.h.
+    
+    * consistently use ATH5K_DEBUG instead of AR_DEBUG and AR5K_DEBUG defines.
+    ATH5K_DEBUG can be set from outside the Makefile via KCFLAGS.
+    
+    * rename DPRINTF to ATH5K_DBG to be consistent with the other logging
+    functions.  ATH5K_DBG honors the debug level set on module load or by debugfs
+    and is limited by net_ratelimit().  another define ATH5K_DBG_UNLIMIT can be
+    used specifically when we do not want the output to be rate limited.
+    
+    * move all instances where the debugging output was controlled by additional
+    defines (ATH_DEBUG_MODES, ATH_DUMP_SKB) to use the debug level too.
+    
+    * make ATH5K_TRACE honor the debug level as well.
+    
+    * remove ath5k_hw_dump_state().
+    
+    * rename all debugging functions to ath5k_debug_xxx. these are static inline {}
+    when ATH5K_DEBUG is 0.
+    
+    * make ath5k_debug_dump_skb distinguish between RX and TX, so we can choose
+    wether we want to see RX or TX packets. also prepend the "phyX" name.
+    
+    * added debugfs entry (ath5k/phyX/debug) to control the debug level for each
+    device.
+    
+    * add kerneldoc for debugging levels.
+    
+    base.[ch]:
+    Changes-licensed-under: 3-clause-BSD
+    
+    hw.c, ath5k.h, phy.c:
+    Changes-licensed-under: ISC
+    
+    debug.[ch]:
+    Changes-licensed-under: GPL
+    
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Acked-by: Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
+    Acked-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 07700ba6c1fe652f0c0b9ad5b9d6525664740cf4
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Fri Nov 30 11:26:33 2007 +0900
+
+    ath5k: more consistent info and error logging
+    
+    added new macros ATH5K_INFO, ATH5K_WARN and ATH5K_ERR for more consistent
+    logging inside ath5k. they prepend "ath5k phyX:" to all lines so we can
+    distinguish between different cards in multi-card setups. ATH5K_WARN and
+    ATH5K_ERR use net_ratelimit(), so they can be used anywhere without having to
+    check net_ratelimit() seperately.
+    
+    the macros get a reference to sc, so we can automatically add additional
+    information: right now it is used to get the phy name, but having this in one
+    central place gived us the flexibility to switch to dev_info/warn/... or others
+    instead too. i think using "phyX" makes the output most readable and easier to
+    match with the output from mac80211. in cases where we don't have sc available
+    we still use ATH5K_PRINTF.
+    
+    changed all printk, most dev_info and most AR5K_PRINTF lines to use these
+    macros instead. deleted AR5K_PRINT because it's easy to use ATH5K_PRINTF
+    instead.
+    
+    for base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    for all others...
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Acked-by: Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
+    Acked-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit fd5be00a58244ffd045c5b5fa1eb4e2279d8c5b3
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Wed Nov 14 19:49:49 2007 +0200
+
+    ath5k: Add myself to MAINTAINERS and rewrite module description on Kconfig
+    
+    *Add better description in Kconfig
+    *Add myself to MAINTAINERS
+    
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit e856715ffedc6b73c546d5f472e4cd876703091d
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Wed Nov 14 18:23:59 2007 +0200
+
+    ath5k: Fix calinterval and add more RF5413/5414 inivals
+    
+    *Fix calinterval to be 10secs for now.
+    *Add some more initial settings i got for RF5413/5414
+    
+    Still no fix for poor 802.11a performance (probably tx power related) ;-(
+    Leave it as "partialy supported" until this issue is resolved...
+    
+    for base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    for all others...
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 838904d60eeab7d4206451a5503d80a0ef8a2884
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Wed Nov 14 18:17:37 2007 +0200
+
+    ath5k: Add RF5413/5414 support
+    
+    *Add support for RF5413/5414 single-chip solutions
+    
+    This needs testing (also on 5424/2424) before we declare that's fully supported.
+    It works for me and the RF5413 i got ;-)
+    
+    Changes-licensed-under: ISC
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 93e5669cf00f5323f65303c4ef096e0c8919d292
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Wed Nov 14 18:14:40 2007 +0200
+
+    ath5k: Fix device info reporting
+    
+    *Fix device info code
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 41bf49ef5be651dfe06e597389a0237ce5298d20
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Wed Nov 14 18:11:40 2007 +0200
+
+    ath5k: Fix another faulty channel flag check
+    
+    *Fix another faulty channel flags check
+    
+    Don't check channel->val against CHANNEL_A/B/G flags because they have common flags set
+    eg. doing AND between CHANNEL_A and CHANNEL_G always returns true because they have
+    CHANNEL_OFDM, same goes for CHANNEL_B and CHANNEL_G that have CHANNEL_2GHZ in common.
+    
+    Instead check against CHANNEL_CCK/OFDM/2GHZ/5GHZ...
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 1ce29f8277f8d9e44995f81e5986361fbdd87615
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Fri Nov 2 16:46:38 2007 -0400
+
+    ath5k: Set ACK to user lower bit rates
+    
+    Sorry, forgot this last hunk in my patch series... This applies on top
+    of my series.
+    
+    This sets the ACK bitrate to the lower rates. Without this I get
+    about 70% packet loss when using the 11M rate. Not sure exactly what rates
+    this is setting the HW to send the ACKs in but it sure does help.
+    
+    I'll be poking more with this and trying to fix rates for g. We'll figure
+    this out ;)
+    
+    Note: our higher rates are still pretty unusable, something is still
+    wrong with those.
+    
+    Changes to base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to ath5k.h, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 01584d2b0e88eea833c378d4da292f8a7e2a4a49
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Nov 1 23:11:31 2007 -0400
+
+    ath5k: Add documentation for struct ath5k_rate
+    
+    This adds documentation for struct ath5k_rate. This also removes
+    some unused variables, lp_ack_duration and sp_ack_duration which
+    are simply unnecessary.
+    
+    We're now just missing information about rate hw values:
+    
+    3-5
+    16
+    17-23
+    28-32
+    
+    If anyone knows what those are, please let us know.
+    
+    Changes to ath5k.h
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 2e046652afab548b98ceee3043173e17cf7f7145
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Nov 1 17:55:53 2007 -0400
+
+    ath5k: Clear up settings of AR5K_RSSI_THR register settings
+    
+    Clear up settings of AR5K_RSSI_THR register settings. These are split between
+    AR5K_TUNE_BMISS_THRES and AR5K_TUNE_RSSI_THRES.
+    
+    Changes to ath5k.h, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 9b83892f2c0a16f087dc45d7b8a6353c69c0fcfb
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Nov 1 17:53:18 2007 -0400
+
+    ath5k: Move OFDM timings into a helper routine
+    
+    This move the OFDM timings on ath5k_hw_reset() onto a helper,
+    ath5k_hw_write_ofdm_timings() to make code cleaner.
+    
+    Changes to ath5k.h, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit f75a5a95a1fc5287143afbeb99c0e238ef4cbd79
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Nov 1 00:38:16 2007 -0400
+
+    ath5k: Fix clock on OFDM timing computation
+    
+    We were setting the clock to the turbo sampling rate always, lets fix this
+    for plain OFDM sampling rate at 40 MHz. I believe this tunes the PLL to
+    the desired frequency, by setting the mantissa and the exponent.
+    
+    Changes to hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 6f95039ebee8f0d79b940f06bcde1e0711334a83
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Nov 1 17:50:30 2007 -0400
+
+    ath5k: Clean up ath5k rate duration settings
+    
+    Replace ath5k's rate duration computations for one using
+    mac80211's internals. Another consideration here is to simply
+    remove these and put them into initval values. They seem to be
+    static values based only on mode. We can do this later though once
+    we can physically confirm by trial and error these are indeed just
+    used for ACK timeout. The next puzzle is figuring out which registers
+    are actually setting the control rates.
+    
+    Changes to ath5k.h, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 012198ddffdb66120528823c73318379b6a59a77
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Nov 1 00:35:20 2007 -0400
+
+    ath5k: Remove opaque pointers from ath5k_hw_attach()
+    
+    Since we don't have a HAL anymore there is no point to use opaque pointers
+    in ath5k_hw_attach(). This will also give hw.c access to ath5k_softc
+    structure now when needed. While we're at it, lets also give some ah_sh
+    a reasonable name, ah_sh --> ah_iobase.
+    
+    Changes to base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to ath5k.h, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit e23be3f08baf10d7ded7eab076b68dc6696d230e
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Nov 1 00:34:24 2007 -0400
+
+    ath5k: Fix initval/eeprom/IQ calibration for G mode
+    
+    ath5k_hw_reset() was always setting initval and eeprom settings for B mode
+    when using G mode. This is because a B channel was being picked up first. We
+    should first instead check for G channel. This patch also introduces a
+    driver_mode variable which should be used instead for determing
+    more reliably the mode we're in.
+    
+    This fixing another bug where IQ calibration was not being run for
+    G mode as CHANNEL_B was always being picked up first. We now instead
+    check for driver_mode.
+    
+    Similar problem was occurring in ath5k_hw_rf5112_rfregs(), we fix this
+    there too.
+    
+    Changes to phy.c, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 45cededd2df27b8c2a4b7c37a02c7f3830d1d243
+Author: Ulrich Meis <meis at nets.rwth-aachen.de>
+Date:   Tue Oct 30 22:20:56 2007 +0100
+
+    ath5k: 4word tx descriptor setup doesn't set BUF_LEN
+    
+    This line got lost when the descriptor setup and fill functions were
+    merged. Applies ontop of Nick's patches.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Ulrich Meis <meis at nets.rwth-aachen.de>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 168048516dbf42ca2deb3cd36101f9b76ecdb030
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:58:27 2007 +0300
+
+    ath5k: Remove fill_tx_desc
+    
+    fill_tx_desc is used for fast frames operation, since
+    we don't support fast frames (and since fill_tx_desc
+    had a bug -thanx to Ulrich Meis for finding that out-)
+    these functions are not needed (+ they are misleading
+    because they don't "fill" any tx descriptor).
+    
+    I couldn't test this patch much so plz someone ACK it...
+    
+    It applies on top of my previous patches (i just thought
+    that [PATCH 8/7] won't look nice ;-) ).
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Ulrich Meis <meis at nets.rwth-aachen.de>
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 7ed69f54e345a9897b0b4617311858303e781aff
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:44:18 2007 +0300
+
+    ath5k: Warn on partially supported chips
+    
+     *Warn on partially supported chips (eg. 5414/5424)
+    
+    These chips need work on PHY part, recently Reyk posted
+    a workaround so that they can work on 2GHz but i believe
+    that the problem is related to PHY initialization. Plz
+    we need help with these...
+    
+    I did some tests on a 5414 at 5GHz and it seemed to work
+    but i didn't test it at 2GHz.
+    
+    I'll try to find one of these and play with.
+    
+    Changes-licensed-under: ISC
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 24d2eab68057de8e63d262e84c0ba3a12a69f0c1
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:31:13 2007 +0300
+
+    ath5k: Add PCI IDs for newer chips
+    
+     *Add PCI IDs for 5416/5418.
+    
+     *Print a message during attach that
+      these chips are not yet supported.
+    
+    for base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    for ath5k.h
+    Changes-licensed-under: ISC
+    
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit d17a1cea1bfc35c735f3ebcf1ef823f06389748d
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:24:59 2007 +0300
+
+    athk: Use SREV to identify single-chip solutions
+    
+    Use SREV instead of pci id to identify single chip solutions.
+    
+    Srev is more accurate info to identify the chip + this makes
+    it possible to identify some 5424 chips found on thinkpads with
+    faulty 5212 pci id.
+    
+    Changes-licensed-under: ISC
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 85364fdd0649d1590e9ae18d1961c6861b7b9288
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:20:33 2007 +0300
+
+    ath5k: Add SREV values for newer chips
+    
+    * Add new Silicon Revision values (hex values written on chip) to be able to identify them.
+    
+    * Give more infos about mac/phy/radio revision during attach.
+    
+    for ath5k.h
+    Changes-licensed-under: ISC
+    
+    for base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 73a0794c3746635652f10bcfe99821b3526163b5
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:13:32 2007 +0300
+
+    ath5k: Remove obsolete sysctl stuff
+    
+    Remove sysctl tables.
+    
+    We shouldn't use /proc to configure things.
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit e05ef94a6f9a5b2c485f552e46e334a2a4d17d85
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:06:42 2007 +0300
+
+    ath5k: Rename some functions
+    
+    I've renamed some functions for better maintainability...
+    
+    ath5k_mode_init -> ath5k_mode_setup
+    ath5k_rxbuf_init -> ath5k_rxbuf_setup
+    Because it's not just initialization + we use
+    "setup" on the rest of the code (eg. beacon_setup).
+    
+    ath5k_tx_bf -> ath5k_txbuf_setup
+    Obvious
+    
+    ath5k_cleanup_txbuf -> ath5k_txbuf_free
+    Previous name is misleading because someone might
+    think that it cleans all tx buffers, we use "free"
+    to declare that it only cleans one given buffer.
+    
+    ath5k_tx_draintxq -> ath5k_txq_drainq
+    ath5k_draintxq -> ath5k_txq_cleanup
+    Same here ath5k_draintxq seems to refer to only
+    one queue when in fact it drains all queues, so
+    we use "cleanup" as above.
+    
+    ath5k_tx_cleanup -> ath5k_txq_release
+    This one doesn't do any cleanup, it just calls
+    hw_release for each queue.
+    
+    ath5k_startrecv -> ath5k_rx_start
+    ath5k_stoprecv -> ath5k_rx_stop
+    As above i try to maintain a naming scheme that links
+    with the sorting i've done. Eg. ath5k_desc for descriptor
+    related funcions, ath5k_rx/tx for general rx/tx functions,
+    ath5k_txq for tx queues, ath5k_hw (inside hw.c and rest) for
+    hw related functions and so on. This helps us track down things
+    more easily.
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 4528852951e6ad64171f584f6b685eb802f6293f
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Sun Oct 28 02:04:25 2007 +0300
+
+    ath5k: Maintain coding style
+    
+    * Sort functions in segments like we do on the rest of the code (eg.
+    hw.c). This improves readability and maintainability.
+    
+    * Add myself as module author (a patch for this was submited some time
+    ago as part of SFLC's changes but wasn't applied)
+    
+    * Declare that this driver is or 5xxx chipset series only in
+    MODULE_SUPPORTED_DEVICE and MODULE_DESCRIPTION.
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 1f480e2920877d373e2a547cf53509fc513e02a9
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Fri Oct 19 18:57:13 2007 -0400
+
+    [PATCH] Net: ath5k, minor fixes
+    
+    ath5k, minor fixes
+    
+    - some -W compiler warnings fixes (signedness)
+    - make ath_stop static
+    - add BUG to ath5k_register_mode when passing supported but not filled mode
+      and move the supported modes check into this function to simplify the
+      macro
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 96a596f082e92fcdf6308b6224104f93e8916394
+Author: John W. Linville <linville at tuxdriver.com>
+Date:   Tue Oct 23 13:41:37 2007 -0400
+
+    [PATCH] ath5k: undo overzealous hunk of "ath5k: avoid oops when..."
+    
+    The first hunk of "ath5k: avoid oops when ah_capabilities.cap_mode not
+    set" was ill-advised.  It can cause its loop to abort prematurely.
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 05a920250b6385c7eb23a94f0532f94dbd4b6160
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Fri Oct 19 23:57:27 2007 +0900
+
+    [PATCH] ath5k: mac revision fixes
+    
+    this are two small fixes:
+    
+    1) actually print the mac revision when we say so
+    
+    2) better check for mac revisions when putting device to sleep: this is
+    important with newer mac revisions (>=7.8) which will freeze the whole system
+    when put to sleep
+    
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 14ca910b99e3dc5a1082e7e7b13a2957ffe44fe0
+Author: Nick Kossifidis <mick at madwifi.org>
+Date:   Fri Oct 19 13:56:19 2007 +0000
+
+    [PATCH] ath5k: Maintain naming scheme
+    
+    Use "ath5k_" instead of "ath_" and "ah" instead of "hal"
+    
+    Changes to base.c, base.h
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to ath5k.h, hw.c, hw.h, reg.h
+    Changes-licensed-under: ISC
+    
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 34edd82ca97a76b921ac52c99f07dbfe324feaae
+Author: mick at ics.forth.gr <mick at ics.forth.gr>
+Date:   Thu Oct 18 00:18:43 2007 +0300
+
+    [PATCH] ath5k: Clean up unused definitions in base.h
+    
+    Get rid of some definitions that are not used anywhere...
+    
+    Changes-licensed-under: 3-clause-BSD
+    
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 4c367a11d4502a6e54fa64514cee61c67be9b411
+Author: mick at ics.forth.gr <mick at ics.forth.gr>
+Date:   Thu Oct 18 00:17:12 2007 +0300
+
+    [PATCH] ath5k: Only one tx descriptor per buffer, no need for ATH_TXDESC
+    
+    Since we don't (and probably won't) support fast frames we'll have
+    only one descriptor for each buffer so there is no need for
+    ATH_TXDESC.
+    
+    Changes-licensed-under: 3-clause-BSD
+    
+    Signed-Off-by: Nick Kossifidis <mickflemm at gmail.com>
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 4472d002f92b4365184acd6d38e4e417afd5b857
+Author: mick at ics.forth.gr <mick at ics.forth.gr>
+Date:   Thu Oct 18 00:13:26 2007 +0300
+
+    [PATCH] ath5k: Get rid of unused channel list parameters used in binary HAL
+    
+    There are some parameters left in the code that were used by binary
+    HAL to generate the channel list. Since we don't use binary HAL and
+    channel list is handled differently, they are out.
+    
+    Changes to base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to ath5k.h, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 9d0d2389d863cc3ef433e5103bd6d37f7a5bc983
+Author: John W. Linville <linville at tuxdriver.com>
+Date:   Wed Oct 17 15:01:48 2007 -0400
+
+    [PATCH] ath5k: avoid oops when ah_capabilities.cap_mode not set
+    
+    ah_capabilities.cap_mode doesn't get set for some cards, causing the
+    kernel to oops when these unknown/unsupported cards are inserted.
+    Add some NULL checks to avoid this.
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 4cdfeb9398897c3969f89a8d32ad7632ead0fc6a
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Tue Oct 16 22:20:37 2007 +0900
+
+    [PATCH] ath5k: better readability for skb dumps
+    
+    print "RX  " and "TX  " in front of hexdump
+    
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Acked-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 75b99ae66c33cfd5664102c2588ebd505577fc7e
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Sun Oct 14 10:45:54 2007 -0400
+
+    [PATCH] Net: ath5k, change set_bit to nonatomic __set_bit
+    
+    ath5k, change set_bit to nonatomic __set_bit
+    
+    We don't need to have atomic set_bit function, so use __set_bit instead.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 2ad8cab5071e6059c7333cac965f2b7e7a3342a5
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Sat Oct 13 16:08:29 2007 -0400
+
+    [PATCH] ath5k: Fix and clean mode initialization, prefer G for AR5212
+    
+    Currently you get locked on B mode with AR5212s. This could be partly
+    mac80211's fault with a recent regression introduced but ath5k mode
+    initialization right now is pretty sloppy. For AR5212s we also currently
+    start scanning in 5GHz. I've made the mode initialization on ath5k a bit
+    clearer and only am registering G mode now instead of both B and G for
+    AR5212s. We now also check eeprom reading for capabilities before registering
+    a specific mode. For AR5212 I get reliable rates only up to 18Mbps for a
+    throughput of up to 5 Mbits/sec. At least now we can work and test the
+    other rates again.
+    
+    Also use a static driver specific NUM_DRIVER_MODES instead of mac80211's
+    NUM_IEEE80211_MODES.
+    
+    This patch has been tested on AR5210, AR5211 and AR5212.
+    
+    Note: mac80211 simple rate algo throws us to 1Mbps after assoc, this is by
+            design. I recommend users to set rate to 11M for now after assoc.
+    
+    Changes to base.[ch]
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to ath5k.h
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 33e9ca7f21695f2f285833cd296f70a2cd345730
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Fri Oct 12 11:07:09 2007 -0400
+
+    [PATCH] Add extensive documenation for the atheros bssid_mask
+    
+    Add extensive documenation for the atheros bssid_mask.
+    Credit to David Kimdon for figuring this out. I am
+    just documenting it.
+    
+    No need to check for ath5k_hw_hasbssidmask() as
+    ath5k_hw_set_bssid_mask() will do the check itself.
+    
+    Also add link to Atheros patent 6677779 B1 about buffer
+    registers and control registers. Hope this helps.
+    
+    Changes to base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to hw.c, reg.h
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 953389189d1790b4346a43309719893400a31fc5
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Fri Oct 12 11:05:43 2007 -0400
+
+    [PATCH] Don't read AR5K_RAC_PISR on AR5210, document ath5k_int
+    
+    AR5210 does not have AR5K_RAC_PISR so do not read it. Also lets start
+    trying to document all hardware interrupts.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 8462b5d694f20a522ba4dfbb153648ba332b5627
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Fri Oct 12 11:04:38 2007 -0400
+
+    [PATCH] Add proper support for multicast
+    
+    There seems to be several ways to enable multicast. We choose right now
+    MadWifi's old implementation. We can later try
+    ath5k_hw_set_mcast_filterindex() as well.
+    
+    ath5k_hw_get_rx_filter() may enable AR5K_RX_FILTER_RADARERR or
+    AR5K_RX_FILTER_PHYERR. We choose to respect only AR5K_RX_FILTER_PHYERR
+    for now because:
+    
+    a. Most radars don't seem to work on 5GHz band now
+    b. Some have reported a lot of unnecessary noise is captured
+       when trying to filter for radar
+    c. When and if someone wants to work on DFS for ath5k later
+       this can be enabled then
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit ad134b6e277058f4ce929fb4903bac8f2ffa2565
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Fri Oct 12 11:03:49 2007 -0400
+
+    [PATCH] ath5k: Fix a bug which pushed us to enable promiscuous
+    
+    Fix a bug which pushed us to enable the promiscuous filter
+    all the time during normal operation. The real problem was caused
+    becuase we were reseting the bssid to the broadcast during
+    ath5k_hw_reset(). We now cache the bssid value and set the
+    bssid again during resets. This gives the driver considerably
+    more stability.
+    
+    Known issue: if your DHCP server doesn't ACK your IP via the broadcast but
+    	instead sends it to the IP it gives you (Cisco seems to do this) you
+    	may not get the reply. Work is in progress to figure this issue out.
+    	This issue was present before this patch.
+    
+    Changes to base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to ath5k.h, hw.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit cc79ada2dc67857c1fd922e16ca3769a302f0b06
+Author: Bruno Randolf <bruno at thinktube.com>
+Date:   Mon Oct 15 21:30:38 2007 +0900
+
+    [PATCH] ath5k: atheros hardware needs header padding
+    
+    handle padding between header and data
+    
+    Atheros hardware requires the header to be padded to 4 byte (32 bit)
+    boundaries. It expects the payload data to start at multiples of 4 byte for TX
+    frames and will add the padding for received frames. For most headers there is
+    no need for padding, since they are multiples of 4 already - except QoS and 4
+    address headers.
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-off-by: Bruno Randolf <bruno at thinktube.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 1c4a64df662171bf85081aea39d155c683966a56
+Author: John W. Linville <linville at tuxdriver.com>
+Date:   Tue Oct 2 19:56:29 2007 -0400
+
+    [PATCH] ath5k: remove reference to ALG_NONE
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit ac82c3d69dca0977ad408153109311faabaa73d3
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Fri Sep 28 11:26:16 2007 -0400
+
+    [PATCH] ath5k: Fix a few typos in copyright
+    
+    This patch fixes a few typos overseen by the introduction of
+    two new files, intvals.c and phy.c. It also adds the missing
+    warranty on base.c and removes the the last CVS tag from base.h
+    
+    Changes to base.[ch]
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to phy.c, initvals.c
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit a1f0e21e5ba549ae9208faf9076b0c807adca7c6
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Sep 27 21:04:19 2007 -0400
+
+    [PATCH] ath5k: add new configure_filter, compile fix on wireless-2.6
+    
+    This patch:
+    
+    * removes the old ath_calcrxfilter() and ath_set_multicast_list()
+    * adds new required required configure_filter() ops, this one
+      just stores the filter value in cache for later use.
+    * introduces a cached sc->filter_flags for hw filter flags
+    * moves the driver to mac80211's new required start()/stop()
+    * initializes at add_interface() sc->bintval to a common value,
+      this will later be updated as per mac80211's preference.
+    * Fix compile bug on ath_set_key() (adds enum for set_key_cmd)
+    
+    We'll later port some driver-specific filter stuff onto mac80211.
+    
+    This has been tested. This patch applies to the wireless-2.6 everything branch,
+    after the new ath5k directory move and file renames.
+    
+    Changes-licensed-under: 3-clause-BSD
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 6a0f742dac6bd0c396eb24c021c6c048f496af6e
+Author: Bradley M. Kuhn <bkuhn at softwarefreedom.org>
+Date:   Thu Sep 27 18:58:24 2007 -0400
+
+    [PATCH] ath5k: final correction of copyright notices
+    
+    The patch below is for application to the wireless-2.6 ath5k branch, and
+    takes into account the latest driver directory move and file renames.  I
+    believe this patch handles all copyright notice issues that SFLC is
+    currently aware of.  Based on our extensive research (which is summarized
+    in http://www.softwarefreedom.org/resources/2007/ath5k-code-analysis.html)
+    we found that the copyright holders below also have a copyright on some
+    files; the patch below adds their copyright notices.
+    
+    We encourage future patchers to add their copyright notice (and any
+    appropriate additional licensing notices as needed) into the files when
+    they make patches.  We also refer developers to our paper at
+    http://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html
+    that recommends ways to incorporate permissive-licensed code like this in
+    a GPL-licensed project like Linux.
+    
+    We at SFLC were all very happy to do this work for the Linux Wireless team
+    and are glad that a favorable outcome for all was reached.
+    
+    I believe I've used all the patch-submission tags correctly based on
+    previous discussions and email exchanges with everyone involved, but I
+    obviously don't patch the kernel often (er, at all :), so if I've made a
+    mistake, please let me know.
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Richard Fontana <fontana at softwarefreedom.org>
+    Signed-off-by: Bradley M. Kuhn <bkuhn at softwarefreedom.org>
+    Signed-off-by: Matt Norwood <norwood at softwarefreedom.org>
+    Signed-off-by: Karen Sandler <karen at softwarefreedom.org>
+    Acked-by: Matthew W. S. Bell  <mentor at madwifi.org>
+    Acked-by: Pavel Roskin <proski at gnu.org>
+    Acked-by: Nick Kossifidis <mickflemm at gmail.com>
+    Acked-by: Jiri Slaby <jirislaby at gmail.com>
+    Acked-by: Luis Rodriguez <mcgrof at winlab.rutgers.edu>
+    Acked-by: Michael Taylor <mike.taylor at apprion.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 4adaee6d7ab1bfd4d9709495a2cb97df4b5afed8
+Author: Andrew Morton <akpm at linux-foundation.org>
+Date:   Thu Sep 20 14:02:31 2007 -0700
+
+    [PATCH] ath5k: Remove pointless empty CVS ID string.
+    
+    Cc: Jeff Garzik <jeff at garzik.org>
+    Cc: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 260dea31422e4c97b88b2f26474eac3b20ee76a4
+Author: Stephen Hemminger <shemminger at linux-foundation.org>
+Date:   Tue Sep 18 10:06:47 2007 -0700
+
+    [PATCH] ath5k: msi support
+    
+    The atheros on my Fujitsu b6210 supports MSI.
+    
+    Signed-off-by: Stephen Hemminger <shemminger at linux-foundation.org>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 6ebc3f5df03a301a173e10dd72b513fe23ecbbce
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Sep 20 17:13:26 2007 -0400
+
+    [PATCH] ath5k - Fix filters for AR5212, correct return values for WEP
+    
+    I was not get getting DHCP replies back with ath5k on a AR5212. Turns
+    out out of all filter flags if I enable AR5K_RX_FILTER_PROM I get my
+    replies back. I've tested enabling AR5K_RX_FILTER_BCAST and
+    AR5K_RX_FILTER_MCAST but AR5K_RX_FILTER_PROM only does the trick. This
+    may fix this for other cards if you are not getting DHCP replies
+    please let us know. For now we can enable AR5K_RX_FILTER_PROM on STA
+    and Ad-hoc only for AR5212 until we sort out the filter flags
+    properly. This patch also takes into account new changes to mac80211
+    for ieee80211_ops's set_key().
+    
+    Filter API changes to come soon.
+    
+    In summary this patch has these changes:
+    
+    * AR5212 now receives broadcasts (DHCP works now)
+    * ath5k_hw_set_key() was checking against key table size against
+    key->keyid -- this can only be 0, 1, 2 or 3. Check against key->keylen
+    and divide the table size by 8.
+    * return proper values for WEP setting as per mac80211 documenation
+    
+    This patch applies to the ath5k branch of wireless-dev.
+    
+    Changes to ath5k_base.c
+    Changes-licensed-under: 3-clause-BSD
+    
+    Changes to ath5k_hw.c, ath5k_reg.h
+    Changes-licensed-under: ISC
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit eae99b799ce2aff97ad9016cac834405678c3d6b
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Wed Sep 26 14:04:10 2007 -0400
+
+    [PATCH] Net: ath5k, remove unused/dead code
+    
+    ath5k, remove unused/dead code
+    
+    Remove ifdeffed code, which is currently (and might not be in the future too)
+    unused. If it was ever really needed, it could be easily ported back from the
+    madwifi-old-openhal repository.
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 9ab409d9f834472b2fdf9705cde52f8b4bc2436e
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Wed Sep 26 14:03:27 2007 -0400
+
+    [PATCH] Net: ath5k, use int as retval
+    
+    ath5k, use int as retval
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 5034f1e5e0610667a77e8ac991255162e5fe9982
+Author: Nick Kossifidis <mickflemm at gmail.com>
+Date:   Wed Sep 26 14:02:50 2007 -0400
+
+    [PATCH] Net: ath5k, split hw into hw, phy and initvals
+    
+    ath5k, split hw into hw, phy and initvals
+    
+    Separate the hw code into logical pieces hw, phy and initvals for better
+    readability and maintainability.
+    
+    This includes suggested file renames (_hw removal).
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Nick Kossifidis <mickflemm at gmail.com>
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit c0a7d16f73da9c33bd71ec8b303bc735f604350c
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Wed Sep 26 14:02:11 2007 -0400
+
+    [PATCH] Net: ath5k, make its own directory
+    
+    ath5k, make its own directory
+    
+    also remove ath5_ prefix from the filenames
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 71b0b4547745b849f1a2535d37e02cff91cb83ad
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Mon Sep 17 17:31:51 2007 -0400
+
+    [PATCH] ath5k: Internalize Atheros Turbo modes
+    
+    This patch:
+    
+    * Internalizes Atheros Turbo modes (MODE_ATHEROS_TURBO,
+    MODE_ATHEROS_TURBOG)
+    
+    * Internatizes Turbo modulation (MODULATION_TURBO)
+    
+    * Adds documention for Atheros Turbo modes (MODE_ATHEROS_TURBO,
+    MODE_ATHEROS_TURBOG), Turbo modulation (MODULATION_TURBO) and XR
+    modulation (MODULATION_XR)
+    
+    Changes-licensed-under: BSD
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit aa03e9134b6aca4522e8f0a772f4509a5cfe4b13
+Author: John W. Linville <linville at tuxdriver.com>
+Date:   Mon Sep 17 17:11:29 2007 -0400
+
+    [PATCH] ath5k: remove HW_KEY_IDX_INVALID
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit a05767ddbfb1138042b5f08c822a54610bd7d437
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Mon Sep 17 00:48:27 2007 -0400
+
+    [PATCH] Correct ath5k Kconfig depends
+    
+    This patch correct's ath5k's Kconfig depends line by making it depend
+    on WLAN_80211 and also for now marks it EXPERIMENTAL. This patch
+    applies to the ath5k branch of wireless-dev.
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit fb31173e6ccfbcadd9d7645a384c9add3ce7be4f
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Mon Sep 17 00:01:09 2007 -0400
+
+    [PATCH] Add Luis to MAINTAINERS for ath5k
+    
+    This patch adds me to the MAINTAINERS entry for ath5k. It applies to
+    the ath5k branch on wireless-dev.
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 5bc68c49c1bdbb92cfcbbea4a57a77b7067350fb
+Author: Krzysztof Halasa <khc at pm.waw.pl>
+Date:   Mon Sep 3 20:35:52 2007 +0200
+
+    [PATCH] Ath5k panic fix
+    
+    Ath5k panics on ath_open() because sc->pdev is never set, fixed.
+    
+    Signed-off-by: Krzysztof Halasa <khc at pm.waw.pl>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 967ee4db879de997e8aadb397317c691480cc9d9
+Author: John W. Linville <linville at tuxdriver.com>
+Date:   Sat Sep 15 11:05:32 2007 -0400
+
+    [PATCH] ath5k: remove use of IEEE80211_HW_WEP_INCLUDE_IV
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 847a9375af07c677f74934e24f779d90bcc9a7c7
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Mon Sep 10 16:00:38 2007 -0400
+
+    [PATCH] ath5k: more license corrections (ath5k_reg.h)
+    
+    This patch corrects the copyright and license on ath5k_reg.h.
+    
+    Specifically, this patch:
+    
+    * Removes the GPL license and restores the ISC license from
+    ath5k_reg.h as Nick indicated.
+    
+    * Adds Reyk's Copyright to ath5k_reg.h
+    
+    Changes-licensed-under: ISC
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 4ac1d5eb15b9f5a31568d06d38326059bacee642
+Author: Luis R. Rodriguez <mcgrof at gmail.com>
+Date:   Thu Sep 6 10:18:22 2007 -0400
+
+    [PATCH] ath5k: correct some license damage
+    
+    The attached patch fixes copyright notice for 3 files which need to be
+    corrected regardless of the outcome of the license of the other files.
+    
+    This patch:
+    
+    * Adds warranty notices back to ath5k_regdom.[ch]
+    
+    * Adds Devicescape Copyright to ath5k_base.c
+    
+    Signed-off-by: Luis R. Rodriguez <mcgrof at gmail.com>
+    Changes-licensed-under: ISC
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 82f2f4094eddd1993b9f2bc0d53f26def57c3fae
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Tue Aug 28 11:59:54 2007 -0400
+
+    [PATCH] Net: ath5k, switch to ioread/iowrite
+    
+    ath5k, switch to ioread/iowrite
+    
+    Do not use readl/writel, since iomap retval is platform dependent and
+    needn't be virtual address awaited by readl/writel.
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit c2877048ec6f854d417e9141bb18cf4ae15f7b33
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Sat Aug 25 03:59:28 2007 -0400
+
+    [PATCH] Net: ath5k, remove some ieee80211 re-defines
+    
+    ath5k, remove some ieee80211 re-defines
+    
+    use mac80211 defines directly instead. this means MODULATION_* to
+    IEEE80211_RATE_* switch.
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: <linville at tuxdriver.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 9d6c3cef55cbbd6f4358d9bd7a59a2b7655eaaa3
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Sat Aug 25 03:58:47 2007 -0400
+
+    [PATCH] Net: ath5k, use short preamble for some rates
+    
+    ath5k, use short preamble for some rates
+    
+    2, 5.5 and 11 in b/g are now in short preamble mode
+    
+    Jiri Slaby wrote:
+    > Johannes Berg wrote:
+    > > umm, mac80211 needs to be able to choose depending on the network.
+    
+    Hmm, misleading log comment. It should be 'can now be in SP mode'.
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: <linville at tuxdriver.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 8695faaeffc78924829afb21fd7602dc3a4d81b9
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Sat Aug 25 03:51:51 2007 -0400
+
+    [PATCH] Net: ath5k, initial write cleanup
+    
+    ath5k, initial write cleanup
+    
+    The final step of initial writing cleanup. ar5211_rf is going away.
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: <linville at tuxdriver.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 5f56d31da11ddf176e313828d168365662ee7b19
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Sat Aug 25 03:57:26 2007 -0400
+
+    [PATCH] Net: ath5k, comment some EEPROM registers
+    
+    ath5k, comment some EEPROM registers
+    
+    make some registers meaning clear
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Cc: <linville at tuxdriver.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit f2854f11abaef57d219103380ab8410eda6a4c83
+Author: John W. Linville <linville at tuxdriver.com>
+Date:   Thu Aug 23 15:23:30 2007 -0400
+
+    [PATCH] ath5k: fix build breakage from recent mac80211 changes
+    
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 042c3bcd643fc46949ddd1e71d16ec1dcc0dcf18
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Wed Aug 22 22:54:07 2007 +0200
+
+    [PATCH] Net: ath5k, remove sysctls
+    
+    ath5k, remove sysctls
+    
+    Syscalls were buggy and defunct in later kernels (due to sysctl check).
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 1fea1eeb34e4092d45e94e6c3e9f2c93b3bc268a
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Wed Aug 22 22:53:25 2007 +0200
+
+    [PATCH] Net: ath5k, no printk after STA->IBSS switch
+    
+    ath5k, no printk after STA->IBSS switch
+    
+    If STA->IBSS switch was done, but beacon_update weas not called so far, do
+    not emit a warning about non-existent skbuf.
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 88ee097caeeb0561c293296c03da47d3b6e688fb
+Author: akpm at linux-foundation.org <akpm at linux-foundation.org>
+Date:   Tue Aug 21 16:53:53 2007 -0700
+
+    [PATCH] ath5k: needs PCI
+    
+    drivers/net/wireless/ath5k_base.c: In function `ath_pci_probe':
+    drivers/net/wireless/ath5k_base.c:2279: error: implicit declaration of function `pci_request_region'
+    drivers/net/wireless/ath5k_base.c:2359: error: implicit declaration of function `pci_release_region'
+    
+    Cc: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit 8ddf75b76f0b704971cb0df635557b5cad84ed7d
+Author: akpm at linux-foundation.org <akpm at linux-foundation.org>
+Date:   Tue Aug 21 00:51:20 2007 -0700
+
+    [PATCH] ath5k: kconfig fix
+    
+    It needs stuff from net/mac80211/ieee80211.c
+    
+    Cc: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit cd59338a9249ea6f216ba291167fa9728f8bc1ce
+Author: akpm at linux-foundation.org <akpm at linux-foundation.org>
+Date:   Tue Aug 21 00:42:32 2007 -0700
+
+    [PATCH] ath5k: printk fix
+    
+    drivers/net/wireless/ath5k_base.c: In function 'ath_txq_setup':
+    drivers/net/wireless/ath5k_base.c:2033: warning: format '%u' expects type 'unsigned int', but argument 3 has type 'long unsigned int'
+    
+    Cc: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+commit d58bf444cd868ce93b29501c013b2c057007eed5
+Author: Jiri Slaby <jirislaby at gmail.com>
+Date:   Sun Aug 12 17:33:16 2007 +0200
+
+    [PATCH] Net: add ath5k wireless driver
+    
+    add ath5k wireless driver
+    
+    Signed-off-by: Jiri Slaby <jirislaby at gmail.com>
+    Signed-off-by: John W. Linville <linville at tuxdriver.com>
+
+diff -up linux-2.6.23.noarch/MAINTAINERS.orig linux-2.6.23.noarch/MAINTAINERS
+--- linux-2.6.23.noarch/MAINTAINERS.orig	2007-12-21 12:15:17.000000000 -0500
++++ linux-2.6.23.noarch/MAINTAINERS	2007-12-21 12:18:50.000000000 -0500
+@@ -646,6 +646,17 @@ M:	ecashin at coraid.com
+ W:	http://www.coraid.com/support/linux
+ S:	Supported
+ 
++ATHEROS ATH5K WIRELESS DRIVER
++P:	Jiri Slaby
++M:	jirislaby at gmail.com
++P:	Nick Kossifidis
++M:	mickflemm at gmail.com
++P:	Luis R. Rodriguez
++M:	mcgrof at gmail.com
++L:	linux-wireless at vger.kernel.org
++L:	ath5k-devel at lists.ath5k.org
++S:	Maintained
++
+ ATL1 ETHERNET DRIVER
+ P:	Jay Cliburn
+ M:	jcliburn at gmail.com
+diff -up linux-2.6.23.noarch/drivers/net/wireless/Makefile.orig linux-2.6.23.noarch/drivers/net/wireless/Makefile
+--- linux-2.6.23.noarch/drivers/net/wireless/Makefile.orig	2007-12-21 12:15:17.000000000 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/Makefile	2007-12-21 12:18:50.000000000 -0500
+@@ -61,3 +61,5 @@ obj-$(CONFIG_RT2X00)	+= rt2x00/
+ obj-$(CONFIG_P54_COMMON)	+= p54common.o
+ obj-$(CONFIG_P54_USB)		+= p54usb.o
+ obj-$(CONFIG_P54_PCI)		+= p54pci.o
++
++obj-$(CONFIG_ATH5K)	+= ath5k/
+diff -up linux-2.6.23.noarch/drivers/net/wireless/Kconfig.orig linux-2.6.23.noarch/drivers/net/wireless/Kconfig
+--- linux-2.6.23.noarch/drivers/net/wireless/Kconfig.orig	2007-12-21 12:15:17.000000000 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/Kconfig	2007-12-21 12:18:50.000000000 -0500
+@@ -656,6 +656,24 @@ config P54_PCI
+ 	tristate "Prism54 PCI support"
+ 	depends on P54_COMMON && PCI
+ 
++config ATH5K
++	tristate "Atheros 5xxx wireless cards support"
++	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
++	default m
++	---help---
++	  This module adds support for wireless adapters based on
++	  Atheros 5xxx chipset.
++
++	  Currently the following chip versions are supported:
++
++	  MAC: AR5211 AR5212
++	  PHY: RF5111/2111 RF5112/2112 RF5413/2413
++
++	  This driver uses the kernel's mac80211 subsystem.
++
++	  If you choose to build a module, it'll be called ath5k. Say M if
++	  unsure.
++
+ source "drivers/net/wireless/iwlwifi/Kconfig"
+ source "drivers/net/wireless/hostap/Kconfig"
+ source "drivers/net/wireless/bcm43xx/Kconfig"
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/phy.c
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/phy.c	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,2071 @@
++/*
++ * PHY functions
++ *
++ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk at openbsd.org>
++ * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm at gmail.com>
++ * Copyright (c) 2007 Jiri Slaby <jirislaby at gmail.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ */
++
++#include <linux/delay.h>
++
++#include "ath5k.h"
++#include "reg.h"
++#include "base.h"
++
++/* Struct to hold initial RF register values (RF Banks) */
++struct ath5k_ini_rf {
++	u8	rf_bank;	/* check out ath5k_reg.h */
++	u16	rf_register;	/* register address */
++	u32	rf_value[5];	/* register value for different modes (above) */
++};
++
++/*
++ * Mode-specific RF Gain table (64bytes) for RF5111/5112
++ * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
++ * RF Gain values are included in AR5K_AR5210_INI)
++ */
++struct ath5k_ini_rfgain {
++	u16	rfg_register;	/* RF Gain register address */
++	u32	rfg_value[2];	/* [freq (see below)] */
++};
++
++struct ath5k_gain_opt {
++	u32			go_default;
++	u32			go_steps_count;
++	const struct ath5k_gain_opt_step	go_step[AR5K_GAIN_STEP_COUNT];
++};
++
++/* RF5111 mode-specific init registers */
++static const struct ath5k_ini_rf rfregs_5111[] = {
++	{ 0, 0x989c,
++	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0, 0x989c,
++	    { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
++	{ 0, 0x989c,
++	    { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
++	{ 0, 0x98d4,
++	    { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
++	{ 1, 0x98d4,
++	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
++	{ 2, 0x98d4,
++	    { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
++	{ 3, 0x98d8,
++	    { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
++	{ 6, 0x989c,
++	    { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
++	{ 6, 0x989c,
++	    { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
++	{ 6, 0x989c,
++	    { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
++	{ 6, 0x989c,
++	    { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
++	{ 6, 0x989c,
++	    { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
++	{ 6, 0x98d4,
++	    { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
++	{ 7, 0x989c,
++	    { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
++	{ 7, 0x989c,
++	    { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
++	{ 7, 0x989c,
++	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
++	{ 7, 0x989c,
++	    { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
++	{ 7, 0x989c,
++	    { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
++	{ 7, 0x989c,
++	    { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
++	{ 7, 0x989c,
++	    { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
++	{ 7, 0x98cc,
++	    { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
++};
++
++/* Initial RF Gain settings for RF5111 */
++static const struct ath5k_ini_rfgain rfgain_5111[] = {
++	/*			      5Ghz	2Ghz	*/
++	{ AR5K_RF_GAIN(0),	{ 0x000001a9, 0x00000000 } },
++	{ AR5K_RF_GAIN(1),	{ 0x000001e9, 0x00000040 } },
++	{ AR5K_RF_GAIN(2),	{ 0x00000029, 0x00000080 } },
++	{ AR5K_RF_GAIN(3),	{ 0x00000069, 0x00000150 } },
++	{ AR5K_RF_GAIN(4),	{ 0x00000199, 0x00000190 } },
++	{ AR5K_RF_GAIN(5),	{ 0x000001d9, 0x000001d0 } },
++	{ AR5K_RF_GAIN(6),	{ 0x00000019, 0x00000010 } },
++	{ AR5K_RF_GAIN(7),	{ 0x00000059, 0x00000044 } },
++	{ AR5K_RF_GAIN(8),	{ 0x00000099, 0x00000084 } },
++	{ AR5K_RF_GAIN(9),	{ 0x000001a5, 0x00000148 } },
++	{ AR5K_RF_GAIN(10),	{ 0x000001e5, 0x00000188 } },
++	{ AR5K_RF_GAIN(11),	{ 0x00000025, 0x000001c8 } },
++	{ AR5K_RF_GAIN(12),	{ 0x000001c8, 0x00000014 } },
++	{ AR5K_RF_GAIN(13),	{ 0x00000008, 0x00000042 } },
++	{ AR5K_RF_GAIN(14),	{ 0x00000048, 0x00000082 } },
++	{ AR5K_RF_GAIN(15),	{ 0x00000088, 0x00000178 } },
++	{ AR5K_RF_GAIN(16),	{ 0x00000198, 0x000001b8 } },
++	{ AR5K_RF_GAIN(17),	{ 0x000001d8, 0x000001f8 } },
++	{ AR5K_RF_GAIN(18),	{ 0x00000018, 0x00000012 } },
++	{ AR5K_RF_GAIN(19),	{ 0x00000058, 0x00000052 } },
++	{ AR5K_RF_GAIN(20),	{ 0x00000098, 0x00000092 } },
++	{ AR5K_RF_GAIN(21),	{ 0x000001a4, 0x0000017c } },
++	{ AR5K_RF_GAIN(22),	{ 0x000001e4, 0x000001bc } },
++	{ AR5K_RF_GAIN(23),	{ 0x00000024, 0x000001fc } },
++	{ AR5K_RF_GAIN(24),	{ 0x00000064, 0x0000000a } },
++	{ AR5K_RF_GAIN(25),	{ 0x000000a4, 0x0000004a } },
++	{ AR5K_RF_GAIN(26),	{ 0x000000e4, 0x0000008a } },
++	{ AR5K_RF_GAIN(27),	{ 0x0000010a, 0x0000015a } },
++	{ AR5K_RF_GAIN(28),	{ 0x0000014a, 0x0000019a } },
++	{ AR5K_RF_GAIN(29),	{ 0x0000018a, 0x000001da } },
++	{ AR5K_RF_GAIN(30),	{ 0x000001ca, 0x0000000e } },
++	{ AR5K_RF_GAIN(31),	{ 0x0000000a, 0x0000004e } },
++	{ AR5K_RF_GAIN(32),	{ 0x0000004a, 0x0000008e } },
++	{ AR5K_RF_GAIN(33),	{ 0x0000008a, 0x0000015e } },
++	{ AR5K_RF_GAIN(34),	{ 0x000001ba, 0x0000019e } },
++	{ AR5K_RF_GAIN(35),	{ 0x000001fa, 0x000001de } },
++	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000009 } },
++	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000049 } },
++	{ AR5K_RF_GAIN(38),	{ 0x00000186, 0x00000089 } },
++	{ AR5K_RF_GAIN(39),	{ 0x000001c6, 0x00000179 } },
++	{ AR5K_RF_GAIN(40),	{ 0x00000006, 0x000001b9 } },
++	{ AR5K_RF_GAIN(41),	{ 0x00000046, 0x000001f9 } },
++	{ AR5K_RF_GAIN(42),	{ 0x00000086, 0x00000039 } },
++	{ AR5K_RF_GAIN(43),	{ 0x000000c6, 0x00000079 } },
++	{ AR5K_RF_GAIN(44),	{ 0x000000c6, 0x000000b9 } },
++	{ AR5K_RF_GAIN(45),	{ 0x000000c6, 0x000001bd } },
++	{ AR5K_RF_GAIN(46),	{ 0x000000c6, 0x000001fd } },
++	{ AR5K_RF_GAIN(47),	{ 0x000000c6, 0x0000003d } },
++	{ AR5K_RF_GAIN(48),	{ 0x000000c6, 0x0000007d } },
++	{ AR5K_RF_GAIN(49),	{ 0x000000c6, 0x000000bd } },
++	{ AR5K_RF_GAIN(50),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(51),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(52),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(53),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(54),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(55),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(56),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(57),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(58),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(59),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(60),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(61),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(62),	{ 0x000000c6, 0x000000fd } },
++	{ AR5K_RF_GAIN(63),	{ 0x000000c6, 0x000000fd } },
++};
++
++static const struct ath5k_gain_opt rfgain_opt_5111 = {
++	4,
++	9,
++	{
++		{ { 4, 1, 1, 1 }, 6 },
++		{ { 4, 0, 1, 1 }, 4 },
++		{ { 3, 1, 1, 1 }, 3 },
++		{ { 4, 0, 0, 1 }, 1 },
++		{ { 4, 1, 1, 0 }, 0 },
++		{ { 4, 0, 1, 0 }, -2 },
++		{ { 3, 1, 1, 0 }, -3 },
++		{ { 4, 0, 0, 0 }, -4 },
++		{ { 2, 1, 1, 0 }, -6 }
++	}
++};
++
++/* RF5112 mode-specific init registers */
++static const struct ath5k_ini_rf rfregs_5112[] = {
++	{ 1, 0x98d4,
++	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
++	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
++	{ 2, 0x98d0,
++	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
++	{ 3, 0x98dc,
++	    { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
++	{ 6, 0x989c,
++	    { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
++	{ 6, 0x989c,
++	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
++	{ 6, 0x989c,
++	    { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
++	{ 6, 0x989c,
++	    { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
++	{ 6, 0x989c,
++	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
++	{ 6, 0x989c,
++	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
++	{ 6, 0x989c,
++	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
++	{ 6, 0x989c,
++	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, 0x989c,
++	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, 0x989c,
++	    { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
++	{ 6, 0x989c,
++	    { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
++	{ 6, 0x989c,
++	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
++	{ 6, 0x989c,
++	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
++	{ 6, 0x989c,
++	    { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
++	{ 6, 0x989c,
++	    { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
++	{ 6, 0x989c,
++	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
++	{ 6, 0x989c,
++	    { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
++	{ 6, 0x989c,
++	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
++	{ 6, 0x989c,
++	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
++	{ 6, 0x989c,
++	    { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
++	{ 6, 0x989c,
++	    { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
++	{ 6, 0x989c,
++	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
++	{ 6, 0x989c,
++	    { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
++	{ 6, 0x989c,
++	    { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
++	{ 6, 0x989c,
++	    { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
++	{ 6, 0x989c,
++	    { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
++	{ 6, 0x989c,
++	    { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
++	{ 6, 0x989c,
++	    { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
++	{ 6, 0x989c,
++	    { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
++	{ 6, 0x989c,
++	    { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
++	{ 6, 0x989c,
++	    { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
++	{ 6, 0x989c,
++	    { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
++	{ 6, 0x98d0,
++	    { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
++	{ 7, 0x989c,
++	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
++	{ 7, 0x989c,
++	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
++	{ 7, 0x989c,
++	    { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
++	{ 7, 0x989c,
++	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
++	{ 7, 0x989c,
++	    { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
++	{ 7, 0x989c,
++	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
++	{ 7, 0x989c,
++	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
++	{ 7, 0x989c,
++	    { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
++	{ 7, 0x989c,
++	    { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
++	{ 7, 0x989c,
++	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
++	{ 7, 0x989c,
++	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
++	{ 7, 0x989c,
++	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
++	{ 7, 0x98c4,
++	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
++};
++
++/* RF5112A mode-specific init registers */
++static const struct ath5k_ini_rf rfregs_5112a[] = {
++	{ 1, 0x98d4,
++	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
++	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
++	{ 2, 0x98d0,
++	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
++	{ 3, 0x98dc,
++	    { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
++	{ 6, 0x989c,
++	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
++	{ 6, 0x989c,
++	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
++	{ 6, 0x989c,
++	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
++	{ 6, 0x989c,
++	    { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
++	{ 6, 0x989c,
++	    { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
++	{ 6, 0x989c,
++	    { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
++	{ 6, 0x989c,
++	    { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
++	{ 6, 0x989c,
++	    { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
++	{ 6, 0x989c,
++	    { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
++	{ 6, 0x989c,
++	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, 0x989c,
++	    { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
++	{ 6, 0x989c,
++	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
++	{ 6, 0x989c,
++	    { 0x00190000, 0x00190000, 0x00190000, 0x00190000, 0x00190000 } },
++	{ 6, 0x989c,
++	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
++	{ 6, 0x989c,
++	    { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
++	{ 6, 0x989c,
++	    { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
++	{ 6, 0x989c,
++	    { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
++	{ 6, 0x989c,
++	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
++	{ 6, 0x989c,
++	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
++	{ 6, 0x989c,
++	    { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
++	{ 6, 0x989c,
++	    { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
++	{ 6, 0x989c,
++	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
++	{ 6, 0x989c,
++	    { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
++	{ 6, 0x989c,
++	    { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
++	{ 6, 0x989c,
++	    { 0x00020080, 0x00020080, 0x00020080, 0x00020080, 0x00020080 } },
++	{ 6, 0x989c,
++	    { 0x00080009, 0x00080009, 0x00080009, 0x00080009, 0x00080009 } },
++	{ 6, 0x989c,
++	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
++	{ 6, 0x989c,
++	    { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
++	{ 6, 0x989c,
++	    { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
++	{ 6, 0x989c,
++	    { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
++	{ 6, 0x989c,
++	    { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
++	{ 6, 0x98d8,
++	    { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
++	{ 7, 0x989c,
++	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
++	{ 7, 0x989c,
++	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
++	{ 7, 0x989c,
++	    { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
++	{ 7, 0x989c,
++	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
++	{ 7, 0x989c,
++	    { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
++	{ 7, 0x989c,
++	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
++	{ 7, 0x989c,
++	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
++	{ 7, 0x989c,
++	    { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
++	{ 7, 0x989c,
++	    { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
++	{ 7, 0x989c,
++	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
++	{ 7, 0x989c,
++	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
++	{ 7, 0x989c,
++	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
++	{ 7, 0x98c4,
++	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
++};
++
++
++static const struct ath5k_ini_rf rfregs_2112a[] = {
++	{ 1, AR5K_RF_BUFFER_CONTROL_4,
++	/*	   mode b	mode g	  mode gTurbo */
++		{ 0x00000020, 0x00000020, 0x00000020 } },
++	{ 2, AR5K_RF_BUFFER_CONTROL_3,
++		{ 0x03060408, 0x03060408, 0x03070408 } },
++	{ 3, AR5K_RF_BUFFER_CONTROL_6,
++		{ 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x0a000000, 0x0a000000, 0x0a000000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00800000, 0x00800000, 0x00800000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x002a0000, 0x002a0000, 0x002a0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00010000, 0x00010000, 0x00010000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00180000, 0x00180000, 0x00180000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x006e0000, 0x006e0000, 0x006e0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00c70000, 0x00c70000, 0x00c70000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x004b0000, 0x004b0000, 0x004b0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x04480000, 0x04480000, 0x04480000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x002a0000, 0x002a0000, 0x002a0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00e40000, 0x00e40000, 0x00e40000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x043f0000, 0x043f0000, 0x043f0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x0c0c0000, 0x0c0c0000, 0x0c0c0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x02190000, 0x02190000, 0x02190000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00240000, 0x00240000, 0x00240000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00b40000, 0x00b40000, 0x00b40000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00990000, 0x00990000, 0x00990000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00500000, 0x00500000, 0x00500000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x002a0000, 0x002a0000, 0x002a0000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00120000, 0x00120000, 0x00120000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0xc0320000, 0xc0320000, 0xc0320000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x01740000, 0x01740000, 0x01740000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00110000, 0x00110000, 0x00110000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x86280000, 0x86280000, 0x86280000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x31840000, 0x31840000, 0x31840000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00f20080, 0x00f20080, 0x00f20080 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00070019, 0x00070019, 0x00070019 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x000000b2, 0x000000b2, 0x000000b2 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00b02184, 0x00b02184, 0x00b02184 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x004125a4, 0x004125a4, 0x004125a4 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x00119220, 0x00119220, 0x00119220 } },
++	{ 6, AR5K_RF_BUFFER,
++		{ 0x001a4800, 0x001a4800, 0x001a4800 } },
++	{ 6, AR5K_RF_BUFFER_CONTROL_5,
++		{ 0x000b0230, 0x000b0230, 0x000b0230 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x00000094, 0x00000094, 0x00000094 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x00000091, 0x00000091, 0x00000091 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x00000012, 0x00000012, 0x00000012 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x00000080, 0x00000080, 0x00000080 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x000000d9, 0x000000d9, 0x000000d9 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x00000060, 0x00000060, 0x00000060 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x000000f0, 0x000000f0, 0x000000f0 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x000000a2, 0x000000a2, 0x000000a2 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x00000052, 0x00000052, 0x00000052 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x000000d4, 0x000000d4, 0x000000d4 } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x000014cc, 0x000014cc, 0x000014cc } },
++	{ 7, AR5K_RF_BUFFER,
++		{ 0x0000048c, 0x0000048c, 0x0000048c } },
++	{ 7, AR5K_RF_BUFFER_CONTROL_1,
++		{ 0x00000003, 0x00000003, 0x00000003 } },
++};
++
++/* RF5413/5414 mode-specific init registers */
++static const struct ath5k_ini_rf rfregs_5413[] = {
++	{ 1, 0x98d4,
++	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
++	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
++	{ 2, 0x98d0,
++	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
++	{ 3, 0x98dc,
++	    { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
++	{ 6, 0x989c,
++	    { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
++	{ 6, 0x989c,
++	    { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
++	{ 6, 0x989c,
++	    { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
++	{ 6, 0x989c,
++	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
++	{ 6, 0x989c,
++	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
++	{ 6, 0x989c,
++	    { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
++	{ 6, 0x989c,
++	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, 0x989c,
++	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, 0x989c,
++	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, 0x989c,
++	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
++	{ 6, 0x989c,
++	    { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
++	{ 6, 0x989c,
++	    { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
++	{ 6, 0x989c,
++	    { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
++	{ 6, 0x989c,
++	    { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
++	{ 6, 0x989c,
++	    { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
++	{ 6, 0x989c,
++	    { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
++	{ 6, 0x989c,
++	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
++	{ 6, 0x989c,
++	    { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
++	{ 6, 0x989c,
++	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
++	{ 6, 0x989c,
++	    { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
++	{ 6, 0x989c,
++	    { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
++	{ 6, 0x989c,
++	    { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
++	{ 6, 0x989c,
++	    { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
++	{ 6, 0x989c,
++	    { 0x00510040, 0x00510040, 0x005100a0, 0x005100a0, 0x005100a0 } },
++	{ 6, 0x989c,
++	    { 0x0050006a, 0x0050006a, 0x005000dd, 0x005000dd, 0x005000dd } },
++	{ 6, 0x989c,
++	    { 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
++	{ 6, 0x989c,
++	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 6, 0x989c,
++	    { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
++	{ 6, 0x989c,
++	    { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00003600 } },
++	{ 6, 0x98c8,
++	    { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
++	{ 7, 0x989c,
++	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
++	{ 7, 0x989c,
++	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
++	{ 7, 0x98cc,
++	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
++};
++
++
++/* Initial RF Gain settings for RF5112 */
++static const struct ath5k_ini_rfgain rfgain_5112[] = {
++	/*			      5Ghz	2Ghz	*/
++	{ AR5K_RF_GAIN(0),	{ 0x00000007, 0x00000007 } },
++	{ AR5K_RF_GAIN(1),	{ 0x00000047, 0x00000047 } },
++	{ AR5K_RF_GAIN(2),	{ 0x00000087, 0x00000087 } },
++	{ AR5K_RF_GAIN(3),	{ 0x000001a0, 0x000001a0 } },
++	{ AR5K_RF_GAIN(4),	{ 0x000001e0, 0x000001e0 } },
++	{ AR5K_RF_GAIN(5),	{ 0x00000020, 0x00000020 } },
++	{ AR5K_RF_GAIN(6),	{ 0x00000060, 0x00000060 } },
++	{ AR5K_RF_GAIN(7),	{ 0x000001a1, 0x000001a1 } },
++	{ AR5K_RF_GAIN(8),	{ 0x000001e1, 0x000001e1 } },
++	{ AR5K_RF_GAIN(9),	{ 0x00000021, 0x00000021 } },
++	{ AR5K_RF_GAIN(10),	{ 0x00000061, 0x00000061 } },
++	{ AR5K_RF_GAIN(11),	{ 0x00000162, 0x00000162 } },
++	{ AR5K_RF_GAIN(12),	{ 0x000001a2, 0x000001a2 } },
++	{ AR5K_RF_GAIN(13),	{ 0x000001e2, 0x000001e2 } },
++	{ AR5K_RF_GAIN(14),	{ 0x00000022, 0x00000022 } },
++	{ AR5K_RF_GAIN(15),	{ 0x00000062, 0x00000062 } },
++	{ AR5K_RF_GAIN(16),	{ 0x00000163, 0x00000163 } },
++	{ AR5K_RF_GAIN(17),	{ 0x000001a3, 0x000001a3 } },
++	{ AR5K_RF_GAIN(18),	{ 0x000001e3, 0x000001e3 } },
++	{ AR5K_RF_GAIN(19),	{ 0x00000023, 0x00000023 } },
++	{ AR5K_RF_GAIN(20),	{ 0x00000063, 0x00000063 } },
++	{ AR5K_RF_GAIN(21),	{ 0x00000184, 0x00000184 } },
++	{ AR5K_RF_GAIN(22),	{ 0x000001c4, 0x000001c4 } },
++	{ AR5K_RF_GAIN(23),	{ 0x00000004, 0x00000004 } },
++	{ AR5K_RF_GAIN(24),	{ 0x000001ea, 0x0000000b } },
++	{ AR5K_RF_GAIN(25),	{ 0x0000002a, 0x0000004b } },
++	{ AR5K_RF_GAIN(26),	{ 0x0000006a, 0x0000008b } },
++	{ AR5K_RF_GAIN(27),	{ 0x000000aa, 0x000001ac } },
++	{ AR5K_RF_GAIN(28),	{ 0x000001ab, 0x000001ec } },
++	{ AR5K_RF_GAIN(29),	{ 0x000001eb, 0x0000002c } },
++	{ AR5K_RF_GAIN(30),	{ 0x0000002b, 0x00000012 } },
++	{ AR5K_RF_GAIN(31),	{ 0x0000006b, 0x00000052 } },
++	{ AR5K_RF_GAIN(32),	{ 0x000000ab, 0x00000092 } },
++	{ AR5K_RF_GAIN(33),	{ 0x000001ac, 0x00000193 } },
++	{ AR5K_RF_GAIN(34),	{ 0x000001ec, 0x000001d3 } },
++	{ AR5K_RF_GAIN(35),	{ 0x0000002c, 0x00000013 } },
++	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000053 } },
++	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000093 } },
++	{ AR5K_RF_GAIN(38),	{ 0x000000ba, 0x00000194 } },
++	{ AR5K_RF_GAIN(39),	{ 0x000001bb, 0x000001d4 } },
++	{ AR5K_RF_GAIN(40),	{ 0x000001fb, 0x00000014 } },
++	{ AR5K_RF_GAIN(41),	{ 0x0000003b, 0x0000003a } },
++	{ AR5K_RF_GAIN(42),	{ 0x0000007b, 0x0000007a } },
++	{ AR5K_RF_GAIN(43),	{ 0x000000bb, 0x000000ba } },
++	{ AR5K_RF_GAIN(44),	{ 0x000001bc, 0x000001bb } },
++	{ AR5K_RF_GAIN(45),	{ 0x000001fc, 0x000001fb } },
++	{ AR5K_RF_GAIN(46),	{ 0x0000003c, 0x0000003b } },
++	{ AR5K_RF_GAIN(47),	{ 0x0000007c, 0x0000007b } },
++	{ AR5K_RF_GAIN(48),	{ 0x000000bc, 0x000000bb } },
++	{ AR5K_RF_GAIN(49),	{ 0x000000fc, 0x000001bc } },
++	{ AR5K_RF_GAIN(50),	{ 0x000000fc, 0x000001fc } },
++	{ AR5K_RF_GAIN(51),	{ 0x000000fc, 0x0000003c } },
++	{ AR5K_RF_GAIN(52),	{ 0x000000fc, 0x0000007c } },
++	{ AR5K_RF_GAIN(53),	{ 0x000000fc, 0x000000bc } },
++	{ AR5K_RF_GAIN(54),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(55),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(56),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(57),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(58),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(59),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(60),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(61),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(62),	{ 0x000000fc, 0x000000fc } },
++	{ AR5K_RF_GAIN(63),	{ 0x000000fc, 0x000000fc } },
++};
++
++/* Initial RF Gain settings for RF5413 */
++static const struct ath5k_ini_rfgain rfgain_5413[] = {
++	/*			      5Ghz	2Ghz	*/
++	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
++	{ AR5K_RF_GAIN(1),	{ 0x00000040, 0x00000040 } },
++	{ AR5K_RF_GAIN(2),	{ 0x00000080, 0x00000080 } },
++	{ AR5K_RF_GAIN(3),	{ 0x000001a1, 0x00000161 } },
++	{ AR5K_RF_GAIN(4),	{ 0x000001e1, 0x000001a1 } },
++	{ AR5K_RF_GAIN(5),	{ 0x00000021, 0x000001e1 } },
++	{ AR5K_RF_GAIN(6),	{ 0x00000061, 0x00000021 } },
++	{ AR5K_RF_GAIN(7),	{ 0x00000188, 0x00000061 } },
++	{ AR5K_RF_GAIN(8),	{ 0x000001c8, 0x00000188 } },
++	{ AR5K_RF_GAIN(9),	{ 0x00000008, 0x000001c8 } },
++	{ AR5K_RF_GAIN(10),	{ 0x00000048, 0x00000008 } },
++	{ AR5K_RF_GAIN(11),	{ 0x00000088, 0x00000048 } },
++	{ AR5K_RF_GAIN(12),	{ 0x000001a9, 0x00000088 } },
++	{ AR5K_RF_GAIN(13),	{ 0x000001e9, 0x00000169 } },
++	{ AR5K_RF_GAIN(14),	{ 0x00000029, 0x000001a9 } },
++	{ AR5K_RF_GAIN(15),	{ 0x00000069, 0x000001e9 } },
++	{ AR5K_RF_GAIN(16),	{ 0x000001d0, 0x00000029 } },
++	{ AR5K_RF_GAIN(17),	{ 0x00000010, 0x00000069 } },
++	{ AR5K_RF_GAIN(18),	{ 0x00000050, 0x00000190 } },
++	{ AR5K_RF_GAIN(19),	{ 0x00000090, 0x000001d0 } },
++	{ AR5K_RF_GAIN(20),	{ 0x000001b1, 0x00000010 } },
++	{ AR5K_RF_GAIN(21),	{ 0x000001f1, 0x00000050 } },
++	{ AR5K_RF_GAIN(22),	{ 0x00000031, 0x00000090 } },
++	{ AR5K_RF_GAIN(23),	{ 0x00000071, 0x00000171 } },
++	{ AR5K_RF_GAIN(24),	{ 0x000001b8, 0x000001b1 } },
++	{ AR5K_RF_GAIN(25),	{ 0x000001f8, 0x000001f1 } },
++	{ AR5K_RF_GAIN(26),	{ 0x00000038, 0x00000031 } },
++	{ AR5K_RF_GAIN(27),	{ 0x00000078, 0x00000071 } },
++	{ AR5K_RF_GAIN(28),	{ 0x00000199, 0x00000198 } },
++	{ AR5K_RF_GAIN(29),	{ 0x000001d9, 0x000001d8 } },
++	{ AR5K_RF_GAIN(30),	{ 0x00000019, 0x00000018 } },
++	{ AR5K_RF_GAIN(31),	{ 0x00000059, 0x00000058 } },
++	{ AR5K_RF_GAIN(32),	{ 0x00000099, 0x00000098 } },
++	{ AR5K_RF_GAIN(33),	{ 0x000000d9, 0x00000179 } },
++	{ AR5K_RF_GAIN(34),	{ 0x000000f9, 0x000001b9 } },
++	{ AR5K_RF_GAIN(35),	{ 0x000000f9, 0x000001f9 } },
++	{ AR5K_RF_GAIN(36),	{ 0x000000f9, 0x00000039 } },
++	{ AR5K_RF_GAIN(37),	{ 0x000000f9, 0x00000079 } },
++	{ AR5K_RF_GAIN(38),	{ 0x000000f9, 0x000000b9 } },
++	{ AR5K_RF_GAIN(39),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(40),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(41),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(42),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(43),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(44),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(45),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(46),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(47),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(48),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(49),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(50),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(51),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(52),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(53),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(54),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(55),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(56),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(57),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(58),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(59),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(60),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(61),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(62),	{ 0x000000f9, 0x000000f9 } },
++	{ AR5K_RF_GAIN(63),	{ 0x000000f9, 0x000000f9 } },
++};
++
++static const struct ath5k_gain_opt rfgain_opt_5112 = {
++	1,
++	8,
++	{
++		{ { 3, 0, 0, 0, 0, 0, 0 }, 6 },
++		{ { 2, 0, 0, 0, 0, 0, 0 }, 0 },
++		{ { 1, 0, 0, 0, 0, 0, 0 }, -3 },
++		{ { 0, 0, 0, 0, 0, 0, 0 }, -6 },
++		{ { 0, 1, 1, 0, 0, 0, 0 }, -8 },
++		{ { 0, 1, 1, 0, 1, 1, 0 }, -10 },
++		{ { 0, 1, 0, 1, 1, 1, 0 }, -13 },
++		{ { 0, 1, 0, 1, 1, 0, 1 }, -16 },
++	}
++};
++
++/*
++ * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
++ */
++static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits,
++		u32 first, u32 col, bool set)
++{
++	u32 mask, entry, last, data, shift, position;
++	s32 left;
++	int i;
++
++	data = 0;
++
++	if (rf == NULL)
++		/* should not happen */
++		return 0;
++
++	if (!(col <= 3 && bits <= 32 && first + bits <= 319)) {
++		ATH5K_PRINTF("invalid values at offset %u\n", offset);
++		return 0;
++	}
++
++	entry = ((first - 1) / 8) + offset;
++	position = (first - 1) % 8;
++
++	if (set == true)
++		data = ath5k_hw_bitswap(reg, bits);
++
++	for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) {
++		last = (position + left > 8) ? 8 : position + left;
++		mask = (((1 << last) - 1) ^ ((1 << position) - 1)) << (col * 8);
++
++		if (set == true) {
++			rf[entry] &= ~mask;
++			rf[entry] |= ((data << position) << (col * 8)) & mask;
++			data >>= (8 - position);
++		} else {
++			data = (((rf[entry] & mask) >> (col * 8)) >> position)
++				<< shift;
++			shift += last - position;
++		}
++
++		left -= 8 - position;
++	}
++
++	data = set == true ? 1 : ath5k_hw_bitswap(data, bits);
++
++	return data;
++}
++
++static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
++{
++	u32 mix, step;
++	u32 *rf;
++
++	if (ah->ah_rf_banks == NULL)
++		return 0;
++
++	rf = ah->ah_rf_banks;
++	ah->ah_gain.g_f_corr = 0;
++
++	if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1)
++		return 0;
++
++	step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false);
++	mix = ah->ah_gain.g_step->gos_param[0];
++
++	switch (mix) {
++	case 3:
++		ah->ah_gain.g_f_corr = step * 2;
++		break;
++	case 2:
++		ah->ah_gain.g_f_corr = (step - 5) * 2;
++		break;
++	case 1:
++		ah->ah_gain.g_f_corr = step;
++		break;
++	default:
++		ah->ah_gain.g_f_corr = 0;
++		break;
++	}
++
++	return ah->ah_gain.g_f_corr;
++}
++
++static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
++{
++	u32 step, mix, level[4];
++	u32 *rf;
++
++	if (ah->ah_rf_banks == NULL)
++		return false;
++
++	rf = ah->ah_rf_banks;
++
++	if (ah->ah_radio == AR5K_RF5111) {
++		step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0,
++				false);
++		level[0] = 0;
++		level[1] = (step == 0x3f) ? 0x32 : step + 4;
++		level[2] = (step != 0x3f) ? 0x40 : level[0];
++		level[3] = level[2] + 0x32;
++
++		ah->ah_gain.g_high = level[3] -
++			(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
++		ah->ah_gain.g_low = level[0] +
++			(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
++	} else {
++		mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
++				false);
++		level[0] = level[2] = 0;
++
++		if (mix == 1) {
++			level[1] = level[3] = 83;
++		} else {
++			level[1] = level[3] = 107;
++			ah->ah_gain.g_high = 55;
++		}
++	}
++
++	return (ah->ah_gain.g_current >= level[0] &&
++			ah->ah_gain.g_current <= level[1]) ||
++		(ah->ah_gain.g_current >= level[2] &&
++			ah->ah_gain.g_current <= level[3]);
++}
++
++static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
++{
++	const struct ath5k_gain_opt *go;
++	int ret = 0;
++
++	switch (ah->ah_radio) {
++	case AR5K_RF5111:
++		go = &rfgain_opt_5111;
++		break;
++	case AR5K_RF5112:
++	case AR5K_RF5413: /* ??? */
++		go = &rfgain_opt_5112;
++		break;
++	default:
++		return 0;
++	}
++
++	ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx];
++
++	if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
++		if (ah->ah_gain.g_step_idx == 0)
++			return -1;
++		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
++				ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
++				ah->ah_gain.g_step_idx > 0;
++				ah->ah_gain.g_step =
++					&go->go_step[ah->ah_gain.g_step_idx])
++			ah->ah_gain.g_target -= 2 *
++			    (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
++			    ah->ah_gain.g_step->gos_gain);
++
++		ret = 1;
++		goto done;
++	}
++
++	if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
++		if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
++			return -2;
++		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
++				ah->ah_gain.g_target <= ah->ah_gain.g_low &&
++				ah->ah_gain.g_step_idx < go->go_steps_count-1;
++				ah->ah_gain.g_step =
++					&go->go_step[ah->ah_gain.g_step_idx])
++			ah->ah_gain.g_target -= 2 *
++			    (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
++			    ah->ah_gain.g_step->gos_gain);
++
++		ret = 2;
++		goto done;
++	}
++
++done:
++	ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
++		"ret %d, gain step %u, current gain %u, target gain %u\n",
++		ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current,
++		ah->ah_gain.g_target);
++
++	return ret;
++}
++
++/*
++ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111
++ */
++static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel, unsigned int mode)
++{
++	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
++	u32 *rf;
++	const unsigned int rf_size = ARRAY_SIZE(rfregs_5111);
++	unsigned int i;
++	int obdb = -1, bank = -1;
++	u32 ee_mode;
++
++	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
++
++	rf = ah->ah_rf_banks;
++
++	/* Copy values to modify them */
++	for (i = 0; i < rf_size; i++) {
++		if (rfregs_5111[i].rf_bank >= AR5K_RF5111_INI_RF_MAX_BANKS) {
++			ATH5K_ERR(ah->ah_sc, "invalid bank\n");
++			return -EINVAL;
++		}
++
++		if (bank != rfregs_5111[i].rf_bank) {
++			bank = rfregs_5111[i].rf_bank;
++			ah->ah_offset[bank] = i;
++		}
++
++		rf[i] = rfregs_5111[i].rf_value[mode];
++	}
++
++	/* Modify bank 0 */
++	if (channel->val & CHANNEL_2GHZ) {
++		if (channel->val & CHANNEL_CCK)
++			ee_mode = AR5K_EEPROM_MODE_11B;
++		else
++			ee_mode = AR5K_EEPROM_MODE_11G;
++		obdb = 0;
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0],
++				ee->ee_ob[ee_mode][obdb], 3, 119, 0, true))
++			return -EINVAL;
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0],
++				ee->ee_ob[ee_mode][obdb], 3, 122, 0, true))
++			return -EINVAL;
++
++		obdb = 1;
++	/* Modify bank 6 */
++	} else {
++		/* For 11a, Turbo and XR */
++		ee_mode = AR5K_EEPROM_MODE_11A;
++		obdb =	 channel->freq >= 5725 ? 3 :
++			(channel->freq >= 5500 ? 2 :
++			(channel->freq >= 5260 ? 1 :
++			 (channel->freq > 4000 ? 0 : -1)));
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++				ee->ee_pwd_84, 1, 51, 3, true))
++			return -EINVAL;
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++				ee->ee_pwd_90, 1, 45, 3, true))
++			return -EINVAL;
++	}
++
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++			!ee->ee_xpd[ee_mode], 1, 95, 0, true))
++		return -EINVAL;
++
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++			ee->ee_x_gain[ee_mode], 4, 96, 0, true))
++		return -EINVAL;
++
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ?
++			ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, true))
++		return -EINVAL;
++
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ?
++			ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, true))
++		return -EINVAL;
++
++	/* Modify bank 7 */
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
++			ee->ee_i_gain[ee_mode], 6, 29, 0, true))
++		return -EINVAL;
++
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
++			ee->ee_xpd[ee_mode], 1, 4, 0, true))
++		return -EINVAL;
++
++	/* Write RF values */
++	for (i = 0; i < rf_size; i++) {
++		AR5K_REG_WAIT(i);
++		ath5k_hw_reg_write(ah, rf[i], rfregs_5111[i].rf_register);
++	}
++
++	return 0;
++}
++
++/*
++ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5112
++ */
++static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel, unsigned int mode)
++{
++	const struct ath5k_ini_rf *rf_ini;
++	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
++	u32 *rf;
++	unsigned int rf_size, i;
++	int obdb = -1, bank = -1;
++	u32 ee_mode;
++
++	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
++
++	rf = ah->ah_rf_banks;
++
++	if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A
++		&& !test_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode)){
++		rf_ini = rfregs_2112a;
++		rf_size = ARRAY_SIZE(rfregs_5112a);
++		if (mode < 2) {
++			ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode);
++			return -EINVAL;
++		}
++		mode = mode - 2; /*no a/turboa modes for 2112*/
++	} else if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
++		rf_ini = rfregs_5112a;
++		rf_size = ARRAY_SIZE(rfregs_5112a);
++	} else {
++		rf_ini = rfregs_5112;
++		rf_size = ARRAY_SIZE(rfregs_5112);
++	}
++
++	/* Copy values to modify them */
++	for (i = 0; i < rf_size; i++) {
++		if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) {
++			ATH5K_ERR(ah->ah_sc, "invalid bank\n");
++			return -EINVAL;
++		}
++
++		if (bank != rf_ini[i].rf_bank) {
++			bank = rf_ini[i].rf_bank;
++			ah->ah_offset[bank] = i;
++		}
++
++		rf[i] = rf_ini[i].rf_value[mode];
++	}
++
++	/* Modify bank 6 */
++	if (channel->val & CHANNEL_2GHZ) {
++		if (channel->val & CHANNEL_OFDM)
++			ee_mode = AR5K_EEPROM_MODE_11G;
++		else
++			ee_mode = AR5K_EEPROM_MODE_11B;
++		obdb = 0;
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++				ee->ee_ob[ee_mode][obdb], 3, 287, 0, true))
++			return -EINVAL;
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++				ee->ee_ob[ee_mode][obdb], 3, 290, 0, true))
++			return -EINVAL;
++	} else {
++		/* For 11a, Turbo and XR */
++		ee_mode = AR5K_EEPROM_MODE_11A;
++		obdb = channel->freq >= 5725 ? 3 :
++		    (channel->freq >= 5500 ? 2 :
++			(channel->freq >= 5260 ? 1 :
++			    (channel->freq > 4000 ? 0 : -1)));
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++				ee->ee_ob[ee_mode][obdb], 3, 279, 0, true))
++			return -EINVAL;
++
++		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++				ee->ee_ob[ee_mode][obdb], 3, 282, 0, true))
++			return -EINVAL;
++	}
++
++	ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++	    ee->ee_x_gain[ee_mode], 2, 270, 0, true);
++	ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++	    ee->ee_x_gain[ee_mode], 2, 257, 0, true);
++
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
++			ee->ee_xpd[ee_mode], 1, 302, 0, true))
++		return -EINVAL;
++
++	/* Modify bank 7 */
++	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
++			ee->ee_i_gain[ee_mode], 6, 14, 0, true))
++		return -EINVAL;
++
++	/* Write RF values */
++	for (i = 0; i < rf_size; i++)
++		ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register);
++
++	return 0;
++}
++
++/*
++ * Initialize RF5413/5414
++ */
++static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel, unsigned int mode)
++{
++	const struct ath5k_ini_rf *rf_ini;
++	u32 *rf;
++	unsigned int rf_size, i;
++	int bank = -1;
++
++	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
++
++	rf = ah->ah_rf_banks;
++
++	rf_ini = rfregs_5413;
++	rf_size = ARRAY_SIZE(rfregs_5413);
++
++	/* Copy values to modify them */
++	for (i = 0; i < rf_size; i++) {
++		if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) {
++			ATH5K_ERR(ah->ah_sc, "invalid bank\n");
++			return -EINVAL;
++		}
++
++		if (bank != rf_ini[i].rf_bank) {
++			bank = rf_ini[i].rf_bank;
++			ah->ah_offset[bank] = i;
++		}
++
++		rf[i] = rf_ini[i].rf_value[mode];
++	}
++
++	/*
++	 * After compairing dumps from different cards
++	 * we get the same RF_BUFFER settings (diff returns
++	 * 0 lines). It seems that RF_BUFFER settings are static
++	 * and are written unmodified (no EEPROM stuff
++	 * is used because calibration data would be
++	 * different between different cards and would result
++	 * different RF_BUFFER settings)
++	 */
++
++	/* Write RF values */
++	for (i = 0; i < rf_size; i++)
++		ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register);
++
++	return 0;
++}
++
++/*
++ * Initialize RF
++ */
++int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel,
++		unsigned int mode)
++{
++	int (*func)(struct ath5k_hw *, struct ieee80211_channel *, unsigned int);
++	int ret;
++
++	switch (ah->ah_radio) {
++	case AR5K_RF5111:
++		ah->ah_rf_banks_size = sizeof(rfregs_5111);
++		func = ath5k_hw_rf5111_rfregs;
++		break;
++	case AR5K_RF5112:
++		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
++			ah->ah_rf_banks_size = sizeof(rfregs_5112a);
++		else
++			ah->ah_rf_banks_size = sizeof(rfregs_5112);
++		func = ath5k_hw_rf5112_rfregs;
++		break;
++	case AR5K_RF5413:
++		ah->ah_rf_banks_size = sizeof(rfregs_5413);
++		func = ath5k_hw_rf5413_rfregs;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (ah->ah_rf_banks == NULL) {
++		/* XXX do extra checks? */
++		ah->ah_rf_banks = kmalloc(ah->ah_rf_banks_size, GFP_KERNEL);
++		if (ah->ah_rf_banks == NULL) {
++			ATH5K_ERR(ah->ah_sc, "out of memory\n");
++			return -ENOMEM;
++		}
++	}
++
++	ret = func(ah, channel, mode);
++	if (!ret)
++		ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE;
++
++	return ret;
++}
++
++int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
++{
++	const struct ath5k_ini_rfgain *ath5k_rfg;
++	unsigned int i, size;
++
++	switch (ah->ah_radio) {
++	case AR5K_RF5111:
++		ath5k_rfg = rfgain_5111;
++		size = ARRAY_SIZE(rfgain_5111);
++		break;
++	case AR5K_RF5112:
++		ath5k_rfg = rfgain_5112;
++		size = ARRAY_SIZE(rfgain_5112);
++		break;
++	case AR5K_RF5413:
++		ath5k_rfg = rfgain_5413;
++		size = ARRAY_SIZE(rfgain_5413);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	switch (freq) {
++	case AR5K_INI_RFGAIN_2GHZ:
++	case AR5K_INI_RFGAIN_5GHZ:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	for (i = 0; i < size; i++) {
++		AR5K_REG_WAIT(i);
++		ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
++			(u32)ath5k_rfg[i].rfg_register);
++	}
++
++	return 0;
++}
++
++enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
++{
++	u32 data, type;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active ||
++			ah->ah_version <= AR5K_AR5211)
++		return AR5K_RFGAIN_INACTIVE;
++
++	if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED)
++		goto done;
++
++	data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
++
++	if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
++		ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
++		type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
++
++		if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK)
++			ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR;
++
++		if (ah->ah_radio >= AR5K_RF5112) {
++			ath5k_hw_rfregs_gainf_corr(ah);
++			ah->ah_gain.g_current =
++				ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ?
++				(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
++				0;
++		}
++
++		if (ath5k_hw_rfregs_gain_readback(ah) &&
++				AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
++				ath5k_hw_rfregs_gain_adjust(ah))
++			ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE;
++	}
++
++done:
++	return ah->ah_rf_gain;
++}
++
++int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah)
++{
++	/* Initialize the gain optimization values */
++	switch (ah->ah_radio) {
++	case AR5K_RF5111:
++		ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
++		ah->ah_gain.g_step =
++		    &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx];
++		ah->ah_gain.g_low = 20;
++		ah->ah_gain.g_high = 35;
++		ah->ah_gain.g_active = 1;
++		break;
++	case AR5K_RF5112:
++	case AR5K_RF5413: /* ??? */
++		ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
++		ah->ah_gain.g_step =
++		    &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx];
++		ah->ah_gain.g_low = 20;
++		ah->ah_gain.g_high = 85;
++		ah->ah_gain.g_active = 1;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++/**************************\
++  PHY/RF channel functions
++\**************************/
++
++/*
++ * Check if a channel is supported
++ */
++bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
++{
++	/* Check if the channel is in our supported range */
++	if (flags & CHANNEL_2GHZ) {
++		if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
++		    (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
++			return true;
++	} else if (flags & CHANNEL_5GHZ)
++		if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
++		    (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
++			return true;
++
++	return false;
++}
++
++/*
++ * Convertion needed for RF5110
++ */
++static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel)
++{
++	u32 athchan;
++
++	/*
++	 * Convert IEEE channel/MHz to an internal channel value used
++	 * by the AR5210 chipset. This has not been verified with
++	 * newer chipsets like the AR5212A who have a completely
++	 * different RF/PHY part.
++	 */
++	athchan = (ath5k_hw_bitswap((channel->chan - 24) / 2, 5) << 1) |
++		(1 << 6) | 0x1;
++
++	return athchan;
++}
++
++/*
++ * Set channel on RF5110
++ */
++static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel)
++{
++	u32 data;
++
++	/*
++	 * Set the channel and wait
++	 */
++	data = ath5k_hw_rf5110_chan2athchan(channel);
++	ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
++	ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
++	mdelay(1);
++
++	return 0;
++}
++
++/*
++ * Convertion needed for 5111
++ */
++static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
++		struct ath5k_athchan_2ghz *athchan)
++{
++	int channel;
++
++	/* Cast this value to catch negative channel numbers (>= -19) */
++	channel = (int)ieee;
++
++	/*
++	 * Map 2GHz IEEE channel to 5GHz Atheros channel
++	 */
++	if (channel <= 13) {
++		athchan->a2_athchan = 115 + channel;
++		athchan->a2_flags = 0x46;
++	} else if (channel == 14) {
++		athchan->a2_athchan = 124;
++		athchan->a2_flags = 0x44;
++	} else if (channel >= 15 && channel <= 26) {
++		athchan->a2_athchan = ((channel - 14) * 4) + 132;
++		athchan->a2_flags = 0x46;
++	} else
++		return -EINVAL;
++
++	return 0;
++}
++
++/*
++ * Set channel on 5111
++ */
++static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel)
++{
++	struct ath5k_athchan_2ghz ath5k_channel_2ghz;
++	unsigned int ath5k_channel = channel->chan;
++	u32 data0, data1, clock;
++	int ret;
++
++	/*
++	 * Set the channel on the RF5111 radio
++	 */
++	data0 = data1 = 0;
++
++	if (channel->val & CHANNEL_2GHZ) {
++		/* Map 2GHz channel to 5GHz Atheros channel ID */
++		ret = ath5k_hw_rf5111_chan2athchan(channel->chan,
++				&ath5k_channel_2ghz);
++		if (ret)
++			return ret;
++
++		ath5k_channel = ath5k_channel_2ghz.a2_athchan;
++		data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
++		    << 5) | (1 << 4);
++	}
++
++	if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
++		clock = 1;
++		data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
++			(clock << 1) | (1 << 10) | 1;
++	} else {
++		clock = 0;
++		data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
++			<< 2) | (clock << 1) | (1 << 10) | 1;
++	}
++
++	ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
++			AR5K_RF_BUFFER);
++	ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
++			AR5K_RF_BUFFER_CONTROL_3);
++
++	return 0;
++}
++
++/*
++ * Set channel on 5112 and newer
++ */
++static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel)
++{
++	u32 data, data0, data1, data2;
++	u16 c;
++
++	data = data0 = data1 = data2 = 0;
++	c = channel->freq;
++
++	/*
++	 * Set the channel on the RF5112 or newer
++	 */
++	if (c < 4800) {
++		if (!((c - 2224) % 5)) {
++			data0 = ((2 * (c - 704)) - 3040) / 10;
++			data1 = 1;
++		} else if (!((c - 2192) % 5)) {
++			data0 = ((2 * (c - 672)) - 3040) / 10;
++			data1 = 0;
++		} else
++			return -EINVAL;
++
++		data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
++	} else {
++		if (!(c % 20) && c >= 5120) {
++			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
++			data2 = ath5k_hw_bitswap(3, 2);
++		} else if (!(c % 10)) {
++			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
++			data2 = ath5k_hw_bitswap(2, 2);
++		} else if (!(c % 5)) {
++			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
++			data2 = ath5k_hw_bitswap(1, 2);
++		} else
++			return -EINVAL;
++	}
++
++	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
++
++	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
++	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
++
++	return 0;
++}
++
++/*
++ * Set a channel on the radio chip
++ */
++int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
++{
++	int ret;
++
++	/*
++	 * Check bounds supported by the PHY
++	 * (don't care about regulation restrictions at this point)
++	 */
++	if ((channel->freq < ah->ah_capabilities.cap_range.range_2ghz_min ||
++	    channel->freq > ah->ah_capabilities.cap_range.range_2ghz_max) &&
++	    (channel->freq < ah->ah_capabilities.cap_range.range_5ghz_min ||
++	    channel->freq > ah->ah_capabilities.cap_range.range_5ghz_max)) {
++		ATH5K_ERR(ah->ah_sc,
++			"channel out of supported range (%u MHz)\n",
++			channel->freq);
++		return -EINVAL;
++	}
++
++	/*
++	 * Set the channel and wait
++	 */
++	switch (ah->ah_radio) {
++	case AR5K_RF5110:
++		ret = ath5k_hw_rf5110_channel(ah, channel);
++		break;
++	case AR5K_RF5111:
++		ret = ath5k_hw_rf5111_channel(ah, channel);
++		break;
++	default:
++		ret = ath5k_hw_rf5112_channel(ah, channel);
++		break;
++	}
++
++	if (ret)
++		return ret;
++
++	ah->ah_current_channel.freq = channel->freq;
++	ah->ah_current_channel.val = channel->val;
++	ah->ah_turbo = channel->val == CHANNEL_T ? true : false;
++
++	return 0;
++}
++
++/*****************\
++  PHY calibration
++\*****************/
++
++/**
++ * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
++ *
++ * @ah: struct ath5k_hw pointer we are operating on
++ * @freq: the channel frequency, just used for error logging
++ *
++ * This function performs a noise floor calibration of the PHY and waits for
++ * it to complete. Then the noise floor value is compared to some maximum
++ * noise floor we consider valid.
++ *
++ * Note that this is different from what the madwifi HAL does: it reads the
++ * noise floor and afterwards initiates the calibration. Since the noise floor
++ * calibration can take some time to finish, depending on the current channel
++ * use, that avoids the occasional timeout warnings we are seeing now.
++ *
++ * See the following link for an Atheros patent on noise floor calibration:
++ * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
++ * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
++ *
++ */
++int
++ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
++{
++	int ret;
++	unsigned int i;
++	s32 noise_floor;
++
++	/*
++	 * Enable noise floor calibration and wait until completion
++	 */
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
++				AR5K_PHY_AGCCTL_NF);
++
++	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
++			AR5K_PHY_AGCCTL_NF, 0, false);
++	if (ret) {
++		ATH5K_ERR(ah->ah_sc,
++			"noise floor calibration timeout (%uMHz)\n", freq);
++		return ret;
++	}
++
++	/* Wait until the noise floor is calibrated and read the value */
++	for (i = 20; i > 0; i--) {
++		mdelay(1);
++		noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
++		noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
++		if (noise_floor & AR5K_PHY_NF_ACTIVE) {
++			noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
++
++			if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
++				break;
++		}
++	}
++
++	ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
++		"noise floor %d\n", noise_floor);
++
++	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
++		ATH5K_ERR(ah->ah_sc,
++			"noise floor calibration failed (%uMHz)\n", freq);
++		return -EIO;
++	}
++
++	ah->ah_noise_floor = noise_floor;
++
++	return 0;
++}
++
++/*
++ * Perform a PHY calibration on RF5110
++ * -Fix BPSK/QAM Constellation (I/Q correction)
++ * -Calculate Noise Floor
++ */
++static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel)
++{
++	u32 phy_sig, phy_agc, phy_sat, beacon;
++	int ret;
++
++	/*
++	 * Disable beacons and RX/TX queues, wait
++	 */
++	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
++		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
++	beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
++	ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
++
++	udelay(2300);
++
++	/*
++	 * Set the channel (with AGC turned off)
++	 */
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
++	udelay(10);
++	ret = ath5k_hw_channel(ah, channel);
++
++	/*
++	 * Activate PHY and wait
++	 */
++	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
++	mdelay(1);
++
++	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
++
++	if (ret)
++		return ret;
++
++	/*
++	 * Calibrate the radio chip
++	 */
++
++	/* Remember normal state */
++	phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
++	phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
++	phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
++
++	/* Update radio registers */
++	ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
++		AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
++
++	ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
++			AR5K_PHY_AGCCOARSE_LO)) |
++		AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
++		AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
++
++	ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
++			AR5K_PHY_ADCSAT_THR)) |
++		AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
++		AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
++
++	udelay(20);
++
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
++	udelay(10);
++	ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
++	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
++
++	mdelay(1);
++
++	/*
++	 * Enable calibration and wait until completion
++	 */
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
++
++	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
++			AR5K_PHY_AGCCTL_CAL, 0, false);
++
++	/* Reset to normal state */
++	ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
++	ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
++	ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
++
++	if (ret) {
++		ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
++				channel->freq);
++		return ret;
++	}
++
++	ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
++	if (ret)
++		return ret;
++
++	/*
++	 * Re-enable RX/TX and beacons
++	 */
++	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
++		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
++	ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
++
++	return 0;
++}
++
++/*
++ * Perform a PHY calibration on RF5111/5112
++ */
++static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel)
++{
++	u32 i_pwr, q_pwr;
++	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (ah->ah_calibration == false ||
++			ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
++		goto done;
++
++	ah->ah_calibration = false;
++
++	iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
++	i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
++	q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
++	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
++	q_coffd = q_pwr >> 6;
++
++	if (i_coffd == 0 || q_coffd == 0)
++		goto done;
++
++	i_coff = ((-iq_corr) / i_coffd) & 0x3f;
++	q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f;
++
++	/* Commit new IQ value */
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
++		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
++
++done:
++	ath5k_hw_noise_floor_calibration(ah, channel->freq);
++
++	/* Request RF gain */
++	if (channel->val & CHANNEL_5GHZ) {
++		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
++			AR5K_PHY_PAPD_PROBE_TXPOWER) |
++			AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
++		ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED;
++	}
++
++	return 0;
++}
++
++/*
++ * Perform a PHY calibration
++ */
++int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel)
++{
++	int ret;
++
++	if (ah->ah_radio == AR5K_RF5110)
++		ret = ath5k_hw_rf5110_calibrate(ah, channel);
++	else
++		ret = ath5k_hw_rf511x_calibrate(ah, channel);
++
++	return ret;
++}
++
++int ath5k_hw_phy_disable(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	/*Just a try M.F.*/
++	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
++
++	return 0;
++}
++
++/********************\
++  Misc PHY functions
++\********************/
++
++/*
++ * Get the PHY Chip revision
++ */
++u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
++{
++	unsigned int i;
++	u32 srev;
++	u16 ret;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/*
++	 * Set the radio chip access register
++	 */
++	switch (chan) {
++	case CHANNEL_2GHZ:
++		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
++		break;
++	case CHANNEL_5GHZ:
++		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
++		break;
++	default:
++		return 0;
++	}
++
++	mdelay(2);
++
++	/* ...wait until PHY is ready and read the selected radio revision */
++	ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
++
++	for (i = 0; i < 8; i++)
++		ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
++
++	if (ah->ah_version == AR5K_AR5210) {
++		srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
++		ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
++	} else {
++		srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
++		ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
++				((srev & 0x0f) << 4), 8);
++	}
++
++	/* Reset to the 5GHz mode */
++	ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
++
++	return ret;
++}
++
++void /*TODO:Boundary check*/
++ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	/*Just a try M.F.*/
++	if (ah->ah_version != AR5K_AR5210)
++		ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
++}
++
++unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	/*Just a try M.F.*/
++	if (ah->ah_version != AR5K_AR5210)
++		return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
++
++	return false; /*XXX: What do we return for 5210 ?*/
++}
++
++/*
++ * TX power setup
++ */
++
++/*
++ * Initialize the tx power table (not fully implemented)
++ */
++static void ath5k_txpower_table(struct ath5k_hw *ah,
++		struct ieee80211_channel *channel, s16 max_power)
++{
++	unsigned int i, min, max, n;
++	u16 txpower, *rates;
++
++	rates = ah->ah_txpower.txp_rates;
++
++	txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2;
++	if (max_power > txpower)
++		txpower = max_power > AR5K_TUNE_MAX_TXPOWER ?
++		    AR5K_TUNE_MAX_TXPOWER : max_power;
++
++	for (i = 0; i < AR5K_MAX_RATES; i++)
++		rates[i] = txpower;
++
++	/* XXX setup target powers by rate */
++
++	ah->ah_txpower.txp_min = rates[7];
++	ah->ah_txpower.txp_max = rates[0];
++	ah->ah_txpower.txp_ofdm = rates[0];
++
++	/* Calculate the power table */
++	n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac);
++	min = AR5K_EEPROM_PCDAC_START;
++	max = AR5K_EEPROM_PCDAC_STOP;
++	for (i = 0; i < n; i += AR5K_EEPROM_PCDAC_STEP)
++		ah->ah_txpower.txp_pcdac[i] =
++#ifdef notyet
++		min + ((i * (max - min)) / n);
++#else
++		min;
++#endif
++}
++
++/*
++ * Set transmition power
++ */
++int /*O.K. - txpower_table is unimplemented so this doesn't work*/
++ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
++		unsigned int txpower)
++{
++	bool tpc = ah->ah_txpower.txp_tpc;
++	unsigned int i;
++
++	ATH5K_TRACE(ah->ah_sc);
++	if (txpower > AR5K_TUNE_MAX_TXPOWER) {
++		ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
++		return -EINVAL;
++	}
++
++	/* Reset TX power values */
++	memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
++	ah->ah_txpower.txp_tpc = tpc;
++
++	/* Initialize TX power table */
++	ath5k_txpower_table(ah, channel, txpower);
++
++	/*
++	 * Write TX power values
++	 */
++	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
++		ath5k_hw_reg_write(ah,
++			((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) |
++			(((ah->ah_txpower.txp_pcdac[(i << 1)    ] << 8) | 0xff) & 0xffff),
++			AR5K_PHY_PCDAC_TXPOWER(i));
++	}
++
++	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
++		AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
++		AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
++
++	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
++		AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
++		AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
++
++	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
++		AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
++		AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
++
++	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
++		AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
++		AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
++
++	if (ah->ah_txpower.txp_tpc == true)
++		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
++			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
++	else
++		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
++			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
++
++	return 0;
++}
++
++int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power)
++{
++	/*Just a try M.F.*/
++	struct ieee80211_channel *channel = &ah->ah_current_channel;
++
++	ATH5K_TRACE(ah->ah_sc);
++	ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER,
++		"changing txpower to %d\n", power);
++
++	return ath5k_hw_txpower(ah, channel, power);
++}
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/ath5k.h
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/ath5k.h	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,1153 @@
++/*
++ * Copyright (c) 2004-2007 Reyk Floeter <reyk at openbsd.org>
++ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm at gmail.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef _ATH5K_H
++#define _ATH5K_H
++
++/* Set this to 1 to disable regulatory domain restrictions for channel tests.
++ * WARNING: This is for debuging only and has side effects (eg. scan takes too
++ * long and results timeouts). It's also illegal to tune to some of the
++ * supported frequencies in some countries, so use this at your own risk,
++ * you've been warned. */
++#define CHAN_DEBUG	0
++
++#include <linux/io.h>
++#include <linux/types.h>
++#include <net/mac80211.h>
++
++#include "hw.h"
++#include "regdom.h"
++
++/* PCI IDs */
++#define PCI_DEVICE_ID_ATHEROS_AR5210 		0x0007 /* AR5210 */
++#define PCI_DEVICE_ID_ATHEROS_AR5311 		0x0011 /* AR5311 */
++#define PCI_DEVICE_ID_ATHEROS_AR5211 		0x0012 /* AR5211 */
++#define PCI_DEVICE_ID_ATHEROS_AR5212 		0x0013 /* AR5212 */
++#define PCI_DEVICE_ID_3COM_3CRDAG675 		0x0013 /* 3CRDAG675 (Atheros AR5212) */
++#define PCI_DEVICE_ID_3COM_2_3CRPAG175 		0x0013 /* 3CRPAG175 (Atheros AR5212) */
++#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 	0x0207 /* AR5210 (Early) */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM	0x1014 /* AR5212 (IBM MiniPCI) */
++#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 	0x1107 /* AR5210 (no eeprom) */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 	0x1113 /* AR5212 (no eeprom) */
++#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 	0x1112 /* AR5211 (no eeprom) */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 	0xf013 /* AR5212 (emulation board) */
++#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 	0xff12 /* AR5211 (emulation board) */
++#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 	0xf11b /* AR5211 (emulation board) */
++#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 	0x0052 /* AR5312 WMAC (AP31) */
++#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 	0x0057 /* AR5312 WMAC (AP30-040) */
++#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 	0x0058 /* AR5312 WMAC (AP43-030) */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 	0x0014 /* AR5212 compatible */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 	0x0015 /* AR5212 compatible */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 	0x0016 /* AR5212 compatible */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 	0x0017 /* AR5212 compatible */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 	0x0018 /* AR5212 compatible */
++#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 	0x0019 /* AR5212 compatible */
++#define PCI_DEVICE_ID_ATHEROS_AR2413 		0x001a /* AR2413 (Griffin-lite) */
++#define PCI_DEVICE_ID_ATHEROS_AR5413 		0x001b /* AR5413 (Eagle) */
++#define PCI_DEVICE_ID_ATHEROS_AR5424 		0x001c /* AR5424 (Condor PCI-E) */
++#define PCI_DEVICE_ID_ATHEROS_AR5416 		0x0023 /* AR5416 */
++#define PCI_DEVICE_ID_ATHEROS_AR5418 		0x0024 /* AR5418 */
++
++/****************************\
++  GENERIC DRIVER DEFINITIONS
++\****************************/
++
++#define ATH5K_PRINTF(fmt, ...)   printk("%s: " fmt, __func__, ##__VA_ARGS__)
++
++#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \
++	printk(_level "ath5k %s: " _fmt, \
++		((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \
++		##__VA_ARGS__)
++
++#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \
++	if (net_ratelimit()) \
++		ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \
++	} while (0)
++
++#define ATH5K_INFO(_sc, _fmt, ...) \
++	ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__)
++
++#define ATH5K_WARN(_sc, _fmt, ...) \
++	ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__)
++
++#define ATH5K_ERR(_sc, _fmt, ...) \
++	ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__)
++
++/*
++ * Some tuneable values (these should be changeable by the user)
++ */
++#define AR5K_TUNE_DMA_BEACON_RESP		2
++#define AR5K_TUNE_SW_BEACON_RESP		10
++#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF	0
++#define AR5K_TUNE_RADAR_ALERT			false
++#define AR5K_TUNE_MIN_TX_FIFO_THRES		1
++#define AR5K_TUNE_MAX_TX_FIFO_THRES		((IEEE80211_MAX_LEN / 64) + 1)
++#define AR5K_TUNE_REGISTER_TIMEOUT		20000
++/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
++ * be the max value. */
++#define AR5K_TUNE_RSSI_THRES                   129
++/* This must be set when setting the RSSI threshold otherwise it can
++ * prevent a reset. If AR5K_RSSI_THR is read after writing to it
++ * the BMISS_THRES will be seen as 0, seems harware doesn't keep
++ * track of it. Max value depends on harware. For AR5210 this is just 7.
++ * For AR5211+ this seems to be up to 255. */
++#define AR5K_TUNE_BMISS_THRES                  7
++#define AR5K_TUNE_REGISTER_DWELL_TIME		20000
++#define AR5K_TUNE_BEACON_INTERVAL		100
++#define AR5K_TUNE_AIFS				2
++#define AR5K_TUNE_AIFS_11B			2
++#define AR5K_TUNE_AIFS_XR			0
++#define AR5K_TUNE_CWMIN				15
++#define AR5K_TUNE_CWMIN_11B			31
++#define AR5K_TUNE_CWMIN_XR			3
++#define AR5K_TUNE_CWMAX				1023
++#define AR5K_TUNE_CWMAX_11B			1023
++#define AR5K_TUNE_CWMAX_XR			7
++#define AR5K_TUNE_NOISE_FLOOR			-72
++#define AR5K_TUNE_MAX_TXPOWER			60
++#define AR5K_TUNE_DEFAULT_TXPOWER		30
++#define AR5K_TUNE_TPC_TXPOWER			true
++#define AR5K_TUNE_ANT_DIVERSITY			true
++#define AR5K_TUNE_HWTXTRIES			4
++
++/* token to use for aifs, cwmin, cwmax in MadWiFi */
++#define	AR5K_TXQ_USEDEFAULT	((u32) -1)
++
++/* GENERIC CHIPSET DEFINITIONS */
++
++/* MAC Chips */
++enum ath5k_version {
++	AR5K_AR5210	= 0,
++	AR5K_AR5211	= 1,
++	AR5K_AR5212	= 2,
++};
++
++/* PHY Chips */
++enum ath5k_radio {
++	AR5K_RF5110	= 0,
++	AR5K_RF5111	= 1,
++	AR5K_RF5112	= 2,
++	AR5K_RF5413	= 3,
++};
++
++/*
++ * Common silicon revision/version values
++ */
++
++enum ath5k_srev_type {
++	AR5K_VERSION_VER,
++	AR5K_VERSION_RAD,
++};
++
++struct ath5k_srev_name {
++	const char		*sr_name;
++	enum ath5k_srev_type	sr_type;
++	u_int			sr_val;
++};
++
++#define AR5K_SREV_UNKNOWN	0xffff
++
++#define AR5K_SREV_VER_AR5210	0x00
++#define AR5K_SREV_VER_AR5311	0x10
++#define AR5K_SREV_VER_AR5311A	0x20
++#define AR5K_SREV_VER_AR5311B	0x30
++#define AR5K_SREV_VER_AR5211	0x40
++#define AR5K_SREV_VER_AR5212	0x50
++#define AR5K_SREV_VER_AR5213	0x55
++#define AR5K_SREV_VER_AR5213A	0x59
++#define AR5K_SREV_VER_AR2424	0xa0
++#define AR5K_SREV_VER_AR5424	0xa3
++#define AR5K_SREV_VER_AR5413	0xa4
++#define AR5K_SREV_VER_AR5414	0xa5
++#define AR5K_SREV_VER_AR5416	0xc0	/* ? */
++#define AR5K_SREV_VER_AR5418	0xca
++
++#define AR5K_SREV_RAD_5110	0x00
++#define AR5K_SREV_RAD_5111	0x10
++#define AR5K_SREV_RAD_5111A	0x15
++#define AR5K_SREV_RAD_2111	0x20
++#define AR5K_SREV_RAD_5112	0x30
++#define AR5K_SREV_RAD_5112A	0x35
++#define AR5K_SREV_RAD_2112	0x40
++#define AR5K_SREV_RAD_2112A	0x45
++#define AR5K_SREV_RAD_SC1	0x63	/* Found on 5413/5414 */
++#define AR5K_SREV_RAD_SC2	0xa2	/* Found on 2424/5424 */
++#define AR5K_SREV_RAD_5133	0xc0	/* MIMO found on 5418 */
++
++/* IEEE defs */
++
++#define IEEE80211_MAX_LEN       2500
++
++/* TODO add support to mac80211 for vendor-specific rates and modes */
++
++/*
++ * Some of this information is based on Documentation from:
++ *
++ * http://madwifi.org/wiki/ChipsetFeatures/SuperAG
++ *
++ * Modulation for Atheros' eXtended Range - range enhancing extension that is
++ * supposed to double the distance an Atheros client device can keep a
++ * connection with an Atheros access point. This is achieved by increasing
++ * the receiver sensitivity up to, -105dBm, which is about 20dB above what
++ * the 802.11 specifications demand. In addition, new (proprietary) data rates
++ * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
++ *
++ * Please note that can you either use XR or TURBO but you cannot use both,
++ * they are exclusive.
++ *
++ */
++#define MODULATION_XR 		0x00000200
++/*
++ * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
++ * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
++ * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
++ * channels. To use this feature your Access Point must also suport it.
++ * There is also a distinction between "static" and "dynamic" turbo modes:
++ *
++ * - Static: is the dumb version: devices set to this mode stick to it until
++ *     the mode is turned off.
++ * - Dynamic: is the intelligent version, the network decides itself if it
++ *     is ok to use turbo. As soon as traffic is detected on adjacent channels
++ *     (which would get used in turbo mode), or when a non-turbo station joins
++ *     the network, turbo mode won't be used until the situation changes again.
++ *     Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which
++ *     monitors the used radio band in order to decide whether turbo mode may
++ *     be used or not.
++ *
++ * This article claims Super G sticks to bonding of channels 5 and 6 for
++ * USA:
++ *
++ * http://www.pcworld.com/article/id,113428-page,1/article.html
++ *
++ * The channel bonding seems to be driver specific though. In addition to
++ * deciding what channels will be used, these "Turbo" modes are accomplished
++ * by also enabling the following features:
++ *
++ * - Bursting: allows multiple frames to be sent at once, rather than pausing
++ *     after each frame. Bursting is a standards-compliant feature that can be
++ *     used with any Access Point.
++ * - Fast frames: increases the amount of information that can be sent per
++ *     frame, also resulting in a reduction of transmission overhead. It is a
++ *     proprietary feature that needs to be supported by the Access Point.
++ * - Compression: data frames are compressed in real time using a Lempel Ziv
++ *     algorithm. This is done transparently. Once this feature is enabled,
++ *     compression and decompression takes place inside the chipset, without
++ *     putting additional load on the host CPU.
++ *
++ */
++#define MODULATION_TURBO	0x00000080
++
++enum ath5k_vendor_mode {
++	MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1,
++	MODE_ATHEROS_TURBOG
++};
++
++/* Number of supported mac80211 enum ieee80211_phymode modes by this driver */
++#define NUM_DRIVER_MODES	3
++
++/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */
++#define AR5K_SET_SHORT_PREAMBLE 0x04
++
++#define HAS_SHPREAMBLE(_ix) (rt->rates[_ix].modulation == IEEE80211_RATE_CCK_2)
++#define SHPREAMBLE_FLAG(_ix) (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0)
++
++/****************\
++  TX DEFINITIONS
++\****************/
++
++/*
++ * Tx Descriptor
++ */
++struct ath5k_tx_status {
++	u16	ts_seqnum;
++	u16	ts_tstamp;
++	u8	ts_status;
++	u8	ts_rate;
++	s8	ts_rssi;
++	u8	ts_shortretry;
++	u8	ts_longretry;
++	u8	ts_virtcol;
++	u8	ts_antenna;
++};
++
++#define AR5K_TXSTAT_ALTRATE	0x80
++#define AR5K_TXERR_XRETRY	0x01
++#define AR5K_TXERR_FILT		0x02
++#define AR5K_TXERR_FIFO		0x04
++
++/*
++ * Queue types used to classify tx queues.
++ */
++enum ath5k_tx_queue {
++	AR5K_TX_QUEUE_INACTIVE = 0, /* q is unused -- see ath5k_hw_release_tx_queue */
++	AR5K_TX_QUEUE_DATA,	  /*A normal data queue*/
++	AR5K_TX_QUEUE_XR_DATA,	  /*An XR-data queue*/
++	AR5K_TX_QUEUE_BEACON,	  /*The beacon queue*/
++	AR5K_TX_QUEUE_CAB,	  /*The ater-beacon queue*/
++	AR5K_TX_QUEUE_UAPSD,	  /*Unscheduled Automatic Power Save Delivery queue*/
++};
++
++#define	AR5K_NUM_TX_QUEUES		10
++#define	AR5K_NUM_TX_QUEUES_NOQCU	2
++
++/*
++ * Queue syb-types to classify normal data queues.
++ * These are the 4 Access Categories as defined in
++ * WME spec. 0 is the lowest priority and 4 is the
++ * highest. Normal data that hasn't been classified
++ * goes to the Best Effort AC.
++ */
++enum ath5k_tx_queue_subtype {
++	AR5K_WME_AC_BK = 0,	/*Background traffic*/
++	AR5K_WME_AC_BE, 	/*Best-effort (normal) traffic)*/
++	AR5K_WME_AC_VI, 	/*Video traffic*/
++	AR5K_WME_AC_VO, 	/*Voice traffic*/
++};
++
++/*
++ * Queue ID numbers as returned by the hw functions, each number
++ * represents a hw queue. If hw does not support hw queues
++ * (eg 5210) all data goes in one queue. These match
++ * d80211 definitions (net80211/MadWiFi don't use them).
++ */
++enum ath5k_tx_queue_id {
++	AR5K_TX_QUEUE_ID_NOQCU_DATA	= 0,
++	AR5K_TX_QUEUE_ID_NOQCU_BEACON	= 1,
++	AR5K_TX_QUEUE_ID_DATA_MIN	= 0, /*IEEE80211_TX_QUEUE_DATA0*/
++	AR5K_TX_QUEUE_ID_DATA_MAX	= 4, /*IEEE80211_TX_QUEUE_DATA4*/
++	AR5K_TX_QUEUE_ID_DATA_SVP	= 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/
++	AR5K_TX_QUEUE_ID_CAB		= 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/
++	AR5K_TX_QUEUE_ID_BEACON		= 7, /*IEEE80211_TX_QUEUE_BEACON*/
++	AR5K_TX_QUEUE_ID_UAPSD		= 8,
++	AR5K_TX_QUEUE_ID_XR_DATA	= 9,
++};
++
++
++/*
++ * Flags to set hw queue's parameters...
++ */
++#define AR5K_TXQ_FLAG_TXOKINT_ENABLE		0x0001	/* Enable TXOK interrupt */
++#define AR5K_TXQ_FLAG_TXERRINT_ENABLE		0x0002	/* Enable TXERR interrupt */
++#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE		0x0004	/* Enable TXEOL interrupt -not used- */
++#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE		0x0008	/* Enable TXDESC interrupt -not used- */
++#define AR5K_TXQ_FLAG_TXURNINT_ENABLE		0x0010	/* Enable TXURN interrupt */
++#define AR5K_TXQ_FLAG_BACKOFF_DISABLE		0x0020	/* Disable random post-backoff */
++#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE	0x0040	/* Enable ready time expiry policy (?)*/
++#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE	0x0080	/* Enable backoff while bursting */
++#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS		0x0100	/* Disable backoff while bursting */
++#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE	0x0200	/* Enable hw compression -not implemented-*/
++
++/*
++ * A struct to hold tx queue's parameters
++ */
++struct ath5k_txq_info {
++	enum ath5k_tx_queue tqi_type;
++	enum ath5k_tx_queue_subtype tqi_subtype;
++	u16	tqi_flags;	/* Tx queue flags (see above) */
++	u32	tqi_aifs;	/* Arbitrated Interframe Space */
++	s32	tqi_cw_min;	/* Minimum Contention Window */
++	s32	tqi_cw_max;	/* Maximum Contention Window */
++	u32	tqi_cbr_period; /* Constant bit rate period */
++	u32	tqi_cbr_overflow_limit;
++	u32	tqi_burst_time;
++	u32	tqi_ready_time; /* Not used */
++};
++
++/*
++ * Transmit packet types.
++ * These are not fully used inside OpenHAL yet
++ */
++enum ath5k_pkt_type {
++	AR5K_PKT_TYPE_NORMAL		= 0,
++	AR5K_PKT_TYPE_ATIM		= 1,
++	AR5K_PKT_TYPE_PSPOLL		= 2,
++	AR5K_PKT_TYPE_BEACON		= 3,
++	AR5K_PKT_TYPE_PROBE_RESP	= 4,
++	AR5K_PKT_TYPE_PIFS		= 5,
++};
++
++/*
++ * TX power and TPC settings
++ */
++#define AR5K_TXPOWER_OFDM(_r, _v)	(			\
++	((0 & 1) << ((_v) + 6)) |				\
++	(((ah->ah_txpower.txp_rates[(_r)]) & 0x3f) << (_v))	\
++)
++
++#define AR5K_TXPOWER_CCK(_r, _v)	(			\
++	(ah->ah_txpower.txp_rates[(_r)] & 0x3f) << (_v)	\
++)
++
++/*
++ * DMA size definitions (2^n+2)
++ */
++enum ath5k_dmasize {
++	AR5K_DMASIZE_4B	= 0,
++	AR5K_DMASIZE_8B,
++	AR5K_DMASIZE_16B,
++	AR5K_DMASIZE_32B,
++	AR5K_DMASIZE_64B,
++	AR5K_DMASIZE_128B,
++	AR5K_DMASIZE_256B,
++	AR5K_DMASIZE_512B
++};
++
++
++/****************\
++  RX DEFINITIONS
++\****************/
++
++/*
++ * Rx Descriptor
++ */
++struct ath5k_rx_status {
++	u16	rs_datalen;
++	u16	rs_tstamp;
++	u8	rs_status;
++	u8	rs_phyerr;
++	s8	rs_rssi;
++	u8	rs_keyix;
++	u8	rs_rate;
++	u8	rs_antenna;
++	u8	rs_more;
++};
++
++#define AR5K_RXERR_CRC		0x01
++#define AR5K_RXERR_PHY		0x02
++#define AR5K_RXERR_FIFO		0x04
++#define AR5K_RXERR_DECRYPT	0x08
++#define AR5K_RXERR_MIC		0x10
++#define AR5K_RXKEYIX_INVALID	((u8) - 1)
++#define AR5K_TXKEYIX_INVALID	((u32) - 1)
++
++struct ath5k_mib_stats {
++	u32	ackrcv_bad;
++	u32	rts_bad;
++	u32	rts_good;
++	u32	fcs_bad;
++	u32	beacons;
++};
++
++
++
++
++/**************************\
++ BEACON TIMERS DEFINITIONS
++\**************************/
++
++#define AR5K_BEACON_PERIOD	0x0000ffff
++#define AR5K_BEACON_ENA		0x00800000 /*enable beacon xmit*/
++#define AR5K_BEACON_RESET_TSF	0x01000000 /*force a TSF reset*/
++
++/*
++ * Per-station beacon timer state.
++ */
++struct ath5k_beacon_state {
++	u32	bs_next_beacon;
++	u32	bs_next_dtim;
++	u32	bs_interval;		/*in TU's -see net80211/ieee80211_var.h-
++						can also include the above flags*/
++	u8	bs_dtim_period;
++	u8	bs_cfp_period;
++	u16	bs_cfp_max_duration;	/*if non-zero hw is setup to coexist with
++						a Point Coordination Function capable AP*/
++	u16	bs_cfp_du_remain;
++	u16	bs_tim_offset;
++	u16	bs_sleep_duration;
++	u16	bs_bmiss_threshold;
++	u32  	bs_cfp_next;
++};
++
++
++
++
++/********************\
++  COMMON DEFINITIONS
++\********************/
++
++/*
++ * Atheros descriptor
++ */
++struct ath5k_desc {
++	u32	ds_link;
++	u32	ds_data;
++	u32	ds_ctl0;
++	u32	ds_ctl1;
++	u32	ds_hw[4];
++
++	union {
++		struct ath5k_rx_status rx;
++		struct ath5k_tx_status tx;
++	} ds_us;
++
++#define ds_rxstat ds_us.rx
++#define ds_txstat ds_us.tx
++
++} __packed;
++
++#define AR5K_RXDESC_INTREQ	0x0020
++
++#define AR5K_TXDESC_CLRDMASK	0x0001
++#define AR5K_TXDESC_NOACK	0x0002	/*[5211+]*/
++#define AR5K_TXDESC_RTSENA	0x0004
++#define AR5K_TXDESC_CTSENA	0x0008
++#define AR5K_TXDESC_INTREQ	0x0010
++#define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
++
++#define AR5K_SLOT_TIME_9	396
++#define AR5K_SLOT_TIME_20	880
++#define AR5K_SLOT_TIME_MAX	0xffff
++
++/* channel_flags */
++#define	CHANNEL_CW_INT	0x0008	/* Contention Window interference detected */
++#define	CHANNEL_TURBO	0x0010	/* Turbo Channel */
++#define	CHANNEL_CCK	0x0020	/* CCK channel */
++#define	CHANNEL_OFDM	0x0040	/* OFDM channel */
++#define	CHANNEL_2GHZ	0x0080	/* 2GHz channel. */
++#define	CHANNEL_5GHZ	0x0100	/* 5GHz channel */
++#define	CHANNEL_PASSIVE	0x0200	/* Only passive scan allowed */
++#define	CHANNEL_DYN	0x0400	/* Dynamic CCK-OFDM channel (for g operation) */
++#define	CHANNEL_XR	0x0800	/* XR channel */
++
++#define	CHANNEL_A	(CHANNEL_5GHZ|CHANNEL_OFDM)
++#define	CHANNEL_B	(CHANNEL_2GHZ|CHANNEL_CCK)
++#define	CHANNEL_G	(CHANNEL_2GHZ|CHANNEL_OFDM)
++#define	CHANNEL_T	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
++#define	CHANNEL_TG	(CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
++#define	CHANNEL_108A	CHANNEL_T
++#define	CHANNEL_108G	CHANNEL_TG
++#define	CHANNEL_X	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
++
++#define	CHANNEL_ALL 	(CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \
++		CHANNEL_TURBO)
++
++#define	CHANNEL_ALL_NOTURBO 	(CHANNEL_ALL & ~CHANNEL_TURBO)
++#define CHANNEL_MODES		CHANNEL_ALL
++
++/*
++ * Used internaly in OpenHAL (ar5211.c/ar5212.c
++ * for reset_tx_queue). Also see struct struct ieee80211_channel.
++ */
++#define IS_CHAN_XR(_c)	((_c.val & CHANNEL_XR) != 0)
++#define IS_CHAN_B(_c)	((_c.val & CHANNEL_B) != 0)
++
++/*
++ * The following structure will be used to map 2GHz channels to
++ * 5GHz Atheros channels.
++ */
++struct ath5k_athchan_2ghz {
++	u32	a2_flags;
++	u16	a2_athchan;
++};
++
++/*
++ * Rate definitions
++ * TODO: Clean them up or move them on mac80211 -most of these infos are
++ * 	 used by the rate control algorytm on MadWiFi.
++ */
++
++/* Max number of rates on the rate table and what it seems
++ * Atheros hardware supports */
++#define AR5K_MAX_RATES 32
++
++/**
++ * struct ath5k_rate - rate structure
++ * @valid: is this a valid rate for the current mode
++ * @modulation: respective mac80211 modulation
++ * @rate_kbps: rate in kbit/s
++ * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on
++ *     &struct ath5k_rx_status.rs_rate and on TX on
++ *     &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports
++ *     up to 32 rates, indexed by 1-32. This means we really only need
++ *     6 bits for the rate_code.
++ * @dot11_rate: respective IEEE-802.11 rate value
++ * @control_rate: index of rate assumed to be used to send control frames.
++ *     This can be used to set override the value on the rate duration
++ *     registers. This is only useful if we can override in the harware at
++ *     what rate we want to send control frames at. Note that IEEE-802.11
++ *     Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we
++ *     should send ACK/CTS, if we change this value we can be breaking
++ *     the spec.
++ *
++ * This structure is used to get the RX rate or set the TX rate on the
++ * hardware descriptors. It is also used for internal modulation control
++ * and settings.
++ *
++ * On RX after the &struct ath5k_desc is parsed by the appropriate
++ * ah_proc_rx_desc() the respective hardware rate value is set in
++ * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in
++ * &struct ath5k_tx_status.ts_rate which is later used to setup the
++ * &struct ath5k_desc correctly. This is the hardware rate map we are
++ * aware of:
++ *
++ * rate_code   1       2       3       4       5       6       7       8
++ * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
++ *
++ * rate_code   9       10      11      12      13      14      15      16
++ * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
++ *
++ * rate_code   17      18      19      20      21      22      23      24
++ * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
++ *
++ * rate_code   25      26      27      28      29      30      31      32
++ * rate_kbps   5500    2000    1000    ?       ?       ?       ?       ?
++ *
++ */
++struct ath5k_rate {
++	u8	valid;
++	u32	modulation;
++	u16	rate_kbps;
++	u8	rate_code;
++	u8	dot11_rate;
++	u8	control_rate;
++};
++
++/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */
++struct ath5k_rate_table {
++	u16	rate_count;
++	u8	rate_code_to_index[AR5K_MAX_RATES];	/* Back-mapping */
++	struct ath5k_rate rates[AR5K_MAX_RATES];
++};
++
++/*
++ * Rate tables...
++ */
++#define AR5K_RATES_11A { 8, {					\
++	255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0,	\
++	7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255,	\
++	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
++	{ 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 0 },		\
++	{ 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 0 },		\
++	{ 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 2 },		\
++	{ 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 2 },		\
++	{ 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 4 },		\
++	{ 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 4 },		\
++	{ 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 4 },		\
++	{ 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 4 } }		\
++}
++
++#define AR5K_RATES_11B { 4, {						\
++	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,	\
++	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,	\
++	3, 2, 1, 0, 255, 255, 255, 255 }, {				\
++	{ 1, IEEE80211_RATE_CCK, 1000, 27, 130, 0 },	\
++	{ 1, IEEE80211_RATE_CCK_2, 2000, 26, 132, 1 },	\
++	{ 1, IEEE80211_RATE_CCK_2, 5500, 25, 139, 1 },	\
++	{ 1, IEEE80211_RATE_CCK_2, 11000, 24, 150, 1 } }	\
++}
++
++#define AR5K_RATES_11G { 12, {					\
++	255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4,	\
++	11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255,	\
++	3, 2, 1, 0, 255, 255, 255, 255 }, {			\
++	{ 1, IEEE80211_RATE_CCK, 1000, 27, 2, 0 },		\
++	{ 1, IEEE80211_RATE_CCK_2, 2000, 26, 4, 1 },		\
++	{ 1, IEEE80211_RATE_CCK_2, 5500, 25, 11, 1 },		\
++	{ 1, IEEE80211_RATE_CCK_2, 11000, 24, 22, 1 },	\
++	{ 0, IEEE80211_RATE_OFDM, 6000, 11, 12, 4 },	\
++	{ 0, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 },	\
++	{ 1, IEEE80211_RATE_OFDM, 12000, 10, 24, 6 },	\
++	{ 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 },	\
++	{ 1, IEEE80211_RATE_OFDM, 24000, 9, 48, 8 },	\
++	{ 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 },	\
++	{ 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 },	\
++	{ 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } }	\
++}
++
++#define AR5K_RATES_TURBO { 8, {					\
++	255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0,	\
++	7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255,	\
++	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
++	{ 1, MODULATION_TURBO, 6000, 11, 140, 0 },	\
++	{ 1, MODULATION_TURBO, 9000, 15, 18, 0 },	\
++	{ 1, MODULATION_TURBO, 12000, 10, 152, 2 },	\
++	{ 1, MODULATION_TURBO, 18000, 14, 36, 2 },	\
++	{ 1, MODULATION_TURBO, 24000, 9, 176, 4 },	\
++	{ 1, MODULATION_TURBO, 36000, 13, 72, 4 },	\
++	{ 1, MODULATION_TURBO, 48000, 8, 96, 4 },	\
++	{ 1, MODULATION_TURBO, 54000, 12, 108, 4 } }	\
++}
++
++#define AR5K_RATES_XR { 12, {					\
++	255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4,		\
++	11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255,	\
++	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
++	{ 1, MODULATION_XR, 500, 7, 129, 0 },		\
++	{ 1, MODULATION_XR, 1000, 2, 139, 1 },		\
++	{ 1, MODULATION_XR, 2000, 6, 150, 2 },		\
++	{ 1, MODULATION_XR, 3000, 1, 150, 3 },		\
++	{ 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 4 },	\
++	{ 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 },	\
++	{ 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 6 },	\
++	{ 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 },	\
++	{ 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 8 },	\
++	{ 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 },	\
++	{ 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 },	\
++	{ 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } }	\
++}
++
++/*
++ * Crypto definitions
++ */
++
++#define AR5K_KEYCACHE_SIZE	8
++
++/***********************\
++ HW RELATED DEFINITIONS
++\***********************/
++
++/*
++ * Misc definitions
++ */
++#define	AR5K_RSSI_EP_MULTIPLIER	(1<<7)
++
++#define AR5K_ASSERT_ENTRY(_e, _s) do {		\
++	if (_e >= _s)				\
++		return (false);			\
++} while (0)
++
++
++enum ath5k_ant_setting {
++	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
++	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
++	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
++	AR5K_ANT_MAX		= 3,
++};
++
++/*
++ * Hardware interrupt abstraction
++ */
++
++/**
++ * enum ath5k_int - Hardware interrupt masks helpers
++ *
++ * @AR5K_INT_RX: mask to identify received frame interrupts, of type
++ * 	AR5K_ISR_RXOK or AR5K_ISR_RXERR
++ * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
++ * @AR5K_INT_RXNOFRM: No frame received (?)
++ * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
++ * 	Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
++ * 	LinkPtr is NULL. For more details, refer to:
++ * 	http://www.freepatentsonline.com/20030225739.html
++ * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
++ * 	Note that Rx overrun is not always fatal, on some chips we can continue
++ * 	operation without reseting the card, that's why int_fatal is not
++ * 	common for all chips.
++ * @AR5K_INT_TX: mask to identify received frame interrupts, of type
++ * 	AR5K_ISR_TXOK or AR5K_ISR_TXERR
++ * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
++ * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
++ * 	We currently do increments on interrupt by
++ * 	(AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
++ * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
++ * 	checked. We should do this with ath5k_hw_update_mib_counters() but
++ * 	it seems we should also then do some noise immunity work.
++ * @AR5K_INT_RXPHY: RX PHY Error
++ * @AR5K_INT_RXKCM: ??
++ * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
++ * 	beacon that must be handled in software. The alternative is if you
++ * 	have VEOL support, in that case you let the hardware deal with things.
++ * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
++ * 	beacons from the AP have associated with, we should probably try to
++ * 	reassociate. When in IBSS mode this might mean we have not received
++ * 	any beacons from any local stations. Note that every station in an
++ * 	IBSS schedules to send beacons at the Target Beacon Transmission Time
++ * 	(TBTT) with a random backoff.
++ * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
++ * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
++ * 	until properly handled
++ * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
++ * 	errors. These types of errors we can enable seem to be of type
++ * 	AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
++ * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER
++ * @AR5K_INT_NOCARD: signals the card has been removed
++ * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
++ * 	bit value
++ *
++ * These are mapped to take advantage of some common bits
++ * between the MACs, to be able to set intr properties
++ * easier. Some of them are not used yet inside hw.c. Most map
++ * to the respective hw interrupt value as they are common amogst different
++ * MACs.
++ */
++enum ath5k_int {
++	AR5K_INT_RX	= 0x00000001, /* Not common */
++	AR5K_INT_RXDESC	= 0x00000002,
++	AR5K_INT_RXNOFRM = 0x00000008,
++	AR5K_INT_RXEOL	= 0x00000010,
++	AR5K_INT_RXORN	= 0x00000020,
++	AR5K_INT_TX	= 0x00000040, /* Not common */
++	AR5K_INT_TXDESC	= 0x00000080,
++	AR5K_INT_TXURN	= 0x00000800,
++	AR5K_INT_MIB	= 0x00001000,
++	AR5K_INT_RXPHY	= 0x00004000,
++	AR5K_INT_RXKCM	= 0x00008000,
++	AR5K_INT_SWBA	= 0x00010000,
++	AR5K_INT_BMISS	= 0x00040000,
++	AR5K_INT_BNR	= 0x00100000, /* Not common */
++	AR5K_INT_GPIO	= 0x01000000,
++	AR5K_INT_FATAL	= 0x40000000, /* Not common */
++	AR5K_INT_GLOBAL	= 0x80000000,
++
++	AR5K_INT_COMMON  = AR5K_INT_RXNOFRM
++			| AR5K_INT_RXDESC
++			| AR5K_INT_RXEOL
++			| AR5K_INT_RXORN
++			| AR5K_INT_TXURN
++			| AR5K_INT_TXDESC
++			| AR5K_INT_MIB
++			| AR5K_INT_RXPHY
++			| AR5K_INT_RXKCM
++			| AR5K_INT_SWBA
++			| AR5K_INT_BMISS
++			| AR5K_INT_GPIO,
++	AR5K_INT_NOCARD	= 0xffffffff
++};
++
++/*
++ * Power management
++ */
++enum ath5k_power_mode {
++	AR5K_PM_UNDEFINED = 0,
++	AR5K_PM_AUTO,
++	AR5K_PM_AWAKE,
++	AR5K_PM_FULL_SLEEP,
++	AR5K_PM_NETWORK_SLEEP,
++};
++
++/*
++ * These match net80211 definitions (not used in
++ * d80211).
++ */
++#define AR5K_LED_INIT	0 /*IEEE80211_S_INIT*/
++#define AR5K_LED_SCAN	1 /*IEEE80211_S_SCAN*/
++#define AR5K_LED_AUTH	2 /*IEEE80211_S_AUTH*/
++#define AR5K_LED_ASSOC	3 /*IEEE80211_S_ASSOC*/
++#define AR5K_LED_RUN	4 /*IEEE80211_S_RUN*/
++
++/* GPIO-controlled software LED */
++#define AR5K_SOFTLED_PIN	0
++#define AR5K_SOFTLED_ON		0
++#define AR5K_SOFTLED_OFF	1
++
++/*
++ * Chipset capabilities -see ath5k_hw_get_capability-
++ * get_capability function is not yet fully implemented
++ * in OpenHAL so most of these don't work yet...
++ */
++enum ath5k_capability_type {
++	AR5K_CAP_REG_DMN		= 0,	/* Used to get current reg. domain id */
++	AR5K_CAP_TKIP_MIC		= 2,	/* Can handle TKIP MIC in hardware */
++	AR5K_CAP_TKIP_SPLIT		= 3,	/* TKIP uses split keys */
++	AR5K_CAP_PHYCOUNTERS		= 4,	/* PHY error counters */
++	AR5K_CAP_DIVERSITY		= 5,	/* Supports fast diversity */
++	AR5K_CAP_NUM_TXQUEUES		= 6,	/* Used to get max number of hw txqueues */
++	AR5K_CAP_VEOL			= 7,	/* Supports virtual EOL */
++	AR5K_CAP_COMPRESSION		= 8,	/* Supports compression */
++	AR5K_CAP_BURST			= 9,	/* Supports packet bursting */
++	AR5K_CAP_FASTFRAME		= 10,	/* Supports fast frames */
++	AR5K_CAP_TXPOW			= 11,	/* Used to get global tx power limit */
++	AR5K_CAP_TPC			= 12,	/* Can do per-packet tx power control (needed for 802.11a) */
++	AR5K_CAP_BSSIDMASK		= 13,	/* Supports bssid mask */
++	AR5K_CAP_MCAST_KEYSRCH		= 14,	/* Supports multicast key search */
++	AR5K_CAP_TSF_ADJUST		= 15,	/* Supports beacon tsf adjust */
++	AR5K_CAP_XR			= 16,	/* Supports XR mode */
++	AR5K_CAP_WME_TKIPMIC 		= 17,	/* Supports TKIP MIC when using WMM */
++	AR5K_CAP_CHAN_HALFRATE 		= 18,	/* Supports half rate channels */
++	AR5K_CAP_CHAN_QUARTERRATE 	= 19,	/* Supports quarter rate channels */
++	AR5K_CAP_RFSILENT		= 20,	/* Supports RFsilent */
++};
++
++struct ath5k_capabilities {
++	/*
++	 * Supported PHY modes
++	 * (ie. CHANNEL_A, CHANNEL_B, ...)
++	 */
++	DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES);
++
++	/*
++	 * Frequency range (without regulation restrictions)
++	 */
++	struct {
++		u16	range_2ghz_min;
++		u16	range_2ghz_max;
++		u16	range_5ghz_min;
++		u16	range_5ghz_max;
++	} cap_range;
++
++	/*
++	 * Active regulation domain settings
++	 */
++	struct {
++		enum ath5k_regdom reg_current;
++		enum ath5k_regdom reg_hw;
++	} cap_regdomain;
++
++	/*
++	 * Values stored in the EEPROM (some of them...)
++	 */
++	struct ath5k_eeprom_info	cap_eeprom;
++
++	/*
++	 * Queue information
++	 */
++	struct {
++		u8	q_tx_num;
++	} cap_queues;
++};
++
++
++/***************************************\
++  HARDWARE ABSTRACTION LAYER STRUCTURE
++\***************************************/
++
++/*
++ * Misc defines
++ */
++
++#define AR5K_MAX_GPIO		10
++#define AR5K_MAX_RF_BANKS	8
++
++struct ath5k_hw {
++	u32			ah_magic;
++
++	struct ath5k_softc	*ah_sc;
++	void __iomem		*ah_iobase;
++
++	enum ath5k_int		ah_imr;
++
++	enum ieee80211_if_types	ah_op_mode;
++	enum ath5k_power_mode	ah_power_mode;
++	struct ieee80211_channel ah_current_channel;
++	/* Current BSSID we are trying to assoc to / creating, this
++	 * comes from ieee80211_if_conf. This is passed by mac80211 on
++	 * config_interface() */
++	u8			bssid[ETH_ALEN];
++	bool			ah_turbo;
++	bool			ah_calibration;
++	bool			ah_running;
++	bool			ah_single_chip;
++	enum ath5k_rfgain	ah_rf_gain;
++
++	u32			ah_mac_srev;
++	u16			ah_mac_version;
++	u16			ah_mac_revision;
++	u16			ah_phy_revision;
++	u16			ah_radio_5ghz_revision;
++	u16			ah_radio_2ghz_revision;
++
++	enum ath5k_version	ah_version;
++	enum ath5k_radio	ah_radio;
++	u32			ah_phy;
++
++	bool			ah_5ghz;
++	bool			ah_2ghz;
++
++#define ah_regdomain		ah_capabilities.cap_regdomain.reg_current
++#define ah_regdomain_hw		ah_capabilities.cap_regdomain.reg_hw
++#define ah_modes		ah_capabilities.cap_mode
++#define ah_ee_version		ah_capabilities.cap_eeprom.ee_version
++
++	u32			ah_atim_window;
++	u32			ah_aifs;
++	u32			ah_cw_min;
++	u32			ah_cw_max;
++	bool			ah_software_retry;
++	u32			ah_limit_tx_retries;
++
++	u32			ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
++	bool			ah_ant_diversity;
++
++	u8			ah_sta_id[ETH_ALEN];
++	u8			ah_bssid[ETH_ALEN];
++
++	u32			ah_gpio[AR5K_MAX_GPIO];
++	int			ah_gpio_npins;
++
++	struct ath5k_capabilities ah_capabilities;
++
++	struct ath5k_txq_info	ah_txq[AR5K_NUM_TX_QUEUES];
++	u32			ah_txq_status;
++	u32			ah_txq_imr_txok;
++	u32			ah_txq_imr_txerr;
++	u32			ah_txq_imr_txurn;
++	u32			ah_txq_imr_txdesc;
++	u32			ah_txq_imr_txeol;
++	u32			*ah_rf_banks;
++	size_t			ah_rf_banks_size;
++	struct ath5k_gain	ah_gain;
++	u32			ah_offset[AR5K_MAX_RF_BANKS];
++
++	struct {
++		u16		txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE];
++		u16		txp_rates[AR5K_MAX_RATES];
++		s16		txp_min;
++		s16		txp_max;
++		bool		txp_tpc;
++		s16		txp_ofdm;
++	} ah_txpower;
++
++	struct {
++		bool		r_enabled;
++		int		r_last_alert;
++		struct ieee80211_channel r_last_channel;
++	} ah_radar;
++
++	/* noise floor from last periodic calibration */
++	s32			ah_noise_floor;
++
++	/*
++	 * Function pointers
++	 */
++	int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
++		unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
++		unsigned int, unsigned int, unsigned int, unsigned int,
++		unsigned int, unsigned int, unsigned int);
++	bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
++		unsigned int, unsigned int, unsigned int, unsigned int,
++		unsigned int, unsigned int);
++	int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *);
++	int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *);
++};
++
++/*
++ * Prototypes
++ */
++
++/* General Functions */
++extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set);
++/* Attach/Detach Functions */
++extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
++extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode);
++extern void ath5k_hw_detach(struct ath5k_hw *ah);
++/* Reset Functions */
++extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel);
++/* Power management functions */
++extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
++/* DMA Related Functions */
++extern void ath5k_hw_start_rx(struct ath5k_hw *ah);
++extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
++extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah);
++extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr);
++extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue);
++extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
++extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue);
++extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr);
++extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
++/* Interrupt handling */
++extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
++extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
++extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
++/* EEPROM access functions */
++extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
++/* Protocol Control Unit Functions */
++extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
++/* BSSID Functions */
++extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
++extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
++extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
++extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
++/* Receive start/stop functions */
++extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
++extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah);
++/* RX Filter functions */
++extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
++extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index);
++extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
++extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
++extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
++/* Beacon related functions */
++extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah);
++extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
++extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
++extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
++extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state);
++extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
++extern int ath5k_hw_wait_for_beacon(struct ath5k_hw *ah, unsigned long phys_addr);
++extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ath5k_mib_stats *statistics);
++/* ACK bit rate */
++void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
++/* ACK/CTS Timeouts */
++extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
++extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
++extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
++extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
++/* Key table (WEP) functions */
++extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
++extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
++extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac);
++extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
++/* Queue Control Unit, DFS Control Unit Functions */
++extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info);
++extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info);
++extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info);
++extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
++extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
++extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
++extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
++extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah);
++/* Hardware Descriptor Functions */
++extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags);
++/* GPIO Functions */
++extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
++extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
++extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
++extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
++extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
++extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
++/* Regulatory Domain/Channels Setup */
++extern u16 ath5k_get_regdomain(struct ath5k_hw *ah);
++/* Misc functions */
++extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
++
++
++/* Initial register settings functions */
++extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
++/* Initialize RF */
++extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
++extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq);
++extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah);
++extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah);
++
++
++/* PHY/RF channel functions */
++extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
++extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
++/* PHY calibration */
++extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
++extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
++/* Misc PHY functions */
++extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
++extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
++extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
++extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
++/* TX power setup */
++extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower);
++extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power);
++
++
++static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
++{
++	return ioread32(ah->ah_iobase + reg);
++}
++
++static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
++{
++	iowrite32(val, ah->ah_iobase + reg);
++}
++
++#endif
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/Makefile
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/Makefile	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,2 @@
++ath5k-objs		= base.o hw.o regdom.o initvals.o phy.o debug.o
++obj-$(CONFIG_ATH5K)	+= ath5k.o
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/reg.h
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/reg.h	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,1987 @@
++/*
++ * Copyright (c) 2007 Nick Kossifidis <mickflemm at gmail.com>
++ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk at openbsd.org>
++ * Copyright (c) 2007 Michael Taylor <mike.taylor at apprion.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ */
++
++/*
++ * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k
++ * maintained by Reyk Floeter
++ *
++ * I tried to document those registers by looking at ar5k code, some
++ * 802.11 (802.11e mostly) papers and by reading various public available
++ * Atheros presentations and papers like these:
++ *
++ * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf
++ *        http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
++ *
++ * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
++ */
++
++
++
++/*====MAC DMA REGISTERS====*/
++
++/*
++ * AR5210-Specific TXDP registers
++ * 5210 has only 2 transmit queues so no DCU/QCU, just
++ * 2 transmit descriptor pointers...
++ */
++#define AR5K_NOQCU_TXDP0	0x0000		/* Queue 0 - data */
++#define AR5K_NOQCU_TXDP1	0x0004		/* Queue 1 - beacons */
++
++/*
++ * Mac Control Register
++ */
++#define	AR5K_CR		0x0008			/* Register Address */
++#define AR5K_CR_TXE0	0x00000001	/* TX Enable for queue 0 on 5210 */
++#define AR5K_CR_TXE1	0x00000002	/* TX Enable for queue 1 on 5210 */
++#define	AR5K_CR_RXE	0x00000004	/* RX Enable */
++#define AR5K_CR_TXD0	0x00000008	/* TX Disable for queue 0 on 5210 */
++#define AR5K_CR_TXD1	0x00000010	/* TX Disable for queue 1 on 5210 */
++#define	AR5K_CR_RXD	0x00000020	/* RX Disable */
++#define	AR5K_CR_SWI	0x00000040
++
++/*
++ * RX Descriptor Pointer register
++ */
++#define	AR5K_RXDP	0x000c
++
++/*
++ * Configuration and status register
++ */
++#define	AR5K_CFG		0x0014			/* Register Address */
++#define	AR5K_CFG_SWTD		0x00000001	/* Byte-swap TX descriptor (for big endian archs) */
++#define	AR5K_CFG_SWTB		0x00000002	/* Byte-swap TX buffer (?) */
++#define	AR5K_CFG_SWRD		0x00000004	/* Byte-swap RX descriptor */
++#define	AR5K_CFG_SWRB		0x00000008	/* Byte-swap RX buffer (?) */
++#define	AR5K_CFG_SWRG		0x00000010	/* Byte-swap Register values (?) */
++#define AR5K_CFG_ADHOC		0x00000020 	/* [5211+] */
++#define AR5K_CFG_PHY_OK		0x00000100	/* [5211+] */
++#define AR5K_CFG_EEBS		0x00000200	/* EEPROM is busy */
++#define	AR5K_CFG_CLKGD		0x00000400	/* Clock gated (?) */
++#define AR5K_CFG_TXCNT		0x00007800	/* Tx frame count (?) [5210] */
++#define AR5K_CFG_TXCNT_S	11
++#define AR5K_CFG_TXFSTAT	0x00008000	/* Tx frame status (?) [5210] */
++#define AR5K_CFG_TXFSTRT	0x00010000	/* [5210] */
++#define	AR5K_CFG_PCI_THRES	0x00060000	/* [5211+] */
++#define	AR5K_CFG_PCI_THRES_S	17
++
++/*
++ * Interrupt enable register
++ */
++#define AR5K_IER		0x0024			/* Register Address */
++#define AR5K_IER_DISABLE	0x00000000	/* Disable card interrupts */
++#define AR5K_IER_ENABLE		0x00000001	/* Enable card interrupts */
++
++
++/*
++ * 0x0028 is Beacon Control Register on 5210
++ * and first RTS duration register on 5211
++ */
++
++/*
++ * Beacon control register [5210]
++ */
++#define AR5K_BCR		0x0028			/* Register Address */
++#define AR5K_BCR_AP		0x00000000	/* AP mode */
++#define AR5K_BCR_ADHOC		0x00000001	/* Ad-Hoc mode */
++#define AR5K_BCR_BDMAE		0x00000002	/* DMA enable */
++#define AR5K_BCR_TQ1FV		0x00000004	/* Use Queue1 for CAB traffic */
++#define AR5K_BCR_TQ1V		0x00000008	/* Use Queue1 for Beacon traffic */
++#define AR5K_BCR_BCGET		0x00000010
++
++/*
++ * First RTS duration register [5211]
++ */
++#define AR5K_RTSD0		0x0028			/* Register Address */
++#define	AR5K_RTSD0_6		0x000000ff	/* 6Mb RTS duration mask (?) */
++#define	AR5K_RTSD0_6_S		0		/* 6Mb RTS duration shift (?) */
++#define	AR5K_RTSD0_9		0x0000ff00	/* 9Mb*/
++#define	AR5K_RTSD0_9_S		8
++#define	AR5K_RTSD0_12		0x00ff0000	/* 12Mb*/
++#define	AR5K_RTSD0_12_S		16
++#define	AR5K_RTSD0_18		0xff000000	/* 16Mb*/
++#define	AR5K_RTSD0_18_S		24
++
++
++/*
++ * 0x002c is Beacon Status Register on 5210
++ * and second RTS duration register on 5211
++ */
++
++/*
++ * Beacon status register [5210]
++ *
++ * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR
++ * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning
++ * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR).
++ * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i
++ * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what
++ * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR.
++ */
++#define AR5K_BSR		0x002c			/* Register Address */
++#define AR5K_BSR_BDLYSW		0x00000001	/* SW Beacon delay (?) */
++#define AR5K_BSR_BDLYDMA	0x00000002	/* DMA Beacon delay (?) */
++#define AR5K_BSR_TXQ1F		0x00000004	/* Beacon queue (1) finished */
++#define AR5K_BSR_ATIMDLY	0x00000008	/* ATIM delay (?) */
++#define AR5K_BSR_SNPADHOC	0x00000100	/* Ad-hoc mode set (?) */
++#define AR5K_BSR_SNPBDMAE	0x00000200	/* Beacon DMA enabled (?) */
++#define AR5K_BSR_SNPTQ1FV	0x00000400	/* Queue1 is used for CAB traffic (?) */
++#define AR5K_BSR_SNPTQ1V	0x00000800	/* Queue1 is used for Beacon traffic (?) */
++#define AR5K_BSR_SNAPSHOTSVALID	0x00001000	/* BCR snapshots are valid (?) */
++#define AR5K_BSR_SWBA_CNT	0x00ff0000
++
++/*
++ * Second RTS duration register [5211]
++ */
++#define AR5K_RTSD1		0x002c			/* Register Address */
++#define	AR5K_RTSD1_24		0x000000ff	/* 24Mb */
++#define	AR5K_RTSD1_24_S		0
++#define	AR5K_RTSD1_36		0x0000ff00	/* 36Mb */
++#define	AR5K_RTSD1_36_S		8
++#define	AR5K_RTSD1_48		0x00ff0000	/* 48Mb */
++#define	AR5K_RTSD1_48_S		16
++#define	AR5K_RTSD1_54		0xff000000	/* 54Mb */
++#define	AR5K_RTSD1_54_S		24
++
++
++/*
++ * Transmit configuration register
++ */
++#define AR5K_TXCFG		0x0030			/* Register Address */
++#define AR5K_TXCFG_SDMAMR	0x00000007	/* DMA size */
++#define AR5K_TXCFG_SDMAMR_S	0
++#define AR5K_TXCFG_B_MODE	0x00000008	/* Set b mode for 5111 (enable 2111) */
++#define AR5K_TXCFG_TXFSTP	0x00000008	/* TX DMA full Stop [5210] */
++#define AR5K_TXCFG_TXFULL	0x000003f0	/* TX Triger level mask */
++#define AR5K_TXCFG_TXFULL_S	4
++#define AR5K_TXCFG_TXFULL_0B	0x00000000
++#define AR5K_TXCFG_TXFULL_64B	0x00000010
++#define AR5K_TXCFG_TXFULL_128B	0x00000020
++#define AR5K_TXCFG_TXFULL_192B	0x00000030
++#define AR5K_TXCFG_TXFULL_256B	0x00000040
++#define AR5K_TXCFG_TXCONT_EN	0x00000080
++#define AR5K_TXCFG_DMASIZE	0x00000100	/* Flag for passing DMA size [5210] */
++#define AR5K_TXCFG_JUMBO_TXE	0x00000400	/* Enable jumbo frames transmition (?) [5211+] */
++#define AR5K_TXCFG_RTSRND	0x00001000	/* [5211+] */
++#define AR5K_TXCFG_FRMPAD_DIS	0x00002000	/* [5211+] */
++#define AR5K_TXCFG_RDY_DIS	0x00004000	/* [5211+] */
++
++/*
++ * Receive configuration register
++ */
++#define AR5K_RXCFG		0x0034			/* Register Address */
++#define AR5K_RXCFG_SDMAMW	0x00000007	/* DMA size */
++#define AR5K_RXCFG_SDMAMW_S	0
++#define	AR5K_RXCFG_DEF_ANTENNA	0x00000008	/* Default antenna */
++#define AR5K_RXCFG_ZLFDMA	0x00000010	/* Zero-length DMA */
++#define AR5K_RXCFG_JUMBO_RXE	0x00000020	/* Enable jumbo frames reception (?) [5211+] */
++#define AR5K_RXCFG_JUMBO_WRAP	0x00000040	/* Wrap jumbo frames (?) [5211+] */
++
++/*
++ * Receive jumbo descriptor last address register
++ * Only found in 5211 (?)
++ */
++#define AR5K_RXJLA		0x0038
++
++/*
++ * MIB control register
++ */
++#define AR5K_MIBC		0x0040			/* Register Address */
++#define AR5K_MIBC_COW		0x00000001
++#define AR5K_MIBC_FMC		0x00000002	/* Freeze Mib Counters (?) */
++#define AR5K_MIBC_CMC		0x00000004	/* Clean Mib Counters (?) */
++#define AR5K_MIBC_MCS		0x00000008
++
++/*
++ * Timeout prescale register
++ */
++#define AR5K_TOPS		0x0044
++#define	AR5K_TOPS_M		0x0000ffff	/* [5211+] (?) */
++
++/*
++ * Receive timeout register (no frame received)
++ */
++#define AR5K_RXNOFRM		0x0048
++#define	AR5K_RXNOFRM_M		0x000003ff	/* [5211+] (?) */
++
++/*
++ * Transmit timeout register (no frame sent)
++ */
++#define AR5K_TXNOFRM		0x004c
++#define	AR5K_TXNOFRM_M		0x000003ff	/* [5211+] (?) */
++#define	AR5K_TXNOFRM_QCU	0x000ffc00	/* [5211+] (?) */
++
++/*
++ * Receive frame gap timeout register
++ */
++#define AR5K_RPGTO		0x0050
++#define AR5K_RPGTO_M		0x000003ff	/* [5211+] (?) */
++
++/*
++ * Receive frame count limit register
++ */
++#define AR5K_RFCNT		0x0054
++#define AR5K_RFCNT_M		0x0000001f	/* [5211+] (?) */
++#define AR5K_RFCNT_RFCL		0x0000000f	/* [5210] */
++
++/*
++ * Misc settings register
++ */
++#define AR5K_MISC		0x0058			/* Register Address */
++#define	AR5K_MISC_DMA_OBS_M	0x000001e0
++#define	AR5K_MISC_DMA_OBS_S	5
++#define	AR5K_MISC_MISC_OBS_M	0x00000e00
++#define	AR5K_MISC_MISC_OBS_S	9
++#define	AR5K_MISC_MAC_OBS_LSB_M	0x00007000
++#define	AR5K_MISC_MAC_OBS_LSB_S	12
++#define	AR5K_MISC_MAC_OBS_MSB_M	0x00038000
++#define	AR5K_MISC_MAC_OBS_MSB_S	15
++#define AR5K_MISC_LED_DECAY	0x001c0000	/* [5210] */
++#define AR5K_MISC_LED_BLINK	0x00e00000	/* [5210] */
++
++/*
++ * QCU/DCU clock gating register (5311)
++ */
++#define	AR5K_QCUDCU_CLKGT	0x005c			/* Register Address (?) */
++#define	AR5K_QCUDCU_CLKGT_QCU	0x0000ffff	/* Mask for QCU clock */
++#define	AR5K_QCUDCU_CLKGT_DCU	0x07ff0000	/* Mask for DCU clock */
++
++/*
++ * Interrupt Status Registers
++ *
++ * For 5210 there is only one status register but for
++ * 5211/5212 we have one primary and 4 secondary registers.
++ * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
++ * Most of these bits are common for all chipsets.
++ */
++#define AR5K_ISR		0x001c			/* Register Address [5210] */
++#define AR5K_PISR		0x0080			/* Register Address [5211+] */
++#define AR5K_ISR_RXOK		0x00000001	/* Frame successfuly recieved */
++#define AR5K_ISR_RXDESC		0x00000002	/* RX descriptor request */
++#define AR5K_ISR_RXERR		0x00000004	/* Receive error */
++#define AR5K_ISR_RXNOFRM	0x00000008	/* No frame received (receive timeout) */
++#define AR5K_ISR_RXEOL		0x00000010	/* Empty RX descriptor */
++#define AR5K_ISR_RXORN		0x00000020	/* Receive FIFO overrun */
++#define AR5K_ISR_TXOK		0x00000040	/* Frame successfuly transmited */
++#define AR5K_ISR_TXDESC		0x00000080	/* TX descriptor request */
++#define AR5K_ISR_TXERR		0x00000100	/* Transmit error */
++#define AR5K_ISR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout) */
++#define AR5K_ISR_TXEOL		0x00000400	/* Empty TX descriptor */
++#define AR5K_ISR_TXURN		0x00000800	/* Transmit FIFO underrun */
++#define AR5K_ISR_MIB		0x00001000	/* Update MIB counters */
++#define AR5K_ISR_SWI		0x00002000	/* Software interrupt (?) */
++#define AR5K_ISR_RXPHY		0x00004000	/* PHY error */
++#define AR5K_ISR_RXKCM		0x00008000
++#define AR5K_ISR_SWBA		0x00010000	/* Software beacon alert */
++#define AR5K_ISR_BRSSI		0x00020000
++#define AR5K_ISR_BMISS		0x00040000	/* Beacon missed */
++#define AR5K_ISR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
++#define AR5K_ISR_BNR		0x00100000 	/* Beacon not ready [5211+] */
++#define AR5K_ISR_MCABT		0x00100000	/* [5210] */
++#define AR5K_ISR_RXCHIRP	0x00200000	/* [5212+] */
++#define AR5K_ISR_SSERR		0x00200000	/* [5210] */
++#define AR5K_ISR_DPERR		0x00400000	/* [5210] */
++#define AR5K_ISR_TIM		0x00800000	/* [5210] */
++#define AR5K_ISR_BCNMISC	0x00800000	/* [5212+] */
++#define AR5K_ISR_GPIO		0x01000000	/* GPIO (rf kill)*/
++#define AR5K_ISR_QCBRORN	0x02000000	/* CBR overrun (?)  [5211+] */
++#define AR5K_ISR_QCBRURN	0x04000000	/* CBR underrun (?) [5211+] */
++#define AR5K_ISR_QTRIG		0x08000000	/* [5211+] */
++
++/*
++ * Secondary status registers [5211+] (0 - 4)
++ *
++ * I guess from the names that these give the status for each
++ * queue, that's why only masks are defined here, haven't got
++ * any info about them (couldn't find them anywhere in ar5k code).
++ */
++#define AR5K_SISR0		0x0084			/* Register Address [5211+] */
++#define AR5K_SISR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
++#define AR5K_SISR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
++
++#define AR5K_SISR1		0x0088			/* Register Address [5211+] */
++#define AR5K_SISR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
++#define AR5K_SISR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
++
++#define AR5K_SISR2		0x008c			/* Register Address [5211+] */
++#define AR5K_SISR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
++#define	AR5K_SISR2_MCABT	0x00100000
++#define	AR5K_SISR2_SSERR	0x00200000
++#define	AR5K_SISR2_DPERR	0x00400000
++#define	AR5K_SISR2_TIM		0x01000000	/* [5212+] */
++#define	AR5K_SISR2_CAB_END	0x02000000	/* [5212+] */
++#define	AR5K_SISR2_DTIM_SYNC	0x04000000	/* [5212+] */
++#define	AR5K_SISR2_BCN_TIMEOUT	0x08000000	/* [5212+] */
++#define	AR5K_SISR2_CAB_TIMEOUT	0x10000000	/* [5212+] */
++#define	AR5K_SISR2_DTIM		0x20000000	/* [5212+] */
++
++#define AR5K_SISR3		0x0090			/* Register Address [5211+] */
++#define AR5K_SISR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
++#define AR5K_SISR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
++
++#define AR5K_SISR4		0x0094			/* Register Address [5211+] */
++#define AR5K_SISR4_QTRIG	0x000003ff	/* Mask for QTRIG */
++
++/*
++ * Shadow read-and-clear interrupt status registers [5211+]
++ */
++#define AR5K_RAC_PISR		0x00c0		/* Read and clear PISR */
++#define AR5K_RAC_SISR0		0x00c4		/* Read and clear SISR0 */
++#define AR5K_RAC_SISR1		0x00c8		/* Read and clear SISR1 */
++#define AR5K_RAC_SISR2		0x00cc		/* Read and clear SISR2 */
++#define AR5K_RAC_SISR3		0x00d0		/* Read and clear SISR3 */
++#define AR5K_RAC_SISR4		0x00d4		/* Read and clear SISR4 */
++
++/*
++ * Interrupt Mask Registers
++ *
++ * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary
++ * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match.
++ */
++#define	AR5K_IMR		0x0020			/* Register Address [5210] */
++#define AR5K_PIMR		0x00a0			/* Register Address [5211+] */
++#define AR5K_IMR_RXOK		0x00000001	/* Frame successfuly recieved*/
++#define AR5K_IMR_RXDESC		0x00000002	/* RX descriptor request*/
++#define AR5K_IMR_RXERR		0x00000004	/* Receive error*/
++#define AR5K_IMR_RXNOFRM	0x00000008	/* No frame received (receive timeout)*/
++#define AR5K_IMR_RXEOL		0x00000010	/* Empty RX descriptor*/
++#define AR5K_IMR_RXORN		0x00000020	/* Receive FIFO overrun*/
++#define AR5K_IMR_TXOK		0x00000040	/* Frame successfuly transmited*/
++#define AR5K_IMR_TXDESC		0x00000080	/* TX descriptor request*/
++#define AR5K_IMR_TXERR		0x00000100	/* Transmit error*/
++#define AR5K_IMR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout)*/
++#define AR5K_IMR_TXEOL		0x00000400	/* Empty TX descriptor*/
++#define AR5K_IMR_TXURN		0x00000800	/* Transmit FIFO underrun*/
++#define AR5K_IMR_MIB		0x00001000	/* Update MIB counters*/
++#define AR5K_IMR_SWI		0x00002000
++#define AR5K_IMR_RXPHY		0x00004000	/* PHY error*/
++#define AR5K_IMR_RXKCM		0x00008000
++#define AR5K_IMR_SWBA		0x00010000	/* Software beacon alert*/
++#define AR5K_IMR_BRSSI		0x00020000
++#define AR5K_IMR_BMISS		0x00040000	/* Beacon missed*/
++#define AR5K_IMR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
++#define AR5K_IMR_BNR		0x00100000 	/* Beacon not ready [5211+] */
++#define AR5K_IMR_MCABT		0x00100000	/* [5210] */
++#define AR5K_IMR_RXCHIRP	0x00200000	/* [5212+]*/
++#define AR5K_IMR_SSERR		0x00200000	/* [5210] */
++#define AR5K_IMR_DPERR		0x00400000	/* [5210] */
++#define AR5K_IMR_TIM		0x00800000	/* [5211+] */
++#define AR5K_IMR_BCNMISC	0x00800000	/* [5212+] */
++#define AR5K_IMR_GPIO		0x01000000	/* GPIO (rf kill)*/
++#define AR5K_IMR_QCBRORN	0x02000000	/* CBR overrun (?) [5211+] */
++#define AR5K_IMR_QCBRURN	0x04000000	/* CBR underrun (?) [5211+] */
++#define AR5K_IMR_QTRIG		0x08000000	/* [5211+] */
++
++/*
++ * Secondary interrupt mask registers [5211+] (0 - 4)
++ */
++#define AR5K_SIMR0		0x00a4			/* Register Address [5211+] */
++#define AR5K_SIMR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
++#define AR5K_SIMR0_QCU_TXOK_S	0
++#define AR5K_SIMR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
++#define AR5K_SIMR0_QCU_TXDESC_S	16
++
++#define AR5K_SIMR1		0x00a8			/* Register Address [5211+] */
++#define AR5K_SIMR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
++#define AR5K_SIMR1_QCU_TXERR_S	0
++#define AR5K_SIMR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
++#define AR5K_SIMR1_QCU_TXEOL_S	16
++
++#define AR5K_SIMR2		0x00ac			/* Register Address [5211+] */
++#define AR5K_SIMR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
++#define AR5K_SIMR2_QCU_TXURN_S	0
++#define	AR5K_SIMR2_MCABT	0x00100000
++#define	AR5K_SIMR2_SSERR	0x00200000
++#define	AR5K_SIMR2_DPERR	0x00400000
++#define	AR5K_SIMR2_TIM		0x01000000	/* [5212+] */
++#define	AR5K_SIMR2_CAB_END	0x02000000	/* [5212+] */
++#define	AR5K_SIMR2_DTIM_SYNC	0x04000000	/* [5212+] */
++#define	AR5K_SIMR2_BCN_TIMEOUT	0x08000000	/* [5212+] */
++#define	AR5K_SIMR2_CAB_TIMEOUT	0x10000000	/* [5212+] */
++#define	AR5K_SIMR2_DTIM		0x20000000	/* [5212+] */
++
++#define AR5K_SIMR3		0x00b0			/* Register Address [5211+] */
++#define AR5K_SIMR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
++#define AR5K_SIMR3_QCBRORN_S	0
++#define AR5K_SIMR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
++#define AR5K_SIMR3_QCBRURN_S	16
++
++#define AR5K_SIMR4		0x00b4			/* Register Address [5211+] */
++#define AR5K_SIMR4_QTRIG	0x000003ff	/* Mask for QTRIG */
++#define AR5K_SIMR4_QTRIG_S	0
++
++
++/*
++ * Decompression mask registers [5212+]
++ */
++#define AR5K_DCM_ADDR		0x0400		/*Decompression mask address (?)*/
++#define AR5K_DCM_DATA		0x0404		/*Decompression mask data (?)*/
++
++/*
++ * Decompression configuration registers [5212+]
++ */
++#define AR5K_DCCFG		0x0420
++
++/*
++ * Compression configuration registers [5212+]
++ */
++#define AR5K_CCFG		0x0600
++#define AR5K_CCFG_CUP		0x0604
++
++/*
++ * Compression performance counter registers [5212+]
++ */
++#define AR5K_CPC0		0x0610		/* Compression performance counter 0 */
++#define AR5K_CPC1		0x0614		/* Compression performance counter 1*/
++#define AR5K_CPC2		0x0618		/* Compression performance counter 2 */
++#define AR5K_CPC3		0x061c		/* Compression performance counter 3 */
++#define AR5K_CPCORN		0x0620		/* Compression performance overrun (?) */
++
++
++/*
++ * Queue control unit (QCU) registers [5211+]
++ *
++ * Card has 12 TX Queues but i see that only 0-9 are used (?)
++ * both in binary HAL (see ah.h) and ar5k. Each queue has it's own
++ * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate)
++ * configuration register (0x08c0 - 0x08ec), a ready time configuration
++ * register (0x0900 - 0x092c), a misc configuration register (0x09c0 -
++ * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some
++ * global registers, QCU transmit enable/disable and "one shot arm (?)"
++ * set/clear, which contain status for all queues (we shift by 1 for each
++ * queue). To access these registers easily we define some macros here
++ * that are used inside HAL. For more infos check out *_tx_queue functs.
++ *
++ * TODO: Boundary checking on macros (here?)
++ */
++
++/*
++ * Generic QCU Register access macros
++ */
++#define	AR5K_QUEUE_REG(_r, _q)		(((_q) << 2) + _r)
++#define AR5K_QCU_GLOBAL_READ(_r, _q)	(AR5K_REG_READ(_r) & (1 << _q))
++#define AR5K_QCU_GLOBAL_WRITE(_r, _q)	AR5K_REG_WRITE(_r, (1 << _q))
++
++/*
++ * QCU Transmit descriptor pointer registers
++ */
++#define AR5K_QCU_TXDP_BASE	0x0800		/* Register Address - Queue0 TXDP */
++#define AR5K_QUEUE_TXDP(_q)	AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q)
++
++/*
++ * QCU Transmit enable register
++ */
++#define AR5K_QCU_TXE		0x0840
++#define AR5K_ENABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q)
++#define AR5K_QUEUE_ENABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q)
++
++/*
++ * QCU Transmit disable register
++ */
++#define AR5K_QCU_TXD		0x0880
++#define AR5K_DISABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q)
++#define AR5K_QUEUE_DISABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q)
++
++/*
++ * QCU Constant Bit Rate configuration registers
++ */
++#define	AR5K_QCU_CBRCFG_BASE		0x08c0	/* Register Address - Queue0 CBRCFG */
++#define	AR5K_QCU_CBRCFG_INTVAL		0x00ffffff	/* CBR Interval mask */
++#define AR5K_QCU_CBRCFG_INTVAL_S	0
++#define	AR5K_QCU_CBRCFG_ORN_THRES	0xff000000	/* CBR overrun threshold mask */
++#define AR5K_QCU_CBRCFG_ORN_THRES_S	24
++#define	AR5K_QUEUE_CBRCFG(_q)		AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q)
++
++/*
++ * QCU Ready time configuration registers
++ */
++#define	AR5K_QCU_RDYTIMECFG_BASE	0x0900	/* Register Address - Queue0 RDYTIMECFG */
++#define	AR5K_QCU_RDYTIMECFG_INTVAL	0x00ffffff	/* Ready time interval mask */
++#define AR5K_QCU_RDYTIMECFG_INTVAL_S	0
++#define	AR5K_QCU_RDYTIMECFG_DURATION	0x00ffffff	/* Ready time duration mask */
++#define	AR5K_QCU_RDYTIMECFG_ENABLE	0x01000000	/* Ready time enable mask */
++#define AR5K_QUEUE_RDYTIMECFG(_q)	AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q)
++
++/*
++ * QCU one shot arm set registers
++ */
++#define	AR5K_QCU_ONESHOTARM_SET		0x0940	/* Register Address -QCU "one shot arm set (?)" */
++#define	AR5K_QCU_ONESHOTARM_SET_M	0x0000ffff
++
++/*
++ * QCU one shot arm clear registers
++ */
++#define	AR5K_QCU_ONESHOTARM_CLEAR	0x0980	/* Register Address -QCU "one shot arm clear (?)" */
++#define	AR5K_QCU_ONESHOTARM_CLEAR_M	0x0000ffff
++
++/*
++ * QCU misc registers
++ */
++#define AR5K_QCU_MISC_BASE		0x09c0			/* Register Address -Queue0 MISC */
++#define	AR5K_QCU_MISC_FRSHED_M		0x0000000f	/* Frame sheduling mask */
++#define	AR5K_QCU_MISC_FRSHED_ASAP	0		/* ASAP */
++#define	AR5K_QCU_MISC_FRSHED_CBR	1		/* Constant Bit Rate */
++#define	AR5K_QCU_MISC_FRSHED_DBA_GT	2		/* DMA Beacon alert gated (?) */
++#define	AR5K_QCU_MISC_FRSHED_TIM_GT	3		/* Time gated (?) */
++#define	AR5K_QCU_MISC_FRSHED_BCN_SENT_GT	4	/* Beacon sent gated (?) */
++#define	AR5K_QCU_MISC_ONESHOT_ENABLE	0x00000010	/* Oneshot enable */
++#define	AR5K_QCU_MISC_CBREXP		0x00000020	/* CBR expired (normal queue) */
++#define	AR5K_QCU_MISC_CBREXP_BCN	0x00000040	/* CBR expired (beacon queue) */
++#define	AR5K_QCU_MISC_BCN_ENABLE	0x00000080	/* Beacons enabled */
++#define	AR5K_QCU_MISC_CBR_THRES_ENABLE	0x00000100	/* CBR threshold enabled (?) */
++#define	AR5K_QCU_MISC_TXE		0x00000200	/* TXE reset when RDYTIME enalbed (?) */
++#define	AR5K_QCU_MISC_CBR		0x00000400	/* CBR threshold reset (?) */
++#define	AR5K_QCU_MISC_DCU_EARLY		0x00000800	/* DCU reset (?) */
++#define AR5K_QUEUE_MISC(_q)		AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q)
++
++
++/*
++ * QCU status registers
++ */
++#define AR5K_QCU_STS_BASE	0x0a00			/* Register Address - Queue0 STS */
++#define	AR5K_QCU_STS_FRMPENDCNT	0x00000003	/* Frames pending counter */
++#define	AR5K_QCU_STS_CBREXPCNT	0x0000ff00	/* CBR expired counter (?) */
++#define	AR5K_QUEUE_STATUS(_q)	AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q)
++
++/*
++ * QCU ready time shutdown register
++ */
++#define AR5K_QCU_RDYTIMESHDN	0x0a40
++#define AR5K_QCU_RDYTIMESHDN_M	0x000003ff
++
++/*
++ * QCU compression buffer base registers [5212+]
++ */
++#define AR5K_QCU_CBB_SELECT	0x0b00
++#define AR5K_QCU_CBB_ADDR	0x0b04
++
++/*
++ * QCU compression buffer configuration register [5212+]
++ */
++#define AR5K_QCU_CBCFG		0x0b08
++
++
++
++/*
++ * Distributed Coordination Function (DCF) control unit (DCU)
++ * registers [5211+]
++ *
++ * These registers control the various characteristics of each queue
++ * for 802.11e (WME) combatibility so they go together with
++ * QCU registers in pairs. For each queue we have a QCU mask register,
++ * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c),
++ * a retry limit register (0x1080 - 0x10ac), a channel time register
++ * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and
++ * a sequence number register (0x1140 - 0x116c). It seems that "global"
++ * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
++ * We use the same macros here for easier register access.
++ *
++ */
++
++/*
++ * DCU QCU mask registers
++ */
++#define AR5K_DCU_QCUMASK_BASE	0x1000		/* Register Address -Queue0 DCU_QCUMASK */
++#define AR5K_DCU_QCUMASK_M	0x000003ff
++#define AR5K_QUEUE_QCUMASK(_q)	AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q)
++
++/*
++ * DCU local Inter Frame Space settings register
++ */
++#define AR5K_DCU_LCL_IFS_BASE		0x1040			/* Register Address -Queue0 DCU_LCL_IFS */
++#define	AR5K_DCU_LCL_IFS_CW_MIN	        0x000003ff	/* Minimum Contention Window */
++#define	AR5K_DCU_LCL_IFS_CW_MIN_S	0
++#define	AR5K_DCU_LCL_IFS_CW_MAX	        0x000ffc00	/* Maximum Contention Window */
++#define	AR5K_DCU_LCL_IFS_CW_MAX_S	10
++#define	AR5K_DCU_LCL_IFS_AIFS		0x0ff00000	/* Arbitrated Interframe Space */
++#define	AR5K_DCU_LCL_IFS_AIFS_S		20
++#define	AR5K_QUEUE_DFS_LOCAL_IFS(_q)	AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q)
++
++/*
++ * DCU retry limit registers
++ */
++#define AR5K_DCU_RETRY_LMT_BASE		0x1080			/* Register Address -Queue0 DCU_RETRY_LMT */
++#define AR5K_DCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
++#define AR5K_DCU_RETRY_LMT_SH_RETRY_S	0
++#define AR5K_DCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry limit mask */
++#define AR5K_DCU_RETRY_LMT_LG_RETRY_S	4
++#define AR5K_DCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask (?) */
++#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S	8
++#define AR5K_DCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask (?) */
++#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S	14
++#define	AR5K_QUEUE_DFS_RETRY_LIMIT(_q)	AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q)
++
++/*
++ * DCU channel time registers
++ */
++#define AR5K_DCU_CHAN_TIME_BASE		0x10c0			/* Register Address -Queue0 DCU_CHAN_TIME */
++#define	AR5K_DCU_CHAN_TIME_DUR		0x000fffff	/* Channel time duration */
++#define	AR5K_DCU_CHAN_TIME_DUR_S	0
++#define	AR5K_DCU_CHAN_TIME_ENABLE	0x00100000	/* Enable channel time */
++#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q)	AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q)
++
++/*
++ * DCU misc registers [5211+]
++ *
++ * For some of the registers i couldn't find in the code
++ * (only backoff stuff is there realy) i tried to match the
++ * names with 802.11e parameters etc, so i guess VIRTCOL here
++ * means Virtual Collision and HCFPOLL means Hybrid Coordination
++ * factor Poll (CF- Poll). Arbiter lockout control controls the
++ * behaviour on low priority queues when we have multiple queues
++ * with pending frames. Intra-frame lockout means we wait until
++ * the queue's current frame transmits (with post frame backoff and bursting)
++ * before we transmit anything else and global lockout means we
++ * wait for the whole queue to finish before higher priority queues
++ * can transmit (this is used on beacon and CAB queues).
++ * No lockout means there is no special handling.
++ */
++#define AR5K_DCU_MISC_BASE		0x1100			/* Register Address -Queue0 DCU_MISC */
++#define	AR5K_DCU_MISC_BACKOFF		0x000007ff	/* Mask for backoff setting (?) */
++#define AR5K_DCU_MISC_BACKOFF_FRAG	0x00000200	/* Enable backoff while bursting */
++#define	AR5K_DCU_MISC_HCFPOLL_ENABLE	0x00000800	/* CF - Poll (?) */
++#define	AR5K_DCU_MISC_BACKOFF_PERSIST	0x00001000	/* Persistent backoff (?) */
++#define	AR5K_DCU_MISC_FRMPRFTCH_ENABLE	0x00002000	/* Enable frame pre-fetch (?) */
++#define	AR5K_DCU_MISC_VIRTCOL		0x0000c000	/* Mask for Virtual Collision (?) */
++#define	AR5K_DCU_MISC_VIRTCOL_NORMAL	0
++#define	AR5K_DCU_MISC_VIRTCOL_MODIFIED	1
++#define	AR5K_DCU_MISC_VIRTCOL_IGNORE	2
++#define	AR5K_DCU_MISC_BCN_ENABLE	0x00010000	/* Beacon enable (?) */
++#define	AR5K_DCU_MISC_ARBLOCK_CTL	0x00060000	/* Arbiter lockout control mask */
++#define	AR5K_DCU_MISC_ARBLOCK_CTL_S	17
++#define	AR5K_DCU_MISC_ARBLOCK_CTL_NONE	0		/* No arbiter lockout */
++#define	AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM	1	/* Intra-frame lockout */
++#define	AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL	2	/* Global lockout */
++#define	AR5K_DCU_MISC_ARBLOCK_IGNORE	0x00080000
++#define	AR5K_DCU_MISC_SEQ_NUM_INCR_DIS	0x00100000	/* Disable sequence number increment (?) */
++#define	AR5K_DCU_MISC_POST_FR_BKOFF_DIS	0x00200000	/* Disable post-frame backoff (?) */
++#define	AR5K_DCU_MISC_VIRT_COLL_POLICY	0x00400000	/* Virtual Collision policy (?) */
++#define	AR5K_DCU_MISC_BLOWN_IFS_POLICY	0x00800000
++#define	AR5K_DCU_MISC_SEQNUM_CTL	0x01000000	/* Sequence number control (?) */
++#define AR5K_QUEUE_DFS_MISC(_q)		AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q)
++
++/*
++ * DCU frame sequence number registers
++ */
++#define AR5K_DCU_SEQNUM_BASE	0x1140
++#define	AR5K_DCU_SEQNUM_M	0x00000fff
++#define	AR5K_QUEUE_DFS_SEQNUM(_q)	AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
++
++/*
++ * DCU global IFS SIFS registers
++ */
++#define AR5K_DCU_GBL_IFS_SIFS	0x1030
++#define AR5K_DCU_GBL_IFS_SIFS_M	0x0000ffff
++
++/*
++ * DCU global IFS slot interval registers
++ */
++#define AR5K_DCU_GBL_IFS_SLOT	0x1070
++#define AR5K_DCU_GBL_IFS_SLOT_M	0x0000ffff
++
++/*
++ * DCU global IFS EIFS registers
++ */
++#define AR5K_DCU_GBL_IFS_EIFS	0x10b0
++#define AR5K_DCU_GBL_IFS_EIFS_M	0x0000ffff
++
++/*
++ * DCU global IFS misc registers
++ */
++#define AR5K_DCU_GBL_IFS_MISC			0x10f0			/* Register Address */
++#define	AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE	0x00000007
++#define	AR5K_DCU_GBL_IFS_MISC_TURBO_MODE	0x00000008	/* Turbo mode (?) */
++#define	AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC	0x000003f0	/* SIFS Duration mask (?) */
++#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR		0x000ffc00
++#define	AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY	0x00300000
++
++/*
++ * DCU frame prefetch control register
++ */
++#define AR5K_DCU_FP		0x1230
++
++/*
++ * DCU transmit pause control/status register
++ */
++#define AR5K_DCU_TXP		0x1270			/* Register Address */
++#define	AR5K_DCU_TXP_M		0x000003ff	/* Tx pause mask (?) */
++#define	AR5K_DCU_TXP_STATUS	0x00010000	/* Tx pause status (?) */
++
++/*
++ * DCU transmit filter register
++ */
++#define AR5K_DCU_TX_FILTER	0x1038
++
++/*
++ * DCU clear transmit filter register
++ */
++#define AR5K_DCU_TX_FILTER_CLR	0x143c
++
++/*
++ * DCU set transmit filter register
++ */
++#define AR5K_DCU_TX_FILTER_SET	0x147c
++
++/*
++ * Reset control register
++ *
++ * 4 and 8 are not used in 5211/5212 and
++ * 2 means "baseband reset" on 5211/5212.
++ */
++#define AR5K_RESET_CTL		0x4000			/* Register Address */
++#define AR5K_RESET_CTL_PCU	0x00000001	/* Protocol Control Unit reset */
++#define AR5K_RESET_CTL_DMA	0x00000002	/* DMA (Rx/Tx) reset [5210] */
++#define	AR5K_RESET_CTL_BASEBAND	0x00000002	/* Baseband reset [5211+] */
++#define AR5K_RESET_CTL_MAC	0x00000004	/* MAC reset (PCU+Baseband ?) [5210] */
++#define AR5K_RESET_CTL_PHY	0x00000008	/* PHY reset [5210] */
++#define AR5K_RESET_CTL_PCI	0x00000010	/* PCI Core reset (interrupts etc) */
++#define AR5K_RESET_CTL_CHIP	(AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA |	\
++				AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY)
++
++/*
++ * Sleep control register
++ */
++#define AR5K_SLEEP_CTL			0x4004			/* Register Address */
++#define AR5K_SLEEP_CTL_SLDUR		0x0000ffff	/* Sleep duration mask */
++#define AR5K_SLEEP_CTL_SLDUR_S		0
++#define AR5K_SLEEP_CTL_SLE		0x00030000	/* Sleep enable mask */
++#define AR5K_SLEEP_CTL_SLE_S		16
++#define AR5K_SLEEP_CTL_SLE_WAKE		0x00000000	/* Force chip awake */
++#define AR5K_SLEEP_CTL_SLE_SLP		0x00010000	/* Force chip sleep */
++#define AR5K_SLEEP_CTL_SLE_ALLOW	0x00020000
++#define AR5K_SLEEP_CTL_SLE_UNITS	0x00000008	/* [5211+] */
++
++/*
++ * Interrupt pending register
++ */
++#define AR5K_INTPEND	0x4008
++#define AR5K_INTPEND_M	0x00000001
++
++/*
++ * Sleep force register
++ */
++#define AR5K_SFR	0x400c
++#define AR5K_SFR_M	0x00000001
++
++/*
++ * PCI configuration register
++ */
++#define AR5K_PCICFG			0x4010			/* Register Address */
++#define AR5K_PCICFG_EEAE		0x00000001	/* Eeprom access enable [5210] */
++#define AR5K_PCICFG_CLKRUNEN		0x00000004	/* CLKRUN enable [5211+] */
++#define AR5K_PCICFG_EESIZE		0x00000018	/* Mask for EEPROM size [5211+] */
++#define AR5K_PCICFG_EESIZE_S		3
++#define AR5K_PCICFG_EESIZE_4K		0		/* 4K */
++#define AR5K_PCICFG_EESIZE_8K		1		/* 8K */
++#define AR5K_PCICFG_EESIZE_16K		2		/* 16K */
++#define AR5K_PCICFG_EESIZE_FAIL		3		/* Failed to get size (?) [5211+] */
++#define AR5K_PCICFG_LED			0x00000060	/* Led status [5211+] */
++#define AR5K_PCICFG_LED_NONE		0x00000000	/* Default [5211+] */
++#define AR5K_PCICFG_LED_PEND		0x00000020	/* Scan / Auth pending */
++#define AR5K_PCICFG_LED_ASSOC		0x00000040	/* Associated */
++#define	AR5K_PCICFG_BUS_SEL		0x00000380	/* Mask for "bus select" [5211+] (?) */
++#define	AR5K_PCICFG_CBEFIX_DIS		0x00000400	/* Disable CBE fix (?) */
++#define AR5K_PCICFG_SL_INTEN		0x00000800	/* Enable interrupts when asleep (?) */
++#define AR5K_PCICFG_LED_BCTL		0x00001000	/* Led blink (?) [5210] */
++#define AR5K_PCICFG_SL_INPEN		0x00002800	/* Sleep even whith pending interrupts (?) */
++#define AR5K_PCICFG_SPWR_DN		0x00010000	/* Mask for power status */
++#define AR5K_PCICFG_LEDMODE		0x000e0000	/* Ledmode [5211+] */
++#define AR5K_PCICFG_LEDMODE_PROP	0x00000000	/* Blink on standard traffic [5211+] */
++#define AR5K_PCICFG_LEDMODE_PROM	0x00020000	/* Default mode (blink on any traffic) [5211+] */
++#define AR5K_PCICFG_LEDMODE_PWR		0x00040000	/* Some other blinking mode  (?) [5211+] */
++#define AR5K_PCICFG_LEDMODE_RAND	0x00060000	/* Random blinking (?) [5211+] */
++#define AR5K_PCICFG_LEDBLINK		0x00700000
++#define AR5K_PCICFG_LEDBLINK_S		20
++#define AR5K_PCICFG_LEDSLOW		0x00800000	/* Slow led blink rate (?) [5211+] */
++#define AR5K_PCICFG_LEDSTATE				\
++	(AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE |	\
++	AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
++
++/*
++ * "General Purpose Input/Output" (GPIO) control register
++ *
++ * I'm not sure about this but after looking at the code
++ * for all chipsets here is what i got.
++ *
++ * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits)
++ * Mode 0 -> always input
++ * Mode 1 -> output when GPIODO for this GPIO is set to 0
++ * Mode 2 -> output when GPIODO for this GPIO is set to 1
++ * Mode 3 -> always output
++ *
++ * For more infos check out get_gpio/set_gpio and
++ * set_gpio_input/set_gpio_output functs.
++ * For more infos on gpio interrupt check out set_gpio_intr.
++ */
++#define AR5K_NUM_GPIO	6
++
++#define AR5K_GPIOCR		0x4014				/* Register Address */
++#define AR5K_GPIOCR_INT_ENA	0x00008000		/* Enable GPIO interrupt */
++#define AR5K_GPIOCR_INT_SELL	0x00000000		/* Generate interrupt when pin is off (?) */
++#define AR5K_GPIOCR_INT_SELH	0x00010000		/* Generate interrupt when pin is on */
++#define AR5K_GPIOCR_IN(n)	(0 << ((n) * 2))	/* Mode 0 for pin n */
++#define AR5K_GPIOCR_OUT0(n)	(1 << ((n) * 2))	/* Mode 1 for pin n */
++#define AR5K_GPIOCR_OUT1(n)	(2 << ((n) * 2))	/* Mode 2 for pin n */
++#define AR5K_GPIOCR_OUT(n)	(3 << ((n) * 2))	/* Mode 3 for pin n */
++#define AR5K_GPIOCR_INT_SEL(n)	((n) << 12)		/* Interrupt for GPIO pin n */
++
++/*
++ * "General Purpose Input/Output" (GPIO) data output register
++ */
++#define AR5K_GPIODO	0x4018
++
++/*
++ * "General Purpose Input/Output" (GPIO) data input register
++ */
++#define AR5K_GPIODI	0x401c
++#define AR5K_GPIODI_M	0x0000002f
++
++
++/*
++ * Silicon revision register
++ */
++#define AR5K_SREV		0x4020			/* Register Address */
++#define AR5K_SREV_REV		0x0000000f	/* Mask for revision */
++#define AR5K_SREV_REV_S		0
++#define AR5K_SREV_VER		0x000000ff	/* Mask for version */
++#define AR5K_SREV_VER_S		4
++
++
++
++/*====EEPROM REGISTERS====*/
++
++/*
++ * EEPROM access registers
++ *
++ * Here we got a difference between 5210/5211-12
++ * read data register for 5210 is at 0x6800 and
++ * status register is at 0x6c00. There is also
++ * no eeprom command register on 5210 and the
++ * offsets are different.
++ *
++ * To read eeprom data for a specific offset:
++ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
++ *        read AR5K_EEPROM_BASE +(4 * offset)
++ *        check the eeprom status register
++ *        and read eeprom data register.
++ *
++ * 5211 - write offset to AR5K_EEPROM_BASE
++ * 5212   write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD
++ *        check the eeprom status register
++ *        and read eeprom data register.
++ *
++ * To write eeprom data for a specific offset:
++ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
++ *        write data to AR5K_EEPROM_BASE +(4 * offset)
++ *        check the eeprom status register
++ * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD
++ * 5212   write offset to AR5K_EEPROM_BASE
++ *        write data to data register
++ *	  write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD
++ *        check the eeprom status register
++ *
++ * For more infos check eeprom_* functs and the ar5k.c
++ * file posted in madwifi-devel mailing list.
++ * http://sourceforge.net/mailarchive/message.php?msg_id=8966525
++ *
++ */
++#define AR5K_EEPROM_BASE	0x6000
++
++/*
++ * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
++ */
++#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
++#define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
++#define AR5K_EEPROM_MAGIC_5212		0x0000145c /* 5212 */
++#define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
++#define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
++
++#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
++#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
++#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
++#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
++#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
++#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
++#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
++#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
++#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
++#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
++#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
++#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
++#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
++#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
++#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
++#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
++#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
++#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
++#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
++#define AR5K_EEPROM_INFO_CKSUM		0xffff
++#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
++
++#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
++#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
++#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
++#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
++#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
++#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
++#define AR5K_EEPROM_VERSION_4_3		0x4003
++#define AR5K_EEPROM_VERSION_4_4		0x4004
++#define AR5K_EEPROM_VERSION_4_5		0x4005
++#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
++#define AR5K_EEPROM_VERSION_4_7		0x3007
++
++#define AR5K_EEPROM_MODE_11A		0
++#define AR5K_EEPROM_MODE_11B		1
++#define AR5K_EEPROM_MODE_11G		2
++
++#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
++#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
++#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
++#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
++#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
++#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
++#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
++#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz (?) */
++#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
++
++#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
++#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
++#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
++#define AR5K_EEPROM_RFKILL_POLARITY_S	1
++
++/* Newer EEPROMs are using a different offset */
++#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
++	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
++
++#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
++#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((int8_t)(((_v) >> 8) & 0xff))
++#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((int8_t)((_v) & 0xff))
++
++/* calibration settings */
++#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
++#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
++#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
++#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
++
++/* [3.1 - 3.3] */
++#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
++#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
++
++/* Misc values available since EEPROM 4.0 */
++#define AR5K_EEPROM_MISC0		0x00c4
++#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
++#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
++#define AR5K_EEPROM_MISC1		0x00c5
++#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
++#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
++
++/*
++ * EEPROM data register
++ */
++#define AR5K_EEPROM_DATA_5211	0x6004
++#define AR5K_EEPROM_DATA_5210	0x6800
++#define	AR5K_EEPROM_DATA	(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
++
++/*
++ * EEPROM command register
++ */
++#define AR5K_EEPROM_CMD		0x6008			/* Register Addres */
++#define AR5K_EEPROM_CMD_READ	0x00000001	/* EEPROM read */
++#define AR5K_EEPROM_CMD_WRITE	0x00000002	/* EEPROM write */
++#define AR5K_EEPROM_CMD_RESET	0x00000004	/* EEPROM reset */
++
++/*
++ * EEPROM status register
++ */
++#define AR5K_EEPROM_STAT_5210	0x6c00			/* Register Address [5210] */
++#define AR5K_EEPROM_STAT_5211	0x600c			/* Register Address [5211+] */
++#define	AR5K_EEPROM_STATUS	(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
++#define AR5K_EEPROM_STAT_RDERR	0x00000001	/* EEPROM read failed */
++#define AR5K_EEPROM_STAT_RDDONE	0x00000002	/* EEPROM read successful */
++#define AR5K_EEPROM_STAT_WRERR	0x00000004	/* EEPROM write failed */
++#define AR5K_EEPROM_STAT_WRDONE	0x00000008	/* EEPROM write successful */
++
++/*
++ * EEPROM config register (?)
++ */
++#define AR5K_EEPROM_CFG	0x6010
++
++
++
++/*
++ * Protocol Control Unit (PCU) registers
++ */
++/*
++ * Used for checking initial register writes
++ * during channel reset (see reset func)
++ */
++#define AR5K_PCU_MIN	0x8000
++#define AR5K_PCU_MAX	0x8fff
++
++/*
++ * First station id register (MAC address in lower 32 bits)
++ */
++#define AR5K_STA_ID0	0x8000
++
++/*
++ * Second station id register (MAC address in upper 16 bits)
++ */
++#define AR5K_STA_ID1			0x8004			/* Register Address */
++#define AR5K_STA_ID1_AP			0x00010000	/* Set AP mode */
++#define AR5K_STA_ID1_ADHOC		0x00020000	/* Set Ad-Hoc mode */
++#define AR5K_STA_ID1_PWR_SV		0x00040000	/* Power save reporting (?) */
++#define AR5K_STA_ID1_NO_KEYSRCH		0x00080000	/* No key search */
++#define AR5K_STA_ID1_NO_PSPOLL		0x00100000	/* No power save polling [5210] */
++#define AR5K_STA_ID1_PCF_5211		0x00100000	/* Enable PCF on [5211+] */
++#define AR5K_STA_ID1_PCF_5210		0x00200000	/* Enable PCF on [5210]*/
++#define	AR5K_STA_ID1_PCF		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211)
++#define AR5K_STA_ID1_DEFAULT_ANTENNA	0x00200000	/* Use default antenna */
++#define AR5K_STA_ID1_DESC_ANTENNA	0x00400000	/* Update antenna from descriptor */
++#define AR5K_STA_ID1_RTS_DEF_ANTENNA	0x00800000	/* Use default antenna for RTS (?) */
++#define AR5K_STA_ID1_ACKCTS_6MB		0x01000000	/* Use 6Mbit/s for ACK/CTS (?) */
++#define AR5K_STA_ID1_BASE_RATE_11B	0x02000000	/* Use 11b base rate (for ACK/CTS ?) [5211+] */
++
++/*
++ * First BSSID register (MAC address, lower 32bits)
++ */
++#define AR5K_BSS_ID0	0x8008
++
++/*
++ * Second BSSID register (MAC address in upper 16 bits)
++ *
++ * AID: Association ID
++ */
++#define AR5K_BSS_ID1		0x800c
++#define AR5K_BSS_ID1_AID	0xffff0000
++#define AR5K_BSS_ID1_AID_S	16
++
++/*
++ * Backoff slot time register
++ */
++#define AR5K_SLOT_TIME	0x8010
++
++/*
++ * ACK/CTS timeout register
++ */
++#define AR5K_TIME_OUT		0x8014			/* Register Address */
++#define AR5K_TIME_OUT_ACK	0x00001fff	/* ACK timeout mask */
++#define AR5K_TIME_OUT_ACK_S	0
++#define AR5K_TIME_OUT_CTS	0x1fff0000	/* CTS timeout mask */
++#define AR5K_TIME_OUT_CTS_S	16
++
++/*
++ * RSSI threshold register
++ */
++#define AR5K_RSSI_THR			0x8018		/* Register Address */
++#define AR5K_RSSI_THR_M			0x000000ff	/* Mask for RSSI threshold [5211+] */
++#define AR5K_RSSI_THR_BMISS_5210	0x00000700	/* Mask for Beacon Missed threshold [5210] */
++#define AR5K_RSSI_THR_BMISS_5210_S	8
++#define AR5K_RSSI_THR_BMISS_5211	0x0000ff00	/* Mask for Beacon Missed threshold [5211+] */
++#define AR5K_RSSI_THR_BMISS_5211_S	8
++#define	AR5K_RSSI_THR_BMISS		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211)
++#define	AR5K_RSSI_THR_BMISS_S		8
++
++/*
++ * 5210 has more PCU registers because there is no QCU/DCU
++ * so queue parameters are set here, this way a lot common
++ * registers have different address for 5210. To make things
++ * easier we define a macro based on ah->ah_version for common
++ * registers with different addresses and common flags.
++ */
++
++/*
++ * Retry limit register
++ *
++ * Retry limit register for 5210 (no QCU/DCU so it's done in PCU)
++ */
++#define AR5K_NODCU_RETRY_LMT		0x801c			/*Register Address */
++#define AR5K_NODCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
++#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S	0
++#define AR5K_NODCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry mask */
++#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S	4
++#define AR5K_NODCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask */
++#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S	8
++#define AR5K_NODCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask */
++#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S	14
++#define AR5K_NODCU_RETRY_LMT_CW_MIN	0x3ff00000	/* Minimum contention window mask */
++#define AR5K_NODCU_RETRY_LMT_CW_MIN_S	20
++
++/*
++ * Transmit latency register
++ */
++#define AR5K_USEC_5210			0x8020			/* Register Address [5210] */
++#define AR5K_USEC_5211			0x801c			/* Register Address [5211+] */
++#define AR5K_USEC			(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_USEC_5210 : AR5K_USEC_5211)
++#define AR5K_USEC_1			0x0000007f
++#define AR5K_USEC_1_S			0
++#define AR5K_USEC_32			0x00003f80
++#define AR5K_USEC_32_S			7
++#define AR5K_USEC_TX_LATENCY_5211	0x007fc000
++#define AR5K_USEC_TX_LATENCY_5211_S	14
++#define AR5K_USEC_RX_LATENCY_5211	0x1f800000
++#define AR5K_USEC_RX_LATENCY_5211_S	23
++#define AR5K_USEC_TX_LATENCY_5210	0x000fc000	/* also for 5311 */
++#define AR5K_USEC_TX_LATENCY_5210_S	14
++#define AR5K_USEC_RX_LATENCY_5210	0x03f00000	/* also for 5311 */
++#define AR5K_USEC_RX_LATENCY_5210_S	20
++
++/*
++ * PCU beacon control register
++ */
++#define AR5K_BEACON_5210	0x8024
++#define AR5K_BEACON_5211	0x8020
++#define AR5K_BEACON		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_BEACON_5210 : AR5K_BEACON_5211)
++#define AR5K_BEACON_PERIOD	0x0000ffff
++#define AR5K_BEACON_PERIOD_S	0
++#define AR5K_BEACON_TIM		0x007f0000
++#define AR5K_BEACON_TIM_S	16
++#define AR5K_BEACON_ENABLE	0x00800000
++#define AR5K_BEACON_RESET_TSF	0x01000000
++
++/*
++ * CFP period register
++ */
++#define AR5K_CFP_PERIOD_5210	0x8028
++#define AR5K_CFP_PERIOD_5211	0x8024
++#define AR5K_CFP_PERIOD		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211)
++
++/*
++ * Next beacon time register
++ */
++#define AR5K_TIMER0_5210	0x802c
++#define AR5K_TIMER0_5211	0x8028
++#define AR5K_TIMER0		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
++
++/*
++ * Next DMA beacon alert register
++ */
++#define AR5K_TIMER1_5210	0x8030
++#define AR5K_TIMER1_5211	0x802c
++#define AR5K_TIMER1		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
++
++/*
++ * Next software beacon alert register
++ */
++#define AR5K_TIMER2_5210	0x8034
++#define AR5K_TIMER2_5211	0x8030
++#define AR5K_TIMER2		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
++
++/*
++ * Next ATIM window time register
++ */
++#define AR5K_TIMER3_5210	0x8038
++#define AR5K_TIMER3_5211	0x8034
++#define AR5K_TIMER3		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
++
++
++/*
++ * 5210 First inter frame spacing register (IFS)
++ */
++#define AR5K_IFS0		0x8040
++#define AR5K_IFS0_SIFS		0x000007ff
++#define AR5K_IFS0_SIFS_S	0
++#define AR5K_IFS0_DIFS		0x007ff800
++#define AR5K_IFS0_DIFS_S	11
++
++/*
++ * 5210 Second inter frame spacing register (IFS)
++ */
++#define AR5K_IFS1		0x8044
++#define AR5K_IFS1_PIFS		0x00000fff
++#define AR5K_IFS1_PIFS_S	0
++#define AR5K_IFS1_EIFS		0x03fff000
++#define AR5K_IFS1_EIFS_S	12
++#define AR5K_IFS1_CS_EN		0x04000000
++
++
++/*
++ * CFP duration register
++ */
++#define AR5K_CFP_DUR_5210	0x8048
++#define AR5K_CFP_DUR_5211	0x8038
++#define AR5K_CFP_DUR		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211)
++
++/*
++ * Receive filter register
++ * TODO: Get these out of ar5xxx.h on ath5k
++ */
++#define AR5K_RX_FILTER_5210	0x804c			/* Register Address [5210] */
++#define AR5K_RX_FILTER_5211	0x803c			/* Register Address [5211+] */
++#define AR5K_RX_FILTER		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211)
++#define	AR5K_RX_FILTER_UCAST 	0x00000001	/* Don't filter unicast frames */
++#define	AR5K_RX_FILTER_MCAST 	0x00000002	/* Don't filter multicast frames */
++#define	AR5K_RX_FILTER_BCAST 	0x00000004	/* Don't filter broadcast frames */
++#define	AR5K_RX_FILTER_CONTROL 	0x00000008	/* Don't filter control frames */
++#define	AR5K_RX_FILTER_BEACON 	0x00000010	/* Don't filter beacon frames */
++#define	AR5K_RX_FILTER_PROM 	0x00000020	/* Set promiscuous mode */
++#define	AR5K_RX_FILTER_XRPOLL 	0x00000040	/* Don't filter XR poll frame [5212+] */
++#define	AR5K_RX_FILTER_PROBEREQ 0x00000080	/* Don't filter probe requests [5212+] */
++#define	AR5K_RX_FILTER_PHYERR_5212	0x00000100	/* Don't filter phy errors [5212+] */
++#define	AR5K_RX_FILTER_RADARERR_5212 	0x00000200	/* Don't filter phy radar errors [5212+] */
++#define AR5K_RX_FILTER_PHYERR_5211	0x00000040	/* [5211] */
++#define AR5K_RX_FILTER_RADARERR_5211	0x00000080	/* [5211] */
++#define AR5K_RX_FILTER_PHYERR  \
++	((ah->ah_version == AR5K_AR5211 ? \
++	AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212))
++#define        AR5K_RX_FILTER_RADARERR \
++	((ah->ah_version == AR5K_AR5211 ? \
++	AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212))
++
++/*
++ * Multicast filter register (lower 32 bits)
++ */
++#define AR5K_MCAST_FILTER0_5210	0x8050
++#define AR5K_MCAST_FILTER0_5211	0x8040
++#define AR5K_MCAST_FILTER0	(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211)
++
++/*
++ * Multicast filter register (higher 16 bits)
++ */
++#define AR5K_MCAST_FILTER1_5210	0x8054
++#define AR5K_MCAST_FILTER1_5211	0x8044
++#define AR5K_MCAST_FILTER1	(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211)
++
++
++/*
++ * Transmit mask register (lower 32 bits) [5210]
++ */
++#define AR5K_TX_MASK0	0x8058
++
++/*
++ * Transmit mask register (higher 16 bits) [5210]
++ */
++#define AR5K_TX_MASK1	0x805c
++
++/*
++ * Clear transmit mask [5210]
++ */
++#define AR5K_CLR_TMASK	0x8060
++
++/*
++ * Trigger level register (before transmission) [5210]
++ */
++#define AR5K_TRIG_LVL	0x8064
++
++
++/*
++ * PCU control register
++ *
++ * Only DIS_RX is used in the code, the rest i guess are
++ * for tweaking/diagnostics.
++ */
++#define AR5K_DIAG_SW_5210		0x8068			/* Register Address [5210] */
++#define AR5K_DIAG_SW_5211		0x8048			/* Register Address [5211+] */
++#define AR5K_DIAG_SW			(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211)
++#define AR5K_DIAG_SW_DIS_WEP_ACK	0x00000001
++#define AR5K_DIAG_SW_DIS_ACK		0x00000002	/* Disable ACKs (?) */
++#define AR5K_DIAG_SW_DIS_CTS		0x00000004	/* Disable CTSs (?) */
++#define AR5K_DIAG_SW_DIS_ENC		0x00000008	/* Disable encryption (?) */
++#define AR5K_DIAG_SW_DIS_DEC		0x00000010	/* Disable decryption (?) */
++#define AR5K_DIAG_SW_DIS_TX		0x00000020	/* Disable transmit [5210] */
++#define AR5K_DIAG_SW_DIS_RX_5210	0x00000040	/* Disable recieve */
++#define AR5K_DIAG_SW_DIS_RX_5211	0x00000020
++#define	AR5K_DIAG_SW_DIS_RX		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211)
++#define AR5K_DIAG_SW_LOOP_BACK_5210	0x00000080	/* Loopback (i guess it goes with DIS_TX) [5210] */
++#define AR5K_DIAG_SW_LOOP_BACK_5211	0x00000040
++#define AR5K_DIAG_SW_LOOP_BACK		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
++#define AR5K_DIAG_SW_CORR_FCS_5210	0x00000100
++#define AR5K_DIAG_SW_CORR_FCS_5211	0x00000080
++#define AR5K_DIAG_SW_CORR_FCS		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
++#define AR5K_DIAG_SW_CHAN_INFO_5210	0x00000200
++#define AR5K_DIAG_SW_CHAN_INFO_5211	0x00000100
++#define AR5K_DIAG_SW_CHAN_INFO		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
++#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211	0x00000200	/* Scrambler seed (?) */
++#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210	0x00000400
++#define AR5K_DIAG_SW_EN_SCRAM_SEED	(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
++#define AR5K_DIAG_SW_ECO_ENABLE		0x00000400	/* [5211+] */
++#define AR5K_DIAG_SW_SCVRAM_SEED	0x0003f800	/* [5210] */
++#define AR5K_DIAG_SW_SCRAM_SEED_M	0x0001fc00	/* Scrambler seed mask (?) */
++#define AR5K_DIAG_SW_SCRAM_SEED_S	10
++#define AR5K_DIAG_SW_DIS_SEQ_INC	0x00040000	/* Disable seqnum increment (?)[5210] */
++#define AR5K_DIAG_SW_FRAME_NV0_5210	0x00080000
++#define AR5K_DIAG_SW_FRAME_NV0_5211	0x00020000
++#define	AR5K_DIAG_SW_FRAME_NV0		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
++#define AR5K_DIAG_SW_OBSPT_M		0x000c0000
++#define AR5K_DIAG_SW_OBSPT_S		18
++
++/*
++ * TSF (clock) register (lower 32 bits)
++ */
++#define AR5K_TSF_L32_5210	0x806c
++#define AR5K_TSF_L32_5211	0x804c
++#define	AR5K_TSF_L32		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
++
++/*
++ * TSF (clock) register (higher 32 bits)
++ */
++#define AR5K_TSF_U32_5210	0x8070
++#define AR5K_TSF_U32_5211	0x8050
++#define	AR5K_TSF_U32		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
++
++/*
++ * Last beacon timestamp register
++ */
++#define AR5K_LAST_TSTP	0x8080
++
++/*
++ * ADDAC test register [5211+]
++ */
++#define AR5K_ADDAC_TEST	0x8054
++#define AR5K_ADDAC_TEST_TXCONT 0x00000001
++
++/*
++ * Default antenna register [5211+]
++ */
++#define AR5K_DEFAULT_ANTENNA	0x8058
++
++
++
++/*
++ * Retry count register [5210]
++ */
++#define AR5K_RETRY_CNT		0x8084			/* Register Address [5210] */
++#define AR5K_RETRY_CNT_SSH	0x0000003f	/* Station short retry count (?) */
++#define AR5K_RETRY_CNT_SLG	0x00000fc0	/* Station long retry count (?) */
++
++/*
++ * Back-off status register [5210]
++ */
++#define AR5K_BACKOFF		0x8088			/* Register Address [5210] */
++#define AR5K_BACKOFF_CW		0x000003ff	/* Backoff Contention Window (?) */
++#define AR5K_BACKOFF_CNT	0x03ff0000	/* Backoff count (?) */
++
++
++
++/*
++ * NAV register (current)
++ */
++#define AR5K_NAV_5210		0x808c
++#define AR5K_NAV_5211		0x8084
++#define	AR5K_NAV		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_NAV_5210 : AR5K_NAV_5211)
++
++/*
++ * RTS success register
++ */
++#define AR5K_RTS_OK_5210	0x8090
++#define AR5K_RTS_OK_5211	0x8088
++#define	AR5K_RTS_OK		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
++
++/*
++ * RTS failure register
++ */
++#define AR5K_RTS_FAIL_5210	0x8094
++#define AR5K_RTS_FAIL_5211	0x808c
++#define	AR5K_RTS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
++
++/*
++ * ACK failure register
++ */
++#define AR5K_ACK_FAIL_5210	0x8098
++#define AR5K_ACK_FAIL_5211	0x8090
++#define	AR5K_ACK_FAIL		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
++
++/*
++ * FCS failure register
++ */
++#define AR5K_FCS_FAIL_5210	0x809c
++#define AR5K_FCS_FAIL_5211	0x8094
++#define	AR5K_FCS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211)
++
++/*
++ * Beacon count register
++ */
++#define AR5K_BEACON_CNT_5210	0x80a0
++#define AR5K_BEACON_CNT_5211	0x8098
++#define	AR5K_BEACON_CNT		(ah->ah_version == AR5K_AR5210 ? \
++				AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211)
++
++
++/*===5212 Specific PCU registers===*/
++
++/*
++ * XR (eXtended Range) mode register
++ */
++#define AR5K_XRMODE			0x80c0
++#define	AR5K_XRMODE_POLL_TYPE_M		0x0000003f
++#define	AR5K_XRMODE_POLL_TYPE_S		0
++#define	AR5K_XRMODE_POLL_SUBTYPE_M	0x0000003c
++#define	AR5K_XRMODE_POLL_SUBTYPE_S	2
++#define	AR5K_XRMODE_POLL_WAIT_ALL	0x00000080
++#define	AR5K_XRMODE_SIFS_DELAY		0x000fff00
++#define	AR5K_XRMODE_FRAME_HOLD_M	0xfff00000
++#define	AR5K_XRMODE_FRAME_HOLD_S	20
++
++/*
++ * XR delay register
++ */
++#define AR5K_XRDELAY			0x80c4
++#define AR5K_XRDELAY_SLOT_DELAY_M	0x0000ffff
++#define AR5K_XRDELAY_SLOT_DELAY_S	0
++#define AR5K_XRDELAY_CHIRP_DELAY_M	0xffff0000
++#define AR5K_XRDELAY_CHIRP_DELAY_S	16
++
++/*
++ * XR timeout register
++ */
++#define AR5K_XRTIMEOUT			0x80c8
++#define AR5K_XRTIMEOUT_CHIRP_M		0x0000ffff
++#define AR5K_XRTIMEOUT_CHIRP_S		0
++#define AR5K_XRTIMEOUT_POLL_M		0xffff0000
++#define AR5K_XRTIMEOUT_POLL_S		16
++
++/*
++ * XR chirp register
++ */
++#define AR5K_XRCHIRP			0x80cc
++#define AR5K_XRCHIRP_SEND		0x00000001
++#define AR5K_XRCHIRP_GAP		0xffff0000
++
++/*
++ * XR stomp register
++ */
++#define AR5K_XRSTOMP			0x80d0
++#define AR5K_XRSTOMP_TX			0x00000001
++#define AR5K_XRSTOMP_RX_ABORT		0x00000002
++#define AR5K_XRSTOMP_RSSI_THRES		0x0000ff00
++
++/*
++ * First enhanced sleep register
++ */
++#define AR5K_SLEEP0			0x80d4
++#define AR5K_SLEEP0_NEXT_DTIM		0x0007ffff
++#define AR5K_SLEEP0_NEXT_DTIM_S		0
++#define AR5K_SLEEP0_ASSUME_DTIM		0x00080000
++#define AR5K_SLEEP0_ENH_SLEEP_EN	0x00100000
++#define AR5K_SLEEP0_CABTO		0xff000000
++#define AR5K_SLEEP0_CABTO_S		24
++
++/*
++ * Second enhanced sleep register
++ */
++#define AR5K_SLEEP1			0x80d8
++#define AR5K_SLEEP1_NEXT_TIM		0x0007ffff
++#define AR5K_SLEEP1_NEXT_TIM_S		0
++#define AR5K_SLEEP1_BEACON_TO		0xff000000
++#define AR5K_SLEEP1_BEACON_TO_S		24
++
++/*
++ * Third enhanced sleep register
++ */
++#define AR5K_SLEEP2			0x80dc
++#define AR5K_SLEEP2_TIM_PER		0x0000ffff
++#define AR5K_SLEEP2_TIM_PER_S		0
++#define AR5K_SLEEP2_DTIM_PER		0xffff0000
++#define AR5K_SLEEP2_DTIM_PER_S		16
++
++/*
++ * BSSID mask registers
++ */
++#define AR5K_BSS_IDM0			0x80e0
++#define AR5K_BSS_IDM1			0x80e4
++
++/*
++ * TX power control (TPC) register
++ */
++#define AR5K_TXPC			0x80e8
++#define AR5K_TXPC_ACK_M			0x0000003f
++#define AR5K_TXPC_ACK_S			0
++#define AR5K_TXPC_CTS_M			0x00003f00
++#define AR5K_TXPC_CTS_S			8
++#define AR5K_TXPC_CHIRP_M		0x003f0000
++#define AR5K_TXPC_CHIRP_S		22
++
++/*
++ * Profile count registers
++ */
++#define AR5K_PROFCNT_TX			0x80ec
++#define AR5K_PROFCNT_RX			0x80f0
++#define AR5K_PROFCNT_RXCLR		0x80f4
++#define AR5K_PROFCNT_CYCLE		0x80f8
++
++/*
++ * TSF parameter register
++ */
++#define AR5K_TSF_PARM			0x8104
++#define AR5K_TSF_PARM_INC_M		0x000000ff
++#define AR5K_TSF_PARM_INC_S		0
++
++/*
++ * PHY error filter register
++ */
++#define AR5K_PHY_ERR_FIL		0x810c
++#define AR5K_PHY_ERR_FIL_RADAR		0x00000020
++#define AR5K_PHY_ERR_FIL_OFDM		0x00020000
++#define AR5K_PHY_ERR_FIL_CCK		0x02000000
++
++/*
++ * Rate duration register
++ */
++#define AR5K_RATE_DUR_BASE		0x8700
++#define AR5K_RATE_DUR(_n)		(AR5K_RATE_DUR_BASE + ((_n) << 2))
++
++/*===5212 end===*/
++
++/*
++ * Key table (WEP) register
++ */
++#define AR5K_KEYTABLE_0_5210		0x9000
++#define AR5K_KEYTABLE_0_5211		0x8800
++#define AR5K_KEYTABLE_5210(_n)		(AR5K_KEYTABLE_0_5210 + ((_n) << 5))
++#define AR5K_KEYTABLE_5211(_n)		(AR5K_KEYTABLE_0_5211 + ((_n) << 5))
++#define	AR5K_KEYTABLE(_n)		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
++#define AR5K_KEYTABLE_OFF(_n, x)	(AR5K_KEYTABLE(_n) + (x << 2))
++#define AR5K_KEYTABLE_TYPE(_n)		AR5K_KEYTABLE_OFF(_n, 5)
++#define AR5K_KEYTABLE_TYPE_40		0x00000000
++#define AR5K_KEYTABLE_TYPE_104		0x00000001
++#define AR5K_KEYTABLE_TYPE_128		0x00000003
++#define AR5K_KEYTABLE_TYPE_TKIP		0x00000004	/* [5212+] */
++#define AR5K_KEYTABLE_TYPE_AES		0x00000005	/* [5211+] */
++#define AR5K_KEYTABLE_TYPE_CCM		0x00000006	/* [5212+] */
++#define AR5K_KEYTABLE_TYPE_NULL		0x00000007	/* [5211+] */
++#define AR5K_KEYTABLE_ANTENNA		0x00000008	/* [5212+] */
++#define AR5K_KEYTABLE_MAC0(_n)		AR5K_KEYTABLE_OFF(_n, 6)
++#define AR5K_KEYTABLE_MAC1(_n)		AR5K_KEYTABLE_OFF(_n, 7)
++#define AR5K_KEYTABLE_VALID		0x00008000
++
++/* WEP 40-bit	= 40-bit  entered key + 24 bit IV = 64-bit
++ * WEP 104-bit	= 104-bit entered key + 24-bit IV = 128-bit
++ * WEP 128-bit	= 128-bit entered key + 24 bit IV = 152-bit
++ *
++ * Some vendors have introduced bigger WEP keys to address
++ * security vulnerabilities in WEP. This includes:
++ *
++ * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
++ *
++ * We can expand this if we find ar5k Atheros cards with a larger
++ * key table size.
++ */
++#define AR5K_KEYTABLE_SIZE_5210		64
++#define AR5K_KEYTABLE_SIZE_5211		128
++#define	AR5K_KEYTABLE_SIZE		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
++
++
++/*===PHY REGISTERS===*/
++
++/*
++ * PHY register
++ */
++#define	AR5K_PHY_BASE			0x9800
++#define	AR5K_PHY(_n)			(AR5K_PHY_BASE + ((_n) << 2))
++#define AR5K_PHY_SHIFT_2GHZ		0x00004007
++#define AR5K_PHY_SHIFT_5GHZ		0x00000007
++
++/*
++ * PHY frame control register [5110] /turbo mode register [5111+]
++ *
++ * There is another frame control register for [5111+]
++ * at address 0x9944 (see below) but the 2 first flags
++ * are common here between 5110 frame control register
++ * and [5111+] turbo mode register, so this also works as
++ * a "turbo mode register" for 5110. We treat this one as
++ * a frame control register for 5110 below.
++ */
++#define	AR5K_PHY_TURBO			0x9804
++#define	AR5K_PHY_TURBO_MODE		0x00000001
++#define	AR5K_PHY_TURBO_SHORT		0x00000002
++
++/*
++ * PHY agility command register
++ */
++#define	AR5K_PHY_AGC			0x9808
++#define	AR5K_PHY_AGC_DISABLE		0x08000000
++
++/*
++ * PHY timing register [5112+]
++ */
++#define	AR5K_PHY_TIMING_3		0x9814
++#define	AR5K_PHY_TIMING_3_DSC_MAN	0xfffe0000
++#define	AR5K_PHY_TIMING_3_DSC_MAN_S	17
++#define	AR5K_PHY_TIMING_3_DSC_EXP	0x0001e000
++#define	AR5K_PHY_TIMING_3_DSC_EXP_S	13
++
++/*
++ * PHY chip revision register
++ */
++#define	AR5K_PHY_CHIP_ID		0x9818
++
++/*
++ * PHY activation register
++ */
++#define	AR5K_PHY_ACT			0x981c
++#define	AR5K_PHY_ACT_ENABLE		0x00000001
++#define	AR5K_PHY_ACT_DISABLE		0x00000002
++
++/*
++ * PHY signal register
++ */
++#define	AR5K_PHY_SIG			0x9858
++#define	AR5K_PHY_SIG_FIRSTEP		0x0003f000
++#define	AR5K_PHY_SIG_FIRSTEP_S		12
++#define	AR5K_PHY_SIG_FIRPWR		0x03fc0000
++#define	AR5K_PHY_SIG_FIRPWR_S		18
++
++/*
++ * PHY coarse agility control register
++ */
++#define	AR5K_PHY_AGCCOARSE		0x985c
++#define	AR5K_PHY_AGCCOARSE_LO		0x00007f80
++#define	AR5K_PHY_AGCCOARSE_LO_S		7
++#define	AR5K_PHY_AGCCOARSE_HI		0x003f8000
++#define	AR5K_PHY_AGCCOARSE_HI_S		15
++
++/*
++ * PHY agility control register
++ */
++#define	AR5K_PHY_AGCCTL			0x9860			/* Register address */
++#define	AR5K_PHY_AGCCTL_CAL		0x00000001	/* Enable PHY calibration */
++#define	AR5K_PHY_AGCCTL_NF		0x00000002	/* Enable Noise Floor calibration */
++
++/*
++ * PHY noise floor status register
++ */
++#define AR5K_PHY_NF			0x9864
++#define AR5K_PHY_NF_M			0x000001ff
++#define AR5K_PHY_NF_ACTIVE		0x00000100
++#define AR5K_PHY_NF_RVAL(_n)		(((_n) >> 19) & AR5K_PHY_NF_M)
++#define AR5K_PHY_NF_AVAL(_n)		(-((_n) ^ AR5K_PHY_NF_M) + 1)
++#define AR5K_PHY_NF_SVAL(_n)		(((_n) & AR5K_PHY_NF_M) | (1 << 9))
++
++/*
++ * PHY ADC saturation register [5110]
++ */
++#define	AR5K_PHY_ADCSAT			0x9868
++#define	AR5K_PHY_ADCSAT_ICNT		0x0001f800
++#define	AR5K_PHY_ADCSAT_ICNT_S		11
++#define	AR5K_PHY_ADCSAT_THR		0x000007e0
++#define	AR5K_PHY_ADCSAT_THR_S		5
++
++/*
++ * PHY sleep registers [5112+]
++ */
++#define AR5K_PHY_SCR			0x9870
++#define AR5K_PHY_SCR_32MHZ		0x0000001f
++#define AR5K_PHY_SLMT			0x9874
++#define AR5K_PHY_SLMT_32MHZ		0x0000007f
++#define AR5K_PHY_SCAL			0x9878
++#define AR5K_PHY_SCAL_32MHZ		0x0000000e
++
++/*
++ * PHY PLL (Phase Locked Loop) control register
++ */
++#define	AR5K_PHY_PLL			0x987c
++#define	AR5K_PHY_PLL_20MHZ		0x13	/* For half rate (?) [5111+] */
++#define	AR5K_PHY_PLL_40MHZ_5211		0x18	/* For 802.11a */
++#define	AR5K_PHY_PLL_40MHZ_5212		0x000000aa
++#define	AR5K_PHY_PLL_40MHZ		(ah->ah_version == AR5K_AR5211 ? \
++					AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212)
++#define	AR5K_PHY_PLL_44MHZ_5211		0x19	/* For 802.11b/g */
++#define	AR5K_PHY_PLL_44MHZ_5212		0x000000ab
++#define	AR5K_PHY_PLL_44MHZ		(ah->ah_version == AR5K_AR5211 ? \
++					AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
++#define AR5K_PHY_PLL_RF5111		0x00000000
++#define AR5K_PHY_PLL_RF5112		0x00000040
++
++/*
++ * RF Buffer register
++ *
++ * There are some special control registers on the RF chip
++ * that hold various operation settings related mostly to
++ * the analog parts (channel, gain adjustment etc).
++ *
++ * We don't write on those registers directly but
++ * we send a data packet on the buffer register and
++ * then write on another special register to notify hw
++ * to apply the settings. This is done so that control registers
++ * can be dynamicaly programmed during operation and the settings
++ * are applied faster on the hw.
++ *
++ * We sent such data packets during rf initialization and channel change
++ * through ath5k_hw_rf*_rfregs and ath5k_hw_rf*_channel functions.
++ *
++ * The data packets we send during initializadion are inside ath5k_ini_rf
++ * struct (see ath5k_hw.h) and each one is related to an "rf register bank".
++ * We use *rfregs functions to modify them  acording to current operation
++ * mode and eeprom values and pass them all together to the chip.
++ *
++ * It's obvious from the code that 0x989c is the buffer register but
++ * for the other special registers that we write to after sending each
++ * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
++ * for now. It's interesting that they are also used for some other operations.
++ *
++ * Also check out hw.h and U.S. Patent 6677779 B1 (about buffer
++ * registers and control registers):
++ *
++ * http://www.google.com/patents?id=qNURAAAAEBAJ
++ */
++
++#define AR5K_RF_BUFFER			0x989c
++#define AR5K_RF_BUFFER_CONTROL_0	0x98c0	/* Channel on 5110 */
++#define AR5K_RF_BUFFER_CONTROL_1	0x98c4	/* Bank 7 on 5112 */
++#define AR5K_RF_BUFFER_CONTROL_2	0x98cc	/* Bank 7 on 5111 */
++
++#define AR5K_RF_BUFFER_CONTROL_3	0x98d0	/* Bank 2 on 5112 */
++						/* Channel set on 5111 */
++						/* Used to read radio revision*/
++
++#define AR5K_RF_BUFFER_CONTROL_4	0x98d4  /* RF Stage register on 5110 */
++						/* Bank 0,1,2,6 on 5111 */
++						/* Bank 1 on 5112 */
++						/* Used during activation on 5111 */
++
++#define AR5K_RF_BUFFER_CONTROL_5	0x98d8	/* Bank 3 on 5111 */
++						/* Used during activation on 5111 */
++						/* Channel on 5112 */
++						/* Bank 6 on 5112 */
++
++#define AR5K_RF_BUFFER_CONTROL_6	0x98dc	/* Bank 3 on 5112 */
++
++/*
++ * PHY RF stage register [5210]
++ */
++#define AR5K_PHY_RFSTG			0x98d4
++#define AR5K_PHY_RFSTG_DISABLE		0x00000021
++
++/*
++ * PHY receiver delay register [5111+]
++ */
++#define	AR5K_PHY_RX_DELAY		0x9914
++#define	AR5K_PHY_RX_DELAY_M		0x00003fff
++
++/*
++ * PHY timing I(nphase) Q(adrature) control register [5111+]
++ */
++#define	AR5K_PHY_IQ			0x9920		/* Register address */
++#define	AR5K_PHY_IQ_CORR_Q_Q_COFF	0x0000001f	/* Mask for q correction info */
++#define	AR5K_PHY_IQ_CORR_Q_I_COFF	0x000007e0	/* Mask for i correction info */
++#define	AR5K_PHY_IQ_CORR_Q_I_COFF_S	5
++#define	AR5K_PHY_IQ_CORR_ENABLE		0x00000800	/* Enable i/q correction */
++#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX	0x0000f000
++#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S	12
++#define	AR5K_PHY_IQ_RUN			0x00010000	/* Run i/q calibration */
++
++
++/*
++ * PHY PAPD probe register [5111+ (?)]
++ * Is this only present in 5212 ?
++ * Because it's always 0 in 5211 initialization code
++ */
++#define	AR5K_PHY_PAPD_PROBE		0x9930
++#define	AR5K_PHY_PAPD_PROBE_TXPOWER	0x00007e00
++#define	AR5K_PHY_PAPD_PROBE_TXPOWER_S	9
++#define	AR5K_PHY_PAPD_PROBE_TX_NEXT	0x00008000
++#define	AR5K_PHY_PAPD_PROBE_TYPE	0x01800000	/* [5112+] */
++#define	AR5K_PHY_PAPD_PROBE_TYPE_S	23
++#define	AR5K_PHY_PAPD_PROBE_TYPE_OFDM	0
++#define	AR5K_PHY_PAPD_PROBE_TYPE_XR	1
++#define	AR5K_PHY_PAPD_PROBE_TYPE_CCK	2
++#define	AR5K_PHY_PAPD_PROBE_GAINF	0xfe000000
++#define	AR5K_PHY_PAPD_PROBE_GAINF_S	25
++#define	AR5K_PHY_PAPD_PROBE_INI_5111	0x00004883	/* [5212+] */
++#define	AR5K_PHY_PAPD_PROBE_INI_5112	0x00004882	/* [5212+] */
++
++
++/*
++ * PHY TX rate power registers [5112+]
++ */
++#define	AR5K_PHY_TXPOWER_RATE1			0x9934
++#define	AR5K_PHY_TXPOWER_RATE2			0x9938
++#define	AR5K_PHY_TXPOWER_RATE_MAX		0x993c
++#define	AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE	0x00000040
++#define	AR5K_PHY_TXPOWER_RATE3			0xa234
++#define	AR5K_PHY_TXPOWER_RATE4			0xa238
++
++/*
++ * PHY frame control register [5111+]
++ */
++#define	AR5K_PHY_FRAME_CTL_5210		0x9804
++#define	AR5K_PHY_FRAME_CTL_5211		0x9944
++#define	AR5K_PHY_FRAME_CTL		(ah->ah_version == AR5K_AR5210 ? \
++					AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
++/*---[5111+]---*/
++#define	AR5K_PHY_FRAME_CTL_TX_CLIP	0x00000038
++#define	AR5K_PHY_FRAME_CTL_TX_CLIP_S	3
++/*---[5110/5111]---*/
++#define	AR5K_PHY_FRAME_CTL_TIMING_ERR	0x01000000
++#define	AR5K_PHY_FRAME_CTL_PARITY_ERR	0x02000000
++#define	AR5K_PHY_FRAME_CTL_ILLRATE_ERR	0x04000000	/* illegal rate */
++#define	AR5K_PHY_FRAME_CTL_ILLLEN_ERR	0x08000000	/* illegal length */
++#define	AR5K_PHY_FRAME_CTL_SERVICE_ERR	0x20000000
++#define	AR5K_PHY_FRAME_CTL_TXURN_ERR	0x40000000	/* tx underrun */
++#define AR5K_PHY_FRAME_CTL_INI		AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
++			AR5K_PHY_FRAME_CTL_TXURN_ERR | \
++			AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
++			AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
++			AR5K_PHY_FRAME_CTL_PARITY_ERR | \
++			AR5K_PHY_FRAME_CTL_TIMING_ERR
++
++/*
++ * PHY radar detection register [5111+]
++ */
++#define	AR5K_PHY_RADAR			0x9954
++
++/* Radar enable 			........ ........ ........ .......1 */
++#define	AR5K_PHY_RADAR_ENABLE		0x00000001
++#define	AR5K_PHY_RADAR_DISABLE          0x00000000
++#define	AR5K_PHY_RADAR_ENABLE_S		0
++
++/* This is the value found on the card  .1.111.1 .1.1.... 111....1 1...1...
++at power on. */
++#define	AR5K_PHY_RADAR_PWONDEF_AR5213	0x5d50e188
++
++/* This is the value found on the card 	.1.1.111 ..11...1 .1...1.1 1...11.1
++after DFS is enabled */
++#define	AR5K_PHY_RADAR_ENABLED_AR5213	0x5731458d
++
++/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........
++ * power out threshold.
++ * 7-bits, standard power range {0..127} in 1/2 dBm units. */
++#define AR5K_PHY_RADAR_FIRPWROUTTHR    	0x7f000000
++#define AR5K_PHY_RADAR_FIRPWROUTTHR_S	24
++
++/* Radar RSSI/SNR threshold.		........ 111111.. ........ ........
++ * 6-bits, dBm range {0..63} in dBm units. */
++#define AR5K_PHY_RADAR_RADARRSSITHR    	0x00fc0000
++#define AR5K_PHY_RADAR_RADARRSSITHR_S	18
++
++/* Pulse height threshold 		........ ......11 1111.... ........
++ * 6-bits, dBm range {0..63} in dBm units. */
++#define AR5K_PHY_RADAR_PULSEHEIGHTTHR   0x0003f000
++#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S	12
++
++/* Pulse RSSI/SNR threshold		........ ........ ....1111 11......
++ * 6-bits, dBm range {0..63} in dBm units. */
++#define AR5K_PHY_RADAR_PULSERSSITHR    	0x00000fc0
++#define AR5K_PHY_RADAR_PULSERSSITHR_S	6
++
++/* Inband threshold  			........ ........ ........ ..11111.
++ * 5-bits, units unknown {0..31} (? MHz ?) */
++#define AR5K_PHY_RADAR_INBANDTHR    	0x0000003e
++#define AR5K_PHY_RADAR_INBANDTHR_S	1
++
++/*
++ * PHY antenna switch table registers [5110]
++ */
++#define AR5K_PHY_ANT_SWITCH_TABLE_0	0x9960
++#define AR5K_PHY_ANT_SWITCH_TABLE_1	0x9964
++
++/*
++ * PHY clock sleep registers [5112+]
++ */
++#define AR5K_PHY_SCLOCK			0x99f0
++#define AR5K_PHY_SCLOCK_32MHZ		0x0000000c
++#define AR5K_PHY_SDELAY			0x99f4
++#define AR5K_PHY_SDELAY_32MHZ		0x000000ff
++#define AR5K_PHY_SPENDING		0x99f8
++#define AR5K_PHY_SPENDING_RF5111	0x00000018
++#define AR5K_PHY_SPENDING_RF5112	0x00000014
++
++/*
++ * Misc PHY/radio registers [5110 - 5111]
++ */
++#define	AR5K_BB_GAIN_BASE		0x9b00 /* BaseBand Amplifier Gain table base address */
++#define AR5K_BB_GAIN(_n)		(AR5K_BB_GAIN_BASE + ((_n) << 2))
++#define	AR5K_RF_GAIN_BASE		0x9a00 /* RF Amplrifier Gain table base address */
++#define AR5K_RF_GAIN(_n)		(AR5K_RF_GAIN_BASE + ((_n) << 2))
++
++/*
++ * PHY timing IQ calibration result register [5111+]
++ */
++#define	AR5K_PHY_IQRES_CAL_PWR_I	0x9c10 /* I (Inphase) power value */
++#define	AR5K_PHY_IQRES_CAL_PWR_Q	0x9c14 /* Q (Quadrature) power value */
++#define	AR5K_PHY_IQRES_CAL_CORR		0x9c18	/* I/Q Correlation */
++
++/*
++ * PHY current RSSI register [5111+]
++ */
++#define	AR5K_PHY_CURRENT_RSSI		0x9c1c
++
++/*
++ * PHY PCDAC TX power table
++ */
++#define	AR5K_PHY_PCDAC_TXPOWER_BASE_5211	0xa180
++#define AR5K_PHY_PCDAC_TXPOWER_BASE_5413	0xa280
++#define AR5K_PHY_PCDAC_TXPOWER_BASE	(ah->ah_radio >= AR5K_RF5413 ? \
++					AR5K_PHY_PCDAC_TXPOWER_BASE_5413 :\
++					AR5K_PHY_PCDAC_TXPOWER_BASE_5211)
++#define	AR5K_PHY_PCDAC_TXPOWER(_n)	(AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
++
++/*
++ * PHY mode register [5111+]
++ */
++#define	AR5K_PHY_MODE			0x0a200		/* Register address */
++#define	AR5K_PHY_MODE_MOD		0x00000001	/* PHY Modulation mask*/
++#define AR5K_PHY_MODE_MOD_OFDM		0
++#define AR5K_PHY_MODE_MOD_CCK		1
++#define AR5K_PHY_MODE_FREQ		0x00000002	/* Freq mode mask */
++#define	AR5K_PHY_MODE_FREQ_5GHZ		0
++#define	AR5K_PHY_MODE_FREQ_2GHZ		2
++#define AR5K_PHY_MODE_MOD_DYN		0x00000004	/* Dynamic OFDM/CCK mode mask [5112+] */
++#define AR5K_PHY_MODE_RAD		0x00000008	/* [5212+] */
++#define AR5K_PHY_MODE_RAD_RF5111	0
++#define AR5K_PHY_MODE_RAD_RF5112	8
++#define AR5K_PHY_MODE_XR		0x00000010	/* [5112+] */
++
++/*
++ * PHY CCK transmit control register [5111+ (?)]
++ */
++#define AR5K_PHY_CCKTXCTL		0xa204
++#define AR5K_PHY_CCKTXCTL_WORLD		0x00000000
++#define AR5K_PHY_CCKTXCTL_JAPAN		0x00000010
++
++/*
++ * PHY 2GHz gain register [5111+]
++ */
++#define	AR5K_PHY_GAIN_2GHZ		0xa20c
++#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX	0x00fc0000
++#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S	18
++#define	AR5K_PHY_GAIN_2GHZ_INI_5111	0x6480416c
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.h
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.h	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,500 @@
++/*
++ * Copyright (c) 2004, 2005 Reyk Floeter <reyk at openbsd.org>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef _IEEE80211_REGDOMAIN_H_
++#define _IEEE80211_REGDOMAIN_H_
++
++#include <linux/types.h>
++
++/* Default regulation domain if stored value EEPROM value is invalid */
++#define AR5K_TUNE_REGDOMAIN	DMN_FCC2_FCCA	/* Canada */
++#define AR5K_TUNE_CTRY		CTRY_DEFAULT
++
++
++enum ath5k_regdom {
++	DMN_DEFAULT		= 0x00,
++	DMN_NULL_WORLD		= 0x03,
++	DMN_NULL_ETSIB		= 0x07,
++	DMN_NULL_ETSIC		= 0x08,
++	DMN_FCC1_FCCA		= 0x10,
++	DMN_FCC1_WORLD		= 0x11,
++	DMN_FCC2_FCCA		= 0x20,
++	DMN_FCC2_WORLD		= 0x21,
++	DMN_FCC2_ETSIC		= 0x22,
++	DMN_FRANCE_NULL		= 0x31,
++	DMN_FCC3_FCCA		= 0x3A,
++	DMN_ETSI1_WORLD		= 0x37,
++	DMN_ETSI3_ETSIA		= 0x32,
++	DMN_ETSI2_WORLD		= 0x35,
++	DMN_ETSI3_WORLD		= 0x36,
++	DMN_ETSI4_WORLD		= 0x30,
++	DMN_ETSI4_ETSIC		= 0x38,
++	DMN_ETSI5_WORLD		= 0x39,
++	DMN_ETSI6_WORLD		= 0x34,
++	DMN_ETSI_NULL		= 0x33,
++	DMN_MKK1_MKKA		= 0x40,
++	DMN_MKK1_MKKB		= 0x41,
++	DMN_APL4_WORLD		= 0x42,
++	DMN_MKK2_MKKA		= 0x43,
++	DMN_APL_NULL		= 0x44,
++	DMN_APL2_WORLD		= 0x45,
++	DMN_APL2_APLC		= 0x46,
++	DMN_APL3_WORLD		= 0x47,
++	DMN_MKK1_FCCA		= 0x48,
++	DMN_APL2_APLD		= 0x49,
++	DMN_MKK1_MKKA1		= 0x4A,
++	DMN_MKK1_MKKA2		= 0x4B,
++	DMN_APL1_WORLD		= 0x52,
++	DMN_APL1_FCCA		= 0x53,
++	DMN_APL1_APLA		= 0x54,
++	DMN_APL1_ETSIC		= 0x55,
++	DMN_APL2_ETSIC		= 0x56,
++	DMN_APL5_WORLD		= 0x58,
++	DMN_WOR0_WORLD		= 0x60,
++	DMN_WOR1_WORLD		= 0x61,
++	DMN_WOR2_WORLD		= 0x62,
++	DMN_WOR3_WORLD		= 0x63,
++	DMN_WOR4_WORLD		= 0x64,
++	DMN_WOR5_ETSIC		= 0x65,
++	DMN_WOR01_WORLD		= 0x66,
++	DMN_WOR02_WORLD		= 0x67,
++	DMN_EU1_WORLD		= 0x68,
++	DMN_WOR9_WORLD		= 0x69,
++	DMN_WORA_WORLD		= 0x6A,
++
++	DMN_APL1		= 0xf0000001,
++	DMN_APL2		= 0xf0000002,
++	DMN_APL3		= 0xf0000004,
++	DMN_APL4		= 0xf0000008,
++	DMN_APL5		= 0xf0000010,
++	DMN_ETSI1		= 0xf0000020,
++	DMN_ETSI2		= 0xf0000040,
++	DMN_ETSI3		= 0xf0000080,
++	DMN_ETSI4		= 0xf0000100,
++	DMN_ETSI5		= 0xf0000200,
++	DMN_ETSI6		= 0xf0000400,
++	DMN_ETSIA		= 0xf0000800,
++	DMN_ETSIB		= 0xf0001000,
++	DMN_ETSIC		= 0xf0002000,
++	DMN_FCC1		= 0xf0004000,
++	DMN_FCC2		= 0xf0008000,
++	DMN_FCC3		= 0xf0010000,
++	DMN_FCCA		= 0xf0020000,
++	DMN_APLD		= 0xf0040000,
++	DMN_MKK1		= 0xf0080000,
++	DMN_MKK2		= 0xf0100000,
++	DMN_MKKA		= 0xf0200000,
++	DMN_NULL		= 0xf0400000,
++	DMN_WORLD		= 0xf0800000,
++	DMN_DEBUG               = 0xf1000000	/* used for debugging */
++};
++
++#define IEEE80211_DMN(_d)	((_d) & ~0xf0000000)
++
++enum ath5k_countrycode {
++	CTRY_DEFAULT            = 0,   /* Default domain (NA) */
++	CTRY_ALBANIA            = 8,   /* Albania */
++	CTRY_ALGERIA            = 12,  /* Algeria */
++	CTRY_ARGENTINA          = 32,  /* Argentina */
++	CTRY_ARMENIA            = 51,  /* Armenia */
++	CTRY_AUSTRALIA          = 36,  /* Australia */
++	CTRY_AUSTRIA            = 40,  /* Austria */
++	CTRY_AZERBAIJAN         = 31,  /* Azerbaijan */
++	CTRY_BAHRAIN            = 48,  /* Bahrain */
++	CTRY_BELARUS            = 112, /* Belarus */
++	CTRY_BELGIUM            = 56,  /* Belgium */
++	CTRY_BELIZE             = 84,  /* Belize */
++	CTRY_BOLIVIA            = 68,  /* Bolivia */
++	CTRY_BRAZIL             = 76,  /* Brazil */
++	CTRY_BRUNEI_DARUSSALAM  = 96,  /* Brunei Darussalam */
++	CTRY_BULGARIA           = 100, /* Bulgaria */
++	CTRY_CANADA             = 124, /* Canada */
++	CTRY_CHILE              = 152, /* Chile */
++	CTRY_CHINA              = 156, /* People's Republic of China */
++	CTRY_COLOMBIA           = 170, /* Colombia */
++	CTRY_COSTA_RICA         = 188, /* Costa Rica */
++	CTRY_CROATIA            = 191, /* Croatia */
++	CTRY_CYPRUS             = 196, /* Cyprus */
++	CTRY_CZECH              = 203, /* Czech Republic */
++	CTRY_DENMARK            = 208, /* Denmark */
++	CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */
++	CTRY_ECUADOR            = 218, /* Ecuador */
++	CTRY_EGYPT              = 818, /* Egypt */
++	CTRY_EL_SALVADOR        = 222, /* El Salvador */
++	CTRY_ESTONIA            = 233, /* Estonia */
++	CTRY_FAEROE_ISLANDS     = 234, /* Faeroe Islands */
++	CTRY_FINLAND            = 246, /* Finland */
++	CTRY_FRANCE             = 250, /* France */
++	CTRY_FRANCE2            = 255, /* France2 */
++	CTRY_GEORGIA            = 268, /* Georgia */
++	CTRY_GERMANY            = 276, /* Germany */
++	CTRY_GREECE             = 300, /* Greece */
++	CTRY_GUATEMALA          = 320, /* Guatemala */
++	CTRY_HONDURAS           = 340, /* Honduras */
++	CTRY_HONG_KONG          = 344, /* Hong Kong S.A.R., P.R.C. */
++	CTRY_HUNGARY            = 348, /* Hungary */
++	CTRY_ICELAND            = 352, /* Iceland */
++	CTRY_INDIA              = 356, /* India */
++	CTRY_INDONESIA          = 360, /* Indonesia */
++	CTRY_IRAN               = 364, /* Iran */
++	CTRY_IRAQ               = 368, /* Iraq */
++	CTRY_IRELAND            = 372, /* Ireland */
++	CTRY_ISRAEL             = 376, /* Israel */
++	CTRY_ITALY              = 380, /* Italy */
++	CTRY_JAMAICA            = 388, /* Jamaica */
++	CTRY_JAPAN              = 392, /* Japan */
++	CTRY_JAPAN1             = 393, /* Japan (JP1) */
++	CTRY_JAPAN2             = 394, /* Japan (JP0) */
++	CTRY_JAPAN3             = 395, /* Japan (JP1-1) */
++	CTRY_JAPAN4             = 396, /* Japan (JE1) */
++	CTRY_JAPAN5             = 397, /* Japan (JE2) */
++	CTRY_JORDAN             = 400, /* Jordan */
++	CTRY_KAZAKHSTAN         = 398, /* Kazakhstan */
++	CTRY_KENYA              = 404, /* Kenya */
++	CTRY_KOREA_NORTH        = 408, /* North Korea */
++	CTRY_KOREA_ROC          = 410, /* South Korea */
++	CTRY_KOREA_ROC2         = 411, /* South Korea */
++	CTRY_KUWAIT             = 414, /* Kuwait */
++	CTRY_LATVIA             = 428, /* Latvia */
++	CTRY_LEBANON            = 422, /* Lebanon */
++	CTRY_LIBYA              = 434, /* Libya */
++	CTRY_LIECHTENSTEIN      = 438, /* Liechtenstein */
++	CTRY_LITHUANIA          = 440, /* Lithuania */
++	CTRY_LUXEMBOURG         = 442, /* Luxembourg */
++	CTRY_MACAU              = 446, /* Macau */
++	CTRY_MACEDONIA          = 807, /* Republic of Macedonia */
++	CTRY_MALAYSIA           = 458, /* Malaysia */
++	CTRY_MEXICO             = 484, /* Mexico */
++	CTRY_MONACO             = 492, /* Principality of Monaco */
++	CTRY_MOROCCO            = 504, /* Morocco */
++	CTRY_NETHERLANDS        = 528, /* Netherlands */
++	CTRY_NEW_ZEALAND        = 554, /* New Zealand */
++	CTRY_NICARAGUA          = 558, /* Nicaragua */
++	CTRY_NORWAY             = 578, /* Norway */
++	CTRY_OMAN               = 512, /* Oman */
++	CTRY_PAKISTAN           = 586, /* Islamic Republic of Pakistan */
++	CTRY_PANAMA             = 591, /* Panama */
++	CTRY_PARAGUAY           = 600, /* Paraguay */
++	CTRY_PERU               = 604, /* Peru */
++	CTRY_PHILIPPINES        = 608, /* Republic of the Philippines */
++	CTRY_POLAND             = 616, /* Poland */
++	CTRY_PORTUGAL           = 620, /* Portugal */
++	CTRY_PUERTO_RICO        = 630, /* Puerto Rico */
++	CTRY_QATAR              = 634, /* Qatar */
++	CTRY_ROMANIA            = 642, /* Romania */
++	CTRY_RUSSIA             = 643, /* Russia */
++	CTRY_SAUDI_ARABIA       = 682, /* Saudi Arabia */
++	CTRY_SINGAPORE          = 702, /* Singapore */
++	CTRY_SLOVAKIA           = 703, /* Slovak Republic */
++	CTRY_SLOVENIA           = 705, /* Slovenia */
++	CTRY_SOUTH_AFRICA       = 710, /* South Africa */
++	CTRY_SPAIN              = 724, /* Spain */
++	CTRY_SRI_LANKA          = 728, /* Sri Lanka */
++	CTRY_SWEDEN             = 752, /* Sweden */
++	CTRY_SWITZERLAND        = 756, /* Switzerland */
++	CTRY_SYRIA              = 760, /* Syria */
++	CTRY_TAIWAN             = 158, /* Taiwan */
++	CTRY_THAILAND           = 764, /* Thailand */
++	CTRY_TRINIDAD_Y_TOBAGO  = 780, /* Trinidad y Tobago */
++	CTRY_TUNISIA            = 788, /* Tunisia */
++	CTRY_TURKEY             = 792, /* Turkey */
++	CTRY_UAE                = 784, /* U.A.E. */
++	CTRY_UKRAINE            = 804, /* Ukraine */
++	CTRY_UNITED_KINGDOM     = 826, /* United Kingdom */
++	CTRY_UNITED_STATES      = 840, /* United States */
++	CTRY_URUGUAY            = 858, /* Uruguay */
++	CTRY_UZBEKISTAN         = 860, /* Uzbekistan */
++	CTRY_VENEZUELA          = 862, /* Venezuela */
++	CTRY_VIET_NAM           = 704, /* Viet Nam */
++	CTRY_YEMEN              = 887, /* Yemen */
++	CTRY_ZIMBABWE           = 716, /* Zimbabwe */
++};
++
++#define IEEE80211_CHANNELS_2GHZ_MIN	2412	/* 2GHz channel 1 */
++#define IEEE80211_CHANNELS_2GHZ_MAX	2732	/* 2GHz channel 26 */
++#define IEEE80211_CHANNELS_5GHZ_MIN	5005	/* 5GHz channel 1 */
++#define IEEE80211_CHANNELS_5GHZ_MAX	6100	/* 5GHz channel 220 */
++
++struct ath5k_regchannel {
++	u16 chan;
++	enum ath5k_regdom domain;
++	u32 mode;
++};
++
++#define IEEE80211_CHANNELS_2GHZ {					\
++/*2412*/ {   1, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2417*/ {   2, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2422*/ {   3, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2427*/ {   4, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2432*/ {   5, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2437*/ {   6, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2442*/ {   7, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2447*/ {   8, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2452*/ {   9, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2457*/ {  10, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2462*/ {  11, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2467*/ {  12, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2472*/ {  13, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++									\
++/*2432*/ {   5, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2437*/ {   6, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*2442*/ {   7, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM },			\
++									\
++/*2412*/ {   1, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2417*/ {   2, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2422*/ {   3, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2427*/ {   4, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2432*/ {   5, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2437*/ {   6, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*2442*/ {   7, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2447*/ {   8, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2452*/ {   9, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2457*/ {  10, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2462*/ {  11, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2467*/ {  12, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2472*/ {  13, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
++									\
++/*2412*/ {   1, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2417*/ {   2, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2422*/ {   3, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2427*/ {   4, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2432*/ {   5, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2437*/ {   6, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*2442*/ {   7, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2447*/ {   8, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2452*/ {   9, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2457*/ {  10, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2462*/ {  11, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
++									\
++/*2412*/ {   1, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2417*/ {   2, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2422*/ {   3, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2427*/ {   4, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2432*/ {   5, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2437*/ {   6, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2442*/ {   7, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2447*/ {   8, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2452*/ {   9, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2457*/ {  10, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2462*/ {  11, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2467*/ {  12, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2472*/ {  13, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2484*/ {  14, DMN_MKKA, CHANNEL_CCK },				\
++									\
++/*2412*/ {   1, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2417*/ {   2, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2422*/ {   3, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2427*/ {   4, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2432*/ {   5, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2437*/ {   6, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*2442*/ {   7, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2447*/ {   8, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2452*/ {   9, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2457*/ {  10, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2462*/ {  11, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2467*/ {  12, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++/*2472*/ {  13, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
++}
++
++#define IEEE80211_CHANNELS_5GHZ {			\
++/*5745*/ { 149, DMN_APL1, CHANNEL_OFDM },		\
++/*5765*/ { 153, DMN_APL1, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_APL1, CHANNEL_OFDM },		\
++/*5805*/ { 161, DMN_APL1, CHANNEL_OFDM },		\
++/*5825*/ { 165, DMN_APL1, CHANNEL_OFDM },		\
++							\
++/*5745*/ { 149, DMN_APL2, CHANNEL_OFDM },		\
++/*5765*/ { 153, DMN_APL2, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_APL2, CHANNEL_OFDM },		\
++/*5805*/ { 161, DMN_APL2, CHANNEL_OFDM },		\
++							\
++/*5280*/ {  56, DMN_APL3, CHANNEL_OFDM },		\
++/*5300*/ {  60, DMN_APL3, CHANNEL_OFDM },		\
++/*5320*/ {  64, DMN_APL3, CHANNEL_OFDM },		\
++/*5745*/ { 149, DMN_APL3, CHANNEL_OFDM },		\
++/*5765*/ { 153, DMN_APL3, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_APL3, CHANNEL_OFDM },		\
++/*5805*/ { 161, DMN_APL3, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_APL4, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_APL4, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_APL4, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_APL4, CHANNEL_OFDM },		\
++/*5745*/ { 149, DMN_APL4, CHANNEL_OFDM },		\
++/*5765*/ { 153, DMN_APL4, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_APL4, CHANNEL_OFDM },		\
++/*5805*/ { 161, DMN_APL4, CHANNEL_OFDM },		\
++/*5825*/ { 165, DMN_APL4, CHANNEL_OFDM },		\
++							\
++/*5745*/ { 149, DMN_APL5, CHANNEL_OFDM },		\
++/*5765*/ { 153, DMN_APL5, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_APL5, CHANNEL_OFDM },		\
++/*5805*/ { 161, DMN_APL5, CHANNEL_OFDM },		\
++/*5825*/ { 165, DMN_APL5, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5260*/ {  52, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5280*/ {  56, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5300*/ {  60, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5320*/ {  64, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5500*/ { 100, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5520*/ { 104, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5540*/ { 108, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5560*/ { 112, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5580*/ { 116, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5600*/ { 120, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5620*/ { 124, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5640*/ { 128, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5660*/ { 132, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5680*/ { 136, DMN_ETSI1, CHANNEL_OFDM },		\
++/*5700*/ { 140, DMN_ETSI1, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_ETSI2, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_ETSI2, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_ETSI2, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_ETSI2, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_ETSI3, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_ETSI3, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_ETSI3, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_ETSI3, CHANNEL_OFDM },		\
++/*5260*/ {  52, DMN_ETSI3, CHANNEL_OFDM },		\
++/*5280*/ {  56, DMN_ETSI3, CHANNEL_OFDM },		\
++/*5300*/ {  60, DMN_ETSI3, CHANNEL_OFDM },		\
++/*5320*/ {  64, DMN_ETSI3, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_ETSI4, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_ETSI4, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_ETSI4, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_ETSI4, CHANNEL_OFDM },		\
++/*5260*/ {  52, DMN_ETSI4, CHANNEL_OFDM },		\
++/*5280*/ {  56, DMN_ETSI4, CHANNEL_OFDM },		\
++/*5300*/ {  60, DMN_ETSI4, CHANNEL_OFDM },		\
++/*5320*/ {  64, DMN_ETSI4, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_ETSI5, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_ETSI5, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_ETSI5, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_ETSI5, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5260*/ {  52, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5280*/ {  56, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5500*/ { 100, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5520*/ { 104, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5540*/ { 108, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5560*/ { 112, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5580*/ { 116, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5600*/ { 120, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5620*/ { 124, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5640*/ { 128, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5660*/ { 132, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5680*/ { 136, DMN_ETSI6, CHANNEL_OFDM },		\
++/*5700*/ { 140, DMN_ETSI6, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_FCC1, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_FCC1, CHANNEL_OFDM },		\
++/*5210*/ {  42, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5220*/ {  44, DMN_FCC1, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_FCC1, CHANNEL_OFDM },		\
++/*5250*/ {  50, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5260*/ {  52, DMN_FCC1, CHANNEL_OFDM },		\
++/*5280*/ {  56, DMN_FCC1, CHANNEL_OFDM },		\
++/*5290*/ {  58, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5300*/ {  60, DMN_FCC1, CHANNEL_OFDM },		\
++/*5320*/ {  64, DMN_FCC1, CHANNEL_OFDM },		\
++/*5745*/ { 149, DMN_FCC1, CHANNEL_OFDM },		\
++/*5760*/ { 152, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5765*/ { 153, DMN_FCC1, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_FCC1, CHANNEL_OFDM },		\
++/*5800*/ { 160, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5805*/ { 161, DMN_FCC1, CHANNEL_OFDM },		\
++/*5825*/ { 165, DMN_FCC1, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_FCC2, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_FCC2, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_FCC2, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_FCC2, CHANNEL_OFDM },		\
++/*5260*/ {  52, DMN_FCC2, CHANNEL_OFDM },		\
++/*5280*/ {  56, DMN_FCC2, CHANNEL_OFDM },		\
++/*5300*/ {  60, DMN_FCC2, CHANNEL_OFDM },		\
++/*5320*/ {  64, DMN_FCC2, CHANNEL_OFDM },		\
++/*5745*/ { 149, DMN_FCC2, CHANNEL_OFDM },		\
++/*5765*/ { 153, DMN_FCC2, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_FCC2, CHANNEL_OFDM },		\
++/*5805*/ { 161, DMN_FCC2, CHANNEL_OFDM },		\
++/*5825*/ { 165, DMN_FCC2, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_FCC3, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_FCC3, CHANNEL_OFDM },		\
++/*5210*/ {  42, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5220*/ {  44, DMN_FCC3, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_FCC3, CHANNEL_OFDM },		\
++/*5250*/ {  50, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5260*/ {  52, DMN_FCC3, CHANNEL_OFDM },		\
++/*5280*/ {  56, DMN_FCC3, CHANNEL_OFDM },		\
++/*5290*/ {  58, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5300*/ {  60, DMN_FCC3, CHANNEL_OFDM },		\
++/*5320*/ {  64, DMN_FCC3, CHANNEL_OFDM },		\
++/*5500*/ { 100, DMN_FCC3, CHANNEL_OFDM },		\
++/*5520*/ { 104, DMN_FCC3, CHANNEL_OFDM },		\
++/*5540*/ { 108, DMN_FCC3, CHANNEL_OFDM },		\
++/*5560*/ { 112, DMN_FCC3, CHANNEL_OFDM },		\
++/*5580*/ { 116, DMN_FCC3, CHANNEL_OFDM },		\
++/*5600*/ { 120, DMN_FCC3, CHANNEL_OFDM },		\
++/*5620*/ { 124, DMN_FCC3, CHANNEL_OFDM },		\
++/*5640*/ { 128, DMN_FCC3, CHANNEL_OFDM },		\
++/*5660*/ { 132, DMN_FCC3, CHANNEL_OFDM },		\
++/*5680*/ { 136, DMN_FCC3, CHANNEL_OFDM },		\
++/*5700*/ { 140, DMN_FCC3, CHANNEL_OFDM },		\
++/*5745*/ { 149, DMN_FCC3, CHANNEL_OFDM },		\
++/*5760*/ { 152, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5765*/ { 153, DMN_FCC3, CHANNEL_OFDM },		\
++/*5785*/ { 157, DMN_FCC3, CHANNEL_OFDM },		\
++/*5800*/ { 160, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
++/*5805*/ { 161, DMN_FCC3, CHANNEL_OFDM },		\
++/*5825*/ { 165, DMN_FCC3, CHANNEL_OFDM },		\
++							\
++/*5170*/ {  34, DMN_MKK1, CHANNEL_OFDM },		\
++/*5190*/ {  38, DMN_MKK1, CHANNEL_OFDM },		\
++/*5210*/ {  42, DMN_MKK1, CHANNEL_OFDM },		\
++/*5230*/ {  46, DMN_MKK1, CHANNEL_OFDM },		\
++							\
++/*5040*/ {   8, DMN_MKK2, CHANNEL_OFDM },		\
++/*5060*/ {  12, DMN_MKK2, CHANNEL_OFDM },		\
++/*5080*/ {  16, DMN_MKK2, CHANNEL_OFDM },		\
++/*5170*/ {  34, DMN_MKK2, CHANNEL_OFDM },		\
++/*5190*/ {  38, DMN_MKK2, CHANNEL_OFDM },		\
++/*5210*/ {  42, DMN_MKK2, CHANNEL_OFDM },		\
++/*5230*/ {  46, DMN_MKK2, CHANNEL_OFDM },		\
++							\
++/*5180*/ {  36, DMN_WORLD, CHANNEL_OFDM },		\
++/*5200*/ {  40, DMN_WORLD, CHANNEL_OFDM },		\
++/*5220*/ {  44, DMN_WORLD, CHANNEL_OFDM },		\
++/*5240*/ {  48, DMN_WORLD, CHANNEL_OFDM },		\
++}
++
++enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom, u16);
++u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee);
++enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain);
++
++#endif
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.h
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.h	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,216 @@
++/*
++ * Copyright (c) 2007 Bruno Randolf <bruno at thinktube.com>
++ *
++ *  This file is free software: you may copy, redistribute and/or modify it
++ *  under the terms of the GNU General Public License as published by the
++ *  Free Software Foundation, either version 2 of the License, or (at your
++ *  option) any later version.
++ *
++ *  This file is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ *
++ * This file incorporates work covered by the following copyright and
++ * permission notice:
++ *
++ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
++ * Copyright (c) 2004-2005 Atheros Communications, Inc.
++ * Copyright (c) 2006 Devicescape Software, Inc.
++ * Copyright (c) 2007 Jiri Slaby <jirislaby at gmail.com>
++ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
++ *
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer,
++ *    without modification.
++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
++ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
++ *    redistribution must be conditioned upon including a substantially
++ *    similar Disclaimer requirement for further binary redistribution.
++ * 3. Neither the names of the above-listed copyright holders nor the names
++ *    of any contributors may be used to endorse or promote products derived
++ *    from this software without specific prior written permission.
++ *
++ * Alternatively, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2 as published by the Free
++ * Software Foundation.
++ *
++ * NO WARRANTY
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
++ * THE POSSIBILITY OF SUCH DAMAGES.
++ */
++
++#ifndef _ATH5K_DEBUG_H
++#define _ATH5K_DEBUG_H
++
++/* set this to 1 for debugging output */
++#ifndef ATH5K_DEBUG
++#define ATH5K_DEBUG	0
++#endif
++
++struct ath5k_softc;
++struct ath5k_hw;
++struct ieee80211_hw_mode;
++struct sk_buff;
++struct ath5k_buf;
++
++struct ath5k_dbg_info {
++	unsigned int		level;		/* debug level */
++	/* debugfs entries */
++	struct dentry		*debugfs_phydir;
++	struct dentry		*debugfs_debug;
++	struct dentry		*debugfs_registers;
++	struct dentry		*debugfs_tsf;
++	struct dentry		*debugfs_beacon;
++	struct dentry		*debugfs_reset;
++};
++
++/**
++ * enum ath5k_debug_level - ath5k debug level
++ *
++ * @ATH5K_DEBUG_RESET: reset processing
++ * @ATH5K_DEBUG_INTR: interrupt handling
++ * @ATH5K_DEBUG_MODE: mode init/setup
++ * @ATH5K_DEBUG_XMIT: basic xmit operation
++ * @ATH5K_DEBUG_BEACON: beacon handling
++ * @ATH5K_DEBUG_BEACON_PROC: beacon ISR proc
++ * @ATH5K_DEBUG_CALIBRATE: periodic calibration
++ * @ATH5K_DEBUG_TXPOWER: transmit power setting
++ * @ATH5K_DEBUG_LED: led management
++ * @ATH5K_DEBUG_DUMP_RX: print received skb content
++ * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
++ * @ATH5K_DEBUG_DUMPMODES: dump modes
++ * @ATH5K_DEBUG_TRACE: trace function calls
++ * @ATH5K_DEBUG_FATAL: fatal errors
++ * @ATH5K_DEBUG_ANY: show at any debug level
++ *
++ * The debug level is used to control the amount and type of debugging output
++ * we want to see. The debug level is given in calls to ATH5K_DBG to specify
++ * where the message should appear, and the user can control the debugging
++ * messages he wants to see, either by the module parameter 'debug' on module
++ * load, or dynamically by using debugfs 'ath5k/phyX/debug'. these levels can
++ * be combined together by bitwise OR.
++ */
++enum ath5k_debug_level {
++	ATH5K_DEBUG_RESET	= 0x00000001,
++	ATH5K_DEBUG_INTR	= 0x00000002,
++	ATH5K_DEBUG_MODE	= 0x00000004,
++	ATH5K_DEBUG_XMIT	= 0x00000008,
++	ATH5K_DEBUG_BEACON	= 0x00000010,
++	ATH5K_DEBUG_BEACON_PROC	= 0x00000020,
++	ATH5K_DEBUG_CALIBRATE	= 0x00000100,
++	ATH5K_DEBUG_TXPOWER	= 0x00000200,
++	ATH5K_DEBUG_LED		= 0x00000400,
++	ATH5K_DEBUG_DUMP_RX	= 0x00001000,
++	ATH5K_DEBUG_DUMP_TX	= 0x00002000,
++	ATH5K_DEBUG_DUMPMODES	= 0x00004000,
++	ATH5K_DEBUG_TRACE	= 0x00010000,
++	ATH5K_DEBUG_FATAL	= 0x80000000,
++	ATH5K_DEBUG_ANY		= 0xffffffff
++};
++
++#if ATH5K_DEBUG
++
++#define ATH5K_TRACE(_sc) do { \
++	if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
++		printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \
++	} while (0)
++
++#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \
++	if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \
++		ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
++			__func__, __LINE__, ##__VA_ARGS__); \
++	} while (0)
++
++#define ATH5K_DBG_UNLIMIT(_sc, _m, _fmt, ...) do { \
++	if (unlikely((_sc)->debug.level & (_m))) \
++		ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
++			__func__, __LINE__, ##__VA_ARGS__); \
++	} while (0)
++
++void
++ath5k_debug_init(void);
++
++void
++ath5k_debug_init_device(struct ath5k_softc *sc);
++
++void
++ath5k_debug_finish(void);
++
++void
++ath5k_debug_finish_device(struct ath5k_softc *sc);
++
++void
++ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
++
++void
++ath5k_debug_dump_modes(struct ath5k_softc *sc,
++			struct ieee80211_hw_mode *modes);
++
++void
++ath5k_debug_dump_skb(struct ath5k_softc *sc,
++			struct sk_buff *skb, const char *prefix, int tx);
++
++void
++ath5k_debug_printtxbuf(struct ath5k_softc *sc,
++			struct ath5k_buf *bf, int done);
++
++#else /* no debugging */
++
++#define ATH5K_TRACE(_sc) /* empty */
++
++static inline void __attribute__ ((format (printf, 3, 4)))
++ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
++
++static inline void __attribute__ ((format (printf, 3, 4)))
++ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...)
++{}
++
++static inline void
++ath5k_debug_init(void) {}
++
++static inline void
++ath5k_debug_init_device(struct ath5k_softc *sc) {}
++
++static inline void
++ath5k_debug_finish(void) {}
++
++static inline void
++ath5k_debug_finish_device(struct ath5k_softc *sc) {}
++
++static inline void
++ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
++
++static inline void
++ath5k_debug_dump_modes(struct ath5k_softc *sc,
++			struct ieee80211_hw_mode *modes) {}
++
++static inline void
++ath5k_debug_dump_skb(struct ath5k_softc *sc,
++			struct sk_buff *skb, const char *prefix, int tx) {}
++
++static inline void
++ath5k_debug_printtxbuf(struct ath5k_softc *sc,
++			struct ath5k_buf *bf, int done) {}
++
++#endif /* if ATH5K_DEBUG */
++
++#endif /* ifndef _ATH5K_DEBUG_H */
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.c
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.c	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,4349 @@
++ /*
++ * Copyright (c) 2004-2007 Reyk Floeter <reyk at openbsd.org>
++ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm at gmail.com>
++ * Copyright (c) 2007 Matthew W. S. Bell  <mentor at madwifi.org>
++ * Copyright (c) 2007 Luis Rodriguez <mcgrof at winlab.rutgers.edu>
++ * Copyright (c) 2007 Pavel Roskin <proski at gnu.org>
++ * Copyright (c) 2007 Jiri Slaby <jirislaby at gmail.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ */
++
++/*
++ * HW related functions for Atheros Wireless LAN devices.
++ */
++
++#include <linux/pci.h>
++#include <linux/delay.h>
++
++#include "reg.h"
++#include "base.h"
++#include "debug.h"
++
++/*Rate tables*/
++static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A;
++static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B;
++static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G;
++static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
++static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR;
++
++/*Prototypes*/
++static int ath5k_hw_nic_reset(struct ath5k_hw *, u32);
++static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool);
++static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
++	unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
++	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
++	unsigned int, unsigned int);
++static bool ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
++	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
++	unsigned int);
++static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
++static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
++	unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
++	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
++	unsigned int, unsigned int);
++static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
++static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *);
++static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *);
++static int ath5k_hw_get_capabilities(struct ath5k_hw *);
++
++static int ath5k_eeprom_init(struct ath5k_hw *);
++static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *);
++
++static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16);
++static int ath5k_hw_disable_pspoll(struct ath5k_hw *);
++
++/*
++ * Enable to overwrite the country code (use "00" for debug)
++ */
++#if 0
++#define COUNTRYCODE "00"
++#endif
++
++/*******************\
++  General Functions
++\*******************/
++
++/*
++ * Functions used internaly
++ */
++
++static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
++{
++	return turbo == true ? (usec * 80) : (usec * 40);
++}
++
++static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
++{
++	return turbo == true ? (clock / 80) : (clock / 40);
++}
++
++/*
++ * Check if a register write has been completed
++ */
++int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
++		bool is_set)
++{
++	int i;
++	u32 data;
++
++	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
++		data = ath5k_hw_reg_read(ah, reg);
++		if ((is_set == true) && (data & flag))
++			break;
++		else if ((data & flag) == val)
++			break;
++		udelay(15);
++	}
++
++	return (i <= 0) ? -EAGAIN : 0;
++}
++
++
++/***************************************\
++	Attach/Detach Functions
++\***************************************/
++
++/*
++ * Check if the device is supported and initialize the needed structs
++ */
++struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
++{
++	struct ath5k_hw *ah;
++	u8 mac[ETH_ALEN];
++	int ret;
++	u32 srev;
++
++	/*If we passed the test malloc a ath5k_hw struct*/
++	ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
++	if (ah == NULL) {
++		ret = -ENOMEM;
++		ATH5K_ERR(sc, "out of memory\n");
++		goto err;
++	}
++
++	ah->ah_sc = sc;
++	ah->ah_iobase = sc->iobase;
++
++	/*
++	 * HW information
++	 */
++
++	/* Get reg domain from eeprom */
++	ath5k_get_regdomain(ah);
++
++	ah->ah_op_mode = IEEE80211_IF_TYPE_STA;
++	ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
++	ah->ah_turbo = false;
++	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
++	ah->ah_imr = 0;
++	ah->ah_atim_window = 0;
++	ah->ah_aifs = AR5K_TUNE_AIFS;
++	ah->ah_cw_min = AR5K_TUNE_CWMIN;
++	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
++	ah->ah_software_retry = false;
++	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
++
++	/*
++	 * Set the mac revision based on the pci id
++	 */
++	ah->ah_version = mac_version;
++
++	/*Fill the ath5k_hw struct with the needed functions*/
++	if (ah->ah_version == AR5K_AR5212)
++		ah->ah_magic = AR5K_EEPROM_MAGIC_5212;
++	else if (ah->ah_version == AR5K_AR5211)
++		ah->ah_magic = AR5K_EEPROM_MAGIC_5211;
++
++	if (ah->ah_version == AR5K_AR5212) {
++		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
++		ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
++		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
++	} else {
++		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
++		ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
++		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
++	}
++
++	if (ah->ah_version == AR5K_AR5212)
++		ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status;
++	else if (ah->ah_version <= AR5K_AR5211)
++		ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status;
++
++	/* Bring device out of sleep and reset it's units */
++	ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true);
++	if (ret)
++		goto err_free;
++
++	/* Get MAC, PHY and RADIO revisions */
++	srev = ath5k_hw_reg_read(ah, AR5K_SREV);
++	ah->ah_mac_srev = srev;
++	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
++	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
++	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
++			0xffffffff;
++	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
++			CHANNEL_5GHZ);
++
++	if (ah->ah_version == AR5K_AR5210)
++		ah->ah_radio_2ghz_revision = 0;
++	else
++		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
++				CHANNEL_2GHZ);
++
++	/* Return on unsuported chips (unsupported eeprom etc) */
++	if(srev >= AR5K_SREV_VER_AR5416){
++		ATH5K_ERR(sc, "Device not yet supported.\n");
++		ret = -ENODEV;
++		goto err_free;
++	}
++
++	/* Identify single chip solutions */
++	if((srev <= AR5K_SREV_VER_AR5414) &&
++	(srev >= AR5K_SREV_VER_AR2424)) {
++		ah->ah_single_chip = true;
++	} else {
++		ah->ah_single_chip = false;
++	}
++
++	/* Single chip radio */
++	if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision)
++		ah->ah_radio_2ghz_revision = 0;
++
++	/* Identify the radio chip*/
++	if (ah->ah_version == AR5K_AR5210) {
++		ah->ah_radio = AR5K_RF5110;
++	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
++		ah->ah_radio = AR5K_RF5111;
++	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
++		ah->ah_radio = AR5K_RF5112;
++	} else {
++		ah->ah_radio = AR5K_RF5413;
++	}
++
++	ah->ah_phy = AR5K_PHY(0);
++
++	/*
++	 * Get card capabilities, values, ...
++	 */
++
++	ret = ath5k_eeprom_init(ah);
++	if (ret) {
++		ATH5K_ERR(sc, "unable to init EEPROM\n");
++		goto err_free;
++	}
++
++	/* Get misc capabilities */
++	ret = ath5k_hw_get_capabilities(ah);
++	if (ret) {
++		ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
++			sc->pdev->device);
++		goto err_free;
++	}
++
++	/* Get MAC address */
++	ret = ath5k_eeprom_read_mac(ah, mac);
++	if (ret) {
++		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
++			sc->pdev->device);
++		goto err_free;
++	}
++
++	ath5k_hw_set_lladdr(ah, mac);
++	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
++	memset(ah->bssid, 0xff, ETH_ALEN);
++	ath5k_hw_set_associd(ah, ah->bssid, 0);
++	ath5k_hw_set_opmode(ah);
++
++	ath5k_hw_set_rfgain_opt(ah);
++
++	return ah;
++err_free:
++	kfree(ah);
++err:
++	return ERR_PTR(ret);
++}
++
++/*
++ * Bring up MAC + PHY Chips
++ */
++static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
++{
++	u32 turbo, mode, clock;
++	int ret;
++
++	turbo = 0;
++	mode = 0;
++	clock = 0;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/* Wakeup the device */
++	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
++	if (ret) {
++		ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
++		return ret;
++	}
++
++	if (ah->ah_version != AR5K_AR5210) {
++		/*
++		 * Get channel mode flags
++		 */
++
++		if (ah->ah_radio >= AR5K_RF5112) {
++			mode = AR5K_PHY_MODE_RAD_RF5112;
++			clock = AR5K_PHY_PLL_RF5112;
++		} else {
++			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
++			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
++		}
++
++		if (flags & CHANNEL_2GHZ) {
++			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
++			clock |= AR5K_PHY_PLL_44MHZ;
++
++			if (flags & CHANNEL_CCK) {
++				mode |= AR5K_PHY_MODE_MOD_CCK;
++			} else if (flags & CHANNEL_OFDM) {
++				/* XXX Dynamic OFDM/CCK is not supported by the
++				 * AR5211 so we set MOD_OFDM for plain g (no
++				 * CCK headers) operation. We need to test
++				 * this, 5211 might support ofdm-only g after
++				 * all, there are also initial register values
++				 * in the code for g mode (see initvals.c). */
++				if (ah->ah_version == AR5K_AR5211)
++					mode |= AR5K_PHY_MODE_MOD_OFDM;
++				else
++					mode |= AR5K_PHY_MODE_MOD_DYN;
++			} else {
++				ATH5K_ERR(ah->ah_sc,
++					"invalid radio modulation mode\n");
++				return -EINVAL;
++			}
++		} else if (flags & CHANNEL_5GHZ) {
++			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
++			clock |= AR5K_PHY_PLL_40MHZ;
++
++			if (flags & CHANNEL_OFDM)
++				mode |= AR5K_PHY_MODE_MOD_OFDM;
++			else {
++				ATH5K_ERR(ah->ah_sc,
++					"invalid radio modulation mode\n");
++				return -EINVAL;
++			}
++		} else {
++			ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n");
++			return -EINVAL;
++		}
++
++		if (flags & CHANNEL_TURBO)
++			turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
++	} else { /* Reset the device */
++
++		/* ...enable Atheros turbo mode if requested */
++		if (flags & CHANNEL_TURBO)
++			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
++					AR5K_PHY_TURBO);
++	}
++
++	/* ...reset chipset and PCI device */
++	if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah,
++				AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) {
++		ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n");
++		return -EIO;
++	}
++
++	if (ah->ah_version == AR5K_AR5210)
++		udelay(2300);
++
++	/* ...wakeup again!*/
++	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
++	if (ret) {
++		ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
++		return ret;
++	}
++
++	/* ...final warm reset */
++	if (ath5k_hw_nic_reset(ah, 0)) {
++		ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
++		return -EIO;
++	}
++
++	if (ah->ah_version != AR5K_AR5210) {
++		/* ...set the PHY operating mode */
++		ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
++		udelay(300);
++
++		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
++		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
++	}
++
++	return 0;
++}
++
++/*
++ * Get the rate table for a specific operation mode
++ */
++const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah,
++		unsigned int mode)
++{
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (!test_bit(mode, ah->ah_capabilities.cap_mode))
++		return NULL;
++
++	/* Get rate tables */
++	switch (mode) {
++	case MODE_IEEE80211A:
++		return &ath5k_rt_11a;
++	case MODE_ATHEROS_TURBO:
++		return &ath5k_rt_turbo;
++	case MODE_IEEE80211B:
++		return &ath5k_rt_11b;
++	case MODE_IEEE80211G:
++		return &ath5k_rt_11g;
++	case MODE_ATHEROS_TURBOG:
++		return &ath5k_rt_xr;
++	}
++
++	return NULL;
++}
++
++/*
++ * Free the ath5k_hw struct
++ */
++void ath5k_hw_detach(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (ah->ah_rf_banks != NULL)
++		kfree(ah->ah_rf_banks);
++
++	/* assume interrupts are down */
++	kfree(ah);
++}
++
++/****************************\
++  Reset function and helpers
++\****************************/
++
++/**
++ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
++ *
++ * @ah: the &struct ath5k_hw
++ * @channel: the currently set channel upon reset
++ *
++ * Write the OFDM timings for the AR5212 upon reset. This is a helper for
++ * ath5k_hw_reset(). This seems to tune the PLL a specified frequency
++ * depending on the bandwidth of the channel.
++ *
++ */
++static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
++	struct ieee80211_channel *channel)
++{
++	/* Get exponent and mantissa and set it */
++	u32 coef_scaled, coef_exp, coef_man,
++		ds_coef_exp, ds_coef_man, clock;
++
++	if (!(ah->ah_version == AR5K_AR5212) ||
++		!(channel->val & CHANNEL_OFDM))
++		BUG();
++
++	/* Seems there are two PLLs, one for baseband sampling and one
++	 * for tuning. Tuning basebands are 40 MHz or 80MHz when in
++	 * turbo. */
++	clock = channel->val & CHANNEL_TURBO ? 80 : 40;
++	coef_scaled = ((5 * (clock << 24)) / 2) /
++	channel->freq;
++
++	for (coef_exp = 31; coef_exp > 0; coef_exp--)
++		if ((coef_scaled >> coef_exp) & 0x1)
++			break;
++
++	if (!coef_exp)
++		return -EINVAL;
++
++	coef_exp = 14 - (coef_exp - 24);
++	coef_man = coef_scaled +
++		(1 << (24 - coef_exp - 1));
++	ds_coef_man = coef_man >> (24 - coef_exp);
++	ds_coef_exp = coef_exp - 16;
++
++	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
++		AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
++	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
++		AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
++
++	return 0;
++}
++
++/**
++ * ath5k_hw_write_rate_duration - set rate duration during hw resets
++ *
++ * @ah: the &struct ath5k_hw
++ * @driver_mode: one of enum ieee80211_phymode or our one of our own
++ *     vendor modes
++ *
++ * Write the rate duration table for the current mode upon hw reset. This
++ * is a helper for ath5k_hw_reset(). It seems all this is doing is setting
++ * an ACK timeout for the hardware for the current mode for each rate. The
++ * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps,
++ * and 11Mbps) have another register for the short preamble ACK timeout
++ * calculation.
++ *
++ */
++static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
++       unsigned int driver_mode)
++{
++	struct ath5k_softc *sc = ah->ah_sc;
++	const struct ath5k_rate_table *rt;
++	unsigned int i;
++
++	/* Get rate table for the current operating mode */
++	rt = ath5k_hw_get_rate_table(ah,
++		driver_mode);
++
++	/* Write rate duration table */
++	for (i = 0; i < rt->rate_count; i++) {
++		const struct ath5k_rate *rate, *control_rate;
++		u32 reg;
++		u16 tx_time;
++
++		rate = &rt->rates[i];
++		control_rate = &rt->rates[rate->control_rate];
++
++		/* Set ACK timeout */
++		reg = AR5K_RATE_DUR(rate->rate_code);
++
++		/* An ACK frame consists of 10 bytes. If you add the FCS,
++		 * which ieee80211_generic_frame_duration() adds,
++		 * its 14 bytes. Note we use the control rate and not the
++		 * actual rate for this rate. See mac80211 tx.c
++		 * ieee80211_duration() for a brief description of
++		 * what rate we should choose to TX ACKs. */
++		tx_time = ieee80211_generic_frame_duration(sc->hw,
++			sc->iface_id, 10, control_rate->rate_kbps/100);
++
++		ath5k_hw_reg_write(ah, tx_time, reg);
++
++		if (!HAS_SHPREAMBLE(i))
++			continue;
++
++		/*
++		 * We're not distinguishing short preamble here,
++		 * This is true, all we'll get is a longer value here
++		 * which is not necessarilly bad. We could use
++		 * export ieee80211_frame_duration() but that needs to be
++		 * fixed first to be properly used by mac802111 drivers:
++		 *
++		 *  - remove erp stuff and let the routine figure ofdm
++		 *    erp rates
++		 *  - remove passing argument ieee80211_local as
++		 *    drivers don't have access to it
++		 *  - move drivers using ieee80211_generic_frame_duration()
++		 *    to this
++		 */
++		ath5k_hw_reg_write(ah, tx_time,
++			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
++	}
++}
++
++/*
++ * Main reset function
++ */
++int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
++	struct ieee80211_channel *channel, bool change_channel)
++{
++	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
++	u32 data, s_seq, s_ant, s_led[3];
++	unsigned int i, mode, freq, ee_mode, ant[2], driver_mode = -1;
++	int ret;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	s_seq = 0;
++	s_ant = 0;
++	ee_mode = 0;
++	freq = 0;
++	mode = 0;
++
++	/*
++	 * Save some registers before a reset
++	 */
++	/*DCU/Antenna selection not available on 5210*/
++	if (ah->ah_version != AR5K_AR5210) {
++		if (change_channel == true) {
++			/* Seq number for queue 0 -do this for all queues ? */
++			s_seq = ath5k_hw_reg_read(ah,
++					AR5K_QUEUE_DFS_SEQNUM(0));
++			/*Default antenna*/
++			s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
++		}
++	}
++
++	/*GPIOs*/
++	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
++	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
++	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
++
++	if (change_channel == true && ah->ah_rf_banks != NULL)
++		ath5k_hw_get_rf_gain(ah);
++
++
++	/*Wakeup the device*/
++	ret = ath5k_hw_nic_wakeup(ah, channel->val, false);
++	if (ret)
++		return ret;
++
++	/*
++	 * Initialize operating mode
++	 */
++	ah->ah_op_mode = op_mode;
++
++	/*
++	 * 5111/5112 Settings
++	 * 5210 only comes with RF5110
++	 */
++	if (ah->ah_version != AR5K_AR5210) {
++		if (ah->ah_radio != AR5K_RF5111 &&
++			ah->ah_radio != AR5K_RF5112 &&
++			ah->ah_radio != AR5K_RF5413) {
++			ATH5K_ERR(ah->ah_sc,
++				"invalid phy radio: %u\n", ah->ah_radio);
++			return -EINVAL;
++		}
++
++		switch (channel->val & CHANNEL_MODES) {
++		case CHANNEL_A:
++			mode = AR5K_INI_VAL_11A;
++			freq = AR5K_INI_RFGAIN_5GHZ;
++			ee_mode = AR5K_EEPROM_MODE_11A;
++			driver_mode = MODE_IEEE80211A;
++			break;
++		case CHANNEL_G:
++			mode = AR5K_INI_VAL_11G;
++			freq = AR5K_INI_RFGAIN_2GHZ;
++			ee_mode = AR5K_EEPROM_MODE_11G;
++			driver_mode = MODE_IEEE80211G;
++			break;
++		case CHANNEL_B:
++			mode = AR5K_INI_VAL_11B;
++			freq = AR5K_INI_RFGAIN_2GHZ;
++			ee_mode = AR5K_EEPROM_MODE_11B;
++			driver_mode = MODE_IEEE80211B;
++			break;
++		case CHANNEL_T:
++			mode = AR5K_INI_VAL_11A_TURBO;
++			freq = AR5K_INI_RFGAIN_5GHZ;
++			ee_mode = AR5K_EEPROM_MODE_11A;
++			driver_mode = MODE_ATHEROS_TURBO;
++			break;
++		/*Is this ok on 5211 too ?*/
++		case CHANNEL_TG:
++			mode = AR5K_INI_VAL_11G_TURBO;
++			freq = AR5K_INI_RFGAIN_2GHZ;
++			ee_mode = AR5K_EEPROM_MODE_11G;
++			driver_mode = MODE_ATHEROS_TURBOG;
++			break;
++		case CHANNEL_XR:
++			if (ah->ah_version == AR5K_AR5211) {
++				ATH5K_ERR(ah->ah_sc,
++					"XR mode not available on 5211");
++				return -EINVAL;
++			}
++			mode = AR5K_INI_VAL_XR;
++			freq = AR5K_INI_RFGAIN_5GHZ;
++			ee_mode = AR5K_EEPROM_MODE_11A;
++			driver_mode = MODE_IEEE80211A;
++			break;
++		default:
++			ATH5K_ERR(ah->ah_sc,
++				"invalid channel: %d\n", channel->freq);
++			return -EINVAL;
++		}
++
++		/* PHY access enable */
++		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
++
++	}
++
++	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
++	if (ret)
++		return ret;
++
++	/*
++	 * 5211/5212 Specific
++	 */
++	if (ah->ah_version != AR5K_AR5210) {
++		/*
++		 * Write initial RF gain settings
++		 * This should work for both 5111/5112
++		 */
++		ret = ath5k_hw_rfgain(ah, freq);
++		if (ret)
++			return ret;
++
++		mdelay(1);
++
++		/*
++		 * Write some more initial register settings
++		 */
++		if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */
++			ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11));
++
++			if (channel->val == CHANNEL_G)
++				ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */
++			else
++				ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83));
++
++			ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */
++			ath5k_hw_reg_write(ah, 0x000009b5, 0xa228);
++			ath5k_hw_reg_write(ah, 0x0000000f, 0x8060);
++			ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
++			ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
++		}
++
++		/* Fix for first revision of the RF5112 RF chipset */
++		if (ah->ah_radio >= AR5K_RF5112 &&
++				ah->ah_radio_5ghz_revision <
++				AR5K_SREV_RAD_5112A) {
++			ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
++					AR5K_PHY_CCKTXCTL);
++			if (channel->val & CHANNEL_5GHZ)
++				data = 0xffb81020;
++			else
++				data = 0xffb80d20;
++			ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
++		}
++
++		/*
++		 * Set TX power (FIXME)
++		 */
++		ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER);
++		if (ret)
++			return ret;
++
++		/* Write rate duration table */
++		if (ah->ah_version == AR5K_AR5212)
++			ath5k_hw_write_rate_duration(ah, driver_mode);
++
++		/*
++		 * Write RF registers
++		 * TODO:Does this work on 5211 (5111) ?
++		 */
++		ret = ath5k_hw_rfregs(ah, channel, mode);
++		if (ret)
++			return ret;
++
++		/*
++		 * Configure additional registers
++		 */
++
++		/* Write OFDM timings on 5212*/
++		if (ah->ah_version == AR5K_AR5212 &&
++			channel->val & CHANNEL_OFDM) {
++			ret = ath5k_hw_write_ofdm_timings(ah, channel);
++			if (ret)
++				return ret;
++		}
++
++		/*Enable/disable 802.11b mode on 5111
++		(enable 2111 frequency converter + CCK)*/
++		if (ah->ah_radio == AR5K_RF5111) {
++			if (driver_mode == MODE_IEEE80211B)
++				AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
++				    AR5K_TXCFG_B_MODE);
++			else
++				AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
++				    AR5K_TXCFG_B_MODE);
++		}
++
++		/*
++		 * Set channel and calibrate the PHY
++		 */
++		ret = ath5k_hw_channel(ah, channel);
++		if (ret)
++			return ret;
++
++		/* Set antenna mode */
++		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44),
++			ah->ah_antenna[ee_mode][0], 0xfffffc06);
++
++		/*
++		 * In case a fixed antenna was set as default
++		 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
++		 * registers.
++		 */
++		if (s_ant != 0){
++			if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
++				ant[0] = ant[1] = AR5K_ANT_FIXED_A;
++			else	/* 2 - Aux */
++				ant[0] = ant[1] = AR5K_ANT_FIXED_B;
++		} else {
++			ant[0] = AR5K_ANT_FIXED_A;
++			ant[1] = AR5K_ANT_FIXED_B;
++		}
++
++		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
++			AR5K_PHY_ANT_SWITCH_TABLE_0);
++		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
++			AR5K_PHY_ANT_SWITCH_TABLE_1);
++
++		/* Commit values from EEPROM */
++		if (ah->ah_radio == AR5K_RF5111)
++			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
++			    AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
++
++		ath5k_hw_reg_write(ah,
++			AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
++			AR5K_PHY(0x5a));
++
++		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11),
++			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
++			0xffffc07f);
++		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12),
++			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
++			0xfffc0fff);
++		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14),
++			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
++			((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
++			0xffff0000);
++
++		ath5k_hw_reg_write(ah,
++			(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
++			(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
++			(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
++			(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY(0x0d));
++
++		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a),
++			ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
++		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19),
++			(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
++		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01);
++
++		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
++		    AR5K_PHY_IQ_CORR_ENABLE |
++		    (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
++		    ee->ee_q_cal[ee_mode]);
++
++		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
++			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
++				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
++				ee->ee_margin_tx_rx[ee_mode]);
++
++	} else {
++		mdelay(1);
++		/* Disable phy and wait */
++		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
++		mdelay(1);
++	}
++
++	/*
++	 * Restore saved values
++	 */
++	/*DCU/Antenna selection not available on 5210*/
++	if (ah->ah_version != AR5K_AR5210) {
++		ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0));
++		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
++	}
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
++	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
++	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
++
++	/*
++	 * Misc
++	 */
++	/* XXX: add ah->aid once mac80211 gives this to us */
++	ath5k_hw_set_associd(ah, ah->bssid, 0);
++
++	ath5k_hw_set_opmode(ah);
++	/*PISR/SISR Not available on 5210*/
++	if (ah->ah_version != AR5K_AR5210) {
++		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
++		/* If we later allow tuning for this, store into sc structure */
++		data = AR5K_TUNE_RSSI_THRES |
++			AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S;
++		ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR);
++	}
++
++	/*
++	 * Set Rx/Tx DMA Configuration
++	 *(passing dma size not available on 5210)
++	 */
++	if (ah->ah_version != AR5K_AR5210) {
++		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR,
++				AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE);
++		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW,
++				AR5K_DMASIZE_512B);
++	}
++
++	/*
++	 * Enable the PHY and wait until completion
++	 */
++	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
++
++	/*
++	 * 5111/5112 Specific
++	 */
++	if (ah->ah_version != AR5K_AR5210) {
++		data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
++			AR5K_PHY_RX_DELAY_M;
++		data = (channel->val & CHANNEL_CCK) ?
++			((data << 2) / 22) : (data / 10);
++
++		udelay(100 + data);
++	} else {
++		mdelay(1);
++	}
++
++	/*
++	 * Enable calibration and wait until completion
++	 */
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
++				AR5K_PHY_AGCCTL_CAL);
++
++	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
++			AR5K_PHY_AGCCTL_CAL, 0, false)) {
++		ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
++			channel->freq);
++		return -EAGAIN;
++	}
++
++	ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
++	if (ret)
++		return ret;
++
++	ah->ah_calibration = false;
++
++	/* A and G modes can use QAM modulation which requires enabling
++	 * I and Q calibration. Don't bother in B mode. */
++	if (!(driver_mode == MODE_IEEE80211B)) {
++		ah->ah_calibration = true;
++		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
++				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
++		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
++				AR5K_PHY_IQ_RUN);
++	}
++
++	/*
++	 * Reset queues and start beacon timers at the end of the reset routine
++	 */
++	for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
++		/*No QCU on 5210*/
++		if (ah->ah_version != AR5K_AR5210)
++			AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i);
++
++		ret = ath5k_hw_reset_tx_queue(ah, i);
++		if (ret) {
++			ATH5K_ERR(ah->ah_sc,
++				"failed to reset TX queue #%d\n", i);
++			return ret;
++		}
++	}
++
++	/* Pre-enable interrupts on 5211/5212*/
++	if (ah->ah_version != AR5K_AR5210)
++		ath5k_hw_set_intr(ah, AR5K_INT_RX | AR5K_INT_TX |
++				AR5K_INT_FATAL);
++
++	/*
++	 * Set RF kill flags if supported by the device (read from the EEPROM)
++	 * Disable gpio_intr for now since it results system hang.
++	 * TODO: Handle this in ath5k_intr
++	 */
++#if 0
++	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
++		ath5k_hw_set_gpio_input(ah, 0);
++		ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
++		if (ah->ah_gpio[0] == 0)
++			ath5k_hw_set_gpio_intr(ah, 0, 1);
++		else
++			ath5k_hw_set_gpio_intr(ah, 0, 0);
++	}
++#endif
++
++	/*
++	 * Set the 32MHz reference clock on 5212 phy clock sleep register
++	 */
++	if (ah->ah_version == AR5K_AR5212) {
++		ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
++		ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
++		ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
++		ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
++		ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
++		ath5k_hw_reg_write(ah, ah->ah_radio == AR5K_RF5111 ?
++			AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112,
++			AR5K_PHY_SPENDING);
++	}
++
++	/*
++	 * Disable beacons and reset the register
++	 */
++	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
++			AR5K_BEACON_RESET_TSF);
++
++	return 0;
++}
++
++/*
++ * Reset chipset
++ */
++static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
++{
++	int ret;
++	u32 mask = val ? val : ~0U;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/* Read-and-clear RX Descriptor Pointer*/
++	ath5k_hw_reg_read(ah, AR5K_RXDP);
++
++	/*
++	 * Reset the device and wait until success
++	 */
++	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
++
++	/* Wait at least 128 PCI clocks */
++	udelay(15);
++
++	if (ah->ah_version == AR5K_AR5210) {
++		val &= AR5K_RESET_CTL_CHIP;
++		mask &= AR5K_RESET_CTL_CHIP;
++	} else {
++		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
++		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
++	}
++
++	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
++
++	/*
++	 * Reset configuration register (for hw byte-swap). Note that this
++	 * is only set for big endian. We do the necessary magic in
++	 * AR5K_INIT_CFG.
++	 */
++	if ((val & AR5K_RESET_CTL_PCU) == 0)
++		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
++
++	return ret;
++}
++
++/*
++ * Power management functions
++ */
++
++/*
++ * Sleep control
++ */
++int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
++		bool set_chip, u16 sleep_duration)
++{
++	unsigned int i;
++	u32 staid;
++
++	ATH5K_TRACE(ah->ah_sc);
++	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
++
++	switch (mode) {
++	case AR5K_PM_AUTO:
++		staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
++		/* fallthrough */
++	case AR5K_PM_NETWORK_SLEEP:
++		if (set_chip == true)
++			ath5k_hw_reg_write(ah,
++				AR5K_SLEEP_CTL_SLE | sleep_duration,
++				AR5K_SLEEP_CTL);
++
++		staid |= AR5K_STA_ID1_PWR_SV;
++		break;
++
++	case AR5K_PM_FULL_SLEEP:
++		if (set_chip == true)
++			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
++				AR5K_SLEEP_CTL);
++
++		staid |= AR5K_STA_ID1_PWR_SV;
++		break;
++
++	case AR5K_PM_AWAKE:
++		if (set_chip == false)
++			goto commit;
++
++		ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
++				AR5K_SLEEP_CTL);
++
++		for (i = 5000; i > 0; i--) {
++			/* Check if the chip did wake up */
++			if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
++					AR5K_PCICFG_SPWR_DN) == 0)
++				break;
++
++			/* Wait a bit and retry */
++			udelay(200);
++			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
++				AR5K_SLEEP_CTL);
++		}
++
++		/* Fail if the chip didn't wake up */
++		if (i <= 0)
++			return -EIO;
++
++		staid &= ~AR5K_STA_ID1_PWR_SV;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++commit:
++	ah->ah_power_mode = mode;
++	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
++
++	return 0;
++}
++
++/***********************\
++  DMA Related Functions
++\***********************/
++
++/*
++ * Receive functions
++ */
++
++/*
++ * Start DMA receive
++ */
++void ath5k_hw_start_rx(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
++}
++
++/*
++ * Stop DMA receive
++ */
++int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
++{
++	unsigned int i;
++
++	ATH5K_TRACE(ah->ah_sc);
++	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
++
++	/*
++	 * It may take some time to disable the DMA receive unit
++	 */
++	for (i = 2000; i > 0 &&
++			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
++			i--)
++		udelay(10);
++
++	return i ? 0 : -EBUSY;
++}
++
++/*
++ * Get the address of the RX Descriptor
++ */
++u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah)
++{
++	return ath5k_hw_reg_read(ah, AR5K_RXDP);
++}
++
++/*
++ * Set the address of the RX Descriptor
++ */
++void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr)
++{
++	ATH5K_TRACE(ah->ah_sc);
++
++	/*TODO:Shouldn't we check if RX is enabled first ?*/
++	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
++}
++
++/*
++ * Transmit functions
++ */
++
++/*
++ * Start DMA transmit for a specific queue
++ * (see also QCU/DCU functions)
++ */
++int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue)
++{
++	u32 tx_queue;
++
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
++
++	/* Return if queue is declared inactive */
++	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
++		return -EIO;
++
++	if (ah->ah_version == AR5K_AR5210) {
++		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
++
++		/*
++		 * Set the queue by type on 5210
++		 */
++		switch (ah->ah_txq[queue].tqi_type) {
++		case AR5K_TX_QUEUE_DATA:
++			tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
++			break;
++		case AR5K_TX_QUEUE_BEACON:
++			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
++			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
++					AR5K_BSR);
++			break;
++		case AR5K_TX_QUEUE_CAB:
++			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
++			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V |
++				AR5K_BCR_BDMAE, AR5K_BSR);
++			break;
++		default:
++			return -EINVAL;
++		}
++		/* Start queue */
++		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
++	} else {
++		/* Return if queue is disabled */
++		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
++			return -EIO;
++
++		/* Start queue */
++		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
++	}
++
++	return 0;
++}
++
++/*
++ * Stop DMA transmit for a specific queue
++ * (see also QCU/DCU functions)
++ */
++int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
++{
++	unsigned int i = 100;
++	u32 tx_queue, pending;
++
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
++
++	/* Return if queue is declared inactive */
++	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
++		return -EIO;
++
++	if (ah->ah_version == AR5K_AR5210) {
++		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
++
++		/*
++		 * Set by queue type
++		 */
++		switch (ah->ah_txq[queue].tqi_type) {
++		case AR5K_TX_QUEUE_DATA:
++			tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
++			break;
++		case AR5K_TX_QUEUE_BEACON:
++		case AR5K_TX_QUEUE_CAB:
++			/* XXX Fix me... */
++			tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1;
++			ath5k_hw_reg_write(ah, 0, AR5K_BSR);
++			break;
++		default:
++			return -EINVAL;
++		}
++
++		/* Stop queue */
++		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
++	} else {
++		/*
++		 * Schedule TX disable and wait until queue is empty
++		 */
++		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
++
++		/*Check for pending frames*/
++		do {
++			pending = ath5k_hw_reg_read(ah,
++				AR5K_QUEUE_STATUS(queue)) &
++				AR5K_QCU_STS_FRMPENDCNT;
++			udelay(100);
++		} while (--i && pending);
++
++		/* Clear register */
++		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
++	}
++
++	/* TODO: Check for success else return error */
++	return 0;
++}
++
++/*
++ * Get the address of the TX Descriptor for a specific queue
++ * (see also QCU/DCU functions)
++ */
++u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue)
++{
++	u16 tx_reg;
++
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
++
++	/*
++	 * Get the transmit queue descriptor pointer from the selected queue
++	 */
++	/*5210 doesn't have QCU*/
++	if (ah->ah_version == AR5K_AR5210) {
++		switch (ah->ah_txq[queue].tqi_type) {
++		case AR5K_TX_QUEUE_DATA:
++			tx_reg = AR5K_NOQCU_TXDP0;
++			break;
++		case AR5K_TX_QUEUE_BEACON:
++		case AR5K_TX_QUEUE_CAB:
++			tx_reg = AR5K_NOQCU_TXDP1;
++			break;
++		default:
++			return 0xffffffff;
++		}
++	} else {
++		tx_reg = AR5K_QUEUE_TXDP(queue);
++	}
++
++	return ath5k_hw_reg_read(ah, tx_reg);
++}
++
++/*
++ * Set the address of the TX Descriptor for a specific queue
++ * (see also QCU/DCU functions)
++ */
++int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
++{
++	u16 tx_reg;
++
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
++
++	/*
++	 * Set the transmit queue descriptor pointer register by type
++	 * on 5210
++	 */
++	if (ah->ah_version == AR5K_AR5210) {
++		switch (ah->ah_txq[queue].tqi_type) {
++		case AR5K_TX_QUEUE_DATA:
++			tx_reg = AR5K_NOQCU_TXDP0;
++			break;
++		case AR5K_TX_QUEUE_BEACON:
++		case AR5K_TX_QUEUE_CAB:
++			tx_reg = AR5K_NOQCU_TXDP1;
++			break;
++		default:
++			return -EINVAL;
++		}
++	} else {
++		/*
++		 * Set the transmit queue descriptor pointer for
++		 * the selected queue on QCU for 5211+
++		 * (this won't work if the queue is still active)
++		 */
++		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
++			return -EIO;
++
++		tx_reg = AR5K_QUEUE_TXDP(queue);
++	}
++
++	/* Set descriptor pointer */
++	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
++
++	return 0;
++}
++
++/*
++ * Update tx trigger level
++ */
++int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
++{
++	u32 trigger_level, imr;
++	int ret = -EIO;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/*
++	 * Disable interrupts by setting the mask
++	 */
++	imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
++
++	/*TODO: Boundary check on trigger_level*/
++	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
++			AR5K_TXCFG_TXFULL);
++
++	if (increase == false) {
++		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
++			goto done;
++	} else
++		trigger_level +=
++			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
++
++	/*
++	 * Update trigger level on success
++	 */
++	if (ah->ah_version == AR5K_AR5210)
++		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
++	else
++		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
++				AR5K_TXCFG_TXFULL, trigger_level);
++
++	ret = 0;
++
++done:
++	/*
++	 * Restore interrupt mask
++	 */
++	ath5k_hw_set_intr(ah, imr);
++
++	return ret;
++}
++
++/*
++ * Interrupt handling
++ */
++
++/*
++ * Check if we have pending interrupts
++ */
++bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	return ath5k_hw_reg_read(ah, AR5K_INTPEND);
++}
++
++/*
++ * Get interrupt mask (ISR)
++ */
++int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
++{
++	u32 data;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/*
++	 * Read interrupt status from the Interrupt Status register
++	 * on 5210
++	 */
++	if (ah->ah_version == AR5K_AR5210) {
++		data = ath5k_hw_reg_read(ah, AR5K_ISR);
++		if (unlikely(data == AR5K_INT_NOCARD)) {
++			*interrupt_mask = data;
++			return -ENODEV;
++		}
++	} else {
++		/*
++		 * Read interrupt status from the Read-And-Clear shadow register
++		 * Note: PISR/SISR Not available on 5210
++		 */
++		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
++	}
++
++	/*
++	 * Get abstract interrupt mask (driver-compatible)
++	 */
++	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
++
++	if (unlikely(data == AR5K_INT_NOCARD))
++		return -ENODEV;
++
++	if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
++		*interrupt_mask |= AR5K_INT_RX;
++
++	if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
++		| AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
++		*interrupt_mask |= AR5K_INT_TX;
++
++	if (ah->ah_version != AR5K_AR5210) {
++		/*HIU = Host Interface Unit (PCI etc)*/
++		if (unlikely(data & (AR5K_ISR_HIUERR)))
++			*interrupt_mask |= AR5K_INT_FATAL;
++
++		/*Beacon Not Ready*/
++		if (unlikely(data & (AR5K_ISR_BNR)))
++			*interrupt_mask |= AR5K_INT_BNR;
++	}
++
++	/*
++	 * XXX: BMISS interrupts may occur after association.
++	 * I found this on 5210 code but it needs testing. If this is
++	 * true we should disable them before assoc and re-enable them
++	 * after a successfull assoc + some jiffies.
++	 */
++#if 0
++	interrupt_mask &= ~AR5K_INT_BMISS;
++#endif
++
++	/*
++	 * In case we didn't handle anything,
++	 * print the register value.
++	 */
++	if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
++		ATH5K_PRINTF("0x%08x\n", data);
++
++	return 0;
++}
++
++/*
++ * Set interrupt mask
++ */
++enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
++{
++	enum ath5k_int old_mask, int_mask;
++
++	/*
++	 * Disable card interrupts to prevent any race conditions
++	 * (they will be re-enabled afterwards).
++	 */
++	ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
++
++	old_mask = ah->ah_imr;
++
++	/*
++	 * Add additional, chipset-dependent interrupt mask flags
++	 * and write them to the IMR (interrupt mask register).
++	 */
++	int_mask = new_mask & AR5K_INT_COMMON;
++
++	if (new_mask & AR5K_INT_RX)
++		int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
++			AR5K_IMR_RXDESC;
++
++	if (new_mask & AR5K_INT_TX)
++		int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
++			AR5K_IMR_TXURN;
++
++	if (ah->ah_version != AR5K_AR5210) {
++		if (new_mask & AR5K_INT_FATAL) {
++			int_mask |= AR5K_IMR_HIUERR;
++			AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
++					AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
++		}
++	}
++
++	ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
++
++	/* Store new interrupt mask */
++	ah->ah_imr = new_mask;
++
++	/* ..re-enable interrupts */
++	ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
++
++	return old_mask;
++}
++
++
++/*************************\
++  EEPROM access functions
++\*************************/
++
++/*
++ * Read from eeprom
++ */
++static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
++{
++	u32 status, timeout;
++
++	ATH5K_TRACE(ah->ah_sc);
++	/*
++	 * Initialize EEPROM access
++	 */
++	if (ah->ah_version == AR5K_AR5210) {
++		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
++		(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
++	} else {
++		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
++		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
++				AR5K_EEPROM_CMD_READ);
++	}
++
++	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
++		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
++		if (status & AR5K_EEPROM_STAT_RDDONE) {
++			if (status & AR5K_EEPROM_STAT_RDERR)
++				return -EIO;
++			*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
++					0xffff);
++			return 0;
++		}
++		udelay(15);
++	}
++
++	return -ETIMEDOUT;
++}
++
++/*
++ * Write to eeprom - currently disabled, use at your own risk
++ */
++static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data)
++{
++#if 0
++	u32 status, timeout;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/*
++	 * Initialize eeprom access
++	 */
++
++	if (ah->ah_version == AR5K_AR5210) {
++		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
++	} else {
++		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
++				AR5K_EEPROM_CMD_RESET);
++	}
++
++	/*
++	 * Write data to data register
++	 */
++
++	if (ah->ah_version == AR5K_AR5210) {
++		ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset));
++	} else {
++		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
++		ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA);
++		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
++				AR5K_EEPROM_CMD_WRITE);
++	}
++
++	/*
++	 * Check status
++	 */
++
++	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
++		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
++		if (status & AR5K_EEPROM_STAT_WRDONE) {
++			if (status & AR5K_EEPROM_STAT_WRERR)
++				return EIO;
++			return 0;
++		}
++		udelay(15);
++	}
++#endif
++	ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!");
++	return -EIO;
++}
++
++/*
++ * Translate binary channel representation in EEPROM to frequency
++ */
++static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode)
++{
++	u16 val;
++
++	if (bin == AR5K_EEPROM_CHANNEL_DIS)
++		return bin;
++
++	if (mode == AR5K_EEPROM_MODE_11A) {
++		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
++			val = (5 * bin) + 4800;
++		else
++			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
++				(bin * 10) + 5100;
++	} else {
++		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
++			val = bin + 2300;
++		else
++			val = bin + 2400;
++	}
++
++	return val;
++}
++
++/*
++ * Read antenna infos from eeprom
++ */
++static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
++		unsigned int mode)
++{
++	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
++	u32 o = *offset;
++	u16 val;
++	int ret, i = 0;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
++	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
++	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
++	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= val & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
++	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
++	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
++	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
++	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
++	ee->ee_ant_control[mode][i++]	= val & 0x3f;
++
++	/* Get antenna modes */
++	ah->ah_antenna[mode][0] =
++	    (ee->ee_ant_control[mode][0] << 4) | 0x1;
++	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
++	     ee->ee_ant_control[mode][1] 	|
++	    (ee->ee_ant_control[mode][2] << 6) 	|
++	    (ee->ee_ant_control[mode][3] << 12) |
++	    (ee->ee_ant_control[mode][4] << 18) |
++	    (ee->ee_ant_control[mode][5] << 24);
++	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
++	     ee->ee_ant_control[mode][6] 	|
++	    (ee->ee_ant_control[mode][7] << 6) 	|
++	    (ee->ee_ant_control[mode][8] << 12) |
++	    (ee->ee_ant_control[mode][9] << 18) |
++	    (ee->ee_ant_control[mode][10] << 24);
++
++	/* return new offset */
++	*offset = o;
++
++	return 0;
++}
++
++/*
++ * Read supported modes from eeprom
++ */
++static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
++		unsigned int mode)
++{
++	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
++	u32 o = *offset;
++	u16 val;
++	int ret;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
++	ee->ee_thr_62[mode]		= val & 0xff;
++
++	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
++		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
++	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
++
++	if ((val & 0xff) & 0x80)
++		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
++	else
++		ee->ee_noise_floor_thr[mode] = val & 0xff;
++
++	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
++		ee->ee_noise_floor_thr[mode] =
++		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
++
++	AR5K_EEPROM_READ(o++, val);
++	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
++	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
++	ee->ee_xpd[mode]		= val & 0x1;
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
++		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
++		AR5K_EEPROM_READ(o++, val);
++		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
++
++		if (mode == AR5K_EEPROM_MODE_11A)
++			ee->ee_xr_power[mode] = val & 0x3f;
++		else {
++			ee->ee_ob[mode][0] = val & 0x7;
++			ee->ee_db[mode][0] = (val >> 3) & 0x7;
++		}
++	}
++
++	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
++		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
++		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
++	} else {
++		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
++
++		AR5K_EEPROM_READ(o++, val);
++		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
++
++		if (mode == AR5K_EEPROM_MODE_11G)
++			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
++	}
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
++			mode == AR5K_EEPROM_MODE_11A) {
++		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++	}
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
++	    mode == AR5K_EEPROM_MODE_11G)
++		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
++
++	/* return new offset */
++	*offset = o;
++
++	return 0;
++}
++
++/*
++ * Initialize eeprom & capabilities structs
++ */
++static int ath5k_eeprom_init(struct ath5k_hw *ah)
++{
++	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
++	unsigned int mode, i;
++	int ret;
++	u32 offset;
++	u16 val;
++
++	/* Initial TX thermal adjustment values */
++	ee->ee_tx_clip = 4;
++	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
++	ee->ee_gain_select = 1;
++
++	/*
++	 * Read values from EEPROM and store them in the capability structure
++	 */
++	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
++	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
++	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
++	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
++	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
++
++	/* Return if we have an old EEPROM */
++	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
++		return 0;
++
++#ifdef notyet
++	/*
++	 * Validate the checksum of the EEPROM date. There are some
++	 * devices with invalid EEPROMs.
++	 */
++	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
++		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
++		cksum ^= val;
++	}
++	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
++		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
++		return -EIO;
++	}
++#endif
++
++	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
++	    ee_ant_gain);
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
++		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
++		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
++	}
++
++	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
++		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
++		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
++		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
++
++		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
++		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
++		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
++	}
++
++	/*
++	 * Get conformance test limit values
++	 */
++	offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
++	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
++
++	for (i = 0; i < ee->ee_ctls; i++) {
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_ctl[i] = (val >> 8) & 0xff;
++		ee->ee_ctl[i + 1] = val & 0xff;
++	}
++
++	/*
++	 * Get values for 802.11a (5GHz)
++	 */
++	mode = AR5K_EEPROM_MODE_11A;
++
++	ee->ee_turbo_max_power[mode] =
++			AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
++
++	offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
++
++	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
++	if (ret)
++		return ret;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
++	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
++	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
++	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
++	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
++	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
++	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
++	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
++	ee->ee_db[mode][0]		= val & 0x7;
++
++	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
++	if (ret)
++		return ret;
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_margin_tx_rx[mode] = val & 0x3f;
++	}
++
++	/*
++	 * Get values for 802.11b (2.4GHz)
++	 */
++	mode = AR5K_EEPROM_MODE_11B;
++	offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
++
++	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
++	if (ret)
++		return ret;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
++	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
++	ee->ee_db[mode][1]		= val & 0x7;
++
++	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
++	if (ret)
++		return ret;
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_cal_pier[mode][0] =
++			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
++		ee->ee_cal_pier[mode][1] =
++			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_cal_pier[mode][2] =
++			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
++	}
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
++		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++	/*
++	 * Get values for 802.11g (2.4GHz)
++	 */
++	mode = AR5K_EEPROM_MODE_11G;
++	offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
++
++	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
++	if (ret)
++		return ret;
++
++	AR5K_EEPROM_READ(offset++, val);
++	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
++	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
++	ee->ee_db[mode][1]		= val & 0x7;
++
++	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
++	if (ret)
++		return ret;
++
++	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_cal_pier[mode][0] =
++			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
++		ee->ee_cal_pier[mode][1] =
++			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_turbo_max_power[mode] = val & 0x7f;
++		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_cal_pier[mode][2] =
++			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
++
++		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
++			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
++
++		AR5K_EEPROM_READ(offset++, val);
++		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
++		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
++
++		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
++			AR5K_EEPROM_READ(offset++, val);
++			ee->ee_cck_ofdm_gain_delta = val & 0xff;
++		}
++	}
++
++	/*
++	 * Read 5GHz EEPROM channels
++	 */
++
++	return 0;
++}
++
++/*
++ * Read the MAC address from eeprom
++ */
++static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
++{
++	u8 mac_d[ETH_ALEN];
++	u32 total, offset;
++	u16 data;
++	int octet, ret;
++
++	memset(mac, 0, ETH_ALEN);
++	memset(mac_d, 0, ETH_ALEN);
++
++	ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
++	if (ret)
++		return ret;
++
++	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
++		ret = ath5k_hw_eeprom_read(ah, offset, &data);
++		if (ret)
++			return ret;
++
++		total += data;
++		mac_d[octet + 1] = data & 0xff;
++		mac_d[octet] = data >> 8;
++		octet += 2;
++	}
++
++	memcpy(mac, mac_d, ETH_ALEN);
++
++	if (!total || total == 3 * 0xffff)
++		return -EINVAL;
++
++	return 0;
++}
++
++/*
++ * Read/Write regulatory domain
++ */
++static bool ath5k_eeprom_regulation_domain(struct ath5k_hw *ah, bool write,
++	enum ath5k_regdom *regdomain)
++{
++	u16 ee_regdomain;
++
++	/* Read current value */
++	if (write != true) {
++		ee_regdomain = ah->ah_capabilities.cap_eeprom.ee_regdomain;
++		*regdomain = ath5k_regdom_to_ieee(ee_regdomain);
++		return true;
++	}
++
++	ee_regdomain = ath5k_regdom_from_ieee(*regdomain);
++
++	/* Try to write a new value */
++	if (ah->ah_capabilities.cap_eeprom.ee_protect &
++			AR5K_EEPROM_PROTECT_WR_128_191)
++		return false;
++	if (ath5k_hw_eeprom_write(ah, AR5K_EEPROM_REG_DOMAIN, ee_regdomain)!=0)
++		return false;
++
++	ah->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain;
++
++	return true;
++}
++
++/*
++ * Use the above to write a new regulatory domain
++ */
++int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain)
++{
++	enum ath5k_regdom ieee_regdomain;
++
++	ieee_regdomain = ath5k_regdom_to_ieee(regdomain);
++
++	if (ath5k_eeprom_regulation_domain(ah, true, &ieee_regdomain) == true)
++		return 0;
++
++	return -EIO;
++}
++
++/*
++ * Fill the capabilities struct
++ */
++static int ath5k_hw_get_capabilities(struct ath5k_hw *ah)
++{
++	u16 ee_header;
++
++	ATH5K_TRACE(ah->ah_sc);
++	/* Capabilities stored in the EEPROM */
++	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
++
++	if (ah->ah_version == AR5K_AR5210) {
++		/*
++		 * Set radio capabilities
++		 * (The AR5110 only supports the middle 5GHz band)
++		 */
++		ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
++		ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
++		ah->ah_capabilities.cap_range.range_2ghz_min = 0;
++		ah->ah_capabilities.cap_range.range_2ghz_max = 0;
++
++		/* Set supported modes */
++		__set_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode);
++		__set_bit(MODE_ATHEROS_TURBO, ah->ah_capabilities.cap_mode);
++	} else {
++		/*
++		 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
++		 * XXX and from 2312 to 2732GHz. There are problems with the
++		 * XXX current ieee80211 implementation because the IEEE
++		 * XXX channel mapping does not support negative channel
++		 * XXX numbers (2312MHz is channel -19). Of course, this
++		 * XXX doesn't matter because these channels are out of range
++		 * XXX but some regulation domains like MKK (Japan) will
++		 * XXX support frequencies somewhere around 4.8GHz.
++		 */
++
++		/*
++		 * Set radio capabilities
++		 */
++
++		if (AR5K_EEPROM_HDR_11A(ee_header)) {
++			ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */
++			ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
++
++			/* Set supported modes */
++			__set_bit(MODE_IEEE80211A,
++					ah->ah_capabilities.cap_mode);
++			__set_bit(MODE_ATHEROS_TURBO,
++					ah->ah_capabilities.cap_mode);
++			if (ah->ah_version == AR5K_AR5212)
++				__set_bit(MODE_ATHEROS_TURBOG,
++						ah->ah_capabilities.cap_mode);
++		}
++
++		/* Enable  802.11b if a 2GHz capable radio (2111/5112) is
++		 * connected */
++		if (AR5K_EEPROM_HDR_11B(ee_header) ||
++				AR5K_EEPROM_HDR_11G(ee_header)) {
++			ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */
++			ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
++
++			if (AR5K_EEPROM_HDR_11B(ee_header))
++				__set_bit(MODE_IEEE80211B,
++						ah->ah_capabilities.cap_mode);
++
++			if (AR5K_EEPROM_HDR_11G(ee_header))
++				__set_bit(MODE_IEEE80211G,
++						ah->ah_capabilities.cap_mode);
++		}
++	}
++
++	/* GPIO */
++	ah->ah_gpio_npins = AR5K_NUM_GPIO;
++
++	/* Set number of supported TX queues */
++	if (ah->ah_version == AR5K_AR5210)
++		ah->ah_capabilities.cap_queues.q_tx_num =
++			AR5K_NUM_TX_QUEUES_NOQCU;
++	else
++		ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
++
++	return 0;
++}
++
++/*********************************\
++  Protocol Control Unit Functions
++\*********************************/
++
++/*
++ * Set Operation mode
++ */
++int ath5k_hw_set_opmode(struct ath5k_hw *ah)
++{
++	u32 pcu_reg, beacon_reg, low_id, high_id;
++
++	pcu_reg = 0;
++	beacon_reg = 0;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	switch (ah->ah_op_mode) {
++	case IEEE80211_IF_TYPE_IBSS:
++		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
++			(ah->ah_version == AR5K_AR5210 ?
++				AR5K_STA_ID1_NO_PSPOLL : 0);
++		beacon_reg |= AR5K_BCR_ADHOC;
++		break;
++
++	case IEEE80211_IF_TYPE_AP:
++		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
++			(ah->ah_version == AR5K_AR5210 ?
++				AR5K_STA_ID1_NO_PSPOLL : 0);
++		beacon_reg |= AR5K_BCR_AP;
++		break;
++
++	case IEEE80211_IF_TYPE_STA:
++		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
++			(ah->ah_version == AR5K_AR5210 ?
++				AR5K_STA_ID1_PWR_SV : 0);
++	case IEEE80211_IF_TYPE_MNTR:
++		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
++			(ah->ah_version == AR5K_AR5210 ?
++				AR5K_STA_ID1_NO_PSPOLL : 0);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	/*
++	 * Set PCU registers
++	 */
++	low_id = AR5K_LOW_ID(ah->ah_sta_id);
++	high_id = AR5K_HIGH_ID(ah->ah_sta_id);
++	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
++	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
++
++	/*
++	 * Set Beacon Control Register on 5210
++	 */
++	if (ah->ah_version == AR5K_AR5210)
++		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
++
++	return 0;
++}
++
++/*
++ * BSSID Functions
++ */
++
++/*
++ * Get station id
++ */
++void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	memcpy(mac, ah->ah_sta_id, ETH_ALEN);
++}
++
++/*
++ * Set station id
++ */
++int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
++{
++	u32 low_id, high_id;
++
++	ATH5K_TRACE(ah->ah_sc);
++	/* Set new station ID */
++	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
++
++	low_id = AR5K_LOW_ID(mac);
++	high_id = AR5K_HIGH_ID(mac);
++
++	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
++	ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1);
++
++	return 0;
++}
++
++/*
++ * Set BSSID
++ */
++void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
++{
++	u32 low_id, high_id;
++	u16 tim_offset = 0;
++
++	/*
++	 * Set simple BSSID mask on 5212
++	 */
++	if (ah->ah_version == AR5K_AR5212) {
++		ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0);
++		ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1);
++	}
++
++	/*
++	 * Set BSSID which triggers the "SME Join" operation
++	 */
++	low_id = AR5K_LOW_ID(bssid);
++	high_id = AR5K_HIGH_ID(bssid);
++	ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
++	ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
++				AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
++	memcpy(&ah->ah_bssid, bssid, ETH_ALEN);
++
++	if (assoc_id == 0) {
++		ath5k_hw_disable_pspoll(ah);
++		return;
++	}
++
++	AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
++			tim_offset ? tim_offset + 4 : 0);
++
++	ath5k_hw_enable_pspoll(ah, NULL, 0);
++}
++/**
++ * ath5k_hw_set_bssid_mask - set common bits we should listen to
++ *
++ * The bssid_mask is a utility used by AR5212 hardware to inform the hardware
++ * which bits of the interface's MAC address should be looked at when trying
++ * to decide which packets to ACK. In station mode every bit matters. In AP
++ * mode with a single BSS every bit matters as well. In AP mode with
++ * multiple BSSes not every bit matters.
++ *
++ * @ah: the &struct ath5k_hw
++ * @mask: the bssid_mask, a u8 array of size ETH_ALEN
++ *
++ * Note that this is a simple filter and *does* not filter out all
++ * relevant frames. Some non-relevant frames will get through, probability
++ * jocks are welcomed to compute.
++ *
++ * When handling multiple BSSes (or VAPs) you can get the BSSID mask by
++ * computing the set of:
++ *
++ *     ~ ( MAC XOR BSSID )
++ *
++ * When you do this you are essentially computing the common bits. Later it
++ * is assumed the harware will "and" (&) the BSSID mask with the MAC address
++ * to obtain the relevant bits which should match on the destination frame.
++ *
++ * Simple example: on your card you have have two BSSes you have created with
++ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
++ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
++ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
++ *
++ *                  \
++ * MAC:                0001 |
++ * BSSID-01:   0100 | --> Belongs to us
++ * BSSID-02:   1001 |
++ *                  /
++ * -------------------
++ * BSSID-03:   0110  | --> External
++ * -------------------
++ *
++ * Our bssid_mask would then be:
++ *
++ *             On loop iteration for BSSID-01:
++ *             ~(0001 ^ 0100)  -> ~(0101)
++ *                             ->   1010
++ *             bssid_mask      =    1010
++ *
++ *             On loop iteration for BSSID-02:
++ *             bssid_mask &= ~(0001   ^   1001)
++ *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
++ *             bssid_mask =   (1010)  & ~(1001)
++ *             bssid_mask =   (1010)  &  (0110)
++ *             bssid_mask =   0010
++ *
++ * A bssid_mask of 0010 means "only pay attention to the second least
++ * significant bit". This is because its the only bit common
++ * amongst the MAC and all BSSIDs we support. To findout what the real
++ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
++ * or our MAC address (we assume the hardware uses the MAC address).
++ *
++ * Now, suppose there's an incoming frame for BSSID-03:
++ *
++ * IFRAME-01:  0110
++ *
++ * An easy eye-inspeciton of this already should tell you that this frame
++ * will not pass our check. This is beacuse the bssid_mask tells the
++ * hardware to only look at the second least significant bit and the
++ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
++ * as 1, which does not match 0.
++ *
++ * So with IFRAME-01 we *assume* the hardware will do:
++ *
++ *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
++ *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
++ *  --> allow = (0010) == 0000 ? 1 : 0;
++ *  --> allow = 0
++ *
++ *  Lets now test a frame that should work:
++ *
++ * IFRAME-02:  0001 (we should allow)
++ *
++ *     allow = (0001 & 1010) == 1010
++ *
++ *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
++ *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
++ *  --> allow = (0010) == (0010)
++ *  --> allow = 1
++ *
++ * Other examples:
++ *
++ * IFRAME-03:  0100 --> allowed
++ * IFRAME-04:  1001 --> allowed
++ * IFRAME-05:  1101 --> allowed but its not for us!!!
++ *
++ */
++int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
++{
++	u32 low_id, high_id;
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (ah->ah_version == AR5K_AR5212) {
++		low_id = AR5K_LOW_ID(mask);
++		high_id = AR5K_HIGH_ID(mask);
++
++		ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
++		ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
++
++		return 0;
++	}
++
++	return -EIO;
++}
++
++/*
++ * Receive start/stop functions
++ */
++
++/*
++ * Start receive on PCU
++ */
++void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
++}
++
++/*
++ * Stop receive on PCU
++ */
++void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
++}
++
++/*
++ * RX Filter functions
++ */
++
++/*
++ * Set multicast filter
++ */
++void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	/* Set the multicat filter */
++	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
++	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
++}
++
++/*
++ * Set multicast filter by index
++ */
++int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index)
++{
++
++	ATH5K_TRACE(ah->ah_sc);
++	if (index >= 64)
++		return -EINVAL;
++	else if (index >= 32)
++		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
++				(1 << (index - 32)));
++	else
++		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
++
++	return 0;
++}
++
++/*
++ * Clear Multicast filter by index
++ */
++int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
++{
++
++	ATH5K_TRACE(ah->ah_sc);
++	if (index >= 64)
++		return -EINVAL;
++	else if (index >= 32)
++		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
++				(1 << (index - 32)));
++	else
++		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
++
++	return 0;
++}
++
++/*
++ * Get current rx filter
++ */
++u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
++{
++	u32 data, filter = 0;
++
++	ATH5K_TRACE(ah->ah_sc);
++	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
++
++	/*Radar detection for 5212*/
++	if (ah->ah_version == AR5K_AR5212) {
++		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
++
++		if (data & AR5K_PHY_ERR_FIL_RADAR)
++			filter |= AR5K_RX_FILTER_RADARERR;
++		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
++			filter |= AR5K_RX_FILTER_PHYERR;
++	}
++
++	return filter;
++}
++
++/*
++ * Set rx filter
++ */
++void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
++{
++	u32 data = 0;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/* Set PHY error filter register on 5212*/
++	if (ah->ah_version == AR5K_AR5212) {
++		if (filter & AR5K_RX_FILTER_RADARERR)
++			data |= AR5K_PHY_ERR_FIL_RADAR;
++		if (filter & AR5K_RX_FILTER_PHYERR)
++			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
++	}
++
++	/*
++	 * The AR5210 uses promiscous mode to detect radar activity
++	 */
++	if (ah->ah_version == AR5K_AR5210 &&
++			(filter & AR5K_RX_FILTER_RADARERR)) {
++		filter &= ~AR5K_RX_FILTER_RADARERR;
++		filter |= AR5K_RX_FILTER_PROM;
++	}
++
++	/*Zero length DMA*/
++	if (data)
++		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
++	else
++		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
++
++	/*Write RX Filter register*/
++	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
++
++	/*Write PHY error filter register on 5212*/
++	if (ah->ah_version == AR5K_AR5212)
++		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
++
++}
++
++/*
++ * Beacon related functions
++ */
++
++/*
++ * Get a 32bit TSF
++ */
++u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	return ath5k_hw_reg_read(ah, AR5K_TSF_L32);
++}
++
++/*
++ * Get the full 64bit TSF
++ */
++u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
++{
++	u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
++	ATH5K_TRACE(ah->ah_sc);
++
++	return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
++}
++
++/*
++ * Force a TSF reset
++ */
++void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF);
++}
++
++/*
++ * Initialize beacon timers
++ */
++void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
++{
++	u32 timer1, timer2, timer3;
++
++	ATH5K_TRACE(ah->ah_sc);
++	/*
++	 * Set the additional timers by mode
++	 */
++	switch (ah->ah_op_mode) {
++	case IEEE80211_IF_TYPE_STA:
++		if (ah->ah_version == AR5K_AR5210) {
++			timer1 = 0xffffffff;
++			timer2 = 0xffffffff;
++		} else {
++			timer1 = 0x0000ffff;
++			timer2 = 0x0007ffff;
++		}
++		break;
++
++	default:
++		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) <<
++		    0x00000003;
++		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) <<
++		    0x00000003;
++	}
++
++	timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
++
++	/*
++	 * Set the beacon register and enable all timers.
++	 * (next beacon, DMA beacon, software beacon, ATIM window time)
++	 */
++	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
++	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
++	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
++	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
++
++	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
++			AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
++		AR5K_BEACON);
++}
++
++/*
++ * Set beacon timers
++ */
++int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
++		const struct ath5k_beacon_state *state)
++{
++	u32 cfp_period, next_cfp, dtim, interval, next_beacon;
++
++	/*
++	 * TODO: should be changed through *state
++	 * review struct ath5k_beacon_state struct
++	 *
++	 * XXX: These are used for cfp period bellow, are they
++	 * ok ? Is it O.K. for tsf here to be 0 or should we use
++	 * get_tsf ?
++	 */
++	u32 dtim_count = 0; /* XXX */
++	u32 cfp_count = 0; /* XXX */
++	u32 tsf = 0; /* XXX */
++
++	ATH5K_TRACE(ah->ah_sc);
++	/* Return on an invalid beacon state */
++	if (state->bs_interval < 1)
++		return -EINVAL;
++
++	interval = state->bs_interval;
++	dtim = state->bs_dtim_period;
++
++	/*
++	 * PCF support?
++	 */
++	if (state->bs_cfp_period > 0) {
++		/*
++		 * Enable PCF mode and set the CFP
++		 * (Contention Free Period) and timer registers
++		 */
++		cfp_period = state->bs_cfp_period * state->bs_dtim_period *
++			state->bs_interval;
++		next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
++			state->bs_interval;
++
++		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
++				AR5K_STA_ID1_DEFAULT_ANTENNA |
++				AR5K_STA_ID1_PCF);
++		ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
++		ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
++				AR5K_CFP_DUR);
++		ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
++						next_cfp)) << 3, AR5K_TIMER2);
++	} else {
++		/* Disable PCF mode */
++		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
++				AR5K_STA_ID1_DEFAULT_ANTENNA |
++				AR5K_STA_ID1_PCF);
++	}
++
++	/*
++	 * Enable the beacon timer register
++	 */
++	ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
++
++	/*
++	 * Start the beacon timers
++	 */
++	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~
++		(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
++		AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
++		AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
++		AR5K_BEACON_PERIOD), AR5K_BEACON);
++
++	/*
++	 * Write new beacon miss threshold, if it appears to be valid
++	 * XXX: Figure out right values for min <= bs_bmiss_threshold <= max
++	 * and return if its not in range. We can test this by reading value and
++	 * setting value to a largest value and seeing which values register.
++	 */
++
++	AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
++			state->bs_bmiss_threshold);
++
++	/*
++	 * Set sleep control register
++	 * XXX: Didn't find this in 5210 code but since this register
++	 * exists also in ar5k's 5210 headers i leave it as common code.
++	 */
++	AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
++			(state->bs_sleep_duration - 3) << 3);
++
++	/*
++	 * Set enhanced sleep registers on 5212
++	 */
++	if (ah->ah_version == AR5K_AR5212) {
++		if (state->bs_sleep_duration > state->bs_interval &&
++				roundup(state->bs_sleep_duration, interval) ==
++				state->bs_sleep_duration)
++			interval = state->bs_sleep_duration;
++
++		if (state->bs_sleep_duration > dtim && (dtim == 0 ||
++				roundup(state->bs_sleep_duration, dtim) ==
++				state->bs_sleep_duration))
++			dtim = state->bs_sleep_duration;
++
++		if (interval > dtim)
++			return -EINVAL;
++
++		next_beacon = interval == dtim ? state->bs_next_dtim :
++			state->bs_next_beacon;
++
++		ath5k_hw_reg_write(ah,
++			AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
++			AR5K_SLEEP0_NEXT_DTIM) |
++			AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
++			AR5K_SLEEP0_ENH_SLEEP_EN |
++			AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
++
++		ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
++			AR5K_SLEEP1_NEXT_TIM) |
++			AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
++
++		ath5k_hw_reg_write(ah,
++			AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
++			AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
++	}
++
++	return 0;
++}
++
++/*
++ * Reset beacon timers
++ */
++void ath5k_hw_reset_beacon(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	/*
++	 * Disable beacon timer
++	 */
++	ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
++
++	/*
++	 * Disable some beacon register values
++	 */
++	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
++			AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
++	ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
++}
++
++/*
++ * Wait for beacon queue to finish
++ * TODO: This function's name is misleading, rename
++ */
++int ath5k_hw_wait_for_beacon(struct ath5k_hw *ah, unsigned long phys_addr)
++{
++	unsigned int i;
++	int ret;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/* 5210 doesn't have QCU*/
++	if (ah->ah_version == AR5K_AR5210) {
++		/*
++		 * Wait for beaconn queue to finish by checking
++		 * Control Register and Beacon Status Register.
++		 */
++		for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
++			if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
++					||
++			    !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
++				break;
++			udelay(10);
++		}
++
++		/* Timeout... */
++		if (i <= 0) {
++			/*
++			 * Re-schedule the beacon queue
++			 */
++			ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
++			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
++					AR5K_BCR);
++
++			return -EIO;
++		}
++		ret = 0;
++	} else {
++	/*5211/5212*/
++		ret = ath5k_hw_register_timeout(ah,
++			AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
++			AR5K_QCU_STS_FRMPENDCNT, 0, false);
++
++		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
++			return -EIO;
++	}
++
++	return ret;
++}
++
++/*
++ * Update mib counters (statistics)
++ */
++void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
++		struct ath5k_mib_stats *statistics)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	/* Read-And-Clear */
++	statistics->ackrcv_bad += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
++	statistics->rts_bad += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
++	statistics->rts_good += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
++	statistics->fcs_bad += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
++	statistics->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
++
++	/* Reset profile count registers on 5212*/
++	if (ah->ah_version == AR5K_AR5212) {
++		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
++		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
++		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
++		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
++	}
++}
++
++/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs
++ *
++ * @ah: the &struct ath5k_hw
++ * @high: determines if to use low bit rate or now
++ */
++void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
++{
++	if (ah->ah_version != AR5K_AR5212)
++		return;
++	else {
++		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
++		if (high)
++			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
++		else
++			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
++	}
++}
++
++
++/*
++ * ACK/CTS Timeouts
++ */
++
++/*
++ * Set ACK timeout on PCU
++ */
++int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
++			ah->ah_turbo) <= timeout)
++		return -EINVAL;
++
++	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
++		ath5k_hw_htoclock(timeout, ah->ah_turbo));
++
++	return 0;
++}
++
++/*
++ * Read the ACK timeout from PCU
++ */
++unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++
++	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
++			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
++}
++
++/*
++ * Set CTS timeout on PCU
++ */
++int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
++			ah->ah_turbo) <= timeout)
++		return -EINVAL;
++
++	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
++			ath5k_hw_htoclock(timeout, ah->ah_turbo));
++
++	return 0;
++}
++
++/*
++ * Read CTS timeout from PCU
++ */
++unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
++			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
++}
++
++/*
++ * Key table (WEP) functions
++ */
++
++int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
++{
++	unsigned int i;
++
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
++
++	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
++		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
++
++	/* Set NULL encryption on non-5210*/
++	if (ah->ah_version != AR5K_AR5210)
++		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
++				AR5K_KEYTABLE_TYPE(entry));
++
++	return 0;
++}
++
++int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
++
++	/* Check the validation flag at the end of the entry */
++	return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
++		AR5K_KEYTABLE_VALID;
++}
++
++int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
++		const struct ieee80211_key_conf *key, const u8 *mac)
++{
++	unsigned int i;
++	__le32 key_v[5] = {};
++	u32 keytype;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/* key->keylen comes in from mac80211 in bytes */
++
++	if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
++		return -EOPNOTSUPP;
++
++	switch (key->keylen) {
++	/* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
++	case 40 / 8:
++		memcpy(&key_v[0], key->key, 5);
++		keytype = AR5K_KEYTABLE_TYPE_40;
++		break;
++
++	/* WEP 104-bit  = 104-bit entered key + 24-bit IV = 128-bit */
++	case 104 / 8:
++		memcpy(&key_v[0], &key->key[0], 6);
++		memcpy(&key_v[2], &key->key[6], 6);
++		memcpy(&key_v[4], &key->key[12], 1);
++		keytype = AR5K_KEYTABLE_TYPE_104;
++		break;
++	/* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
++	case 128 / 8:
++		memcpy(&key_v[0], &key->key[0], 6);
++		memcpy(&key_v[2], &key->key[6], 6);
++		memcpy(&key_v[4], &key->key[12], 4);
++		keytype = AR5K_KEYTABLE_TYPE_128;
++		break;
++
++	default:
++		return -EINVAL; /* shouldn't happen */
++	}
++
++	for (i = 0; i < ARRAY_SIZE(key_v); i++)
++		ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
++				AR5K_KEYTABLE_OFF(entry, i));
++
++	ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
++
++	return ath5k_hw_set_key_lladdr(ah, entry, mac);
++}
++
++int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
++{
++	u32 low_id, high_id;
++
++	ATH5K_TRACE(ah->ah_sc);
++	 /* Invalid entry (key table overflow) */
++	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
++
++	/* MAC may be NULL if it's a broadcast key. In this case no need to
++	 * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
++	if (unlikely(mac == NULL)) {
++		low_id = 0xffffffff;
++		high_id = 0xffff | AR5K_KEYTABLE_VALID;
++	} else {
++		low_id = AR5K_LOW_ID(mac);
++		high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
++	}
++
++	ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
++	ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
++
++	return 0;
++}
++
++
++/********************************************\
++Queue Control Unit, DFS Control Unit Functions
++\********************************************/
++
++/*
++ * Initialize a transmit queue
++ */
++int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
++		struct ath5k_txq_info *queue_info)
++{
++	unsigned int queue;
++	int ret;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/*
++	 * Get queue by type
++	 */
++	/*5210 only has 2 queues*/
++	if (ah->ah_version == AR5K_AR5210) {
++		switch (queue_type) {
++		case AR5K_TX_QUEUE_DATA:
++			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
++			break;
++		case AR5K_TX_QUEUE_BEACON:
++		case AR5K_TX_QUEUE_CAB:
++			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
++			break;
++		default:
++			return -EINVAL;
++		}
++	} else {
++		switch (queue_type) {
++		case AR5K_TX_QUEUE_DATA:
++			for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
++				ah->ah_txq[queue].tqi_type !=
++				AR5K_TX_QUEUE_INACTIVE; queue++) {
++
++				if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
++					return -EINVAL;
++			}
++			break;
++		case AR5K_TX_QUEUE_UAPSD:
++			queue = AR5K_TX_QUEUE_ID_UAPSD;
++			break;
++		case AR5K_TX_QUEUE_BEACON:
++			queue = AR5K_TX_QUEUE_ID_BEACON;
++			break;
++		case AR5K_TX_QUEUE_CAB:
++			queue = AR5K_TX_QUEUE_ID_CAB;
++			break;
++		case AR5K_TX_QUEUE_XR_DATA:
++			if (ah->ah_version != AR5K_AR5212)
++				ATH5K_ERR(ah->ah_sc,
++					"XR data queues only supported in"
++					" 5212!\n");
++			queue = AR5K_TX_QUEUE_ID_XR_DATA;
++			break;
++		default:
++			return -EINVAL;
++		}
++	}
++
++	/*
++	 * Setup internal queue structure
++	 */
++	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
++	ah->ah_txq[queue].tqi_type = queue_type;
++
++	if (queue_info != NULL) {
++		queue_info->tqi_type = queue_type;
++		ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info);
++		if (ret)
++			return ret;
++	}
++	/*
++	 * We use ah_txq_status to hold a temp value for
++	 * the Secondary interrupt mask registers on 5211+
++	 * check out ath5k_hw_reset_tx_queue
++	 */
++	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
++
++	return queue;
++}
++
++/*
++ * Setup a transmit queue
++ */
++int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue,
++				const struct ath5k_txq_info *queue_info)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
++
++	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
++		return -EIO;
++
++	memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
++
++	/*XXX: Is this supported on 5210 ?*/
++	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
++			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
++			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
++			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
++		ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
++
++	return 0;
++}
++
++/*
++ * Get properties for a specific transmit queue
++ */
++int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
++		struct ath5k_txq_info *queue_info)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
++	return 0;
++}
++
++/*
++ * Set a transmit queue inactive
++ */
++void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
++		return;
++
++	/* This queue will be skipped in further operations */
++	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
++	/*For SIMR setup*/
++	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
++}
++
++/*
++ * Set DFS params for a transmit queue
++ */
++int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
++{
++	u32 cw_min, cw_max, retry_lg, retry_sh;
++	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
++
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
++
++	tq = &ah->ah_txq[queue];
++
++	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
++		return 0;
++
++	if (ah->ah_version == AR5K_AR5210) {
++		/* Only handle data queues, others will be ignored */
++		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
++			return 0;
++
++		/* Set Slot time */
++		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
++			AR5K_SLOT_TIME);
++		/* Set ACK_CTS timeout */
++		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
++			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
++		/* Set Transmit Latency */
++		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
++			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
++		/* Set IFS0 */
++		if (ah->ah_turbo == true)
++			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
++				(ah->ah_aifs + tq->tqi_aifs) *
++				AR5K_INIT_SLOT_TIME_TURBO) <<
++				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
++				AR5K_IFS0);
++		else
++			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
++				(ah->ah_aifs + tq->tqi_aifs) *
++				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
++				AR5K_INIT_SIFS, AR5K_IFS0);
++
++		/* Set IFS1 */
++		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
++			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
++		/* Set PHY register 0x9844 (??) */
++		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++			(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 :
++			(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C,
++			AR5K_PHY(17));
++		/* Set Frame Control Register */
++		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
++			AR5K_PHY_TURBO_SHORT | 0x2020) :
++			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
++			AR5K_PHY_FRAME_CTL_5210);
++	}
++
++	/*
++	 * Calculate cwmin/max by channel mode
++	 */
++	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
++	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
++	ah->ah_aifs = AR5K_TUNE_AIFS;
++	/*XR is only supported on 5212*/
++	if (IS_CHAN_XR(ah->ah_current_channel) &&
++			ah->ah_version == AR5K_AR5212) {
++		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
++		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
++		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
++	/*B mode is not supported on 5210*/
++	} else if (IS_CHAN_B(ah->ah_current_channel) &&
++			ah->ah_version != AR5K_AR5210) {
++		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
++		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
++		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
++	}
++
++	cw_min = 1;
++	while (cw_min < ah->ah_cw_min)
++		cw_min = (cw_min << 1) | 1;
++
++	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
++		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
++	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
++		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
++
++	/*
++	 * Calculate and set retry limits
++	 */
++	if (ah->ah_software_retry == true) {
++		/* XXX Need to test this */
++		retry_lg = ah->ah_limit_tx_retries;
++		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
++			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
++	} else {
++		retry_lg = AR5K_INIT_LG_RETRY;
++		retry_sh = AR5K_INIT_SH_RETRY;
++	}
++
++	/*No QCU/DCU [5210]*/
++	if (ah->ah_version == AR5K_AR5210) {
++		ath5k_hw_reg_write(ah,
++			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
++			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
++				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
++			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
++				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
++			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
++			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
++			AR5K_NODCU_RETRY_LMT);
++	} else {
++		/*QCU/DCU [5211+]*/
++		ath5k_hw_reg_write(ah,
++			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
++				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
++			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
++				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
++			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
++			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
++			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
++
++	/*===Rest is also for QCU/DCU only [5211+]===*/
++
++		/*
++		 * Set initial content window (cw_min/cw_max)
++		 * and arbitrated interframe space (aifs)...
++		 */
++		ath5k_hw_reg_write(ah,
++			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
++			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
++			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
++				AR5K_DCU_LCL_IFS_AIFS),
++			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
++
++		/*
++		 * Set misc registers
++		 */
++		ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
++			AR5K_QUEUE_MISC(queue));
++
++		if (tq->tqi_cbr_period) {
++			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
++				AR5K_QCU_CBRCFG_INTVAL) |
++				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
++				AR5K_QCU_CBRCFG_ORN_THRES),
++				AR5K_QUEUE_CBRCFG(queue));
++			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
++				AR5K_QCU_MISC_FRSHED_CBR);
++			if (tq->tqi_cbr_overflow_limit)
++				AR5K_REG_ENABLE_BITS(ah,
++					AR5K_QUEUE_MISC(queue),
++					AR5K_QCU_MISC_CBR_THRES_ENABLE);
++		}
++
++		if (tq->tqi_ready_time)
++			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
++				AR5K_QCU_RDYTIMECFG_INTVAL) |
++				AR5K_QCU_RDYTIMECFG_ENABLE,
++				AR5K_QUEUE_RDYTIMECFG(queue));
++
++		if (tq->tqi_burst_time) {
++			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
++				AR5K_DCU_CHAN_TIME_DUR) |
++				AR5K_DCU_CHAN_TIME_ENABLE,
++				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
++
++			if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
++				AR5K_REG_ENABLE_BITS(ah,
++					AR5K_QUEUE_MISC(queue),
++					AR5K_QCU_MISC_TXE);
++		}
++
++		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
++			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
++				AR5K_QUEUE_DFS_MISC(queue));
++
++		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
++			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
++				AR5K_QUEUE_DFS_MISC(queue));
++
++		/*
++		 * Set registers by queue type
++		 */
++		switch (tq->tqi_type) {
++		case AR5K_TX_QUEUE_BEACON:
++			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
++				AR5K_QCU_MISC_FRSHED_DBA_GT |
++				AR5K_QCU_MISC_CBREXP_BCN |
++				AR5K_QCU_MISC_BCN_ENABLE);
++
++			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
++				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
++				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
++				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
++				AR5K_DCU_MISC_BCN_ENABLE);
++
++			ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
++				(AR5K_TUNE_SW_BEACON_RESP -
++				AR5K_TUNE_DMA_BEACON_RESP) -
++				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
++				AR5K_QCU_RDYTIMECFG_ENABLE,
++				AR5K_QUEUE_RDYTIMECFG(queue));
++			break;
++
++		case AR5K_TX_QUEUE_CAB:
++			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
++				AR5K_QCU_MISC_FRSHED_DBA_GT |
++				AR5K_QCU_MISC_CBREXP |
++				AR5K_QCU_MISC_CBREXP_BCN);
++
++			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
++				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
++				AR5K_DCU_MISC_ARBLOCK_CTL_S));
++			break;
++
++		case AR5K_TX_QUEUE_UAPSD:
++			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
++				AR5K_QCU_MISC_CBREXP);
++			break;
++
++		case AR5K_TX_QUEUE_DATA:
++		default:
++			break;
++		}
++
++		/*
++		 * Enable interrupts for this tx queue
++		 * in the secondary interrupt mask registers
++		 */
++		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
++			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
++
++		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
++			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
++
++		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
++			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
++
++		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
++			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
++
++		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
++			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
++
++
++		/* Update secondary interrupt mask registers */
++		ah->ah_txq_imr_txok &= ah->ah_txq_status;
++		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
++		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
++		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
++		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
++
++		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
++			AR5K_SIMR0_QCU_TXOK) |
++			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
++			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
++		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
++			AR5K_SIMR1_QCU_TXERR) |
++			AR5K_REG_SM(ah->ah_txq_imr_txeol,
++			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
++		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
++			AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
++	}
++
++	return 0;
++}
++
++/*
++ * Get number of pending frames
++ * for a specific queue [5211+]
++ */
++u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) {
++	ATH5K_TRACE(ah->ah_sc);
++	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
++
++	/* Return if queue is declared inactive */
++	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
++		return false;
++
++	/* XXX: How about AR5K_CFG_TXCNT ? */
++	if (ah->ah_version == AR5K_AR5210)
++		return false;
++
++	return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
++}
++
++/*
++ * Set slot time
++ */
++int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
++		return -EINVAL;
++
++	if (ah->ah_version == AR5K_AR5210)
++		ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
++				ah->ah_turbo), AR5K_SLOT_TIME);
++	else
++		ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
++
++	return 0;
++}
++
++/*
++ * Get slot time
++ */
++unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (ah->ah_version == AR5K_AR5210)
++		return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
++				AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
++	else
++		return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
++}
++
++
++/******************************\
++ Hardware Descriptor Functions
++\******************************/
++
++/*
++ * TX Descriptor
++ */
++
++/*
++ * Initialize the 2-word tx descriptor on 5210/5211
++ */
++static int
++ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
++	unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
++	unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
++	unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
++	unsigned int rtscts_rate, unsigned int rtscts_duration)
++{
++	u32 frame_type;
++	struct ath5k_hw_2w_tx_desc *tx_desc;
++	unsigned int buff_len;
++
++	tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
++
++	/*
++	 * Validate input
++	 * - Zero retries don't make sense.
++	 * - A zero rate will put the HW into a mode where it continously sends
++	 *   noise on the channel, so it is important to avoid this.
++	 */
++	if (unlikely(tx_tries0 == 0)) {
++		ATH5K_ERR(ah->ah_sc, "zero retries\n");
++		WARN_ON(1);
++		return -EINVAL;
++	}
++	if (unlikely(tx_rate0 == 0)) {
++		ATH5K_ERR(ah->ah_sc, "zero rate\n");
++		WARN_ON(1);
++		return -EINVAL;
++	}
++
++	/* Clear status descriptor */
++	memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status));
++
++	/* Initialize control descriptor */
++	tx_desc->tx_control_0 = 0;
++	tx_desc->tx_control_1 = 0;
++
++	/* Setup control descriptor */
++
++	/* Verify and set frame length */
++	if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
++		return -EINVAL;
++
++	tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
++
++	/* Verify and set buffer length */
++	buff_len = pkt_len - FCS_LEN;
++
++	/* NB: beacon's BufLen must be a multiple of 4 bytes */
++	if(type == AR5K_PKT_TYPE_BEACON)
++		buff_len = roundup(buff_len, 4);
++
++	if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
++		return -EINVAL;
++
++	tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
++
++	/*
++	 * Verify and set header length
++	 * XXX: I only found that on 5210 code, does it work on 5211 ?
++	 */
++	if (ah->ah_version == AR5K_AR5210) {
++		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
++			return -EINVAL;
++		tx_desc->tx_control_0 |=
++			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
++	}
++
++	/*Diferences between 5210-5211*/
++	if (ah->ah_version == AR5K_AR5210) {
++		switch (type) {
++		case AR5K_PKT_TYPE_BEACON:
++		case AR5K_PKT_TYPE_PROBE_RESP:
++			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
++		case AR5K_PKT_TYPE_PIFS:
++			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
++		default:
++			frame_type = type /*<< 2 ?*/;
++		}
++
++		tx_desc->tx_control_0 |=
++			AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
++			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
++	} else {
++		tx_desc->tx_control_0 |=
++			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
++			AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
++		tx_desc->tx_control_1 |=
++			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
++	}
++#define _TX_FLAGS(_c, _flag)						\
++	if (flags & AR5K_TXDESC_##_flag)				\
++		tx_desc->tx_control_##_c |=				\
++			AR5K_2W_TX_DESC_CTL##_c##_##_flag
++
++	_TX_FLAGS(0, CLRDMASK);
++	_TX_FLAGS(0, VEOL);
++	_TX_FLAGS(0, INTREQ);
++	_TX_FLAGS(0, RTSENA);
++	_TX_FLAGS(1, NOACK);
++
++#undef _TX_FLAGS
++
++	/*
++	 * WEP crap
++	 */
++	if (key_index != AR5K_TXKEYIX_INVALID) {
++		tx_desc->tx_control_0 |=
++			AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
++		tx_desc->tx_control_1 |=
++			AR5K_REG_SM(key_index,
++			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
++	}
++
++	/*
++	 * RTS/CTS Duration [5210 ?]
++	 */
++	if ((ah->ah_version == AR5K_AR5210) &&
++			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
++		tx_desc->tx_control_1 |= rtscts_duration &
++				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
++
++	return 0;
++}
++
++/*
++ * Initialize the 4-word tx descriptor on 5212
++ */
++static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
++	struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
++	enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
++	unsigned int tx_tries0, unsigned int key_index,
++	unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate,
++	unsigned int rtscts_duration)
++{
++	struct ath5k_hw_4w_tx_desc *tx_desc;
++	struct ath5k_hw_tx_status *tx_status;
++	unsigned int buff_len;
++
++	ATH5K_TRACE(ah->ah_sc);
++	tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
++	tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
++
++	/*
++	 * Validate input
++	 * - Zero retries don't make sense.
++	 * - A zero rate will put the HW into a mode where it continously sends
++	 *   noise on the channel, so it is important to avoid this.
++	 */
++	if (unlikely(tx_tries0 == 0)) {
++		ATH5K_ERR(ah->ah_sc, "zero retries\n");
++		WARN_ON(1);
++		return -EINVAL;
++	}
++	if (unlikely(tx_rate0 == 0)) {
++		ATH5K_ERR(ah->ah_sc, "zero rate\n");
++		WARN_ON(1);
++		return -EINVAL;
++	}
++
++	/* Clear status descriptor */
++	memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status));
++
++	/* Initialize control descriptor */
++	tx_desc->tx_control_0 = 0;
++	tx_desc->tx_control_1 = 0;
++	tx_desc->tx_control_2 = 0;
++	tx_desc->tx_control_3 = 0;
++
++	/* Setup control descriptor */
++
++	/* Verify and set frame length */
++	if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
++		return -EINVAL;
++
++	tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
++
++	/* Verify and set buffer length */
++	buff_len = pkt_len - FCS_LEN;
++
++	/* NB: beacon's BufLen must be a multiple of 4 bytes */
++	if(type == AR5K_PKT_TYPE_BEACON)
++		buff_len = roundup(buff_len, 4);
++
++	if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
++		return -EINVAL;
++
++	tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
++
++	tx_desc->tx_control_0 |=
++		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
++		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
++	tx_desc->tx_control_1 |= AR5K_REG_SM(type,
++					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
++	tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
++					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
++	tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
++
++#define _TX_FLAGS(_c, _flag)			\
++	if (flags & AR5K_TXDESC_##_flag)	\
++		tx_desc->tx_control_##_c |=	\
++			AR5K_4W_TX_DESC_CTL##_c##_##_flag
++
++	_TX_FLAGS(0, CLRDMASK);
++	_TX_FLAGS(0, VEOL);
++	_TX_FLAGS(0, INTREQ);
++	_TX_FLAGS(0, RTSENA);
++	_TX_FLAGS(0, CTSENA);
++	_TX_FLAGS(1, NOACK);
++
++#undef _TX_FLAGS
++
++	/*
++	 * WEP crap
++	 */
++	if (key_index != AR5K_TXKEYIX_INVALID) {
++		tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
++		tx_desc->tx_control_1 |= AR5K_REG_SM(key_index,
++				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
++	}
++
++	/*
++	 * RTS/CTS
++	 */
++	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
++		if ((flags & AR5K_TXDESC_RTSENA) &&
++				(flags & AR5K_TXDESC_CTSENA))
++			return -EINVAL;
++		tx_desc->tx_control_2 |= rtscts_duration &
++				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
++		tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
++				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
++	}
++
++	return 0;
++}
++
++/*
++ * Initialize a 4-word multirate tx descriptor on 5212
++ */
++static bool
++ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
++	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2,
++	unsigned int tx_rate3, u_int tx_tries3)
++{
++	struct ath5k_hw_4w_tx_desc *tx_desc;
++
++	/*
++	 * Rates can be 0 as long as the retry count is 0 too.
++	 * A zero rate and nonzero retry count will put the HW into a mode where
++	 * it continously sends noise on the channel, so it is important to
++	 * avoid this.
++	 */
++	if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
++		     (tx_rate2 == 0 && tx_tries2 != 0) ||
++		     (tx_rate3 == 0 && tx_tries3 != 0))) {
++		ATH5K_ERR(ah->ah_sc, "zero rate\n");
++		WARN_ON(1);
++		return -EINVAL;
++	}
++
++	if (ah->ah_version == AR5K_AR5212) {
++		tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
++
++#define _XTX_TRIES(_n)							\
++	if (tx_tries##_n) {						\
++		tx_desc->tx_control_2 |=				\
++		    AR5K_REG_SM(tx_tries##_n,				\
++		    AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n);		\
++		tx_desc->tx_control_3 |=				\
++		    AR5K_REG_SM(tx_rate##_n,				\
++		    AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n);		\
++	}
++
++		_XTX_TRIES(1);
++		_XTX_TRIES(2);
++		_XTX_TRIES(3);
++
++#undef _XTX_TRIES
++
++		return true;
++	}
++
++	return false;
++}
++
++/*
++ * Proccess the tx status descriptor on 5210/5211
++ */
++static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
++		struct ath5k_desc *desc)
++{
++	struct ath5k_hw_tx_status *tx_status;
++	struct ath5k_hw_2w_tx_desc *tx_desc;
++
++	tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
++	tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0];
++
++	/* No frame has been send or error */
++	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
++		return -EINPROGRESS;
++
++	/*
++	 * Get descriptor status
++	 */
++	desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
++		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
++	desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
++		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
++	desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
++		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
++	/*TODO: desc->ds_us.tx.ts_virtcol + test*/
++	desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
++		AR5K_DESC_TX_STATUS1_SEQ_NUM);
++	desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
++		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
++	desc->ds_us.tx.ts_antenna = 1;
++	desc->ds_us.tx.ts_status = 0;
++	desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0,
++		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
++
++	if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
++		if (tx_status->tx_status_0 &
++				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
++			desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
++
++		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
++			desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
++
++		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
++			desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
++	}
++
++	return 0;
++}
++
++/*
++ * Proccess a tx descriptor on 5212
++ */
++static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
++		struct ath5k_desc *desc)
++{
++	struct ath5k_hw_tx_status *tx_status;
++	struct ath5k_hw_4w_tx_desc *tx_desc;
++
++	ATH5K_TRACE(ah->ah_sc);
++	tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
++	tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
++
++	/* No frame has been send or error */
++	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
++		return -EINPROGRESS;
++
++	/*
++	 * Get descriptor status
++	 */
++	desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
++		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
++	desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
++		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
++	desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
++		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
++	desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
++		AR5K_DESC_TX_STATUS1_SEQ_NUM);
++	desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
++		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
++	desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 &
++		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
++	desc->ds_us.tx.ts_status = 0;
++
++	switch (AR5K_REG_MS(tx_status->tx_status_1,
++			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
++	case 0:
++		desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 &
++			AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
++		break;
++	case 1:
++		desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
++			AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
++		desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
++			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
++		break;
++	case 2:
++		desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
++			AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
++		desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
++			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
++		break;
++	case 3:
++		desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
++			AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
++		desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
++			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
++		break;
++	}
++
++	if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
++		if (tx_status->tx_status_0 &
++				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
++			desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
++
++		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
++			desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
++
++		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
++			desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
++	}
++
++	return 0;
++}
++
++/*
++ * RX Descriptor
++ */
++
++/*
++ * Initialize an rx descriptor
++ */
++int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
++			u32 size, unsigned int flags)
++{
++	struct ath5k_rx_desc *rx_desc;
++
++	ATH5K_TRACE(ah->ah_sc);
++	rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0;
++
++	/*
++	 *Clear ds_hw
++	 * If we don't clean the status descriptor,
++	 * while scanning we get too many results,
++	 * most of them virtual, after some secs
++	 * of scanning system hangs. M.F.
++	*/
++	memset(desc->ds_hw, 0, sizeof(desc->ds_hw));
++
++	/*Initialize rx descriptor*/
++	rx_desc->rx_control_0 = 0;
++	rx_desc->rx_control_1 = 0;
++
++	/* Setup descriptor */
++	rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
++	if (unlikely(rx_desc->rx_control_1 != size))
++		return -EINVAL;
++
++	if (flags & AR5K_RXDESC_INTREQ)
++		rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
++
++	return 0;
++}
++
++/*
++ * Proccess the rx status descriptor on 5210/5211
++ */
++static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah,
++		struct ath5k_desc *desc)
++{
++	struct ath5k_hw_old_rx_status *rx_status;
++
++	rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0];
++
++	/* No frame received / not ready */
++	if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE)
++				== 0))
++		return -EINPROGRESS;
++
++	/*
++	 * Frame receive status
++	 */
++	desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
++		AR5K_OLD_RX_DESC_STATUS0_DATA_LEN;
++	desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
++		AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL);
++	desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
++		AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE);
++	desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
++		AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA;
++	desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
++		AR5K_OLD_RX_DESC_STATUS0_MORE;
++	desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
++		AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
++	desc->ds_us.rx.rs_status = 0;
++
++	/*
++	 * Key table status
++	 */
++	if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID)
++		desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
++			AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX);
++	else
++		desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
++
++	/*
++	 * Receive/descriptor errors
++	 */
++	if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK)
++			== 0) {
++		if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR)
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
++
++		if (rx_status->rx_status_1 &
++				AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN)
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO;
++
++		if (rx_status->rx_status_1 &
++				AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) {
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
++			desc->ds_us.rx.rs_phyerr =
++				AR5K_REG_MS(rx_status->rx_status_1,
++					AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR);
++		}
++
++		if (rx_status->rx_status_1 &
++				AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
++	}
++
++	return 0;
++}
++
++/*
++ * Proccess the rx status descriptor on 5212
++ */
++static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah,
++		struct ath5k_desc *desc)
++{
++	struct ath5k_hw_new_rx_status *rx_status;
++	struct ath5k_hw_rx_error *rx_err;
++
++	ATH5K_TRACE(ah->ah_sc);
++	rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0];
++
++	/* Overlay on error */
++	rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0];
++
++	/* No frame received / not ready */
++	if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE)
++				== 0))
++		return -EINPROGRESS;
++
++	/*
++	 * Frame receive status
++	 */
++	desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
++		AR5K_NEW_RX_DESC_STATUS0_DATA_LEN;
++	desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
++		AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL);
++	desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
++		AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE);
++	desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
++		AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA;
++	desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
++		AR5K_NEW_RX_DESC_STATUS0_MORE;
++	desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
++		AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
++	desc->ds_us.rx.rs_status = 0;
++
++	/*
++	 * Key table status
++	 */
++	if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID)
++		desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
++				AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX);
++	else
++		desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
++
++	/*
++	 * Receive/descriptor errors
++	 */
++	if ((rx_status->rx_status_1 &
++			AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
++		if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR)
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
++
++		if (rx_status->rx_status_1 &
++				AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) {
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
++			desc->ds_us.rx.rs_phyerr =
++				AR5K_REG_MS(rx_err->rx_error_1,
++					AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
++		}
++
++		if (rx_status->rx_status_1 &
++				AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
++
++		if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR)
++			desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC;
++	}
++
++	return 0;
++}
++
++
++/****************\
++  GPIO Functions
++\****************/
++
++/*
++ * Set led state
++ */
++void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
++{
++	u32 led;
++	/*5210 has different led mode handling*/
++	u32 led_5210;
++
++	ATH5K_TRACE(ah->ah_sc);
++
++	/*Reset led status*/
++	if (ah->ah_version != AR5K_AR5210)
++		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
++			AR5K_PCICFG_LEDMODE |  AR5K_PCICFG_LED);
++	else
++		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED);
++
++	/*
++	 * Some blinking values, define at your wish
++	 */
++	switch (state) {
++	case AR5K_LED_SCAN:
++	case AR5K_LED_AUTH:
++		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND;
++		led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL;
++		break;
++
++	case AR5K_LED_INIT:
++		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE;
++		led_5210 = AR5K_PCICFG_LED_PEND;
++		break;
++
++	case AR5K_LED_ASSOC:
++	case AR5K_LED_RUN:
++		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC;
++		led_5210 = AR5K_PCICFG_LED_ASSOC;
++		break;
++
++	default:
++		led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE;
++		led_5210 = AR5K_PCICFG_LED_PEND;
++		break;
++	}
++
++	/*Write new status to the register*/
++	if (ah->ah_version != AR5K_AR5210)
++		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led);
++	else
++		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
++}
++
++/*
++ * Set GPIO outputs
++ */
++int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (gpio > AR5K_NUM_GPIO)
++		return -EINVAL;
++
++	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
++		AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
++
++	return 0;
++}
++
++/*
++ * Set GPIO inputs
++ */
++int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (gpio > AR5K_NUM_GPIO)
++		return -EINVAL;
++
++	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
++		AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
++
++	return 0;
++}
++
++/*
++ * Get GPIO state
++ */
++u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
++{
++	ATH5K_TRACE(ah->ah_sc);
++	if (gpio > AR5K_NUM_GPIO)
++		return 0xffffffff;
++
++	/* GPIO input magic */
++	return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
++		0x1;
++}
++
++/*
++ * Set GPIO state
++ */
++int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
++{
++	u32 data;
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (gpio > AR5K_NUM_GPIO)
++		return -EINVAL;
++
++	/* GPIO output magic */
++	data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
++
++	data &= ~(1 << gpio);
++	data |= (val & 1) << gpio;
++
++	ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
++
++	return 0;
++}
++
++/*
++ * Initialize the GPIO interrupt (RFKill switch)
++ */
++void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
++		u32 interrupt_level)
++{
++	u32 data;
++
++	ATH5K_TRACE(ah->ah_sc);
++	if (gpio > AR5K_NUM_GPIO)
++		return;
++
++	/*
++	 * Set the GPIO interrupt
++	 */
++	data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
++		~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
++		AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
++		(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
++
++	ath5k_hw_reg_write(ah, interrupt_level ? data :
++		(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
++
++	ah->ah_imr |= AR5K_IMR_GPIO;
++
++	/* Enable GPIO interrupts */
++	AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
++}
++
++
++/*********************************\
++ Regulatory Domain/Channels Setup
++\*********************************/
++
++u16 ath5k_get_regdomain(struct ath5k_hw *ah)
++{
++	u16 regdomain;
++	enum ath5k_regdom ieee_regdomain;
++#ifdef COUNTRYCODE
++	u16 code;
++#endif
++
++	ath5k_eeprom_regulation_domain(ah, false, &ieee_regdomain);
++	ah->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain;
++
++#ifdef COUNTRYCODE
++	/*
++	 * Get the regulation domain by country code. This will ignore
++	 * the settings found in the EEPROM.
++	 */
++	code = ieee80211_name2countrycode(COUNTRYCODE);
++	ieee_regdomain = ieee80211_countrycode2regdomain(code);
++#endif
++
++	regdomain = ath5k_regdom_from_ieee(ieee_regdomain);
++	ah->ah_capabilities.cap_regdomain.reg_current = regdomain;
++
++	return regdomain;
++}
++
++
++/****************\
++  Misc functions
++\****************/
++
++int ath5k_hw_get_capability(struct ath5k_hw *ah,
++		enum ath5k_capability_type cap_type,
++		u32 capability, u32 *result)
++{
++	ATH5K_TRACE(ah->ah_sc);
++
++	switch (cap_type) {
++	case AR5K_CAP_NUM_TXQUEUES:
++		if (result) {
++			if (ah->ah_version == AR5K_AR5210)
++				*result = AR5K_NUM_TX_QUEUES_NOQCU;
++			else
++				*result = AR5K_NUM_TX_QUEUES;
++			goto yes;
++		}
++	case AR5K_CAP_VEOL:
++		goto yes;
++	case AR5K_CAP_COMPRESSION:
++		if (ah->ah_version == AR5K_AR5212)
++			goto yes;
++		else
++			goto no;
++	case AR5K_CAP_BURST:
++		goto yes;
++	case AR5K_CAP_TPC:
++		goto yes;
++	case AR5K_CAP_BSSIDMASK:
++		if (ah->ah_version == AR5K_AR5212)
++			goto yes;
++		else
++			goto no;
++	case AR5K_CAP_XR:
++		if (ah->ah_version == AR5K_AR5212)
++			goto yes;
++		else
++			goto no;
++	default:
++		goto no;
++	}
++
++no:
++	return -EINVAL;
++yes:
++	return 0;
++}
++
++static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
++		u16 assoc_id)
++{
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (ah->ah_version == AR5K_AR5210) {
++		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
++			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
++		return 0;
++	}
++
++	return -EIO;
++}
++
++static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
++{
++	ATH5K_TRACE(ah->ah_sc);
++
++	if (ah->ah_version == AR5K_AR5210) {
++		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
++			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
++		return 0;
++	}
++
++	return -EIO;
++}
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.h
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/hw.h	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,588 @@
++/*
++ * Copyright (c) 2004-2007 Reyk Floeter <reyk at openbsd.org>
++ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm at gmail.com>
++ * Copyright (c) 2007 Matthew W. S. Bell  <mentor at madwifi.org>
++ * Copyright (c) 2007 Luis Rodriguez <mcgrof at winlab.rutgers.edu>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <linux/delay.h>
++
++/*
++ * Gain settings
++ */
++
++enum ath5k_rfgain {
++	AR5K_RFGAIN_INACTIVE = 0,
++	AR5K_RFGAIN_READ_REQUESTED,
++	AR5K_RFGAIN_NEED_CHANGE,
++};
++
++#define AR5K_GAIN_CRN_FIX_BITS_5111		4
++#define AR5K_GAIN_CRN_FIX_BITS_5112		7
++#define AR5K_GAIN_CRN_MAX_FIX_BITS		AR5K_GAIN_CRN_FIX_BITS_5112
++#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN		15
++#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN		20
++#define AR5K_GAIN_CCK_PROBE_CORR		5
++#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA		15
++#define AR5K_GAIN_STEP_COUNT			10
++#define AR5K_GAIN_PARAM_TX_CLIP			0
++#define AR5K_GAIN_PARAM_PD_90			1
++#define AR5K_GAIN_PARAM_PD_84			2
++#define AR5K_GAIN_PARAM_GAIN_SEL		3
++#define AR5K_GAIN_PARAM_MIX_ORN			0
++#define AR5K_GAIN_PARAM_PD_138			1
++#define AR5K_GAIN_PARAM_PD_137			2
++#define AR5K_GAIN_PARAM_PD_136			3
++#define AR5K_GAIN_PARAM_PD_132			4
++#define AR5K_GAIN_PARAM_PD_131			5
++#define AR5K_GAIN_PARAM_PD_130			6
++#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
++	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
++
++struct ath5k_gain_opt_step {
++	s16				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
++	s32				gos_gain;
++};
++
++struct ath5k_gain {
++	u32			g_step_idx;
++	u32			g_current;
++	u32			g_target;
++	u32			g_low;
++	u32			g_high;
++	u32			g_f_corr;
++	u32			g_active;
++	const struct ath5k_gain_opt_step	*g_step;
++};
++
++
++/*
++ * HW SPECIFIC STRUCTS
++ */
++
++/* Some EEPROM defines */
++#define AR5K_EEPROM_EEP_SCALE		100
++#define AR5K_EEPROM_EEP_DELTA		10
++#define AR5K_EEPROM_N_MODES		3
++#define AR5K_EEPROM_N_5GHZ_CHAN		10
++#define AR5K_EEPROM_N_2GHZ_CHAN		3
++#define AR5K_EEPROM_MAX_CHAN		10
++#define AR5K_EEPROM_N_PCDAC		11
++#define AR5K_EEPROM_N_TEST_FREQ		8
++#define AR5K_EEPROM_N_EDGES		8
++#define AR5K_EEPROM_N_INTERCEPTS	11
++#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
++#define AR5K_EEPROM_PCDAC_M		0x3f
++#define AR5K_EEPROM_PCDAC_START		1
++#define AR5K_EEPROM_PCDAC_STOP		63
++#define AR5K_EEPROM_PCDAC_STEP		1
++#define AR5K_EEPROM_NON_EDGE_M		0x40
++#define AR5K_EEPROM_CHANNEL_POWER	8
++#define AR5K_EEPROM_N_OBDB		4
++#define AR5K_EEPROM_OBDB_DIS		0xffff
++#define AR5K_EEPROM_CHANNEL_DIS		0xff
++#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
++#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
++#define AR5K_EEPROM_MAX_CTLS		32
++#define AR5K_EEPROM_N_XPD_PER_CHANNEL	4
++#define AR5K_EEPROM_N_XPD0_POINTS	4
++#define AR5K_EEPROM_N_XPD3_POINTS	3
++#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
++#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
++#define AR5K_EEPROM_POWER_M		0x3f
++#define AR5K_EEPROM_POWER_MIN		0
++#define AR5K_EEPROM_POWER_MAX		3150
++#define AR5K_EEPROM_POWER_STEP		50
++#define AR5K_EEPROM_POWER_TABLE_SIZE	64
++#define AR5K_EEPROM_N_POWER_LOC_11B	4
++#define AR5K_EEPROM_N_POWER_LOC_11G	6
++#define AR5K_EEPROM_I_GAIN		10
++#define AR5K_EEPROM_CCK_OFDM_DELTA	15
++#define AR5K_EEPROM_N_IQ_CAL		2
++
++/* Struct to hold EEPROM calibration data */
++struct ath5k_eeprom_info {
++	u16	ee_magic;
++	u16	ee_protect;
++	u16	ee_regdomain;
++	u16	ee_version;
++	u16	ee_header;
++	u16	ee_ant_gain;
++	u16	ee_misc0;
++	u16	ee_misc1;
++	u16	ee_cck_ofdm_gain_delta;
++	u16	ee_cck_ofdm_power_delta;
++	u16	ee_scaled_cck_delta;
++
++	/* Used for tx thermal adjustment (eeprom_init, rfregs) */
++	u16	ee_tx_clip;
++	u16	ee_pwd_84;
++	u16	ee_pwd_90;
++	u16	ee_gain_select;
++
++	/* RF Calibration settings (reset, rfregs) */
++	u16	ee_i_cal[AR5K_EEPROM_N_MODES];
++	u16	ee_q_cal[AR5K_EEPROM_N_MODES];
++	u16	ee_fixed_bias[AR5K_EEPROM_N_MODES];
++	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
++	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
++	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
++	u16	ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
++	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
++	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
++	u16	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
++	u16	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
++	u16	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
++	u16	ee_thr_62[AR5K_EEPROM_N_MODES];
++	u16	ee_xlna_gain[AR5K_EEPROM_N_MODES];
++	u16	ee_xpd[AR5K_EEPROM_N_MODES];
++	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
++	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
++	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
++
++	/* Unused */
++	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
++	u16	ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
++	u16	ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
++
++	/* Conformance test limits (Unused) */
++	u16	ee_ctls;
++	u16	ee_ctl[AR5K_EEPROM_MAX_CTLS];
++
++	/* Noise Floor Calibration settings */
++	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
++	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
++	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
++};
++
++/*
++ * Internal RX/TX descriptor structures
++ * (rX: reserved fields possibily used by future versions of the ar5k chipset)
++ */
++
++struct ath5k_rx_desc {
++	u32	rx_control_0; /* RX control word 0 */
++
++#define AR5K_DESC_RX_CTL0			0x00000000
++
++	u32	rx_control_1; /* RX control word 1 */
++
++#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
++#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
++} __packed;
++
++/*
++ * 5210/5211 rx status descriptor
++ */
++struct ath5k_hw_old_rx_status {
++	u32	rx_status_0; /* RX status word 0 */
++
++#define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN		0x00000fff
++#define AR5K_OLD_RX_DESC_STATUS0_MORE			0x00001000
++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S		15
++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL		0x07f80000
++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
++#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
++
++	u32	rx_status_1; /* RX status word 1 */
++
++#define AR5K_OLD_RX_DESC_STATUS1_DONE			0x00000001
++#define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
++#define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR		0x00000004
++#define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
++#define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
++#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
++#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S		5
++#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
++#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
++#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S		9
++#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
++#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
++#define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS		0x10000000
++} __packed;
++
++/*
++ * 5212 rx status descriptor
++ */
++struct ath5k_hw_new_rx_status {
++	u32	rx_status_0; /* RX status word 0 */
++
++#define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN		0x00000fff
++#define AR5K_NEW_RX_DESC_STATUS0_MORE			0x00001000
++#define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S		15
++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL		0x0ff00000
++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
++#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
++
++	u32	rx_status_1; /* RX status word 1 */
++
++#define AR5K_NEW_RX_DESC_STATUS1_DONE			0x00000001
++#define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
++#define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR		0x00000004
++#define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
++#define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR		0x00000010
++#define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR		0x00000020
++#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
++#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
++#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S		9
++#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
++#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
++#define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS		0x80000000
++} __packed;
++
++struct ath5k_hw_rx_error {
++	u32	rx_error_0; /* RX error word 0 */
++
++#define AR5K_RX_DESC_ERROR0			0x00000000
++
++	u32	rx_error_1; /* RX error word 1 */
++
++#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
++#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
++} __packed;
++
++#define AR5K_DESC_RX_PHY_ERROR_NONE		0x00
++#define AR5K_DESC_RX_PHY_ERROR_TIMING		0x20
++#define AR5K_DESC_RX_PHY_ERROR_PARITY		0x40
++#define AR5K_DESC_RX_PHY_ERROR_RATE		0x60
++#define AR5K_DESC_RX_PHY_ERROR_LENGTH		0x80
++#define AR5K_DESC_RX_PHY_ERROR_64QAM		0xa0
++#define AR5K_DESC_RX_PHY_ERROR_SERVICE		0xc0
++#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR	0xe0
++
++struct ath5k_hw_2w_tx_desc {
++	u32	tx_control_0; /* TX control word 0 */
++
++#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
++#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
++#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
++#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
++#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
++#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
++#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
++#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
++#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
++#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
++#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT	(ah->ah_version == AR5K_AR5210 ? \
++						AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \
++						AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
++#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
++#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
++#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
++
++	u32	tx_control_1; /* TX control word 1 */
++
++#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
++#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	(ah->ah_version == AR5K_AR5210 ? \
++						AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \
++						AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
++#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
++#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
++#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
++#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
++#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
++} __packed;
++
++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
++#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
++
++/*
++ * 5212 4-word tx control descriptor
++ */
++struct ath5k_hw_4w_tx_desc {
++	u32	tx_control_0; /* TX control word 0 */
++
++#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
++#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
++#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
++#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
++#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
++#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
++#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
++#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
++#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
++#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
++#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
++
++	u32	tx_control_1; /* TX control word 1 */
++
++#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
++#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
++#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
++#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
++#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
++#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
++#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
++#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
++#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
++#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
++#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
++#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
++#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
++
++	u32	tx_control_2; /* TX control word 2 */
++
++#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
++#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
++#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
++
++	u32	tx_control_3; /* TX control word 3 */
++
++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
++#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
++#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
++#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
++} __packed;
++
++/*
++ * Common tx status descriptor
++ */
++struct ath5k_hw_tx_status {
++	u32	tx_status_0; /* TX status word 0 */
++
++#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
++#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
++#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
++#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
++/*???
++#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
++#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
++*/
++#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
++#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
++/*???
++#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
++#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
++*/
++#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
++#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
++#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
++#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
++#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
++#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
++
++	u32	tx_status_1; /* TX status word 1 */
++
++#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
++#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
++#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
++#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
++#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
++#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
++#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
++#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
++#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
++} __packed;
++
++
++/*
++ * AR5K REGISTER ACCESS
++ */
++
++/*Swap RX/TX Descriptor for big endian archs*/
++#if defined(__BIG_ENDIAN)
++#define AR5K_INIT_CFG	(		\
++	AR5K_CFG_SWTD | AR5K_CFG_SWRD	\
++)
++#else
++#define AR5K_INIT_CFG	0x00000000
++#endif
++
++/*#define AR5K_REG_READ(_reg)	ath5k_hw_reg_read(ah, _reg)
++
++#define AR5K_REG_WRITE(_reg, _val)	ath5k_hw_reg_write(ah, _val, _reg)*/
++
++#define AR5K_REG_SM(_val, _flags)					\
++	(((_val) << _flags##_S) & (_flags))
++
++#define AR5K_REG_MS(_val, _flags)					\
++	(((_val) & (_flags)) >> _flags##_S)
++
++/* Some registers can hold multiple values of interest. For this
++ * reason when we want to write to these registers we must first
++ * retrieve the values which we do not want to clear (lets call this
++ * old_data) and then set the register with this and our new_value:
++ * ( old_data | new_value) */
++#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)			\
++	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
++	    (((_val) << _flags##_S) & (_flags)), _reg)
++
++#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)			\
++	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &		\
++			(_mask)) | (_flags), _reg)
++
++#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)				\
++	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
++
++#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
++	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
++
++#define AR5K_PHY_WRITE(ah, _reg, _val)					\
++	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
++
++#define AR5K_PHY_READ(ah, _reg)					\
++	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
++
++#define AR5K_REG_WAIT(_i) do {						\
++	if (_i % 64)							\
++		udelay(1);						\
++} while (0)
++
++#define AR5K_EEPROM_READ(_o, _v) do {					\
++	if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0)	\
++		return (ret);						\
++} while (0)
++
++#define AR5K_EEPROM_READ_HDR(_o, _v)					\
++	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
++
++/* Read status of selected queue */
++#define AR5K_REG_READ_Q(ah, _reg, _queue)				\
++	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
++
++#define AR5K_REG_WRITE_Q(ah, _reg, _queue)				\
++	ath5k_hw_reg_write(ah, (1 << _queue), _reg)
++
++#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {				\
++	_reg |= 1 << _queue;						\
++} while (0)
++
++#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {				\
++	_reg &= ~(1 << _queue);						\
++} while (0)
++
++#define AR5K_LOW_ID(_a)(				\
++(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
++)
++
++#define AR5K_HIGH_ID(_a)	((_a)[4] | (_a)[5] << 8)
++
++/*
++ * Initial register values
++ */
++
++/*
++ * Common initial register values
++ */
++#define AR5K_INIT_MODE				CHANNEL_B
++
++#define AR5K_INIT_TX_LATENCY			502
++#define AR5K_INIT_USEC				39
++#define AR5K_INIT_USEC_TURBO			79
++#define AR5K_INIT_USEC_32			31
++#define AR5K_INIT_CARR_SENSE_EN			1
++#define AR5K_INIT_PROG_IFS			920
++#define AR5K_INIT_PROG_IFS_TURBO		960
++#define AR5K_INIT_EIFS				3440
++#define AR5K_INIT_EIFS_TURBO			6880
++#define AR5K_INIT_SLOT_TIME			396
++#define AR5K_INIT_SLOT_TIME_TURBO		480
++#define AR5K_INIT_ACK_CTS_TIMEOUT		1024
++#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO		0x08000800
++#define AR5K_INIT_SIFS				560
++#define AR5K_INIT_SIFS_TURBO			480
++#define AR5K_INIT_SH_RETRY			10
++#define AR5K_INIT_LG_RETRY			AR5K_INIT_SH_RETRY
++#define AR5K_INIT_SSH_RETRY			32
++#define AR5K_INIT_SLG_RETRY			AR5K_INIT_SSH_RETRY
++#define AR5K_INIT_TX_RETRY			10
++#define AR5K_INIT_TOPS				8
++#define AR5K_INIT_RXNOFRM			8
++#define AR5K_INIT_RPGTO				0
++#define AR5K_INIT_TXNOFRM			0
++#define AR5K_INIT_BEACON_PERIOD			65535
++#define AR5K_INIT_TIM_OFFSET			0
++#define AR5K_INIT_BEACON_EN			0
++#define AR5K_INIT_RESET_TSF			0
++
++#define AR5K_INIT_TRANSMIT_LATENCY		(			\
++	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
++	(AR5K_INIT_USEC)						\
++)
++#define AR5K_INIT_TRANSMIT_LATENCY_TURBO	(			\
++	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
++	(AR5K_INIT_USEC_TURBO)						\
++)
++#define AR5K_INIT_PROTO_TIME_CNTRL		(			\
++	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |	\
++	(AR5K_INIT_PROG_IFS)						\
++)
++#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO	(			\
++	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
++	(AR5K_INIT_PROG_IFS_TURBO)					\
++)
++#define AR5K_INIT_BEACON_CONTROL		(			\
++	(AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) |	\
++	(AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD)	\
++)
++
++/*
++ * Non-common initial register values which have to be loaded into the
++ * card at boot time and after each reset.
++ */
++
++/* Register dumps are done per operation mode */
++#define AR5K_INI_RFGAIN_5GHZ		0
++#define AR5K_INI_RFGAIN_2GHZ		1
++
++#define AR5K_INI_VAL_11A		0
++#define AR5K_INI_VAL_11A_TURBO		1
++#define AR5K_INI_VAL_11B		2
++#define AR5K_INI_VAL_11G		3
++#define AR5K_INI_VAL_11G_TURBO		4
++#define AR5K_INI_VAL_XR			0
++#define AR5K_INI_VAL_MAX		5
++
++#define AR5K_RF5111_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
++#define AR5K_RF5112_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
++
++static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
++{
++	u32 retval = 0, bit, i;
++
++	for (i = 0; i < bits; i++) {
++		bit = (val >> i) & 1;
++		retval = (retval << 1) | bit;
++	}
++
++	return retval;
++}
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/initvals.c
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/initvals.c	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,1347 @@
++/*
++ * Initial register settings functions
++ *
++ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk at openbsd.org>
++ * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm at gmail.com>
++ * Copyright (c) 2007 Jiri Slaby <jirislaby at gmail.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ */
++
++#include "ath5k.h"
++#include "base.h"
++#include "reg.h"
++
++/*
++ * MAC/PHY REGISTERS
++ */
++
++
++/*
++ * Mode-independent initial register writes
++ */
++
++struct ath5k_ini {
++	u16	ini_register;
++	u32	ini_value;
++
++	enum {
++		AR5K_INI_WRITE = 0,	/* Default */
++		AR5K_INI_READ = 1,	/* Cleared on read */
++	} ini_mode;
++};
++
++/*
++ * Mode specific initial register values
++ */
++
++struct ath5k_ini_mode {
++	u16	mode_register;
++	u32	mode_value[5];
++};
++
++/* Initial register settings for AR5210 */
++static const struct ath5k_ini ar5210_ini[] = {
++	/* PCU and MAC registers */
++	{ AR5K_NOQCU_TXDP0,	0 },
++	{ AR5K_NOQCU_TXDP1,	0 },
++	{ AR5K_RXDP,		0 },
++	{ AR5K_CR,		0 },
++	{ AR5K_ISR,		0, AR5K_INI_READ },
++	{ AR5K_IMR,		0 },
++	{ AR5K_IER,		AR5K_IER_DISABLE },
++	{ AR5K_BSR,		0, AR5K_INI_READ },
++	{ AR5K_TXCFG,		AR5K_DMASIZE_128B },
++	{ AR5K_RXCFG,		AR5K_DMASIZE_128B },
++	{ AR5K_CFG,		AR5K_INIT_CFG },
++	{ AR5K_TOPS,		AR5K_INIT_TOPS },
++	{ AR5K_RXNOFRM,		AR5K_INIT_RXNOFRM },
++	{ AR5K_RPGTO,		AR5K_INIT_RPGTO },
++	{ AR5K_TXNOFRM,		AR5K_INIT_TXNOFRM },
++	{ AR5K_SFR,		0 },
++	{ AR5K_MIBC,		0 },
++	{ AR5K_MISC,		0 },
++	{ AR5K_RX_FILTER_5210,	0 },
++	{ AR5K_MCAST_FILTER0_5210, 0 },
++	{ AR5K_MCAST_FILTER1_5210, 0 },
++	{ AR5K_TX_MASK0,	0 },
++	{ AR5K_TX_MASK1,	0 },
++	{ AR5K_CLR_TMASK,	0 },
++	{ AR5K_TRIG_LVL,	AR5K_TUNE_MIN_TX_FIFO_THRES },
++	{ AR5K_DIAG_SW_5210,	0 },
++	{ AR5K_RSSI_THR,	AR5K_TUNE_RSSI_THRES },
++	{ AR5K_TSF_L32_5210,	0 },
++	{ AR5K_TIMER0_5210,	0 },
++	{ AR5K_TIMER1_5210,	0xffffffff },
++	{ AR5K_TIMER2_5210,	0xffffffff },
++	{ AR5K_TIMER3_5210,	1 },
++	{ AR5K_CFP_DUR_5210,	0 },
++	{ AR5K_CFP_PERIOD_5210,	0 },
++	/* PHY registers */
++	{ AR5K_PHY(0),	0x00000047 },
++	{ AR5K_PHY_AGC,	0x00000000 },
++	{ AR5K_PHY(3),	0x09848ea6 },
++	{ AR5K_PHY(4),	0x3d32e000 },
++	{ AR5K_PHY(5),	0x0000076b },
++	{ AR5K_PHY_ACT,	AR5K_PHY_ACT_DISABLE },
++	{ AR5K_PHY(8),	0x02020200 },
++	{ AR5K_PHY(9),	0x00000e0e },
++	{ AR5K_PHY(10),	0x0a020201 },
++	{ AR5K_PHY(11),	0x00036ffc },
++	{ AR5K_PHY(12),	0x00000000 },
++	{ AR5K_PHY(13),	0x00000e0e },
++	{ AR5K_PHY(14),	0x00000007 },
++	{ AR5K_PHY(15),	0x00020100 },
++	{ AR5K_PHY(16),	0x89630000 },
++	{ AR5K_PHY(17),	0x1372169c },
++	{ AR5K_PHY(18),	0x0018b633 },
++	{ AR5K_PHY(19),	0x1284613c },
++	{ AR5K_PHY(20),	0x0de8b8e0 },
++	{ AR5K_PHY(21),	0x00074859 },
++	{ AR5K_PHY(22),	0x7e80beba },
++	{ AR5K_PHY(23),	0x313a665e },
++	{ AR5K_PHY_AGCCTL, 0x00001d08 },
++	{ AR5K_PHY(25),	0x0001ce00 },
++	{ AR5K_PHY(26),	0x409a4190 },
++	{ AR5K_PHY(28),	0x0000000f },
++	{ AR5K_PHY(29),	0x00000080 },
++	{ AR5K_PHY(30),	0x00000004 },
++	{ AR5K_PHY(31),	0x00000018 }, 	/* 0x987c */
++	{ AR5K_PHY(64),	0x00000000 }, 	/* 0x9900 */
++	{ AR5K_PHY(65),	0x00000000 },
++	{ AR5K_PHY(66),	0x00000000 },
++	{ AR5K_PHY(67),	0x00800000 },
++	{ AR5K_PHY(68),	0x00000003 },
++	/* BB gain table (64bytes) */
++	{ AR5K_BB_GAIN(0), 0x00000000 },
++	{ AR5K_BB_GAIN(1), 0x00000020 },
++	{ AR5K_BB_GAIN(2), 0x00000010 },
++	{ AR5K_BB_GAIN(3), 0x00000030 },
++	{ AR5K_BB_GAIN(4), 0x00000008 },
++	{ AR5K_BB_GAIN(5), 0x00000028 },
++	{ AR5K_BB_GAIN(6), 0x00000028 },
++	{ AR5K_BB_GAIN(7), 0x00000004 },
++	{ AR5K_BB_GAIN(8), 0x00000024 },
++	{ AR5K_BB_GAIN(9), 0x00000014 },
++	{ AR5K_BB_GAIN(10), 0x00000034 },
++	{ AR5K_BB_GAIN(11), 0x0000000c },
++	{ AR5K_BB_GAIN(12), 0x0000002c },
++	{ AR5K_BB_GAIN(13), 0x00000002 },
++	{ AR5K_BB_GAIN(14), 0x00000022 },
++	{ AR5K_BB_GAIN(15), 0x00000012 },
++	{ AR5K_BB_GAIN(16), 0x00000032 },
++	{ AR5K_BB_GAIN(17), 0x0000000a },
++	{ AR5K_BB_GAIN(18), 0x0000002a },
++	{ AR5K_BB_GAIN(19), 0x00000001 },
++	{ AR5K_BB_GAIN(20), 0x00000021 },
++	{ AR5K_BB_GAIN(21), 0x00000011 },
++	{ AR5K_BB_GAIN(22), 0x00000031 },
++	{ AR5K_BB_GAIN(23), 0x00000009 },
++	{ AR5K_BB_GAIN(24), 0x00000029 },
++	{ AR5K_BB_GAIN(25), 0x00000005 },
++	{ AR5K_BB_GAIN(26), 0x00000025 },
++	{ AR5K_BB_GAIN(27), 0x00000015 },
++	{ AR5K_BB_GAIN(28), 0x00000035 },
++	{ AR5K_BB_GAIN(29), 0x0000000d },
++	{ AR5K_BB_GAIN(30), 0x0000002d },
++	{ AR5K_BB_GAIN(31), 0x00000003 },
++	{ AR5K_BB_GAIN(32), 0x00000023 },
++	{ AR5K_BB_GAIN(33), 0x00000013 },
++	{ AR5K_BB_GAIN(34), 0x00000033 },
++	{ AR5K_BB_GAIN(35), 0x0000000b },
++	{ AR5K_BB_GAIN(36), 0x0000002b },
++	{ AR5K_BB_GAIN(37), 0x00000007 },
++	{ AR5K_BB_GAIN(38), 0x00000027 },
++	{ AR5K_BB_GAIN(39), 0x00000017 },
++	{ AR5K_BB_GAIN(40), 0x00000037 },
++	{ AR5K_BB_GAIN(41), 0x0000000f },
++	{ AR5K_BB_GAIN(42), 0x0000002f },
++	{ AR5K_BB_GAIN(43), 0x0000002f },
++	{ AR5K_BB_GAIN(44), 0x0000002f },
++	{ AR5K_BB_GAIN(45), 0x0000002f },
++	{ AR5K_BB_GAIN(46), 0x0000002f },
++	{ AR5K_BB_GAIN(47), 0x0000002f },
++	{ AR5K_BB_GAIN(48), 0x0000002f },
++	{ AR5K_BB_GAIN(49), 0x0000002f },
++	{ AR5K_BB_GAIN(50), 0x0000002f },
++	{ AR5K_BB_GAIN(51), 0x0000002f },
++	{ AR5K_BB_GAIN(52), 0x0000002f },
++	{ AR5K_BB_GAIN(53), 0x0000002f },
++	{ AR5K_BB_GAIN(54), 0x0000002f },
++	{ AR5K_BB_GAIN(55), 0x0000002f },
++	{ AR5K_BB_GAIN(56), 0x0000002f },
++	{ AR5K_BB_GAIN(57), 0x0000002f },
++	{ AR5K_BB_GAIN(58), 0x0000002f },
++	{ AR5K_BB_GAIN(59), 0x0000002f },
++	{ AR5K_BB_GAIN(60), 0x0000002f },
++	{ AR5K_BB_GAIN(61), 0x0000002f },
++	{ AR5K_BB_GAIN(62), 0x0000002f },
++	{ AR5K_BB_GAIN(63), 0x0000002f },
++	/* 5110 RF gain table (64btes) */
++	{ AR5K_RF_GAIN(0), 0x0000001d },
++	{ AR5K_RF_GAIN(1), 0x0000005d },
++	{ AR5K_RF_GAIN(2), 0x0000009d },
++	{ AR5K_RF_GAIN(3), 0x000000dd },
++	{ AR5K_RF_GAIN(4), 0x0000011d },
++	{ AR5K_RF_GAIN(5), 0x00000021 },
++	{ AR5K_RF_GAIN(6), 0x00000061 },
++	{ AR5K_RF_GAIN(7), 0x000000a1 },
++	{ AR5K_RF_GAIN(8), 0x000000e1 },
++	{ AR5K_RF_GAIN(9), 0x00000031 },
++	{ AR5K_RF_GAIN(10), 0x00000071 },
++	{ AR5K_RF_GAIN(11), 0x000000b1 },
++	{ AR5K_RF_GAIN(12), 0x0000001c },
++	{ AR5K_RF_GAIN(13), 0x0000005c },
++	{ AR5K_RF_GAIN(14), 0x00000029 },
++	{ AR5K_RF_GAIN(15), 0x00000069 },
++	{ AR5K_RF_GAIN(16), 0x000000a9 },
++	{ AR5K_RF_GAIN(17), 0x00000020 },
++	{ AR5K_RF_GAIN(18), 0x00000019 },
++	{ AR5K_RF_GAIN(19), 0x00000059 },
++	{ AR5K_RF_GAIN(20), 0x00000099 },
++	{ AR5K_RF_GAIN(21), 0x00000030 },
++	{ AR5K_RF_GAIN(22), 0x00000005 },
++	{ AR5K_RF_GAIN(23), 0x00000025 },
++	{ AR5K_RF_GAIN(24), 0x00000065 },
++	{ AR5K_RF_GAIN(25), 0x000000a5 },
++	{ AR5K_RF_GAIN(26), 0x00000028 },
++	{ AR5K_RF_GAIN(27), 0x00000068 },
++	{ AR5K_RF_GAIN(28), 0x0000001f },
++	{ AR5K_RF_GAIN(29), 0x0000001e },
++	{ AR5K_RF_GAIN(30), 0x00000018 },
++	{ AR5K_RF_GAIN(31), 0x00000058 },
++	{ AR5K_RF_GAIN(32), 0x00000098 },
++	{ AR5K_RF_GAIN(33), 0x00000003 },
++	{ AR5K_RF_GAIN(34), 0x00000004 },
++	{ AR5K_RF_GAIN(35), 0x00000044 },
++	{ AR5K_RF_GAIN(36), 0x00000084 },
++	{ AR5K_RF_GAIN(37), 0x00000013 },
++	{ AR5K_RF_GAIN(38), 0x00000012 },
++	{ AR5K_RF_GAIN(39), 0x00000052 },
++	{ AR5K_RF_GAIN(40), 0x00000092 },
++	{ AR5K_RF_GAIN(41), 0x000000d2 },
++	{ AR5K_RF_GAIN(42), 0x0000002b },
++	{ AR5K_RF_GAIN(43), 0x0000002a },
++	{ AR5K_RF_GAIN(44), 0x0000006a },
++	{ AR5K_RF_GAIN(45), 0x000000aa },
++	{ AR5K_RF_GAIN(46), 0x0000001b },
++	{ AR5K_RF_GAIN(47), 0x0000001a },
++	{ AR5K_RF_GAIN(48), 0x0000005a },
++	{ AR5K_RF_GAIN(49), 0x0000009a },
++	{ AR5K_RF_GAIN(50), 0x000000da },
++	{ AR5K_RF_GAIN(51), 0x00000006 },
++	{ AR5K_RF_GAIN(52), 0x00000006 },
++	{ AR5K_RF_GAIN(53), 0x00000006 },
++	{ AR5K_RF_GAIN(54), 0x00000006 },
++	{ AR5K_RF_GAIN(55), 0x00000006 },
++	{ AR5K_RF_GAIN(56), 0x00000006 },
++	{ AR5K_RF_GAIN(57), 0x00000006 },
++	{ AR5K_RF_GAIN(58), 0x00000006 },
++	{ AR5K_RF_GAIN(59), 0x00000006 },
++	{ AR5K_RF_GAIN(60), 0x00000006 },
++	{ AR5K_RF_GAIN(61), 0x00000006 },
++	{ AR5K_RF_GAIN(62), 0x00000006 },
++	{ AR5K_RF_GAIN(63), 0x00000006 },
++	/* PHY activation */
++	{ AR5K_PHY(53), 0x00000020 },
++	{ AR5K_PHY(51), 0x00000004 },
++	{ AR5K_PHY(50), 0x00060106 },
++	{ AR5K_PHY(39), 0x0000006d },
++	{ AR5K_PHY(48), 0x00000000 },
++	{ AR5K_PHY(52), 0x00000014 },
++	{ AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE },
++};
++
++/* Initial register settings for AR5211 */
++static const struct ath5k_ini ar5211_ini[] = {
++	{ AR5K_RXDP,		0x00000000 },
++	{ AR5K_RTSD0,		0x84849c9c },
++	{ AR5K_RTSD1,		0x7c7c7c7c },
++	{ AR5K_RXCFG,		0x00000005 },
++	{ AR5K_MIBC,		0x00000000 },
++	{ AR5K_TOPS,		0x00000008 },
++	{ AR5K_RXNOFRM,		0x00000008 },
++	{ AR5K_TXNOFRM,		0x00000010 },
++	{ AR5K_RPGTO,		0x00000000 },
++	{ AR5K_RFCNT,		0x0000001f },
++	{ AR5K_QUEUE_TXDP(0),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(1),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(2),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(3),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(4),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(5),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(6),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(7),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(8),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(9),	0x00000000 },
++	{ AR5K_DCU_FP,		0x00000000 },
++	{ AR5K_STA_ID1,		0x00000000 },
++	{ AR5K_BSS_ID0,		0x00000000 },
++	{ AR5K_BSS_ID1,		0x00000000 },
++	{ AR5K_RSSI_THR,	0x00000000 },
++	{ AR5K_CFP_PERIOD_5211,	0x00000000 },
++	{ AR5K_TIMER0_5211,	0x00000030 },
++	{ AR5K_TIMER1_5211,	0x0007ffff },
++	{ AR5K_TIMER2_5211,	0x01ffffff },
++	{ AR5K_TIMER3_5211,	0x00000031 },
++	{ AR5K_CFP_DUR_5211,	0x00000000 },
++	{ AR5K_RX_FILTER_5211,	0x00000000 },
++	{ AR5K_MCAST_FILTER0_5211, 0x00000000 },
++	{ AR5K_MCAST_FILTER1_5211, 0x00000002 },
++	{ AR5K_DIAG_SW_5211,	0x00000000 },
++	{ AR5K_ADDAC_TEST,	0x00000000 },
++	{ AR5K_DEFAULT_ANTENNA,	0x00000000 },
++	/* PHY registers */
++	{ AR5K_PHY_AGC,	0x00000000 },
++	{ AR5K_PHY(3),	0x2d849093 },
++	{ AR5K_PHY(4),	0x7d32e000 },
++	{ AR5K_PHY(5),	0x00000f6b },
++	{ AR5K_PHY_ACT,	0x00000000 },
++	{ AR5K_PHY(11),	0x00026ffe },
++	{ AR5K_PHY(12),	0x00000000 },
++	{ AR5K_PHY(15),	0x00020100 },
++	{ AR5K_PHY(16),	0x206a017a },
++	{ AR5K_PHY(19),	0x1284613c },
++	{ AR5K_PHY(21),	0x00000859 },
++	{ AR5K_PHY(26),	0x409a4190 },	/* 0x9868 */
++	{ AR5K_PHY(27),	0x050cb081 },
++	{ AR5K_PHY(28),	0x0000000f },
++	{ AR5K_PHY(29),	0x00000080 },
++	{ AR5K_PHY(30),	0x0000000c },
++	{ AR5K_PHY(64),	0x00000000 },
++	{ AR5K_PHY(65),	0x00000000 },
++	{ AR5K_PHY(66),	0x00000000 },
++	{ AR5K_PHY(67),	0x00800000 },
++	{ AR5K_PHY(68),	0x00000001 },
++	{ AR5K_PHY(71),	0x0000092a },
++	{ AR5K_PHY_IQ,	0x00000000 },
++	{ AR5K_PHY(73),	0x00058a05 },
++	{ AR5K_PHY(74),	0x00000001 },
++	{ AR5K_PHY(75),	0x00000000 },
++	{ AR5K_PHY_PAPD_PROBE, 0x00000000 },
++	{ AR5K_PHY(77),	0x00000000 },	/* 0x9934 */
++	{ AR5K_PHY(78),	0x00000000 },	/* 0x9938 */
++	{ AR5K_PHY(79),	0x0000003f },	/* 0x993c */
++	{ AR5K_PHY(80),	0x00000004 },
++	{ AR5K_PHY(82),	0x00000000 },
++	{ AR5K_PHY(83),	0x00000000 },
++	{ AR5K_PHY(84),	0x00000000 },
++	{ AR5K_PHY_RADAR, 0x5d50f14c },
++	{ AR5K_PHY(86),	0x00000018 },
++	{ AR5K_PHY(87),	0x004b6a8e },
++	/* Initial Power table (32bytes)
++	 * common on all cards/modes.
++	 * Note: Table is rewritten during
++	 * txpower setup later using calibration
++	 * data etc. so next write is non-common
++	{ AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff },
++	{ AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff },
++	{ AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff },
++	{ AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff },
++	{ AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff },
++	{ AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff },
++	{ AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff },
++	{ AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff },
++	{ AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff },*/
++	{ AR5K_PHY_CCKTXCTL, 0x00000000 },
++	{ AR5K_PHY(642), 0x503e4646 },
++	{ AR5K_PHY_GAIN_2GHZ, 0x6480416c },
++	{ AR5K_PHY(644), 0x0199a003 },
++	{ AR5K_PHY(645), 0x044cd610 },
++	{ AR5K_PHY(646), 0x13800040 },
++	{ AR5K_PHY(647), 0x1be00060 },
++	{ AR5K_PHY(648), 0x0c53800a },
++	{ AR5K_PHY(649), 0x0014df3b },
++	{ AR5K_PHY(650), 0x000001b5 },
++	{ AR5K_PHY(651), 0x00000020 },
++};
++
++/* Initial mode-specific settings for AR5211
++ * XXX: how about g / gTurbo ? RF5111 supports it, how about AR5211 ?
++ * Maybe 5211 supports OFDM-only g but we need to test it !
++ */
++static const struct ath5k_ini_mode ar5211_ini_mode[] = {
++	{ AR5K_TXCFG,
++	/*	  a	      aTurbo	  b		*/
++		{ 0x00000015, 0x00000015, 0x0000001d } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
++	{ AR5K_DCU_GBL_IFS_SLOT,
++		{ 0x00000168, 0x000001e0, 0x000001b8 } },
++	{ AR5K_DCU_GBL_IFS_SIFS,
++		{ 0x00000230, 0x000001e0, 0x000000b0 } },
++	{ AR5K_DCU_GBL_IFS_EIFS,
++		{ 0x00000d98, 0x00001180, 0x00001f48 } },
++	{ AR5K_DCU_GBL_IFS_MISC,
++		{ 0x0000a0e0, 0x00014068, 0x00005880 } },
++	{ AR5K_TIME_OUT,
++		{ 0x04000400, 0x08000800, 0x20003000 } },
++	{ AR5K_USEC_5211,
++		{ 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95 } },
++	{ AR5K_PHY_TURBO,
++		{ 0x00000000, 0x00000003, 0x00000000 } },
++	{ AR5K_PHY(8),
++		{ 0x02020200, 0x02020200, 0x02010200 } },
++	{ AR5K_PHY(9),
++		{ 0x00000e0e, 0x00000e0e, 0x00000707 } },
++	{ AR5K_PHY(10),
++		{ 0x0a020001, 0x0a020001, 0x05010000 } },
++	{ AR5K_PHY(13),
++		{ 0x00000e0e, 0x00000e0e, 0x00000e0e } },
++	{ AR5K_PHY(14),
++		{ 0x00000007, 0x00000007, 0x0000000b } },
++	{ AR5K_PHY(17),
++		{ 0x1372169c, 0x137216a5, 0x137216a8 } },
++	{ AR5K_PHY(18),
++		{ 0x0018ba67, 0x0018ba67, 0x0018ba69 } },
++	{ AR5K_PHY(20),
++		{ 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
++	{ AR5K_PHY_SIG,
++		{ 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e } },
++	{ AR5K_PHY_AGCCOARSE,
++		{ 0x31375d5e, 0x31375d5e, 0x313a5d5e } },
++	{ AR5K_PHY_AGCCTL,
++		{ 0x0000bd10, 0x0000bd10, 0x0000bd38 } },
++	{ AR5K_PHY_NF,
++		{ 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
++	{ AR5K_PHY_RX_DELAY,
++		{ 0x00002710, 0x00002710, 0x0000157c } },
++	{ AR5K_PHY(70),
++		{ 0x00000190, 0x00000190, 0x00000084 } },
++	{ AR5K_PHY_FRAME_CTL_5211,
++		{ 0x6fe01020, 0x6fe01020, 0x6fe00920 } },
++	{ AR5K_PHY_PCDAC_TXPOWER_BASE_5211,
++		{ 0x05ff14ff, 0x05ff14ff, 0x05ff14ff } },
++	{ AR5K_RF_BUFFER_CONTROL_4,
++		{ 0x00000010, 0x00000014, 0x00000010 } },
++};
++
++/* Initial register settings for AR5212 */
++static const struct ath5k_ini ar5212_ini[] = {
++	{ AR5K_RXDP,		0x00000000 },
++	{ AR5K_RXCFG,		0x00000005 },
++	{ AR5K_MIBC,		0x00000000 },
++	{ AR5K_TOPS,		0x00000008 },
++	{ AR5K_RXNOFRM,		0x00000008 },
++	{ AR5K_TXNOFRM,		0x00000010 },
++	{ AR5K_RPGTO,		0x00000000 },
++	{ AR5K_RFCNT,		0x0000001f },
++	{ AR5K_QUEUE_TXDP(0),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(1),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(2),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(3),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(4),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(5),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(6),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(7),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(8),	0x00000000 },
++	{ AR5K_QUEUE_TXDP(9),	0x00000000 },
++	{ AR5K_DCU_FP,		0x00000000 },
++	{ AR5K_DCU_TXP,		0x00000000 },
++	{ AR5K_DCU_TX_FILTER,	0x00000000 },
++	/* Unknown table */
++	{ 0x1078, 0x00000000 },
++	{ 0x10b8, 0x00000000 },
++	{ 0x10f8, 0x00000000 },
++	{ 0x1138, 0x00000000 },
++	{ 0x1178, 0x00000000 },
++	{ 0x11b8, 0x00000000 },
++	{ 0x11f8, 0x00000000 },
++	{ 0x1238, 0x00000000 },
++	{ 0x1278, 0x00000000 },
++	{ 0x12b8, 0x00000000 },
++	{ 0x12f8, 0x00000000 },
++	{ 0x1338, 0x00000000 },
++	{ 0x1378, 0x00000000 },
++	{ 0x13b8, 0x00000000 },
++	{ 0x13f8, 0x00000000 },
++	{ 0x1438, 0x00000000 },
++	{ 0x1478, 0x00000000 },
++	{ 0x14b8, 0x00000000 },
++	{ 0x14f8, 0x00000000 },
++	{ 0x1538, 0x00000000 },
++	{ 0x1578, 0x00000000 },
++	{ 0x15b8, 0x00000000 },
++	{ 0x15f8, 0x00000000 },
++	{ 0x1638, 0x00000000 },
++	{ 0x1678, 0x00000000 },
++	{ 0x16b8, 0x00000000 },
++	{ 0x16f8, 0x00000000 },
++	{ 0x1738, 0x00000000 },
++	{ 0x1778, 0x00000000 },
++	{ 0x17b8, 0x00000000 },
++	{ 0x17f8, 0x00000000 },
++	{ 0x103c, 0x00000000 },
++	{ 0x107c, 0x00000000 },
++	{ 0x10bc, 0x00000000 },
++	{ 0x10fc, 0x00000000 },
++	{ 0x113c, 0x00000000 },
++	{ 0x117c, 0x00000000 },
++	{ 0x11bc, 0x00000000 },
++	{ 0x11fc, 0x00000000 },
++	{ 0x123c, 0x00000000 },
++	{ 0x127c, 0x00000000 },
++	{ 0x12bc, 0x00000000 },
++	{ 0x12fc, 0x00000000 },
++	{ 0x133c, 0x00000000 },
++	{ 0x137c, 0x00000000 },
++	{ 0x13bc, 0x00000000 },
++	{ 0x13fc, 0x00000000 },
++	{ 0x143c, 0x00000000 },
++	{ 0x147c, 0x00000000 },
++	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
++	{ AR5K_DCU_TX_FILTER_SET, 0x00000000 },
++	{ AR5K_STA_ID1,		0x00000000 },
++	{ AR5K_BSS_ID0,		0x00000000 },
++	{ AR5K_BSS_ID1,		0x00000000 },
++	/*{ AR5K_RSSI_THR,	0x00000000 },*/	/* Found on SuperAG cards */
++	{ AR5K_BEACON_5211,	0x00000000 },	/* Found on SuperAG cards */
++	{ AR5K_CFP_PERIOD_5211, 0x00000000 },	/* Found on SuperAG cards */
++	{ AR5K_TIMER0_5211,	0x00000030 },	/* Found on SuperAG cards */
++	{ AR5K_TIMER1_5211,	0x0007ffff },	/* Found on SuperAG cards */
++	{ AR5K_TIMER2_5211,	0x01ffffff },	/* Found on SuperAG cards */
++	{ AR5K_TIMER3_5211,	0x00000031 },	/* Found on SuperAG cards */
++	{ AR5K_CFP_DUR_5211,	0x00000000 },	/* Found on SuperAG cards */
++	{ AR5K_RX_FILTER_5211,	0x00000000 },
++	{ AR5K_DIAG_SW_5211,	0x00000000 },
++	{ AR5K_ADDAC_TEST,	0x00000000 },
++	{ AR5K_DEFAULT_ANTENNA,	0x00000000 },
++	{ 0x8080, 0x00000000 },
++	/*{ 0x805c, 0xffffc7ff },*/ /* Old value */
++	{ 0x805c, 0x000fc78f },
++	{ AR5K_NAV_5211,	0x00000000 },	/* Not found on recent */
++	{ AR5K_RTS_OK_5211,	0x00000000 },	/* dumps but it makes  */
++	{ AR5K_RTS_FAIL_5211,	0x00000000 },	/* sense to reset counters */
++	{ AR5K_ACK_FAIL_5211,	0x00000000 },	/* since pcu registers */
++	{ AR5K_FCS_FAIL_5211,	0x00000000 },	/* are skiped during chan*/
++	{ AR5K_BEACON_CNT_5211, 0x00000000 },	/* change */
++	{ AR5K_XRMODE,		0x2a82301a },
++	{ AR5K_XRDELAY,		0x05dc01e0 },
++	{ AR5K_XRTIMEOUT,	0x1f402710 },
++	{ AR5K_XRCHIRP,		0x01f40000 },
++	{ AR5K_XRSTOMP,		0x00001e1c },
++	{ AR5K_SLEEP0,		0x0002aaaa },	/* Found on SuperAG cards */
++	{ AR5K_SLEEP1,		0x02005555 },	/* Found on SuperAG cards */
++	{ AR5K_SLEEP2,		0x00000000 },	/* Found on SuperAG cards */
++	{ AR5K_BSS_IDM0,	0xffffffff },
++	{ AR5K_BSS_IDM1,	0x0000ffff },
++	{ AR5K_TXPC,		0x00000000 },
++	{ AR5K_PROFCNT_TX,	0x00000000 },
++	{ AR5K_PROFCNT_RX,	0x00000000 },
++	{ AR5K_PROFCNT_RXCLR,	0x00000000 },
++	{ AR5K_PROFCNT_CYCLE,	0x00000000 },
++	{ 0x80fc, 0x00000088 },
++	{ AR5K_RATE_DUR(0),	0x00000000 },
++	{ AR5K_RATE_DUR(1),	0x0000008c },
++	{ AR5K_RATE_DUR(2),	0x000000e4 },
++	{ AR5K_RATE_DUR(3),	0x000002d5 },
++	{ AR5K_RATE_DUR(4),	0x00000000 },
++	{ AR5K_RATE_DUR(5),	0x00000000 },
++	{ AR5K_RATE_DUR(6),	0x000000a0 },
++	{ AR5K_RATE_DUR(7),	0x000001c9 },
++	{ AR5K_RATE_DUR(8),	0x0000002c },
++	{ AR5K_RATE_DUR(9),	0x0000002c },
++	{ AR5K_RATE_DUR(10),	0x00000030 },
++	{ AR5K_RATE_DUR(11),	0x0000003c },
++	{ AR5K_RATE_DUR(12),	0x0000002c },
++	{ AR5K_RATE_DUR(13),	0x0000002c },
++	{ AR5K_RATE_DUR(14),	0x00000030 },
++	{ AR5K_RATE_DUR(15),	0x0000003c },
++	{ AR5K_RATE_DUR(16),	0x00000000 },
++	{ AR5K_RATE_DUR(17),	0x00000000 },
++	{ AR5K_RATE_DUR(18),	0x00000000 },
++	{ AR5K_RATE_DUR(19),	0x00000000 },
++	{ AR5K_RATE_DUR(20),	0x00000000 },
++	{ AR5K_RATE_DUR(21),	0x00000000 },
++	{ AR5K_RATE_DUR(22),	0x00000000 },
++	{ AR5K_RATE_DUR(23),	0x00000000 },
++	{ AR5K_RATE_DUR(24),	0x000000d5 },
++	{ AR5K_RATE_DUR(25),	0x000000df },
++	{ AR5K_RATE_DUR(26),	0x00000102 },
++	{ AR5K_RATE_DUR(27),	0x0000013a },
++	{ AR5K_RATE_DUR(28),	0x00000075 },
++	{ AR5K_RATE_DUR(29),	0x0000007f },
++	{ AR5K_RATE_DUR(30),	0x000000a2 },
++	{ AR5K_RATE_DUR(31),	0x00000000 },
++	{ 0x8100, 0x00010002},
++	{ AR5K_TSF_PARM,	0x00000001 },
++	{ 0x8108, 0x000000c0 },
++	{ AR5K_PHY_ERR_FIL,	0x00000000 },
++	{ 0x8110, 0x00000168 },
++	{ 0x8114, 0x00000000 },
++	/* Some kind of table
++	 * also notice ...03<-02<-01<-00) */
++	{ 0x87c0, 0x03020100 },
++	{ 0x87c4, 0x07060504 },
++	{ 0x87c8, 0x0b0a0908 },
++	{ 0x87cc, 0x0f0e0d0c },
++	{ 0x87d0, 0x13121110 },
++	{ 0x87d4, 0x17161514 },
++	{ 0x87d8, 0x1b1a1918 },
++	{ 0x87dc, 0x1f1e1d1c },
++	/* loop ? */
++	{ 0x87e0, 0x03020100 },
++	{ 0x87e4, 0x07060504 },
++	{ 0x87e8, 0x0b0a0908 },
++	{ 0x87ec, 0x0f0e0d0c },
++	{ 0x87f0, 0x13121110 },
++	{ 0x87f4, 0x17161514 },
++	{ 0x87f8, 0x1b1a1918 },
++	{ 0x87fc, 0x1f1e1d1c },
++	/* PHY registers */
++	/*{ AR5K_PHY_AGC, 0x00000000 },*/
++	{ AR5K_PHY(3),	0xad848e19 },
++	{ AR5K_PHY(4),	0x7d28e000 },
++	{ AR5K_PHY_TIMING_3, 0x9c0a9f6b },
++	{ AR5K_PHY_ACT,	0x00000000 },
++	/*{ AR5K_PHY(11), 0x00022ffe },*/
++	/*{ AR5K_PHY(15), 0x00020100 },*/
++	{ AR5K_PHY(16),	0x206a017a },
++	/*{ AR5K_PHY(19), 0x1284613c },*/
++	{ AR5K_PHY(21),	0x00000859 },
++	{ AR5K_PHY(64),	0x00000000 },
++	{ AR5K_PHY(65),	0x00000000 },
++	{ AR5K_PHY(66),	0x00000000 },
++	{ AR5K_PHY(67),	0x00800000 },
++	{ AR5K_PHY(68),	0x00000001 },
++	/*{ AR5K_PHY(71), 0x0000092a },*/ /* Old value */
++	{ AR5K_PHY(71),	0x00000c80 },
++	{ AR5K_PHY_IQ,	0x05100000 },
++	{ AR5K_PHY(74), 0x00000001 },
++	{ AR5K_PHY(75), 0x00000004 },
++	{ AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022 },
++	{ AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d },
++	{ AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f },
++	/*{ AR5K_PHY(80), 0x00000004 },*/
++	{ AR5K_PHY(82), 0x9280b212 },
++	{ AR5K_PHY_RADAR, 0x5d50e188 },
++	/*{ AR5K_PHY(86), 0x000000ff },*/
++	{ AR5K_PHY(87), 0x004b6a8e },
++	{ AR5K_PHY(90),	0x000003ce },
++	{ AR5K_PHY(92),	0x192fb515 },
++	/*{ AR5K_PHY(93), 0x00000000 },*/
++	{ AR5K_PHY(94),	0x00000001 },
++	{ AR5K_PHY(95),	0x00000000 },
++	/*{ AR5K_PHY(644), 0x0080a333 },*/ /* Old value */
++	/*{ AR5K_PHY(645), 0x00206c10 },*/ /* Old value */
++	{ AR5K_PHY(644), 0x00806333 },
++	{ AR5K_PHY(645), 0x00106c10 },
++	{ AR5K_PHY(646), 0x009c4060 },
++	/*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */
++	{ AR5K_PHY(647), 0x1483800a },
++	{ AR5K_PHY(648), 0x01831061 },
++	{ AR5K_PHY(649), 0x00000400 },
++	/*{ AR5K_PHY(650), 0x000001b5 },*/
++	{ AR5K_PHY(651), 0x00000000 },
++	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020 },
++	{ AR5K_PHY_TXPOWER_RATE2, 0x20202020 },
++	/*{ AR5K_PHY(655), 0x13c889af },*/
++	{ AR5K_PHY(656), 0x38490a20 },
++	{ AR5K_PHY(657), 0x00007bb6 },
++	{ AR5K_PHY(658), 0x0fff3ffc },
++	/*{ AR5K_PHY_CCKTXCTL, 0x00000000 },*/
++};
++
++/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
++static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
++	{ AR5K_PHY(640),
++	/*	  a/XR	      aTurbo	  b	      g (DYN)	  gTurbo */
++		{ 0x00000008, 0x00000008, 0x0000000b, 0x0000000e, 0x0000000e } },
++	{ AR5K_PHY(0),
++		{ 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
++		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
++	{ AR5K_DCU_GBL_IFS_SIFS,
++		{ 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
++	{ AR5K_DCU_GBL_IFS_SLOT,
++		{ 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
++	{ AR5K_DCU_GBL_IFS_EIFS,
++		{ 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
++	{ AR5K_DCU_GBL_IFS_MISC,
++		{ 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
++	{ AR5K_TIME_OUT,
++		{ 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
++	{ AR5K_PHY_TURBO,
++		{ 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
++	{ AR5K_PHY(8),
++		{ 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
++	{ AR5K_PHY(9),
++		{ 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
++	{ AR5K_PHY(17),
++		{ 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
++	{ AR5K_PHY_AGCCTL,
++		{ 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } },
++	{ AR5K_PHY_NF,
++		{ 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
++	{ AR5K_PHY(26),
++		{ 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
++	{ AR5K_PHY(70),
++		{ 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
++	{ AR5K_PHY(73),
++		{ 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
++	{ 0xa230,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
++};
++
++/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
++/* New dump pending */
++static const struct ath5k_ini_mode ar5212_rf5111_ini_mode_end[] = {
++	{ AR5K_PHY(640), /* This one differs from ar5212_ini_mode_start ! */
++	/*	  a/XR	      aTurbo	  b	      g (DYN)	  gTurbo */
++		{ 0x00000000, 0x00000000, 0x00000003, 0x00000006, 0x00000006 } },
++	{ AR5K_TXCFG,
++		{ 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
++	{ AR5K_USEC_5211,
++		{ 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
++	{ AR5K_PHY(10),
++		{ 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
++	{ AR5K_PHY(13),
++		{ 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
++	{ AR5K_PHY(14),
++		{ 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
++	{ AR5K_PHY(18),
++		{ 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
++	{ AR5K_PHY(20),
++		{ 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
++	{ AR5K_PHY_SIG,
++		{ 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
++	{ AR5K_PHY_AGCCOARSE,
++		{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
++	{ AR5K_PHY(27),
++		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
++	{ AR5K_PHY_RX_DELAY,
++		{ 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
++	{ AR5K_PHY_FRAME_CTL_5211,
++		{ 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
++	{ AR5K_PHY_GAIN_2GHZ,
++		{ 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
++	{ 0xa21c,
++		{ 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
++	{ AR5K_DCU_FP,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY_AGC,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(11),
++		{ 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } },
++	{ AR5K_PHY(15),
++		{ 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } },
++	{ AR5K_PHY(19),
++		{ 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } },
++	{ AR5K_PHY_PAPD_PROBE,
++		{ 0x00004883, 0x00004883, 0x00004883, 0x00004883, 0x00004883 } },
++	{ AR5K_PHY(80),
++		{ 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } },
++	{ AR5K_PHY(86),
++		{ 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
++	{ AR5K_PHY(93),
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY_SPENDING,
++		{ 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018 } },
++	{ AR5K_PHY_CCKTXCTL,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(642),
++		{ 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
++	{ 0xa23c,
++		{ 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } },
++};
++
++/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
++/* XXX: No dumps for turbog yet, but i found settings from old values so it should be ok */
++static const struct ath5k_ini_mode ar5212_rf5112_ini_mode_end[] = {
++	{ AR5K_TXCFG,
++	/*	  a/XR	      aTurbo	  b	      g (DYN)	  gTurbo */
++		{ 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
++	{ AR5K_USEC_5211,
++		{ 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
++	{ AR5K_PHY(10),
++		{ 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
++	{ AR5K_PHY(13),
++		{ 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
++	{ AR5K_PHY(14),
++		{ 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
++	{ AR5K_PHY(18),
++		{ 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
++	{ AR5K_PHY(20),
++		{ 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
++	{ AR5K_PHY_SIG,
++		{ 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } },
++	{ AR5K_PHY_AGCCOARSE,
++		{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
++	{ AR5K_PHY(27),
++		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
++	{ AR5K_PHY_RX_DELAY,
++		{ 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
++	{ AR5K_PHY_FRAME_CTL_5211,
++		{ 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
++	{ AR5K_PHY_CCKTXCTL,
++		{ 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
++	{ AR5K_PHY(642),
++		{ 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
++	{ AR5K_PHY_GAIN_2GHZ,
++		{ 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
++	{ 0xa21c,
++		{ 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
++	{ AR5K_DCU_FP,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY_AGC,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(11),
++		{ 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } },
++	{ AR5K_PHY(15),
++		{ 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } },
++	{ AR5K_PHY(19),
++		{ 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } },
++	{ AR5K_PHY_PAPD_PROBE,
++		{ 0x00004882, 0x00004882, 0x00004882, 0x00004882, 0x00004882 } },
++	{ AR5K_PHY(80),
++		{ 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } },
++	{ AR5K_PHY(86),
++		{ 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
++	{ AR5K_PHY(93),
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0xa228,
++		{ 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5 } },
++	{ 0xa23c,
++		{ 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } },
++};
++
++/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
++/* XXX: No dumps for turbog yet, so turbog is the same with g here with some
++ * minor tweaking based on dumps from other chips */
++static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
++	{ AR5K_TXCFG,
++	/*	  a/XR	      aTurbo	  b	      g		  gTurbo */
++		{ 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
++	{ AR5K_USEC_5211,
++		{ 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
++	{ AR5K_PHY(10),
++		{ 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
++	{ AR5K_PHY(13),
++		{ 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
++	{ AR5K_PHY(14),
++		{ 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
++	{ AR5K_PHY(18),
++		{ 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
++	{ AR5K_PHY(20),
++		{ 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
++	{ AR5K_PHY_SIG,
++		{ 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
++	{ AR5K_PHY_AGCCOARSE,
++		{ 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
++	{ AR5K_PHY(27),
++		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
++	{ AR5K_PHY_RX_DELAY,
++		{ 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
++	{ AR5K_PHY_FRAME_CTL_5211,
++		{ 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
++	{ AR5K_PHY_CCKTXCTL,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(642),
++		{ 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
++	{ AR5K_PHY_GAIN_2GHZ,
++		{ 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
++	{ 0xa21c,
++		{ 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
++	{ 0xa300,
++		{ 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
++	{ 0xa304,
++		{ 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
++	{ 0xa308,
++		{ 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
++	{ 0xa30c,
++		{ 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
++	{ 0xa310,
++		{ 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
++	{ 0xa314,
++		{ 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
++	{ 0xa318,
++		{ 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
++	{ 0xa31c,
++		{ 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
++	{ 0xa320,
++		{ 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
++	{ 0xa324,
++		{ 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
++	{ 0xa328,
++		{ 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
++	{ 0xa32c,
++		{ 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
++	{ 0xa330,
++		{ 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
++	{ 0xa334,
++		{ 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
++	{ AR5K_DCU_FP,
++		{ 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0 } },
++	{ 0x4068,
++		{ 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
++	{ 0x8060,
++		{ 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f } },
++	{ 0x809c,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x80a0,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8118,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x811c,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8120,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8124,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8128,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x812c,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8130,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8134,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8138,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x813c,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0x8140,
++		{ 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9 } },
++	{ 0x8144,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY_AGC,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(11),
++		{ 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } },
++	{ AR5K_PHY(15),
++		{ 0x00200400, 0x00200400, 0x00200400, 0x00200400, 0x00200400 } },
++	{ AR5K_PHY(19),
++		{ 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c } },
++	{ AR5K_PHY_SCR,
++		{ 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f } },
++	{ AR5K_PHY_SLMT,
++		{ 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
++	{ AR5K_PHY_SCAL,
++		{ 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
++	{ AR5K_PHY(86),
++		{ 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff } },
++	{ AR5K_PHY(96),
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(97),
++		{ 0x02800000, 0x02800000, 0x02800000, 0x02800000, 0x02800000 } },
++	{ AR5K_PHY(104),
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(120),
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ AR5K_PHY(121),
++		{ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } },
++	{ AR5K_PHY(122),
++		{ 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478 } },
++	{ AR5K_PHY(123),
++		{ 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa } },
++	{ AR5K_PHY_SCLOCK,
++		{ 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c } },
++	{ AR5K_PHY_SDELAY,
++		{ 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
++	{ AR5K_PHY_SPENDING,
++		{ 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000014 } },
++	{ 0xa228,
++		{ 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5 } },
++	{ 0xa23c,
++		{ 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af } },
++	{ 0xa24c,
++		{ 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
++	{ 0xa250,
++		{ 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } },
++	{ 0xa254,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0xa258,
++		{ 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380 } },
++	{ 0xa25c,
++		{ 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } },
++	{ 0xa260,
++		{ 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01 } },
++	{ 0xa264,
++		{ 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11 } },
++	{ 0xa268,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0xa26c,
++		{ 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } },
++	{ 0xa270,
++		{ 0x00820820, 0x00820820, 0x00820820, 0x00820820, 0x00820820 } },
++	{ 0xa274,
++		{ 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa } },
++	{ 0xa278,
++		{ 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } },
++	{ 0xa27c,
++		{ 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce } },
++	{ 0xa338,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0xa33c,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0xa340,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0xa344,
++		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
++	{ 0xa348,
++		{ 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
++	{ 0xa34c,
++		{ 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
++	{ 0xa350,
++		{ 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
++	{ 0xa354,
++		{ 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff } },
++	{ 0xa358,
++		{ 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } },
++	{ 0xa35c,
++		{ 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f } },
++	{ 0xa360,
++		{ 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207 } },
++	{ 0xa364,
++		{ 0x17601685, 0x17601685, 0x17601685, 0x17601685, 0x17601685 } },
++	{ 0xa368,
++		{ 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104 } },
++	{ 0xa36c,
++		{ 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03 } },
++	{ 0xa370,
++		{ 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883 } },
++	{ 0xa374,
++		{ 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803 } },
++	{ 0xa378,
++		{ 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682 } },
++	{ 0xa37c,
++		{ 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482 } },
++	{ 0xa380,
++		{ 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } },
++	{ 0xa384,
++		{ 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
++};
++
++/*
++ * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
++ * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
++ */
++
++/* RF5111 Initial BaseBand Gain settings */
++static const struct ath5k_ini rf5111_ini_bbgain[] = {
++	{ AR5K_BB_GAIN(0), 0x00000000 },
++	{ AR5K_BB_GAIN(1), 0x00000020 },
++	{ AR5K_BB_GAIN(2), 0x00000010 },
++	{ AR5K_BB_GAIN(3), 0x00000030 },
++	{ AR5K_BB_GAIN(4), 0x00000008 },
++	{ AR5K_BB_GAIN(5), 0x00000028 },
++	{ AR5K_BB_GAIN(6), 0x00000004 },
++	{ AR5K_BB_GAIN(7), 0x00000024 },
++	{ AR5K_BB_GAIN(8), 0x00000014 },
++	{ AR5K_BB_GAIN(9), 0x00000034 },
++	{ AR5K_BB_GAIN(10), 0x0000000c },
++	{ AR5K_BB_GAIN(11), 0x0000002c },
++	{ AR5K_BB_GAIN(12), 0x00000002 },
++	{ AR5K_BB_GAIN(13), 0x00000022 },
++	{ AR5K_BB_GAIN(14), 0x00000012 },
++	{ AR5K_BB_GAIN(15), 0x00000032 },
++	{ AR5K_BB_GAIN(16), 0x0000000a },
++	{ AR5K_BB_GAIN(17), 0x0000002a },
++	{ AR5K_BB_GAIN(18), 0x00000006 },
++	{ AR5K_BB_GAIN(19), 0x00000026 },
++	{ AR5K_BB_GAIN(20), 0x00000016 },
++	{ AR5K_BB_GAIN(21), 0x00000036 },
++	{ AR5K_BB_GAIN(22), 0x0000000e },
++	{ AR5K_BB_GAIN(23), 0x0000002e },
++	{ AR5K_BB_GAIN(24), 0x00000001 },
++	{ AR5K_BB_GAIN(25), 0x00000021 },
++	{ AR5K_BB_GAIN(26), 0x00000011 },
++	{ AR5K_BB_GAIN(27), 0x00000031 },
++	{ AR5K_BB_GAIN(28), 0x00000009 },
++	{ AR5K_BB_GAIN(29), 0x00000029 },
++	{ AR5K_BB_GAIN(30), 0x00000005 },
++	{ AR5K_BB_GAIN(31), 0x00000025 },
++	{ AR5K_BB_GAIN(32), 0x00000015 },
++	{ AR5K_BB_GAIN(33), 0x00000035 },
++	{ AR5K_BB_GAIN(34), 0x0000000d },
++	{ AR5K_BB_GAIN(35), 0x0000002d },
++	{ AR5K_BB_GAIN(36), 0x00000003 },
++	{ AR5K_BB_GAIN(37), 0x00000023 },
++	{ AR5K_BB_GAIN(38), 0x00000013 },
++	{ AR5K_BB_GAIN(39), 0x00000033 },
++	{ AR5K_BB_GAIN(40), 0x0000000b },
++	{ AR5K_BB_GAIN(41), 0x0000002b },
++	{ AR5K_BB_GAIN(42), 0x0000002b },
++	{ AR5K_BB_GAIN(43), 0x0000002b },
++	{ AR5K_BB_GAIN(44), 0x0000002b },
++	{ AR5K_BB_GAIN(45), 0x0000002b },
++	{ AR5K_BB_GAIN(46), 0x0000002b },
++	{ AR5K_BB_GAIN(47), 0x0000002b },
++	{ AR5K_BB_GAIN(48), 0x0000002b },
++	{ AR5K_BB_GAIN(49), 0x0000002b },
++	{ AR5K_BB_GAIN(50), 0x0000002b },
++	{ AR5K_BB_GAIN(51), 0x0000002b },
++	{ AR5K_BB_GAIN(52), 0x0000002b },
++	{ AR5K_BB_GAIN(53), 0x0000002b },
++	{ AR5K_BB_GAIN(54), 0x0000002b },
++	{ AR5K_BB_GAIN(55), 0x0000002b },
++	{ AR5K_BB_GAIN(56), 0x0000002b },
++	{ AR5K_BB_GAIN(57), 0x0000002b },
++	{ AR5K_BB_GAIN(58), 0x0000002b },
++	{ AR5K_BB_GAIN(59), 0x0000002b },
++	{ AR5K_BB_GAIN(60), 0x0000002b },
++	{ AR5K_BB_GAIN(61), 0x0000002b },
++	{ AR5K_BB_GAIN(62), 0x00000002 },
++	{ AR5K_BB_GAIN(63), 0x00000016 },
++};
++
++/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414) */
++static const struct ath5k_ini rf5112_ini_bbgain[] = {
++	{ AR5K_BB_GAIN(0), 0x00000000 },
++	{ AR5K_BB_GAIN(1), 0x00000001 },
++	{ AR5K_BB_GAIN(2), 0x00000002 },
++	{ AR5K_BB_GAIN(3), 0x00000003 },
++	{ AR5K_BB_GAIN(4), 0x00000004 },
++	{ AR5K_BB_GAIN(5), 0x00000005 },
++	{ AR5K_BB_GAIN(6), 0x00000008 },
++	{ AR5K_BB_GAIN(7), 0x00000009 },
++	{ AR5K_BB_GAIN(8), 0x0000000a },
++	{ AR5K_BB_GAIN(9), 0x0000000b },
++	{ AR5K_BB_GAIN(10), 0x0000000c },
++	{ AR5K_BB_GAIN(11), 0x0000000d },
++	{ AR5K_BB_GAIN(12), 0x00000010 },
++	{ AR5K_BB_GAIN(13), 0x00000011 },
++	{ AR5K_BB_GAIN(14), 0x00000012 },
++	{ AR5K_BB_GAIN(15), 0x00000013 },
++	{ AR5K_BB_GAIN(16), 0x00000014 },
++	{ AR5K_BB_GAIN(17), 0x00000015 },
++	{ AR5K_BB_GAIN(18), 0x00000018 },
++	{ AR5K_BB_GAIN(19), 0x00000019 },
++	{ AR5K_BB_GAIN(20), 0x0000001a },
++	{ AR5K_BB_GAIN(21), 0x0000001b },
++	{ AR5K_BB_GAIN(22), 0x0000001c },
++	{ AR5K_BB_GAIN(23), 0x0000001d },
++	{ AR5K_BB_GAIN(24), 0x00000020 },
++	{ AR5K_BB_GAIN(25), 0x00000021 },
++	{ AR5K_BB_GAIN(26), 0x00000022 },
++	{ AR5K_BB_GAIN(27), 0x00000023 },
++	{ AR5K_BB_GAIN(28), 0x00000024 },
++	{ AR5K_BB_GAIN(29), 0x00000025 },
++	{ AR5K_BB_GAIN(30), 0x00000028 },
++	{ AR5K_BB_GAIN(31), 0x00000029 },
++	{ AR5K_BB_GAIN(32), 0x0000002a },
++	{ AR5K_BB_GAIN(33), 0x0000002b },
++	{ AR5K_BB_GAIN(34), 0x0000002c },
++	{ AR5K_BB_GAIN(35), 0x0000002d },
++	{ AR5K_BB_GAIN(36), 0x00000030 },
++	{ AR5K_BB_GAIN(37), 0x00000031 },
++	{ AR5K_BB_GAIN(38), 0x00000032 },
++	{ AR5K_BB_GAIN(39), 0x00000033 },
++	{ AR5K_BB_GAIN(40), 0x00000034 },
++	{ AR5K_BB_GAIN(41), 0x00000035 },
++	{ AR5K_BB_GAIN(42), 0x00000035 },
++	{ AR5K_BB_GAIN(43), 0x00000035 },
++	{ AR5K_BB_GAIN(44), 0x00000035 },
++	{ AR5K_BB_GAIN(45), 0x00000035 },
++	{ AR5K_BB_GAIN(46), 0x00000035 },
++	{ AR5K_BB_GAIN(47), 0x00000035 },
++	{ AR5K_BB_GAIN(48), 0x00000035 },
++	{ AR5K_BB_GAIN(49), 0x00000035 },
++	{ AR5K_BB_GAIN(50), 0x00000035 },
++	{ AR5K_BB_GAIN(51), 0x00000035 },
++	{ AR5K_BB_GAIN(52), 0x00000035 },
++	{ AR5K_BB_GAIN(53), 0x00000035 },
++	{ AR5K_BB_GAIN(54), 0x00000035 },
++	{ AR5K_BB_GAIN(55), 0x00000035 },
++	{ AR5K_BB_GAIN(56), 0x00000035 },
++	{ AR5K_BB_GAIN(57), 0x00000035 },
++	{ AR5K_BB_GAIN(58), 0x00000035 },
++	{ AR5K_BB_GAIN(59), 0x00000035 },
++	{ AR5K_BB_GAIN(60), 0x00000035 },
++	{ AR5K_BB_GAIN(61), 0x00000035 },
++	{ AR5K_BB_GAIN(62), 0x00000010 },
++	{ AR5K_BB_GAIN(63), 0x0000001a },
++};
++
++
++/*
++ * Write initial register dump
++ */
++static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
++		const struct ath5k_ini *ini_regs, bool change_channel)
++{
++	unsigned int i;
++
++	/* Write initial registers */
++	for (i = 0; i < size; i++) {
++		/* On channel change there is
++		 * no need to mess with PCU */
++		if (change_channel &&
++				ini_regs[i].ini_register >= AR5K_PCU_MIN &&
++				ini_regs[i].ini_register <= AR5K_PCU_MAX)
++			continue;
++
++		switch (ini_regs[i].ini_mode) {
++		case AR5K_INI_READ:
++			/* Cleared on read */
++			ath5k_hw_reg_read(ah, ini_regs[i].ini_register);
++			break;
++		case AR5K_INI_WRITE:
++		default:
++			AR5K_REG_WAIT(i);
++			ath5k_hw_reg_write(ah, ini_regs[i].ini_value,
++					ini_regs[i].ini_register);
++		}
++	}
++}
++
++static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
++		unsigned int size, const struct ath5k_ini_mode *ini_mode,
++		u8 mode)
++{
++	unsigned int i;
++
++	for (i = 0; i < size; i++) {
++		AR5K_REG_WAIT(i);
++		ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode],
++			(u32)ini_mode[i].mode_register);
++	}
++
++}
++
++int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
++{
++	/*
++	 * Write initial register settings
++	 */
++
++	/* For AR5212 and combatible */
++	if (ah->ah_version == AR5K_AR5212){
++
++		/* First set of mode-specific settings */
++		ath5k_hw_ini_mode_registers(ah,
++			ARRAY_SIZE(ar5212_ini_mode_start),
++			ar5212_ini_mode_start, mode);
++
++		/*
++		 * Write initial settings common for all modes
++		 */
++		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini),
++					ar5212_ini, change_channel);
++
++		/* Second set of mode-specific settings */
++		if (ah->ah_radio == AR5K_RF5111){
++			ath5k_hw_ini_mode_registers(ah,
++					ARRAY_SIZE(ar5212_rf5111_ini_mode_end),
++					ar5212_rf5111_ini_mode_end, mode);
++			/* Baseband gain table */
++			ath5k_hw_ini_registers(ah,
++					ARRAY_SIZE(rf5111_ini_bbgain),
++					rf5111_ini_bbgain, change_channel);
++		} else if (ah->ah_radio == AR5K_RF5112){
++			ath5k_hw_ini_mode_registers(ah,
++					ARRAY_SIZE(ar5212_rf5112_ini_mode_end),
++					ar5212_rf5112_ini_mode_end, mode);
++			/* Baseband gain table */
++			ath5k_hw_ini_registers(ah,
++					ARRAY_SIZE(rf5112_ini_bbgain),
++					rf5112_ini_bbgain, change_channel);
++		} else if (ah->ah_radio == AR5K_RF5413){
++			ath5k_hw_ini_mode_registers(ah,
++					ARRAY_SIZE(rf5413_ini_mode_end),
++					rf5413_ini_mode_end, mode);
++			/* Baseband gain table */
++			ath5k_hw_ini_registers(ah,
++					ARRAY_SIZE(rf5112_ini_bbgain),
++					rf5112_ini_bbgain, change_channel);
++		}
++	/* For AR5211 */
++	} else if (ah->ah_version == AR5K_AR5211) {
++
++		if(mode > 2){ /* AR5K_INI_VAL_11B */
++			ATH5K_ERR(ah->ah_sc,"unsupported channel mode: %d\n", mode);
++			return -EINVAL;
++		}
++
++		/* Mode-specific settings */
++		ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode),
++				ar5211_ini_mode, mode);
++
++		/*
++		 * Write initial settings common for all modes
++		 */
++		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
++				ar5211_ini, change_channel);
++
++		/* AR5211 only comes with 5111 */
++
++		/* Baseband gain table */
++		ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
++				rf5111_ini_bbgain, change_channel);
++	/* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
++	} else if (ah->ah_version == AR5K_AR5210) {
++		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
++				ar5210_ini, change_channel);
++	}
++
++	return 0;
++}
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.c
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.c	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,2822 @@
++/*-
++ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
++ * Copyright (c) 2004-2005 Atheros Communications, Inc.
++ * Copyright (c) 2006 Devicescape Software, Inc.
++ * Copyright (c) 2007 Jiri Slaby <jirislaby at gmail.com>
++ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
++ *
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer,
++ *    without modification.
++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
++ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
++ *    redistribution must be conditioned upon including a substantially
++ *    similar Disclaimer requirement for further binary redistribution.
++ * 3. Neither the names of the above-listed copyright holders nor the names
++ *    of any contributors may be used to endorse or promote products derived
++ *    from this software without specific prior written permission.
++ *
++ * Alternatively, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2 as published by the Free
++ * Software Foundation.
++ *
++ * NO WARRANTY
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
++ * THE POSSIBILITY OF SUCH DAMAGES.
++ *
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/if.h>
++#include <linux/netdevice.h>
++#include <linux/cache.h>
++#include <linux/pci.h>
++#include <linux/ethtool.h>
++#include <linux/uaccess.h>
++
++#include <net/ieee80211_radiotap.h>
++
++#include <asm/unaligned.h>
++
++#include "base.h"
++#include "reg.h"
++#include "debug.h"
++
++/* unaligned little endian access */
++#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p))))
++#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p))))
++
++enum {
++	ATH_LED_TX,
++	ATH_LED_RX,
++};
++
++static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
++
++
++/******************\
++* Internal defines *
++\******************/
++
++/* Module info */
++MODULE_AUTHOR("Jiri Slaby");
++MODULE_AUTHOR("Nick Kossifidis");
++MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
++MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_VERSION("0.1.1 (EXPERIMENTAL)");
++
++
++/* Known PCI ids */
++static struct pci_device_id ath5k_pci_id_table[] __devinitdata = {
++	{ PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
++	{ PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
++	{ PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
++	{ PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */
++	{ PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */
++	{ PCI_VDEVICE(3COM_2,  0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */
++	{ PCI_VDEVICE(3COM,    0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */
++	{ PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */
++	{ PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
++	{ PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
++	{ PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
++	{ PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
++	{ PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
++	{ PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
++	{ PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
++	{ PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
++	{ PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/
++	{ PCI_VDEVICE(ATHEROS, 0x0023), .driver_data = AR5K_AR5212 }, /* 5416 */
++	{ PCI_VDEVICE(ATHEROS, 0x0024), .driver_data = AR5K_AR5212 }, /* 5418 */
++	{ 0 }
++};
++MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
++
++/* Known SREVs */
++static struct ath5k_srev_name srev_names[] = {
++	{ "5210",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5210 },
++	{ "5311",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311 },
++	{ "5311A",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311A },
++	{ "5311B",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311B },
++	{ "5211",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5211 },
++	{ "5212",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5212 },
++	{ "5213",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5213 },
++	{ "5213A",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5213A },
++	{ "2424",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR2424 },
++	{ "5424",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5424 },
++	{ "5413",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5413 },
++	{ "5414",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5414 },
++	{ "5416",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5416 },
++	{ "5418",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5418 },
++	{ "xxxxx",	AR5K_VERSION_VER,	AR5K_SREV_UNKNOWN },
++	{ "5110",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5110 },
++	{ "5111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111 },
++	{ "2111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2111 },
++	{ "5112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112 },
++	{ "5112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112A },
++	{ "2112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112 },
++	{ "2112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112A },
++	{ "SChip",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_SC1 },
++	{ "SChip",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_SC2 },
++	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
++	{ "xxxxx",	AR5K_VERSION_RAD,	AR5K_SREV_UNKNOWN },
++};
++
++/*
++ * Prototypes - PCI stack related functions
++ */
++static int __devinit	ath5k_pci_probe(struct pci_dev *pdev,
++				const struct pci_device_id *id);
++static void __devexit	ath5k_pci_remove(struct pci_dev *pdev);
++#ifdef CONFIG_PM
++static int		ath5k_pci_suspend(struct pci_dev *pdev,
++					pm_message_t state);
++static int		ath5k_pci_resume(struct pci_dev *pdev);
++#else
++#define ath5k_pci_suspend NULL
++#define ath5k_pci_resume NULL
++#endif /* CONFIG_PM */
++
++static struct pci_driver ath5k_pci_drv_id = {
++	.name		= "ath5k_pci",
++	.id_table	= ath5k_pci_id_table,
++	.probe		= ath5k_pci_probe,
++	.remove		= __devexit_p(ath5k_pci_remove),
++	.suspend	= ath5k_pci_suspend,
++	.resume		= ath5k_pci_resume,
++};
++
++
++
++/*
++ * Prototypes - MAC 802.11 stack related functions
++ */
++static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
++		struct ieee80211_tx_control *ctl);
++static int ath5k_reset(struct ieee80211_hw *hw);
++static int ath5k_start(struct ieee80211_hw *hw);
++static void ath5k_stop(struct ieee80211_hw *hw);
++static int ath5k_add_interface(struct ieee80211_hw *hw,
++		struct ieee80211_if_init_conf *conf);
++static void ath5k_remove_interface(struct ieee80211_hw *hw,
++		struct ieee80211_if_init_conf *conf);
++static int ath5k_config(struct ieee80211_hw *hw,
++		struct ieee80211_conf *conf);
++static int ath5k_config_interface(struct ieee80211_hw *hw, int if_id,
++		struct ieee80211_if_conf *conf);
++static void ath5k_configure_filter(struct ieee80211_hw *hw,
++		unsigned int changed_flags,
++		unsigned int *new_flags,
++		int mc_count, struct dev_mc_list *mclist);
++static int ath5k_set_key(struct ieee80211_hw *hw,
++		enum set_key_cmd cmd,
++		const u8 *local_addr, const u8 *addr,
++		struct ieee80211_key_conf *key);
++static int ath5k_get_stats(struct ieee80211_hw *hw,
++		struct ieee80211_low_level_stats *stats);
++static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
++		struct ieee80211_tx_queue_stats *stats);
++static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
++static void ath5k_reset_tsf(struct ieee80211_hw *hw);
++static int ath5k_beacon_update(struct ieee80211_hw *hw,
++		struct sk_buff *skb,
++		struct ieee80211_tx_control *ctl);
++
++static struct ieee80211_ops ath5k_hw_ops = {
++	.tx 		= ath5k_tx,
++	.start 		= ath5k_start,
++	.stop 		= ath5k_stop,
++	.add_interface 	= ath5k_add_interface,
++	.remove_interface = ath5k_remove_interface,
++	.config 	= ath5k_config,
++	.config_interface = ath5k_config_interface,
++	.configure_filter = ath5k_configure_filter,
++	.set_key 	= ath5k_set_key,
++	.get_stats 	= ath5k_get_stats,
++	.conf_tx 	= NULL,
++	.get_tx_stats 	= ath5k_get_tx_stats,
++	.get_tsf 	= ath5k_get_tsf,
++	.reset_tsf 	= ath5k_reset_tsf,
++	.beacon_update 	= ath5k_beacon_update,
++};
++
++/*
++ * Prototypes - Internal functions
++ */
++/* Attach detach */
++static int 	ath5k_attach(struct pci_dev *pdev,
++			struct ieee80211_hw *hw);
++static void 	ath5k_detach(struct pci_dev *pdev,
++			struct ieee80211_hw *hw);
++/* Channel/mode setup */
++static inline short ath5k_ieee2mhz(short chan);
++static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates,
++				const struct ath5k_rate_table *rt,
++				unsigned int max);
++static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
++				struct ieee80211_channel *channels,
++				unsigned int mode,
++				unsigned int max);
++static int 	ath5k_getchannels(struct ieee80211_hw *hw);
++static int 	ath5k_chan_set(struct ath5k_softc *sc,
++				struct ieee80211_channel *chan);
++static void	ath5k_setcurmode(struct ath5k_softc *sc,
++				unsigned int mode);
++static void	ath5k_mode_setup(struct ath5k_softc *sc);
++/* Descriptor setup */
++static int	ath5k_desc_alloc(struct ath5k_softc *sc,
++				struct pci_dev *pdev);
++static void	ath5k_desc_free(struct ath5k_softc *sc,
++				struct pci_dev *pdev);
++/* Buffers setup */
++static int 	ath5k_rxbuf_setup(struct ath5k_softc *sc,
++				struct ath5k_buf *bf);
++static int 	ath5k_txbuf_setup(struct ath5k_softc *sc,
++				struct ath5k_buf *bf,
++				struct ieee80211_tx_control *ctl);
++
++static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
++				struct ath5k_buf *bf)
++{
++	BUG_ON(!bf);
++	if (!bf->skb)
++		return;
++	pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len,
++			PCI_DMA_TODEVICE);
++	dev_kfree_skb(bf->skb);
++	bf->skb = NULL;
++}
++
++/* Queues setup */
++static struct 	ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc,
++				int qtype, int subtype);
++static int 	ath5k_beaconq_setup(struct ath5k_hw *ah);
++static int 	ath5k_beaconq_config(struct ath5k_softc *sc);
++static void 	ath5k_txq_drainq(struct ath5k_softc *sc,
++				struct ath5k_txq *txq);
++static void 	ath5k_txq_cleanup(struct ath5k_softc *sc);
++static void 	ath5k_txq_release(struct ath5k_softc *sc);
++/* Rx handling */
++static int 	ath5k_rx_start(struct ath5k_softc *sc);
++static void 	ath5k_rx_stop(struct ath5k_softc *sc);
++static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc,
++					struct ath5k_desc *ds,
++					struct sk_buff *skb);
++static void 	ath5k_tasklet_rx(unsigned long data);
++/* Tx handling */
++static void 	ath5k_tx_processq(struct ath5k_softc *sc,
++				struct ath5k_txq *txq);
++static void 	ath5k_tasklet_tx(unsigned long data);
++/* Beacon handling */
++static int 	ath5k_beacon_setup(struct ath5k_softc *sc,
++				struct ath5k_buf *bf,
++				struct ieee80211_tx_control *ctl);
++static void 	ath5k_beacon_send(struct ath5k_softc *sc);
++static void 	ath5k_beacon_config(struct ath5k_softc *sc);
++
++static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
++{
++	u64 tsf = ath5k_hw_get_tsf64(ah);
++
++	if ((tsf & 0x7fff) < rstamp)
++		tsf -= 0x8000;
++
++	return (tsf & ~0x7fff) | rstamp;
++}
++
++/* Interrupt handling */
++static int 	ath5k_init(struct ath5k_softc *sc);
++static int 	ath5k_stop_locked(struct ath5k_softc *sc);
++static int 	ath5k_stop_hw(struct ath5k_softc *sc);
++static irqreturn_t ath5k_intr(int irq, void *dev_id);
++static void 	ath5k_tasklet_reset(unsigned long data);
++
++static void 	ath5k_calibrate(unsigned long data);
++/* LED functions */
++static void 	ath5k_led_off(unsigned long data);
++static void 	ath5k_led_blink(struct ath5k_softc *sc,
++				unsigned int on,
++				unsigned int off);
++static void 	ath5k_led_event(struct ath5k_softc *sc,
++				int event);
++
++
++/*
++ * Module init/exit functions
++ */
++static int __init
++init_ath5k_pci(void)
++{
++	int ret;
++
++	ath5k_debug_init();
++
++	ret = pci_register_driver(&ath5k_pci_drv_id);
++	if (ret) {
++		printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static void __exit
++exit_ath5k_pci(void)
++{
++	pci_unregister_driver(&ath5k_pci_drv_id);
++
++	ath5k_debug_finish();
++}
++
++module_init(init_ath5k_pci);
++module_exit(exit_ath5k_pci);
++
++
++/********************\
++* PCI Initialization *
++\********************/
++
++static const char *
++ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
++{
++	const char *name = "xxxxx";
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(srev_names); i++) {
++		if (srev_names[i].sr_type != type)
++			continue;
++		if ((val & 0xff) < srev_names[i + 1].sr_val) {
++			name = srev_names[i].sr_name;
++			break;
++		}
++	}
++
++	return name;
++}
++
++static int __devinit
++ath5k_pci_probe(struct pci_dev *pdev,
++		const struct pci_device_id *id)
++{
++	void __iomem *mem;
++	struct ath5k_softc *sc;
++	struct ieee80211_hw *hw;
++	int ret;
++	u8 csz;
++
++	ret = pci_enable_device(pdev);
++	if (ret) {
++		dev_err(&pdev->dev, "can't enable device\n");
++		goto err;
++	}
++
++	/* XXX 32-bit addressing only */
++	ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++	if (ret) {
++		dev_err(&pdev->dev, "32-bit DMA not available\n");
++		goto err_dis;
++	}
++
++	/*
++	 * Cache line size is used to size and align various
++	 * structures used to communicate with the hardware.
++	 */
++	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
++	if (csz == 0) {
++		/*
++		 * Linux 2.4.18 (at least) writes the cache line size
++		 * register as a 16-bit wide register which is wrong.
++		 * We must have this setup properly for rx buffer
++		 * DMA to work so force a reasonable value here if it
++		 * comes up zero.
++		 */
++		csz = L1_CACHE_BYTES / sizeof(u32);
++		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
++	}
++	/*
++	 * The default setting of latency timer yields poor results,
++	 * set it to the value used by other systems.  It may be worth
++	 * tweaking this setting more.
++	 */
++	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
++
++	/* Enable bus mastering */
++	pci_set_master(pdev);
++
++	/*
++	 * Disable the RETRY_TIMEOUT register (0x41) to keep
++	 * PCI Tx retries from interfering with C3 CPU state.
++	 */
++	pci_write_config_byte(pdev, 0x41, 0);
++
++	ret = pci_request_region(pdev, 0, "ath5k");
++	if (ret) {
++		dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
++		goto err_dis;
++	}
++
++	mem = pci_iomap(pdev, 0, 0);
++	if (!mem) {
++		dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
++		ret = -EIO;
++		goto err_reg;
++	}
++
++	/*
++	 * Allocate hw (mac80211 main struct)
++	 * and hw->priv (driver private data)
++	 */
++	hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
++	if (hw == NULL) {
++		dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
++		ret = -ENOMEM;
++		goto err_map;
++	}
++
++	dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
++
++	/* Initialize driver private data */
++	SET_IEEE80211_DEV(hw, &pdev->dev);
++	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS;
++	hw->extra_tx_headroom = 2;
++	hw->channel_change_time = 5000;
++	/* these names are misleading */
++	hw->max_rssi = -110; /* signal in dBm */
++	hw->max_noise = -110; /* noise in dBm */
++	hw->max_signal = 100; /* we will provide a percentage based on rssi */
++	sc = hw->priv;
++	sc->hw = hw;
++	sc->pdev = pdev;
++
++	ath5k_debug_init_device(sc);
++
++	/*
++	 * Mark the device as detached to avoid processing
++	 * interrupts until setup is complete.
++	 */
++	__set_bit(ATH_STAT_INVALID, sc->status);
++
++	sc->iobase = mem; /* So we can unmap it on detach */
++	sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
++	sc->opmode = IEEE80211_IF_TYPE_STA;
++	mutex_init(&sc->lock);
++	spin_lock_init(&sc->rxbuflock);
++	spin_lock_init(&sc->txbuflock);
++
++	/* Set private data */
++	pci_set_drvdata(pdev, hw);
++
++	/* Enable msi for devices that support it */
++	pci_enable_msi(pdev);
++
++	/* Setup interrupt handler */
++	ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
++	if (ret) {
++		ATH5K_ERR(sc, "request_irq failed\n");
++		goto err_free;
++	}
++
++	/* Initialize device */
++	sc->ah = ath5k_hw_attach(sc, id->driver_data);
++	if (IS_ERR(sc->ah)) {
++		ret = PTR_ERR(sc->ah);
++		goto err_irq;
++	}
++
++	/* Finish private driver data initialization */
++	ret = ath5k_attach(pdev, hw);
++	if (ret)
++		goto err_ah;
++
++	ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
++			ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev),
++					sc->ah->ah_mac_srev,
++					sc->ah->ah_phy_revision);
++
++	if(!sc->ah->ah_single_chip){
++		/* Single chip radio (!RF5111) */
++		if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) {
++			/* No 5GHz support -> report 2GHz radio */
++			if(!test_bit(MODE_IEEE80211A, sc->ah->ah_capabilities.cap_mode)){
++				ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
++					ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
++							sc->ah->ah_radio_5ghz_revision);
++			/* No 2GHz support (5110 and some 5Ghz only cards) -> report 5Ghz radio */
++			} else if(!test_bit(MODE_IEEE80211B, sc->ah->ah_capabilities.cap_mode)){
++				ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
++					ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
++							sc->ah->ah_radio_5ghz_revision);
++			/* Multiband radio */
++			} else {
++				ATH5K_INFO(sc, "RF%s multiband radio found"
++					" (0x%x)\n",
++					ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
++							sc->ah->ah_radio_5ghz_revision);
++			}
++		}
++		/* Multi chip radio (RF5111 - RF2111) -> report both 2GHz/5GHz radios */
++		else if(sc->ah->ah_radio_5ghz_revision && sc->ah->ah_radio_2ghz_revision){
++			ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
++				ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
++						sc->ah->ah_radio_5ghz_revision);
++			ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
++				ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_2ghz_revision),
++						sc->ah->ah_radio_2ghz_revision);
++		}
++	}
++
++
++	/* ready to process interrupts */
++	__clear_bit(ATH_STAT_INVALID, sc->status);
++
++	return 0;
++err_ah:
++	ath5k_hw_detach(sc->ah);
++err_irq:
++	free_irq(pdev->irq, sc);
++err_free:
++	pci_disable_msi(pdev);
++	ieee80211_free_hw(hw);
++err_map:
++	pci_iounmap(pdev, mem);
++err_reg:
++	pci_release_region(pdev, 0);
++err_dis:
++	pci_disable_device(pdev);
++err:
++	return ret;
++}
++
++static void __devexit
++ath5k_pci_remove(struct pci_dev *pdev)
++{
++	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
++	struct ath5k_softc *sc = hw->priv;
++
++	ath5k_debug_finish_device(sc);
++	ath5k_detach(pdev, hw);
++	ath5k_hw_detach(sc->ah);
++	free_irq(pdev->irq, sc);
++	pci_disable_msi(pdev);
++	pci_iounmap(pdev, sc->iobase);
++	pci_release_region(pdev, 0);
++	pci_disable_device(pdev);
++	ieee80211_free_hw(hw);
++}
++
++#ifdef CONFIG_PM
++static int
++ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
++{
++	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
++	struct ath5k_softc *sc = hw->priv;
++
++	if (test_bit(ATH_STAT_LEDSOFT, sc->status))
++		ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1);
++
++	ath5k_stop_hw(sc);
++	pci_save_state(pdev);
++	pci_disable_device(pdev);
++	pci_set_power_state(pdev, PCI_D3hot);
++
++	return 0;
++}
++
++static int
++ath5k_pci_resume(struct pci_dev *pdev)
++{
++	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
++	struct ath5k_softc *sc = hw->priv;
++	int err;
++
++	err = pci_set_power_state(pdev, PCI_D0);
++	if (err)
++		return err;
++
++	err = pci_enable_device(pdev);
++	if (err)
++		return err;
++
++	pci_restore_state(pdev);
++	/*
++	 * Suspend/Resume resets the PCI configuration space, so we have to
++	 * re-disable the RETRY_TIMEOUT register (0x41) to keep
++	 * PCI Tx retries from interfering with C3 CPU state
++	 */
++	pci_write_config_byte(pdev, 0x41, 0);
++
++	ath5k_init(sc);
++	if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
++		ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
++		ath5k_hw_set_gpio(sc->ah, sc->led_pin, 0);
++	}
++
++	return 0;
++}
++#endif /* CONFIG_PM */
++
++
++
++/***********************\
++* Driver Initialization *
++\***********************/
++
++static int
++ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
++{
++	struct ath5k_softc *sc = hw->priv;
++	struct ath5k_hw *ah = sc->ah;
++	u8 mac[ETH_ALEN];
++	unsigned int i;
++	int ret;
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
++
++	/*
++	 * Check if the MAC has multi-rate retry support.
++	 * We do this by trying to setup a fake extended
++	 * descriptor.  MAC's that don't have support will
++	 * return false w/o doing anything.  MAC's that do
++	 * support it will return true w/o doing anything.
++	 */
++	if (ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0))
++		__set_bit(ATH_STAT_MRRETRY, sc->status);
++
++	/*
++	 * Reset the key cache since some parts do not
++	 * reset the contents on initial power up.
++	 */
++	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
++		ath5k_hw_reset_key(ah, i);
++
++	/*
++	 * Collect the channel list.  The 802.11 layer
++	 * is resposible for filtering this list based
++	 * on settings like the phy mode and regulatory
++	 * domain restrictions.
++	 */
++	ret = ath5k_getchannels(hw);
++	if (ret) {
++		ATH5K_ERR(sc, "can't get channels\n");
++		goto err;
++	}
++
++	/* NB: setup here so ath5k_rate_update is happy */
++	if (test_bit(MODE_IEEE80211A, ah->ah_modes))
++		ath5k_setcurmode(sc, MODE_IEEE80211A);
++	else
++		ath5k_setcurmode(sc, MODE_IEEE80211B);
++
++	/*
++	 * Allocate tx+rx descriptors and populate the lists.
++	 */
++	ret = ath5k_desc_alloc(sc, pdev);
++	if (ret) {
++		ATH5K_ERR(sc, "can't allocate descriptors\n");
++		goto err;
++	}
++
++	/*
++	 * Allocate hardware transmit queues: one queue for
++	 * beacon frames and one data queue for each QoS
++	 * priority.  Note that hw functions handle reseting
++	 * these queues at the needed time.
++	 */
++	ret = ath5k_beaconq_setup(ah);
++	if (ret < 0) {
++		ATH5K_ERR(sc, "can't setup a beacon xmit queue\n");
++		goto err_desc;
++	}
++	sc->bhalq = ret;
++
++	sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
++	if (IS_ERR(sc->txq)) {
++		ATH5K_ERR(sc, "can't setup xmit queue\n");
++		ret = PTR_ERR(sc->txq);
++		goto err_bhal;
++	}
++
++	tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
++	tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
++	tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
++	setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
++	setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc);
++
++	sc->led_on = 0; /* low true */
++	/*
++	 * Auto-enable soft led processing for IBM cards and for
++	 * 5211 minipci cards.
++	 */
++	if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
++			pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
++		__set_bit(ATH_STAT_LEDSOFT, sc->status);
++		sc->led_pin = 0;
++	}
++	/* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
++	if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
++		__set_bit(ATH_STAT_LEDSOFT, sc->status);
++		sc->led_pin = 0;
++	}
++	if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
++		ath5k_hw_set_gpio_output(ah, sc->led_pin);
++		ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
++	}
++
++	ath5k_hw_get_lladdr(ah, mac);
++	SET_IEEE80211_PERM_ADDR(hw, mac);
++	/* All MAC address bits matter for ACKs */
++	memset(sc->bssidmask, 0xff, ETH_ALEN);
++	ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
++
++	ret = ieee80211_register_hw(hw);
++	if (ret) {
++		ATH5K_ERR(sc, "can't register ieee80211 hw\n");
++		goto err_queues;
++	}
++
++	return 0;
++err_queues:
++	ath5k_txq_release(sc);
++err_bhal:
++	ath5k_hw_release_tx_queue(ah, sc->bhalq);
++err_desc:
++	ath5k_desc_free(sc, pdev);
++err:
++	return ret;
++}
++
++static void
++ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
++{
++	struct ath5k_softc *sc = hw->priv;
++
++	/*
++	 * NB: the order of these is important:
++	 * o call the 802.11 layer before detaching ath5k_hw to
++	 *   insure callbacks into the driver to delete global
++	 *   key cache entries can be handled
++	 * o reclaim the tx queue data structures after calling
++	 *   the 802.11 layer as we'll get called back to reclaim
++	 *   node state and potentially want to use them
++	 * o to cleanup the tx queues the hal is called, so detach
++	 *   it last
++	 * XXX: ??? detach ath5k_hw ???
++	 * Other than that, it's straightforward...
++	 */
++	ieee80211_unregister_hw(hw);
++	ath5k_desc_free(sc, pdev);
++	ath5k_txq_release(sc);
++	ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
++
++	/*
++	 * NB: can't reclaim these until after ieee80211_ifdetach
++	 * returns because we'll get called back to reclaim node
++	 * state and potentially want to use them.
++	 */
++}
++
++
++
++
++/********************\
++* Channel/mode setup *
++\********************/
++
++/*
++ * Convert IEEE channel number to MHz frequency.
++ */
++static inline short
++ath5k_ieee2mhz(short chan)
++{
++	if (chan <= 14 || chan >= 27)
++		return ieee80211chan2mhz(chan);
++	else
++		return 2212 + chan * 20;
++}
++
++static unsigned int
++ath5k_copy_rates(struct ieee80211_rate *rates,
++		const struct ath5k_rate_table *rt,
++		unsigned int max)
++{
++	unsigned int i, count;
++
++	if (rt == NULL)
++		return 0;
++
++	for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) {
++		if (!rt->rates[i].valid)
++			continue;
++		rates->rate = rt->rates[i].rate_kbps / 100;
++		rates->val = rt->rates[i].rate_code;
++		rates->flags = rt->rates[i].modulation;
++		rates++;
++		count++;
++		max--;
++	}
++
++	return count;
++}
++
++static unsigned int
++ath5k_copy_channels(struct ath5k_hw *ah,
++		struct ieee80211_channel *channels,
++		unsigned int mode,
++		unsigned int max)
++{
++	static const struct { unsigned int mode, mask, chan; } map[] = {
++		[MODE_IEEE80211A] = { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A },
++		[MODE_ATHEROS_TURBO] = { CHANNEL_OFDM|CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T },
++		[MODE_IEEE80211B] = { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B },
++		[MODE_IEEE80211G] = { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G },
++		[MODE_ATHEROS_TURBOG] = { CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG },
++	};
++	static const struct ath5k_regchannel chans_2ghz[] =
++		IEEE80211_CHANNELS_2GHZ;
++	static const struct ath5k_regchannel chans_5ghz[] =
++		IEEE80211_CHANNELS_5GHZ;
++	const struct ath5k_regchannel *chans;
++	enum ath5k_regdom dmn;
++	unsigned int i, count, size, chfreq, all, f, ch;
++
++	if (!test_bit(mode, ah->ah_modes))
++		return 0;
++
++	all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1;
++
++	switch (mode) {
++	case MODE_IEEE80211A:
++	case MODE_ATHEROS_TURBO:
++		/* 1..220, but 2GHz frequencies are filtered by check_channel */
++		size = all ? 220 : ARRAY_SIZE(chans_5ghz);
++		chans = chans_5ghz;
++		dmn = ath5k_regdom2flag(ah->ah_regdomain,
++				IEEE80211_CHANNELS_5GHZ_MIN);
++		chfreq = CHANNEL_5GHZ;
++		break;
++	case MODE_IEEE80211B:
++	case MODE_IEEE80211G:
++	case MODE_ATHEROS_TURBOG:
++		size = all ? 26 : ARRAY_SIZE(chans_2ghz);
++		chans = chans_2ghz;
++		dmn = ath5k_regdom2flag(ah->ah_regdomain,
++				IEEE80211_CHANNELS_2GHZ_MIN);
++		chfreq = CHANNEL_2GHZ;
++		break;
++	default:
++		ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n");
++		return 0;
++	}
++
++	for (i = 0, count = 0; i < size && max > 0; i++) {
++		ch = all ? i + 1 : chans[i].chan;
++		f = ath5k_ieee2mhz(ch);
++		/* Check if channel is supported by the chipset */
++		if (!ath5k_channel_ok(ah, f, chfreq))
++			continue;
++
++		/* Match regulation domain */
++		if (!all && !(IEEE80211_DMN(chans[i].domain) &
++							IEEE80211_DMN(dmn)))
++			continue;
++
++		if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode)
++			continue;
++
++		/* Write channel and increment counter */
++		channels->chan = ch;
++		channels->freq = f;
++		channels->val = map[mode].chan;
++		channels++;
++		count++;
++		max--;
++	}
++
++	return count;
++}
++
++/* Only tries to register modes our EEPROM says it can support */
++#define REGISTER_MODE(m) do { \
++	ret = ath5k_register_mode(hw, m); \
++	if (ret) \
++		return ret; \
++} while (0) \
++
++static inline int
++ath5k_register_mode(struct ieee80211_hw *hw, u8 m)
++{
++	struct ath5k_softc *sc = hw->priv;
++	struct ieee80211_hw_mode *modes = sc->modes;
++	unsigned int i;
++	int ret;
++
++	if (!test_bit(m, sc->ah->ah_capabilities.cap_mode))
++		return 0;
++
++	for (i = 0; i < NUM_DRIVER_MODES; i++) {
++		if (modes[i].mode != m || !modes[i].num_channels)
++			continue;
++		ret = ieee80211_register_hwmode(hw, &modes[i]);
++		if (ret) {
++			ATH5K_ERR(sc, "can't register hwmode %u\n", m);
++			return ret;
++		}
++		return 0;
++	}
++	BUG();
++}
++
++static int
++ath5k_getchannels(struct ieee80211_hw *hw)
++{
++	struct ath5k_softc *sc = hw->priv;
++	struct ath5k_hw *ah = sc->ah;
++	struct ieee80211_hw_mode *modes = sc->modes;
++	unsigned int i, max_r, max_c;
++	int ret;
++
++	BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3);
++
++	/* The order here does not matter */
++	modes[0].mode = MODE_IEEE80211G;
++	modes[1].mode = MODE_IEEE80211B;
++	modes[2].mode = MODE_IEEE80211A;
++
++	max_r = ARRAY_SIZE(sc->rates);
++	max_c = ARRAY_SIZE(sc->channels);
++
++	for (i = 0; i < NUM_DRIVER_MODES; i++) {
++		struct ieee80211_hw_mode *mode = &modes[i];
++		const struct ath5k_rate_table *hw_rates;
++
++		if (i == 0) {
++			modes[0].rates	= sc->rates;
++			modes->channels	= sc->channels;
++		} else {
++			struct ieee80211_hw_mode *prev_mode = &modes[i-1];
++			int prev_num_r	= prev_mode->num_rates;
++			int prev_num_c	= prev_mode->num_channels;
++			mode->rates	= &prev_mode->rates[prev_num_r];
++			mode->channels	= &prev_mode->channels[prev_num_c];
++		}
++
++		hw_rates = ath5k_hw_get_rate_table(ah, mode->mode);
++		mode->num_rates    = ath5k_copy_rates(mode->rates, hw_rates,
++			max_r);
++		mode->num_channels = ath5k_copy_channels(ah, mode->channels,
++			mode->mode, max_c);
++		max_r -= mode->num_rates;
++		max_c -= mode->num_channels;
++	}
++
++	/* We try to register all modes this driver supports. We don't bother
++	 * with MODE_IEEE80211B for AR5212 as MODE_IEEE80211G already accounts
++	 * for that as per mac80211. Then, REGISTER_MODE() will will actually
++	 * check the eeprom reading for more reliable capability information.
++	 * Order matters here as per mac80211's latest preference. This will
++	 * all hopefullly soon go away. */
++
++	REGISTER_MODE(MODE_IEEE80211G);
++	if (ah->ah_version != AR5K_AR5212)
++		REGISTER_MODE(MODE_IEEE80211B);
++	REGISTER_MODE(MODE_IEEE80211A);
++
++	ath5k_debug_dump_modes(sc, modes);
++
++	return ret;
++}
++
++/*
++ * Set/change channels.  If the channel is really being changed,
++ * it's done by reseting the chip.  To accomplish this we must
++ * first cleanup any pending DMA, then restart stuff after a la
++ * ath5k_init.
++ */
++static int
++ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
++{
++	struct ath5k_hw *ah = sc->ah;
++	int ret;
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "%u (%u MHz) -> %u (%u MHz)\n",
++		sc->curchan->chan, sc->curchan->freq,
++		chan->chan, chan->freq);
++
++	if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) {
++		/*
++		 * To switch channels clear any pending DMA operations;
++		 * wait long enough for the RX fifo to drain, reset the
++		 * hardware at the new frequency, and then re-enable
++		 * the relevant bits of the h/w.
++		 */
++		ath5k_hw_set_intr(ah, 0);	/* disable interrupts */
++		ath5k_txq_cleanup(sc);		/* clear pending tx frames */
++		ath5k_rx_stop(sc);		/* turn off frame recv */
++		ret = ath5k_hw_reset(ah, sc->opmode, chan, true);
++		if (ret) {
++			ATH5K_ERR(sc, "%s: unable to reset channel %u "
++				"(%u Mhz)\n", __func__, chan->chan, chan->freq);
++			return ret;
++		}
++		sc->curchan = chan;
++		ath5k_hw_set_txpower_limit(sc->ah, 0);
++
++		/*
++		 * Re-enable rx framework.
++		 */
++		ret = ath5k_rx_start(sc);
++		if (ret) {
++			ATH5K_ERR(sc, "%s: unable to restart recv logic\n",
++					__func__);
++			return ret;
++		}
++
++		/*
++		 * Change channels and update the h/w rate map
++		 * if we're switching; e.g. 11a to 11b/g.
++		 *
++		 * XXX needed?
++		 */
++/*		ath5k_chan_change(sc, chan); */
++
++		/*
++		 * Re-enable interrupts.
++		 */
++		ath5k_hw_set_intr(ah, sc->imask);
++	}
++
++	return 0;
++}
++
++static void
++ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
++{
++	if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) {
++		/* from Atheros NDIS driver, w/ permission */
++		static const struct {
++			u16 rate;	/* tx/rx 802.11 rate */
++			u16 timeOn;	/* LED on time (ms) */
++			u16 timeOff;	/* LED off time (ms) */
++		} blinkrates[] = {
++			{ 108,  40,  10 },
++			{  96,  44,  11 },
++			{  72,  50,  13 },
++			{  48,  57,  14 },
++			{  36,  67,  16 },
++			{  24,  80,  20 },
++			{  22, 100,  25 },
++			{  18, 133,  34 },
++			{  12, 160,  40 },
++			{  10, 200,  50 },
++			{   6, 240,  58 },
++			{   4, 267,  66 },
++			{   2, 400, 100 },
++			{   0, 500, 130 }
++		};
++		const struct ath5k_rate_table *rt =
++				ath5k_hw_get_rate_table(sc->ah, mode);
++		unsigned int i, j;
++
++		BUG_ON(rt == NULL);
++
++		memset(sc->hwmap, 0, sizeof(sc->hwmap));
++		for (i = 0; i < 32; i++) {
++			u8 ix = rt->rate_code_to_index[i];
++			if (ix == 0xff) {
++				sc->hwmap[i].ledon = msecs_to_jiffies(500);
++				sc->hwmap[i].ledoff = msecs_to_jiffies(130);
++				continue;
++			}
++			sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
++			if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation ==
++					IEEE80211_RATE_OFDM)
++				sc->hwmap[i].txflags |=
++						IEEE80211_RADIOTAP_F_SHORTPRE;
++			/* receive frames include FCS */
++			sc->hwmap[i].rxflags = sc->hwmap[i].txflags |
++					IEEE80211_RADIOTAP_F_FCS;
++			/* setup blink rate table to avoid per-packet lookup */
++			for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++)
++				if (blinkrates[j].rate == /* XXX why 7f? */
++						(rt->rates[ix].dot11_rate&0x7f))
++					break;
++
++			sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j].
++					timeOn);
++			sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j].
++					timeOff);
++		}
++	}
++
++	sc->curmode = mode;
++}
++
++static void
++ath5k_mode_setup(struct ath5k_softc *sc)
++{
++	struct ath5k_hw *ah = sc->ah;
++	u32 rfilt;
++
++	/* configure rx filter */
++	rfilt = sc->filter_flags;
++	ath5k_hw_set_rx_filter(ah, rfilt);
++
++	if (ath5k_hw_hasbssidmask(ah))
++		ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
++
++	/* configure operational mode */
++	ath5k_hw_set_opmode(ah);
++
++	ath5k_hw_set_mcast_filter(ah, 0, 0);
++	ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
++}
++
++
++
++
++/***************\
++* Buffers setup *
++\***************/
++
++static int
++ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
++{
++	struct ath5k_hw *ah = sc->ah;
++	struct sk_buff *skb = bf->skb;
++	struct ath5k_desc *ds;
++
++	if (likely(skb == NULL)) {
++		unsigned int off;
++
++		/*
++		 * Allocate buffer with headroom_needed space for the
++		 * fake physical layer header at the start.
++		 */
++		skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
++		if (unlikely(skb == NULL)) {
++			ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
++					sc->rxbufsize + sc->cachelsz - 1);
++			return -ENOMEM;
++		}
++		/*
++		 * Cache-line-align.  This is important (for the
++		 * 5210 at least) as not doing so causes bogus data
++		 * in rx'd frames.
++		 */
++		off = ((unsigned long)skb->data) % sc->cachelsz;
++		if (off != 0)
++			skb_reserve(skb, sc->cachelsz - off);
++
++		bf->skb = skb;
++		bf->skbaddr = pci_map_single(sc->pdev,
++			skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
++		if (unlikely(pci_dma_mapping_error(bf->skbaddr))) {
++			ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
++			dev_kfree_skb(skb);
++			bf->skb = NULL;
++			return -ENOMEM;
++		}
++	}
++
++	/*
++	 * Setup descriptors.  For receive we always terminate
++	 * the descriptor list with a self-linked entry so we'll
++	 * not get overrun under high load (as can happen with a
++	 * 5212 when ANI processing enables PHY error frames).
++	 *
++	 * To insure the last descriptor is self-linked we create
++	 * each descriptor as self-linked and add it to the end.  As
++	 * each additional descriptor is added the previous self-linked
++	 * entry is ``fixed'' naturally.  This should be safe even
++	 * if DMA is happening.  When processing RX interrupts we
++	 * never remove/process the last, self-linked, entry on the
++	 * descriptor list.  This insures the hardware always has
++	 * someplace to write a new frame.
++	 */
++	ds = bf->desc;
++	ds->ds_link = bf->daddr;	/* link to self */
++	ds->ds_data = bf->skbaddr;
++	ath5k_hw_setup_rx_desc(ah, ds,
++		skb_tailroom(skb),	/* buffer size */
++		0);
++
++	if (sc->rxlink != NULL)
++		*sc->rxlink = bf->daddr;
++	sc->rxlink = &ds->ds_link;
++	return 0;
++}
++
++static int
++ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
++		struct ieee80211_tx_control *ctl)
++{
++	struct ath5k_hw *ah = sc->ah;
++	struct ath5k_txq *txq = sc->txq;
++	struct ath5k_desc *ds = bf->desc;
++	struct sk_buff *skb = bf->skb;
++	unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
++	int ret;
++
++	flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
++	bf->ctl = *ctl;
++	/* XXX endianness */
++	bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
++			PCI_DMA_TODEVICE);
++
++	if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
++		flags |= AR5K_TXDESC_NOACK;
++
++	pktlen = skb->len + FCS_LEN;
++
++	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
++		keyidx = ctl->key_idx;
++		pktlen += ctl->icv_len;
++	}
++
++	ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
++		ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
++		(ctl->power_level * 2), ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0);
++	if (ret)
++		goto err_unmap;
++
++	ds->ds_link = 0;
++	ds->ds_data = bf->skbaddr;
++
++	spin_lock_bh(&txq->lock);
++	list_add_tail(&bf->list, &txq->q);
++	sc->tx_stats.data[txq->qnum].len++;
++	if (txq->link == NULL) /* is this first packet? */
++		ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr);
++	else /* no, so only link it */
++		*txq->link = bf->daddr;
++
++	txq->link = &ds->ds_link;
++	ath5k_hw_tx_start(ah, txq->qnum);
++	spin_unlock_bh(&txq->lock);
++
++	return 0;
++err_unmap:
++	pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
++	return ret;
++}
++
++/*******************\
++* Descriptors setup *
++\*******************/
++
++static int
++ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
++{
++	struct ath5k_desc *ds;
++	struct ath5k_buf *bf;
++	dma_addr_t da;
++	unsigned int i;
++	int ret;
++
++	/* allocate descriptors */
++	sc->desc_len = sizeof(struct ath5k_desc) *
++			(ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1);
++	sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr);
++	if (sc->desc == NULL) {
++		ATH5K_ERR(sc, "can't allocate descriptors\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++	ds = sc->desc;
++	da = sc->desc_daddr;
++	ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n",
++		ds, sc->desc_len, (unsigned long long)sc->desc_daddr);
++
++	bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF,
++			sizeof(struct ath5k_buf), GFP_KERNEL);
++	if (bf == NULL) {
++		ATH5K_ERR(sc, "can't allocate bufptr\n");
++		ret = -ENOMEM;
++		goto err_free;
++	}
++	sc->bufptr = bf;
++
++	INIT_LIST_HEAD(&sc->rxbuf);
++	for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
++		bf->desc = ds;
++		bf->daddr = da;
++		list_add_tail(&bf->list, &sc->rxbuf);
++	}
++
++	INIT_LIST_HEAD(&sc->txbuf);
++	sc->txbuf_len = ATH_TXBUF;
++	for (i = 0; i < ATH_TXBUF; i++, bf++, ds++,
++			da += sizeof(*ds)) {
++		bf->desc = ds;
++		bf->daddr = da;
++		list_add_tail(&bf->list, &sc->txbuf);
++	}
++
++	/* beacon buffer */
++	bf->desc = ds;
++	bf->daddr = da;
++	sc->bbuf = bf;
++
++	return 0;
++err_free:
++	pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
++err:
++	sc->desc = NULL;
++	return ret;
++}
++
++static void
++ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
++{
++	struct ath5k_buf *bf;
++
++	ath5k_txbuf_free(sc, sc->bbuf);
++	list_for_each_entry(bf, &sc->txbuf, list)
++		ath5k_txbuf_free(sc, bf);
++	list_for_each_entry(bf, &sc->rxbuf, list)
++		ath5k_txbuf_free(sc, bf);
++
++	/* Free memory associated with all descriptors */
++	pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
++
++	kfree(sc->bufptr);
++	sc->bufptr = NULL;
++}
++
++
++
++
++
++/**************\
++* Queues setup *
++\**************/
++
++static struct ath5k_txq *
++ath5k_txq_setup(struct ath5k_softc *sc,
++		int qtype, int subtype)
++{
++	struct ath5k_hw *ah = sc->ah;
++	struct ath5k_txq *txq;
++	struct ath5k_txq_info qi = {
++		.tqi_subtype = subtype,
++		.tqi_aifs = AR5K_TXQ_USEDEFAULT,
++		.tqi_cw_min = AR5K_TXQ_USEDEFAULT,
++		.tqi_cw_max = AR5K_TXQ_USEDEFAULT
++	};
++	int qnum;
++
++	/*
++	 * Enable interrupts only for EOL and DESC conditions.
++	 * We mark tx descriptors to receive a DESC interrupt
++	 * when a tx queue gets deep; otherwise waiting for the
++	 * EOL to reap descriptors.  Note that this is done to
++	 * reduce interrupt load and this only defers reaping
++	 * descriptors, never transmitting frames.  Aside from
++	 * reducing interrupts this also permits more concurrency.
++	 * The only potential downside is if the tx queue backs
++	 * up in which case the top half of the kernel may backup
++	 * due to a lack of tx descriptors.
++	 */
++	qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE |
++				AR5K_TXQ_FLAG_TXDESCINT_ENABLE;
++	qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi);
++	if (qnum < 0) {
++		/*
++		 * NB: don't print a message, this happens
++		 * normally on parts with too few tx queues
++		 */
++		return ERR_PTR(qnum);
++	}
++	if (qnum >= ARRAY_SIZE(sc->txqs)) {
++		ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n",
++			qnum, ARRAY_SIZE(sc->txqs));
++		ath5k_hw_release_tx_queue(ah, qnum);
++		return ERR_PTR(-EINVAL);
++	}
++	txq = &sc->txqs[qnum];
++	if (!txq->setup) {
++		txq->qnum = qnum;
++		txq->link = NULL;
++		INIT_LIST_HEAD(&txq->q);
++		spin_lock_init(&txq->lock);
++		txq->setup = true;
++	}
++	return &sc->txqs[qnum];
++}
++
++static int
++ath5k_beaconq_setup(struct ath5k_hw *ah)
++{
++	struct ath5k_txq_info qi = {
++		.tqi_aifs = AR5K_TXQ_USEDEFAULT,
++		.tqi_cw_min = AR5K_TXQ_USEDEFAULT,
++		.tqi_cw_max = AR5K_TXQ_USEDEFAULT,
++		/* NB: for dynamic turbo, don't enable any other interrupts */
++		.tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE
++	};
++
++	return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi);
++}
++
++static int
++ath5k_beaconq_config(struct ath5k_softc *sc)
++{
++	struct ath5k_hw *ah = sc->ah;
++	struct ath5k_txq_info qi;
++	int ret;
++
++	ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
++	if (ret)
++		return ret;
++	if (sc->opmode == IEEE80211_IF_TYPE_AP ||
++			sc->opmode == IEEE80211_IF_TYPE_IBSS) {
++		/*
++		 * Always burst out beacon and CAB traffic
++		 * (aifs = cwmin = cwmax = 0)
++		 */
++		qi.tqi_aifs = 0;
++		qi.tqi_cw_min = 0;
++		qi.tqi_cw_max = 0;
++	}
++
++	ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi);
++	if (ret) {
++		ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
++			"hardware queue!\n", __func__);
++		return ret;
++	}
++
++	return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */;
++}
++
++static void
++ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
++{
++	struct ath5k_buf *bf, *bf0;
++
++	/*
++	 * NB: this assumes output has been stopped and
++	 *     we do not need to block ath5k_tx_tasklet
++	 */
++	spin_lock_bh(&txq->lock);
++	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
++		ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah,
++					bf->desc));
++
++		ath5k_txbuf_free(sc, bf);
++
++		spin_lock_bh(&sc->txbuflock);
++		sc->tx_stats.data[txq->qnum].len--;
++		list_move_tail(&bf->list, &sc->txbuf);
++		sc->txbuf_len++;
++		spin_unlock_bh(&sc->txbuflock);
++	}
++	txq->link = NULL;
++	spin_unlock_bh(&txq->lock);
++}
++
++/*
++ * Drain the transmit queues and reclaim resources.
++ */
++static void
++ath5k_txq_cleanup(struct ath5k_softc *sc)
++{
++	struct ath5k_hw *ah = sc->ah;
++	unsigned int i;
++
++	/* XXX return value */
++	if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) {
++		/* don't touch the hardware if marked invalid */
++		(void)ath5k_hw_stop_tx_dma(ah, sc->bhalq);
++		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
++			ath5k_hw_get_tx_buf(ah, sc->bhalq));
++		for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
++			if (sc->txqs[i].setup) {
++				ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
++				ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
++					"link %p\n",
++					sc->txqs[i].qnum,
++					ath5k_hw_get_tx_buf(ah,
++							sc->txqs[i].qnum),
++					sc->txqs[i].link);
++			}
++	}
++	ieee80211_start_queues(sc->hw); /* XXX move to callers */
++
++	for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
++		if (sc->txqs[i].setup)
++			ath5k_txq_drainq(sc, &sc->txqs[i]);
++}
++
++static void
++ath5k_txq_release(struct ath5k_softc *sc)
++{
++	struct ath5k_txq *txq = sc->txqs;
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++)
++		if (txq->setup) {
++			ath5k_hw_release_tx_queue(sc->ah, txq->qnum);
++			txq->setup = false;
++		}
++}
++
++
++
++
++/*************\
++* RX Handling *
++\*************/
++
++/*
++ * Enable the receive h/w following a reset.
++ */
++static int
++ath5k_rx_start(struct ath5k_softc *sc)
++{
++	struct ath5k_hw *ah = sc->ah;
++	struct ath5k_buf *bf;
++	int ret;
++
++	sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz);
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
++		sc->cachelsz, sc->rxbufsize);
++
++	sc->rxlink = NULL;
++
++	spin_lock_bh(&sc->rxbuflock);
++	list_for_each_entry(bf, &sc->rxbuf, list) {
++		ret = ath5k_rxbuf_setup(sc, bf);
++		if (ret != 0) {
++			spin_unlock_bh(&sc->rxbuflock);
++			goto err;
++		}
++	}
++	bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
++	spin_unlock_bh(&sc->rxbuflock);
++
++	ath5k_hw_put_rx_buf(ah, bf->daddr);
++	ath5k_hw_start_rx(ah);		/* enable recv descriptors */
++	ath5k_mode_setup(sc);		/* set filters, etc. */
++	ath5k_hw_start_rx_pcu(ah);	/* re-enable PCU/DMA engine */
++
++	return 0;
++err:
++	return ret;
++}
++
++/*
++ * Disable the receive h/w in preparation for a reset.
++ */
++static void
++ath5k_rx_stop(struct ath5k_softc *sc)
++{
++	struct ath5k_hw *ah = sc->ah;
++
++	ath5k_hw_stop_pcu_recv(ah);	/* disable PCU */
++	ath5k_hw_set_rx_filter(ah, 0);	/* clear recv filter */
++	ath5k_hw_stop_rx_dma(ah);	/* disable DMA engine */
++	mdelay(3);			/* 3ms is long enough for 1 frame */
++
++	ath5k_debug_printrxbuffs(sc, ah);
++
++	sc->rxlink = NULL;		/* just in case */
++}
++
++static unsigned int
++ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
++		struct sk_buff *skb)
++{
++	struct ieee80211_hdr *hdr = (void *)skb->data;
++	unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb);
++
++	if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
++			ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID)
++		return RX_FLAG_DECRYPTED;
++
++	/* Apparently when a default key is used to decrypt the packet
++	   the hw does not set the index used to decrypt.  In such cases
++	   get the index from the packet. */
++	if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) &&
++			!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
++			skb->len >= hlen + 4) {
++		keyix = skb->data[hlen + 3] >> 6;
++
++		if (test_bit(keyix, sc->keymap))
++			return RX_FLAG_DECRYPTED;
++	}
++
++	return 0;
++}
++
++static void
++ath5k_tasklet_rx(unsigned long data)
++{
++	struct ieee80211_rx_status rxs = {};
++	struct sk_buff *skb;
++	struct ath5k_softc *sc = (void *)data;
++	struct ath5k_buf *bf;
++	struct ath5k_desc *ds;
++	u16 len;
++	u8 stat;
++	int ret;
++	int hdrlen;
++	int pad;
++
++	spin_lock(&sc->rxbuflock);
++	do {
++		if (unlikely(list_empty(&sc->rxbuf))) {
++			ATH5K_WARN(sc, "empty rx buf pool\n");
++			break;
++		}
++		bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
++		BUG_ON(bf->skb == NULL);
++		skb = bf->skb;
++		ds = bf->desc;
++
++		/* TODO only one segment */
++		pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
++				sc->desc_len, PCI_DMA_FROMDEVICE);
++
++		if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
++			break;
++
++		ret = sc->ah->ah_proc_rx_desc(sc->ah, ds);
++		if (unlikely(ret == -EINPROGRESS))
++			break;
++		else if (unlikely(ret)) {
++			ATH5K_ERR(sc, "error in processing rx descriptor\n");
++			return;
++		}
++
++		if (unlikely(ds->ds_rxstat.rs_more)) {
++			ATH5K_WARN(sc, "unsupported jumbo\n");
++			goto next;
++		}
++
++		stat = ds->ds_rxstat.rs_status;
++		if (unlikely(stat)) {
++			if (stat & AR5K_RXERR_PHY)
++				goto next;
++			if (stat & AR5K_RXERR_DECRYPT) {
++				/*
++				 * Decrypt error.  If the error occurred
++				 * because there was no hardware key, then
++				 * let the frame through so the upper layers
++				 * can process it.  This is necessary for 5210
++				 * parts which have no way to setup a ``clear''
++				 * key cache entry.
++				 *
++				 * XXX do key cache faulting
++				 */
++				if (ds->ds_rxstat.rs_keyix ==
++						AR5K_RXKEYIX_INVALID &&
++						!(stat & AR5K_RXERR_CRC))
++					goto accept;
++			}
++			if (stat & AR5K_RXERR_MIC) {
++				rxs.flag |= RX_FLAG_MMIC_ERROR;
++				goto accept;
++			}
++
++			/* let crypto-error packets fall through in MNTR */
++			if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
++					sc->opmode != IEEE80211_IF_TYPE_MNTR)
++				goto next;
++		}
++accept:
++		len = ds->ds_rxstat.rs_datalen;
++		pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len,
++				PCI_DMA_FROMDEVICE);
++		pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
++				PCI_DMA_FROMDEVICE);
++		bf->skb = NULL;
++
++		skb_put(skb, len);
++
++		/*
++		 * the hardware adds a padding to 4 byte boundaries between
++		 * the header and the payload data if the header length is
++		 * not multiples of 4 - remove it
++		 */
++		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
++		if (hdrlen & 3) {
++			pad = hdrlen % 4;
++			memmove(skb->data + pad, skb->data, hdrlen);
++			skb_pull(skb, pad);
++		}
++
++		if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
++			rxs.mactime = ath5k_extend_tsf(sc->ah,
++					ds->ds_rxstat.rs_tstamp);
++		else
++			rxs.mactime = ds->ds_rxstat.rs_tstamp;
++		rxs.freq = sc->curchan->freq;
++		rxs.channel = sc->curchan->chan;
++		rxs.phymode = sc->curmode;
++
++		/*
++		 * signal quality:
++		 * the names here are misleading and the usage of these
++		 * values by iwconfig makes it even worse
++		 */
++		/* noise floor in dBm, from the last noise calibration */
++		rxs.noise = sc->ah->ah_noise_floor;
++		/* signal level in dBm */
++		rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi;
++		/*
++		 * "signal" is actually displayed as Link Quality by iwconfig
++		 * we provide a percentage based on rssi (assuming max rssi 64)
++		 */
++		rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64;
++
++		rxs.antenna = ds->ds_rxstat.rs_antenna;
++		rxs.rate = ds->ds_rxstat.rs_rate;
++		rxs.flag |= ath5k_rx_decrypted(sc, ds, skb);
++
++		ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
++
++		__ieee80211_rx(sc->hw, skb, &rxs);
++		sc->led_rxrate = ds->ds_rxstat.rs_rate;
++		ath5k_led_event(sc, ATH_LED_RX);
++next:
++		list_move_tail(&bf->list, &sc->rxbuf);
++	} while (ath5k_rxbuf_setup(sc, bf) == 0);
++	spin_unlock(&sc->rxbuflock);
++}
++
++
++
++
++/*************\
++* TX Handling *
++\*************/
++
++static void
++ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
++{
++	struct ieee80211_tx_status txs = {};
++	struct ath5k_buf *bf, *bf0;
++	struct ath5k_desc *ds;
++	struct sk_buff *skb;
++	int ret;
++
++	spin_lock(&txq->lock);
++	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
++		ds = bf->desc;
++
++		/* TODO only one segment */
++		pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
++				sc->desc_len, PCI_DMA_FROMDEVICE);
++		ret = sc->ah->ah_proc_tx_desc(sc->ah, ds);
++		if (unlikely(ret == -EINPROGRESS))
++			break;
++		else if (unlikely(ret)) {
++			ATH5K_ERR(sc, "error %d while processing queue %u\n",
++				ret, txq->qnum);
++			break;
++		}
++
++		skb = bf->skb;
++		bf->skb = NULL;
++		pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
++				PCI_DMA_TODEVICE);
++
++		txs.control = bf->ctl;
++		txs.retry_count = ds->ds_txstat.ts_shortretry +
++			ds->ds_txstat.ts_longretry / 6;
++		if (unlikely(ds->ds_txstat.ts_status)) {
++			sc->ll_stats.dot11ACKFailureCount++;
++			if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY)
++				txs.excessive_retries = 1;
++			else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT)
++				txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
++		} else {
++			txs.flags |= IEEE80211_TX_STATUS_ACK;
++			txs.ack_signal = ds->ds_txstat.ts_rssi;
++		}
++
++		ieee80211_tx_status(sc->hw, skb, &txs);
++		sc->tx_stats.data[txq->qnum].count++;
++
++		spin_lock(&sc->txbuflock);
++		sc->tx_stats.data[txq->qnum].len--;
++		list_move_tail(&bf->list, &sc->txbuf);
++		sc->txbuf_len++;
++		spin_unlock(&sc->txbuflock);
++	}
++	if (likely(list_empty(&txq->q)))
++		txq->link = NULL;
++	spin_unlock(&txq->lock);
++	if (sc->txbuf_len > ATH_TXBUF / 5)
++		ieee80211_wake_queues(sc->hw);
++}
++
++static void
++ath5k_tasklet_tx(unsigned long data)
++{
++	struct ath5k_softc *sc = (void *)data;
++
++	ath5k_tx_processq(sc, sc->txq);
++
++	ath5k_led_event(sc, ATH_LED_TX);
++}
++
++
++
++
++/*****************\
++* Beacon handling *
++\*****************/
++
++/*
++ * Setup the beacon frame for transmit.
++ */
++static int
++ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
++		struct ieee80211_tx_control *ctl)
++{
++	struct sk_buff *skb = bf->skb;
++	struct ath5k_hw *ah = sc->ah;
++	struct ath5k_desc *ds;
++	int ret, antenna = 0;
++	u32 flags;
++
++	bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
++			PCI_DMA_TODEVICE);
++	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] "
++			"skbaddr %llx\n", skb, skb->data, skb->len,
++			(unsigned long long)bf->skbaddr);
++	if (pci_dma_mapping_error(bf->skbaddr)) {
++		ATH5K_ERR(sc, "beacon DMA mapping failed\n");
++		return -EIO;
++	}
++
++	ds = bf->desc;
++
++	flags = AR5K_TXDESC_NOACK;
++	if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) {
++		ds->ds_link = bf->daddr;	/* self-linked */
++		flags |= AR5K_TXDESC_VEOL;
++		/*
++		 * Let hardware handle antenna switching if txantenna is not set
++		 */
++	} else {
++		ds->ds_link = 0;
++		/*
++		 * Switch antenna every 4 beacons if txantenna is not set
++		 * XXX assumes two antennas
++		 */
++		if (antenna == 0)
++			antenna = sc->bsent & 4 ? 2 : 1;
++	}
++
++	ds->ds_data = bf->skbaddr;
++	ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN,
++			ieee80211_get_hdrlen_from_skb(skb),
++			AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1,
++			AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0);
++	if (ret)
++		goto err_unmap;
++
++	return 0;
++err_unmap:
++	pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
++	return ret;
++}
++
++/*
++ * Transmit a beacon frame at SWBA.  Dynamic updates to the
++ * frame contents are done as needed and the slot time is
++ * also adjusted based on current state.
++ *
++ * this is usually called from interrupt context (ath5k_intr())
++ * but also from ath5k_beacon_config() in IBSS mode which in turn
++ * can be called from a tasklet and user context
++ */
++static void
++ath5k_beacon_send(struct ath5k_softc *sc)
++{
++	struct ath5k_buf *bf = sc->bbuf;
++	struct ath5k_hw *ah = sc->ah;
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "in beacon_send\n");
++
++	if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA ||
++			sc->opmode == IEEE80211_IF_TYPE_MNTR)) {
++		ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
++		return;
++	}
++	/*
++	 * Check if the previous beacon has gone out.  If
++	 * not don't don't try to post another, skip this
++	 * period and wait for the next.  Missed beacons
++	 * indicate a problem and should not occur.  If we
++	 * miss too many consecutive beacons reset the device.
++	 */
++	if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) {
++		sc->bmisscount++;
++		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
++			"missed %u consecutive beacons\n", sc->bmisscount);
++		if (sc->bmisscount > 3) {		/* NB: 3 is a guess */
++			ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
++				"stuck beacon time (%u missed)\n",
++				sc->bmisscount);
++			tasklet_schedule(&sc->restq);
++		}
++		return;
++	}
++	if (unlikely(sc->bmisscount != 0)) {
++		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
++			"resume beacon xmit after %u misses\n",
++			sc->bmisscount);
++		sc->bmisscount = 0;
++	}
++
++	/*
++	 * Stop any current dma and put the new frame on the queue.
++	 * This should never fail since we check above that no frames
++	 * are still pending on the queue.
++	 */
++	if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
++		ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq);
++		/* NB: hw still stops DMA, so proceed */
++	}
++	pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len,
++			PCI_DMA_TODEVICE);
++
++	ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
++	ath5k_hw_tx_start(ah, sc->bhalq);
++	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "TXDP[%u] = %llx (%p)\n",
++		sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
++
++	sc->bsent++;
++}
++
++/*
++ * Configure the beacon and sleep timers.
++ *
++ * When operating as an AP this resets the TSF and sets
++ * up the hardware to notify us when we need to issue beacons.
++ *
++ * When operating in station mode this sets up the beacon
++ * timers according to the timestamp of the last received
++ * beacon and the current TSF, configures PCF and DTIM
++ * handling, programs the sleep registers so the hardware
++ * will wakeup in time to receive beacons, and configures
++ * the beacon miss handling so we'll receive a BMISS
++ * interrupt when we stop seeing beacons from the AP
++ * we've associated with.
++ */
++static void
++ath5k_beacon_config(struct ath5k_softc *sc)
++{
++#define TSF_TO_TU(_h, _l)	(((_h) << 22) | ((_l) >> 10))
++	struct ath5k_hw *ah = sc->ah;
++	u32 uninitialized_var(nexttbtt), intval, tsftu;
++	u64 tsf;
++
++	intval = sc->bintval & AR5K_BEACON_PERIOD;
++	if (WARN_ON(!intval))
++		return;
++
++	/* current TSF converted to TU */
++	tsf = ath5k_hw_get_tsf64(ah);
++	tsftu = TSF_TO_TU((u32)(tsf >> 32), (u32)tsf);
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "intval %u hw tsftu %u\n",
++		intval, tsftu);
++
++	if (sc->opmode == IEEE80211_IF_TYPE_STA ||
++			(sc->opmode == IEEE80211_IF_TYPE_IBSS &&
++				!sc->bbuf->skb)) {
++		ath5k_hw_set_intr(ah, 0);
++		sc->imask |= AR5K_INT_BMISS;
++		sc->bmisscount = 0;
++		ath5k_hw_set_intr(ah, sc->imask);
++	} else if (sc->opmode == IEEE80211_IF_TYPE_IBSS /* TODO || AP */) {
++		ath5k_hw_set_intr(ah, 0);
++		if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
++			/*
++			 * Pull nexttbtt forward to reflect the current
++			 * TSF. Add one intval otherwise the timespan
++			 * can be too short for ibss merges.
++			 */
++			nexttbtt = tsftu + 2 * intval;
++
++			ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "nexttbtt %u "
++				"intval %u\n", nexttbtt, intval);
++
++			/*
++			 * In IBSS mode enable the beacon timers but only
++			 * enable SWBA interrupts if we need to manually
++			 * prepare beacon frames.  Otherwise we use a
++			 * self-linked tx descriptor and let the hardware
++			 * deal with things.
++			 */
++			if (!ath5k_hw_hasveol(ah))
++				sc->imask |= AR5K_INT_SWBA;
++		} /* TODO else AP */
++
++		intval |= AR5K_BEACON_ENA;
++
++		ath5k_beaconq_config(sc);
++		ath5k_hw_init_beacon(ah, nexttbtt, intval);
++
++		sc->bmisscount = 0;
++		ath5k_hw_set_intr(ah, sc->imask);
++		/*
++		 * When using a self-linked beacon descriptor in
++		 * ibss mode load it once here.
++		 */
++		if (sc->opmode == IEEE80211_IF_TYPE_IBSS &&
++				ath5k_hw_hasveol(ah))
++			ath5k_beacon_send(sc);
++	}
++#undef TSF_TO_TU
++}
++
++/********************\
++* Interrupt handling *
++\********************/
++
++static int
++ath5k_init(struct ath5k_softc *sc)
++{
++	int ret;
++
++	mutex_lock(&sc->lock);
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
++
++	/*
++	 * Stop anything previously setup.  This is safe
++	 * no matter this is the first time through or not.
++	 */
++	ath5k_stop_locked(sc);
++
++	/*
++	 * The basic interface to setting the hardware in a good
++	 * state is ``reset''.  On return the hardware is known to
++	 * be powered up and with interrupts disabled.  This must
++	 * be followed by initialization of the appropriate bits
++	 * and then setup of the interrupt mask.
++	 */
++	sc->curchan = sc->hw->conf.chan;
++	ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false);
++	if (ret) {
++		ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret);
++		goto done;
++	}
++	/*
++	 * This is needed only to setup initial state
++	 * but it's best done after a reset.
++	 */
++	ath5k_hw_set_txpower_limit(sc->ah, 0);
++
++	/*
++	 * Setup the hardware after reset: the key cache
++	 * is filled as needed and the receive engine is
++	 * set going.  Frame transmit is handled entirely
++	 * in the frame output path; there's nothing to do
++	 * here except setup the interrupt mask.
++	 */
++	ret = ath5k_rx_start(sc);
++	if (ret)
++		goto done;
++
++	/*
++	 * Enable interrupts.
++	 */
++	sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
++		AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL;
++
++	ath5k_hw_set_intr(sc->ah, sc->imask);
++	/* Set ack to be sent at low bit-rates */
++	ath5k_hw_set_ack_bitrate_high(sc->ah, false);
++
++	mod_timer(&sc->calib_tim, round_jiffies(jiffies +
++			msecs_to_jiffies(ath5k_calinterval * 1000)));
++
++	ret = 0;
++done:
++	mutex_unlock(&sc->lock);
++	return ret;
++}
++
++static int
++ath5k_stop_locked(struct ath5k_softc *sc)
++{
++	struct ath5k_hw *ah = sc->ah;
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n",
++			test_bit(ATH_STAT_INVALID, sc->status));
++
++	/*
++	 * Shutdown the hardware and driver:
++	 *    stop output from above
++	 *    disable interrupts
++	 *    turn off timers
++	 *    turn off the radio
++	 *    clear transmit machinery
++	 *    clear receive machinery
++	 *    drain and release tx queues
++	 *    reclaim beacon resources
++	 *    power down hardware
++	 *
++	 * Note that some of this work is not possible if the
++	 * hardware is gone (invalid).
++	 */
++	ieee80211_stop_queues(sc->hw);
++
++	if (!test_bit(ATH_STAT_INVALID, sc->status)) {
++		if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
++			del_timer_sync(&sc->led_tim);
++			ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
++			__clear_bit(ATH_STAT_LEDBLINKING, sc->status);
++		}
++		ath5k_hw_set_intr(ah, 0);
++	}
++	ath5k_txq_cleanup(sc);
++	if (!test_bit(ATH_STAT_INVALID, sc->status)) {
++		ath5k_rx_stop(sc);
++		ath5k_hw_phy_disable(ah);
++	} else
++		sc->rxlink = NULL;
++
++	return 0;
++}
++
++/*
++ * Stop the device, grabbing the top-level lock to protect
++ * against concurrent entry through ath5k_init (which can happen
++ * if another thread does a system call and the thread doing the
++ * stop is preempted).
++ */
++static int
++ath5k_stop_hw(struct ath5k_softc *sc)
++{
++	int ret;
++
++	mutex_lock(&sc->lock);
++	ret = ath5k_stop_locked(sc);
++	if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
++		/*
++		 * Set the chip in full sleep mode.  Note that we are
++		 * careful to do this only when bringing the interface
++		 * completely to a stop.  When the chip is in this state
++		 * it must be carefully woken up or references to
++		 * registers in the PCI clock domain may freeze the bus
++		 * (and system).  This varies by chip and is mostly an
++		 * issue with newer parts that go to sleep more quickly.
++		 */
++		if (sc->ah->ah_mac_srev >= 0x78) {
++			/*
++			 * XXX
++			 * don't put newer MAC revisions > 7.8 to sleep because
++			 * of the above mentioned problems
++			 */
++			ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "
++				"not putting device to sleep\n");
++		} else {
++			ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
++				"putting device to full sleep\n");
++			ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
++		}
++	}
++	ath5k_txbuf_free(sc, sc->bbuf);
++	mutex_unlock(&sc->lock);
++
++	del_timer_sync(&sc->calib_tim);
++
++	return ret;
++}
++
++static irqreturn_t
++ath5k_intr(int irq, void *dev_id)
++{
++	struct ath5k_softc *sc = dev_id;
++	struct ath5k_hw *ah = sc->ah;
++	enum ath5k_int status;
++	unsigned int counter = 1000;
++
++	if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
++				!ath5k_hw_is_intr_pending(ah)))
++		return IRQ_NONE;
++
++	do {
++		/*
++		 * Figure out the reason(s) for the interrupt.  Note
++		 * that get_isr returns a pseudo-ISR that may include
++		 * bits we haven't explicitly enabled so we mask the
++		 * value to insure we only process bits we requested.
++		 */
++		ath5k_hw_get_isr(ah, &status);		/* NB: clears IRQ too */
++		ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",
++				status, sc->imask);
++		status &= sc->imask; /* discard unasked for bits */
++		if (unlikely(status & AR5K_INT_FATAL)) {
++			/*
++			 * Fatal errors are unrecoverable.
++			 * Typically these are caused by DMA errors.
++			 */
++			tasklet_schedule(&sc->restq);
++		} else if (unlikely(status & AR5K_INT_RXORN)) {
++			tasklet_schedule(&sc->restq);
++		} else {
++			if (status & AR5K_INT_SWBA) {
++				/*
++				* Software beacon alert--time to send a beacon.
++				* Handle beacon transmission directly; deferring
++				* this is too slow to meet timing constraints
++				* under load.
++				*/
++				ath5k_beacon_send(sc);
++			}
++			if (status & AR5K_INT_RXEOL) {
++				/*
++				* NB: the hardware should re-read the link when
++				*     RXE bit is written, but it doesn't work at
++				*     least on older hardware revs.
++				*/
++				sc->rxlink = NULL;
++			}
++			if (status & AR5K_INT_TXURN) {
++				/* bump tx trigger level */
++				ath5k_hw_update_tx_triglevel(ah, true);
++			}
++			if (status & AR5K_INT_RX)
++				tasklet_schedule(&sc->rxtq);
++			if (status & AR5K_INT_TX)
++				tasklet_schedule(&sc->txtq);
++			if (status & AR5K_INT_BMISS) {
++			}
++			if (status & AR5K_INT_MIB) {
++				/* TODO */
++			}
++		}
++	} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
++
++	if (unlikely(!counter))
++		ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
++
++	return IRQ_HANDLED;
++}
++
++static void
++ath5k_tasklet_reset(unsigned long data)
++{
++	struct ath5k_softc *sc = (void *)data;
++
++	ath5k_reset(sc->hw);
++}
++
++/*
++ * Periodically recalibrate the PHY to account
++ * for temperature/environment changes.
++ */
++static void
++ath5k_calibrate(unsigned long data)
++{
++	struct ath5k_softc *sc = (void *)data;
++	struct ath5k_hw *ah = sc->ah;
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
++		sc->curchan->chan, sc->curchan->val);
++
++	if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
++		/*
++		 * Rfgain is out of bounds, reset the chip
++		 * to load new gain values.
++		 */
++		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
++		ath5k_reset(sc->hw);
++	}
++	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
++		ATH5K_ERR(sc, "calibration of channel %u failed\n",
++				sc->curchan->chan);
++
++	mod_timer(&sc->calib_tim, round_jiffies(jiffies +
++			msecs_to_jiffies(ath5k_calinterval * 1000)));
++}
++
++
++
++/***************\
++* LED functions *
++\***************/
++
++static void
++ath5k_led_off(unsigned long data)
++{
++	struct ath5k_softc *sc = (void *)data;
++
++	if (test_bit(ATH_STAT_LEDENDBLINK, sc->status))
++		__clear_bit(ATH_STAT_LEDBLINKING, sc->status);
++	else {
++		__set_bit(ATH_STAT_LEDENDBLINK, sc->status);
++		ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
++		mod_timer(&sc->led_tim, jiffies + sc->led_off);
++	}
++}
++
++/*
++ * Blink the LED according to the specified on/off times.
++ */
++static void
++ath5k_led_blink(struct ath5k_softc *sc, unsigned int on,
++		unsigned int off)
++{
++	ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off);
++	ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
++	__set_bit(ATH_STAT_LEDBLINKING, sc->status);
++	__clear_bit(ATH_STAT_LEDENDBLINK, sc->status);
++	sc->led_off = off;
++	mod_timer(&sc->led_tim, jiffies + on);
++}
++
++static void
++ath5k_led_event(struct ath5k_softc *sc, int event)
++{
++	if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
++		return;
++	if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status)))
++		return; /* don't interrupt active blink */
++	switch (event) {
++	case ATH_LED_TX:
++		ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon,
++			sc->hwmap[sc->led_txrate].ledoff);
++		break;
++	case ATH_LED_RX:
++		ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon,
++			sc->hwmap[sc->led_rxrate].ledoff);
++		break;
++	}
++}
++
++
++
++
++/********************\
++* Mac80211 functions *
++\********************/
++
++static int
++ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
++			struct ieee80211_tx_control *ctl)
++{
++	struct ath5k_softc *sc = hw->priv;
++	struct ath5k_buf *bf;
++	unsigned long flags;
++	int hdrlen;
++	int pad;
++
++	ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
++
++	if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
++		ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
++
++	/*
++	 * the hardware expects the header padded to 4 byte boundaries
++	 * if this is not the case we add the padding after the header
++	 */
++	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
++	if (hdrlen & 3) {
++		pad = hdrlen % 4;
++		if (skb_headroom(skb) < pad) {
++			ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
++				" headroom to pad %d\n", hdrlen, pad);
++			return -1;
++		}
++		skb_push(skb, pad);
++		memmove(skb->data, skb->data+pad, hdrlen);
++	}
++
++	sc->led_txrate = ctl->tx_rate;
++
++	spin_lock_irqsave(&sc->txbuflock, flags);
++	if (list_empty(&sc->txbuf)) {
++		ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
++		spin_unlock_irqrestore(&sc->txbuflock, flags);
++		ieee80211_stop_queue(hw, ctl->queue);
++		return -1;
++	}
++	bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
++	list_del(&bf->list);
++	sc->txbuf_len--;
++	if (list_empty(&sc->txbuf))
++		ieee80211_stop_queues(hw);
++	spin_unlock_irqrestore(&sc->txbuflock, flags);
++
++	bf->skb = skb;
++
++	if (ath5k_txbuf_setup(sc, bf, ctl)) {
++		bf->skb = NULL;
++		spin_lock_irqsave(&sc->txbuflock, flags);
++		list_add_tail(&bf->list, &sc->txbuf);
++		sc->txbuf_len++;
++		spin_unlock_irqrestore(&sc->txbuflock, flags);
++		dev_kfree_skb_any(skb);
++		return 0;
++	}
++
++	return 0;
++}
++
++static int
++ath5k_reset(struct ieee80211_hw *hw)
++{
++	struct ath5k_softc *sc = hw->priv;
++	struct ath5k_hw *ah = sc->ah;
++	int ret;
++
++	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
++	/*
++	 * Convert to a hw channel description with the flags
++	 * constrained to reflect the current operating mode.
++	 */
++	sc->curchan = hw->conf.chan;
++
++	ath5k_hw_set_intr(ah, 0);
++	ath5k_txq_cleanup(sc);
++	ath5k_rx_stop(sc);
++
++	ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
++	if (unlikely(ret)) {
++		ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
++		goto err;
++	}
++	ath5k_hw_set_txpower_limit(sc->ah, 0);
++
++	ret = ath5k_rx_start(sc);
++	if (unlikely(ret)) {
++		ATH5K_ERR(sc, "can't start recv logic\n");
++		goto err;
++	}
++	/*
++	 * We may be doing a reset in response to an ioctl
++	 * that changes the channel so update any state that
++	 * might change as a result.
++	 *
++	 * XXX needed?
++	 */
++/*	ath5k_chan_change(sc, c); */
++	ath5k_beacon_config(sc);
++	/* intrs are started by ath5k_beacon_config */
++
++	ieee80211_wake_queues(hw);
++
++	return 0;
++err:
++	return ret;
++}
++
++static int ath5k_start(struct ieee80211_hw *hw)
++{
++	return ath5k_init(hw->priv);
++}
++
++static void ath5k_stop(struct ieee80211_hw *hw)
++{
++	ath5k_stop_hw(hw->priv);
++}
++
++static int ath5k_add_interface(struct ieee80211_hw *hw,
++		struct ieee80211_if_init_conf *conf)
++{
++	struct ath5k_softc *sc = hw->priv;
++	int ret;
++
++	mutex_lock(&sc->lock);
++	if (sc->iface_id) {
++		ret = 0;
++		goto end;
++	}
++
++	sc->iface_id = conf->if_id;
++
++	switch (conf->type) {
++	case IEEE80211_IF_TYPE_STA:
++	case IEEE80211_IF_TYPE_IBSS:
++	case IEEE80211_IF_TYPE_MNTR:
++		sc->opmode = conf->type;
++		break;
++	default:
++		ret = -EOPNOTSUPP;
++		goto end;
++	}
++	ret = 0;
++end:
++	mutex_unlock(&sc->lock);
++	return ret;
++}
++
++static void
++ath5k_remove_interface(struct ieee80211_hw *hw,
++			struct ieee80211_if_init_conf *conf)
++{
++	struct ath5k_softc *sc = hw->priv;
++
++	mutex_lock(&sc->lock);
++	if (sc->iface_id != conf->if_id)
++		goto end;
++
++	sc->iface_id = 0;
++end:
++	mutex_unlock(&sc->lock);
++}
++
++static int
++ath5k_config(struct ieee80211_hw *hw,
++			struct ieee80211_conf *conf)
++{
++	struct ath5k_softc *sc = hw->priv;
++
++	sc->bintval = conf->beacon_int * 1000 / 1024;
++	ath5k_setcurmode(sc, conf->phymode);
++
++	return ath5k_chan_set(sc, conf->chan);
++}
++
++static int
++ath5k_config_interface(struct ieee80211_hw *hw, int if_id,
++			struct ieee80211_if_conf *conf)
++{
++	struct ath5k_softc *sc = hw->priv;
++	struct ath5k_hw *ah = sc->ah;
++	int ret;
++
++	/* Set to a reasonable value. Note that this will
++	 * be set to mac80211's value at ath5k_config(). */
++	sc->bintval = 1000 * 1000 / 1024;
++	mutex_lock(&sc->lock);
++	if (sc->iface_id != if_id) {
++		ret = -EIO;
++		goto unlock;
++	}
++	if (conf->bssid) {
++		/* Cache for later use during resets */
++		memcpy(ah->bssid, conf->bssid, ETH_ALEN);
++		/* XXX: assoc id is set to 0 for now, mac80211 doesn't have
++		 * a clean way of letting us retrieve this yet. */
++		ath5k_hw_set_associd(ah, ah->bssid, 0);
++	}
++	mutex_unlock(&sc->lock);
++
++	return ath5k_reset(hw);
++unlock:
++	mutex_unlock(&sc->lock);
++	return ret;
++}
++
++#define SUPPORTED_FIF_FLAGS \
++	FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
++	FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
++	FIF_BCN_PRBRESP_PROMISC
++/*
++ * o always accept unicast, broadcast, and multicast traffic
++ * o multicast traffic for all BSSIDs will be enabled if mac80211
++ *   says it should be
++ * o maintain current state of phy ofdm or phy cck error reception.
++ *   If the hardware detects any of these type of errors then
++ *   ath5k_hw_get_rx_filter() will pass to us the respective
++ *   hardware filters to be able to receive these type of frames.
++ * o probe request frames are accepted only when operating in
++ *   hostap, adhoc, or monitor modes
++ * o enable promiscuous mode according to the interface state
++ * o accept beacons:
++ *   - when operating in adhoc mode so the 802.11 layer creates
++ *     node table entries for peers,
++ *   - when operating in station mode for collecting rssi data when
++ *     the station is otherwise quiet, or
++ *   - when scanning
++ */
++static void ath5k_configure_filter(struct ieee80211_hw *hw,
++		unsigned int changed_flags,
++		unsigned int *new_flags,
++		int mc_count, struct dev_mc_list *mclist)
++{
++	struct ath5k_softc *sc = hw->priv;
++	struct ath5k_hw *ah = sc->ah;
++	u32 mfilt[2], val, rfilt;
++	u8 pos;
++	int i;
++
++	mfilt[0] = 0;
++	mfilt[1] = 0;
++
++	/* Only deal with supported flags */
++	changed_flags &= SUPPORTED_FIF_FLAGS;
++	*new_flags &= SUPPORTED_FIF_FLAGS;
++
++	/* If HW detects any phy or radar errors, leave those filters on.
++	 * Also, always enable Unicast, Broadcasts and Multicast
++	 * XXX: move unicast, bssid broadcasts and multicast to mac80211 */
++	rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
++		(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
++		AR5K_RX_FILTER_MCAST);
++
++	if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
++		if (*new_flags & FIF_PROMISC_IN_BSS) {
++			rfilt |= AR5K_RX_FILTER_PROM;
++			__set_bit(ATH_STAT_PROMISC, sc->status);
++		}
++		else
++			__clear_bit(ATH_STAT_PROMISC, sc->status);
++	}
++
++	/* Note, AR5K_RX_FILTER_MCAST is already enabled */
++	if (*new_flags & FIF_ALLMULTI) {
++		mfilt[0] =  ~0;
++		mfilt[1] =  ~0;
++	} else {
++		for (i = 0; i < mc_count; i++) {
++			if (!mclist)
++				break;
++			/* calculate XOR of eight 6-bit values */
++			val = LE_READ_4(mclist->dmi_addr + 0);
++			pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
++			val = LE_READ_4(mclist->dmi_addr + 3);
++			pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
++			pos &= 0x3f;
++			mfilt[pos / 32] |= (1 << (pos % 32));
++			/* XXX: we might be able to just do this instead,
++			* but not sure, needs testing, if we do use this we'd
++			* neet to inform below to not reset the mcast */
++			/* ath5k_hw_set_mcast_filterindex(ah,
++			 *      mclist->dmi_addr[5]); */
++			mclist = mclist->next;
++		}
++	}
++
++	/* This is the best we can do */
++	if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
++		rfilt |= AR5K_RX_FILTER_PHYERR;
++
++	/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
++	* and probes for any BSSID, this needs testing */
++	if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
++		rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ;
++
++	/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
++	 * set we should only pass on control frames for this
++	 * station. This needs testing. I believe right now this
++	 * enables *all* control frames, which is OK.. but
++	 * but we should see if we can improve on granularity */
++	if (*new_flags & FIF_CONTROL)
++		rfilt |= AR5K_RX_FILTER_CONTROL;
++
++	/* Additional settings per mode -- this is per ath5k */
++
++	/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
++
++	if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
++		rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
++			AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
++	if (sc->opmode != IEEE80211_IF_TYPE_STA)
++		rfilt |= AR5K_RX_FILTER_PROBEREQ;
++	if (sc->opmode != IEEE80211_IF_TYPE_AP &&
++		test_bit(ATH_STAT_PROMISC, sc->status))
++		rfilt |= AR5K_RX_FILTER_PROM;
++	if (sc->opmode == IEEE80211_IF_TYPE_STA ||
++		sc->opmode == IEEE80211_IF_TYPE_IBSS) {
++		rfilt |= AR5K_RX_FILTER_BEACON;
++	}
++
++	/* Set filters */
++	ath5k_hw_set_rx_filter(ah,rfilt);
++
++	/* Set multicast bits */
++	ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
++	/* Set the cached hw filter flags, this will alter actually
++	 * be set in HW */
++	sc->filter_flags = rfilt;
++}
++
++static int
++ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
++		const u8 *local_addr, const u8 *addr,
++		struct ieee80211_key_conf *key)
++{
++	struct ath5k_softc *sc = hw->priv;
++	int ret = 0;
++
++	switch(key->alg) {
++	case ALG_WEP:
++		break;
++	case ALG_TKIP:
++	case ALG_CCMP:
++		return -EOPNOTSUPP;
++	default:
++		WARN_ON(1);
++		return -EINVAL;
++	}
++
++	mutex_lock(&sc->lock);
++
++	switch (cmd) {
++	case SET_KEY:
++		ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, addr);
++		if (ret) {
++			ATH5K_ERR(sc, "can't set the key\n");
++			goto unlock;
++		}
++		__set_bit(key->keyidx, sc->keymap);
++		key->hw_key_idx = key->keyidx;
++		break;
++	case DISABLE_KEY:
++		ath5k_hw_reset_key(sc->ah, key->keyidx);
++		__clear_bit(key->keyidx, sc->keymap);
++		break;
++	default:
++		ret = -EINVAL;
++		goto unlock;
++	}
++
++unlock:
++	mutex_unlock(&sc->lock);
++	return ret;
++}
++
++static int
++ath5k_get_stats(struct ieee80211_hw *hw,
++		struct ieee80211_low_level_stats *stats)
++{
++	struct ath5k_softc *sc = hw->priv;
++
++	memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
++
++	return 0;
++}
++
++static int
++ath5k_get_tx_stats(struct ieee80211_hw *hw,
++		struct ieee80211_tx_queue_stats *stats)
++{
++	struct ath5k_softc *sc = hw->priv;
++
++	memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats));
++
++	return 0;
++}
++
++static u64
++ath5k_get_tsf(struct ieee80211_hw *hw)
++{
++	struct ath5k_softc *sc = hw->priv;
++
++	return ath5k_hw_get_tsf64(sc->ah);
++}
++
++static void
++ath5k_reset_tsf(struct ieee80211_hw *hw)
++{
++	struct ath5k_softc *sc = hw->priv;
++
++	ath5k_hw_reset_tsf(sc->ah);
++}
++
++static int
++ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
++			struct ieee80211_tx_control *ctl)
++{
++	struct ath5k_softc *sc = hw->priv;
++	int ret;
++
++	ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
++
++	mutex_lock(&sc->lock);
++
++	if (sc->opmode != IEEE80211_IF_TYPE_IBSS) {
++		ret = -EIO;
++		goto end;
++	}
++
++	ath5k_txbuf_free(sc, sc->bbuf);
++	sc->bbuf->skb = skb;
++	ret = ath5k_beacon_setup(sc, sc->bbuf, ctl);
++	if (ret)
++		sc->bbuf->skb = NULL;
++
++end:
++	mutex_unlock(&sc->lock);
++	return ret;
++}
++
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.c
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/debug.c	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,469 @@
++/*
++ * Copyright (c) 2007 Bruno Randolf <bruno at thinktube.com>
++ *
++ *  This file is free software: you may copy, redistribute and/or modify it
++ *  under the terms of the GNU General Public License as published by the
++ *  Free Software Foundation, either version 2 of the License, or (at your
++ *  option) any later version.
++ *
++ *  This file is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ *
++ * This file incorporates work covered by the following copyright and
++ * permission notice:
++ *
++ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
++ * Copyright (c) 2004-2005 Atheros Communications, Inc.
++ * Copyright (c) 2006 Devicescape Software, Inc.
++ * Copyright (c) 2007 Jiri Slaby <jirislaby at gmail.com>
++ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof at winlab.rutgers.edu>
++ *
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer,
++ *    without modification.
++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
++ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
++ *    redistribution must be conditioned upon including a substantially
++ *    similar Disclaimer requirement for further binary redistribution.
++ * 3. Neither the names of the above-listed copyright holders nor the names
++ *    of any contributors may be used to endorse or promote products derived
++ *    from this software without specific prior written permission.
++ *
++ * Alternatively, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2 as published by the Free
++ * Software Foundation.
++ *
++ * NO WARRANTY
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
++ * THE POSSIBILITY OF SUCH DAMAGES.
++ */
++
++#include "debug.h"
++#include "base.h"
++
++static unsigned int ath5k_debug;
++module_param_named(debug, ath5k_debug, uint, 0);
++
++
++#if ATH5K_DEBUG
++
++#include <linux/seq_file.h>
++#include "reg.h"
++
++static struct dentry *ath5k_global_debugfs;
++
++static int ath5k_debugfs_open(struct inode *inode, struct file *file)
++{
++	file->private_data = inode->i_private;
++	return 0;
++}
++
++
++/* debugfs: registers */
++
++struct reg {
++	char *name;
++	int addr;
++};
++
++#define REG_STRUCT_INIT(r) { #r, r }
++
++/* just a few random registers, might want to add more */
++static struct reg regs[] = {
++	REG_STRUCT_INIT(AR5K_CR),
++	REG_STRUCT_INIT(AR5K_RXDP),
++	REG_STRUCT_INIT(AR5K_CFG),
++	REG_STRUCT_INIT(AR5K_IER),
++	REG_STRUCT_INIT(AR5K_BCR),
++	REG_STRUCT_INIT(AR5K_RTSD0),
++	REG_STRUCT_INIT(AR5K_RTSD1),
++	REG_STRUCT_INIT(AR5K_TXCFG),
++	REG_STRUCT_INIT(AR5K_RXCFG),
++	REG_STRUCT_INIT(AR5K_RXJLA),
++	REG_STRUCT_INIT(AR5K_MIBC),
++	REG_STRUCT_INIT(AR5K_TOPS),
++	REG_STRUCT_INIT(AR5K_RXNOFRM),
++	REG_STRUCT_INIT(AR5K_TXNOFRM),
++	REG_STRUCT_INIT(AR5K_RPGTO),
++	REG_STRUCT_INIT(AR5K_RFCNT),
++	REG_STRUCT_INIT(AR5K_MISC),
++	REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT),
++	REG_STRUCT_INIT(AR5K_ISR),
++	REG_STRUCT_INIT(AR5K_PISR),
++	REG_STRUCT_INIT(AR5K_SISR0),
++	REG_STRUCT_INIT(AR5K_SISR1),
++	REG_STRUCT_INIT(AR5K_SISR2),
++	REG_STRUCT_INIT(AR5K_SISR3),
++	REG_STRUCT_INIT(AR5K_SISR4),
++	REG_STRUCT_INIT(AR5K_IMR),
++	REG_STRUCT_INIT(AR5K_PIMR),
++	REG_STRUCT_INIT(AR5K_SIMR0),
++	REG_STRUCT_INIT(AR5K_SIMR1),
++	REG_STRUCT_INIT(AR5K_SIMR2),
++	REG_STRUCT_INIT(AR5K_SIMR3),
++	REG_STRUCT_INIT(AR5K_SIMR4),
++	REG_STRUCT_INIT(AR5K_DCM_ADDR),
++	REG_STRUCT_INIT(AR5K_DCCFG),
++	REG_STRUCT_INIT(AR5K_CCFG),
++	REG_STRUCT_INIT(AR5K_CPC0),
++	REG_STRUCT_INIT(AR5K_CPC1),
++	REG_STRUCT_INIT(AR5K_CPC2),
++	REG_STRUCT_INIT(AR5K_CPC3),
++	REG_STRUCT_INIT(AR5K_CPCORN),
++	REG_STRUCT_INIT(AR5K_RESET_CTL),
++	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
++	REG_STRUCT_INIT(AR5K_INTPEND),
++	REG_STRUCT_INIT(AR5K_SFR),
++	REG_STRUCT_INIT(AR5K_PCICFG),
++	REG_STRUCT_INIT(AR5K_GPIOCR),
++	REG_STRUCT_INIT(AR5K_GPIODO),
++	REG_STRUCT_INIT(AR5K_SREV),
++};
++
++static void *reg_start(struct seq_file *seq, loff_t *pos)
++{
++	return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
++}
++
++static void reg_stop(struct seq_file *seq, void *p)
++{
++	/* nothing to do */
++}
++
++static void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
++{
++	++*pos;
++	return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
++}
++
++static int reg_show(struct seq_file *seq, void *p)
++{
++	struct ath5k_softc *sc = seq->private;
++	struct reg *r = p;
++	seq_printf(seq, "%-25s0x%08x\n", r->name,
++		ath5k_hw_reg_read(sc->ah, r->addr));
++	return 0;
++}
++
++static struct seq_operations register_seq_ops = {
++	.start = reg_start,
++	.next  = reg_next,
++	.stop  = reg_stop,
++	.show  = reg_show
++};
++
++static int open_file_registers(struct inode *inode, struct file *file)
++{
++	struct seq_file *s;
++	int res;
++	res = seq_open(file, &register_seq_ops);
++	if (res == 0) {
++		s = file->private_data;
++		s->private = inode->i_private;
++	}
++	return res;
++}
++
++static const struct file_operations fops_registers = {
++	.open = open_file_registers,
++	.read    = seq_read,
++	.llseek  = seq_lseek,
++	.release = seq_release,
++	.owner = THIS_MODULE,
++};
++
++
++/* debugfs: TSF */
++
++static ssize_t read_file_tsf(struct file *file, char __user *user_buf,
++				   size_t count, loff_t *ppos)
++{
++	struct ath5k_softc *sc = file->private_data;
++	char buf[100];
++	snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
++	return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
++}
++
++static ssize_t write_file_tsf(struct file *file,
++				 const char __user *userbuf,
++				 size_t count, loff_t *ppos)
++{
++	struct ath5k_softc *sc = file->private_data;
++	if (strncmp(userbuf, "reset", 5) == 0) {
++		ath5k_hw_reset_tsf(sc->ah);
++		printk(KERN_INFO "debugfs reset TSF\n");
++	}
++	return count;
++}
++
++static const struct file_operations fops_tsf = {
++	.read = read_file_tsf,
++	.write = write_file_tsf,
++	.open = ath5k_debugfs_open,
++	.owner = THIS_MODULE,
++};
++
++
++/* debugfs: beacons */
++
++static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
++				   size_t count, loff_t *ppos)
++{
++	struct ath5k_softc *sc = file->private_data;
++	struct ath5k_hw *ah = sc->ah;
++	char buf[1000];
++	int len = 0;
++	unsigned int v;
++	u64 tsf;
++
++	v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON);
++	len += snprintf(buf+len, sizeof(buf)-len,
++		"%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
++		"AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
++		(v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
++
++	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n",
++		"AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP));
++
++	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n",
++		"AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT));
++
++	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0);
++	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
++		"AR5K_TIMER0 (TBTT)", v, v);
++
++	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1);
++	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
++		"AR5K_TIMER1 (DMA)", v, v >> 3);
++
++	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2);
++	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
++		"AR5K_TIMER2 (SWBA)", v, v >> 3);
++
++	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3);
++	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
++		"AR5K_TIMER3 (ATIM)", v, v);
++
++	tsf = ath5k_hw_get_tsf64(sc->ah);
++	len += snprintf(buf+len, sizeof(buf)-len,
++		"TSF\t\t0x%016llx\tTU: %08x\n", tsf, (u32)(tsf >> 10));
++
++	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_beacon(struct file *file,
++				 const char __user *userbuf,
++				 size_t count, loff_t *ppos)
++{
++	struct ath5k_softc *sc = file->private_data;
++	struct ath5k_hw *ah = sc->ah;
++
++	if (strncmp(userbuf, "disable", 7) == 0) {
++		AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
++		printk(KERN_INFO "debugfs disable beacons\n");
++	} else if (strncmp(userbuf, "enable", 6) == 0) {
++		AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
++		printk(KERN_INFO "debugfs enable beacons\n");
++	}
++	return count;
++}
++
++static const struct file_operations fops_beacon = {
++	.read = read_file_beacon,
++	.write = write_file_beacon,
++	.open = ath5k_debugfs_open,
++	.owner = THIS_MODULE,
++};
++
++
++/* debugfs: reset */
++
++static ssize_t write_file_reset(struct file *file,
++				 const char __user *userbuf,
++				 size_t count, loff_t *ppos)
++{
++	struct ath5k_softc *sc = file->private_data;
++	tasklet_schedule(&sc->restq);
++	return count;
++}
++
++static const struct file_operations fops_reset = {
++	.write = write_file_reset,
++	.open = ath5k_debugfs_open,
++	.owner = THIS_MODULE,
++};
++
++
++/* init */
++
++void
++ath5k_debug_init(void)
++{
++	ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL);
++}
++
++void
++ath5k_debug_init_device(struct ath5k_softc *sc)
++{
++	sc->debug.level = ath5k_debug;
++	sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
++			ath5k_global_debugfs);
++	sc->debug.debugfs_debug = debugfs_create_u32("debug",
++			0666, sc->debug.debugfs_phydir, &sc->debug.level);
++
++	sc->debug.debugfs_registers = debugfs_create_file("registers", 0444,
++				sc->debug.debugfs_phydir,
++				sc, &fops_registers);
++
++	sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666,
++				sc->debug.debugfs_phydir,
++				sc, &fops_tsf);
++
++	sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666,
++				sc->debug.debugfs_phydir,
++				sc, &fops_beacon);
++
++	sc->debug.debugfs_reset = debugfs_create_file("reset", 0222,
++				sc->debug.debugfs_phydir,
++				sc, &fops_reset);
++}
++
++void
++ath5k_debug_finish(void)
++{
++	debugfs_remove(ath5k_global_debugfs);
++}
++
++void
++ath5k_debug_finish_device(struct ath5k_softc *sc)
++{
++	debugfs_remove(sc->debug.debugfs_debug);
++	debugfs_remove(sc->debug.debugfs_registers);
++	debugfs_remove(sc->debug.debugfs_tsf);
++	debugfs_remove(sc->debug.debugfs_beacon);
++	debugfs_remove(sc->debug.debugfs_reset);
++	debugfs_remove(sc->debug.debugfs_phydir);
++}
++
++
++/* functions used in other places */
++
++void
++ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes)
++{
++	unsigned int m, i;
++
++	if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES)))
++		return;
++
++	for (m = 0; m < NUM_DRIVER_MODES; m++) {
++		printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m,
++				modes[m].num_channels, modes[m].num_rates);
++		printk(KERN_DEBUG " channels:\n");
++		for (i = 0; i < modes[m].num_channels; i++)
++			printk(KERN_DEBUG "  %3d %d %.4x %.4x\n",
++					modes[m].channels[i].chan,
++					modes[m].channels[i].freq,
++					modes[m].channels[i].val,
++					modes[m].channels[i].flag);
++		printk(KERN_DEBUG " rates:\n");
++		for (i = 0; i < modes[m].num_rates; i++)
++			printk(KERN_DEBUG "  %4d %.4x %.4x %.4x\n",
++					modes[m].rates[i].rate,
++					modes[m].rates[i].val,
++					modes[m].rates[i].flags,
++					modes[m].rates[i].val2);
++	}
++}
++
++static inline void
++ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done)
++{
++	struct ath5k_desc *ds = bf->desc;
++
++	printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
++		ds, (unsigned long long)bf->daddr,
++		ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
++		ds->ds_hw[0], ds->ds_hw[1],
++		!done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!');
++}
++
++void
++ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
++{
++	struct ath5k_desc *ds;
++	struct ath5k_buf *bf;
++	int status;
++
++	if (likely(!(sc->debug.level &
++	    (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL))))
++		return;
++
++	printk(KERN_DEBUG "rx queue %x, link %p\n",
++		ath5k_hw_get_rx_buf(ah), sc->rxlink);
++
++	spin_lock_bh(&sc->rxbuflock);
++	list_for_each_entry(bf, &sc->rxbuf, list) {
++		ds = bf->desc;
++		status = ah->ah_proc_rx_desc(ah, ds);
++		if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL))
++			ath5k_debug_printrxbuf(bf, status == 0);
++	}
++	spin_unlock_bh(&sc->rxbuflock);
++}
++
++void
++ath5k_debug_dump_skb(struct ath5k_softc *sc,
++			struct sk_buff *skb, const char *prefix, int tx)
++{
++	char buf[16];
++
++	if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) ||
++		     (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX)))))
++		return;
++
++	snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix);
++
++	print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data,
++		min(200U, skb->len));
++
++	printk(KERN_DEBUG "\n");
++}
++
++void
++ath5k_debug_printtxbuf(struct ath5k_softc *sc,
++			struct ath5k_buf *bf, int done)
++{
++	struct ath5k_desc *ds = bf->desc;
++
++	if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
++		return;
++
++	printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
++		"%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
++		ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
++		ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3],
++		!done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!');
++}
++
++#endif /* if ATH5K_DEBUG */
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.h
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/base.h	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,178 @@
++/*-
++ * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer,
++ *    without modification.
++ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
++ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
++ *    redistribution must be conditioned upon including a substantially
++ *    similar Disclaimer requirement for further binary redistribution.
++ * 3. Neither the names of the above-listed copyright holders nor the names
++ *    of any contributors may be used to endorse or promote products derived
++ *    from this software without specific prior written permission.
++ *
++ * Alternatively, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2 as published by the Free
++ * Software Foundation.
++ *
++ * NO WARRANTY
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
++ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
++ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
++ * THE POSSIBILITY OF SUCH DAMAGES.
++ *
++ */
++
++/*
++ * Defintions for the Atheros Wireless LAN controller driver.
++ */
++#ifndef _DEV_ATH_ATHVAR_H
++#define _DEV_ATH_ATHVAR_H
++
++#include <linux/interrupt.h>
++#include <linux/list.h>
++#include <linux/wireless.h>
++#include <linux/if_ether.h>
++
++#include "ath5k.h"
++#include "debug.h"
++
++#define	ATH_RXBUF	40		/* number of RX buffers */
++#define	ATH_TXBUF	200		/* number of TX buffers */
++#define ATH_BCBUF	1		/* number of beacon buffers */
++
++struct ath5k_buf {
++	struct list_head	list;
++	unsigned int		flags;	/* tx descriptor flags */
++	struct ath5k_desc		*desc;	/* virtual addr of desc */
++	dma_addr_t		daddr;	/* physical addr of desc */
++	struct sk_buff		*skb;	/* skbuff for buf */
++	dma_addr_t		skbaddr;/* physical addr of skb data */
++	struct ieee80211_tx_control ctl;
++};
++
++/*
++ * Data transmit queue state.  One of these exists for each
++ * hardware transmit queue.  Packets sent to us from above
++ * are assigned to queues based on their priority.  Not all
++ * devices support a complete set of hardware transmit queues.
++ * For those devices the array sc_ac2q will map multiple
++ * priorities to fewer hardware queues (typically all to one
++ * hardware queue).
++ */
++struct ath5k_txq {
++	unsigned int	qnum;		/* hardware q number */
++	u32		*link;		/* link ptr in last TX desc */
++	struct list_head q;		/* transmit queue */
++	spinlock_t	lock;		/* lock on q and link */
++	bool		setup;
++};
++
++#if CHAN_DEBUG
++#define ATH_CHAN_MAX	(26+26+26+200+200)
++#else
++#define ATH_CHAN_MAX	(14+14+14+252+20)	/* XXX what's the max? */
++#endif
++
++/* Software Carrier, keeps track of the driver state
++ * associated with an instance of a device */
++struct ath5k_softc {
++	struct pci_dev		*pdev;		/* for dma mapping */
++	void __iomem		*iobase;	/* address of the device */
++	struct mutex		lock;		/* dev-level lock */
++	struct ieee80211_tx_queue_stats tx_stats;
++	struct ieee80211_low_level_stats ll_stats;
++	struct ieee80211_hw	*hw;		/* IEEE 802.11 common */
++	struct ieee80211_hw_mode modes[NUM_DRIVER_MODES];
++	struct ieee80211_channel channels[ATH_CHAN_MAX];
++	struct ieee80211_rate	rates[AR5K_MAX_RATES * NUM_DRIVER_MODES];
++	enum ieee80211_if_types	opmode;
++	struct ath5k_hw		*ah;		/* Atheros HW */
++
++#if ATH5K_DEBUG
++	struct ath5k_dbg_info	debug;		/* debug info */
++#endif
++
++	struct ath5k_buf	*bufptr;	/* allocated buffer ptr */
++	struct ath5k_desc	*desc;		/* TX/RX descriptors */
++	dma_addr_t		desc_daddr;	/* DMA (physical) address */
++	size_t			desc_len;	/* size of TX/RX descriptors */
++	u16			cachelsz;	/* cache line size */
++
++	DECLARE_BITMAP(status, 6);
++#define ATH_STAT_INVALID	0		/* disable hardware accesses */
++#define ATH_STAT_MRRETRY	1		/* multi-rate retry support */
++#define ATH_STAT_PROMISC	2
++#define ATH_STAT_LEDBLINKING	3		/* LED blink operation active */
++#define ATH_STAT_LEDENDBLINK	4		/* finish LED blink operation */
++#define ATH_STAT_LEDSOFT	5		/* enable LED gpio status */
++
++	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
++	unsigned int		curmode;	/* current phy mode */
++	struct ieee80211_channel *curchan;	/* current h/w channel */
++
++	int 			iface_id;	/* add/remove_interface id */
++
++	struct {
++		u8	rxflags;	/* radiotap rx flags */
++		u8	txflags;	/* radiotap tx flags */
++		u16	ledon;		/* softled on time */
++		u16	ledoff;		/* softled off time */
++	} hwmap[32];				/* h/w rate ix mappings */
++
++	enum ath5k_int		imask;		/* interrupt mask copy */
++
++	DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
++
++	u8			bssidmask[ETH_ALEN];
++
++	unsigned int		led_pin,	/* GPIO pin for driving LED */
++				led_on,		/* pin setting for LED on */
++				led_off;	/* off time for current blink */
++	struct timer_list	led_tim;	/* led off timer */
++	u8			led_rxrate;	/* current rx rate for LED */
++	u8			led_txrate;	/* current tx rate for LED */
++
++	struct tasklet_struct	restq;		/* reset tasklet */
++
++	unsigned int		rxbufsize;	/* rx size based on mtu */
++	struct list_head	rxbuf;		/* receive buffer */
++	spinlock_t		rxbuflock;
++	u32			*rxlink;	/* link ptr in last RX desc */
++	struct tasklet_struct	rxtq;		/* rx intr tasklet */
++
++	struct list_head	txbuf;		/* transmit buffer */
++	spinlock_t		txbuflock;
++	unsigned int		txbuf_len;	/* buf count in txbuf list */
++	struct ath5k_txq	txqs[2];	/* beacon and tx */
++
++	struct ath5k_txq	*txq;		/* beacon and tx*/
++	struct tasklet_struct	txtq;		/* tx intr tasklet */
++
++	struct ath5k_buf	*bbuf;		/* beacon buffer */
++	unsigned int		bhalq,		/* SW q for outgoing beacons */
++				bmisscount,	/* missed beacon transmits */
++				bintval,	/* beacon interval */
++				bsent;
++
++	struct timer_list	calib_tim;	/* calibration timer */
++};
++
++#define ath5k_hw_hasbssidmask(_ah) \
++	(ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0)
++#define ath5k_hw_hasveol(_ah) \
++	(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
++
++#endif
+diff -up /dev/null linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.c
+--- /dev/null	2007-12-21 08:33:07.834165456 -0500
++++ linux-2.6.23.noarch/drivers/net/wireless/ath5k/regdom.c	2007-12-21 12:18:50.000000000 -0500
+@@ -0,0 +1,121 @@
++/*
++ * Copyright (c) 2004, 2005 Reyk Floeter <reyk at vantronix.net>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Basic regulation domain extensions for the IEEE 802.11 stack
++ */
++
++#include <linux/kernel.h>
++#include <linux/string.h>
++
++#include "regdom.h"
++
++static const struct ath5k_regdommap {
++	enum ath5k_regdom dmn;
++	enum ath5k_regdom dmn5;
++	enum ath5k_regdom dmn2;
++} r_map[] = {
++	{ DMN_DEFAULT,		DMN_DEBUG,	DMN_DEBUG },
++	{ DMN_NULL_WORLD,	DMN_NULL,	DMN_WORLD },
++	{ DMN_NULL_ETSIB,	DMN_NULL,	DMN_ETSIB },
++	{ DMN_NULL_ETSIC,	DMN_NULL,	DMN_ETSIC },
++	{ DMN_FCC1_FCCA,	DMN_FCC1,	DMN_FCCA },
++	{ DMN_FCC1_WORLD,	DMN_FCC1,	DMN_WORLD },
++	{ DMN_FCC2_FCCA,	DMN_FCC2,	DMN_FCCA },
++	{ DMN_FCC2_WORLD,	DMN_FCC2,	DMN_WORLD },
++	{ DMN_FCC2_ETSIC,	DMN_FCC2,	DMN_ETSIC },
++	{ DMN_FRANCE_NULL,	DMN_ETSI3,	DMN_ETSI3 },
++	{ DMN_FCC3_FCCA,	DMN_FCC3,	DMN_WORLD },
++	{ DMN_ETSI1_WORLD,	DMN_ETSI1,	DMN_WORLD },
++	{ DMN_ETSI3_ETSIA,	DMN_ETSI3,	DMN_WORLD },
++	{ DMN_ETSI2_WORLD,	DMN_ETSI2,	DMN_WORLD },
++	{ DMN_ETSI3_WORLD,	DMN_ETSI3,	DMN_WORLD },
++	{ DMN_ETSI4_WORLD,	DMN_ETSI4,	DMN_WORLD },
++	{ DMN_ETSI4_ETSIC,	DMN_ETSI4,	DMN_ETSIC },
++	{ DMN_ETSI5_WORLD,	DMN_ETSI5,	DMN_WORLD },
++	{ DMN_ETSI6_WORLD,	DMN_ETSI6,	DMN_WORLD },
++	{ DMN_ETSI_NULL,	DMN_ETSI1,	DMN_ETSI1 },
++	{ DMN_MKK1_MKKA,	DMN_MKK1,	DMN_MKKA },
++	{ DMN_MKK1_MKKB,	DMN_MKK1,	DMN_MKKA },
++	{ DMN_APL4_WORLD,	DMN_APL4,	DMN_WORLD },
++	{ DMN_MKK2_MKKA,	DMN_MKK2,	DMN_MKKA },
++	{ DMN_APL_NULL,		DMN_APL1,	DMN_NULL },
++	{ DMN_APL2_WORLD,	DMN_APL2,	DMN_WORLD },
++	{ DMN_APL2_APLC,	DMN_APL2,	DMN_WORLD },
++	{ DMN_APL3_WORLD,	DMN_APL3,	DMN_WORLD },
++	{ DMN_MKK1_FCCA,	DMN_MKK1,	DMN_FCCA },
++	{ DMN_APL2_APLD,	DMN_APL2,	DMN_APLD },
++	{ DMN_MKK1_MKKA1,	DMN_MKK1,	DMN_MKKA },
++	{ DMN_MKK1_MKKA2,	DMN_MKK1,	DMN_MKKA },
++	{ DMN_APL1_WORLD,	DMN_APL1,	DMN_WORLD },
++	{ DMN_APL1_FCCA,	DMN_APL1,	DMN_FCCA },
++	{ DMN_APL1_APLA,	DMN_APL1,	DMN_WORLD },
++	{ DMN_APL1_ETSIC,	DMN_APL1,	DMN_ETSIC },
++	{ DMN_APL2_ETSIC,	DMN_APL2,	DMN_ETSIC },
++	{ DMN_APL5_WORLD,	DMN_APL5,	DMN_WORLD },
++	{ DMN_WOR0_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WOR1_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WOR2_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WOR3_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WOR4_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WOR5_ETSIC,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WOR01_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WOR02_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_EU1_WORLD,	DMN_ETSI1,	DMN_WORLD },
++	{ DMN_WOR9_WORLD,	DMN_WORLD,	DMN_WORLD },
++	{ DMN_WORA_WORLD,	DMN_WORLD,	DMN_WORLD },
++};
++
++enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom dmn, u16 mhz)
++{
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(r_map); i++) {
++		if (r_map[i].dmn == dmn) {
++			if (mhz >= 2000 && mhz <= 3000)
++				return r_map[i].dmn2;
++			if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN &&
++					mhz <= IEEE80211_CHANNELS_5GHZ_MAX)
++				return r_map[i].dmn5;
++		}
++	}
++
++	return DMN_DEBUG;
++}
++
++u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee)
++{
++	u32 regdomain = (u32)ieee;
++
++	/*
++	 * Use the default regulation domain if the value is empty
++	 * or not supported by the net80211 regulation code.
++	 */
++	if (ath5k_regdom2flag(regdomain, IEEE80211_CHANNELS_5GHZ_MIN) ==
++			DMN_DEBUG)
++		return (u16)AR5K_TUNE_REGDOMAIN;
++
++	/* It is supported, just return the value */
++	return regdomain;
++}
++
++enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain)
++{
++	enum ath5k_regdom ieee = (enum ath5k_regdom)regdomain;
++
++	return ieee;
++}
++

Modified: dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	(original)
+++ dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	Sun Jan  6 23:52:40 2008
@@ -40,3 +40,4 @@
 + bugfix/arm/disable-scsi_acard.patch
 + bugfix/all/git-ieee1394.patch
 + features/at76.patch
++ features/ath5k.patch



More information about the Kernel-svn-changes mailing list