summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreisnerd <eisnerd@localhost>2008-06-09 08:02:11 +0000
committereisnerd <eisnerd@localhost>2008-06-09 08:02:11 +0000
commit06555b1f440bd336a2dedf91ee86c4b64a3dbd1c (patch)
tree113f61dfd69f4787d191c46574340effa02637ec /sys-kernel
parentx11-drivers/xf86-video-radeonhd: Add DRI useflag (diff)
downloadjokey-06555b1f440bd336a2dedf91ee86c4b64a3dbd1c.tar.gz
jokey-06555b1f440bd336a2dedf91ee86c4b64a3dbd1c.tar.bz2
jokey-06555b1f440bd336a2dedf91ee86c4b64a3dbd1c.zip
bump to 2.6.25-r1 more powersaving and bay is working now
svn path=/trunk/; revision=425
Diffstat (limited to 'sys-kernel')
-rw-r--r--sys-kernel/thinkpad-sources/ChangeLog25
-rw-r--r--sys-kernel/thinkpad-sources/Manifest33
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.24-r1/colored-printk-output-2.6.24.patch347
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.24-r1/iwlwifi-leds-v2-2.6.24-rc4.diff532
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.24-r3/disk-protect-fix-for-2.6.24.patch22
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/00-bay-cleanup_exit-for-2.6.25.patch41
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/01-disk-protect-for-2.6.25.patch (renamed from sys-kernel/thinkpad-sources/files/2.6.24/disk-protect-for-2.6.24.patch)344
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/02-ipw2200-inject-for-2.6.25.patch77
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/03-libata-acpi_hotplug_fixups-for-2.6.25.patch215
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/04-linux-phc-0.3.1-for-2.6.25.patch (renamed from sys-kernel/thinkpad-sources/files/2.6.24/linux-phc-0.3.1-for-2.6.24-rc1.patch)26
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part1.patch113
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part2.patch220
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part3.patch146
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-export-init_mm.patch11
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-rcu-license.patch20
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/linux-2.6.25-iwl-merge.patch124255
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/pci-e_aspm_v3.5.patch (renamed from sys-kernel/thinkpad-sources/files/2.6.24-r1/pci-e_aspm_v3.patch)386
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/power-off-unused-ports.patch129
-rw-r--r--sys-kernel/thinkpad-sources/files/2.6.25-r1/vt-fix.patch146
-rw-r--r--sys-kernel/thinkpad-sources/files/configs/config-for-core-2.6.25-r1 (renamed from sys-kernel/thinkpad-sources/files/configs/config-for-core-2.6.24-r3)302
-rw-r--r--sys-kernel/thinkpad-sources/thinkpad-sources-2.6.25-r1.ebuild (renamed from sys-kernel/thinkpad-sources/thinkpad-sources-2.6.24-r4.ebuild)45
21 files changed, 126070 insertions, 1365 deletions
diff --git a/sys-kernel/thinkpad-sources/ChangeLog b/sys-kernel/thinkpad-sources/ChangeLog
index 9b2af2c..97bbe11 100644
--- a/sys-kernel/thinkpad-sources/ChangeLog
+++ b/sys-kernel/thinkpad-sources/ChangeLog
@@ -1,5 +1,30 @@
+ 09 Jun 2008; Florian Manschwetus <FlorianManschwetus@gmx.de>
+ -files/2.6.24/linux-phc-0.3.1-for-2.6.24-rc1.patch,
+ +files/2.6.25-r1/04-linux-phc-0.3.1-for-2.6.25.patch, -files/2.6.24-r1,
+ +files/2.6.25-r1/vt-fix.patch, -files/configs/config-for-core-2.6.24-r3,
+ -files/2.6.24-r3/disk-protect-fix-for-2.6.24.patch,
+ -files/2.6.24-r1/pci-e_aspm_v3.patch, -thinkpad-sources-2.6.24-r4.ebuild,
+ +thinkpad-sources-2.6.25-r1.ebuild, +files/2.6.25-r1,
+ -files/2.6.24-r1/iwlwifi-leds-v2-2.6.24-rc4.diff,
+ -files/2.6.24/disk-protect-for-2.6.24.patch,
+ -files/2.6.24-r1/colored-printk-output-2.6.24.patch,
+ +files/configs/config-for-core-2.6.25-r1,
+ +files/2.6.25-r1/linux-2.6.25-iwl-merge.patch, -files/2.6.24,
+ +files/2.6.25-r1/kernel-2.6.25-export-init_mm.patch,
+ +files/2.6.25-r1/kernel-2.6.25-rcu-license.patch,
+ +files/2.6.25-r1/colored-printk-2.6.25.part2.patch, -files/2.6.24-r3,
+ +files/2.6.25-r1/power-off-unused-ports.patch,
+ +files/2.6.25-r1/colored-printk-2.6.25.part1.patch,
+ +files/2.6.25-r1/colored-printk-2.6.25.part3.patch,
+ +files/2.6.25-r1/03-libata-acpi_hotplug_fixups-for-2.6.25.patch,
+ +files/2.6.25-r1/00-bay-cleanup_exit-for-2.6.25.patch,
+ +files/2.6.25-r1/01-disk-protect-for-2.6.25.patch,
+ +files/2.6.25-r1/pci-e_aspm_v3.5.patch,
+ +files/2.6.25-r1/02-ipw2200-inject-for-2.6.25.patch:
+ Bump to 2.6.25-r1 more powersaving and bay is working
+
16 May 2008; Florian Manschwetus <FlorianManschwetus@gmx.de>
-thinkpad-sources-2.6.24-r3.ebuild, +thinkpad-sources-2.6.25.ebuild,
+files/2.6.25/kernel-2.6.25-export-init_mm.patch,
diff --git a/sys-kernel/thinkpad-sources/Manifest b/sys-kernel/thinkpad-sources/Manifest
index b990062..92f0d6c 100644
--- a/sys-kernel/thinkpad-sources/Manifest
+++ b/sys-kernel/thinkpad-sources/Manifest
@@ -1,9 +1,17 @@
-AUX 2.6.24-r1/colored-printk-output-2.6.24.patch 11150 RMD160 b16121f94651256d561ee0d7af8e910f76a4ac32 SHA1 635d332e0e13aa3c492f4dd65ea1dc696a7ec99c SHA256 7868c3ea8550b66d1c31aa71a19725ad5198d4e63767410465747e6a23f03e3d
-AUX 2.6.24-r1/iwlwifi-leds-v2-2.6.24-rc4.diff 14641 RMD160 1dd66b789095ee7b66a1bbc2a460b88f5b34ff98 SHA1 0f4b5127db2b0bd8bb244edba1cba389fff0bc9b SHA256 ab9ba7cebf01f2b060a0c852ada40fdbd9940b81e6e335db7dd33bd58c2d3932
-AUX 2.6.24-r1/pci-e_aspm_v3.patch 30672 RMD160 6533c11e2e8b8b7f092488b193e9b31ff432f5ab SHA1 39ca821c88c9fa0500a958d76c83b676e5885fb7 SHA256 88174311c4c5a95b16534f4174fb7782a359d5f076f6f5c081e414ba21f90902
-AUX 2.6.24-r3/disk-protect-fix-for-2.6.24.patch 723 RMD160 93670c5310ff7e2cd2fd33367756fec91f1ce7fc SHA1 7d896adf370dbdef73e39a1b58a0cc66be337483 SHA256 5f755833a64abd8d9ef2a5a060b40f22478e13ee91c2722cc2161f87a80bec01
-AUX 2.6.24/disk-protect-for-2.6.24.patch 26920 RMD160 6ec7ac0b4c56ba15d0bc66cfe1c2ec71263cfbd0 SHA1 917c4d0f3620227f61e399a73bbedf6ec227e357 SHA256 bf831e5a068ffbf4182974287c600646afee84878c12697da05f8bca440ae22e
-AUX 2.6.24/linux-phc-0.3.1-for-2.6.24-rc1.patch 15425 RMD160 a1317ed8dabde11a1abde5887d972912bb8130b3 SHA1 4c31ff80c16ab0238e6fa254507d79f11e301241 SHA256 0789f27d86f8aa580d628ce0190eb50a0232678107f85d63819ba09a435ff057
+AUX 2.6.25-r1/00-bay-cleanup_exit-for-2.6.25.patch 1406 RMD160 5af97e44a193cfd3383e5719c708ad98249f2f7f SHA1 a147ba8383c9b2bd93125d3e8d52bda906c21fb2 SHA256 ed14a40a797b08ab08974af93af17d971bf056dee6c5a70d7cc82398ff37e6e3
+AUX 2.6.25-r1/01-disk-protect-for-2.6.25.patch 28041 RMD160 db29875229b28a95c68c1da982727a4e08f105ab SHA1 4799500b74091173d1c1f17a6f7df668f800a400 SHA256 a6ce92c1eac576709e4dd067663f6fed427dd7721b2633b1d954301300cb38b7
+AUX 2.6.25-r1/02-ipw2200-inject-for-2.6.25.patch 2182 RMD160 da365e1a73901e813ec9e73caca385dd5290d7b4 SHA1 67528e54a48288edee6f6c1642d73dee7a4146d2 SHA256 2e1016a2ebbde01ba34ea60b86ceec9082399afaaab0fd5ad03546a9a6b197e9
+AUX 2.6.25-r1/03-libata-acpi_hotplug_fixups-for-2.6.25.patch 5551 RMD160 437f60ab5e64bccfbe61872e09391cc7db10017e SHA1 6f630f7fe97927699d86501c2d893c5e03303cb3 SHA256 f2fa74439cdc5da81c053b2e6dc67b0b2b56bc7fa863f965c957ac3fc71ee43c
+AUX 2.6.25-r1/04-linux-phc-0.3.1-for-2.6.25.patch 15389 RMD160 2c33673ff0ec9021c1ec214b022fe73900c2811a SHA1 292f4a9874cb5905ef4feb06bfbcbc07e8dcdfca SHA256 1c00c0b22116b59bb4f77e5dcaad649120ad100eb4fded50924e76279d965049
+AUX 2.6.25-r1/colored-printk-2.6.25.part1.patch 3151 RMD160 15417414247874e7c47bc0ac44a1eb9565bebfae SHA1 5edeca7d5f8625f8fadcdfbdbac2d3480cba8d2c SHA256 290afd26e79fc4493de29ea20e86ea92f809da1e3db6c2e8a0edf9e0455fcea8
+AUX 2.6.25-r1/colored-printk-2.6.25.part2.patch 7972 RMD160 4ecc61abcf310a6013124fc1a49d046d7ab11fd6 SHA1 60a14368c01148f9ead5b4fe682d36e24a9e8933 SHA256 bbbff7947588f222610bd75be772351f9de08eb3df3ce4be20153bac7759578f
+AUX 2.6.25-r1/colored-printk-2.6.25.part3.patch 4150 RMD160 c1ffc2b7d28ac86b167179b9793bc2971648118d SHA1 4d8ee860b0d0b0951b34414f2591e725d88aa53a SHA256 e12e2aedff58baa521523160ad8a16fca8372b347c147d1c16263d3b6c79aab9
+AUX 2.6.25-r1/kernel-2.6.25-export-init_mm.patch 527 RMD160 09470465828a58d09f6a924e51ea9b34754cf108 SHA1 c0790545008f44287e8b8264c5d9919bf372e6c8 SHA256 4be986289e4032eecc8909cf636d3e47e66044d9bc40d36f4e10f8ba472ef203
+AUX 2.6.25-r1/kernel-2.6.25-rcu-license.patch 492 RMD160 375a45f3b55a6e591c872eb3213b1cb7d3f9cb3f SHA1 1aa76913d07870967fccc4deb235619ca2ce7297 SHA256 1e27b7522dd0a2ac2ee6913c4a1a403eff7e2652b9dfd4625f657f5ff2f8a75f
+AUX 2.6.25-r1/linux-2.6.25-iwl-merge.patch 3805877 RMD160 45f9a15c4dfc543b00132d2578327cb3184576a1 SHA1 5fa038f7a24d97f0b42bef54efb3857849ff9456 SHA256 409a56f78699c3386ebd7945940a36acf212d340ef5367aa5e4a567b5e762766
+AUX 2.6.25-r1/pci-e_aspm_v3.5.patch 32683 RMD160 8e126c0894d85f508ac190a6fecaa45fb7c56875 SHA1 697401cab1315e1c9025b8c17d0cfc78c59d2cda SHA256 89bf8956cc6cc0720bf0dad7107691a5bc5bd33da35fab1909e9f59f08e9ae5b
+AUX 2.6.25-r1/power-off-unused-ports.patch 4600 RMD160 9131091dee1ebe30259a0bce728206f0c36bd2a3 SHA1 4e15bb31848a503a3986b34eb22c6eb3b2efde2d SHA256 2621c0affed9e0ec966192ccfcc9b68644e68985434b0512202c849c44fe23c0
+AUX 2.6.25-r1/vt-fix.patch 6046 RMD160 6c018e117029867928713f9c1577f70a32a8541c SHA1 9da5b59769ead4d971def7a26d98cae3741f2474 SHA256 4e62d4467e3c11f3f3e37787e583ffefe333cbdf367cae2fef384673dcd31d47
AUX 2.6.25/02-disk-protect-for-2.6.25.patch 28041 RMD160 db29875229b28a95c68c1da982727a4e08f105ab SHA1 4799500b74091173d1c1f17a6f7df668f800a400 SHA256 a6ce92c1eac576709e4dd067663f6fed427dd7721b2633b1d954301300cb38b7
AUX 2.6.25/03-ipw2200-inject-for-2.6.25.patch 2182 RMD160 da365e1a73901e813ec9e73caca385dd5290d7b4 SHA1 67528e54a48288edee6f6c1642d73dee7a4146d2 SHA256 2e1016a2ebbde01ba34ea60b86ceec9082399afaaab0fd5ad03546a9a6b197e9
AUX 2.6.25/04-linux-phc-0.3.1-for-2.6.25.patch 15389 RMD160 2c33673ff0ec9021c1ec214b022fe73900c2811a SHA1 292f4a9874cb5905ef4feb06bfbcbc07e8dcdfca SHA256 1c00c0b22116b59bb4f77e5dcaad649120ad100eb4fded50924e76279d965049
@@ -14,19 +22,16 @@ AUX 2.6.25/kernel-2.6.25-export-init_mm.patch 527 RMD160 09470465828a58d09f6a924
AUX 2.6.25/kernel-2.6.25-rcu-license.patch 492 RMD160 375a45f3b55a6e591c872eb3213b1cb7d3f9cb3f SHA1 1aa76913d07870967fccc4deb235619ca2ce7297 SHA256 1e27b7522dd0a2ac2ee6913c4a1a403eff7e2652b9dfd4625f657f5ff2f8a75f
AUX 2.6.25/pci-e_aspm_v3.5.patch 32683 RMD160 8e126c0894d85f508ac190a6fecaa45fb7c56875 SHA1 697401cab1315e1c9025b8c17d0cfc78c59d2cda SHA256 89bf8956cc6cc0720bf0dad7107691a5bc5bd33da35fab1909e9f59f08e9ae5b
AUX 2.6.25/vt-fix.patch 6046 RMD160 6c018e117029867928713f9c1577f70a32a8541c SHA1 9da5b59769ead4d971def7a26d98cae3741f2474 SHA256 4e62d4467e3c11f3f3e37787e583ffefe333cbdf367cae2fef384673dcd31d47
-AUX configs/config-for-core-2.6.24-r3 54230 RMD160 f8e14cb7ced5f2c4686e0ca71f4af7fd50a52ef7 SHA1 fd96216727e11ade2f60fd59c6bb0ca573aa2111 SHA256 d07ea05322d46d0c26a7ed15c557d48628c1a60bd68204f8a9829c961ed70639
AUX configs/config-for-core-2.6.25 57068 RMD160 1cab7fb18d023e9aabd0df30db4a4825ee52eee2 SHA1 5b6ec9e157213243e444e1f899d1a097946a1eb7 SHA256 3b35429771d0f11d57c1ee57f5fee1db15622e7c1533f6330f6fd6e47945e190
-DIST genpatches-2.6.24-4.base.tar.bz2 39369 RMD160 c6c0bd063edbd4a2d1606cc53580530e6b0e01c4 SHA1 b6e0d72b5d452648ca3f33a529e4b6a063b10ed7 SHA256 bae9b6d932d18089283ca5ec4a8999b888dbf8d5ae3f5be8302c823f14b6f082
-DIST genpatches-2.6.24-4.extras.tar.bz2 43587 RMD160 a41366bb7372c168d4ede2de420256e25560122c SHA1 3a048660019206344a065beaa8dbaadbfa0a7f3b SHA256 8cee70233f609bd01c1645e9cb90c4637ee6f989b4583d652ea2df57a8894296
+AUX configs/config-for-core-2.6.25-r1 57094 RMD160 f01c3aa0c94167bbdfcf83a7beb07d580c6a9896 SHA1 034bd829217395ba7fca5b1a12610f42e414c99e SHA256 79a765bff651f66342d3487a93b35b0290f3c40720f2eb92f0e25789474577f1
DIST genpatches-2.6.25-4.base.tar.bz2 22088 RMD160 fd3a402ac7bd0f5fd7b623571b3e0452beb90fb3 SHA1 28c320f763160a428b466c4cdec3da7d17145e03 SHA256 7898eda702de503afe70b8d36e0594623453457cfa3fb7eabdd2b44de7f88fb0
DIST genpatches-2.6.25-4.extras.tar.bz2 41717 RMD160 bc2f220a944f701d944061f11d633f2301139ccc SHA1 79d093c93ff1c76e98bff174d5b3c603cd1f0d7e SHA256 0cc8eaab5e746a7b514ee6c86e6ae986618ae4929c0a0c4a8e6098c9d3a43eae
-DIST linux-2.6.24.tar.bz2 46737783 RMD160 0e5194c69c3d82c41ece689c4f84e638f8776d34 SHA1 351aebc784a5395fe4c92d1e514a89680482f7e2 SHA256 413c64fbbcf81244cb5571be4963644a1e81166a2b0f008a016528363b65c5d3
+DIST genpatches-2.6.25-5.base.tar.bz2 43426 RMD160 f5350e3a3113fe3400ec7fc35541513b70681fea SHA1 06c2a7c9224507e89736f918bc9ca8caf6b36194 SHA256 9633e3480434abe8426465213b8af88cee3f2af015c12ebb7a0fdbe01ed45c1d
+DIST genpatches-2.6.25-5.extras.tar.bz2 41717 RMD160 bc2f220a944f701d944061f11d633f2301139ccc SHA1 79d093c93ff1c76e98bff174d5b3c603cd1f0d7e SHA256 0cc8eaab5e746a7b514ee6c86e6ae986618ae4929c0a0c4a8e6098c9d3a43eae
DIST linux-2.6.25.tar.bz2 48601689 RMD160 cf3ed52f888fe9df7a93abe4fdc2f598e1ba0ce4 SHA1 aa6187a1c212dd2d8bd906b023fcefdcf711f35e SHA256 108b2a3f2b05c0e57d1d0977619525e46f8d4b425aef4b38b47dcf94292f2dd2
-DIST thinkpad-acpi-0.19-20080229_v2.6.24.3.patch.gz 41763 RMD160 bdcea1df691197351b60ad0721f0fd6c9cf36d7f SHA1 0e88d4223908e6c837576b3f986c8ebd94d9b9bc SHA256 5b5d6a2fc9da5ccf0dddec0ac470deb88b6adb5f2606015672c9f79120569e13
DIST thinkpad-acpi-0.20-20080430_v2.6.25.1.patch.gz 14918 RMD160 ed6e3b8b686fe95b68536ef29359d82967542860 SHA1 bd92ed2559b03b09519ddf37cea73a1d3c7c7003 SHA256 57b8fdc3b44ed9c7255e979d3db3ff6d351adc436b3a973f87ebb333c800b001
-DIST tuxonice-3.0-rc5-for-2.6.24.patch.bz2 113258 RMD160 c1fde23de970b6347302ae2bff71bf3ab1bfbeb3 SHA1 bf559c8dead1d0372d3388e4f9d2c4d145862ec1 SHA256 0a3b502b89bebbcd0f701a0e89c072797257ce766b2ea2d2bda1f6762ca2ce9b
DIST tuxonice-3.0-rc7-for-2.6.25.patch.bz2 113685 RMD160 863ca8197572c2b1a14a0922fff21723fe23d455 SHA1 3629a55777740bda65d5df62309aa3e978e91f79 SHA256 1dbd15f436026c5383db42da7ce96708542b3dd42e17446bf809e5b8ce5c3bd2
-EBUILD thinkpad-sources-2.6.24-r4.ebuild 3439 RMD160 b574ba9ae5f097444523bda049ae9247914aa4dd SHA1 2d1cf7e59f33a85587568a0cd46d1ab545ad1607 SHA256 15ca5c2cdb3fafc2589d587116f94eb5abd6d627100b246053bab810cdac6900
+EBUILD thinkpad-sources-2.6.25-r1.ebuild 3804 RMD160 2aa72aa1408edbe18190b49088f4c6f6fb27d104 SHA1 301c54df7996a930e1caa17393f3d845a12ae578 SHA256 97165d253c3e67dcec32b4a5b8f5199a2853b3171e51f6128522c1d64bf7b5eb
EBUILD thinkpad-sources-2.6.25.ebuild 3678 RMD160 27fdee391b1bb1fdccd28d3f8154d8ef85901fba SHA1 30d6f8171a05a2d08247ef9b2941ba9c54ffb402 SHA256 604ef6d2172c6a364f292509f88f32d16f56c584bba45d985447751f00426c1f
-MISC ChangeLog 4016 RMD160 8ff530776a534cb79b2bb90729eb1a3699907a51 SHA1 8297e8cd1738af94677a8c053c2535840f744641 SHA256 b8002e68a05a49ed8e457718152e9b3f8e4a5cf24187c038bc8c6088c88a4c2f
+MISC ChangeLog 5397 RMD160 a574661f7566b11a53d37268d3d427a8730bd28b SHA1 1e7f700d8ca5822ed9476e93922e3711917815c1 SHA256 0e889c947cdaf3d1e308ad825a28efaf6103ba2e9b4272e6fdf3475cc2f53743
MISC metadata.xml 284 RMD160 5062b08f804b7eaf9e1765c0d38b7fc95bc467e4 SHA1 687ba9103e597aad8a7231ff9a470d841f7121df SHA256 6ca83c8927bd3516baac49bc9ea82ddbeeddbe38a5a98b637d6eb1f1d436c84a
diff --git a/sys-kernel/thinkpad-sources/files/2.6.24-r1/colored-printk-output-2.6.24.patch b/sys-kernel/thinkpad-sources/files/2.6.24-r1/colored-printk-output-2.6.24.patch
deleted file mode 100644
index 0ccf792..0000000
--- a/sys-kernel/thinkpad-sources/files/2.6.24-r1/colored-printk-output-2.6.24.patch
+++ /dev/null
@@ -1,347 +0,0 @@
-diff -ruN linux-2.6.23.orig/arch/x86/kernel/early_printk.c linux-2.6.23/arch/x86/kernel/early_printk.c
---- linux-2.6.23.orig/arch/x86/kernel/early_printk.c 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/arch/x86/kernel/early_printk.c 2007-10-06 23:00:39.000000000 +0200
-@@ -20,7 +20,8 @@
- static int max_ypos = 25, max_xpos = 80;
- static int current_ypos = 25, current_xpos = 0;
-
--static void early_vga_write(struct console *con, const char *str, unsigned n)
-+static void early_vga_write(struct console *con, const char *str, unsigned n,
-+ unsigned int loglevel)
- {
- char c;
- int i, k, j;
-@@ -89,7 +90,8 @@
- return timeout ? 0 : -1;
- }
-
--static void early_serial_write(struct console *con, const char *s, unsigned n)
-+static void early_serial_write(struct console *con, const char *s, unsigned n,
-+ unsigned int loglevel)
- {
- while (*s && n-- > 0) {
- if (*s == '\n')
-@@ -185,7 +187,8 @@
- simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644);
- }
-
--static void simnow_write(struct console *con, const char *s, unsigned n)
-+static void simnow_write(struct console *con, const char *s, unsigned n,
-+ unsigned int loglevel)
- {
- simnow(XWRITE, simnow_fd, (unsigned long)s, n);
- }
-@@ -209,7 +212,7 @@
-
- va_start(ap,fmt);
- n = vscnprintf(buf,512,fmt,ap);
-- early_console->write(early_console,buf,n);
-+ early_console->write(early_console, buf, n, 0);
- va_end(ap);
- }
-
-diff -ruN linux-2.6.23.orig/drivers/char/Kconfig linux-2.6.23/drivers/char/Kconfig
---- linux-2.6.23.orig/drivers/char/Kconfig 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/drivers/char/Kconfig 2007-10-06 23:06:55.000000000 +0200
-@@ -58,6 +58,111 @@
-
- If unsure, say Y.
-
-+menuconfig VT_CKO
-+ bool "Colored kernel message output"
-+ depends on VT_CONSOLE
-+ ---help---
-+ This option enables kernel messages to be emitted in
-+ colors other than the default.
-+
-+ The color value you need to enter is composed (OR-ed)
-+ of a foreground and a background color.
-+
-+ Foreground:
-+ 0x00 = black, 0x08 = dark gray,
-+ 0x01 = red, 0x09 = light red,
-+ 0x02 = green, 0x0A = light green,
-+ 0x03 = brown, 0x0B = yellow,
-+ 0x04 = blue, 0x0C = light blue,
-+ 0x05 = magenta, 0x0D = light magenta,
-+ 0x06 = cyan, 0x0E = light cyan,
-+ 0x07 = gray, 0x0F = white,
-+
-+ (Foreground colors 0x08 to 0x0F do not work when a VGA
-+ console font with 512 glyphs is used.)
-+
-+ Background:
-+ 0x00 = black, 0x40 = blue,
-+ 0x10 = red, 0x50 = magenta,
-+ 0x20 = green, 0x60 = cyan,
-+ 0x30 = brown, 0x70 = gray,
-+
-+ For example, 0x1F would yield white on red.
-+
-+ If unsure, say N.
-+
-+config VT_PRINTK_EMERG_COLOR
-+ hex "Emergency messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel emergency messages will
-+ be printed to the console.
-+
-+config VT_PRINTK_ALERT_COLOR
-+ hex "Alert messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel alert messages will
-+ be printed to the console.
-+
-+config VT_PRINTK_CRIT_COLOR
-+ hex "Critical messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel critical messages will
-+ be printed to the console.
-+
-+config VT_PRINTK_ERR_COLOR
-+ hex "Error messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel error messages will
-+ be printed to the console.
-+
-+config VT_PRINTK_WARNING_COLOR
-+ hex "Warning messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel warning messages will
-+ be printed to the console.
-+
-+config VT_PRINTK_NOTICE_COLOR
-+ hex "Notice messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel notice messages will
-+ be printed to the console.
-+
-+config VT_PRINTK_INFO_COLOR
-+ hex "Information messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel information messages will
-+ be printed to the console.
-+
-+config VT_PRINTK_DEBUG_COLOR
-+ hex "Debug messages color"
-+ range 0x00 0xFF
-+ depends on VT_CKO
-+ default 0x07
-+ ---help---
-+ This option defines with which color kernel debug messages will
-+ be printed to the console.
-+
- config HW_CONSOLE
- bool
- depends on VT && !S390 && !UML
-diff -ruN linux-2.6.23.orig/drivers/char/vt.c linux-2.6.23/drivers/char/vt.c
---- linux-2.6.23.orig/drivers/char/vt.c 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/drivers/char/vt.c 2007-10-06 23:06:55.000000000 +0200
-@@ -73,6 +73,7 @@
- */
-
- #include <linux/module.h>
-+#include <linux/moduleparam.h>
- #include <linux/types.h>
- #include <linux/sched.h>
- #include <linux/tty.h>
-@@ -2344,16 +2345,44 @@
-
- #ifdef CONFIG_VT_CONSOLE
-
-+#ifdef CONFIG_VT_CKO
-+static unsigned int printk_color[8] __read_mostly = {
-+ CONFIG_VT_PRINTK_EMERG_COLOR, /* KERN_EMERG */
-+ CONFIG_VT_PRINTK_ALERT_COLOR, /* KERN_ALERT */
-+ CONFIG_VT_PRINTK_CRIT_COLOR, /* KERN_CRIT */
-+ CONFIG_VT_PRINTK_ERR_COLOR, /* KERN_ERR */
-+ CONFIG_VT_PRINTK_WARNING_COLOR, /* KERN_WARNING */
-+ CONFIG_VT_PRINTK_NOTICE_COLOR, /* KERN_NOTICE */
-+ CONFIG_VT_PRINTK_INFO_COLOR, /* KERN_INFO */
-+ CONFIG_VT_PRINTK_DEBUG_COLOR, /* KERN_DEBUG */
-+};
-+module_param_array(printk_color, uint, NULL, S_IRUGO | S_IWUSR);
-+
-+static inline void vc_set_color(struct vc_data *vc, unsigned char color)
-+{
-+ vc->vc_color = color_table[color & 0xF] |
-+ (color_table[(color >> 4) & 0x7] << 4) |
-+ (color & 0x80);
-+ update_attr(vc);
-+}
-+#else
-+static unsigned int printk_color[8];
-+static inline void vc_set_color(const struct vc_data *vc, unsigned char c)
-+{
-+}
-+#endif
-+
- /*
- * Console on virtual terminal
- *
- * The console must be locked when we get here.
- */
-
--static void vt_console_print(struct console *co, const char *b, unsigned count)
-+static void vt_console_print(struct console *co, const char *b, unsigned count,
-+ unsigned int loglevel)
- {
- struct vc_data *vc = vc_cons[fg_console].d;
-- unsigned char c;
-+ unsigned char current_color, c;
- static unsigned long printing;
- const ushort *start;
- ushort cnt = 0;
-@@ -2385,11 +2414,19 @@
-
- start = (ushort *)vc->vc_pos;
-
-+ /*
-+ * We always get a valid loglevel - <8> and "no level" is transformed
-+ * to <4> in the typical kernel.
-+ */
-+ current_color = printk_color[loglevel];
-+ vc_set_color(vc, current_color);
-+
- /* Contrived structure to try to emulate original need_wrap behaviour
- * Problems caused when we have need_wrap set on '\n' character */
- while (count--) {
- c = *b++;
- if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
-+ vc_set_color(vc, vc->vc_def_color);
- if (cnt > 0) {
- if (CON_IS_VISIBLE(vc))
- vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-@@ -2402,6 +2439,7 @@
- bs(vc);
- start = (ushort *)vc->vc_pos;
- myx = vc->vc_x;
-+ vc_set_color(vc, current_color);
- continue;
- }
- if (c != 13)
-@@ -2409,6 +2447,7 @@
- cr(vc);
- start = (ushort *)vc->vc_pos;
- myx = vc->vc_x;
-+ vc_set_color(vc, current_color);
- if (c == 10 || c == 13)
- continue;
- }
-@@ -2430,6 +2469,7 @@
- vc->vc_need_wrap = 1;
- }
- }
-+ vc_set_color(vc, vc->vc_def_color);
- set_cursor(vc);
-
- quit:
-diff -ruN linux-2.6.23.orig/drivers/net/netconsole.c linux-2.6.23/drivers/net/netconsole.c
---- linux-2.6.23.orig/drivers/net/netconsole.c 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/drivers/net/netconsole.c 2007-10-06 23:00:39.000000000 +0200
-@@ -65,7 +65,8 @@
-
- #define MAX_PRINT_CHUNK 1000
-
--static void write_msg(struct console *con, const char *msg, unsigned int len)
-+static void write_msg(struct console *con, const char *msg, unsigned int len,
-+ unsigned int loglevel)
- {
- int frag, left;
- unsigned long flags;
-diff -ruN linux-2.6.23.orig/drivers/serial/8250.c linux-2.6.23/drivers/serial/8250.c
---- linux-2.6.23.orig/drivers/serial/8250.c 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/drivers/serial/8250.c 2007-10-06 23:00:39.000000000 +0200
-@@ -2464,7 +2464,8 @@
- * The console_lock must be held when we get here.
- */
- static void
--serial8250_console_write(struct console *co, const char *s, unsigned int count)
-+serial8250_console_write(struct console *co, const char *s, unsigned int count,
-+ unsigned int loglevel)
- {
- struct uart_8250_port *up = &serial8250_ports[co->index];
- unsigned long flags;
-diff -ruN linux-2.6.23.orig/drivers/serial/8250_early.c linux-2.6.23/drivers/serial/8250_early.c
---- linux-2.6.23.orig/drivers/serial/8250_early.c 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/drivers/serial/8250_early.c 2007-10-06 23:00:39.000000000 +0200
-@@ -82,7 +82,8 @@
- serial_out(port, UART_TX, c);
- }
-
--static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count)
-+static void __init early_serial8250_write(struct console *console,
-+ const char *s, unsigned int count, unsigned int loglevel)
- {
- struct uart_port *port = &early_device.port;
- unsigned int ier;
-diff -ruN linux-2.6.23.orig/include/linux/console.h linux-2.6.23/include/linux/console.h
---- linux-2.6.23.orig/include/linux/console.h 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/include/linux/console.h 2007-10-06 23:00:39.000000000 +0200
-@@ -93,7 +93,7 @@
-
- struct console {
- char name[16];
-- void (*write)(struct console *, const char *, unsigned);
-+ void (*write)(struct console *, const char *, unsigned, unsigned int);
- int (*read)(struct console *, char *, unsigned);
- struct tty_driver *(*device)(struct console *, int *);
- void (*unblank)(void);
-diff -ruN linux-2.6.23.orig/kernel/printk.c linux-2.6.23/kernel/printk.c
---- linux-2.6.23.orig/kernel/printk.c 2007-10-02 05:24:52.000000000 +0200
-+++ linux-2.6.23/kernel/printk.c 2007-10-06 23:00:39.000000000 +0200
-@@ -320,7 +320,8 @@
- /*
- * Call the console drivers on a range of log_buf
- */
--static void __call_console_drivers(unsigned long start, unsigned long end)
-+static void __call_console_drivers(unsigned long start, unsigned long end,
-+ unsigned int loglevel)
- {
- struct console *con;
-
-@@ -328,7 +329,7 @@
- if ((con->flags & CON_ENABLED) && con->write &&
- (cpu_online(smp_processor_id()) ||
- (con->flags & CON_ANYTIME)))
-- con->write(con, &LOG_BUF(start), end - start);
-+ con->write(con, &LOG_BUF(start), end - start, loglevel);
- }
- }
-
-@@ -355,10 +356,11 @@
- if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
- /* wrapped write */
- __call_console_drivers(start & LOG_BUF_MASK,
-- log_buf_len);
-- __call_console_drivers(0, end & LOG_BUF_MASK);
-+ log_buf_len, msg_log_level);
-+ __call_console_drivers(0, end & LOG_BUF_MASK,
-+ msg_log_level);
- } else {
-- __call_console_drivers(start, end);
-+ __call_console_drivers(start, end, msg_log_level);
- }
- }
- }
diff --git a/sys-kernel/thinkpad-sources/files/2.6.24-r1/iwlwifi-leds-v2-2.6.24-rc4.diff b/sys-kernel/thinkpad-sources/files/2.6.24-r1/iwlwifi-leds-v2-2.6.24-rc4.diff
deleted file mode 100644
index 22e8d9c..0000000
--- a/sys-kernel/thinkpad-sources/files/2.6.24-r1/iwlwifi-leds-v2-2.6.24-rc4.diff
+++ /dev/null
@@ -1,532 +0,0 @@
---- ./drivers/net/wireless/iwlwifi/Kconfig.orig 2007-12-04 07:57:24.000000000 +0100
-+++ ./drivers/net/wireless/iwlwifi/Kconfig 2007-12-04 13:04:52.000000000 +0100
-@@ -126,3 +126,9 @@
- inserted in and remvoed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>. The
- module will be called iwl3945.ko.
-+config IWLWIFI_LEDS
-+ bool "IWLWIFI leds"
-+ depends on IWLWIFI && MAC80211_LEDS
-+ default y
-+ ---help---
-+ This options enables the wireless led.
---- ./drivers/net/wireless/iwlwifi/iwl-priv.h.orig 2007-12-04 07:57:24.000000000 +0100
-+++ ./drivers/net/wireless/iwlwifi/iwl-priv.h 2007-12-04 13:04:52.000000000 +0100
-@@ -127,11 +127,14 @@
- struct iwl_init_alive_resp card_alive_init;
- struct iwl_alive_resp card_alive;
-
--#ifdef LED
-- /* LED related variables */
-- struct iwl_activity_blink activity;
-- unsigned long led_packets;
-- int led_state;
-+
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ u8 led_state;
-+ unsigned int rxtxpackets;
-+ atomic_t ledtimer;
-+ struct iwl_led tx_led;
-+ struct iwl_led rx_led;
-+ struct iwl_led assoc_led;
- #endif
-
- u16 active_rate;
-@@ -274,6 +277,7 @@
- struct delayed_work gather_stats;
- struct delayed_work scan_check;
- struct delayed_work post_associate;
-+ struct delayed_work update_led;
-
- #define IWL_DEFAULT_TX_POWER 0x0F
- s8 user_txpower_limit;
---- ./drivers/net/wireless/iwlwifi/iwlwifi.h.orig 2007-12-04 07:57:24.000000000 +0100
-+++ ./drivers/net/wireless/iwlwifi/iwlwifi.h 2007-12-04 13:04:52.000000000 +0100
-@@ -50,6 +50,9 @@
-
- #include "iwl-prph.h"
-
-+#ifdef CONFIG_IWLWIFI_LEDS
-+#include "iwl-leds.h"
-+#endif
- /*
- * Driver implementation data structures, constants, inline
- * functions
---- ./drivers/net/wireless/iwlwifi/iwl-leds.h.orig 2007-12-04 13:04:52.000000000 +0100
-+++ ./drivers/net/wireless/iwlwifi/iwl-leds.h 2007-12-04 13:04:52.000000000 +0100
-@@ -0,0 +1,20 @@
-+#ifndef __iwl_leds_h__
-+#define __iwl_leds_h__
-+
-+
-+#include <linux/leds.h>
-+
-+
-+#define IWL_LED_ACTIVITY (0<<1)
-+#define IWL_LED_LINK (1<<1)
-+#define IWL_LED_INTERVAL __constant_cpu_to_le32(1000)
-+#define IWL_LED_ACTIVITY_PERIOD msecs_to_jiffies(500)
-+#define IWL_LED_MAX_NAME_LEN 31
-+
-+struct iwl_led {
-+ char name[IWL_LED_MAX_NAME_LEN + 1];
-+ struct led_classdev cdev;
-+};
-+
-+
-+#endif
---- ./drivers/net/wireless/iwlwifi/iwl3945-base.c.orig 2007-12-04 07:57:24.000000000 +0100
-+++ ./drivers/net/wireless/iwlwifi/iwl3945-base.c 2007-12-04 13:06:17.000000000 +0100
-@@ -6086,6 +6086,173 @@
- queue_work(priv->workqueue, &priv->restart);
- }
-
-+#ifdef CONFIG_IWLWIFI_LEDS
-+static int iwl_led_cmd_callback(struct iwl_priv *priv,
-+ struct iwl_cmd *cmd, struct sk_buff *skb)
-+{
-+ return 1;
-+}
-+
-+static void iwl_bg_led_update(struct work_struct *data)
-+{
-+ struct iwl_priv *priv =
-+ container_of(data, struct iwl_priv, update_led.work);
-+ struct iwl_led_cmd led_cmd = {
-+ .id = IWL_LED_ACTIVITY,
-+ .interval = IWL_LED_INTERVAL,
-+ };
-+ struct iwl_host_cmd cmd = {
-+ .id = REPLY_LEDS_CMD,
-+ .len = sizeof(struct iwl_led_cmd),
-+ .data = &led_cmd,
-+ .meta.flags = CMD_ASYNC,
-+ .meta.u.callback = iwl_led_cmd_callback,
-+ };
-+ u8 on;
-+ unsigned long flags;
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ if (priv->rxtxpackets) {
-+ on = 25 + 230 / (1 + (priv->rxtxpackets >> 2));
-+ priv->rxtxpackets = 0;
-+ queue_delayed_work(priv->workqueue, &priv->update_led,
-+ IWL_LED_ACTIVITY_PERIOD);
-+
-+ if (on == priv->led_state)
-+ goto exit_unlock;
-+
-+ led_cmd.on = led_cmd.off = on;
-+ priv->led_state = on;
-+
-+ }
-+ else {
-+ atomic_set(&priv->ledtimer, 0);
-+ led_cmd.on = led_cmd.off = 0;
-+ priv->led_state = 0;
-+ }
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+ iwl_send_cmd(priv, &cmd);
-+
-+ return;
-+
-+exit_unlock:
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+static void iwl_led_set_rx(struct led_classdev *led_cdev,
-+ enum led_brightness value)
-+{
-+ struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv,
-+ rx_led.cdev);
-+ unsigned long flags;
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+ priv->rxtxpackets += 2;
-+ if (!atomic_xchg(&priv->ledtimer, 1))
-+ queue_delayed_work(priv->workqueue, &priv->update_led,
-+ IWL_LED_ACTIVITY_PERIOD);
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+}
-+
-+static void iwl_led_set_tx(struct led_classdev *led_cdev,
-+ enum led_brightness value)
-+{
-+ struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv,
-+ tx_led.cdev);
-+ unsigned long flags;
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+ priv->rxtxpackets++;
-+ if (!atomic_xchg(&priv->ledtimer, 1))
-+ queue_delayed_work(priv->workqueue, &priv->update_led,
-+ IWL_LED_ACTIVITY_PERIOD);
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+static void iwl_led_set_assoc(struct led_classdev *led_cdev,
-+ enum led_brightness value)
-+{
-+ struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv,
-+ assoc_led.cdev);
-+ struct iwl_led_cmd led_cmd = {
-+ .id = IWL_LED_LINK,
-+ .interval = IWL_LED_INTERVAL,
-+ };
-+ struct iwl_host_cmd cmd = {
-+ .id = REPLY_LEDS_CMD,
-+ .len = sizeof(struct iwl_led_cmd),
-+ .data = &led_cmd,
-+ .meta.flags = CMD_ASYNC,
-+ .meta.u.callback = iwl_led_cmd_callback
-+ };
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ switch(value)
-+ {
-+ case LED_OFF:
-+ led_cmd.off = 0;
-+ led_cmd.on = 0;
-+ break;
-+ case LED_HALF:
-+ case LED_FULL:
-+ led_cmd.off = 0;
-+ led_cmd.on = 40;
-+ }
-+ iwl_send_cmd(priv, &cmd);
-+}
-+
-+
-+static int iwl_register_led(struct iwl_priv *priv, struct iwl_led *led, char *ledname,
-+ char *triggername, void (*callback)
-+ (struct led_classdev *, enum led_brightness))
-+{
-+ snprintf(led->name, sizeof(led->name), ledname,
-+ wiphy_name(priv->hw->wiphy));
-+ led->cdev.name = led->name;
-+ led->cdev.brightness_set = callback;
-+ led->cdev.default_trigger = triggername;
-+
-+ return led_classdev_register(&priv->pci_dev->dev, &led->cdev);
-+}
-+
-+static void iwl_register_leds(struct iwl_priv *priv)
-+{
-+ iwl_register_led(priv, &priv->tx_led, "iwl-%s:tx",
-+ ieee80211_get_tx_led_name(priv->hw),
-+ iwl_led_set_tx);
-+ iwl_register_led(priv, &priv->rx_led, "iwl-%s:rx",
-+ ieee80211_get_rx_led_name(priv->hw),
-+ iwl_led_set_rx);
-+ iwl_register_led(priv, &priv->assoc_led, "iwl-%s:asoc",
-+ ieee80211_get_assoc_led_name(priv->hw),
-+ iwl_led_set_assoc);
-+}
-+
-+static void iwl_unregister_leds(struct iwl_priv *priv)
-+{
-+ led_classdev_unregister(&priv->tx_led.cdev);
-+ led_classdev_unregister(&priv->rx_led.cdev);
-+ led_classdev_unregister(&priv->assoc_led.cdev);
-+}
-+#endif
-
- /**
- * iwl_alive_start - called after REPLY_ALIVE notification received
-@@ -6161,6 +6328,9 @@
- if (iwl_is_rfkill(priv))
- return;
-
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ atomic_set(&priv->ledtimer, 0);
-+#endif
- if (!priv->mac80211_registered) {
- /* Unlock so any user space entry points can call back into
- * the driver without a deadlock... */
-@@ -6179,6 +6349,9 @@
- priv->mac80211_registered = 1;
-
- iwl_reset_channel_flag(priv);
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ iwl_register_leds(priv);
-+#endif
- } else
- ieee80211_start_queues(priv->hw);
-
-@@ -8266,7 +8439,9 @@
- INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
- INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
- INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
--
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ INIT_DELAYED_WORK(&priv->update_led, iwl_bg_led_update);
-+#endif
- iwl_hw_setup_deferred_work(priv);
-
- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-@@ -8278,6 +8453,9 @@
- iwl_hw_cancel_deferred_work(priv);
-
- cancel_delayed_work_sync(&priv->init_alive_start);
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ cancel_delayed_work(&priv->update_led);
-+#endif
- cancel_delayed_work(&priv->scan_check);
- cancel_delayed_work(&priv->alive_start);
- cancel_delayed_work(&priv->post_associate);
-@@ -8602,6 +8780,9 @@
- iwl_clear_stations_table(priv);
-
- if (priv->mac80211_registered) {
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ iwl_unregister_leds(priv);
-+#endif
- ieee80211_unregister_hw(priv->hw);
- iwl_rate_control_unregister(priv->hw);
- }
---- ./drivers/net/wireless/iwlwifi/iwl4965-base.c.orig 2007-12-04 07:57:24.000000000 +0100
-+++ ./drivers/net/wireless/iwlwifi/iwl4965-base.c 2007-12-04 13:06:54.000000000 +0100
-@@ -6462,6 +6462,174 @@
- queue_work(priv->workqueue, &priv->restart);
- }
-
-+#ifdef CONFIG_IWLWIFI_LEDS
-+static int iwl_led_cmd_callback(struct iwl_priv *priv,
-+ struct iwl_cmd *cmd, struct sk_buff *skb)
-+{
-+ return 1;
-+}
-+
-+static void iwl_bg_led_update(struct work_struct *data)
-+{
-+ struct iwl_priv *priv =
-+ container_of(data, struct iwl_priv, update_led.work);
-+ struct iwl_led_cmd led_cmd = {
-+ .id = IWL_LED_ACTIVITY,
-+ .interval = IWL_LED_INTERVAL,
-+ };
-+ struct iwl_host_cmd cmd = {
-+ .id = REPLY_LEDS_CMD,
-+ .len = sizeof(struct iwl_led_cmd),
-+ .data = &led_cmd,
-+ .meta.flags = CMD_ASYNC,
-+ .meta.u.callback = iwl_led_cmd_callback,
-+ };
-+ u8 on;
-+ unsigned long flags;
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ if (priv->rxtxpackets) {
-+ on = 25 + 230 / (1 + (priv->rxtxpackets >> 2));
-+ priv->rxtxpackets = 0;
-+ queue_delayed_work(priv->workqueue, &priv->update_led,
-+ IWL_LED_ACTIVITY_PERIOD);
-+
-+ if (on == priv->led_state)
-+ goto exit_unlock;
-+
-+ led_cmd.on = led_cmd.off = on;
-+ priv->led_state = on;
-+
-+ }
-+ else {
-+ atomic_set(&priv->ledtimer, 0);
-+ led_cmd.on = led_cmd.off = 0;
-+ priv->led_state = 0;
-+ }
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+ iwl_send_cmd(priv, &cmd);
-+
-+ return;
-+
-+exit_unlock:
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+static void iwl_led_set_rx(struct led_classdev *led_cdev,
-+ enum led_brightness value)
-+{
-+ struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv,
-+ rx_led.cdev);
-+ unsigned long flags;
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+ priv->rxtxpackets += 2;
-+ if (!atomic_xchg(&priv->ledtimer, 1))
-+ queue_delayed_work(priv->workqueue, &priv->update_led,
-+ IWL_LED_ACTIVITY_PERIOD);
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+}
-+
-+static void iwl_led_set_tx(struct led_classdev *led_cdev,
-+ enum led_brightness value)
-+{
-+ struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv,
-+ tx_led.cdev);
-+ unsigned long flags;
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+ priv->rxtxpackets++;
-+ if (!atomic_xchg(&priv->ledtimer, 1))
-+ queue_delayed_work(priv->workqueue, &priv->update_led,
-+ IWL_LED_ACTIVITY_PERIOD);
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+static void iwl_led_set_assoc(struct led_classdev *led_cdev,
-+ enum led_brightness value)
-+{
-+ struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv,
-+ assoc_led.cdev);
-+ struct iwl_led_cmd led_cmd = {
-+ .id = IWL_LED_LINK,
-+ .interval = IWL_LED_INTERVAL,
-+ };
-+ struct iwl_host_cmd cmd = {
-+ .id = REPLY_LEDS_CMD,
-+ .len = sizeof(struct iwl_led_cmd),
-+ .data = &led_cmd,
-+ .meta.flags = CMD_ASYNC,
-+ .meta.u.callback = iwl_led_cmd_callback
-+ };
-+
-+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-+ !test_bit(STATUS_READY, &priv->status))
-+ return;
-+
-+ switch(value)
-+ {
-+ case LED_OFF:
-+ led_cmd.off = 0;
-+ led_cmd.on = 0;
-+ break;
-+ case LED_HALF:
-+ case LED_FULL:
-+ led_cmd.off = 0;
-+ led_cmd.on = 40;
-+ }
-+ iwl_send_cmd(priv, &cmd);
-+}
-+
-+
-+static int iwl_register_led(struct iwl_priv *priv, struct iwl_led *led, char *ledname,
-+ char *triggername, void (*callback)
-+ (struct led_classdev *, enum led_brightness))
-+{
-+ snprintf(led->name, sizeof(led->name), ledname,
-+ wiphy_name(priv->hw->wiphy));
-+ led->cdev.name = led->name;
-+ led->cdev.brightness_set = callback;
-+ led->cdev.default_trigger = triggername;
-+
-+ return led_classdev_register(&priv->pci_dev->dev, &led->cdev);
-+}
-+
-+static void iwl_register_leds(struct iwl_priv *priv)
-+{
-+ iwl_register_led(priv, &priv->tx_led, "iwl-%s:tx",
-+ ieee80211_get_tx_led_name(priv->hw),
-+ iwl_led_set_tx);
-+ iwl_register_led(priv, &priv->rx_led, "iwl-%s:rx",
-+ ieee80211_get_rx_led_name(priv->hw),
-+ iwl_led_set_rx);
-+ iwl_register_led(priv, &priv->assoc_led, "iwl-%s:asoc",
-+ ieee80211_get_assoc_led_name(priv->hw),
-+ iwl_led_set_assoc);
-+}
-+
-+static void iwl_unregister_leds(struct iwl_priv *priv)
-+{
-+ led_classdev_unregister(&priv->tx_led.cdev);
-+ led_classdev_unregister(&priv->rx_led.cdev);
-+ led_classdev_unregister(&priv->assoc_led.cdev);
-+}
-+#endif
-+
-
- /**
- * iwl_alive_start - called after REPLY_ALIVE notification received
-@@ -6517,6 +6685,9 @@
- if (iwl_is_rfkill(priv))
- return;
-
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ atomic_set(&priv->ledtimer, 0);
-+#endif
- if (!priv->mac80211_registered) {
- /* Unlock so any user space entry points can call back into
- * the driver without a deadlock... */
-@@ -6535,6 +6706,9 @@
- priv->mac80211_registered = 1;
-
- iwl_reset_channel_flag(priv);
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ iwl_register_leds(priv);
-+#endif
- } else
- ieee80211_start_queues(priv->hw);
-
-@@ -8859,7 +9033,9 @@
- INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
- INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
- INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
--
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ INIT_DELAYED_WORK(&priv->update_led, iwl_bg_led_update);
-+#endif
- iwl_hw_setup_deferred_work(priv);
-
- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-@@ -8871,6 +9047,9 @@
- iwl_hw_cancel_deferred_work(priv);
-
- cancel_delayed_work_sync(&priv->init_alive_start);
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ cancel_delayed_work(&priv->update_led);
-+#endif
- cancel_delayed_work(&priv->scan_check);
- cancel_delayed_work(&priv->alive_start);
- cancel_delayed_work(&priv->post_associate);
-@@ -9196,6 +9375,9 @@
- iwl_clear_stations_table(priv);
-
- if (priv->mac80211_registered) {
-+#ifdef CONFIG_IWLWIFI_LEDS
-+ iwl_unregister_leds(priv);
-+#endif
- ieee80211_unregister_hw(priv->hw);
- iwl_rate_control_unregister(priv->hw);
- }
diff --git a/sys-kernel/thinkpad-sources/files/2.6.24-r3/disk-protect-fix-for-2.6.24.patch b/sys-kernel/thinkpad-sources/files/2.6.24-r3/disk-protect-fix-for-2.6.24.patch
deleted file mode 100644
index 1fd2281..0000000
--- a/sys-kernel/thinkpad-sources/files/2.6.24-r3/disk-protect-fix-for-2.6.24.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
-index 14daf48..bab372b 100644
---- a/drivers/ata/libata-scsi.c
-+++ b/drivers/ata/libata-scsi.c
-@@ -823,7 +823,7 @@ static void ata_scsi_sdev_config(struct
- * prevent SCSI midlayer from automatically deferring
- * requests.
- */
-- sdev->max_device_blocked = 1;
-+ sdev->max_device_blocked = 2;
- }
-
- static void ata_scsi_dev_config(struct scsi_device *sdev,
-@@ -3120,7 +3120,7 @@ int ata_scsi_add_hosts(struct ata_host *
- * Set host_blocked to 1 to prevent SCSI midlayer from
- * automatically deferring requests.
- */
-- shost->max_host_blocked = 1;
-+ shost->max_host_blocked = 2;
-
- rc = scsi_add_host(ap->scsi_host, ap->host->dev);
- if (rc)
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/00-bay-cleanup_exit-for-2.6.25.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/00-bay-cleanup_exit-for-2.6.25.patch
new file mode 100644
index 0000000..d8c36a1
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/00-bay-cleanup_exit-for-2.6.25.patch
@@ -0,0 +1,41 @@
+If acpi_install_notify_handler() for a bay device fails, the bay driver is
+superfluous. Most likely, another driver (like libata) is already caring
+about this device anyway. Furthermore,
+register_hotplug_dock_device(acpi_handle) from the dock driver must not be
+called twice with the same handler. This would result in an endless loop
+consuming 100% of CPU. So clean up and exit.
+
+Signed-off-by: Holger Macht <hmacht@suse.de>
+---
+
+diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
+index d2fc941..26038c2 100644
+--- a/drivers/acpi/bay.c
++++ b/drivers/acpi/bay.c
+@@ -299,16 +299,20 @@ static int bay_add(acpi_handle handle, int id)
+ */
+ pdev->dev.uevent_suppress = 0;
+
+- if (acpi_bay_add_fs(new_bay)) {
+- platform_device_unregister(new_bay->pdev);
+- goto bay_add_err;
+- }
+-
+ /* register for events on this device */
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify, new_bay);
+ if (ACPI_FAILURE(status)) {
+- printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
++ printk(KERN_INFO PREFIX "Error installing bay notify handler\n");
++ platform_device_unregister(new_bay->pdev);
++ goto bay_add_err;
++ }
++
++ if (acpi_bay_add_fs(new_bay)) {
++ acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
++ bay_notify);
++ platform_device_unregister(new_bay->pdev);
++ goto bay_add_err;
+ }
+
+ /* if we are on a dock station, we should register for dock
diff --git a/sys-kernel/thinkpad-sources/files/2.6.24/disk-protect-for-2.6.24.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/01-disk-protect-for-2.6.25.patch
index e9d516b..9738753 100644
--- a/sys-kernel/thinkpad-sources/files/2.6.24/disk-protect-for-2.6.24.patch
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/01-disk-protect-for-2.6.25.patch
@@ -1,103 +1,14 @@
-diff -Naur a/block/ll_rw_blk.c b/block/ll_rw_blk.c
---- a/block/ll_rw_blk.c 2008-01-20 14:45:41.000000000 +0100
-+++ b/block/ll_rw_blk.c 2008-01-20 14:47:50.000000000 +0100
-@@ -39,6 +39,10 @@
-
- static void blk_unplug_work(struct work_struct *work);
- static void blk_unplug_timeout(unsigned long data);
-+static void blk_unfreeze_work(struct work_struct *work);
-+static void blk_unfreeze_timeout(unsigned long data);
-+static int blk_protect_register(struct request_queue *q);
-+static void blk_protect_unregister(struct request_queue *q);
- static void drive_stat_acct(struct request *rq, int new_io);
- static void init_request_from_bio(struct request *req, struct bio *bio);
- static int __make_request(struct request_queue *q, struct bio *bio);
-@@ -231,6 +235,16 @@
- q->unplug_timer.function = blk_unplug_timeout;
- q->unplug_timer.data = (unsigned long)q;
-
-+ q->max_unfreeze = 30;
-+
-+ INIT_WORK(&q->unfreeze_work, blk_unfreeze_work);
-+
-+ q->unfreeze_timer.function = blk_unfreeze_timeout;
-+ q->unfreeze_timer.data = (unsigned long)q;
-+
-+ /* Set protect_method to auto detection initially */
-+ q->protect_method = 2;
-+
- /*
- * by default assume old behaviour and bounce for any highmem page
- */
-@@ -263,6 +277,18 @@
- rq->next_rq = NULL;
- }
-
-+void blk_queue_issue_protect_fn(struct request_queue *q, issue_protect_fn *ipf)
-+{
-+ q->issue_protect_fn = ipf;
-+}
-+EXPORT_SYMBOL(blk_queue_issue_protect_fn);
-+
-+void blk_queue_issue_unprotect_fn(struct request_queue *q, issue_unprotect_fn *iuf)
-+{
-+ q->issue_unprotect_fn = iuf;
-+}
-+EXPORT_SYMBOL(blk_queue_issue_unprotect_fn);
-+
- /**
- * blk_queue_ordered - does this queue support ordered writes
- * @q: the request queue
-@@ -1861,6 +1887,7 @@
- }
-
- init_timer(&q->unplug_timer);
-+ init_timer(&q->unfreeze_timer);
-
- kobject_set_name(&q->kobj, "%s", "queue");
- q->kobj.ktype = &queue_ktype;
-@@ -4191,13 +4218,21 @@
- kobject_uevent(&q->kobj, KOBJ_ADD);
-
- ret = elv_register_queue(q);
-+ if (ret)
-+ goto err;
-+
-+ ret = blk_protect_register(q);
- if (ret) {
-- kobject_uevent(&q->kobj, KOBJ_REMOVE);
-- kobject_del(&q->kobj);
-- return ret;
-+ elv_unregister_queue(q);
-+ goto err;
- }
-
- return 0;
-+
-+err:
-+ kobject_uevent(&q->kobj, KOBJ_REMOVE);
-+ kobject_del(&q->kobj);
-+ return ret;
+diff -Naur a/block/blk-core.c b/block/blk-core.c
+--- a/block/blk-core.c 2008-04-13 14:04:22.000000000 +0200
++++ b/block/blk-core.c 2008-04-13 14:25:48.000000000 +0200
+@@ -320,6 +320,46 @@
}
+ EXPORT_SYMBOL(blk_unplug);
- void blk_unregister_queue(struct gendisk *disk)
-@@ -4205,6 +4240,7 @@
- struct request_queue *q = disk->queue;
-
- if (q && q->request_fn) {
-+ blk_protect_unregister(q);
- elv_unregister_queue(q);
-
- kobject_uevent(&q->kobj, KOBJ_REMOVE);
-@@ -4212,3 +4248,197 @@
- kobject_put(&disk->kobj);
- }
- }
-+
+/*
+ * Issue lower level unprotect function if no timers are pending.
+ */
-+static void blk_unfreeze_work(struct work_struct *work)
++void blk_unfreeze_work(struct work_struct *work)
+{
+ struct request_queue *q = container_of(work, struct request_queue, unfreeze_work);
+ int pending;
@@ -113,7 +24,7 @@ diff -Naur a/block/ll_rw_blk.c b/block/ll_rw_blk.c
+/*
+ * Called when the queue freeze timeout expires...
+ */
-+static void blk_unfreeze_timeout(unsigned long data)
++void blk_unfreeze_timeout(unsigned long data)
+{
+ struct request_queue *q = (struct request_queue *) data;
+
@@ -134,6 +45,76 @@ diff -Naur a/block/ll_rw_blk.c b/block/ll_rw_blk.c
+ mod_timer(&q->unfreeze_timer, msecs_to_jiffies(seconds*1000) + jiffies);
+}
+
+ /**
+ * blk_start_queue - restart a previously stopped queue
+ * @q: The &struct request_queue in question
+@@ -482,6 +522,7 @@
+ }
+
+ init_timer(&q->unplug_timer);
++ init_timer(&q->unfreeze_timer);
+
+ kobject_init(&q->kobj, &blk_queue_ktype);
+
+diff -Naur a/block/blk.h b/block/blk.h
+--- a/block/blk.h 2008-04-13 14:04:22.000000000 +0200
++++ b/block/blk.h 2008-04-13 14:25:48.000000000 +0200
+@@ -18,6 +18,9 @@
+
+ void blk_unplug_work(struct work_struct *work);
+ void blk_unplug_timeout(unsigned long data);
++void blk_unfreeze_work(struct work_struct *work);
++void blk_unfreeze_timeout(unsigned long data);
++void blk_freeze_queue(struct request_queue *q, int seconds);
+
+ struct io_context *current_io_context(gfp_t gfp_flags, int node);
+
+diff -Naur a/block/blk-settings.c b/block/blk-settings.c
+--- a/block/blk-settings.c 2008-04-13 14:04:22.000000000 +0200
++++ b/block/blk-settings.c 2008-04-13 14:25:48.000000000 +0200
+@@ -112,6 +112,16 @@
+ q->unplug_timer.function = blk_unplug_timeout;
+ q->unplug_timer.data = (unsigned long)q;
+
++ q->max_unfreeze = 30;
++
++ INIT_WORK(&q->unfreeze_work, blk_unfreeze_work);
++
++ q->unfreeze_timer.function = blk_unfreeze_timeout;
++ q->unfreeze_timer.data = (unsigned long)q;
++
++ /* Set protect_method to auto detection initially */
++ q->protect_method = 2;
++
+ /*
+ * by default assume old behaviour and bounce for any highmem page
+ */
+@@ -119,6 +129,18 @@
+ }
+ EXPORT_SYMBOL(blk_queue_make_request);
+
++void blk_queue_issue_protect_fn(struct request_queue *q, issue_protect_fn *ipf)
++{
++ q->issue_protect_fn = ipf;
++}
++EXPORT_SYMBOL(blk_queue_issue_protect_fn);
++
++void blk_queue_issue_unprotect_fn(struct request_queue *q, issue_unprotect_fn *iuf)
++{
++ q->issue_unprotect_fn = iuf;
++}
++EXPORT_SYMBOL(blk_queue_issue_unprotect_fn);
++
+ /**
+ * blk_queue_bounce_limit - set bounce buffer limit for queue
+ * @q: the request queue for the device
+diff -Naur a/block/blk-sysfs.c b/block/blk-sysfs.c
+--- a/block/blk-sysfs.c 2008-04-13 14:04:22.000000000 +0200
++++ b/block/blk-sysfs.c 2008-04-13 14:25:48.000000000 +0200
+@@ -270,6 +270,160 @@
+ .release = blk_release_queue,
+ };
+
+/*
+ * When reading the 'protect' attribute, we return seconds remaining
+ * before unfreeze timeout expires
@@ -287,9 +268,45 @@ diff -Naur a/block/ll_rw_blk.c b/block/ll_rw_blk.c
+ sysfs_remove_file(&q->kobj, &queue_protect_entry.attr);
+ kobject_put(&q->kobj);
+}
++
+ int blk_register_queue(struct gendisk *disk)
+ {
+ int ret;
+@@ -287,13 +441,20 @@
+ kobject_uevent(&q->kobj, KOBJ_ADD);
+
+ ret = elv_register_queue(q);
++ if (ret)
++ goto err;
++ ret = blk_protect_register(q);
+ if (ret) {
+- kobject_uevent(&q->kobj, KOBJ_REMOVE);
+- kobject_del(&q->kobj);
+- return ret;
++ elv_unregister_queue(q);
++ goto err;
+ }
+
+ return 0;
++
++err:
++ kobject_uevent(&q->kobj, KOBJ_REMOVE);
++ kobject_del(&q->kobj);
++ return ret;
+ }
+
+ void blk_unregister_queue(struct gendisk *disk)
+@@ -301,6 +462,7 @@
+ struct request_queue *q = disk->queue;
+
+ if (q && q->request_fn) {
++ blk_protect_unregister(q);
+ elv_unregister_queue(q);
+
+ kobject_uevent(&q->kobj, KOBJ_REMOVE);
diff -Naur a/Documentation/block/disk-protection.txt b/Documentation/block/disk-protection.txt
--- a/Documentation/block/disk-protection.txt 1970-01-01 01:00:00.000000000 +0100
-+++ b/Documentation/block/disk-protection.txt 2008-01-20 14:47:50.000000000 +0100
++++ b/Documentation/block/disk-protection.txt 2008-04-13 14:25:48.000000000 +0200
@@ -0,0 +1,79 @@
+Hard disk protection
+====================
@@ -366,15 +383,24 @@ diff -Naur a/Documentation/block/disk-protection.txt b/Documentation/block/disk-
+-------
+
+The patch to implement the interface described in this file has
-+originally been published by Jon Escombe <lists@...>.
++originally been published by Jon Escombe <lists-Xbpc2PeERmvQXOPxS62xeg@public.gmane.org>.
+
+
-+05 Dec 2006, Elias Oltmanns <eo@...>
++05 Dec 2006, Elias Oltmanns <eo-oA28OIkTjSVZXbeN9DUtxg@public.gmane.org>
diff -Naur a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
---- a/drivers/ata/libata-scsi.c 2008-01-20 14:45:41.000000000 +0100
-+++ b/drivers/ata/libata-scsi.c 2008-01-20 14:47:50.000000000 +0100
-@@ -856,6 +856,38 @@
- }
+--- a/drivers/ata/libata-scsi.c 2008-04-13 14:04:23.000000000 +0200
++++ b/drivers/ata/libata-scsi.c 2008-04-13 14:26:04.000000000 +0200
+@@ -831,7 +831,7 @@
+ * prevent SCSI midlayer from automatically deferring
+ * requests.
+ */
+- sdev->max_device_blocked = 1;
++ sdev->max_device_blocked = 2;
+ }
+
+ /**
+@@ -905,6 +905,38 @@
+ return 0;
}
+extern int scsi_protect_queue(struct request_queue *q, int unload);
@@ -412,21 +438,30 @@ diff -Naur a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
/**
* ata_scsi_slave_config - Set SCSI device attributes
* @sdev: SCSI device to examine
-@@ -877,6 +909,10 @@
+@@ -927,6 +959,10 @@
if (dev)
- ata_scsi_dev_config(sdev, dev);
+ rc = ata_scsi_dev_config(sdev, dev);
+ blk_queue_issue_protect_fn(sdev->request_queue,
+ ata_scsi_issue_protect_fn);
+ blk_queue_issue_unprotect_fn(sdev->request_queue,
+ ata_scsi_issue_unprotect_fn);
- return 0; /* scsi layer doesn't check return value, sigh */
+ return rc;
}
+@@ -3206,7 +3242,7 @@
+ * Set host_blocked to 1 to prevent SCSI midlayer from
+ * automatically deferring requests.
+ */
+- shost->max_host_blocked = 1;
++ shost->max_host_blocked = 2;
+
+ rc = scsi_add_host(ap->scsi_host, ap->host->dev);
+ if (rc)
diff -Naur a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
---- a/drivers/ide/ide-disk.c 2008-01-20 14:45:41.000000000 +0100
-+++ b/drivers/ide/ide-disk.c 2008-01-20 14:47:50.000000000 +0100
-@@ -675,6 +675,145 @@
+--- a/drivers/ide/ide-disk.c 2008-04-13 14:04:31.000000000 +0200
++++ b/drivers/ide/ide-disk.c 2008-04-13 14:25:48.000000000 +0200
+@@ -612,6 +612,148 @@
}
/*
@@ -452,9 +487,9 @@ diff -Naur a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
+{
+ struct request rq;
+ unsigned long flags;
-+ int pending = 0, rc = 0;
++ int pending, rc = 0;
+ ide_drive_t *drive = q->queuedata;
-+ u8 args[7], *argbuf = args;
++ ide_task_t task;
+
+ if (!blk_queue_stopped(q))
+ return -EIO;
@@ -474,11 +509,13 @@ diff -Naur a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
+ just fine. */
+ if (!pending) {
+ printk(KERN_DEBUG "ide_unprotect_queue(): No pending I/O, re-enabling power management..\n");
-+ memset(args, 0, sizeof(args));
-+ argbuf[0] = 0xe5; /* CHECK_POWER_MODE1 */
++ memset(&task, 0, sizeof(task));
++ task.tf.command = WIN_CHECKPOWERMODE1; /* CHECK_POWER_MODE1 */
++ task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++ task.data_phase = TASKFILE_NO_DATA;
+ ide_init_drive_cmd(&rq);
-+ rq.cmd_type = REQ_TYPE_ATA_TASK;
-+ rq.buffer = argbuf;
++ rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
++ rq.special = &task;
+ rc = ide_do_drive_cmd(drive, &rq, ide_head_wait);
+ }
+
@@ -489,45 +526,46 @@ diff -Naur a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
+{
+ ide_drive_t *drive = q->queuedata;
+ struct request rq;
-+ u8 args[7], *argbuf = args;
++ ide_task_t task;
+ int ret = 0;
+ DECLARE_COMPLETION(wait);
+
+ memset(&rq, 0, sizeof(rq));
-+ memset(args, 0, sizeof(args));
++ memset(&task, 0, sizeof(task));
+
+ if (blk_queue_stopped(q))
+ return -EIO;
+
++ task.data_phase = TASKFILE_NO_DATA;
++ task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ if (unload) {
-+ argbuf[0] = 0xe1;
-+ argbuf[1] = 0x44;
-+ argbuf[3] = 0x4c;
-+ argbuf[4] = 0x4e;
-+ argbuf[5] = 0x55;
++ task.tf.command = 0xe1;
++ task.tf.feature = 0x44;
++ task.tf.lbal = 0x4c;
++ task.tf.lbam = 0x4e;
++ task.tf.lbah = 0x55;
+ } else
-+ argbuf[0] = 0xe0;
++ task.tf.command = 0xe0;
+
+ /* Issue the park command & freeze */
+ ide_init_drive_cmd(&rq);
+
-+ rq.cmd_type = REQ_TYPE_ATA_TASK;
-+ rq.buffer = argbuf;
++ rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
++ rq.special = &task;
+ rq.end_io_data = &wait;
+ rq.end_io = ide_end_protect_rq;
+
+ ret = ide_do_drive_cmd(drive, &rq, ide_next);
+ wait_for_completion(&wait);
+
-+ if (ret)
-+ {
++ if (ret) {
+ printk(KERN_DEBUG "ide_protect_queue(): Warning: head NOT parked!..\n");
+ ide_unprotect_queue(q);
+ return ret;
+ }
+
+ if (unload) {
-+ if (args[3] == 0xc4)
++ if (task.tf.lbal == 0xc4)
+ printk(KERN_DEBUG "ide_protect_queue(): head parked..\n");
+ else {
+ /* error parking the head */
@@ -572,7 +610,7 @@ diff -Naur a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
* This is tightly woven into the driver->do_special can not touch.
* DON'T do it again until a total personality rewrite is committed.
*/
-@@ -943,6 +1082,9 @@
+@@ -877,6 +1019,9 @@
drive->wcache = 1;
write_cache(drive, 1);
@@ -583,9 +621,9 @@ diff -Naur a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
static void ide_cacheflush_p(ide_drive_t *drive)
diff -Naur a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
---- a/drivers/ide/ide-io.c 2008-01-20 14:45:41.000000000 +0100
-+++ b/drivers/ide/ide-io.c 2008-01-20 14:47:50.000000000 +0100
-@@ -1271,6 +1271,17 @@
+--- a/drivers/ide/ide-io.c 2008-04-13 14:04:31.000000000 +0200
++++ b/drivers/ide/ide-io.c 2008-04-13 14:25:48.000000000 +0200
+@@ -1158,6 +1158,17 @@
}
/*
@@ -603,7 +641,7 @@ diff -Naur a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
* Sanity: don't accept a request that isn't a PM request
* if we are currently power managed. This is very important as
* blk_stop_queue() doesn't prevent the elv_next_request()
-@@ -1768,6 +1779,9 @@
+@@ -1651,6 +1662,9 @@
where = ELEVATOR_INSERT_FRONT;
rq->cmd_flags |= REQ_PREEMPT;
}
@@ -614,9 +652,9 @@ diff -Naur a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
ide_do_request(hwgroup, IDE_NO_IRQ);
spin_unlock_irqrestore(&ide_lock, flags);
diff -Naur a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
---- a/drivers/scsi/scsi_lib.c 2008-01-20 14:45:43.000000000 +0100
-+++ b/drivers/scsi/scsi_lib.c 2008-01-20 14:49:04.000000000 +0100
-@@ -2268,7 +2268,13 @@
+--- a/drivers/scsi/scsi_lib.c 2008-04-13 14:04:50.000000000 +0200
++++ b/drivers/scsi/scsi_lib.c 2008-04-13 14:25:48.000000000 +0200
+@@ -2248,7 +2248,13 @@
int
scsi_device_quiesce(struct scsi_device *sdev)
{
@@ -630,7 +668,7 @@ diff -Naur a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
if (err)
return err;
-@@ -2518,3 +2524,168 @@
+@@ -2496,3 +2502,168 @@
kunmap_atomic(virt, KM_BIO_SRC_IRQ);
}
EXPORT_SYMBOL(scsi_kunmap_atomic_sg);
@@ -760,8 +798,8 @@ diff -Naur a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+ siocs.waiting = &wait;
+
+ rc = scsi_execute_async(sdev, scsi_cmd, COMMAND_SIZE(scsi_cmd[0]),
-+ DMA_NONE, NULL, 0, 0, (10*HZ), 5,
-+ &siocs, &scsi_protect_wait_done, GFP_NOWAIT);
++ DMA_NONE, NULL, 0, 0, (10*HZ), 5,
++ &siocs, &scsi_protect_wait_done, GFP_NOWAIT);
+ if (rc)
+ goto out;
+ wait_for_completion(&wait);
@@ -800,9 +838,9 @@ diff -Naur a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+}
+EXPORT_SYMBOL_GPL(scsi_protect_queue);
diff -Naur a/include/linux/ata.h b/include/linux/ata.h
---- a/include/linux/ata.h 2008-01-20 14:45:45.000000000 +0100
-+++ b/include/linux/ata.h 2008-01-20 14:47:50.000000000 +0100
-@@ -395,6 +395,18 @@
+--- a/include/linux/ata.h 2008-04-13 14:04:53.000000000 +0200
++++ b/include/linux/ata.h 2008-04-13 14:25:48.000000000 +0200
+@@ -459,6 +459,18 @@
#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
@@ -822,27 +860,27 @@ diff -Naur a/include/linux/ata.h b/include/linux/ata.h
{
u16 val = id[76];
diff -Naur a/include/linux/blkdev.h b/include/linux/blkdev.h
---- a/include/linux/blkdev.h 2008-01-20 14:45:45.000000000 +0100
-+++ b/include/linux/blkdev.h 2008-01-20 14:47:50.000000000 +0100
-@@ -332,6 +332,8 @@
- typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *);
+--- a/include/linux/blkdev.h 2008-04-13 14:04:53.000000000 +0200
++++ b/include/linux/blkdev.h 2008-04-13 14:25:48.000000000 +0200
+@@ -260,6 +260,8 @@
typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
typedef void (softirq_done_fn)(struct request *);
+ typedef int (dma_drain_needed_fn)(struct request *);
+typedef int (issue_protect_fn) (struct request_queue *);
+typedef int (issue_unprotect_fn) (struct request_queue *);
enum blk_queue_state {
Queue_down,
-@@ -368,6 +370,8 @@
- merge_bvec_fn *merge_bvec_fn;
+@@ -297,6 +299,8 @@
prepare_flush_fn *prepare_flush_fn;
softirq_done_fn *softirq_done_fn;
+ dma_drain_needed_fn *dma_drain_needed;
+ issue_protect_fn *issue_protect_fn;
+ issue_unprotect_fn *issue_unprotect_fn;
/*
* Dispatch queue sorting
-@@ -383,6 +387,14 @@
+@@ -312,6 +316,14 @@
unsigned long unplug_delay; /* After this many jiffies */
struct work_struct unplug_work;
@@ -857,7 +895,7 @@ diff -Naur a/include/linux/blkdev.h b/include/linux/blkdev.h
struct backing_dev_info backing_dev_info;
/*
-@@ -773,6 +785,8 @@
+@@ -718,6 +730,8 @@
extern unsigned blk_ordered_cur_seq(struct request_queue *);
extern unsigned blk_ordered_req_seq(struct request *);
extern void blk_ordered_complete_seq(struct request_queue *, unsigned, int);
@@ -867,9 +905,9 @@ diff -Naur a/include/linux/blkdev.h b/include/linux/blkdev.h
extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
extern void blk_dump_rq_flags(struct request *, char *);
diff -Naur a/include/linux/ide.h b/include/linux/ide.h
---- a/include/linux/ide.h 2008-01-20 14:45:45.000000000 +0100
-+++ b/include/linux/ide.h 2008-01-20 14:47:50.000000000 +0100
-@@ -1045,6 +1045,7 @@
+--- a/include/linux/ide.h 2008-04-13 14:04:53.000000000 +0200
++++ b/include/linux/ide.h 2008-04-13 14:25:48.000000000 +0200
+@@ -837,6 +837,7 @@
*/
typedef enum {
ide_wait, /* insert rq at end of list, and wait for it */
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/02-ipw2200-inject-for-2.6.25.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/02-ipw2200-inject-for-2.6.25.patch
new file mode 100644
index 0000000..ffb49a9
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/02-ipw2200-inject-for-2.6.25.patch
@@ -0,0 +1,77 @@
+--- a/drivers/net/wireless/ipw2200.c 2007-10-07 12:41:29.000000000 +0200
++++ b/drivers/net/wireless/ipw2200.c 2007-10-07 12:50:43.000000000 +0200
+@@ -1860,6 +1860,66 @@
+ static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
+ show_net_stats, store_net_stats);
+
++static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, int pri);
++
++/* SYSFS INJECT */
++static ssize_t store_inject(struct device *d,
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
++ struct device_attribute *attr,
++#endif
++ const char *buf, size_t count)
++{
++ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
++ struct ieee80211_device *ieee = priv->ieee;
++ struct ieee80211_txb * txb;
++ struct sk_buff *skb_frag;
++ unsigned char * newbuf;
++ unsigned long flags;
++
++ // should test (ieee->is_queue_full)
++
++ // Fw only accepts data, so avoid accidental fw errors.
++ if ( (buf[0]&0x0c) != '\x08') {
++ //printk("ipw2200: inject: discarding non-data frame (type=%02X)\n",(int)(unsigned char)buf[0]);
++ return count;
++ }
++
++ if (count>1500) {
++ count=1500;
++ printk("ipw2200: inject: cutting down frame to 1500 bytes\n");
++ }
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ // Create a txb with one skb
++ txb = kmalloc(sizeof(struct ieee80211_txb) + sizeof(u8 *), GFP_ATOMIC);
++ if (!txb)
++ goto nosepuede;
++ txb->nr_frags=1;
++ txb->frag_size = ieee->tx_headroom;
++ txb->fragments[0]=__dev_alloc_skb(count + ieee->tx_headroom, GFP_ATOMIC);
++ if (!txb->fragments[0]) {
++ kfree(txb);
++ goto nosepuede;
++ }
++ skb_reserve(txb->fragments[0], ieee->tx_headroom);
++ txb->encrypted=0;
++ txb->payload_size=count;
++ skb_frag = txb->fragments[0];
++ newbuf=skb_put(skb_frag, count);
++
++ // copy data into txb->skb and send it
++ memcpy(newbuf, buf, count);
++
++ ipw_tx_skb(priv, txb, 0);
++
++nosepuede:
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return count;
++}
++
++static DEVICE_ATTR(inject, S_IWUSR, NULL, store_inject);
++
+ static ssize_t show_channels(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+@@ -11498,6 +11558,7 @@
+ #ifdef CONFIG_IPW2200_PROMISCUOUS
+ &dev_attr_rtap_iface.attr,
+ &dev_attr_rtap_filter.attr,
++ &dev_attr_inject.attr,
+ #endif
+ NULL
+ };
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/03-libata-acpi_hotplug_fixups-for-2.6.25.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/03-libata-acpi_hotplug_fixups-for-2.6.25.patch
new file mode 100644
index 0000000..8cd7b7f
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/03-libata-acpi_hotplug_fixups-for-2.6.25.patch
@@ -0,0 +1,215 @@
+diff -Naur a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
+--- a/drivers/ata/libata-acpi.c 2008-05-15 17:00:12.000000000 +0200
++++ b/drivers/ata/libata-acpi.c 2008-06-03 20:53:52.000000000 +0200
+@@ -118,19 +118,82 @@
+ ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
+ }
+
++static void ata_acpi_eject_device(acpi_handle handle)
++{
++ struct acpi_object_list arg_list;
++ union acpi_object arg;
++
++ arg_list.count = 1;
++ arg_list.pointer = &arg;
++ arg.type = ACPI_TYPE_INTEGER;
++ arg.integer.value = 1;
++
++ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
++ &arg_list, NULL)))
++ printk(KERN_ERR "Failed to evaluate _EJ0!\n");
++}
++
++/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
++static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
++{
++ if (dev)
++ dev->flags |= ATA_DFLAG_DETACH;
++ else {
++ struct ata_link *tlink;
++ struct ata_device *tdev;
++
++ ata_port_for_each_link(tlink, ap)
++ ata_link_for_each_dev(tdev, tlink)
++ tdev->flags |= ATA_DFLAG_DETACH;
++ }
++
++ ata_port_schedule_eh(ap);
++}
++
++/**
++ * ata_acpi_handle_hotplug - ACPI event handler backend
++ * @ap: ATA port ACPI event occurred
++ * @dev: ATA device ACPI event occurred (can be NULL)
++ * @event: ACPI event which occurred
++ * @is_dock_event: boolean indicating whether the event was a dock one
++ *
++ * All ACPI bay / device realted events end up in this function. If
++ * the event is port-wide @dev is NULL. If the event is specific to a
++ * device, @dev points to it.
++ *
++ * Hotplug (as opposed to unplug) notification is always handled as
++ * port-wide while unplug only kills the target device on device-wide
++ * event.
++ *
++ * LOCKING:
++ * ACPI notify handler context. May sleep.
++ */
+ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
+- u32 event)
++ u32 event, int is_dock_event)
+ {
+ char event_string[12];
+ char *envp[] = { event_string, NULL };
+- struct ata_eh_info *ehi;
++ struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct kobject *kobj = NULL;
+ int wait = 0;
+ unsigned long flags;
++ acpi_handle handle, tmphandle;
++ unsigned long sta;
++ acpi_status status;
++
++ if (dev) {
++ if (dev->sdev)
++ kobj = &dev->sdev->sdev_gendev.kobj;
++ handle = dev->acpi_handle;
++ } else {
++ kobj = &ap->dev->kobj;
++ handle = ap->acpi_handle;
++ }
+
+- if (!ap)
+- ap = dev->link->ap;
+- ehi = &ap->link.eh_info;
++ status = acpi_get_handle(handle, "_EJ0", &tmphandle);
++ if (ACPI_FAILURE(status))
++ /* This device does not support hotplug */
++ return;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+@@ -138,57 +201,80 @@
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ ata_ehi_push_desc(ehi, "ACPI event");
+- ata_ehi_hotplugged(ehi);
+- ata_port_freeze(ap);
+- break;
+
++ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
++ if (ACPI_FAILURE(status)) {
++ ata_port_printk(ap, KERN_ERR,
++ "acpi: failed to determine bay status (0x%x)\n",
++ status);
++ break;
++ }
++
++ if (sta) {
++ ata_ehi_hotplugged(ehi);
++ ata_port_freeze(ap);
++ } else {
++ /* The device has gone - unplug it */
++ ata_acpi_detach_device(ap, dev);
++ wait = 1;
++ }
++ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ ata_ehi_push_desc(ehi, "ACPI event");
+- if (dev)
+- dev->flags |= ATA_DFLAG_DETACH;
+- else {
+- struct ata_link *tlink;
+- struct ata_device *tdev;
+-
+- ata_port_for_each_link(tlink, ap)
+- ata_link_for_each_dev(tdev, tlink)
+- tdev->flags |= ATA_DFLAG_DETACH;
+- }
+
+- ata_port_schedule_eh(ap);
++ if (!is_dock_event)
++ break;
++
++ /* undock event - immediate unplug */
++ ata_acpi_detach_device(ap, dev);
+ wait = 1;
+ break;
+ }
+
+- if (dev) {
+- if (dev->sdev)
+- kobj = &dev->sdev->sdev_gendev.kobj;
+- } else
+- kobj = &ap->dev->kobj;
++ /* make sure kobj doesn't go away while ap->lock is released */
++ kobject_get(kobj);
++
++ spin_unlock_irqrestore(ap->lock, flags);
++
++ if (wait) {
++ ata_port_wait_eh(ap);
++ ata_acpi_eject_device(handle);
++ }
+
+- if (kobj) {
++ if (kobj && !is_dock_event) {
+ sprintf(event_string, "BAY_EVENT=%d", event);
+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+ }
+
+- spin_unlock_irqrestore(ap->lock, flags);
++ kobject_put(kobj);
++}
+
+- if (wait)
+- ata_port_wait_eh(ap);
++static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
++{
++ struct ata_device *dev = data;
++
++ ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
++}
++
++static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
++{
++ struct ata_port *ap = data;
++
++ ata_acpi_handle_hotplug(ap, NULL, event, 1);
+ }
+
+ static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+ {
+ struct ata_device *dev = data;
+
+- ata_acpi_handle_hotplug(NULL, dev, event);
++ ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
+ }
+
+ static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+ {
+ struct ata_port *ap = data;
+
+- ata_acpi_handle_hotplug(ap, NULL, event);
++ ata_acpi_handle_hotplug(ap, NULL, event, 0);
+ }
+
+ /**
+@@ -230,7 +316,7 @@
+ #if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
+ /* we might be on a docking station */
+ register_hotplug_dock_device(ap->acpi_handle,
+- ata_acpi_ap_notify, ap);
++ ata_acpi_ap_notify_dock, ap);
+ #endif
+ }
+
+@@ -244,7 +330,7 @@
+ #if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
+ /* we might be on a docking station */
+ register_hotplug_dock_device(dev->acpi_handle,
+- ata_acpi_dev_notify, dev);
++ ata_acpi_dev_notify_dock, dev);
+ #endif
+ }
+ }
diff --git a/sys-kernel/thinkpad-sources/files/2.6.24/linux-phc-0.3.1-for-2.6.24-rc1.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/04-linux-phc-0.3.1-for-2.6.25.patch
index 695743b..f40f581 100644
--- a/sys-kernel/thinkpad-sources/files/2.6.24/linux-phc-0.3.1-for-2.6.24-rc1.patch
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/04-linux-phc-0.3.1-for-2.6.25.patch
@@ -17,9 +17,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/sched.h>
-@@ -57,16 +62,22 @@
- };
-
+@@ -59,12 +59,18 @@
#define INTEL_MSR_RANGE (0xffff)
#define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1)
@@ -37,10 +35,8 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+ acpi_integer *original_controls;
};
- static struct acpi_cpufreq_data *drv_data[NR_CPUS];
- /* acpi_perf_data is a pointer to percpu data. */
- static struct acpi_processor_performance *acpi_perf_data;
-@@ -101,17 +112,19 @@
+ static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data);
+@@ -102,17 +113,19 @@
}
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
@@ -65,7 +61,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
@@ -729,10 +742,12 @@
if (data) {
cpufreq_frequency_table_put_attr(policy->cpu);
- drv_data[policy->cpu] = NULL;
+ per_cpu(drv_data, policy->cpu) = NULL;
acpi_processor_unregister_performance(data->acpi_data,
policy->cpu);
+ if (data->original_controls)
@@ -122,7 +118,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+
+static ssize_t show_freq_attr_vids(struct cpufreq_policy *policy, char *buf)
+{
-+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
++ struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+ struct acpi_processor_performance *acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int i;
@@ -150,7 +146,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+
+static ssize_t show_freq_attr_default_vids(struct cpufreq_policy *policy, char *buf)
+{
-+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
++ struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int i;
+ unsigned int vid;
@@ -181,7 +177,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+
+static ssize_t show_freq_attr_fids(struct cpufreq_policy *policy, char *buf)
+{
-+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
++ struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+ struct acpi_processor_performance *acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int i;
@@ -209,7 +205,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+
+static ssize_t show_freq_attr_controls(struct cpufreq_policy *policy, char *buf)
+{
-+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
++ struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+ struct acpi_processor_performance *acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int i;
@@ -239,7 +235,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+
+static ssize_t show_freq_attr_default_controls(struct cpufreq_policy *policy, char *buf)
+{
-+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
++ struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int i;
+ unsigned int fid;
@@ -273,7 +269,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+
+static ssize_t store_freq_attr_vids(struct cpufreq_policy *policy, const char *buf, size_t count)
+{
-+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
++ struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+ struct acpi_processor_performance *acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int freq_index;
@@ -340,7 +336,7 @@ diff --new-file -a --unified=5 --recursive linux-2.6.24-rc1/arch/x86/kernel/cpu/
+
+static ssize_t store_freq_attr_controls(struct cpufreq_policy *policy, const char *buf, size_t count)
+{
-+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
++ struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+ struct acpi_processor_performance *acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ const char *curr_buf;
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part1.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part1.patch
new file mode 100644
index 0000000..e239571
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part1.patch
@@ -0,0 +1,113 @@
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index 47c6be8..a55a1c9 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -58,6 +58,49 @@ config VT_CONSOLE
+
+ If unsure, say Y.
+
++config VT_CKO
++ bool "Colored kernel message output"
++ depends on VT_CONSOLE
++ ---help---
++ This option enables kernel messages to be emitted in
++ colors other than the default.
++ This option enlarges your kernel by approximately 1/2 KB.
++
++ If unsure, say N.
++
++config VT_PRINTK_COLOR
++ hex "Colored kernel message output"
++ range 0x00 0xFF
++ depends on VT_CKO
++ default 0x07
++ ---help---
++ This option defines with which color kernel messages will be
++ printed to the console.
++
++ The value you need to enter here is the value is composed
++ (OR-ed) of a foreground and a background color.
++
++ Foreground:
++ 0x00 = black, 0x08 = dark gray,
++ 0x01 = red, 0x09 = light red,
++ 0x02 = green, 0x0A = light green,
++ 0x03 = brown, 0x0B = yellow,
++ 0x04 = blue, 0x0C = light blue,
++ 0x05 = magenta, 0x0D = light magenta,
++ 0x06 = cyan, 0x0E = light cyan,
++ 0x07 = gray, 0x0F = white,
++
++ (Foreground colors 0x08 to 0x0F do not work when a VGA
++ console font with 512 glyphs is used.)
++
++ Background:
++ 0x00 = black, 0x40 = blue,
++ 0x10 = red, 0x50 = magenta,
++ 0x20 = green, 0x60 = cyan,
++ 0x30 = brown, 0x70 = gray,
++
++ For example, 0x1F would yield white on red.
++
+ config HW_CONSOLE
+ bool
+ depends on VT && !S390 && !UML
+diff --git a/drivers/char/vt.c b/drivers/char/vt.c
+index 159c9e2..cf61236 100644
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -73,6 +73,7 @@
+ */
+
+ #include <linux/module.h>
++#include <linux/moduleparam.h>
+ #include <linux/types.h>
+ #include <linux/sched.h>
+ #include <linux/tty.h>
+@@ -2392,6 +2393,24 @@ struct tty_driver *console_driver;
+
+ #ifdef CONFIG_VT_CONSOLE
+
++#ifdef CONFIG_VT_CKO
++static unsigned int printk_color __read_mostly = CONFIG_VT_PRINTK_COLOR;
++module_param(printk_color, uint, S_IRUGO | S_IWUSR);
++
++static void vc_set_color(struct vc_data *vc, unsigned char color)
++{
++ vc->vc_color = color_table[color & 0xF] |
++ (color_table[(color >> 4) & 0x7] << 4) |
++ (color & 0x80);
++ update_attr(vc);
++}
++#else
++static const unsigned int printk_color;
++static inline void vc_set_color(const struct vc_data *vc, unsigned char c)
++{
++}
++#endif
++
+ /*
+ * Console on virtual terminal
+ *
+@@ -2434,6 +2453,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
+ hide_cursor(vc);
+
+ start = (ushort *)vc->vc_pos;
++ vc_set_color(vc, printk_color);
+
+ /* Contrived structure to try to emulate original need_wrap behaviour
+ * Problems caused when we have need_wrap set on '\n' character */
+@@ -2482,6 +2502,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
+ }
+ }
+ set_cursor(vc);
++ vc_set_color(vc, vc->vc_def_color);
+ notify_update(vc);
+
+ quit:
+--
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at http://www.tux.org/lkml/
+
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part2.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part2.patch
new file mode 100644
index 0000000..231e9d0
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part2.patch
@@ -0,0 +1,220 @@
+diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
+index cff84cd..ba137a4 100644
+--- a/arch/x86/kernel/early_printk.c
++++ b/arch/x86/kernel/early_printk.c
+@@ -15,7 +15,8 @@
+ static int max_ypos = 25, max_xpos = 80;
+ static int current_ypos = 25, current_xpos = 0;
+
+-static void early_vga_write(struct console *con, const char *str, unsigned n)
++static void early_vga_write(struct console *con, const char *str, unsigned n,
++ unsigned int loglevel)
+ {
+ char c;
+ int i, k, j;
+@@ -84,7 +85,8 @@ static int early_serial_putc(unsigned char ch)
+ return timeout ? 0 : -1;
+ }
+
+-static void early_serial_write(struct console *con, const char *s, unsigned n)
++static void early_serial_write(struct console *con, const char *s, unsigned n,
++ unsigned int loglevel)
+ {
+ while (*s && n-- > 0) {
+ if (*s == '\n')
+@@ -180,7 +182,8 @@ static void __init simnow_init(char *str)
+ simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644);
+ }
+
+-static void simnow_write(struct console *con, const char *s, unsigned n)
++static void simnow_write(struct console *con, const char *s, unsigned n,
++ unsigned int loglevel)
+ {
+ simnow(XWRITE, simnow_fd, (unsigned long)s, n);
+ }
+@@ -204,7 +207,7 @@ void early_printk(const char *fmt, ...)
+
+ va_start(ap,fmt);
+ n = vscnprintf(buf,512,fmt,ap);
+- early_console->write(early_console,buf,n);
++ early_console->write(early_console, buf, n, 0);
+ va_end(ap);
+ }
+
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index a55a1c9..3f5877e 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -75,7 +75,9 @@ config VT_PRINTK_COLOR
+ default 0x07
+ ---help---
+ This option defines with which color kernel messages will be
+- printed to the console.
++ printed to the console. This applies to all log levels.
++ You can change the colors at run-time, or set them at boot-time
++ using the "vt.printk_color" option.
+
+ The value you need to enter here is the value is composed
+ (OR-ed) of a foreground and a background color.
+diff --git a/drivers/char/vt.c b/drivers/char/vt.c
+index cf61236..75ca0cf 100644
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -2394,8 +2394,17 @@ struct tty_driver *console_driver;
+ #ifdef CONFIG_VT_CONSOLE
+
+ #ifdef CONFIG_VT_CKO
+-static unsigned int printk_color __read_mostly = CONFIG_VT_PRINTK_COLOR;
+-module_param(printk_color, uint, S_IRUGO | S_IWUSR);
++static unsigned int printk_color[8] __read_mostly = {
++ CONFIG_VT_PRINTK_COLOR, /* KERN_EMERG */
++ CONFIG_VT_PRINTK_COLOR, /* KERN_ALERT */
++ CONFIG_VT_PRINTK_COLOR, /* KERN_CRIT */
++ CONFIG_VT_PRINTK_COLOR, /* KERN_ERR */
++ CONFIG_VT_PRINTK_COLOR, /* KERN_WARNING */
++ CONFIG_VT_PRINTK_COLOR, /* KERN_NOTICE */
++ CONFIG_VT_PRINTK_COLOR, /* KERN_INFO */
++ CONFIG_VT_PRINTK_COLOR, /* KERN_DEBUG */
++};
++module_param_array(printk_color, uint, NULL, S_IRUGO | S_IWUSR);
+
+ static void vc_set_color(struct vc_data *vc, unsigned char color)
+ {
+@@ -2405,7 +2414,7 @@ static void vc_set_color(struct vc_data *vc, unsigned char color)
+ update_attr(vc);
+ }
+ #else
+-static const unsigned int printk_color;
++static const unsigned int printk_color[8];
+ static inline void vc_set_color(const struct vc_data *vc, unsigned char c)
+ {
+ }
+@@ -2417,10 +2426,11 @@ static inline void vc_set_color(const struct vc_data *vc, unsigned char c)
+ * The console must be locked when we get here.
+ */
+
+-static void vt_console_print(struct console *co, const char *b, unsigned count)
++static void vt_console_print(struct console *co, const char *b,
++ unsigned int count, unsigned int loglevel)
+ {
+ struct vc_data *vc = vc_cons[fg_console].d;
+- unsigned char c;
++ unsigned char current_color, c;
+ static DEFINE_SPINLOCK(printing_lock);
+ const ushort *start;
+ ushort cnt = 0;
+@@ -2453,7 +2463,13 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
+ hide_cursor(vc);
+
+ start = (ushort *)vc->vc_pos;
+- vc_set_color(vc, printk_color);
++
++ /*
++ * We always get a valid loglevel - <8> and "no level" is transformed
++ * to <4> in the typical kernel.
++ */
++ current_color = printk_color[loglevel];
++ vc_set_color(vc, current_color);
+
+ /* Contrived structure to try to emulate original need_wrap behaviour
+ * Problems caused when we have need_wrap set on '\n' character */
+diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
+index 665341e..ae04e77 100644
+--- a/drivers/net/netconsole.c
++++ b/drivers/net/netconsole.c
+@@ -694,7 +694,8 @@ static struct notifier_block netconsole_netdev_notifier = {
+ .notifier_call = netconsole_netdev_event,
+ };
+
+-static void write_msg(struct console *con, const char *msg, unsigned int len)
++static void write_msg(struct console *con, const char *msg, unsigned int len,
++ unsigned int loglevel)
+ {
+ int frag, left;
+ unsigned long flags;
+diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
+index 77f7a7f..21a0ebf 100644
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -2466,7 +2466,8 @@ static void serial8250_console_putchar(struct uart_port *port, int ch)
+ * The console_lock must be held when we get here.
+ */
+ static void
+-serial8250_console_write(struct console *co, const char *s, unsigned int count)
++serial8250_console_write(struct console *co, const char *s, unsigned int count,
++ unsigned int loglevel)
+ {
+ struct uart_8250_port *up = &serial8250_ports[co->index];
+ unsigned long flags;
+diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
+index 38776e8..88aa01c 100644
+--- a/drivers/serial/8250_early.c
++++ b/drivers/serial/8250_early.c
+@@ -83,7 +83,8 @@ static void __init serial_putc(struct uart_port *port, int c)
+ }
+
+ static void __init early_serial8250_write(struct console *console,
+- const char *s, unsigned int count)
++ const char *s, unsigned int count,
++ unsigned int loglevel)
+ {
+ struct uart_port *port = &early_device.port;
+ unsigned int ier;
+diff --git a/include/linux/console.h b/include/linux/console.h
+index a5f88a6..23626e6 100644
+--- a/include/linux/console.h
++++ b/include/linux/console.h
+@@ -94,7 +94,8 @@ void give_up_console(const struct consw *sw);
+
+ struct console {
+ char name[16];
+- void (*write)(struct console *, const char *, unsigned);
++ void (*write)(struct console *, const char *,
++ unsigned int, unsigned int);
+ int (*read)(struct console *, char *, unsigned);
+ struct tty_driver *(*device)(struct console *, int *);
+ void (*unblank)(void);
+diff --git a/kernel/printk.c b/kernel/printk.c
+index bdd4ea8..809ba4b 100644
+--- a/kernel/printk.c
++++ b/kernel/printk.c
+@@ -435,7 +435,8 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len)
+ /*
+ * Call the console drivers on a range of log_buf
+ */
+-static void __call_console_drivers(unsigned start, unsigned end)
++static void __call_console_drivers(unsigned int start, unsigned int end,
++ unsigned int loglevel)
+ {
+ struct console *con;
+
+@@ -443,7 +444,7 @@ static void __call_console_drivers(unsigned start, unsigned end)
+ if ((con->flags & CON_ENABLED) && con->write &&
+ (cpu_online(smp_processor_id()) ||
+ (con->flags & CON_ANYTIME)))
+- con->write(con, &LOG_BUF(start), end - start);
++ con->write(con, &LOG_BUF(start), end - start, loglevel);
+ }
+ }
+
+@@ -470,10 +471,11 @@ static void _call_console_drivers(unsigned start,
+ if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
+ /* wrapped write */
+ __call_console_drivers(start & LOG_BUF_MASK,
+- log_buf_len);
+- __call_console_drivers(0, end & LOG_BUF_MASK);
++ log_buf_len, msg_log_level);
++ __call_console_drivers(0, end & LOG_BUF_MASK,
++ msg_log_level);
+ } else {
+- __call_console_drivers(start, end);
++ __call_console_drivers(start, end, msg_log_level);
+ }
+ }
+ }
+--
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at http://www.tux.org/lkml/
+
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part3.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part3.patch
new file mode 100644
index 0000000..06d9f6c
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/colored-printk-2.6.25.part3.patch
@@ -0,0 +1,146 @@
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index 3f5877e..600c75a 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -58,28 +58,20 @@ config VT_CONSOLE
+
+ If unsure, say Y.
+
+-config VT_CKO
++menuconfig VT_CKO
+ bool "Colored kernel message output"
+ depends on VT_CONSOLE
+ ---help---
+ This option enables kernel messages to be emitted in
+ colors other than the default.
++ You can also change the colors at run-time, or set them at boot-time
++ using the "vt.printk_color" option.
++
+ This option enlarges your kernel by approximately 1/2 KB.
+
+ If unsure, say N.
+
+-config VT_PRINTK_COLOR
+- hex "Colored kernel message output"
+- range 0x00 0xFF
+- depends on VT_CKO
+- default 0x07
+- ---help---
+- This option defines with which color kernel messages will be
+- printed to the console. This applies to all log levels.
+- You can change the colors at run-time, or set them at boot-time
+- using the "vt.printk_color" option.
+-
+- The value you need to enter here is the value is composed
++ The value you need to enter is the value is composed
+ (OR-ed) of a foreground and a background color.
+
+ Foreground:
+@@ -103,6 +95,74 @@ config VT_PRINTK_COLOR
+
+ For example, 0x1F would yield white on red.
+
++if VT_CKO
++
++config VT_PRINTK_EMERG_COLOR
++ hex 'Color for "emergency" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color kernel emergency messages
++ will be printed to the console.
++
++config VT_PRINTK_ALERT_COLOR
++ hex 'Color for "alert" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color kernel alert messages
++ will be printed to the console.
++
++config VT_PRINTK_CRIT_COLOR
++ hex 'Color for "critical" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color critical kernel messages
++ will be printed to the console.
++
++config VT_PRINTK_ERROR_COLOR
++ hex 'Color for "error" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color kernel error messages
++ will be printed to the console.
++
++config VT_PRINTK_WARNING_COLOR
++ hex 'Color for "warning" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color kernel warning messages
++ will be printed to the console.
++
++config VT_PRINTK_NOTICE_COLOR
++ hex 'Color for "notice" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color kernel notices
++ will be printed to the console.
++
++config VT_PRINTK_INFO_COLOR
++ hex 'Color for "info" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color informational kernel messages
++ will be printed to the console.
++
++config VT_PRINTK_DEBUG_COLOR
++ hex 'Color for "debug" level'
++ range 0x00 0xFF
++ default 0x07
++ ---help---
++ This option defines in which color kernel debugging messages
++ will be printed to the console.
++
++endif # VT_CKO
++
+ config HW_CONSOLE
+ bool
+ depends on VT && !S390 && !UML
+diff --git a/drivers/char/vt.c b/drivers/char/vt.c
+index 75ca0cf..a3f2ff3 100644
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -2395,14 +2395,14 @@ struct tty_driver *console_driver;
+
+ #ifdef CONFIG_VT_CKO
+ static unsigned int printk_color[8] __read_mostly = {
+- CONFIG_VT_PRINTK_COLOR, /* KERN_EMERG */
+- CONFIG_VT_PRINTK_COLOR, /* KERN_ALERT */
+- CONFIG_VT_PRINTK_COLOR, /* KERN_CRIT */
+- CONFIG_VT_PRINTK_COLOR, /* KERN_ERR */
+- CONFIG_VT_PRINTK_COLOR, /* KERN_WARNING */
+- CONFIG_VT_PRINTK_COLOR, /* KERN_NOTICE */
+- CONFIG_VT_PRINTK_COLOR, /* KERN_INFO */
+- CONFIG_VT_PRINTK_COLOR, /* KERN_DEBUG */
++ CONFIG_VT_PRINTK_EMERG_COLOR,
++ CONFIG_VT_PRINTK_ALERT_COLOR,
++ CONFIG_VT_PRINTK_CRIT_COLOR,
++ CONFIG_VT_PRINTK_ERROR_COLOR,
++ CONFIG_VT_PRINTK_WARNING_COLOR,
++ CONFIG_VT_PRINTK_NOTICE_COLOR,
++ CONFIG_VT_PRINTK_INFO_COLOR,
++ CONFIG_VT_PRINTK_DEBUG_COLOR,
+ };
+ module_param_array(printk_color, uint, NULL, S_IRUGO | S_IWUSR);
+
+--
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at http://www.tux.org/lkml/
+
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-export-init_mm.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-export-init_mm.patch
new file mode 100644
index 0000000..5f95a6b
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-export-init_mm.patch
@@ -0,0 +1,11 @@
+--- arch/x86/kernel/init_task.c.orig 2008-04-17 04:49:44.000000000 +0200
++++ arch/x86/kernel/init_task.c 2008-04-17 23:52:15.000000000 +0200
+@@ -15,7 +15,7 @@
+ static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+ static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+ struct mm_struct init_mm = INIT_MM(init_mm);
+-EXPORT_UNUSED_SYMBOL(init_mm); /* will be removed in 2.6.26 */
++EXPORT_SYMBOL(init_mm); /* will be removed in 2.6.26 */ // temporary kludge
+
+ /*
+ * Initial thread structure.
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-rcu-license.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-rcu-license.patch
new file mode 100644
index 0000000..fbdb7c2
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/kernel-2.6.25-rcu-license.patch
@@ -0,0 +1,20 @@
+--- kernel/rcupreempt.c.orig 2008-04-17 04:49:44.000000000 +0200
++++ kernel/rcupreempt.c 2008-04-19 12:27:19.000000000 +0200
+@@ -283,7 +283,7 @@
+ local_irq_restore(flags);
+ }
+ }
+-EXPORT_SYMBOL_GPL(__rcu_read_lock);
++EXPORT_SYMBOL(__rcu_read_lock);
+
+ void __rcu_read_unlock(void)
+ {
+@@ -353,7 +353,7 @@
+ local_irq_restore(flags);
+ }
+ }
+-EXPORT_SYMBOL_GPL(__rcu_read_unlock);
++EXPORT_SYMBOL(__rcu_read_unlock);
+
+ /*
+ * If a global counter flip has occurred since the last time that we
diff --git a/sys-kernel/thinkpad-sources/files/2.6.25-r1/linux-2.6.25-iwl-merge.patch b/sys-kernel/thinkpad-sources/files/2.6.25-r1/linux-2.6.25-iwl-merge.patch
new file mode 100644
index 0000000..f000009
--- /dev/null
+++ b/sys-kernel/thinkpad-sources/files/2.6.25-r1/linux-2.6.25-iwl-merge.patch
@@ -0,0 +1,124255 @@
+diff -Nbur linux-2.6.25.old/Documentation/DocBook/mac80211.tmpl linux-2.6.25/Documentation/DocBook/mac80211.tmpl
+--- linux-2.6.25.old/Documentation/DocBook/mac80211.tmpl 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.25/Documentation/DocBook/mac80211.tmpl 2008-04-19 13:54:59.000000000 +0200
+@@ -0,0 +1,335 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
++ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
++
++<book id="mac80211-developers-guide">
++ <bookinfo>
++ <title>The mac80211 subsystem for kernel developers</title>
++
++ <authorgroup>
++ <author>
++ <firstname>Johannes</firstname>
++ <surname>Berg</surname>
++ <affiliation>
++ <address><email>johannes@sipsolutions.net</email></address>
++ </affiliation>
++ </author>
++ </authorgroup>
++
++ <copyright>
++ <year>2007</year>
++ <year>2008</year>
++ <holder>Johannes Berg</holder>
++ </copyright>
++
++ <legalnotice>
++ <para>
++ This documentation is free software; you can redistribute
++ it and/or modify it under the terms of the GNU General Public
++ License version 2 as published by the Free Software Foundation.
++ </para>
++
++ <para>
++ This documentation 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.
++ </para>
++
++ <para>
++ You should have received a copy of the GNU General Public
++ License along with this documentation; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ MA 02111-1307 USA
++ </para>
++
++ <para>
++ For more details see the file COPYING in the source
++ distribution of Linux.
++ </para>
++ </legalnotice>
++
++ <abstract>
++!Pinclude/net/mac80211.h Introduction
++!Pinclude/net/mac80211.h Warning
++ </abstract>
++ </bookinfo>
++
++ <toc></toc>
++
++<!--
++Generally, this document shall be ordered by increasing complexity.
++It is important to note that readers should be able to read only
++the first few sections to get a working driver and only advanced
++usage should require reading the full document.
++-->
++
++ <part>
++ <title>The basic mac80211 driver interface</title>
++ <partintro>
++ <para>
++ You should read and understand the information contained
++ within this part of the book while implementing a driver.
++ In some chapters, advanced usage is noted, that may be
++ skipped at first.
++ </para>
++ <para>
++ This part of the book only covers station and monitor mode
++ functionality, additional information required to implement
++ the other modes is covered in the second part of the book.
++ </para>
++ </partintro>
++
++ <chapter id="basics">
++ <title>Basic hardware handling</title>
++ <para>TBD</para>
++ <para>
++ This chapter shall contain information on getting a hw
++ struct allocated and registered with mac80211.
++ </para>
++ <para>
++ Since it is required to allocate rates/modes before registering
++ a hw struct, this chapter shall also contain information on setting
++ up the rate/mode structs.
++ </para>
++ <para>
++ Additionally, some discussion about the callbacks and
++ the general programming model should be in here, including
++ the definition of ieee80211_ops which will be referred to
++ a lot.
++ </para>
++ <para>
++ Finally, a discussion of hardware capabilities should be done
++ with references to other parts of the book.
++ </para>
++<!-- intentionally multiple !F lines to get proper order -->
++!Finclude/net/mac80211.h ieee80211_hw
++!Finclude/net/mac80211.h ieee80211_hw_flags
++!Finclude/net/mac80211.h SET_IEEE80211_DEV
++!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
++!Finclude/net/mac80211.h ieee80211_ops
++!Finclude/net/mac80211.h ieee80211_alloc_hw
++!Finclude/net/mac80211.h ieee80211_register_hw
++!Finclude/net/mac80211.h ieee80211_get_tx_led_name
++!Finclude/net/mac80211.h ieee80211_get_rx_led_name
++!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
++!Finclude/net/mac80211.h ieee80211_get_radio_led_name
++!Finclude/net/mac80211.h ieee80211_unregister_hw
++!Finclude/net/mac80211.h ieee80211_free_hw
++ </chapter>
++
++ <chapter id="phy-handling">
++ <title>PHY configuration</title>
++ <para>TBD</para>
++ <para>
++ This chapter should describe PHY handling including
++ start/stop callbacks and the various structures used.
++ </para>
++!Finclude/net/mac80211.h ieee80211_conf
++!Finclude/net/mac80211.h ieee80211_conf_flags
++ </chapter>
++
++ <chapter id="iface-handling">
++ <title>Virtual interfaces</title>
++ <para>TBD</para>
++ <para>
++ This chapter should describe virtual interface basics
++ that are relevant to the driver (VLANs, MGMT etc are not.)
++ It should explain the use of the add_iface/remove_iface
++ callbacks as well as the interface configuration callbacks.
++ </para>
++ <para>Things related to AP mode should be discussed there.</para>
++ <para>
++ Things related to supporting multiple interfaces should be
++ in the appropriate chapter, a BIG FAT note should be here about
++ this though and the recommendation to allow only a single
++ interface in STA mode at first!
++ </para>
++!Finclude/net/mac80211.h ieee80211_if_types
++!Finclude/net/mac80211.h ieee80211_if_init_conf
++!Finclude/net/mac80211.h ieee80211_if_conf
++ </chapter>
++
++ <chapter id="rx-tx">
++ <title>Receive and transmit processing</title>
++ <sect1>
++ <title>what should be here</title>
++ <para>TBD</para>
++ <para>
++ This should describe the receive and transmit
++ paths in mac80211/the drivers as well as
++ transmit status handling.
++ </para>
++ </sect1>
++ <sect1>
++ <title>Frame format</title>
++!Pinclude/net/mac80211.h Frame format
++ </sect1>
++ <sect1>
++ <title>Alignment issues</title>
++ <para>TBD</para>
++ </sect1>
++ <sect1>
++ <title>Calling into mac80211 from interrupts</title>
++!Pinclude/net/mac80211.h Calling mac80211 from interrupts
++ </sect1>
++ <sect1>
++ <title>functions/definitions</title>
++!Finclude/net/mac80211.h ieee80211_rx_status
++!Finclude/net/mac80211.h mac80211_rx_flags
++!Finclude/net/mac80211.h ieee80211_tx_control
++!Finclude/net/mac80211.h ieee80211_tx_status_flags
++!Finclude/net/mac80211.h ieee80211_rx
++!Finclude/net/mac80211.h ieee80211_rx_irqsafe
++!Finclude/net/mac80211.h ieee80211_tx_status
++!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
++!Finclude/net/mac80211.h ieee80211_rts_get
++!Finclude/net/mac80211.h ieee80211_rts_duration
++!Finclude/net/mac80211.h ieee80211_ctstoself_get
++!Finclude/net/mac80211.h ieee80211_ctstoself_duration
++!Finclude/net/mac80211.h ieee80211_generic_frame_duration
++!Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb
++!Finclude/net/mac80211.h ieee80211_get_hdrlen
++!Finclude/net/mac80211.h ieee80211_wake_queue
++!Finclude/net/mac80211.h ieee80211_stop_queue
++!Finclude/net/mac80211.h ieee80211_start_queues
++!Finclude/net/mac80211.h ieee80211_stop_queues
++!Finclude/net/mac80211.h ieee80211_wake_queues
++ </sect1>
++ </chapter>
++
++ <chapter id="filters">
++ <title>Frame filtering</title>
++!Pinclude/net/mac80211.h Frame filtering
++!Finclude/net/mac80211.h ieee80211_filter_flags
++ </chapter>
++ </part>
++
++ <part id="advanced">
++ <title>Advanced driver interface</title>
++ <partintro>
++ <para>
++ Information contained within this part of the book is
++ of interest only for advanced interaction of mac80211
++ with drivers to exploit more hardware capabilities and
++ improve performance.
++ </para>
++ </partintro>
++
++ <chapter id="hardware-crypto-offload">
++ <title>Hardware crypto acceleration</title>
++!Pinclude/net/mac80211.h Hardware crypto acceleration
++<!-- intentionally multiple !F lines to get proper order -->
++!Finclude/net/mac80211.h set_key_cmd
++!Finclude/net/mac80211.h ieee80211_key_conf
++!Finclude/net/mac80211.h ieee80211_key_alg
++!Finclude/net/mac80211.h ieee80211_key_flags
++ </chapter>
++
++ <chapter id="qos">
++ <title>Multiple queues and QoS support</title>
++ <para>TBD</para>
++!Finclude/net/mac80211.h ieee80211_tx_queue_params
++!Finclude/net/mac80211.h ieee80211_tx_queue_stats_data
++!Finclude/net/mac80211.h ieee80211_tx_queue
++ </chapter>
++
++ <chapter id="AP">
++ <title>Access point mode support</title>
++ <para>TBD</para>
++ <para>Some parts of the if_conf should be discussed here instead</para>
++ <para>
++ Insert notes about VLAN interfaces with hw crypto here or
++ in the hw crypto chapter.
++ </para>
++!Finclude/net/mac80211.h ieee80211_get_buffered_bc
++!Finclude/net/mac80211.h ieee80211_beacon_get
++ </chapter>
++
++ <chapter id="multi-iface">
++ <title>Supporting multiple virtual interfaces</title>
++ <para>TBD</para>
++ <para>
++ Note: WDS with identical MAC address should almost always be OK
++ </para>
++ <para>
++ Insert notes about having multiple virtual interfaces with
++ different MAC addresses here, note which configurations are
++ supported by mac80211, add notes about supporting hw crypto
++ with it.
++ </para>
++ </chapter>
++
++ <chapter id="hardware-scan-offload">
++ <title>Hardware scan offload</title>
++ <para>TBD</para>
++!Finclude/net/mac80211.h ieee80211_scan_completed
++ </chapter>
++ </part>
++
++ <part id="rate-control">
++ <title>Rate control interface</title>
++ <partintro>
++ <para>TBD</para>
++ <para>
++ This part of the book describes the rate control algorithm
++ interface and how it relates to mac80211 and drivers.
++ </para>
++ </partintro>
++ <chapter id="dummy">
++ <title>dummy chapter</title>
++ <para>TBD</para>
++ </chapter>
++ </part>
++
++ <part id="internal">
++ <title>Internals</title>
++ <partintro>
++ <para>TBD</para>
++ <para>
++ This part of the book describes mac80211 internals.
++ </para>
++ </partintro>
++
++ <chapter id="key-handling">
++ <title>Key handling</title>
++ <sect1>
++ <title>Key handling basics</title>
++!Pnet/mac80211/key.c Key handling basics
++ </sect1>
++ <sect1>
++ <title>MORE TBD</title>
++ <para>TBD</para>
++ </sect1>
++ </chapter>
++
++ <chapter id="rx-processing">
++ <title>Receive processing</title>
++ <para>TBD</para>
++ </chapter>
++
++ <chapter id="tx-processing">
++ <title>Transmit processing</title>
++ <para>TBD</para>
++ </chapter>
++
++ <chapter id="sta-info">
++ <title>Station info handling</title>
++ <sect1>
++ <title>Programming information</title>
++!Fnet/mac80211/sta_info.h sta_info
++!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
++ </sect1>
++ <sect1>
++ <title>STA information lifetime rules</title>
++!Pnet/mac80211/sta_info.c STA information lifetime rules
++ </sect1>
++ </chapter>
++
++ <chapter id="synchronisation">
++ <title>Synchronisation</title>
++ <para>TBD</para>
++ <para>Locking, lots of RCU</para>
++ </chapter>
++ </part>
++</book>
+diff -Nbur linux-2.6.25.old/Documentation/DocBook/Makefile linux-2.6.25/Documentation/DocBook/Makefile
+--- linux-2.6.25.old/Documentation/DocBook/Makefile 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/Documentation/DocBook/Makefile 2008-04-19 16:23:24.000000000 +0200
+@@ -11,7 +11,8 @@
+ procfs-guide.xml writing_usb_driver.xml networking.xml \
+ kernel-api.xml filesystems.xml lsm.xml usb.xml \
+ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
+- genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml
++ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
++ mac80211.xml
+
+ ###
+ # The build process is as follows (targets):
+diff -Nbur linux-2.6.25.old/Documentation/feature-removal-schedule.txt linux-2.6.25/Documentation/feature-removal-schedule.txt
+--- linux-2.6.25.old/Documentation/feature-removal-schedule.txt 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/Documentation/feature-removal-schedule.txt 2008-04-19 16:23:24.000000000 +0200
+@@ -230,33 +230,6 @@
+
+ ---------------------------
+
+-What: bcm43xx wireless network driver
+-When: 2.6.26
+-Files: drivers/net/wireless/bcm43xx
+-Why: This driver's functionality has been replaced by the
+- mac80211-based b43 and b43legacy drivers.
+-Who: John W. Linville <linville@tuxdriver.com>
+-
+----------------------------
+-
+-What: ieee80211 softmac wireless networking component
+-When: 2.6.26 (or after removal of bcm43xx and port of zd1211rw to mac80211)
+-Files: net/ieee80211/softmac
+-Why: No in-kernel drivers will depend on it any longer.
+-Who: John W. Linville <linville@tuxdriver.com>
+-
+----------------------------
+-
+-What: rc80211-simple rate control algorithm for mac80211
+-When: 2.6.26
+-Files: net/mac80211/rc80211-simple.c
+-Why: This algorithm was provided for reference but always exhibited bad
+- responsiveness and performance and has some serious flaws. It has been
+- replaced by rc80211-pid.
+-Who: Stefano Brivio <stefano.brivio@polimi.it>
+-
+----------------------------
+-
+ What (Why):
+ - include/linux/netfilter_ipv4/ipt_TOS.h ipt_tos.h header files
+ (superseded by xt_TOS/xt_tos target & match)
+diff -Nbur linux-2.6.25.old/Documentation/laptops/acer-wmi.txt linux-2.6.25/Documentation/laptops/acer-wmi.txt
+--- linux-2.6.25.old/Documentation/laptops/acer-wmi.txt 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/Documentation/laptops/acer-wmi.txt 2008-04-19 13:54:59.000000000 +0200
+@@ -80,7 +80,7 @@
+ e.g. With the BCM4318 on the Acer Aspire 5020 series:
+
+ ndiswrapper: Light blinks on when transmitting
+-bcm43xx/b43: Solid light, blinks off when transmitting
++b43: Solid light, blinks off when transmitting
+
+ Wireless radio control is unconditionally enabled - all Acer laptops that support
+ acer-wmi come with built-in wireless. However, should you feel so inclined to
+diff -Nbur linux-2.6.25.old/Documentation/networking/bcm43xx.txt linux-2.6.25/Documentation/networking/bcm43xx.txt
+--- linux-2.6.25.old/Documentation/networking/bcm43xx.txt 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/Documentation/networking/bcm43xx.txt 1970-01-01 01:00:00.000000000 +0100
+@@ -1,89 +0,0 @@
+-
+- BCM43xx Linux Driver Project
+- ============================
+-
+-Introduction
+-------------
+-
+-Many of the wireless devices found in modern notebook computers are
+-based on the wireless chips produced by Broadcom. These devices have
+-been a problem for Linux users as there is no open-source driver
+-available. In addition, Broadcom has not released specifications
+-for the device, and driver availability has been limited to the
+-binary-only form used in the GPL versions of AP hardware such as the
+-Linksys WRT54G, and the Windows and OS X drivers. Before this project
+-began, the only way to use these devices were to use the Windows or
+-OS X drivers with either the Linuxant or ndiswrapper modules. There
+-is a strong penalty if this method is used as loading the binary-only
+-module "taints" the kernel, and no kernel developer will help diagnose
+-any kernel problems.
+-
+-Development
+------------
+-
+-This driver has been developed using
+-a clean-room technique that is described at
+-http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal
+-reasons, none of the clean-room crew works on the on the Linux driver,
+-and none of the Linux developers sees anything but the specifications,
+-which are the ultimate product of the reverse-engineering group.
+-
+-Software
+---------
+-
+-Since the release of the 2.6.17 kernel, the bcm43xx driver has been
+-distributed with the kernel source, and is prebuilt in most, if not
+-all, distributions. There is, however, additional software that is
+-required. The firmware used by the chip is the intellectual property
+-of Broadcom and they have not given the bcm43xx team redistribution
+-rights to this firmware. Since we cannot legally redistribute
+-the firmware we cannot include it with the driver. Furthermore, it
+-cannot be placed in the downloadable archives of any distributing
+-organization; therefore, the user is responsible for obtaining the
+-firmware and placing it in the appropriate location so that the driver
+-can find it when initializing.
+-
+-To help with this process, the bcm43xx developers provide a separate
+-program named bcm43xx-fwcutter to "cut" the firmware out of a
+-Windows or OS X driver and write the extracted files to the proper
+-location. This program is usually provided with the distribution;
+-however, it may be downloaded from
+-
+-http://developer.berlios.de/project/showfiles.php?group_id=4547
+-
+-The firmware is available in two versions. V3 firmware is used with
+-the in-kernel bcm43xx driver that uses a software MAC layer called
+-SoftMAC, and will have a microcode revision of 0x127 or smaller. The
+-V4 firmware is used by an out-of-kernel driver employing a variation of
+-the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches
+-a satisfactory level of development, it will replace bcm43xx-softmac
+-in the kernel as it is much more flexible and powerful.
+-
+-A source for the latest V3 firmware is
+-
+-http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o
+-
+-Once this file is downloaded, the command
+-'bcm43xx-fwcutter -w <dir> <filename>'
+-will extract the microcode and write it to directory
+-<dir>. The correct directory will depend on your distribution;
+-however, most use '/lib/firmware'. Once this step is completed,
+-the bcm3xx driver should load when the system is booted. To see
+-any messages relating to the driver, issue the command 'dmesg |
+-grep bcm43xx' from a terminal window. If there are any problems,
+-please send that output to Bcm43xx-dev@lists.berlios.de.
+-
+-Although the driver has been in-kernel since 2.6.17, the earliest
+-version is quite limited in its capability. Patches that include
+-all features of later versions are available for the stable kernel
+-versions from 2.6.18. These will be needed if you use a BCM4318,
+-or a PCI Express version (BCM4311 and BCM4312). In addition, if you
+-have an early BCM4306 and more than 1 GB RAM, your kernel will need
+-to be patched. These patches, which are being updated regularly,
+-are available at ftp://lwfinger.dynalias.org/patches. Look for
+-combined_2.6.YY.patch. Of course you will need kernel source downloaded
+-from kernel.org, or the source from your distribution.
+-
+-If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG
+-and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is
+-essential for solving any problems.
+diff -Nbur linux-2.6.25.old/drivers/net/ps3_gelic_wireless.c linux-2.6.25/drivers/net/ps3_gelic_wireless.c
+--- linux-2.6.25.old/drivers/net/ps3_gelic_wireless.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/ps3_gelic_wireless.c 2008-04-19 16:24:28.000000000 +0200
+@@ -87,7 +87,7 @@
+
+ static inline int precise_ie(void)
+ {
+- return 0; /* FIXME */
++ return (0 <= ps3_compare_firmware_version(2, 2, 0));
+ }
+ /*
+ * post_eurus_cmd helpers
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/adm8211.c linux-2.6.25/drivers/net/wireless/adm8211.c
+--- linux-2.6.25.old/drivers/net/wireless/adm8211.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/adm8211.c 2008-04-19 13:54:59.000000000 +0200
+@@ -48,6 +48,32 @@
+ { 0 }
+ };
+
++static struct ieee80211_rate adm8211_rates[] = {
++ { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
++ { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
++ { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
++ { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
++ { .bitrate = 220, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, /* XX ?? */
++};
++
++static const struct ieee80211_channel adm8211_channels[] = {
++ { .center_freq = 2412},
++ { .center_freq = 2417},
++ { .center_freq = 2422},
++ { .center_freq = 2427},
++ { .center_freq = 2432},
++ { .center_freq = 2437},
++ { .center_freq = 2442},
++ { .center_freq = 2447},
++ { .center_freq = 2452},
++ { .center_freq = 2457},
++ { .center_freq = 2462},
++ { .center_freq = 2467},
++ { .center_freq = 2472},
++ { .center_freq = 2484},
++};
++
++
+ static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+ {
+ struct adm8211_priv *priv = eeprom->data;
+@@ -155,17 +181,17 @@
+ printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n",
+ pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max);
+
+- priv->modes[0].num_channels = chan_range.max - chan_range.min + 1;
+- priv->modes[0].channels = priv->channels;
++ BUILD_BUG_ON(sizeof(priv->channels) != sizeof(adm8211_channels));
+
+- memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels));
++ memcpy(priv->channels, adm8211_channels, sizeof(priv->channels));
++ priv->band.channels = priv->channels;
++ priv->band.n_channels = ARRAY_SIZE(adm8211_channels);
++ priv->band.bitrates = adm8211_rates;
++ priv->band.n_bitrates = ARRAY_SIZE(adm8211_rates);
+
+ for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++)
+- if (i >= chan_range.min && i <= chan_range.max)
+- priv->channels[i - 1].flag =
+- IEEE80211_CHAN_W_SCAN |
+- IEEE80211_CHAN_W_ACTIVE_SCAN |
+- IEEE80211_CHAN_W_IBSS;
++ if (i < chan_range.min || i > chan_range.max)
++ priv->channels[i - 1].flags |= IEEE80211_CHAN_DISABLED;
+
+ switch (priv->eeprom->specific_bbptype) {
+ case ADM8211_BBP_RFMD3000:
+@@ -347,7 +373,6 @@
+ unsigned int pktlen;
+ struct sk_buff *skb, *newskb;
+ unsigned int limit = priv->rx_ring_size;
+- static const u8 rate_tbl[] = {10, 20, 55, 110, 220};
+ u8 rssi, rate;
+
+ while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) {
+@@ -425,12 +450,10 @@
+ else
+ rx_status.ssi = 100 - rssi;
+
+- if (rate <= 4)
+- rx_status.rate = rate_tbl[rate];
++ rx_status.rate_idx = rate;
+
+- rx_status.channel = priv->channel;
+- rx_status.freq = adm8211_channels[priv->channel - 1].freq;
+- rx_status.phymode = MODE_IEEE80211B;
++ rx_status.freq = adm8211_channels[priv->channel - 1].center_freq;
++ rx_status.band = IEEE80211_BAND_2GHZ;
+
+ ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ }
+@@ -465,9 +488,6 @@
+ if (stsr & ADM8211_STSR_TCI)
+ adm8211_interrupt_tci(dev);
+
+- /*ADM8211_INT(LinkOn);*/
+- /*ADM8211_INT(LinkOff);*/
+-
+ ADM8211_INT(PCF);
+ ADM8211_INT(BCNTC);
+ ADM8211_INT(GPINT);
+@@ -477,7 +497,6 @@
+ ADM8211_INT(SQL);
+ ADM8211_INT(WEPTD);
+ ADM8211_INT(ATIME);
+- /*ADM8211_INT(TBTT);*/
+ ADM8211_INT(TEIS);
+ ADM8211_INT(FBE);
+ ADM8211_INT(REIS);
+@@ -485,9 +504,6 @@
+ ADM8211_INT(RPS);
+ ADM8211_INT(RDU);
+ ADM8211_INT(TUF);
+- /*ADM8211_INT(TRT);*/
+- /*ADM8211_INT(TLT);*/
+- /*ADM8211_INT(TDU);*/
+ ADM8211_INT(TPS);
+
+ return IRQ_HANDLED;
+@@ -1054,7 +1070,7 @@
+ if (priv->pdev->revision != ADM8211_REV_BA) {
+ rate_buf[0] = ARRAY_SIZE(adm8211_rates);
+ for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++)
+- rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80;
++ rate_buf[i + 1] = (adm8211_rates[i].bitrate / 5) | 0x80;
+ } else {
+ /* workaround for rev BA specific bug */
+ rate_buf[0] = 0x04;
+@@ -1086,7 +1102,7 @@
+ u32 reg;
+ u8 cline;
+
+- reg = le32_to_cpu(ADM8211_CSR_READ(PAR));
++ reg = ADM8211_CSR_READ(PAR);
+ reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME;
+ reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL);
+
+@@ -1303,9 +1319,10 @@
+ static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+ {
+ struct adm8211_priv *priv = dev->priv;
++ int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+
+- if (conf->channel != priv->channel) {
+- priv->channel = conf->channel;
++ if (channel != priv->channel) {
++ priv->channel = channel;
+ adm8211_rf_set_channel(dev, priv->channel);
+ }
+
+@@ -1678,13 +1695,9 @@
+ int plcp, dur, len, plcp_signal, short_preamble;
+ struct ieee80211_hdr *hdr;
+
+- if (control->tx_rate < 0) {
+- short_preamble = 1;
+- plcp_signal = -control->tx_rate;
+- } else {
+- short_preamble = 0;
+- plcp_signal = control->tx_rate;
+- }
++ short_preamble = !!(control->tx_rate->flags &
++ IEEE80211_TXCTL_SHORT_PREAMBLE);
++ plcp_signal = control->tx_rate->bitrate;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
+@@ -1880,18 +1893,11 @@
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+
+ dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
+- dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+- /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
++ /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
+
+ dev->channel_change_time = 1000;
+ dev->max_rssi = 100; /* FIXME: find better value */
+
+- priv->modes[0].mode = MODE_IEEE80211B;
+- /* channel info filled in by adm8211_read_eeprom */
+- memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));
+- priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);
+- priv->modes[0].rates = priv->rates;
+-
+ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
+
+ priv->retry_limit = 3;
+@@ -1917,14 +1923,9 @@
+ goto err_free_desc;
+ }
+
+- priv->channel = priv->modes[0].channels[0].chan;
++ priv->channel = 1;
+
+- err = ieee80211_register_hwmode(dev, &priv->modes[0]);
+- if (err) {
+- printk(KERN_ERR "%s (adm8211): Can't register hwmode\n",
+- pci_name(pdev));
+- goto err_free_desc;
+- }
++ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/adm8211.h linux-2.6.25/drivers/net/wireless/adm8211.h
+--- linux-2.6.25.old/drivers/net/wireless/adm8211.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/adm8211.h 2008-04-19 13:54:59.000000000 +0200
+@@ -534,61 +534,6 @@
+ u8 cis_data[0]; /* 0x80, 384 bytes */
+ } __attribute__ ((packed));
+
+-static const struct ieee80211_rate adm8211_rates[] = {
+- { .rate = 10,
+- .val = 10,
+- .val2 = -10,
+- .flags = IEEE80211_RATE_CCK_2 },
+- { .rate = 20,
+- .val = 20,
+- .val2 = -20,
+- .flags = IEEE80211_RATE_CCK_2 },
+- { .rate = 55,
+- .val = 55,
+- .val2 = -55,
+- .flags = IEEE80211_RATE_CCK_2 },
+- { .rate = 110,
+- .val = 110,
+- .val2 = -110,
+- .flags = IEEE80211_RATE_CCK_2 }
+-};
+-
+-struct ieee80211_chan_range {
+- u8 min;
+- u8 max;
+-};
+-
+-static const struct ieee80211_channel adm8211_channels[] = {
+- { .chan = 1,
+- .freq = 2412},
+- { .chan = 2,
+- .freq = 2417},
+- { .chan = 3,
+- .freq = 2422},
+- { .chan = 4,
+- .freq = 2427},
+- { .chan = 5,
+- .freq = 2432},
+- { .chan = 6,
+- .freq = 2437},
+- { .chan = 7,
+- .freq = 2442},
+- { .chan = 8,
+- .freq = 2447},
+- { .chan = 9,
+- .freq = 2452},
+- { .chan = 10,
+- .freq = 2457},
+- { .chan = 11,
+- .freq = 2462},
+- { .chan = 12,
+- .freq = 2467},
+- { .chan = 13,
+- .freq = 2472},
+- { .chan = 14,
+- .freq = 2484},
+-};
+-
+ struct adm8211_priv {
+ struct pci_dev *pdev;
+ spinlock_t lock;
+@@ -603,9 +548,8 @@
+ unsigned int cur_tx, dirty_tx, cur_rx;
+
+ struct ieee80211_low_level_stats stats;
+- struct ieee80211_hw_mode modes[1];
+- struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)];
+- struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)];
++ struct ieee80211_supported_band band;
++ struct ieee80211_channel channels[14];
+ int mode;
+
+ int channel;
+@@ -643,6 +587,11 @@
+ } transceiver_type;
+ };
+
++struct ieee80211_chan_range {
++ u8 min;
++ u8 max;
++};
++
+ static const struct ieee80211_chan_range cranges[] = {
+ {1, 11}, /* FCC */
+ {1, 11}, /* IC */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/at76_usb.c linux-2.6.25/drivers/net/wireless/at76_usb.c
+--- linux-2.6.25.old/drivers/net/wireless/at76_usb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.25/drivers/net/wireless/at76_usb.c 2008-04-19 16:23:26.000000000 +0200
+@@ -0,0 +1,2518 @@
++/*
++ * at76c503/at76c505 USB driver
++ *
++ * Copyright (c) 2002 - 2003 Oliver Kurth
++ * Copyright (c) 2004 Joerg Albert <joerg.albert@gmx.de>
++ * Copyright (c) 2004 Nick Jones
++ * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
++ * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
++ * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>
++ *
++ * This program is free software; you can redistribute it 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 part of the Berlios driver for WLAN USB devices based on the
++ * Atmel AT76C503A/505/505A.
++ *
++ * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed
++ *
++ * TODO for the mac80211 port:
++ * o adhoc support
++ * o RTS/CTS support
++ * o Power Save Mode support
++ * o support for short/long preambles
++ * o export variables through debugfs/sysfs
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/usb.h>
++#include <linux/netdevice.h>
++#include <linux/if_arp.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/wireless.h>
++#include <net/iw_handler.h>
++#include <net/ieee80211_radiotap.h>
++#include <linux/firmware.h>
++#include <linux/leds.h>
++#include <net/mac80211.h>
++
++#include "at76_usb.h"
++
++/* Version information */
++#define DRIVER_NAME "at76_usb"
++#define DRIVER_VERSION "0.17"
++#define DRIVER_DESC "Atmel at76x USB Wireless LAN Driver"
++
++/* at76_debug bits */
++#define DBG_PROGRESS 0x00000001 /* authentication/accociation */
++#define DBG_BSS_TABLE 0x00000002 /* show BSS table after scans */
++#define DBG_IOCTL 0x00000004 /* ioctl calls / settings */
++#define DBG_MAC_STATE 0x00000008 /* MAC state transitions */
++#define DBG_TX_DATA 0x00000010 /* tx header */
++#define DBG_TX_DATA_CONTENT 0x00000020 /* tx content */
++#define DBG_TX_MGMT 0x00000040 /* tx management */
++#define DBG_RX_DATA 0x00000080 /* rx data header */
++#define DBG_RX_DATA_CONTENT 0x00000100 /* rx data content */
++#define DBG_RX_MGMT 0x00000200 /* rx mgmt frame headers */
++#define DBG_RX_BEACON 0x00000400 /* rx beacon */
++#define DBG_RX_CTRL 0x00000800 /* rx control */
++#define DBG_RX_MGMT_CONTENT 0x00001000 /* rx mgmt content */
++#define DBG_RX_FRAGS 0x00002000 /* rx data fragment handling */
++#define DBG_DEVSTART 0x00004000 /* fw download, device start */
++#define DBG_URB 0x00008000 /* rx urb status, ... */
++#define DBG_RX_ATMEL_HDR 0x00010000 /* Atmel-specific Rx headers */
++#define DBG_PROC_ENTRY 0x00020000 /* procedure entries/exits */
++#define DBG_PM 0x00040000 /* power management settings */
++#define DBG_BSS_MATCH 0x00080000 /* BSS match failures */
++#define DBG_PARAMS 0x00100000 /* show configured parameters */
++#define DBG_WAIT_COMPLETE 0x00200000 /* command completion */
++#define DBG_RX_FRAGS_SKB 0x00400000 /* skb header of Rx fragments */
++#define DBG_BSS_TABLE_RM 0x00800000 /* purging bss table entries */
++#define DBG_MONITOR_MODE 0x01000000 /* monitor mode */
++#define DBG_MIB 0x02000000 /* dump all MIBs on startup */
++#define DBG_MGMT_TIMER 0x04000000 /* dump mgmt_timer ops */
++#define DBG_WE_EVENTS 0x08000000 /* dump wireless events */
++#define DBG_FW 0x10000000 /* firmware download */
++#define DBG_DFU 0x20000000 /* device firmware upgrade */
++#define DBG_CMD 0x40000000
++#define DBG_MAC80211 0x80000000
++
++#define DBG_DEFAULTS 0
++
++/* Use our own dbg macro */
++#define at76_dbg(bits, format, arg...) \
++ do { \
++ if (at76_debug & (bits)) \
++ printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , ## arg); \
++ } while (0)
++
++#define at76_dbg_dump(bits, buf, len, format, arg...) \
++ do { \
++ if (at76_debug & (bits)) { \
++ printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , ## arg); \
++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); \
++ } \
++ } while (0)
++
++static int at76_debug = DBG_DEFAULTS;
++
++/* Protect against concurrent firmware loading and parsing */
++static struct mutex fw_mutex;
++
++static struct fwentry firmwares[] = {
++ [0] = { "" },
++ [BOARD_503_ISL3861] = { "atmel_at76c503-i3861.bin" },
++ [BOARD_503_ISL3863] = { "atmel_at76c503-i3863.bin" },
++ [BOARD_503] = { "atmel_at76c503-rfmd.bin" },
++ [BOARD_503_ACC] = { "atmel_at76c503-rfmd-acc.bin" },
++ [BOARD_505] = { "atmel_at76c505-rfmd.bin" },
++ [BOARD_505_2958] = { "atmel_at76c505-rfmd2958.bin" },
++ [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" },
++ [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" },
++};
++
++#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
++
++static struct usb_device_id dev_table[] = {
++ /*
++ * at76c503-i3861
++ */
++ /* Generic AT76C503/3861 device */
++ { USB_DEVICE(0x03eb, 0x7603), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Linksys WUSB11 v2.1/v2.6 */
++ { USB_DEVICE(0x066b, 0x2211), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Netgear MA101 rev. A */
++ { USB_DEVICE(0x0864, 0x4100), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Tekram U300C / Allnet ALL0193 */
++ { USB_DEVICE(0x0b3b, 0x1612), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* HP HN210W J7801A */
++ { USB_DEVICE(0x03f0, 0x011c), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Sitecom/Z-Com/Zyxel M4Y-750 */
++ { USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Dynalink/Askey WLL013 (intersil) */
++ { USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */
++ { USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* BenQ AWL300 */
++ { USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Addtron AWU-120, Compex WLU11 */
++ { USB_DEVICE(0x05dd, 0xff31), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Intel AP310 AnyPoint II USB */
++ { USB_DEVICE(0x8086, 0x0200), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Dynalink L11U */
++ { USB_DEVICE(0x0d8e, 0x7100), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* Arescom WL-210, FCC id 07J-GL2411USB */
++ { USB_DEVICE(0x0d8e, 0x7110), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* I-O DATA WN-B11/USB */
++ { USB_DEVICE(0x04bb, 0x0919), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /* BT Voyager 1010 */
++ { USB_DEVICE(0x069a, 0x0821), USB_DEVICE_DATA(BOARD_503_ISL3861) },
++ /*
++ * at76c503-i3863
++ */
++ /* Generic AT76C503/3863 device */
++ { USB_DEVICE(0x03eb, 0x7604), USB_DEVICE_DATA(BOARD_503_ISL3863) },
++ /* Samsung SWL-2100U */
++ { USB_DEVICE(0x055d, 0xa000), USB_DEVICE_DATA(BOARD_503_ISL3863) },
++ /*
++ * at76c503-rfmd
++ */
++ /* Generic AT76C503/RFMD device */
++ { USB_DEVICE(0x03eb, 0x7605), USB_DEVICE_DATA(BOARD_503) },
++ /* Dynalink/Askey WLL013 (rfmd) */
++ { USB_DEVICE(0x069a, 0x0321), USB_DEVICE_DATA(BOARD_503) },
++ /* Linksys WUSB11 v2.6 */
++ { USB_DEVICE(0x077b, 0x2219), USB_DEVICE_DATA(BOARD_503) },
++ /* Network Everywhere NWU11B */
++ { USB_DEVICE(0x077b, 0x2227), USB_DEVICE_DATA(BOARD_503) },
++ /* Netgear MA101 rev. B */
++ { USB_DEVICE(0x0864, 0x4102), USB_DEVICE_DATA(BOARD_503) },
++ /* D-Link DWL-120 rev. E */
++ { USB_DEVICE(0x2001, 0x3200), USB_DEVICE_DATA(BOARD_503) },
++ /* Actiontec 802UAT1, HWU01150-01UK */
++ { USB_DEVICE(0x1668, 0x7605), USB_DEVICE_DATA(BOARD_503) },
++ /* AirVast W-Buddie WN210 */
++ { USB_DEVICE(0x03eb, 0x4102), USB_DEVICE_DATA(BOARD_503) },
++ /* Dick Smith Electronics XH1153 802.11b USB adapter */
++ { USB_DEVICE(0x1371, 0x5743), USB_DEVICE_DATA(BOARD_503) },
++ /* CNet CNUSB611 */
++ { USB_DEVICE(0x1371, 0x0001), USB_DEVICE_DATA(BOARD_503) },
++ /* FiberLine FL-WL200U */
++ { USB_DEVICE(0x1371, 0x0002), USB_DEVICE_DATA(BOARD_503) },
++ /* BenQ AWL400 USB stick */
++ { USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503) },
++ /* 3Com 3CRSHEW696 */
++ { USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503) },
++ /* Siemens Santis ADSL WLAN USB adapter WLL 013 */
++ { USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503) },
++ /* Belkin F5D6050, version 2 */
++ { USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503) },
++ /* iBlitzz, BWU613 (not *B or *SB) */
++ { USB_DEVICE(0x07b8, 0xb000), USB_DEVICE_DATA(BOARD_503) },
++ /* Gigabyte GN-WLBM101 */
++ { USB_DEVICE(0x1044, 0x8003), USB_DEVICE_DATA(BOARD_503) },
++ /* Planex GW-US11S */
++ { USB_DEVICE(0x2019, 0x3220), USB_DEVICE_DATA(BOARD_503) },
++ /* Internal WLAN adapter in h5[4,5]xx series iPAQs */
++ { USB_DEVICE(0x049f, 0x0032), USB_DEVICE_DATA(BOARD_503) },
++ /* Corega Wireless LAN USB-11 mini */
++ { USB_DEVICE(0x07aa, 0x0011), USB_DEVICE_DATA(BOARD_503) },
++ /* Corega Wireless LAN USB-11 mini2 */
++ { USB_DEVICE(0x07aa, 0x0018), USB_DEVICE_DATA(BOARD_503) },
++ /* Uniden PCW100 */
++ { USB_DEVICE(0x05dd, 0xff35), USB_DEVICE_DATA(BOARD_503) },
++ /*
++ * at76c503-rfmd-acc
++ */
++ /* SMC2664W */
++ { USB_DEVICE(0x083a, 0x3501), USB_DEVICE_DATA(BOARD_503_ACC) },
++ /* Belkin F5D6050, SMC2662W v2, SMC2662W-AR */
++ { USB_DEVICE(0x0d5c, 0xa002), USB_DEVICE_DATA(BOARD_503_ACC) },
++ /*
++ * at76c505-rfmd
++ */
++ /* Generic AT76C505/RFMD */
++ { USB_DEVICE(0x03eb, 0x7606), USB_DEVICE_DATA(BOARD_505) },
++ /*
++ * at76c505-rfmd2958
++ */
++ /* Generic AT76C505/RFMD, OvisLink WL-1130USB */
++ { USB_DEVICE(0x03eb, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },
++ /* Fiberline FL-WL240U */
++ { USB_DEVICE(0x1371, 0x0014), USB_DEVICE_DATA(BOARD_505_2958) },
++ /* CNet CNUSB-611G */
++ { USB_DEVICE(0x1371, 0x0013), USB_DEVICE_DATA(BOARD_505_2958) },
++ /* Linksys WUSB11 v2.8 */
++ { USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958) },
++ /* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */
++ { USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958) },
++ /* Corega WLAN USB Stick 11 */
++ { USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },
++ /* Microstar MSI Box MS6978 */
++ { USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958) },
++ /*
++ * at76c505a-rfmd2958
++ */
++ /* Generic AT76C505A device */
++ { USB_DEVICE(0x03eb, 0x7614), USB_DEVICE_DATA(BOARD_505A) },
++ /* Generic AT76C505AS device */
++ { USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A) },
++ /* Siemens Gigaset USB WLAN Adapter 11 */
++ { USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A) },
++ /*
++ * at76c505amx-rfmd
++ */
++ /* Generic AT76C505AMX device */
++ { USB_DEVICE(0x03eb, 0x7615), USB_DEVICE_DATA(BOARD_505AMX) },
++ { }
++};
++
++MODULE_DEVICE_TABLE(usb, dev_table);
++
++/* Supported rates of this hardware, bit 7 marks basic rates */
++static const u8 hw_rates[] = { 0x82, 0x84, 0x0b, 0x16 };
++
++static const char *const preambles[] = { "long", "short", "auto" };
++
++/* Firmware download */
++/* DFU states */
++#define STATE_IDLE 0x00
++#define STATE_DETACH 0x01
++#define STATE_DFU_IDLE 0x02
++#define STATE_DFU_DOWNLOAD_SYNC 0x03
++#define STATE_DFU_DOWNLOAD_BUSY 0x04
++#define STATE_DFU_DOWNLOAD_IDLE 0x05
++#define STATE_DFU_MANIFEST_SYNC 0x06
++#define STATE_DFU_MANIFEST 0x07
++#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
++#define STATE_DFU_UPLOAD_IDLE 0x09
++#define STATE_DFU_ERROR 0x0a
++
++/* DFU commands */
++#define DFU_DETACH 0
++#define DFU_DNLOAD 1
++#define DFU_UPLOAD 2
++#define DFU_GETSTATUS 3
++#define DFU_CLRSTATUS 4
++#define DFU_GETSTATE 5
++#define DFU_ABORT 6
++
++#define FW_BLOCK_SIZE 1024
++
++struct dfu_status {
++ unsigned char status;
++ unsigned char poll_timeout[3];
++ unsigned char state;
++ unsigned char string;
++} __attribute__((packed));
++
++static inline int at76_is_intersil(enum board_type board)
++{
++ return (board == BOARD_503_ISL3861 || board == BOARD_503_ISL3863);
++}
++
++static inline int at76_is_503rfmd(enum board_type board)
++{
++ return (board == BOARD_503 || board == BOARD_503_ACC);
++}
++
++static inline int at76_is_505a(enum board_type board)
++{
++ return (board == BOARD_505A || board == BOARD_505AMX);
++}
++
++/* Load a block of the first (internal) part of the firmware */
++static int at76_load_int_fw_block(struct usb_device *udev, int blockno,
++ void *block, int size)
++{
++ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), DFU_DNLOAD,
++ USB_TYPE_CLASS | USB_DIR_OUT |
++ USB_RECIP_INTERFACE, blockno, 0, block, size,
++ USB_CTRL_GET_TIMEOUT);
++}
++
++static int at76_dfu_get_status(struct usb_device *udev,
++ struct dfu_status *status)
++{
++ int ret;
++
++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATUS,
++ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
++ 0, 0, status, sizeof(struct dfu_status),
++ USB_CTRL_GET_TIMEOUT);
++ return ret;
++}
++
++static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)
++{
++ int ret;
++
++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATE,
++ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
++ 0, 0, state, 1, USB_CTRL_GET_TIMEOUT);
++ return ret;
++}
++
++/* Convert timeout from the DFU status to jiffies */
++static inline unsigned long at76_get_timeout(struct dfu_status *s)
++{
++ return msecs_to_jiffies((s->poll_timeout[2] << 16)
++ | (s->poll_timeout[1] << 8)
++ | (s->poll_timeout[0]));
++}
++
++/* Load internal firmware from the buffer. If manifest_sync_timeout > 0, use
++ * its value in jiffies in the MANIFEST_SYNC state. */
++static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
++ int manifest_sync_timeout)
++{
++ u8 *block;
++ struct dfu_status dfu_stat_buf;
++ int ret = 0;
++ int need_dfu_state = 1;
++ int is_done = 0;
++ u8 dfu_state = 0;
++ u32 dfu_timeout = 0;
++ int bsize = 0;
++ int blockno = 0;
++
++ at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size,
++ manifest_sync_timeout);
++
++ if (!size) {
++ dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n");
++ return -EINVAL;
++ }
++
++ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
++ if (!block)
++ return -ENOMEM;
++
++ do {
++ if (need_dfu_state) {
++ ret = at76_dfu_get_state(udev, &dfu_state);
++ if (ret < 0) {
++ dev_printk(KERN_ERR, &udev->dev,
++ "cannot get DFU state: %d\n", ret);
++ goto exit;
++ }
++ need_dfu_state = 0;
++ }
++
++ switch (dfu_state) {
++ case STATE_DFU_DOWNLOAD_SYNC:
++ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
++ ret = at76_dfu_get_status(udev, &dfu_stat_buf);
++ if (ret >= 0) {
++ dfu_state = dfu_stat_buf.state;
++ dfu_timeout = at76_get_timeout(&dfu_stat_buf);
++ need_dfu_state = 0;
++ } else
++ dev_printk(KERN_ERR, &udev->dev,
++ "at76_dfu_get_status returned %d\n",
++ ret);
++ break;
++
++ case STATE_DFU_DOWNLOAD_BUSY:
++ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY");
++ need_dfu_state = 1;
++
++ at76_dbg(DBG_DFU, "DFU: Resetting device");
++ schedule_timeout_interruptible(dfu_timeout);
++ break;
++
++ case STATE_DFU_DOWNLOAD_IDLE:
++ at76_dbg(DBG_DFU, "DOWNLOAD...");
++ /* fall through */
++ case STATE_DFU_IDLE:
++ at76_dbg(DBG_DFU, "DFU IDLE");
++
++ bsize = min_t(int, size, FW_BLOCK_SIZE);
++ memcpy(block, buf, bsize);
++ at76_dbg(DBG_DFU, "int fw, size left = %5d, "
++ "bsize = %4d, blockno = %2d", size, bsize,
++ blockno);
++ ret =
++ at76_load_int_fw_block(udev, blockno, block, bsize);
++ buf += bsize;
++ size -= bsize;
++ blockno++;
++
++ if (ret != bsize)
++ dev_printk(KERN_ERR, &udev->dev,
++ "at76_load_int_fw_block "
++ "returned %d\n", ret);
++ need_dfu_state = 1;
++ break;
++
++ case STATE_DFU_MANIFEST_SYNC:
++ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");
++
++ ret = at76_dfu_get_status(udev, &dfu_stat_buf);
++ if (ret < 0)
++ break;
++
++ dfu_state = dfu_stat_buf.state;
++ dfu_timeout = at76_get_timeout(&dfu_stat_buf);
++ need_dfu_state = 0;
++
++ /* override the timeout from the status response,
++ needed for AT76C505A */
++ if (manifest_sync_timeout > 0)
++ dfu_timeout = manifest_sync_timeout;
++
++ at76_dbg(DBG_DFU, "DFU: Waiting for manifest phase");
++ schedule_timeout_interruptible(dfu_timeout);
++ break;
++
++ case STATE_DFU_MANIFEST:
++ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST");
++ is_done = 1;
++ break;
++
++ case STATE_DFU_MANIFEST_WAIT_RESET:
++ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET");
++ is_done = 1;
++ break;
++
++ case STATE_DFU_UPLOAD_IDLE:
++ at76_dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE");
++ break;
++
++ case STATE_DFU_ERROR:
++ at76_dbg(DBG_DFU, "STATE_DFU_ERROR");
++ ret = -EPIPE;
++ break;
++
++ default:
++ at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
++ ret = -EINVAL;
++ break;
++ }
++ } while (!is_done && (ret >= 0));
++
++exit:
++ kfree(block);
++ if (ret >= 0)
++ ret = 0;
++
++ return ret;
++}
++
++#define HEX2STR_BUFFERS 4
++#define HEX2STR_MAX_LEN 64
++#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)
++
++/* Convert binary data into hex string */
++static char *hex2str(void *buf, int len)
++{
++ static atomic_t a = ATOMIC_INIT(0);
++ static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
++ char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)];
++ char *obuf = ret;
++ u8 *ibuf = buf;
++
++ if (len > HEX2STR_MAX_LEN)
++ len = HEX2STR_MAX_LEN;
++
++ if (len <= 0) {
++ ret[0] = '\0';
++ return ret;
++ }
++
++ while (len--) {
++ *obuf++ = BIN2HEX(*ibuf >> 4);
++ *obuf++ = BIN2HEX(*ibuf & 0xf);
++ *obuf++ = '-';
++ ibuf++;
++ }
++ *(--obuf) = '\0';
++
++ return ret;
++}
++
++#define MAC2STR_BUFFERS 4
++
++static inline char *mac2str(u8 *mac)
++{
++ static atomic_t a = ATOMIC_INIT(0);
++ static char bufs[MAC2STR_BUFFERS][6 * 3];
++ char *str;
++
++ str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)];
++ sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ return str;
++}
++
++/* LED trigger */
++static int tx_activity;
++static void at76_ledtrig_tx_timerfunc(unsigned long data);
++static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0);
++DEFINE_LED_TRIGGER(ledtrig_tx);
++
++static void at76_ledtrig_tx_timerfunc(unsigned long data)
++{
++ static int tx_lastactivity;
++
++ if (tx_lastactivity != tx_activity) {
++ tx_lastactivity = tx_activity;
++ led_trigger_event(ledtrig_tx, LED_FULL);
++ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);
++ } else
++ led_trigger_event(ledtrig_tx, LED_OFF);
++}
++
++static void at76_ledtrig_tx_activity(void)
++{
++ tx_activity++;
++ if (!timer_pending(&ledtrig_tx_timer))
++ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);
++}
++
++static int at76_remap(struct usb_device *udev)
++{
++ int ret;
++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0a,
++ USB_TYPE_VENDOR | USB_DIR_OUT |
++ USB_RECIP_INTERFACE, 0, 0, NULL, 0,
++ USB_CTRL_GET_TIMEOUT);
++ if (ret < 0)
++ return ret;
++ return 0;
++}
++
++static int at76_get_op_mode(struct usb_device *udev)
++{
++ int ret;
++ u8 op_mode;
++
++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
++ USB_TYPE_VENDOR | USB_DIR_IN |
++ USB_RECIP_INTERFACE, 0x01, 0, &op_mode, 1,
++ USB_CTRL_GET_TIMEOUT);
++ if (ret < 0)
++ return ret;
++ else if (ret < 1)
++ return -EIO;
++ else
++ return op_mode;
++}
++
++/* Load a block of the second ("external") part of the firmware */
++static inline int at76_load_ext_fw_block(struct usb_device *udev, int blockno,
++ void *block, int size)
++{
++ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,
++ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
++ 0x0802, blockno, block, size,
++ USB_CTRL_GET_TIMEOUT);
++}
++
++static inline int at76_get_hw_cfg(struct usb_device *udev,
++ union at76_hwcfg *buf, int buf_size)
++{
++ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
++ USB_TYPE_VENDOR | USB_DIR_IN |
++ USB_RECIP_INTERFACE, 0x0a02, 0,
++ buf, buf_size, USB_CTRL_GET_TIMEOUT);
++}
++
++/* Intersil boards use a different "value" for GetHWConfig requests */
++static inline int at76_get_hw_cfg_intersil(struct usb_device *udev,
++ union at76_hwcfg *buf, int buf_size)
++{
++ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
++ USB_TYPE_VENDOR | USB_DIR_IN |
++ USB_RECIP_INTERFACE, 0x0902, 0,
++ buf, buf_size, USB_CTRL_GET_TIMEOUT);
++}
++
++/* Get the hardware configuration for the adapter and put it to the appropriate
++ * fields of 'priv' (the GetHWConfig request and interpretation of the result
++ * depends on the board type) */
++static int at76_get_hw_config(struct at76_priv *priv)
++{
++ int ret;
++ union at76_hwcfg *hwcfg = kmalloc(sizeof(*hwcfg), GFP_KERNEL);
++
++ if (!hwcfg)
++ return -ENOMEM;
++
++ if (at76_is_intersil(priv->board_type)) {
++ ret = at76_get_hw_cfg_intersil(priv->udev, hwcfg,
++ sizeof(hwcfg->i));
++ if (ret < 0)
++ goto exit;
++ memcpy(priv->mac_addr, hwcfg->i.mac_addr, ETH_ALEN);
++ priv->regulatory_domain = hwcfg->i.regulatory_domain;
++ } else if (at76_is_503rfmd(priv->board_type)) {
++ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r3));
++ if (ret < 0)
++ goto exit;
++ memcpy(priv->mac_addr, hwcfg->r3.mac_addr, ETH_ALEN);
++ priv->regulatory_domain = hwcfg->r3.regulatory_domain;
++ } else {
++ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r5));
++ if (ret < 0)
++ goto exit;
++ memcpy(priv->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN);
++ priv->regulatory_domain = hwcfg->r5.regulatory_domain;
++ }
++
++exit:
++ kfree(hwcfg);
++ if (ret < 0)
++ printk(KERN_ERR "%s: cannot get HW Config (error %d)\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++static struct reg_domain const *at76_get_reg_domain(u16 code)
++{
++ int i;
++ static struct reg_domain const fd_tab[] = {
++ { 0x10, "FCC (USA)", 0x7ff }, /* ch 1-11 */
++ { 0x20, "IC (Canada)", 0x7ff }, /* ch 1-11 */
++ { 0x30, "ETSI (most of Europe)", 0x1fff }, /* ch 1-13 */
++ { 0x31, "Spain", 0x600 }, /* ch 10-11 */
++ { 0x32, "France", 0x1e00 }, /* ch 10-13 */
++ { 0x40, "MKK (Japan)", 0x2000 }, /* ch 14 */
++ { 0x41, "MKK1 (Japan)", 0x3fff }, /* ch 1-14 */
++ { 0x50, "Israel", 0x3fc }, /* ch 3-9 */
++ { 0x00, "<unknown>", 0xffffffff } /* ch 1-32 */
++ };
++
++ /* Last entry is fallback for unknown domain code */
++ for (i = 0; i < ARRAY_SIZE(fd_tab) - 1; i++)
++ if (code == fd_tab[i].code)
++ break;
++
++ return &fd_tab[i];
++}
++
++static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf,
++ int buf_size)
++{
++ int ret;
++
++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
++ USB_TYPE_VENDOR | USB_DIR_IN |
++ USB_RECIP_INTERFACE, mib << 8, 0, buf, buf_size,
++ USB_CTRL_GET_TIMEOUT);
++ if (ret >= 0 && ret != buf_size)
++ return -EIO;
++ return ret;
++}
++
++/* Return positive number for status, negative for an error */
++static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd)
++{
++ u8 stat_buf[40];
++ int ret;
++
++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x22,
++ USB_TYPE_VENDOR | USB_DIR_IN |
++ USB_RECIP_INTERFACE, cmd, 0, stat_buf,
++ sizeof(stat_buf), USB_CTRL_GET_TIMEOUT);
++ if (ret < 0)
++ return ret;
++
++ return stat_buf[5];
++}
++
++#define MAKE_CMD_CASE(c) case (c): return #c
++
++static const char *at76_get_cmd_string(u8 cmd_status)
++{
++ switch (cmd_status) {
++ MAKE_CMD_CASE(CMD_SET_MIB);
++ MAKE_CMD_CASE(CMD_GET_MIB);
++ MAKE_CMD_CASE(CMD_SCAN);
++ MAKE_CMD_CASE(CMD_JOIN);
++ MAKE_CMD_CASE(CMD_START_IBSS);
++ MAKE_CMD_CASE(CMD_RADIO_ON);
++ MAKE_CMD_CASE(CMD_RADIO_OFF);
++ MAKE_CMD_CASE(CMD_STARTUP);
++ }
++
++ return "UNKNOWN";
++}
++
++static int at76_set_card_command(struct usb_device *udev, int cmd, void *buf,
++ int buf_size)
++{
++ int ret;
++ struct at76_command *cmd_buf = kmalloc(sizeof(struct at76_command) +
++ buf_size, GFP_KERNEL);
++
++ if (!cmd_buf)
++ return -ENOMEM;
++
++ cmd_buf->cmd = cmd;
++ cmd_buf->reserved = 0;
++ cmd_buf->size = cpu_to_le16(buf_size);
++ memcpy(cmd_buf->data, buf, buf_size);
++
++ at76_dbg_dump(DBG_CMD, cmd_buf, sizeof(struct at76_command) + buf_size,
++ "issuing command %s (0x%02x)",
++ at76_get_cmd_string(cmd), cmd);
++
++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,
++ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
++ 0, 0, cmd_buf,
++ sizeof(struct at76_command) + buf_size,
++ USB_CTRL_GET_TIMEOUT);
++ kfree(cmd_buf);
++ return ret;
++}
++
++#define MAKE_CMD_STATUS_CASE(c) case (c): return #c
++static const char *at76_get_cmd_status_string(u8 cmd_status)
++{
++ switch (cmd_status) {
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE);
++ MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED);
++ }
++
++ return "UNKNOWN";
++}
++
++/* Wait until the command is completed */
++static int at76_wait_completion(struct at76_priv *priv, int cmd)
++{
++ int status = 0;
++ unsigned long timeout = jiffies + CMD_COMPLETION_TIMEOUT;
++
++ do {
++ status = at76_get_cmd_status(priv->udev, cmd);
++ if (status < 0) {
++ printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n",
++ wiphy_name(priv->hw->wiphy), status);
++ break;
++ }
++
++ at76_dbg(DBG_WAIT_COMPLETE,
++ "%s: Waiting on cmd %d, status = %d (%s)",
++ wiphy_name(priv->hw->wiphy), cmd, status,
++ at76_get_cmd_status_string(status));
++
++ if (status != CMD_STATUS_IN_PROGRESS
++ && status != CMD_STATUS_IDLE)
++ break;
++
++ schedule_timeout_interruptible(HZ / 10); /* 100 ms */
++ if (time_after(jiffies, timeout)) {
++ printk(KERN_ERR
++ "%s: completion timeout for command %d\n",
++ wiphy_name(priv->hw->wiphy), cmd);
++ status = -ETIMEDOUT;
++ break;
++ }
++ } while (1);
++
++ return status;
++}
++
++static int at76_set_mib(struct at76_priv *priv, struct set_mib_buffer *buf)
++{
++ int ret;
++
++ ret = at76_set_card_command(priv->udev, CMD_SET_MIB, buf,
++ offsetof(struct set_mib_buffer,
++ data) + buf->size);
++ if (ret < 0)
++ return ret;
++
++ ret = at76_wait_completion(priv, CMD_SET_MIB);
++ if (ret != CMD_STATUS_COMPLETE) {
++ printk(KERN_INFO
++ "%s: set_mib: at76_wait_completion failed "
++ "with %d\n", wiphy_name(priv->hw->wiphy), ret);
++ ret = -EIO;
++ }
++
++ return ret;
++}
++
++/* Return < 0 on error, == 0 if no command sent, == 1 if cmd sent */
++static int at76_set_radio(struct at76_priv *priv, int enable)
++{
++ int ret;
++ int cmd;
++
++ if (priv->radio_on == enable)
++ return 0;
++
++ cmd = enable ? CMD_RADIO_ON : CMD_RADIO_OFF;
++
++ ret = at76_set_card_command(priv->udev, cmd, NULL, 0);
++ if (ret < 0)
++ printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), cmd, ret);
++ else
++ ret = 1;
++
++ priv->radio_on = enable;
++ return ret;
++}
++
++/* Set current power save mode (AT76_PM_OFF/AT76_PM_ON/AT76_PM_SMART) */
++static int at76_set_pm_mode(struct at76_priv *priv)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_MAC_MGMT;
++ priv->mib_buf.size = 1;
++ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, power_mgmt_mode);
++ priv->mib_buf.data.byte = priv->pm_mode;
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++/* Set the association id for power save mode */
++static int at76_set_associd(struct at76_priv *priv, u16 id)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_MAC_MGMT;
++ priv->mib_buf.size = 2;
++ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, station_id);
++ priv->mib_buf.data.word = cpu_to_le16(id);
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (associd) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++/* Set the listen interval for power save mode */
++static int at76_set_listen_interval(struct at76_priv *priv, u16 interval)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_MAC;
++ priv->mib_buf.size = 2;
++ priv->mib_buf.index = offsetof(struct mib_mac, listen_interval);
++ priv->mib_buf.data.word = cpu_to_le16(interval);
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR
++ "%s: set_mib (listen_interval) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++static int at76_set_preamble(struct at76_priv *priv, u8 type)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_LOCAL;
++ priv->mib_buf.size = 1;
++ priv->mib_buf.index = offsetof(struct mib_local, preamble_type);
++ priv->mib_buf.data.byte = type;
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++static int at76_set_frag(struct at76_priv *priv, u16 size)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_MAC;
++ priv->mib_buf.size = 2;
++ priv->mib_buf.index = offsetof(struct mib_mac, frag_threshold);
++ priv->mib_buf.data.word = cpu_to_le16(size);
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++static int at76_set_rts(struct at76_priv *priv, u16 size)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_MAC;
++ priv->mib_buf.size = 2;
++ priv->mib_buf.index = offsetof(struct mib_mac, rts_threshold);
++ priv->mib_buf.data.word = cpu_to_le16(size);
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (rts) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++static int at76_set_autorate_fallback(struct at76_priv *priv, int onoff)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_LOCAL;
++ priv->mib_buf.size = 1;
++ priv->mib_buf.index = offsetof(struct mib_local, txautorate_fallback);
++ priv->mib_buf.data.byte = onoff;
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++static int at76_add_mac_address(struct at76_priv *priv, void *addr)
++{
++ int ret = 0;
++
++ priv->mib_buf.type = MIB_MAC_ADDR;
++ priv->mib_buf.size = ETH_ALEN;
++ priv->mib_buf.index = offsetof(struct mib_mac_addr, mac_addr);
++ memcpy(priv->mib_buf.data.addr, addr, ETH_ALEN);
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (MAC_ADDR, mac_addr) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ return ret;
++}
++
++static void at76_dump_mib_mac_addr(struct at76_priv *priv)
++{
++ int i;
++ int ret;
++ struct mib_mac_addr *m = kmalloc(sizeof(struct mib_mac_addr),
++ GFP_KERNEL);
++
++ if (!m)
++ return;
++
++ ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m,
++ sizeof(struct mib_mac_addr));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x",
++ wiphy_name(priv->hw->wiphy),
++ mac2str(m->mac_addr), m->res[0], m->res[1]);
++ for (i = 0; i < ARRAY_SIZE(m->group_addr); i++)
++ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, "
++ "status %d", wiphy_name(priv->hw->wiphy), i,
++ mac2str(m->group_addr[i]), m->group_addr_status[i]);
++exit:
++ kfree(m);
++}
++
++static void at76_dump_mib_mac_wep(struct at76_priv *priv)
++{
++ int i;
++ int ret;
++ int key_len;
++ struct mib_mac_wep *m = kmalloc(sizeof(struct mib_mac_wep), GFP_KERNEL);
++
++ if (!m)
++ return;
++
++ ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m,
++ sizeof(struct mib_mac_wep));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: priv_invoked %u def_key_id %u "
++ "key_len %u excl_unencr %u wep_icv_err %u wep_excluded %u "
++ "encr_level %u key %d", wiphy_name(priv->hw->wiphy),
++ m->privacy_invoked, m->wep_default_key_id,
++ m->wep_key_mapping_len, m->exclude_unencrypted,
++ le32_to_cpu(m->wep_icv_error_count),
++ le32_to_cpu(m->wep_excluded_count), m->encryption_level,
++ m->wep_default_key_id);
++
++ key_len = (m->encryption_level == 1) ?
++ WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;
++
++ for (i = 0; i < WEP_KEYS; i++)
++ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s",
++ wiphy_name(priv->hw->wiphy), i,
++ hex2str(m->wep_default_keyvalue[i], key_len));
++exit:
++ kfree(m);
++}
++
++static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
++{
++ int ret;
++ struct mib_mac_mgmt *m = kmalloc(sizeof(struct mib_mac_mgmt),
++ GFP_KERNEL);
++
++ if (!m)
++ return;
++
++ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m,
++ sizeof(struct mib_mac_mgmt));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "
++ "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
++ "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
++ "current_bssid %s current_essid %s current_bss_type %d "
++ "pm_mode %d ibss_change %d res %d "
++ "multi_domain_capability_implemented %d "
++ "international_roaming %d country_string %.3s",
++ wiphy_name(priv->hw->wiphy), le16_to_cpu(m->beacon_period),
++ le16_to_cpu(m->CFP_max_duration),
++ le16_to_cpu(m->medium_occupancy_limit),
++ le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),
++ m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,
++ m->CFP_period, mac2str(m->current_bssid),
++ hex2str(m->current_essid, IW_ESSID_MAX_SIZE),
++ m->current_bss_type, m->power_mgmt_mode, m->ibss_change,
++ m->res, m->multi_domain_capability_implemented,
++ m->multi_domain_capability_enabled, m->country_string);
++exit:
++ kfree(m);
++}
++
++static void at76_dump_mib_mac(struct at76_priv *priv)
++{
++ int ret;
++ struct mib_mac *m = kmalloc(sizeof(struct mib_mac), GFP_KERNEL);
++
++ if (!m)
++ return;
++
++ ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_MIB, "%s: MIB MAC: max_tx_msdu_lifetime %d "
++ "max_rx_lifetime %d frag_threshold %d rts_threshold %d "
++ "cwmin %d cwmax %d short_retry_time %d long_retry_time %d "
++ "scan_type %d scan_channel %d probe_delay %u "
++ "min_channel_time %d max_channel_time %d listen_int %d "
++ "desired_ssid %s desired_bssid %s desired_bsstype %d",
++ wiphy_name(priv->hw->wiphy),
++ le32_to_cpu(m->max_tx_msdu_lifetime),
++ le32_to_cpu(m->max_rx_lifetime),
++ le16_to_cpu(m->frag_threshold), le16_to_cpu(m->rts_threshold),
++ le16_to_cpu(m->cwmin), le16_to_cpu(m->cwmax),
++ m->short_retry_time, m->long_retry_time, m->scan_type,
++ m->scan_channel, le16_to_cpu(m->probe_delay),
++ le16_to_cpu(m->min_channel_time),
++ le16_to_cpu(m->max_channel_time),
++ le16_to_cpu(m->listen_interval),
++ hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),
++ mac2str(m->desired_bssid), m->desired_bsstype);
++exit:
++ kfree(m);
++}
++
++static void at76_dump_mib_phy(struct at76_priv *priv)
++{
++ int ret;
++ struct mib_phy *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
++
++ if (!m)
++ return;
++
++ ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_MIB, "%s: MIB PHY: ed_threshold %d slot_time %d "
++ "sifs_time %d preamble_length %d plcp_header_length %d "
++ "mpdu_max_length %d cca_mode_supported %d operation_rate_set "
++ "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d "
++ "phy_type %d current_reg_domain %d",
++ wiphy_name(priv->hw->wiphy), le32_to_cpu(m->ed_threshold),
++ le16_to_cpu(m->slot_time), le16_to_cpu(m->sifs_time),
++ le16_to_cpu(m->preamble_length),
++ le16_to_cpu(m->plcp_header_length),
++ le16_to_cpu(m->mpdu_max_length),
++ le16_to_cpu(m->cca_mode_supported), m->operation_rate_set[0],
++ m->operation_rate_set[1], m->operation_rate_set[2],
++ m->operation_rate_set[3], m->channel_id, m->current_cca_mode,
++ m->phy_type, m->current_reg_domain);
++exit:
++ kfree(m);
++}
++
++static void at76_dump_mib_local(struct at76_priv *priv)
++{
++ int ret;
++ struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
++
++ if (!m)
++ return;
++
++ ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_MIB, "%s: MIB LOCAL: beacon_enable %d "
++ "txautorate_fallback %d ssid_size %d promiscuous_mode %d "
++ "preamble_type %d", wiphy_name(priv->hw->wiphy),
++ m->beacon_enable,
++ m->txautorate_fallback, m->ssid_size, m->promiscuous_mode,
++ m->preamble_type);
++exit:
++ kfree(m);
++}
++
++static void at76_dump_mib_mdomain(struct at76_priv *priv)
++{
++ int ret;
++ struct mib_mdomain *m = kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL);
++
++ if (!m)
++ return;
++
++ ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m,
++ sizeof(struct mib_mdomain));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s",
++ wiphy_name(priv->hw->wiphy),
++ hex2str(m->channel_list, sizeof(m->channel_list)));
++
++ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s",
++ wiphy_name(priv->hw->wiphy),
++ hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel)));
++exit:
++ kfree(m);
++}
++
++/* Enable monitor mode */
++static int at76_start_monitor(struct at76_priv *priv)
++{
++ struct at76_req_scan scan;
++ int ret;
++
++ memset(&scan, 0, sizeof(struct at76_req_scan));
++ memset(scan.bssid, 0xff, ETH_ALEN);
++
++ scan.channel = priv->channel;
++ scan.scan_type = SCAN_TYPE_PASSIVE;
++ scan.international_scan = 0;
++
++ ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
++ if (ret >= 0)
++ ret = at76_get_cmd_status(priv->udev, CMD_SCAN);
++
++ return ret;
++}
++
++/* Calculate padding from txbuf->wlength (which excludes the USB TX header),
++ likely to compensate a flaw in the AT76C503A USB part ... */
++static inline int at76_calc_padding(int wlen)
++{
++ /* add the USB TX header */
++ wlen += AT76_TX_HDRLEN;
++
++ wlen = wlen % 64;
++
++ if (wlen < 50)
++ return 50 - wlen;
++
++ if (wlen >= 61)
++ return 64 + 50 - wlen;
++
++ return 0;
++}
++
++static void at76_rx_callback(struct urb *urb)
++{
++ struct at76_priv *priv = urb->context;
++
++ priv->rx_tasklet.data = (unsigned long)urb;
++ tasklet_schedule(&priv->rx_tasklet);
++ return;
++}
++
++static int at76_submit_rx_urb(struct at76_priv *priv)
++{
++ int ret;
++ int size;
++ struct sk_buff *skb = priv->rx_skb;
++
++ if (!priv->rx_urb) {
++ printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n",
++ wiphy_name(priv->hw->wiphy), __func__);
++ return -EFAULT;
++ }
++
++ if (!skb) {
++ skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));
++ if (!skb) {
++ printk(KERN_ERR "%s: cannot allocate rx skbuff\n",
++ wiphy_name(priv->hw->wiphy));
++ ret = -ENOMEM;
++ goto exit;
++ }
++ priv->rx_skb = skb;
++ } else {
++ skb_push(skb, skb_headroom(skb));
++ skb_trim(skb, 0);
++ }
++
++ size = skb_tailroom(skb);
++ usb_fill_bulk_urb(priv->rx_urb, priv->udev, priv->rx_pipe,
++ skb_put(skb, size), size, at76_rx_callback, priv);
++ ret = usb_submit_urb(priv->rx_urb, GFP_ATOMIC);
++ if (ret < 0) {
++ if (ret == -ENODEV)
++ at76_dbg(DBG_DEVSTART,
++ "usb_submit_urb returned -ENODEV");
++ else
++ printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ }
++
++exit:
++ if (ret < 0 && ret != -ENODEV)
++ printk(KERN_ERR "%s: cannot submit rx urb - please unload the "
++ "driver and/or power cycle the device\n",
++ wiphy_name(priv->hw->wiphy));
++
++ return ret;
++}
++
++/* Download external firmware */
++static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
++{
++ int ret;
++ int op_mode;
++ int blockno = 0;
++ int bsize;
++ u8 *block;
++ u8 *buf = fwe->extfw;
++ int size = fwe->extfw_size;
++
++ if (!buf || !size)
++ return -ENOENT;
++
++ op_mode = at76_get_op_mode(udev);
++ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
++
++ if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
++ dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n",
++ op_mode);
++ return -EINVAL;
++ }
++
++ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
++ if (!block)
++ return -ENOMEM;
++
++ at76_dbg(DBG_DEVSTART, "downloading external firmware");
++
++ /* for fw >= 0.100, the device needs an extra empty block */
++ do {
++ bsize = min_t(int, size, FW_BLOCK_SIZE);
++ memcpy(block, buf, bsize);
++ at76_dbg(DBG_DEVSTART,
++ "ext fw, size left = %5d, bsize = %4d, blockno = %2d",
++ size, bsize, blockno);
++ ret = at76_load_ext_fw_block(udev, blockno, block, bsize);
++ if (ret != bsize) {
++ dev_printk(KERN_ERR, &udev->dev,
++ "loading %dth firmware block failed: %d\n",
++ blockno, ret);
++ goto exit;
++ }
++ buf += bsize;
++ size -= bsize;
++ blockno++;
++ } while (bsize > 0);
++
++ if (at76_is_505a(fwe->board_type)) {
++ at76_dbg(DBG_DEVSTART, "200 ms delay for 505a");
++ schedule_timeout_interruptible(HZ / 5 + 1);
++ }
++
++exit:
++ kfree(block);
++ if (ret < 0)
++ dev_printk(KERN_ERR, &udev->dev,
++ "downloading external firmware failed: %d\n", ret);
++ return ret;
++}
++
++/* Download internal firmware */
++static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)
++{
++ int ret;
++ int need_remap = !at76_is_505a(fwe->board_type);
++
++ ret = at76_usbdfu_download(udev, fwe->intfw, fwe->intfw_size,
++ need_remap ? 0 : 2 * HZ);
++
++ if (ret < 0) {
++ dev_printk(KERN_ERR, &udev->dev,
++ "downloading internal fw failed with %d\n", ret);
++ goto exit;
++ }
++
++ at76_dbg(DBG_DEVSTART, "sending REMAP");
++
++ /* no REMAP for 505A (see SF driver) */
++ if (need_remap) {
++ ret = at76_remap(udev);
++ if (ret < 0) {
++ dev_printk(KERN_ERR, &udev->dev,
++ "sending REMAP failed with %d\n", ret);
++ goto exit;
++ }
++ }
++
++ at76_dbg(DBG_DEVSTART, "sleeping for 2 seconds");
++ schedule_timeout_interruptible(2 * HZ + 1);
++ usb_reset_device(udev);
++
++exit:
++ return ret;
++}
++
++static int at76_startup_device(struct at76_priv *priv)
++{
++ struct at76_card_config *ccfg = &priv->card_config;
++ int ret;
++
++ at76_dbg(DBG_PARAMS,
++ "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d "
++ "keylen %d", wiphy_name(priv->hw->wiphy), priv->essid_size,
++ priv->essid, hex2str(priv->essid, IW_ESSID_MAX_SIZE),
++ priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",
++ priv->channel, priv->wep_enabled ? "enabled" : "disabled",
++ priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]);
++ at76_dbg(DBG_PARAMS,
++ "%s param: preamble %s rts %d retry %d frag %d "
++ "txrate %s auth_mode %d", wiphy_name(priv->hw->wiphy),
++ preambles[priv->preamble_type], priv->rts_threshold,
++ priv->short_retry_limit, priv->frag_threshold,
++ priv->txrate == TX_RATE_1MBIT ? "1MBit" : priv->txrate ==
++ TX_RATE_2MBIT ? "2MBit" : priv->txrate ==
++ TX_RATE_5_5MBIT ? "5.5MBit" : priv->txrate ==
++ TX_RATE_11MBIT ? "11MBit" : priv->txrate ==
++ TX_RATE_AUTO ? "auto" : "<invalid>", priv->auth_mode);
++ at76_dbg(DBG_PARAMS,
++ "%s param: pm_mode %d pm_period %d auth_mode %s "
++ "scan_times %d %d scan_mode %s",
++ wiphy_name(priv->hw->wiphy), priv->pm_mode, priv->pm_period,
++ priv->auth_mode == WLAN_AUTH_OPEN ? "open" : "shared_secret",
++ priv->scan_min_time, priv->scan_max_time,
++ priv->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive");
++
++ memset(ccfg, 0, sizeof(struct at76_card_config));
++ ccfg->promiscuous_mode = 0;
++ ccfg->short_retry_limit = priv->short_retry_limit;
++
++ if (priv->wep_enabled) {
++ if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN)
++ ccfg->encryption_type = 2;
++ else
++ ccfg->encryption_type = 1;
++
++ /* jal: always exclude unencrypted if WEP is active */
++ ccfg->exclude_unencrypted = 1;
++ } else {
++ ccfg->exclude_unencrypted = 0;
++ ccfg->encryption_type = 0;
++ }
++
++ ccfg->rts_threshold = cpu_to_le16(priv->rts_threshold);
++ ccfg->fragmentation_threshold = cpu_to_le16(priv->frag_threshold);
++
++ memcpy(ccfg->basic_rate_set, hw_rates, 4);
++ /* jal: really needed, we do a set_mib for autorate later ??? */
++ ccfg->auto_rate_fallback = (priv->txrate == TX_RATE_AUTO ? 1 : 0);
++ ccfg->channel = priv->channel;
++ ccfg->privacy_invoked = priv->wep_enabled;
++ memcpy(ccfg->current_ssid, priv->essid, IW_ESSID_MAX_SIZE);
++ ccfg->ssid_len = priv->essid_size;
++
++ ccfg->wep_default_key_id = priv->wep_key_id;
++ memcpy(ccfg->wep_default_key_value, priv->wep_keys,
++ sizeof(priv->wep_keys));
++
++ ccfg->short_preamble = priv->preamble_type;
++ ccfg->beacon_period = cpu_to_le16(priv->beacon_period);
++
++ ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config,
++ sizeof(struct at76_card_config));
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ return ret;
++ }
++
++ at76_wait_completion(priv, CMD_STARTUP);
++
++ /* remove BSSID from previous run */
++ memset(priv->bssid, 0, ETH_ALEN);
++
++ if (at76_set_radio(priv, 1) == 1)
++ at76_wait_completion(priv, CMD_RADIO_ON);
++
++ ret = at76_set_preamble(priv, priv->preamble_type);
++ if (ret < 0)
++ return ret;
++
++ ret = at76_set_frag(priv, priv->frag_threshold);
++ if (ret < 0)
++ return ret;
++
++ ret = at76_set_rts(priv, priv->rts_threshold);
++ if (ret < 0)
++ return ret;
++
++ ret = at76_set_autorate_fallback(priv,
++ priv->txrate == TX_RATE_AUTO ? 1 : 0);
++ if (ret < 0)
++ return ret;
++
++ ret = at76_set_pm_mode(priv);
++ if (ret < 0)
++ return ret;
++
++ if (at76_debug & DBG_MIB) {
++ at76_dump_mib_mac(priv);
++ at76_dump_mib_mac_addr(priv);
++ at76_dump_mib_mac_mgmt(priv);
++ at76_dump_mib_mac_wep(priv);
++ at76_dump_mib_mdomain(priv);
++ at76_dump_mib_phy(priv);
++ at76_dump_mib_local(priv);
++ }
++
++ return 0;
++}
++
++/* Enable or disable promiscuous mode */
++static void at76_work_set_promisc(struct work_struct *work)
++{
++ struct at76_priv *priv = container_of(work, struct at76_priv,
++ work_set_promisc);
++ int ret = 0;
++
++ mutex_lock(&priv->mtx);
++
++ priv->mib_buf.type = MIB_LOCAL;
++ priv->mib_buf.size = 1;
++ priv->mib_buf.index = offsetof(struct mib_local, promiscuous_mode);
++ priv->mib_buf.data.byte = priv->promisc ? 1 : 0;
++
++ ret = at76_set_mib(priv, &priv->mib_buf);
++ if (ret < 0)
++ printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++
++ mutex_unlock(&priv->mtx);
++}
++
++/* Submit Rx urb back to the device */
++static void at76_work_submit_rx(struct work_struct *work)
++{
++ struct at76_priv *priv = container_of(work, struct at76_priv,
++ work_submit_rx);
++
++ mutex_lock(&priv->mtx);
++ at76_submit_rx_urb(priv);
++ mutex_unlock(&priv->mtx);
++}
++
++static void at76_rx_tasklet(unsigned long param)
++{
++ struct urb *urb = (struct urb *)param;
++ struct at76_priv *priv = urb->context;
++ struct at76_rx_buffer *buf;
++ struct ieee80211_rx_status rx_status = { 0 };
++
++ if (priv->device_unplugged) {
++ at76_dbg(DBG_DEVSTART, "device unplugged");
++ if (urb)
++ at76_dbg(DBG_DEVSTART, "urb status %d", urb->status);
++ return;
++ }
++
++ if (!priv->rx_skb || !priv->rx_skb->data)
++ return;
++
++ buf = (struct at76_rx_buffer *)priv->rx_skb->data;
++
++ if (urb->status != 0) {
++ if (urb->status != -ENOENT && urb->status != -ECONNRESET)
++ at76_dbg(DBG_URB,
++ "%s %s: - nonzero Rx bulk status received: %d",
++ __func__, wiphy_name(priv->hw->wiphy),
++ urb->status);
++ return;
++ }
++
++ at76_dbg(DBG_RX_ATMEL_HDR,
++ "%s: rx frame: rate %d rssi %d noise %d link %d",
++ wiphy_name(priv->hw->wiphy), buf->rx_rate, buf->rssi,
++ buf->noise_level, buf->link_quality);
++
++ skb_pull(priv->rx_skb, AT76_RX_HDRLEN);
++ skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength));
++ at76_dbg_dump(DBG_RX_DATA, priv->rx_skb->data,
++ priv->rx_skb->len, "RX: len=%d", priv->rx_skb->len);
++
++ rx_status.ssi = buf->rssi;
++ rx_status.flag |= RX_FLAG_DECRYPTED;
++ rx_status.flag |= RX_FLAG_IV_STRIPPED;
++
++ at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
++ priv->rx_skb->len, priv->rx_skb->data_len);
++ ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
++
++ /* Use a new skb for the next receive */
++ priv->rx_skb = NULL;
++
++ at76_submit_rx_urb(priv);
++}
++
++/* Load firmware into kernel memory and parse it */
++static struct fwentry *at76_load_firmware(struct usb_device *udev,
++ enum board_type board_type)
++{
++ int ret;
++ char *str;
++ struct at76_fw_header *fwh;
++ struct fwentry *fwe = &firmwares[board_type];
++
++ mutex_lock(&fw_mutex);
++
++ if (fwe->loaded) {
++ at76_dbg(DBG_FW, "re-using previously loaded fw");
++ goto exit;
++ }
++
++ at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname);
++ ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev);
++ if (ret < 0) {
++ dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n",
++ fwe->fwname);
++ dev_printk(KERN_ERR, &udev->dev,
++ "you may need to download the firmware from "
++ "http://developer.berlios.de/projects/at76c503a/\n");
++ goto exit;
++ }
++
++ at76_dbg(DBG_FW, "got it.");
++ fwh = (struct at76_fw_header *)(fwe->fw->data);
++
++ if (fwe->fw->size <= sizeof(*fwh)) {
++ dev_printk(KERN_ERR, &udev->dev,
++ "firmware is too short (0x%zx)\n", fwe->fw->size);
++ goto exit;
++ }
++
++ /* CRC currently not checked */
++ fwe->board_type = le32_to_cpu(fwh->board_type);
++ if (fwe->board_type != board_type) {
++ dev_printk(KERN_ERR, &udev->dev,
++ "board type mismatch, requested %u, got %u\n",
++ board_type, fwe->board_type);
++ goto exit;
++ }
++
++ fwe->fw_version.major = fwh->major;
++ fwe->fw_version.minor = fwh->minor;
++ fwe->fw_version.patch = fwh->patch;
++ fwe->fw_version.build = fwh->build;
++
++ str = (char *)fwh + le32_to_cpu(fwh->str_offset);
++ fwe->intfw = (u8 *)fwh + le32_to_cpu(fwh->int_fw_offset);
++ fwe->intfw_size = le32_to_cpu(fwh->int_fw_len);
++ fwe->extfw = (u8 *)fwh + le32_to_cpu(fwh->ext_fw_offset);
++ fwe->extfw_size = le32_to_cpu(fwh->ext_fw_len);
++
++ fwe->loaded = 1;
++
++ dev_printk(KERN_DEBUG, &udev->dev,
++ "using firmware %s (version %d.%d.%d-%d)\n",
++ fwe->fwname, fwh->major, fwh->minor, fwh->patch, fwh->build);
++
++ at76_dbg(DBG_DEVSTART, "board %u, int %d:%d, ext %d:%d", board_type,
++ le32_to_cpu(fwh->int_fw_offset), le32_to_cpu(fwh->int_fw_len),
++ le32_to_cpu(fwh->ext_fw_offset), le32_to_cpu(fwh->ext_fw_len));
++ at76_dbg(DBG_DEVSTART, "firmware id %s", str);
++
++exit:
++ mutex_unlock(&fw_mutex);
++
++ if (fwe->loaded)
++ return fwe;
++ else
++ return NULL;
++}
++
++static void at76_mac80211_tx_callback(struct urb *urb)
++{
++ struct at76_priv *priv = urb->context;
++
++ at76_dbg(DBG_MAC80211, "%s()", __func__);
++
++ switch (urb->status) {
++ case 0:
++ /* success */
++ priv->tx_status.flags |= IEEE80211_TX_STATUS_ACK;
++ break;
++ case -ENOENT:
++ case -ECONNRESET:
++ /* fail, urb has been unlinked */
++ /* FIXME: add error message */
++ break;
++ default:
++ at76_dbg(DBG_URB, "%s - nonzero tx status received: %d",
++ __func__, urb->status);
++ break;
++ }
++
++ priv->tx_status.excessive_retries = 0;
++ priv->tx_status.retry_count = 0;
++ priv->tx_status.ack_signal = 0;
++
++ ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb, &priv->tx_status);
++
++ memset(&priv->tx_status, 0, sizeof(priv->tx_status));
++ priv->tx_skb = NULL;
++
++ ieee80211_start_queues(priv->hw);
++}
++
++static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
++ struct ieee80211_tx_control *control)
++{
++ struct at76_priv *priv = hw->priv;
++ struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
++ int padding, submit_len, ret;
++
++ at76_dbg(DBG_MAC80211, "%s()", __func__);
++
++ if (priv->tx_urb->status == -EINPROGRESS) {
++ printk(KERN_ERR "%s: %s called while tx urb is pending\n",
++ wiphy_name(priv->hw->wiphy), __func__);
++ return NETDEV_TX_BUSY;
++ }
++
++ ieee80211_stop_queues(hw);
++
++ at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */
++
++ WARN_ON(priv->tx_skb != NULL);
++
++ priv->tx_skb = skb;
++ memcpy(&priv->tx_status.control, control, sizeof(*control));
++ padding = at76_calc_padding(skb->len);
++ submit_len = AT76_TX_HDRLEN + skb->len + padding;
++
++ /* setup 'Atmel' header */
++ memset(tx_buffer, 0, sizeof(*tx_buffer));
++ tx_buffer->padding = padding;
++ tx_buffer->wlength = cpu_to_le16(skb->len);
++ tx_buffer->tx_rate = control->tx_rate->hw_value;
++ memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved));
++ memcpy(tx_buffer->packet, skb->data, skb->len);
++
++ at76_dbg(DBG_TX_DATA, "%s tx: wlen 0x%x pad 0x%x rate %d hdr",
++ wiphy_name(priv->hw->wiphy), le16_to_cpu(tx_buffer->wlength),
++ tx_buffer->padding, tx_buffer->tx_rate);
++
++ /* send stuff */
++ at76_dbg_dump(DBG_TX_DATA_CONTENT, tx_buffer, submit_len,
++ "%s(): tx_buffer %d bytes:", __func__, submit_len);
++ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, tx_buffer,
++ submit_len, at76_mac80211_tx_callback, priv);
++ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);
++ if (ret) {
++ printk(KERN_ERR "%s: error in tx submit urb: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ if (ret == -EINVAL)
++ printk(KERN_ERR
++ "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n",
++ wiphy_name(priv->hw->wiphy), priv->tx_urb,
++ priv->tx_urb->hcpriv, priv->tx_urb->complete);
++ }
++
++ return 0;
++}
++
++static int at76_mac80211_start(struct ieee80211_hw *hw)
++{
++ struct at76_priv *priv = hw->priv;
++ int ret;
++
++ at76_dbg(DBG_MAC80211, "%s()", __func__);
++
++ mutex_lock(&priv->mtx);
++
++ ret = at76_submit_rx_urb(priv);
++ if (ret < 0) {
++ printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ goto error;
++ }
++
++ at76_startup_device(priv);
++
++ at76_start_monitor(priv);
++
++error:
++ mutex_unlock(&priv->mtx);
++
++ return 0;
++}
++
++static void at76_mac80211_stop(struct ieee80211_hw *hw)
++{
++ struct at76_priv *priv = hw->priv;
++
++ at76_dbg(DBG_MAC80211, "%s()", __func__);
++
++ mutex_lock(&priv->mtx);
++
++ if (!priv->device_unplugged) {
++ /* We are called by "ifconfig ethX down", not because the
++ * device is not available anymore. */
++ at76_set_radio(priv, 0);
++
++ /* We unlink rx_urb because at76_open() re-submits it.
++ * If unplugged, at76_delete_device() takes care of it. */
++ usb_kill_urb(priv->rx_urb);
++ }
++
++ mutex_unlock(&priv->mtx);
++}
++
++static int at76_add_interface(struct ieee80211_hw *hw,
++ struct ieee80211_if_init_conf *conf)
++{
++ struct at76_priv *priv = hw->priv;
++ int ret = 0;
++
++ at76_dbg(DBG_MAC80211, "%s()", __func__);
++
++ mutex_lock(&priv->mtx);
++
++ switch (conf->type) {
++ case IEEE80211_IF_TYPE_STA:
++ priv->iw_mode = IW_MODE_INFRA;
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++ goto exit;
++ }
++
++exit:
++ mutex_unlock(&priv->mtx);
++
++ return ret;
++}
++
++static void at76_remove_interface(struct ieee80211_hw *hw,
++ struct ieee80211_if_init_conf *conf)
++{
++ at76_dbg(DBG_MAC80211, "%s()", __func__);
++}
++
++static int at76_join(struct at76_priv *priv)
++{
++ struct at76_req_join join;
++ int ret;
++
++ memset(&join, 0, sizeof(struct at76_req_join));
++ memcpy(join.essid, priv->essid, priv->essid_size);
++ join.essid_size = priv->essid_size;
++ memcpy(join.bssid, priv->bssid, ETH_ALEN);
++ join.bss_type = INFRASTRUCTURE_MODE;
++ join.channel = priv->channel;
++ join.timeout = cpu_to_le16(2000);
++
++ at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
++ ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
++ sizeof(struct at76_req_join));
++
++ if (ret < 0) {
++ printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ return 0;
++ }
++
++ ret = at76_wait_completion(priv, CMD_JOIN);
++ at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
++ if (ret != CMD_STATUS_COMPLETE) {
++ printk(KERN_ERR "%s: at76_wait_completion failed: %d\n",
++ wiphy_name(priv->hw->wiphy), ret);
++ return 0;
++ }
++
++ at76_set_pm_mode(priv);
++
++ return 0;
++}
++
++static void at76_dwork_hw_scan(struct work_struct *work)
++{
++ struct at76_priv *priv = container_of(work, struct at76_priv,
++ dwork_hw_scan.work);
++ int ret;
++
++ mutex_lock(&priv->mtx);
++
++ ret = at76_get_cmd_status(priv->udev, CMD_SCAN);
++ at76_dbg(DBG_MAC80211, "%s: CMD_SCAN status 0x%02x", __func__, ret);
++
++ /* FIXME: add maximum time for scan to complete */
++
++ if (ret != CMD_STATUS_COMPLETE) {
++ queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
++ SCAN_POLL_INTERVAL);
++ goto exit;
++ }
++
++ ieee80211_scan_completed(priv->hw);
++
++ if (is_valid_ether_addr(priv->bssid))
++ at76_join(priv);
++
++ ieee80211_start_queues(priv->hw);
++
++exit:
++ mutex_unlock(&priv->mtx);
++}
++
++static int at76_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
++{
++ struct at76_priv *priv = hw->priv;
++ struct at76_req_scan scan;
++ int ret;
++
++ at76_dbg(DBG_MAC80211, "%s():", __func__);
++ at76_dbg_dump(DBG_MAC80211, ssid, len, "ssid %zd bytes:", len);
++
++ mutex_lock(&priv->mtx);
++
++ ieee80211_stop_queues(hw);
++
++ memset(&scan, 0, sizeof(struct at76_req_scan));
++ memset(scan.bssid, 0xFF, ETH_ALEN);
++ scan.scan_type = SCAN_TYPE_ACTIVE;
++ if (priv->essid_size > 0) {
++ memcpy(scan.essid, ssid, len);
++ scan.essid_size = len;
++ }
++ scan.min_channel_time = cpu_to_le16(priv->scan_min_time);
++ scan.max_channel_time = cpu_to_le16(priv->scan_max_time);
++ scan.probe_delay = cpu_to_le16(priv->scan_min_time * 1000);
++ scan.international_scan = 0;
++
++ at76_dbg(DBG_MAC80211, "%s: sending CMD_SCAN", __func__);
++ ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
++
++ if (ret < 0) {
++ err("CMD_SCAN failed: %d", ret);
++ goto exit;
++ }
++
++ queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
++ SCAN_POLL_INTERVAL);
++
++exit:
++ mutex_unlock(&priv->mtx);
++
++ return 0;
++}
++
++static int at76_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
++{
++ struct at76_priv *priv = hw->priv;
++
++ at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d",
++ __func__, conf->channel->hw_value, conf->radio_enabled);
++ at76_dbg_dump(DBG_MAC80211, priv->essid, priv->essid_size, "ssid:");
++ at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:");
++
++ mutex_lock(&priv->mtx);
++
++ priv->channel = conf->channel->hw_value;
++
++ if (is_valid_ether_addr(priv->bssid))
++ at76_join(priv);
++ else
++ at76_start_monitor(priv);
++
++ mutex_unlock(&priv->mtx);
++
++ return 0;
++}
++
++static int at76_config_interface(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif,
++ struct ieee80211_if_conf *conf)
++{
++ struct at76_priv *priv = hw->priv;
++
++ at76_dbg(DBG_MAC80211, "%s(): ssid_len=%zd", __func__, conf->ssid_len);
++ at76_dbg_dump(DBG_MAC80211, conf->ssid, conf->ssid_len, "ssid:");
++ at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:");
++
++ mutex_lock(&priv->mtx);
++
++ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
++ memcpy(priv->essid, conf->ssid, conf->ssid_len);
++ priv->essid_size = conf->ssid_len;
++
++ if (is_valid_ether_addr(priv->bssid))
++ /* mac80211 is joining a bss */
++ at76_join(priv);
++
++ mutex_unlock(&priv->mtx);
++
++ return 0;
++}
++
++/* must be atomic */
++static void at76_configure_filter(struct ieee80211_hw *hw,
++ unsigned int changed_flags,
++ unsigned int *total_flags, int mc_count,
++ struct dev_addr_list *mc_list)
++{
++ struct at76_priv *priv = hw->priv;
++ int flags;
++
++ at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
++ "total_flags=0x%08x mc_count=%d",
++ __func__, changed_flags, *total_flags, mc_count);
++
++ flags = changed_flags & AT76_SUPPORTED_FILTERS;
++ *total_flags = AT76_SUPPORTED_FILTERS;
++
++ /* FIXME: access to priv->promisc should be protected with
++ * priv->mtx, but it's impossible because this function needs to be
++ * atomic */
++
++ if (flags && !priv->promisc) {
++ /* mac80211 wants us to enable promiscuous mode */
++ priv->promisc = 1;
++ } else if (!flags && priv->promisc) {
++ /* we need to disable promiscuous mode */
++ priv->promisc = 0;
++ } else
++ return;
++
++ queue_work(hw->workqueue, &priv->work_set_promisc);
++}
++
++static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
++ const u8 *local_address, const u8 *address,
++ struct ieee80211_key_conf *key)
++{
++ struct at76_priv *priv = hw->priv;
++
++ int i;
++
++ at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "
++ "key->keylen %d",
++ __func__, cmd, key->alg, key->keyidx, key->keylen);
++
++ if (key->alg != ALG_WEP)
++ return -EOPNOTSUPP;
++
++ key->hw_key_idx = key->keyidx;
++
++ mutex_lock(&priv->mtx);
++
++ switch (cmd) {
++ case SET_KEY:
++ memcpy(priv->wep_keys[key->keyidx], key->key, key->keylen);
++ priv->wep_keys_len[key->keyidx] = key->keylen;
++
++ /* FIXME: find out how to do this properly */
++ priv->wep_key_id = key->keyidx;
++
++ break;
++ case DISABLE_KEY:
++ default:
++ priv->wep_keys_len[key->keyidx] = 0;
++ break;
++ }
++
++ priv->wep_enabled = 0;
++
++ for (i = 0; i < WEP_KEYS; i++) {
++ if (priv->wep_keys_len[i] != 0)
++ priv->wep_enabled = 1;
++ }
++
++ at76_startup_device(priv);
++
++ mutex_unlock(&priv->mtx);
++
++ return 0;
++}
++
++static const struct ieee80211_ops at76_ops = {
++ .tx = at76_mac80211_tx,
++ .add_interface = at76_add_interface,
++ .remove_interface = at76_remove_interface,
++ .config = at76_config,
++ .config_interface = at76_config_interface,
++ .configure_filter = at76_configure_filter,
++ .start = at76_mac80211_start,
++ .stop = at76_mac80211_stop,
++ .hw_scan = at76_hw_scan,
++ .set_key = at76_set_key,
++};
++
++/* Allocate network device and initialize private data */
++static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
++{
++ struct ieee80211_hw *hw;
++ struct at76_priv *priv;
++
++ hw = ieee80211_alloc_hw(sizeof(struct at76_priv), &at76_ops);
++ if (!hw) {
++ printk(KERN_ERR DRIVER_NAME ": could not register"
++ " ieee80211_hw\n");
++ return NULL;
++ }
++
++ priv = hw->priv;
++ priv->hw = hw;
++
++ priv->udev = udev;
++
++ mutex_init(&priv->mtx);
++ INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
++ INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);
++ INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan);
++
++ priv->rx_tasklet.func = at76_rx_tasklet;
++ priv->rx_tasklet.data = 0;
++
++ priv->pm_mode = AT76_PM_OFF;
++ priv->pm_period = 0;
++
++ /* unit us */
++ priv->hw->channel_change_time = 100000;
++
++ return priv;
++}
++
++static int at76_alloc_urbs(struct at76_priv *priv,
++ struct usb_interface *interface)
++{
++ struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out;
++ int i;
++ int buffer_size;
++ struct usb_host_interface *iface_desc;
++
++ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
++
++ at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__,
++ interface->altsetting[0].desc.bNumEndpoints);
++
++ ep_in = NULL;
++ ep_out = NULL;
++ iface_desc = interface->cur_altsetting;
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
++ endpoint = &iface_desc->endpoint[i].desc;
++
++ at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x",
++ __func__, i, endpoint->bEndpointAddress,
++ endpoint->bmAttributes);
++
++ if (!ep_in && usb_endpoint_is_bulk_in(endpoint))
++ ep_in = endpoint;
++
++ if (!ep_out && usb_endpoint_is_bulk_out(endpoint))
++ ep_out = endpoint;
++ }
++
++ if (!ep_in || !ep_out) {
++ dev_printk(KERN_ERR, &interface->dev,
++ "bulk endpoints missing\n");
++ return -ENXIO;
++ }
++
++ priv->rx_pipe = usb_rcvbulkpipe(priv->udev, ep_in->bEndpointAddress);
++ priv->tx_pipe = usb_sndbulkpipe(priv->udev, ep_out->bEndpointAddress);
++
++ priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
++ priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!priv->rx_urb || !priv->tx_urb) {
++ dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n");
++ return -ENOMEM;
++ }
++
++ buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;
++ priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
++ if (!priv->bulk_out_buffer) {
++ dev_printk(KERN_ERR, &interface->dev,
++ "cannot allocate output buffer\n");
++ return -ENOMEM;
++ }
++
++ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
++
++ return 0;
++}
++
++static struct ieee80211_rate at76_rates[] = {
++ { .bitrate = 10, .hw_value = TX_RATE_1MBIT, },
++ { .bitrate = 20, .hw_value = TX_RATE_2MBIT, },
++ { .bitrate = 55, .hw_value = TX_RATE_5_5MBIT, },
++ { .bitrate = 110, .hw_value = TX_RATE_11MBIT, },
++};
++
++static struct ieee80211_channel at76_channels[] = {
++ { .center_freq = 2412, .hw_value = 1 },
++ { .center_freq = 2417, .hw_value = 2 },
++ { .center_freq = 2422, .hw_value = 3 },
++ { .center_freq = 2427, .hw_value = 4 },
++ { .center_freq = 2432, .hw_value = 5 },
++ { .center_freq = 2437, .hw_value = 6 },
++ { .center_freq = 2442, .hw_value = 7 },
++ { .center_freq = 2447, .hw_value = 8 },
++ { .center_freq = 2452, .hw_value = 9 },
++ { .center_freq = 2457, .hw_value = 10 },
++ { .center_freq = 2462, .hw_value = 11 },
++ { .center_freq = 2467, .hw_value = 12 },
++ { .center_freq = 2472, .hw_value = 13 },
++ { .center_freq = 2484, .hw_value = 14 }
++};
++
++static struct ieee80211_supported_band at76_supported_band = {
++ .channels = at76_channels,
++ .n_channels = ARRAY_SIZE(at76_channels),
++ .bitrates = at76_rates,
++ .n_bitrates = ARRAY_SIZE(at76_rates),
++};
++
++/* Register network device and initialize the hardware */
++static int at76_init_new_device(struct at76_priv *priv,
++ struct usb_interface *interface)
++{
++ int ret;
++
++ /* set up the endpoint information */
++ /* check out the endpoints */
++
++ at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints",
++ interface->cur_altsetting->desc.bNumEndpoints);
++
++ ret = at76_alloc_urbs(priv, interface);
++ if (ret < 0)
++ goto exit;
++
++ /* MAC address */
++ ret = at76_get_hw_config(priv);
++ if (ret < 0) {
++ dev_printk(KERN_ERR, &interface->dev,
++ "cannot get MAC address\n");
++ goto exit;
++ }
++
++ priv->domain = at76_get_reg_domain(priv->regulatory_domain);
++
++ priv->channel = DEF_CHANNEL;
++ priv->iw_mode = IW_MODE_INFRA;
++ priv->rts_threshold = DEF_RTS_THRESHOLD;
++ priv->frag_threshold = DEF_FRAG_THRESHOLD;
++ priv->short_retry_limit = DEF_SHORT_RETRY_LIMIT;
++ priv->txrate = TX_RATE_AUTO;
++ priv->preamble_type = PREAMBLE_TYPE_LONG;
++ priv->beacon_period = 100;
++ priv->auth_mode = WLAN_AUTH_OPEN;
++ priv->scan_min_time = DEF_SCAN_MIN_TIME;
++ priv->scan_max_time = DEF_SCAN_MAX_TIME;
++ priv->scan_mode = SCAN_TYPE_ACTIVE;
++
++ /* mac80211 initialisation */
++ priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
++ priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS;
++
++ SET_IEEE80211_DEV(priv->hw, &interface->dev);
++ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
++
++ ret = ieee80211_register_hw(priv->hw);
++ if (ret) {
++ printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",
++ ret);
++ goto exit;
++ }
++
++ priv->mac80211_registered = 1;
++
++ printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n",
++ wiphy_name(priv->hw->wiphy),
++ interface->dev.bus_id, mac2str(priv->mac_addr),
++ priv->fw_version.major, priv->fw_version.minor,
++ priv->fw_version.patch, priv->fw_version.build);
++ printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",
++ wiphy_name(priv->hw->wiphy),
++ priv->regulatory_domain, priv->domain->name);
++
++exit:
++ return ret;
++}
++
++static void at76_delete_device(struct at76_priv *priv)
++{
++ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
++
++ /* The device is gone, don't bother turning it off */
++ priv->device_unplugged = 1;
++
++ if (priv->mac80211_registered)
++ ieee80211_unregister_hw(priv->hw);
++
++ /* assuming we used keventd, it must quiesce too */
++ flush_scheduled_work();
++
++ kfree(priv->bulk_out_buffer);
++
++ if (priv->tx_urb) {
++ usb_kill_urb(priv->tx_urb);
++ usb_free_urb(priv->tx_urb);
++ }
++ if (priv->rx_urb) {
++ usb_kill_urb(priv->rx_urb);
++ usb_free_urb(priv->rx_urb);
++ }
++
++ at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__);
++
++ if (priv->rx_skb)
++ kfree_skb(priv->rx_skb);
++
++ usb_put_dev(priv->udev);
++
++ at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/ieee80211_hw",
++ __func__);
++ ieee80211_free_hw(priv->hw);
++
++ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
++}
++
++static int at76_probe(struct usb_interface *interface,
++ const struct usb_device_id *id)
++{
++ int ret;
++ struct at76_priv *priv;
++ struct fwentry *fwe;
++ struct usb_device *udev;
++ int op_mode;
++ int need_ext_fw = 0;
++ struct mib_fw_version fwv;
++ int board_type = (int)id->driver_info;
++
++ udev = usb_get_dev(interface_to_usbdev(interface));
++
++ /* Load firmware into kernel memory */
++ fwe = at76_load_firmware(udev, board_type);
++ if (!fwe) {
++ ret = -ENOENT;
++ goto error;
++ }
++
++ op_mode = at76_get_op_mode(udev);
++
++ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
++
++ /* we get OPMODE_NONE with 2.4.23, SMC2662W-AR ???
++ we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */
++
++ if (op_mode == OPMODE_HW_CONFIG_MODE) {
++ dev_printk(KERN_ERR, &interface->dev,
++ "cannot handle a device in HW_CONFIG_MODE\n");
++ ret = -EBUSY;
++ goto error;
++ }
++
++ if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH
++ && op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
++ /* download internal firmware part */
++ dev_printk(KERN_DEBUG, &interface->dev,
++ "downloading internal firmware\n");
++ ret = at76_load_internal_fw(udev, fwe);
++ if (ret < 0) {
++ dev_printk(KERN_ERR, &interface->dev,
++ "error %d downloading internal firmware\n",
++ ret);
++ goto error;
++ }
++ usb_put_dev(udev);
++ return ret;
++ }
++
++ /* Internal firmware already inside the device. Get firmware
++ * version to test if external firmware is loaded.
++ * This works only for newer firmware, e.g. the Intersil 0.90.x
++ * says "control timeout on ep0in" and subsequent
++ * at76_get_op_mode() fail too :-( */
++
++ /* if version >= 0.100.x.y or device with built-in flash we can
++ * query the device for the fw version */
++ if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100)
++ || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {
++ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
++ if (ret < 0 || (fwv.major | fwv.minor) == 0)
++ need_ext_fw = 1;
++ } else
++ /* No way to check firmware version, reload to be sure */
++ need_ext_fw = 1;
++
++ if (need_ext_fw) {
++ dev_printk(KERN_DEBUG, &interface->dev,
++ "downloading external firmware\n");
++
++ ret = at76_load_external_fw(udev, fwe);
++ if (ret)
++ goto error;
++
++ /* Re-check firmware version */
++ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
++ if (ret < 0) {
++ dev_printk(KERN_ERR, &interface->dev,
++ "error %d getting firmware version\n", ret);
++ goto error;
++ }
++ }
++
++ priv = at76_alloc_new_device(udev);
++ if (!priv) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ usb_set_intfdata(interface, priv);
++
++ memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version));
++ priv->board_type = board_type;
++
++ ret = at76_init_new_device(priv, interface);
++ if (ret < 0)
++ at76_delete_device(priv);
++
++ return ret;
++
++error:
++ usb_put_dev(udev);
++ return ret;
++}
++
++static void at76_disconnect(struct usb_interface *interface)
++{
++ struct at76_priv *priv;
++
++ priv = usb_get_intfdata(interface);
++ usb_set_intfdata(interface, NULL);
++
++ /* Disconnect after loading internal firmware */
++ if (!priv)
++ return;
++
++ printk(KERN_INFO "%s: disconnecting\n", wiphy_name(priv->hw->wiphy));
++ at76_delete_device(priv);
++ dev_printk(KERN_INFO, &interface->dev, "disconnected\n");
++}
++
++/* Structure for registering this driver with the USB subsystem */
++static struct usb_driver at76_driver = {
++ .name = DRIVER_NAME,
++ .probe = at76_probe,
++ .disconnect = at76_disconnect,
++ .id_table = dev_table,
++};
++
++static int __init at76_mod_init(void)
++{
++ int result;
++
++ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " loading\n");
++
++ mutex_init(&fw_mutex);
++
++ /* register this driver with the USB subsystem */
++ result = usb_register(&at76_driver);
++ if (result < 0)
++ printk(KERN_ERR DRIVER_NAME
++ ": usb_register failed (status %d)\n", result);
++
++ led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);
++ return result;
++}
++
++static void __exit at76_mod_exit(void)
++{
++ int i;
++
++ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n");
++ usb_deregister(&at76_driver);
++ for (i = 0; i < ARRAY_SIZE(firmwares); i++) {
++ if (firmwares[i].fw)
++ release_firmware(firmwares[i].fw);
++ }
++ led_trigger_unregister_simple(ledtrig_tx);
++}
++
++module_param_named(debug, at76_debug, int, 0600);
++MODULE_PARM_DESC(debug, "Debugging level");
++
++module_init(at76_mod_init);
++module_exit(at76_mod_exit);
++
++MODULE_AUTHOR("Oliver Kurth <oku@masqmail.cx>");
++MODULE_AUTHOR("Joerg Albert <joerg.albert@gmx.de>");
++MODULE_AUTHOR("Alex <alex@foogod.com>");
++MODULE_AUTHOR("Nick Jones");
++MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");
++MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
++MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
++MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/at76_usb.h linux-2.6.25/drivers/net/wireless/at76_usb.h
+--- linux-2.6.25.old/drivers/net/wireless/at76_usb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.25/drivers/net/wireless/at76_usb.h 2008-04-19 16:23:26.000000000 +0200
+@@ -0,0 +1,464 @@
++/*
++ * Copyright (c) 2002,2003 Oliver Kurth
++ * (c) 2003,2004 Joerg Albert <joerg.albert@gmx.de>
++ * (c) 2007 Guido Guenther <agx@sigxcpu.org>
++ *
++ * This program is free software; you can redistribute it 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 driver was based on information from the Sourceforge driver
++ * released and maintained by Atmel:
++ *
++ * http://sourceforge.net/projects/atmelwlandriver/
++ *
++ * Although the code was completely re-written,
++ * it would have been impossible without Atmel's decision to
++ * release an Open Source driver (unfortunately the firmware was
++ * kept binary only). Thanks for that decision to Atmel!
++ */
++
++#ifndef _AT76_USB_H
++#define _AT76_USB_H
++
++/* Board types */
++enum board_type {
++ BOARD_503_ISL3861 = 1,
++ BOARD_503_ISL3863 = 2,
++ BOARD_503 = 3,
++ BOARD_503_ACC = 4,
++ BOARD_505 = 5,
++ BOARD_505_2958 = 6,
++ BOARD_505A = 7,
++ BOARD_505AMX = 8
++};
++
++#define CMD_STATUS_IDLE 0x00
++#define CMD_STATUS_COMPLETE 0x01
++#define CMD_STATUS_UNKNOWN 0x02
++#define CMD_STATUS_INVALID_PARAMETER 0x03
++#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04
++#define CMD_STATUS_TIME_OUT 0x07
++#define CMD_STATUS_IN_PROGRESS 0x08
++#define CMD_STATUS_HOST_FAILURE 0xff
++#define CMD_STATUS_SCAN_FAILED 0xf0
++
++/* answers to get op mode */
++#define OPMODE_NONE 0x00
++#define OPMODE_NORMAL_NIC_WITH_FLASH 0x01
++#define OPMODE_HW_CONFIG_MODE 0x02
++#define OPMODE_DFU_MODE_WITH_FLASH 0x03
++#define OPMODE_NORMAL_NIC_WITHOUT_FLASH 0x04
++
++#define CMD_SET_MIB 0x01
++#define CMD_GET_MIB 0x02
++#define CMD_SCAN 0x03
++#define CMD_JOIN 0x04
++#define CMD_START_IBSS 0x05
++#define CMD_RADIO_ON 0x06
++#define CMD_RADIO_OFF 0x07
++#define CMD_STARTUP 0x0B
++
++#define MIB_LOCAL 0x01
++#define MIB_MAC_ADDR 0x02
++#define MIB_MAC 0x03
++#define MIB_MAC_MGMT 0x05
++#define MIB_MAC_WEP 0x06
++#define MIB_PHY 0x07
++#define MIB_FW_VERSION 0x08
++#define MIB_MDOMAIN 0x09
++
++#define ADHOC_MODE 1
++#define INFRASTRUCTURE_MODE 2
++
++/* values for struct mib_local, field preamble_type */
++#define PREAMBLE_TYPE_LONG 0
++#define PREAMBLE_TYPE_SHORT 1
++#define PREAMBLE_TYPE_AUTO 2
++
++/* values for tx_rate */
++#define TX_RATE_1MBIT 0
++#define TX_RATE_2MBIT 1
++#define TX_RATE_5_5MBIT 2
++#define TX_RATE_11MBIT 3
++#define TX_RATE_AUTO 4
++
++/* power management modes */
++#define AT76_PM_OFF 1
++#define AT76_PM_ON 2
++#define AT76_PM_SMART 3
++
++struct hwcfg_r505 {
++ u8 cr39_values[14];
++ u8 reserved1[14];
++ u8 bb_cr[14];
++ u8 pidvid[4];
++ u8 mac_addr[ETH_ALEN];
++ u8 regulatory_domain;
++ u8 reserved2[14];
++ u8 cr15_values[14];
++ u8 reserved3[3];
++} __attribute__((packed));
++
++struct hwcfg_rfmd {
++ u8 cr20_values[14];
++ u8 cr21_values[14];
++ u8 bb_cr[14];
++ u8 pidvid[4];
++ u8 mac_addr[ETH_ALEN];
++ u8 regulatory_domain;
++ u8 low_power_values[14];
++ u8 normal_power_values[14];
++ u8 reserved1[3];
++} __attribute__((packed));
++
++struct hwcfg_intersil {
++ u8 mac_addr[ETH_ALEN];
++ u8 cr31_values[14];
++ u8 cr58_values[14];
++ u8 pidvid[4];
++ u8 regulatory_domain;
++ u8 reserved[1];
++} __attribute__((packed));
++
++union at76_hwcfg {
++ struct hwcfg_intersil i;
++ struct hwcfg_rfmd r3;
++ struct hwcfg_r505 r5;
++};
++
++#define WEP_SMALL_KEY_LEN (40 / 8)
++#define WEP_LARGE_KEY_LEN (104 / 8)
++#define WEP_KEYS (4)
++
++struct at76_card_config {
++ u8 exclude_unencrypted;
++ u8 promiscuous_mode;
++ u8 short_retry_limit;
++ u8 encryption_type;
++ __le16 rts_threshold;
++ __le16 fragmentation_threshold; /* 256..2346 */
++ u8 basic_rate_set[4];
++ u8 auto_rate_fallback; /* 0,1 */
++ u8 channel;
++ u8 privacy_invoked;
++ u8 wep_default_key_id; /* 0..3 */
++ u8 current_ssid[32];
++ u8 wep_default_key_value[4][WEP_LARGE_KEY_LEN];
++ u8 ssid_len;
++ u8 short_preamble;
++ __le16 beacon_period;
++} __attribute__((packed));
++
++struct at76_command {
++ u8 cmd;
++ u8 reserved;
++ __le16 size;
++ u8 data[0];
++} __attribute__((packed));
++
++/* Length of Atmel-specific Rx header before 802.11 frame */
++#define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet)
++
++struct at76_rx_buffer {
++ __le16 wlength;
++ u8 rx_rate;
++ u8 newbss;
++ u8 fragmentation;
++ u8 rssi;
++ u8 link_quality;
++ u8 noise_level;
++ __le32 rx_time;
++ u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
++} __attribute__((packed));
++
++/* Length of Atmel-specific Tx header before 802.11 frame */
++#define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet)
++
++struct at76_tx_buffer {
++ __le16 wlength;
++ u8 tx_rate;
++ u8 padding;
++ u8 reserved[4];
++ u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
++} __attribute__((packed));
++
++/* defines for scan_type below */
++#define SCAN_TYPE_ACTIVE 0
++#define SCAN_TYPE_PASSIVE 1
++
++struct at76_req_scan {
++ u8 bssid[ETH_ALEN];
++ u8 essid[32];
++ u8 scan_type;
++ u8 channel;
++ __le16 probe_delay;
++ __le16 min_channel_time;
++ __le16 max_channel_time;
++ u8 essid_size;
++ u8 international_scan;
++} __attribute__((packed));
++
++struct at76_req_ibss {
++ u8 bssid[ETH_ALEN];
++ u8 essid[32];
++ u8 bss_type;
++ u8 channel;
++ u8 essid_size;
++ u8 reserved[3];
++} __attribute__((packed));
++
++struct at76_req_join {
++ u8 bssid[ETH_ALEN];
++ u8 essid[32];
++ u8 bss_type;
++ u8 channel;
++ __le16 timeout;
++ u8 essid_size;
++ u8 reserved;
++} __attribute__((packed));
++
++struct set_mib_buffer {
++ u8 type;
++ u8 size;
++ u8 index;
++ u8 reserved;
++ union {
++ u8 byte;
++ __le16 word;
++ u8 addr[ETH_ALEN];
++ } data;
++} __attribute__((packed));
++
++struct mib_local {
++ u16 reserved0;
++ u8 beacon_enable;
++ u8 txautorate_fallback;
++ u8 reserved1;
++ u8 ssid_size;
++ u8 promiscuous_mode;
++ u16 reserved2;
++ u8 preamble_type;
++ u16 reserved3;
++} __attribute__((packed));
++
++struct mib_mac_addr {
++ u8 mac_addr[ETH_ALEN];
++ u8 res[2]; /* ??? */
++ u8 group_addr[4][ETH_ALEN];
++ u8 group_addr_status[4];
++} __attribute__((packed));
++
++struct mib_mac {
++ __le32 max_tx_msdu_lifetime;
++ __le32 max_rx_lifetime;
++ __le16 frag_threshold;
++ __le16 rts_threshold;
++ __le16 cwmin;
++ __le16 cwmax;
++ u8 short_retry_time;
++ u8 long_retry_time;
++ u8 scan_type; /* active or passive */
++ u8 scan_channel;
++ __le16 probe_delay; /* delay before ProbeReq in active scan, RO */
++ __le16 min_channel_time;
++ __le16 max_channel_time;
++ __le16 listen_interval;
++ u8 desired_ssid[32];
++ u8 desired_bssid[ETH_ALEN];
++ u8 desired_bsstype; /* ad-hoc or infrastructure */
++ u8 reserved2;
++} __attribute__((packed));
++
++struct mib_mac_mgmt {
++ __le16 beacon_period;
++ __le16 CFP_max_duration;
++ __le16 medium_occupancy_limit;
++ __le16 station_id; /* assoc id */
++ __le16 ATIM_window;
++ u8 CFP_mode;
++ u8 privacy_option_implemented;
++ u8 DTIM_period;
++ u8 CFP_period;
++ u8 current_bssid[ETH_ALEN];
++ u8 current_essid[32];
++ u8 current_bss_type;
++ u8 power_mgmt_mode;
++ /* rfmd and 505 */
++ u8 ibss_change;
++ u8 res;
++ u8 multi_domain_capability_implemented;
++ u8 multi_domain_capability_enabled;
++ u8 country_string[3];
++ u8 reserved[3];
++} __attribute__((packed));
++
++struct mib_mac_wep {
++ u8 privacy_invoked; /* 0 disable encr., 1 enable encr */
++ u8 wep_default_key_id;
++ u8 wep_key_mapping_len;
++ u8 exclude_unencrypted;
++ __le32 wep_icv_error_count;
++ __le32 wep_excluded_count;
++ u8 wep_default_keyvalue[WEP_KEYS][WEP_LARGE_KEY_LEN];
++ u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */
++} __attribute__((packed));
++
++struct mib_phy {
++ __le32 ed_threshold;
++
++ __le16 slot_time;
++ __le16 sifs_time;
++ __le16 preamble_length;
++ __le16 plcp_header_length;
++ __le16 mpdu_max_length;
++ __le16 cca_mode_supported;
++
++ u8 operation_rate_set[4];
++ u8 channel_id;
++ u8 current_cca_mode;
++ u8 phy_type;
++ u8 current_reg_domain;
++} __attribute__((packed));
++
++struct mib_fw_version {
++ u8 major;
++ u8 minor;
++ u8 patch;
++ u8 build;
++} __attribute__((packed));
++
++struct mib_mdomain {
++ u8 tx_powerlevel[14];
++ u8 channel_list[14]; /* 0 for invalid channels */
++} __attribute__((packed));
++
++struct at76_fw_header {
++ __le32 crc; /* CRC32 of the whole image */
++ __le32 board_type; /* firmware compatibility code */
++ u8 build; /* firmware build number */
++ u8 patch; /* firmware patch level */
++ u8 minor; /* firmware minor version */
++ u8 major; /* firmware major version */
++ __le32 str_offset; /* offset of the copyright string */
++ __le32 int_fw_offset; /* internal firmware image offset */
++ __le32 int_fw_len; /* internal firmware image length */
++ __le32 ext_fw_offset; /* external firmware image offset */
++ __le32 ext_fw_len; /* external firmware image length */
++} __attribute__((packed));
++
++/* a description of a regulatory domain and the allowed channels */
++struct reg_domain {
++ u16 code;
++ char const *name;
++ u32 channel_map; /* if bit N is set, channel (N+1) is allowed */
++};
++
++/* Data for one loaded firmware file */
++struct fwentry {
++ const char *const fwname;
++ const struct firmware *fw;
++ int extfw_size;
++ int intfw_size;
++ /* pointer to loaded firmware, no need to free */
++ u8 *extfw; /* external firmware, extfw_size bytes long */
++ u8 *intfw; /* internal firmware, intfw_size bytes long */
++ enum board_type board_type; /* board type */
++ struct mib_fw_version fw_version;
++ int loaded; /* Loaded and parsed successfully */
++};
++
++struct at76_priv {
++ struct usb_device *udev; /* USB device pointer */
++
++ struct sk_buff *rx_skb; /* skbuff for receiving data */
++ struct sk_buff *tx_skb; /* skbuff for transmitting data */
++ void *bulk_out_buffer; /* buffer for sending data */
++
++ struct urb *tx_urb; /* URB for sending data */
++ struct urb *rx_urb; /* URB for receiving data */
++
++ unsigned int tx_pipe; /* bulk out pipe */
++ unsigned int rx_pipe; /* bulk in pipe */
++
++ struct mutex mtx; /* locks this structure */
++
++ /* work queues */
++ struct work_struct work_set_promisc;
++ struct work_struct work_submit_rx;
++ struct delayed_work dwork_hw_scan;
++
++ struct tasklet_struct rx_tasklet;
++
++ /* the WEP stuff */
++ int wep_enabled; /* 1 if WEP is enabled */
++ int wep_key_id; /* key id to be used */
++ u8 wep_keys[WEP_KEYS][WEP_LARGE_KEY_LEN]; /* WEP keys */
++ u8 wep_keys_len[WEP_KEYS]; /* length of WEP keys */
++
++ int channel;
++ int iw_mode;
++ u8 bssid[ETH_ALEN];
++ u8 essid[IW_ESSID_MAX_SIZE];
++ int essid_size;
++ int radio_on;
++ int promisc;
++
++ int preamble_type; /* 0 - long, 1 - short, 2 - auto */
++ int auth_mode; /* authentication type: 0 open, 1 shared key */
++ int txrate; /* 0,1,2,3 = 1,2,5.5,11 Mbps, 4 is auto */
++ int frag_threshold; /* threshold for fragmentation of tx packets */
++ int rts_threshold; /* threshold for RTS mechanism */
++ int short_retry_limit;
++
++ int scan_min_time; /* scan min channel time */
++ int scan_max_time; /* scan max channel time */
++ int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */
++ int scan_need_any; /* if set, need to scan for any ESSID */
++
++ u16 assoc_id; /* current association ID, if associated */
++
++ u8 pm_mode; /* power management mode */
++ u32 pm_period; /* power management period in microseconds */
++
++ struct reg_domain const *domain; /* reg domain description */
++
++ /* These fields contain HW config provided by the device (not all of
++ * these fields are used by all board types) */
++ u8 mac_addr[ETH_ALEN];
++ u8 regulatory_domain;
++
++ struct at76_card_config card_config;
++
++ enum board_type board_type;
++ struct mib_fw_version fw_version;
++
++ unsigned int device_unplugged:1;
++ unsigned int netdev_registered:1;
++ struct set_mib_buffer mib_buf; /* global buffer for set_mib calls */
++
++ int beacon_period; /* period of mgmt beacons, Kus */
++
++ struct ieee80211_hw *hw;
++ struct ieee80211_tx_status tx_status;
++ int mac80211_registered;
++};
++
++#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS
++
++#define SCAN_POLL_INTERVAL (HZ / 4)
++
++#define CMD_COMPLETION_TIMEOUT (5 * HZ)
++
++#define DEF_RTS_THRESHOLD 1536
++#define DEF_FRAG_THRESHOLD 1536
++#define DEF_SHORT_RETRY_LIMIT 8
++#define DEF_CHANNEL 10
++#define DEF_SCAN_MIN_TIME 10
++#define DEF_SCAN_MAX_TIME 120
++
++/* the max padding size for tx in bytes (see calc_padding) */
++#define MAX_PADDING_SIZE 53
++
++#endif /* _AT76_USB_H */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/ath5k.h linux-2.6.25/drivers/net/wireless/ath5k/ath5k.h
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/ath5k.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/ath5k.h 2008-04-19 13:54:59.000000000 +0200
+@@ -30,7 +30,6 @@
+ #include <net/mac80211.h>
+
+ #include "hw.h"
+-#include "regdom.h"
+
+ /* PCI IDs */
+ #define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */
+@@ -141,7 +140,9 @@
+ AR5K_RF5110 = 0,
+ AR5K_RF5111 = 1,
+ AR5K_RF5112 = 2,
+- AR5K_RF5413 = 3,
++ AR5K_RF2413 = 3,
++ AR5K_RF5413 = 4,
++ AR5K_RF2425 = 5,
+ };
+
+ /*
+@@ -169,12 +170,15 @@
+ #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_AR2413 0x78
++#define AR5K_SREV_VER_AR2414 0x79
++#define AR5K_SREV_VER_AR2424 0xa0 /* PCI-E */
++#define AR5K_SREV_VER_AR5424 0xa3 /* PCI-E */
+ #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_VER_AR5416 0xc0 /* PCI-E */
++#define AR5K_SREV_VER_AR5418 0xca /* PCI-E */
++#define AR5K_SREV_VER_AR2425 0xe2 /* PCI-E */
+
+ #define AR5K_SREV_RAD_5110 0x00
+ #define AR5K_SREV_RAD_5111 0x10
+@@ -184,8 +188,9 @@
+ #define AR5K_SREV_RAD_5112A 0x35
+ #define AR5K_SREV_RAD_2112 0x40
+ #define AR5K_SREV_RAD_2112A 0x45
++#define AR5K_SREV_RAD_SC0 0x56 /* Found on 2413/2414 */
+ #define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */
+-#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */
++#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424-5/5424 */
+ #define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */
+
+ /* IEEE defs */
+@@ -251,26 +256,31 @@
+ */
+ #define MODULATION_TURBO 0x00000080
+
+-enum ath5k_vendor_mode {
+- MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1,
+- MODE_ATHEROS_TURBOG
++enum ath5k_driver_mode {
++ AR5K_MODE_11A = 0,
++ AR5K_MODE_11A_TURBO = 1,
++ AR5K_MODE_11B = 2,
++ AR5K_MODE_11G = 3,
++ AR5K_MODE_11G_TURBO = 4,
++ AR5K_MODE_XR = 0,
++ AR5K_MODE_MAX = 5
+ };
+
+-/* 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)
++#define HAS_SHPREAMBLE(_ix) \
++ (rt->rates[_ix].modulation == IEEE80211_RATE_SHORT_PREAMBLE)
++#define SHPREAMBLE_FLAG(_ix) \
++ (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0)
++
+
+ /****************\
+ TX DEFINITIONS
+ \****************/
+
+ /*
+- * Tx Descriptor
++ * TX Status
+ */
+ struct ath5k_tx_status {
+ u16 ts_seqnum;
+@@ -418,7 +428,7 @@
+ \****************/
+
+ /*
+- * Rx Descriptor
++ * RX Status
+ */
+ struct ath5k_rx_status {
+ u16 rs_datalen;
+@@ -440,16 +450,6 @@
+ #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
+@@ -492,29 +492,23 @@
+ #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
+
+
+-
+ /********************\
+ COMMON DEFINITIONS
+ \********************/
+
+ /*
+- * Atheros descriptor
++ * Atheros hardware descriptor
++ * This is read and written to by the hardware
+ */
+ struct ath5k_desc {
+- u32 ds_link;
+- u32 ds_data;
+- u32 ds_ctl0;
+- u32 ds_ctl1;
+- u32 ds_hw[4];
++ u32 ds_link; /* physical address of the next descriptor */
++ u32 ds_data; /* physical address of data buffer (skb) */
+
+ 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
+-
++ struct ath5k_hw_5210_tx_desc ds_tx5210;
++ struct ath5k_hw_5212_tx_desc ds_tx5212;
++ struct ath5k_hw_all_rx_desc ds_rx;
++ } ud;
+ } __packed;
+
+ #define AR5K_RXDESC_INTREQ 0x0020
+@@ -560,8 +554,8 @@
+ * 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)
++#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
++#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0)
+
+ /*
+ * The following structure will be used to map 2GHz channels to
+@@ -584,7 +578,7 @@
+
+ /**
+ * struct ath5k_rate - rate structure
+- * @valid: is this a valid rate for the current mode
++ * @valid: is this a valid rate for rate control (remove)
+ * @modulation: respective mac80211 modulation
+ * @rate_kbps: rate in kbit/s
+ * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on
+@@ -643,47 +637,48 @@
+
+ /*
+ * Rate tables...
++ * TODO: CLEAN THIS !!!
+ */
+ #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 } } \
++ { 1, 0, 6000, 11, 140, 0 }, \
++ { 1, 0, 9000, 15, 18, 0 }, \
++ { 1, 0, 12000, 10, 152, 2 }, \
++ { 1, 0, 18000, 14, 36, 2 }, \
++ { 1, 0, 24000, 9, 176, 4 }, \
++ { 1, 0, 36000, 13, 72, 4 }, \
++ { 1, 0, 48000, 8, 96, 4 }, \
++ { 1, 0, 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 } } \
++ { 1, 0, 1000, 27, 130, 0 }, \
++ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 132, 1 }, \
++ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 139, 1 }, \
++ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 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 } } \
++ { 1, 0, 1000, 27, 2, 0 }, \
++ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 4, 1 }, \
++ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 11, 1 }, \
++ { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 22, 1 }, \
++ { 0, 0, 6000, 11, 12, 4 }, \
++ { 0, 0, 9000, 15, 18, 4 }, \
++ { 1, 0, 12000, 10, 24, 6 }, \
++ { 1, 0, 18000, 14, 36, 6 }, \
++ { 1, 0, 24000, 9, 48, 8 }, \
++ { 1, 0, 36000, 13, 72, 8 }, \
++ { 1, 0, 48000, 8, 96, 8 }, \
++ { 1, 0, 54000, 12, 108, 8 } } \
+ }
+
+ #define AR5K_RATES_TURBO { 8, { \
+@@ -708,14 +703,14 @@
+ { 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 } } \
++ { 1, 0, 6000, 11, 140, 4 }, \
++ { 1, 0, 9000, 15, 18, 4 }, \
++ { 1, 0, 12000, 10, 152, 6 }, \
++ { 1, 0, 18000, 14, 36, 6 }, \
++ { 1, 0, 24000, 9, 176, 8 }, \
++ { 1, 0, 36000, 13, 72, 8 }, \
++ { 1, 0, 48000, 8, 96, 8 }, \
++ { 1, 0, 54000, 12, 108, 8 } } \
+ }
+
+ /*
+@@ -890,12 +885,14 @@
+ AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */
+ };
+
++
++/* XXX: we *may* move cap_range stuff to struct wiphy */
+ struct ath5k_capabilities {
+ /*
+ * Supported PHY modes
+ * (ie. CHANNEL_A, CHANNEL_B, ...)
+ */
+- DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES);
++ DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX);
+
+ /*
+ * Frequency range (without regulation restrictions)
+@@ -908,14 +905,6 @@
+ } 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;
+@@ -963,6 +952,7 @@
+ u16 ah_phy_revision;
+ u16 ah_radio_5ghz_revision;
+ u16 ah_radio_2ghz_revision;
++ u32 ah_phy_spending;
+
+ enum ath5k_version ah_version;
+ enum ath5k_radio ah_radio;
+@@ -1038,8 +1028,10 @@
+ int (*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 *);
++ int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
++ struct ath5k_tx_status *);
++ int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *,
++ struct ath5k_rx_status *);
+ };
+
+ /*
+@@ -1070,6 +1062,7 @@
+ 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);
++extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats);
+ /* EEPROM access functions */
+ extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
+ /* Protocol Control Unit Functions */
+@@ -1098,7 +1091,6 @@
+ extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
+ extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr);
+ #endif
+-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 */
+@@ -1129,8 +1121,6 @@
+ 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);
+
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/base.c linux-2.6.25/drivers/net/wireless/ath5k/base.c
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/base.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/base.c 2008-04-19 13:54:59.000000000 +0200
+@@ -80,7 +80,7 @@
+ 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)");
++MODULE_VERSION("0.5.0 (EXPERIMENTAL)");
+
+
+ /* Known PCI ids */
+@@ -118,12 +118,15 @@
+ { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 },
+ { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 },
+ { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A },
++ { "2413", AR5K_VERSION_VER, AR5K_SREV_VER_AR2413 },
++ { "2414", AR5K_VERSION_VER, AR5K_SREV_VER_AR2414 },
+ { "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 },
++ { "2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425 },
+ { "xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN },
+ { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 },
+ { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 },
+@@ -132,6 +135,7 @@
+ { "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_SC0 },
+ { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 },
+ { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 },
+ { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 },
+@@ -240,6 +244,8 @@
+ static void ath5k_setcurmode(struct ath5k_softc *sc,
+ unsigned int mode);
+ static void ath5k_mode_setup(struct ath5k_softc *sc);
++static void ath5k_set_total_hw_rates(struct ath5k_softc *sc);
++
+ /* Descriptor setup */
+ static int ath5k_desc_alloc(struct ath5k_softc *sc,
+ struct pci_dev *pdev);
+@@ -278,7 +284,8 @@
+ 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);
++ struct sk_buff *skb,
++ struct ath5k_rx_status *rs);
+ static void ath5k_tasklet_rx(unsigned long data);
+ /* Tx handling */
+ static void ath5k_tx_processq(struct ath5k_softc *sc,
+@@ -511,34 +518,45 @@
+ sc->ah->ah_mac_srev,
+ sc->ah->ah_phy_revision);
+
+- if(!sc->ah->ah_single_chip){
++ if (!sc->ah->ah_single_chip) {
+ /* Single chip radio (!RF5111) */
+- if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) {
++ 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)){
++ if (!test_bit(AR5K_MODE_11A,
++ 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),
++ 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)){
++ /* No 2GHz support (5110 and some
++ * 5Ghz only cards) -> report 5Ghz radio */
++ } else if (!test_bit(AR5K_MODE_11B,
++ 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),
++ 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),
++ 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){
++ /* 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),
++ 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),
++ ath5k_chip_name(AR5K_VERSION_RAD,
++ sc->ah->ah_radio_2ghz_revision),
+ sc->ah->ah_radio_2ghz_revision);
+ }
+ }
+@@ -693,11 +711,14 @@
+ goto err;
+ }
+
++ /* Set *_rates so we can map hw rate index */
++ ath5k_set_total_hw_rates(sc);
++
+ /* NB: setup here so ath5k_rate_update is happy */
+- if (test_bit(MODE_IEEE80211A, ah->ah_modes))
+- ath5k_setcurmode(sc, MODE_IEEE80211A);
++ if (test_bit(AR5K_MODE_11A, ah->ah_modes))
++ ath5k_setcurmode(sc, AR5K_MODE_11A);
+ else
+- ath5k_setcurmode(sc, MODE_IEEE80211B);
++ ath5k_setcurmode(sc, AR5K_MODE_11B);
+
+ /*
+ * Allocate tx+rx descriptors and populate the lists.
+@@ -837,12 +858,9 @@
+ 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++;
++ rates[count].bitrate = rt->rates[i].rate_kbps / 100;
++ rates[count].hw_value = rt->rates[i].rate_code;
++ rates[count].flags = rt->rates[i].modulation;
+ count++;
+ max--;
+ }
+@@ -856,43 +874,22 @@
+ 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;
++ unsigned int i, count, size, chfreq, freq, 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:
++ case AR5K_MODE_11A:
++ case AR5K_MODE_11A_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);
++ size = 220 ;
+ 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);
++ case AR5K_MODE_11B:
++ case AR5K_MODE_11G:
++ case AR5K_MODE_11G_TURBO:
++ size = 26;
+ chfreq = CHANNEL_2GHZ;
+ break;
+ default:
+@@ -901,25 +898,31 @@
+ }
+
+ 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;
++ ch = i + 1 ;
++ freq = ath5k_ieee2mhz(ch);
+
+- /* Match regulation domain */
+- if (!all && !(IEEE80211_DMN(chans[i].domain) &
+- IEEE80211_DMN(dmn)))
++ /* Check if channel is supported by the chipset */
++ if (!ath5k_channel_ok(ah, freq, chfreq))
+ continue;
+
+- if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode)
+- continue;
++ /* Write channel info and increment counter */
++ channels[count].center_freq = freq;
++ channels[count].band = (chfreq == CHANNEL_2GHZ) ?
++ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
++ switch (mode) {
++ case AR5K_MODE_11A:
++ case AR5K_MODE_11G:
++ channels[count].hw_value = chfreq | CHANNEL_OFDM;
++ break;
++ case AR5K_MODE_11A_TURBO:
++ case AR5K_MODE_11G_TURBO:
++ channels[count].hw_value = chfreq |
++ CHANNEL_OFDM | CHANNEL_TURBO;
++ break;
++ case AR5K_MODE_11B:
++ channels[count].hw_value = CHANNEL_B;
++ }
+
+- /* Write channel and increment counter */
+- channels->chan = ch;
+- channels->freq = f;
+- channels->val = map[mode].chan;
+- channels++;
+ count++;
+ max--;
+ }
+@@ -927,95 +930,78 @@
+ 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)
++static int
++ath5k_getchannels(struct ieee80211_hw *hw)
+ {
+ struct ath5k_softc *sc = hw->priv;
+- struct ieee80211_hw_mode *modes = sc->modes;
+- unsigned int i;
+- int ret;
++ struct ath5k_hw *ah = sc->ah;
++ struct ieee80211_supported_band *sbands = sc->sbands;
++ const struct ath5k_rate_table *hw_rates;
++ unsigned int max_r, max_c, count_r, count_c;
++ int mode2g = AR5K_MODE_11G;
+
+- if (!test_bit(m, sc->ah->ah_capabilities.cap_mode))
+- return 0;
++ BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS);
+
+- 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;
++ max_r = ARRAY_SIZE(sc->rates);
++ max_c = ARRAY_SIZE(sc->channels);
++ count_r = count_c = 0;
++
++ /* 2GHz band */
++ if (!test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) {
++ mode2g = AR5K_MODE_11B;
++ if (!test_bit(AR5K_MODE_11B,
++ sc->ah->ah_capabilities.cap_mode))
++ mode2g = -1;
+ }
+- return 0;
++
++ if (mode2g > 0) {
++ struct ieee80211_supported_band *sband =
++ &sbands[IEEE80211_BAND_2GHZ];
++
++ sband->bitrates = sc->rates;
++ sband->channels = sc->channels;
++
++ sband->band = IEEE80211_BAND_2GHZ;
++ sband->n_channels = ath5k_copy_channels(ah, sband->channels,
++ mode2g, max_c);
++
++ hw_rates = ath5k_hw_get_rate_table(ah, mode2g);
++ sband->n_bitrates = ath5k_copy_rates(sband->bitrates,
++ hw_rates, max_r);
++
++ count_c = sband->n_channels;
++ count_r = sband->n_bitrates;
++
++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
++
++ max_r -= count_r;
++ max_c -= count_c;
++
+ }
+- 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;
++ /* 5GHz band */
+
+- BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3);
++ if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) {
++ struct ieee80211_supported_band *sband =
++ &sbands[IEEE80211_BAND_5GHZ];
+
+- /* The order here does not matter */
+- modes[0].mode = MODE_IEEE80211G;
+- modes[1].mode = MODE_IEEE80211B;
+- modes[2].mode = MODE_IEEE80211A;
++ sband->bitrates = &sc->rates[count_r];
++ sband->channels = &sc->channels[count_c];
+
+- max_r = ARRAY_SIZE(sc->rates);
+- max_c = ARRAY_SIZE(sc->channels);
++ sband->band = IEEE80211_BAND_5GHZ;
++ sband->n_channels = ath5k_copy_channels(ah, sband->channels,
++ AR5K_MODE_11A, max_c);
+
+- for (i = 0; i < NUM_DRIVER_MODES; i++) {
+- struct ieee80211_hw_mode *mode = &modes[i];
+- const struct ath5k_rate_table *hw_rates;
++ hw_rates = ath5k_hw_get_rate_table(ah, AR5K_MODE_11A);
++ sband->n_bitrates = ath5k_copy_rates(sband->bitrates,
++ hw_rates, max_r);
+
+- 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);
++ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
++ }
+
+- ath5k_debug_dump_modes(sc, modes);
++ ath5k_debug_dump_bands(sc);
+
+- return ret;
++ return 0;
+ }
+
+ /*
+@@ -1030,11 +1016,15 @@
+ 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);
++ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
++ sc->curchan->center_freq, chan->center_freq);
++
++ if (chan->center_freq != sc->curchan->center_freq ||
++ chan->hw_value != sc->curchan->hw_value) {
++
++ sc->curchan = chan;
++ sc->curband = &sc->sbands[chan->band];
+
+- 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
+@@ -1044,13 +1034,13 @@
+ 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);
++ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+ if (ret) {
+- ATH5K_ERR(sc, "%s: unable to reset channel %u "
+- "(%u Mhz)\n", __func__, chan->chan, chan->freq);
++ ATH5K_ERR(sc, "%s: unable to reset channel "
++ "(%u Mhz)\n", __func__, chan->center_freq);
+ return ret;
+ }
+- sc->curchan = chan;
++
+ ath5k_hw_set_txpower_limit(sc->ah, 0);
+
+ /*
+@@ -1081,6 +1071,9 @@
+ return 0;
+ }
+
++/*
++ * TODO: CLEAN THIS !!!
++ */
+ static void
+ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
+ {
+@@ -1121,10 +1114,6 @@
+ 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;
+@@ -1142,6 +1131,12 @@
+ }
+
+ sc->curmode = mode;
++
++ if (mode == AR5K_MODE_11A) {
++ sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ];
++ } else {
++ sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ];
++ }
+ }
+
+ static void
+@@ -1164,6 +1159,72 @@
+ ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
+ }
+
++/*
++ * Match the hw provided rate index (through descriptors)
++ * to an index for sc->curband->bitrates, so it can be used
++ * by the stack.
++ *
++ * This one is a little bit tricky but i think i'm right
++ * about this...
++ *
++ * We have 4 rate tables in the following order:
++ * XR (4 rates)
++ * 802.11a (8 rates)
++ * 802.11b (4 rates)
++ * 802.11g (12 rates)
++ * that make the hw rate table.
++ *
++ * Lets take a 5211 for example that supports a and b modes only.
++ * First comes the 802.11a table and then 802.11b (total 12 rates).
++ * When hw returns eg. 11 it points to the last 802.11b rate (11Mbit),
++ * if it returns 2 it points to the second 802.11a rate etc.
++ *
++ * Same goes for 5212 who has xr/a/b/g support (total 28 rates).
++ * First comes the XR table, then 802.11a, 802.11b and 802.11g.
++ * When hw returns eg. 27 it points to the last 802.11g rate (54Mbits) etc
++ */
++static void
++ath5k_set_total_hw_rates(struct ath5k_softc *sc) {
++
++ struct ath5k_hw *ah = sc->ah;
++
++ if (test_bit(AR5K_MODE_11A, ah->ah_modes))
++ sc->a_rates = 8;
++
++ if (test_bit(AR5K_MODE_11B, ah->ah_modes))
++ sc->b_rates = 4;
++
++ if (test_bit(AR5K_MODE_11G, ah->ah_modes))
++ sc->g_rates = 12;
++
++ /* XXX: Need to see what what happens when
++ xr disable bits in eeprom are set */
++ if (ah->ah_version >= AR5K_AR5212)
++ sc->xr_rates = 4;
++
++}
++
++static inline int
++ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) {
++
++ int mac80211_rix;
++
++ if(sc->curband->band == IEEE80211_BAND_2GHZ) {
++ /* We setup a g ratetable for both b/g modes */
++ mac80211_rix =
++ hw_rix - sc->b_rates - sc->a_rates - sc->xr_rates;
++ } else {
++ mac80211_rix = hw_rix - sc->xr_rates;
++ }
++
++ /* Something went wrong, fallback to basic rate for this band */
++ if ((mac80211_rix >= sc->curband->n_bitrates) ||
++ (mac80211_rix <= 0 ))
++ mac80211_rix = 1;
++
++ return mac80211_rix;
++}
++
+
+
+
+@@ -1268,7 +1329,8 @@
+
+ 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);
++ (sc->power_level * 2), ctl->tx_rate->hw_value,
++ ctl->retry_limit, keyidx, 0, flags, 0, 0);
+ if (ret)
+ goto err_unmap;
+
+@@ -1503,8 +1565,7 @@
+ */
+ 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_debug_printtxbuf(sc, bf);
+
+ ath5k_txbuf_free(sc, bf);
+
+@@ -1629,20 +1690,20 @@
+
+ static unsigned int
+ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
+- struct sk_buff *skb)
++ struct sk_buff *skb, struct ath5k_rx_status *rs)
+ {
+ 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)
++ if (!(rs->rs_status & AR5K_RXERR_DECRYPT) &&
++ rs->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) &&
++ !(rs->rs_status & AR5K_RXERR_DECRYPT) &&
+ skb->len >= hlen + 4) {
+ keyix = skb->data[hlen + 3] >> 6;
+
+@@ -1655,28 +1716,62 @@
+
+
+ static void
+-ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb)
++ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
++ struct ieee80211_rx_status *rxs)
+ {
++ u64 tsf, bc_tstamp;
+ u32 hw_tu;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+
+- if ((mgmt->frame_control & IEEE80211_FCTL_FTYPE) ==
++ if ((le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_FTYPE) ==
+ IEEE80211_FTYPE_MGMT &&
+- (mgmt->frame_control & IEEE80211_FCTL_STYPE) ==
++ (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) ==
+ IEEE80211_STYPE_BEACON &&
+- mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
++ le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
+ memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
+ /*
+- * Received an IBSS beacon with the same BSSID. Hardware might
+- * have updated the TSF, check if we need to update timers.
++ * Received an IBSS beacon with the same BSSID. Hardware *must*
++ * have updated the local TSF. We have to work around various
++ * hardware bugs, though...
++ */
++ tsf = ath5k_hw_get_tsf64(sc->ah);
++ bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp);
++ hw_tu = TSF_TO_TU(tsf);
++
++ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
++ "beacon %llx mactime %llx (diff %lld) tsf now %llx\n",
++ (unsigned long long)bc_tstamp,
++ (unsigned long long)rxs->mactime,
++ (unsigned long long)(rxs->mactime - bc_tstamp),
++ (unsigned long long)tsf);
++
++ /*
++ * Sometimes the HW will give us a wrong tstamp in the rx
++ * status, causing the timestamp extension to go wrong.
++ * (This seems to happen especially with beacon frames bigger
++ * than 78 byte (incl. FCS))
++ * But we know that the receive timestamp must be later than the
++ * timestamp of the beacon since HW must have synced to that.
++ *
++ * NOTE: here we assume mactime to be after the frame was
++ * received, not like mac80211 which defines it at the start.
+ */
+- hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah));
+- if (hw_tu >= sc->nexttbtt) {
+- ath5k_beacon_update_timers(sc,
+- mgmt->u.beacon.timestamp);
++ if (bc_tstamp > rxs->mactime) {
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+- "detected HW merge from received beacon\n");
++ "fixing mactime from %llx to %llx\n",
++ (unsigned long long)rxs->mactime,
++ (unsigned long long)tsf);
++ rxs->mactime = tsf;
+ }
++
++ /*
++ * Local TSF might have moved higher than our beacon timers,
++ * in that case we have to update them to continue sending
++ * beacons. This also takes care of synchronizing beacon sending
++ * times with other stations.
++ */
++ if (hw_tu >= sc->nexttbtt)
++ ath5k_beacon_update_timers(sc, bc_tstamp);
+ }
+ }
+
+@@ -1685,12 +1780,11 @@
+ ath5k_tasklet_rx(unsigned long data)
+ {
+ struct ieee80211_rx_status rxs = {};
++ struct ath5k_rx_status rs = {};
+ 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;
+@@ -1713,7 +1807,7 @@
+ if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
+ break;
+
+- ret = sc->ah->ah_proc_rx_desc(sc->ah, ds);
++ ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
+ if (unlikely(ret == -EINPROGRESS))
+ break;
+ else if (unlikely(ret)) {
+@@ -1722,16 +1816,15 @@
+ return;
+ }
+
+- if (unlikely(ds->ds_rxstat.rs_more)) {
++ if (unlikely(rs.rs_more)) {
+ ATH5K_WARN(sc, "unsupported jumbo\n");
+ goto next;
+ }
+
+- stat = ds->ds_rxstat.rs_status;
+- if (unlikely(stat)) {
+- if (stat & AR5K_RXERR_PHY)
++ if (unlikely(rs.rs_status)) {
++ if (rs.rs_status & AR5K_RXERR_PHY)
+ goto next;
+- if (stat & AR5K_RXERR_DECRYPT) {
++ if (rs.rs_status & AR5K_RXERR_DECRYPT) {
+ /*
+ * Decrypt error. If the error occurred
+ * because there was no hardware key, then
+@@ -1742,30 +1835,29 @@
+ *
+ * XXX do key cache faulting
+ */
+- if (ds->ds_rxstat.rs_keyix ==
+- AR5K_RXKEYIX_INVALID &&
+- !(stat & AR5K_RXERR_CRC))
++ if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
++ !(rs.rs_status & AR5K_RXERR_CRC))
+ goto accept;
+ }
+- if (stat & AR5K_RXERR_MIC) {
++ if (rs.rs_status & 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)) ||
++ if ((rs.rs_status &
++ ~(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_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr,
++ rs.rs_datalen, PCI_DMA_FROMDEVICE);
+ pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
+ PCI_DMA_FROMDEVICE);
+ bf->skb = NULL;
+
+- skb_put(skb, len);
++ skb_put(skb, rs.rs_datalen);
+
+ /*
+ * the hardware adds a padding to 4 byte boundaries between
+@@ -1787,13 +1879,23 @@
+ * 15bit only. that means TSF extension has to be done within
+ * 32768usec (about 32ms). it might be necessary to move this to
+ * the interrupt handler, like it is done in madwifi.
++ *
++ * Unfortunately we don't know when the hardware takes the rx
++ * timestamp (beginning of phy frame, data frame, end of rx?).
++ * The only thing we know is that it is hardware specific...
++ * On AR5213 it seems the rx timestamp is at the end of the
++ * frame, but i'm not sure.
++ *
++ * NOTE: mac80211 defines mactime at the beginning of the first
++ * data symbol. Since we don't have any time references it's
++ * impossible to comply to that. This affects IBSS merge only
++ * right now, so it's not too bad...
+ */
+- rxs.mactime = ath5k_extend_tsf(sc->ah, ds->ds_rxstat.rs_tstamp);
++ rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
+ rxs.flag |= RX_FLAG_TSFT;
+
+- rxs.freq = sc->curchan->freq;
+- rxs.channel = sc->curchan->chan;
+- rxs.phymode = sc->curmode;
++ rxs.freq = sc->curchan->center_freq;
++ rxs.band = sc->curband->band;
+
+ /*
+ * signal quality:
+@@ -1803,25 +1905,25 @@
+ /* 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;
++ rxs.ssi = rxs.noise + rs.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.signal = rs.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);
++ rxs.antenna = rs.rs_antenna;
++ rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
++ rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
+
+ ath5k_debug_dump_skb(sc, skb, "RX ", 0);
+
+ /* check beacons in IBSS mode */
+ if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+- ath5k_check_ibss_hw_merge(sc, skb);
++ ath5k_check_ibss_tsf(sc, skb, &rxs);
+
+ __ieee80211_rx(sc->hw, skb, &rxs);
+- sc->led_rxrate = ds->ds_rxstat.rs_rate;
++ sc->led_rxrate = rs.rs_rate;
+ ath5k_led_event(sc, ATH_LED_RX);
+ next:
+ list_move_tail(&bf->list, &sc->rxbuf);
+@@ -1840,6 +1942,7 @@
+ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+ {
+ struct ieee80211_tx_status txs = {};
++ struct ath5k_tx_status ts = {};
+ struct ath5k_buf *bf, *bf0;
+ struct ath5k_desc *ds;
+ struct sk_buff *skb;
+@@ -1852,7 +1955,7 @@
+ /* 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);
++ ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
+ if (unlikely(ret == -EINPROGRESS))
+ break;
+ else if (unlikely(ret)) {
+@@ -1867,17 +1970,16 @@
+ 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)) {
++ txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
++ if (unlikely(ts.ts_status)) {
+ sc->ll_stats.dot11ACKFailureCount++;
+- if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY)
++ if (ts.ts_status & AR5K_TXERR_XRETRY)
+ txs.excessive_retries = 1;
+- else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT)
++ else if (ts.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;
++ txs.ack_signal = ts.ts_rssi;
+ }
+
+ ieee80211_tx_status(sc->hw, skb, &txs);
+@@ -1958,8 +2060,9 @@
+ ds->ds_data = bf->skbaddr;
+ ret = ah->ah_setup_tx_desc(ah, ds, skb->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);
++ AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
++ ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID,
++ antenna, flags, 0, 0);
+ if (ret)
+ goto err_unmap;
+
+@@ -2050,7 +2153,7 @@
+ * beacon timer registers.
+ *
+ * This is called in a variety of situations, e.g. when a beacon is received,
+- * when a HW merge has been detected, but also when an new IBSS is created or
++ * when a TSF update has been detected, but also when an new IBSS is created or
+ * when we otherwise know we have to update the timers, but we keep it in this
+ * function to have it all together in one place.
+ */
+@@ -2150,7 +2253,7 @@
+ * another AP to associate with.
+ *
+ * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
+- * interrupts to detect HW merges only.
++ * interrupts to detect TSF updates only.
+ *
+ * AP mode is missing.
+ */
+@@ -2170,7 +2273,7 @@
+ * hardware send the beacons automatically. We have to load it
+ * only once here.
+ * We use the SWBA interrupt only to keep track of the beacon
+- * timers in order to detect HW merges (automatic TSF updates).
++ * timers in order to detect automatic TSF updates.
+ */
+ ath5k_beaconq_config(sc);
+
+@@ -2211,7 +2314,8 @@
+ * be followed by initialization of the appropriate bits
+ * and then setup of the interrupt mask.
+ */
+- sc->curchan = sc->hw->conf.chan;
++ sc->curchan = sc->hw->conf.channel;
++ sc->curband = &sc->sbands[sc->curchan->band];
+ ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false);
+ if (ret) {
+ ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret);
+@@ -2238,7 +2342,8 @@
+ * Enable interrupts.
+ */
+ sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
+- AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL;
++ AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL |
++ AR5K_INT_MIB;
+
+ ath5k_hw_set_intr(sc->ah, sc->imask);
+ /* Set ack to be sent at low bit-rates */
+@@ -2382,8 +2487,8 @@
+ *
+ * In IBSS mode we use this interrupt just to
+ * keep track of the next TBTT (target beacon
+- * transmission time) in order to detect hardware
+- * merges (TSF updates).
++ * transmission time) in order to detect wether
++ * automatic TSF updates happened.
+ */
+ if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ /* XXX: only if VEOL suppported */
+@@ -2418,7 +2523,11 @@
+ if (status & AR5K_INT_BMISS) {
+ }
+ if (status & AR5K_INT_MIB) {
+- /* TODO */
++ /*
++ * These stats are also used for ANI i think
++ * so how about updating them more often ?
++ */
++ ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
+ }
+ }
+ } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
+@@ -2448,7 +2557,8 @@
+ struct ath5k_hw *ah = sc->ah;
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
+- sc->curchan->chan, sc->curchan->val);
++ ieee80211_frequency_to_channel(sc->curchan->center_freq),
++ sc->curchan->hw_value);
+
+ if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+ /*
+@@ -2460,7 +2570,8 @@
+ }
+ if (ath5k_hw_phy_calibrate(ah, sc->curchan))
+ ATH5K_ERR(sc, "calibration of channel %u failed\n",
+- sc->curchan->chan);
++ ieee80211_frequency_to_channel(
++ sc->curchan->center_freq));
+
+ mod_timer(&sc->calib_tim, round_jiffies(jiffies +
+ msecs_to_jiffies(ath5k_calinterval * 1000)));
+@@ -2558,7 +2669,7 @@
+ memmove(skb->data, skb->data+pad, hdrlen);
+ }
+
+- sc->led_txrate = ctl->tx_rate;
++ sc->led_txrate = ctl->tx_rate->hw_value;
+
+ spin_lock_irqsave(&sc->txbuflock, flags);
+ if (list_empty(&sc->txbuf)) {
+@@ -2597,11 +2708,6 @@
+ 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);
+@@ -2692,6 +2798,9 @@
+ mutex_unlock(&sc->lock);
+ }
+
++/*
++ * TODO: Phy disable/diversity etc
++ */
+ static int
+ ath5k_config(struct ieee80211_hw *hw,
+ struct ieee80211_conf *conf)
+@@ -2699,9 +2808,9 @@
+ struct ath5k_softc *sc = hw->priv;
+
+ sc->bintval = conf->beacon_int;
+- ath5k_setcurmode(sc, conf->phymode);
++ sc->power_level = conf->power_level;
+
+- return ath5k_chan_set(sc, conf->chan);
++ return ath5k_chan_set(sc, conf->channel);
+ }
+
+ static int
+@@ -2869,7 +2978,9 @@
+
+ switch(key->alg) {
+ case ALG_WEP:
+- break;
++ /* XXX: fix hardware encryption, its not working. For now
++ * allow software encryption */
++ /* break; */
+ case ALG_TKIP:
+ case ALG_CCMP:
+ return -EOPNOTSUPP;
+@@ -2909,6 +3020,10 @@
+ struct ieee80211_low_level_stats *stats)
+ {
+ struct ath5k_softc *sc = hw->priv;
++ struct ath5k_hw *ah = sc->ah;
++
++ /* Force update */
++ ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
+
+ memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
+
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/base.h linux-2.6.25/drivers/net/wireless/ath5k/base.h
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/base.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/base.h 2008-04-19 13:54:59.000000000 +0200
+@@ -83,7 +83,7 @@
+ #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? */
++#define ATH_CHAN_MAX (14+14+14+252+20)
+ #endif
+
+ /* Software Carrier, keeps track of the driver state
+@@ -95,15 +95,22 @@
+ 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_supported_band sbands[IEEE80211_NUM_BANDS];
+ struct ieee80211_channel channels[ATH_CHAN_MAX];
+- struct ieee80211_rate rates[AR5K_MAX_RATES * NUM_DRIVER_MODES];
++ struct ieee80211_rate rates[AR5K_MAX_RATES * IEEE80211_NUM_BANDS];
+ enum ieee80211_if_types opmode;
+ struct ath5k_hw *ah; /* Atheros HW */
+
+-#if ATH5K_DEBUG
++ struct ieee80211_supported_band *curband;
++
++ u8 a_rates;
++ u8 b_rates;
++ u8 g_rates;
++ u8 xr_rates;
++
++#ifdef CONFIG_ATH5K_DEBUG
+ struct ath5k_dbg_info debug; /* debug info */
+-#endif
++#endif /* CONFIG_ATH5K_DEBUG */
+
+ struct ath5k_buf *bufptr; /* allocated buffer ptr */
+ struct ath5k_desc *desc; /* TX/RX descriptors */
+@@ -169,6 +176,7 @@
+ unsigned int nexttbtt; /* next beacon time in TU */
+
+ struct timer_list calib_tim; /* calibration timer */
++ int power_level; /* Requested tx power in dbm */
+ };
+
+ #define ath5k_hw_hasbssidmask(_ah) \
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/debug.c linux-2.6.25/drivers/net/wireless/ath5k/debug.c
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/debug.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/debug.c 2008-04-19 13:54:59.000000000 +0200
+@@ -65,7 +65,7 @@
+ module_param_named(debug, ath5k_debug, uint, 0);
+
+
+-#if ATH5K_DEBUG
++#ifdef CONFIG_ATH5K_DEBUG
+
+ #include <linux/seq_file.h>
+ #include "reg.h"
+@@ -200,7 +200,8 @@
+ {
+ struct ath5k_softc *sc = file->private_data;
+ char buf[100];
+- snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
++ snprintf(buf, sizeof(buf), "0x%016llx\n",
++ (unsigned long long)ath5k_hw_get_tsf64(sc->ah));
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
+ }
+
+@@ -271,7 +272,8 @@
+
+ tsf = ath5k_hw_get_tsf64(sc->ah);
+ len += snprintf(buf+len, sizeof(buf)-len,
+- "TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf));
++ "TSF\t\t0x%016llx\tTU: %08x\n",
++ (unsigned long long)tsf, TSF_TO_TU(tsf));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ }
+@@ -340,7 +342,7 @@
+ { ATH5K_DEBUG_LED, "led", "LED mamagement" },
+ { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" },
+ { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
+- { ATH5K_DEBUG_DUMPMODES, "dumpmodes", "dump modes" },
++ { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" },
+ { ATH5K_DEBUG_TRACE, "trace", "trace function calls" },
+ { ATH5K_DEBUG_ANY, "all", "show all debug levels" },
+ };
+@@ -452,43 +454,63 @@
+ /* functions used in other places */
+
+ void
+-ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes)
++ath5k_debug_dump_bands(struct ath5k_softc *sc)
+ {
+- unsigned int m, i;
++ unsigned int b, i;
+
+- if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES)))
++ if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPBANDS)))
+ 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);
++ BUG_ON(!sc->sbands);
++
++ for (b = 0; b < IEEE80211_NUM_BANDS; b++) {
++ struct ieee80211_supported_band *band = &sc->sbands[b];
++ char bname[5];
++ switch (band->band) {
++ case IEEE80211_BAND_2GHZ:
++ strcpy(bname, "2 GHz");
++ break;
++ case IEEE80211_BAND_5GHZ:
++ strcpy(bname, "5 GHz");
++ break;
++ default:
++ printk(KERN_DEBUG "Band not supported: %d\n",
++ band->band);
++ return;
++ }
++ printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname,
++ band->n_channels, band->n_bitrates);
+ printk(KERN_DEBUG " channels:\n");
+- for (i = 0; i < modes[m].num_channels; i++)
++ for (i = 0; i < band->n_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);
++ ieee80211_frequency_to_channel(
++ band->channels[i].center_freq),
++ band->channels[i].center_freq,
++ band->channels[i].hw_value,
++ band->channels[i].flags);
+ printk(KERN_DEBUG " rates:\n");
+- for (i = 0; i < modes[m].num_rates; i++)
++ for (i = 0; i < band->n_bitrates; 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);
++ band->bitrates[i].bitrate,
++ band->bitrates[i].hw_value,
++ band->bitrates[i].flags,
++ band->bitrates[i].hw_value_short);
+ }
+ }
+
+ static inline void
+-ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done)
++ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done,
++ struct ath5k_rx_status *rs)
+ {
+ struct ath5k_desc *ds = bf->desc;
++ struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx;
+
+ 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) ? '*' : '!');
++ ds->ds_link, ds->ds_data,
++ rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
++ rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0,
++ !done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
+ }
+
+ void
+@@ -496,6 +518,7 @@
+ {
+ struct ath5k_desc *ds;
+ struct ath5k_buf *bf;
++ struct ath5k_rx_status rs = {};
+ int status;
+
+ if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+@@ -507,9 +530,9 @@
+ spin_lock_bh(&sc->rxbuflock);
+ list_for_each_entry(bf, &sc->rxbuf, list) {
+ ds = bf->desc;
+- status = ah->ah_proc_rx_desc(ah, ds);
++ status = ah->ah_proc_rx_desc(ah, ds, &rs);
+ if (!status)
+- ath5k_debug_printrxbuf(bf, status == 0);
++ ath5k_debug_printrxbuf(bf, status == 0, &rs);
+ }
+ spin_unlock_bh(&sc->rxbuflock);
+ }
+@@ -533,19 +556,24 @@
+ }
+
+ void
+-ath5k_debug_printtxbuf(struct ath5k_softc *sc,
+- struct ath5k_buf *bf, int done)
++ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf)
+ {
+ struct ath5k_desc *ds = bf->desc;
++ struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212;
++ struct ath5k_tx_status ts = {};
++ int done;
+
+ if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+ return;
+
++ done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts);
++
+ 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) ? '*' : '!');
++ ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1,
++ td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3,
++ td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
++ done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
+ }
+
+-#endif /* if ATH5K_DEBUG */
++#endif /* ifdef CONFIG_ATH5K_DEBUG */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/debug.h linux-2.6.25/drivers/net/wireless/ath5k/debug.h
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/debug.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/debug.h 2008-04-19 13:54:59.000000000 +0200
+@@ -61,11 +61,6 @@
+ #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;
+@@ -96,7 +91,7 @@
+ * @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_DUMPBANDS: dump bands
+ * @ATH5K_DEBUG_TRACE: trace function calls
+ * @ATH5K_DEBUG_ANY: show at any debug level
+ *
+@@ -118,12 +113,12 @@
+ ATH5K_DEBUG_LED = 0x00000080,
+ ATH5K_DEBUG_DUMP_RX = 0x00000100,
+ ATH5K_DEBUG_DUMP_TX = 0x00000200,
+- ATH5K_DEBUG_DUMPMODES = 0x00000400,
++ ATH5K_DEBUG_DUMPBANDS = 0x00000400,
+ ATH5K_DEBUG_TRACE = 0x00001000,
+ ATH5K_DEBUG_ANY = 0xffffffff
+ };
+
+-#if ATH5K_DEBUG
++#ifdef CONFIG_ATH5K_DEBUG
+
+ #define ATH5K_TRACE(_sc) do { \
+ if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
+@@ -158,20 +153,20 @@
+ 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);
++ath5k_debug_dump_bands(struct ath5k_softc *sc);
+
+ 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);
++ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf);
+
+ #else /* no debugging */
+
+-#define ATH5K_TRACE(_sc) /* empty */
++#include <linux/compiler.h>
++
++#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc))
+
+ static inline void __attribute__ ((format (printf, 3, 4)))
+ ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
+@@ -196,17 +191,15 @@
+ 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) {}
++ath5k_debug_dump_bands(struct ath5k_softc *sc) {}
+
+ 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) {}
++ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {}
+
+-#endif /* if ATH5K_DEBUG */
++#endif /* ifdef CONFIG_ATH5K_DEBUG */
+
+ #endif /* ifndef _ATH5K_DEBUG_H */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/hw.c linux-2.6.25/drivers/net/wireless/ath5k/hw.c
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/hw.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/hw.c 2008-04-19 13:54:59.000000000 +0200
+@@ -1,4 +1,4 @@
+- /*
++/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org>
+@@ -48,14 +48,18 @@
+ static int 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_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *,
++ struct ath5k_tx_status *);
+ 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_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *,
++ struct ath5k_tx_status *);
++static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *, struct ath5k_desc *,
++ struct ath5k_rx_status *);
++static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *, struct ath5k_desc *,
++ struct ath5k_rx_status *);
+ static int ath5k_hw_get_capabilities(struct ath5k_hw *);
+
+ static int ath5k_eeprom_init(struct ath5k_hw *);
+@@ -81,12 +85,12 @@
+
+ static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
+ {
+- return turbo == true ? (usec * 80) : (usec * 40);
++ return turbo ? (usec * 80) : (usec * 40);
+ }
+
+ static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
+ {
+- return turbo == true ? (clock / 80) : (clock / 40);
++ return turbo ? (clock / 80) : (clock / 40);
+ }
+
+ /*
+@@ -100,7 +104,7 @@
+
+ for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+ data = ath5k_hw_reg_read(ah, reg);
+- if ((is_set == true) && (data & flag))
++ if (is_set && (data & flag))
+ break;
+ else if ((data & flag) == val)
+ break;
+@@ -116,11 +120,69 @@
+ \***************************************/
+
+ /*
++ * Power On Self Test helper function
++ */
++static int ath5k_hw_post(struct ath5k_hw *ah)
++{
++
++ int i, c;
++ u16 cur_reg;
++ u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)};
++ u32 var_pattern;
++ u32 static_pattern[4] = {
++ 0x55555555, 0xaaaaaaaa,
++ 0x66666666, 0x99999999
++ };
++ u32 init_val;
++ u32 cur_val;
++
++ for (c = 0; c < 2; c++) {
++
++ cur_reg = regs[c];
++ init_val = ath5k_hw_reg_read(ah, cur_reg);
++
++ for (i = 0; i < 256; i++) {
++ var_pattern = i << 16 | i;
++ ath5k_hw_reg_write(ah, var_pattern, cur_reg);
++ cur_val = ath5k_hw_reg_read(ah, cur_reg);
++
++ if (cur_val != var_pattern) {
++ ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
++ return -EAGAIN;
++ }
++
++ /* Found on ndiswrapper dumps */
++ var_pattern = 0x0039080f;
++ ath5k_hw_reg_write(ah, var_pattern, cur_reg);
++ }
++
++ for (i = 0; i < 4; i++) {
++ var_pattern = static_pattern[i];
++ ath5k_hw_reg_write(ah, var_pattern, cur_reg);
++ cur_val = ath5k_hw_reg_read(ah, cur_reg);
++
++ if (cur_val != var_pattern) {
++ ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
++ return -EAGAIN;
++ }
++
++ /* Found on ndiswrapper dumps */
++ var_pattern = 0x003b080f;
++ ath5k_hw_reg_write(ah, var_pattern, cur_reg);
++ }
++ }
++
++ return 0;
++
++}
++
++/*
+ * 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;
++ struct pci_dev *pdev = sc->pdev;
+ u8 mac[ETH_ALEN];
+ int ret;
+ u32 srev;
+@@ -140,9 +202,6 @@
+ * 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;
+@@ -177,9 +236,9 @@
+ }
+
+ if (ah->ah_version == AR5K_AR5212)
+- ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status;
++ ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
+ else if (ah->ah_version <= AR5K_AR5211)
+- ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status;
++ ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
+
+ /* Bring device out of sleep and reset it's units */
+ ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true);
+@@ -203,15 +262,19 @@
+ CHANNEL_2GHZ);
+
+ /* Return on unsuported chips (unsupported eeprom etc) */
+- if(srev >= AR5K_SREV_VER_AR5416){
++ if ((srev >= AR5K_SREV_VER_AR5416) &&
++ (srev < AR5K_SREV_VER_AR2425)) {
+ ATH5K_ERR(sc, "Device not yet supported.\n");
+ ret = -ENODEV;
+ goto err_free;
++ } else if (srev == AR5K_SREV_VER_AR2425) {
++ ATH5K_WARN(sc, "Support for RF2425 is under development.\n");
+ }
+
+ /* Identify single chip solutions */
+- if((srev <= AR5K_SREV_VER_AR5414) &&
+- (srev >= AR5K_SREV_VER_AR2424)) {
++ if (((srev <= AR5K_SREV_VER_AR5414) &&
++ (srev >= AR5K_SREV_VER_AR2413)) ||
++ (srev == AR5K_SREV_VER_AR2425)) {
+ ah->ah_single_chip = true;
+ } else {
+ ah->ah_single_chip = false;
+@@ -226,15 +289,81 @@
+ 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_phy_spending = AR5K_PHY_SPENDING_RF5111;
++ } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) {
++
+ ah->ah_radio = AR5K_RF5112;
++
++ if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
++ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
+ } else {
++ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
++ }
++
++ } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
++ ah->ah_radio = AR5K_RF2413;
++ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
++ } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
++
+ ah->ah_radio = AR5K_RF5413;
++
++ if (ah->ah_mac_srev <= AR5K_SREV_VER_AR5424 &&
++ ah->ah_mac_srev >= AR5K_SREV_VER_AR2424)
++ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
++ else
++ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
++ /*
++ * Register returns 0x4 for radio revision
++ * so ath5k_hw_radio_revision doesn't parse the value
++ * correctly. For now we are based on mac's srev to
++ * identify RF2425 radio.
++ */
++ } else if (srev == AR5K_SREV_VER_AR2425) {
++ ah->ah_radio = AR5K_RF2425;
++ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
+ }
+
+ ah->ah_phy = AR5K_PHY(0);
+
+ /*
++ * Identify AR5212-based PCI-E cards
++ * And write some initial settings.
++ *
++ * (doing a "strings" on ndis driver
++ * -ar5211.sys- reveals the following
++ * pci-e related functions:
++ *
++ * pcieClockReq
++ * pcieRxErrNotify
++ * pcieL1SKPEnable
++ * pcieAspm
++ * pcieDisableAspmOnRfWake
++ * pciePowerSaveEnable
++ *
++ * I guess these point to ClockReq but
++ * i'm not sure.)
++ */
++ if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
++ ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
++ ath5k_hw_reg_write(ah, 0x24924924, 0x4080);
++ ath5k_hw_reg_write(ah, 0x28000039, 0x4080);
++ ath5k_hw_reg_write(ah, 0x53160824, 0x4080);
++ ath5k_hw_reg_write(ah, 0xe5980579, 0x4080);
++ ath5k_hw_reg_write(ah, 0x001defff, 0x4080);
++ ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080);
++ ath5k_hw_reg_write(ah, 0xbe105554, 0x4080);
++ ath5k_hw_reg_write(ah, 0x000e3007, 0x4080);
++ ath5k_hw_reg_write(ah, 0x00000000, 0x4084);
++ }
++
++ /*
++ * POST
++ */
++ ret = ath5k_hw_post(ah);
++ if (ret)
++ goto err_free;
++
++ /*
+ * Get card capabilities, values, ...
+ */
+
+@@ -280,7 +409,8 @@
+ */
+ static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
+ {
+- u32 turbo, mode, clock;
++ struct pci_dev *pdev = ah->ah_sc->pdev;
++ u32 turbo, mode, clock, bus_flags;
+ int ret;
+
+ turbo = 0;
+@@ -357,10 +487,16 @@
+ 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");
++ /* reseting PCI on PCI-E cards results card to hang
++ * and always return 0xffff... so we ingore that flag
++ * for PCI-E cards */
++ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
++
++ /* Reset chipset */
++ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
++ AR5K_RESET_CTL_BASEBAND | bus_flags);
++ if (ret) {
++ ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
+ return -EIO;
+ }
+
+@@ -405,15 +541,15 @@
+
+ /* Get rate tables */
+ switch (mode) {
+- case MODE_IEEE80211A:
++ case AR5K_MODE_11A:
+ return &ath5k_rt_11a;
+- case MODE_ATHEROS_TURBO:
++ case AR5K_MODE_11A_TURBO:
+ return &ath5k_rt_turbo;
+- case MODE_IEEE80211B:
++ case AR5K_MODE_11B:
+ return &ath5k_rt_11b;
+- case MODE_IEEE80211G:
++ case AR5K_MODE_11G:
+ return &ath5k_rt_11g;
+- case MODE_ATHEROS_TURBOG:
++ case AR5K_MODE_11G_TURBO:
+ return &ath5k_rt_xr;
+ }
+
+@@ -459,15 +595,15 @@
+ ds_coef_exp, ds_coef_man, clock;
+
+ if (!(ah->ah_version == AR5K_AR5212) ||
+- !(channel->val & CHANNEL_OFDM))
++ !(channel->hw_value & 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;
++ clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40;
+ coef_scaled = ((5 * (clock << 24)) / 2) /
+- channel->freq;
++ channel->center_freq;
+
+ for (coef_exp = 31; coef_exp > 0; coef_exp--)
+ if ((coef_scaled >> coef_exp) & 0x1)
+@@ -494,8 +630,7 @@
+ * 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
++ * @mode: one of enum ath5k_driver_mode
+ *
+ * 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
+@@ -506,19 +641,20 @@
+ *
+ */
+ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
+- unsigned int driver_mode)
++ unsigned int mode)
+ {
+ struct ath5k_softc *sc = ah->ah_sc;
+ const struct ath5k_rate_table *rt;
++ struct ieee80211_rate srate = {};
+ unsigned int i;
+
+ /* Get rate table for the current operating mode */
+- rt = ath5k_hw_get_rate_table(ah,
+- driver_mode);
++ rt = ath5k_hw_get_rate_table(ah, 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;
+
+@@ -528,14 +664,16 @@
+ /* Set ACK timeout */
+ reg = AR5K_RATE_DUR(rate->rate_code);
+
++ srate.bitrate = control_rate->rate_kbps/100;
++
+ /* 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->vif, 10, control_rate->rate_kbps/100);
++ tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
++ sc->vif, 10, &srate));
+
+ ath5k_hw_reg_write(ah, tx_time, reg);
+
+@@ -568,8 +706,9 @@
+ 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;
++ struct pci_dev *pdev = ah->ah_sc->pdev;
++ u32 data, s_seq, s_ant, s_led[3], dma_size;
++ unsigned int i, mode, freq, ee_mode, ant[2];
+ int ret;
+
+ ATH5K_TRACE(ah->ah_sc);
+@@ -585,7 +724,7 @@
+ */
+ /*DCU/Antenna selection not available on 5210*/
+ if (ah->ah_version != AR5K_AR5210) {
+- if (change_channel == true) {
++ if (change_channel) {
+ /* Seq number for queue 0 -do this for all queues ? */
+ s_seq = ath5k_hw_reg_read(ah,
+ AR5K_QUEUE_DFS_SEQNUM(0));
+@@ -599,12 +738,12 @@
+ 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)
++ if (change_channel && ah->ah_rf_banks != NULL)
+ ath5k_hw_get_rf_gain(ah);
+
+
+ /*Wakeup the device*/
+- ret = ath5k_hw_nic_wakeup(ah, channel->val, false);
++ ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
+ if (ret)
+ return ret;
+
+@@ -620,43 +759,40 @@
+ if (ah->ah_version != AR5K_AR5210) {
+ if (ah->ah_radio != AR5K_RF5111 &&
+ ah->ah_radio != AR5K_RF5112 &&
+- ah->ah_radio != AR5K_RF5413) {
++ ah->ah_radio != AR5K_RF5413 &&
++ ah->ah_radio != AR5K_RF2413 &&
++ ah->ah_radio != AR5K_RF2425) {
+ ATH5K_ERR(ah->ah_sc,
+ "invalid phy radio: %u\n", ah->ah_radio);
+ return -EINVAL;
+ }
+
+- switch (channel->val & CHANNEL_MODES) {
++ switch (channel->hw_value & CHANNEL_MODES) {
+ case CHANNEL_A:
+- mode = AR5K_INI_VAL_11A;
++ mode = AR5K_MODE_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;
++ mode = AR5K_MODE_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;
++ mode = AR5K_MODE_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;
++ mode = AR5K_MODE_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;
++ mode = AR5K_MODE_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) {
+@@ -664,14 +800,13 @@
+ "XR mode not available on 5211");
+ return -EINVAL;
+ }
+- mode = AR5K_INI_VAL_XR;
++ mode = AR5K_MODE_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);
++ "invalid channel: %d\n", channel->center_freq);
+ return -EINVAL;
+ }
+
+@@ -701,15 +836,26 @@
+ /*
+ * Write some more initial register settings
+ */
+- if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */
++ if (ah->ah_version == AR5K_AR5212) {
+ ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11));
+
+- if (channel->val == CHANNEL_G)
+- ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */
++ if (channel->hw_value == CHANNEL_G)
++ if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413)
++ ath5k_hw_reg_write(ah, 0x00f80d80,
++ AR5K_PHY(83));
++ else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424)
++ ath5k_hw_reg_write(ah, 0x00380140,
++ AR5K_PHY(83));
++ else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425)
++ ath5k_hw_reg_write(ah, 0x00fc0ec0,
++ AR5K_PHY(83));
++ else /* 2425 */
++ ath5k_hw_reg_write(ah, 0x00fc0fc0,
++ AR5K_PHY(83));
+ else
+- ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83));
++ 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);
+@@ -722,7 +868,7 @@
+ AR5K_SREV_RAD_5112A) {
+ ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+ AR5K_PHY_CCKTXCTL);
+- if (channel->val & CHANNEL_5GHZ)
++ if (channel->hw_value & CHANNEL_5GHZ)
+ data = 0xffb81020;
+ else
+ data = 0xffb80d20;
+@@ -742,7 +888,7 @@
+ * mac80211 are integrated */
+ if (ah->ah_version == AR5K_AR5212 &&
+ ah->ah_sc->vif != NULL)
+- ath5k_hw_write_rate_duration(ah, driver_mode);
++ ath5k_hw_write_rate_duration(ah, mode);
+
+ /*
+ * Write RF registers
+@@ -758,7 +904,7 @@
+
+ /* Write OFDM timings on 5212*/
+ if (ah->ah_version == AR5K_AR5212 &&
+- channel->val & CHANNEL_OFDM) {
++ channel->hw_value & CHANNEL_OFDM) {
+ ret = ath5k_hw_write_ofdm_timings(ah, channel);
+ if (ret)
+ return ret;
+@@ -767,7 +913,7 @@
+ /*Enable/disable 802.11b mode on 5111
+ (enable 2111 frequency converter + CCK)*/
+ if (ah->ah_radio == AR5K_RF5111) {
+- if (driver_mode == MODE_IEEE80211B)
++ if (mode == AR5K_MODE_11B)
+ AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_B_MODE);
+ else
+@@ -885,13 +1031,24 @@
+
+ /*
+ * Set Rx/Tx DMA Configuration
+- *(passing dma size not available on 5210)
++ *
++ * Set maximum DMA size (512) except for PCI-E cards since
++ * it causes rx overruns and tx errors (tested on 5424 but since
++ * rx overruns also occur on 5416/5418 with madwifi we set 128
++ * for all PCI-E cards to be safe).
++ *
++ * In dumps this is 128 for allchips.
++ *
++ * XXX: need to check 5210 for this
++ * TODO: Check out tx triger level, it's always 64 on dumps but I
++ * guess we can tweak it and see how it goes ;-)
+ */
++ dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B;
+ 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);
++ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
++ AR5K_TXCFG_SDMAMR, dma_size);
++ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
++ AR5K_RXCFG_SDMAMW, dma_size);
+ }
+
+ /*
+@@ -905,7 +1062,7 @@
+ 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 = (channel->hw_value & CHANNEL_CCK) ?
+ ((data << 2) / 22) : (data / 10);
+
+ udelay(100 + data);
+@@ -922,11 +1079,11 @@
+ 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);
++ channel->center_freq);
+ return -EAGAIN;
+ }
+
+- ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
++ ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+ if (ret)
+ return ret;
+
+@@ -934,7 +1091,7 @@
+
+ /* 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)) {
++ if (!(mode == AR5K_MODE_11B)) {
+ ah->ah_calibration = true;
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+ AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+@@ -981,6 +1138,8 @@
+
+ /*
+ * Set the 32MHz reference clock on 5212 phy clock sleep register
++ *
++ * TODO: Find out how to switch to external 32Khz clock to save power
+ */
+ if (ah->ah_version == AR5K_AR5212) {
+ ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
+@@ -988,9 +1147,15 @@
+ 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);
++ ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
++ }
++
++ if (ah->ah_version == AR5K_AR5212) {
++ ath5k_hw_reg_write(ah, 0x000100aa, 0x8118);
++ ath5k_hw_reg_write(ah, 0x00003210, 0x811c);
++ ath5k_hw_reg_write(ah, 0x00000052, 0x8108);
++ if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413)
++ ath5k_hw_reg_write(ah, 0x00000004, 0x8120);
+ }
+
+ /*
+@@ -1065,7 +1230,7 @@
+ staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
+ /* fallthrough */
+ case AR5K_PM_NETWORK_SLEEP:
+- if (set_chip == true)
++ if (set_chip)
+ ath5k_hw_reg_write(ah,
+ AR5K_SLEEP_CTL_SLE | sleep_duration,
+ AR5K_SLEEP_CTL);
+@@ -1074,7 +1239,7 @@
+ break;
+
+ case AR5K_PM_FULL_SLEEP:
+- if (set_chip == true)
++ if (set_chip)
+ ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
+ AR5K_SLEEP_CTL);
+
+@@ -1082,7 +1247,7 @@
+ break;
+
+ case AR5K_PM_AWAKE:
+- if (set_chip == false)
++ if (!set_chip)
+ goto commit;
+
+ ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
+@@ -1389,7 +1554,7 @@
+ trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
+ AR5K_TXCFG_TXFULL);
+
+- if (increase == false) {
++ if (!increase) {
+ if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
+ goto done;
+ } else
+@@ -1592,9 +1757,10 @@
+ /*
+ * Write to eeprom - currently disabled, use at your own risk
+ */
++#if 0
+ static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data)
+ {
+-#if 0
++
+ u32 status, timeout;
+
+ ATH5K_TRACE(ah->ah_sc);
+@@ -1636,10 +1802,11 @@
+ }
+ udelay(15);
+ }
+-#endif
++
+ ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!");
+ return -EIO;
+ }
++#endif
+
+ /*
+ * Translate binary channel representation in EEPROM to frequency
+@@ -2045,50 +2212,6 @@
+ }
+
+ /*
+- * 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)
+@@ -2110,8 +2233,8 @@
+ 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);
++ __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
++ __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode);
+ } else {
+ /*
+ * XXX The tranceiver supports frequencies from 4920 to 6100GHz
+@@ -2133,12 +2256,12 @@
+ ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
+
+ /* Set supported modes */
+- __set_bit(MODE_IEEE80211A,
++ __set_bit(AR5K_MODE_11A,
+ ah->ah_capabilities.cap_mode);
+- __set_bit(MODE_ATHEROS_TURBO,
++ __set_bit(AR5K_MODE_11A_TURBO,
+ ah->ah_capabilities.cap_mode);
+ if (ah->ah_version == AR5K_AR5212)
+- __set_bit(MODE_ATHEROS_TURBOG,
++ __set_bit(AR5K_MODE_11G_TURBO,
+ ah->ah_capabilities.cap_mode);
+ }
+
+@@ -2150,11 +2273,11 @@
+ ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
+
+ if (AR5K_EEPROM_HDR_11B(ee_header))
+- __set_bit(MODE_IEEE80211B,
++ __set_bit(AR5K_MODE_11B,
+ ah->ah_capabilities.cap_mode);
+
+ if (AR5K_EEPROM_HDR_11G(ee_header))
+- __set_bit(MODE_IEEE80211G,
++ __set_bit(AR5K_MODE_11G,
+ ah->ah_capabilities.cap_mode);
+ }
+ }
+@@ -2279,8 +2402,8 @@
+ * 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);
++ ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
++ ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
+ }
+
+ /*
+@@ -2425,6 +2548,8 @@
+ {
+ ATH5K_TRACE(ah->ah_sc);
+ AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
++
++ /* TODO: ANI Support */
+ }
+
+ /*
+@@ -2434,6 +2559,8 @@
+ {
+ ATH5K_TRACE(ah->ah_sc);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
++
++ /* TODO: ANI Support */
+ }
+
+ /*
+@@ -2828,15 +2955,19 @@
+ * Update mib counters (statistics)
+ */
+ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
+- struct ath5k_mib_stats *statistics)
++ struct ieee80211_low_level_stats *stats)
+ {
+ 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);
++ stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
++ stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
++ stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
++ stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
++
++ /* XXX: Should we use this to track beacon count ?
++ * -we read it anyway to clear the register */
++ ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
+
+ /* Reset profile count registers on 5212*/
+ if (ah->ah_version == AR5K_AR5212) {
+@@ -2937,8 +3068,16 @@
+ 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)
++ /*
++ * Set NULL encryption on AR5212+
++ *
++ * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
++ * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
++ *
++ * Note2: Windows driver (ndiswrapper) sets this to
++ * 0x00000714 instead of 0x00000007
++ */
++ if (ah->ah_version > AR5K_AR5211)
+ ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+ AR5K_KEYTABLE_TYPE(entry));
+
+@@ -3186,19 +3325,19 @@
+ return 0;
+
+ /* Set Slot time */
+- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++ ath5k_hw_reg_write(ah, ah->ah_turbo ?
+ 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 ?
++ ath5k_hw_reg_write(ah, ah->ah_turbo ?
+ 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 ?
++ ath5k_hw_reg_write(ah, ah->ah_turbo ?
+ AR5K_INIT_TRANSMIT_LATENCY_TURBO :
+ AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
+ /* Set IFS0 */
+- if (ah->ah_turbo == true)
++ if (ah->ah_turbo)
+ ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
+ (ah->ah_aifs + tq->tqi_aifs) *
+ AR5K_INIT_SLOT_TIME_TURBO) <<
+@@ -3211,16 +3350,16 @@
+ AR5K_INIT_SIFS, AR5K_IFS0);
+
+ /* Set IFS1 */
+- ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
++ ath5k_hw_reg_write(ah, ah->ah_turbo ?
+ 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_write(ah, ah->ah_turbo ?
+ (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 ?
++ ath5k_hw_reg_write(ah, ah->ah_turbo ?
+ (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
+ AR5K_PHY_TURBO_SHORT | 0x2020) :
+ (AR5K_PHY_FRAME_CTL_INI | 0x1020),
+@@ -3259,7 +3398,7 @@
+ /*
+ * Calculate and set retry limits
+ */
+- if (ah->ah_software_retry == true) {
++ if (ah->ah_software_retry) {
+ /* XXX Need to test this */
+ retry_lg = ah->ah_limit_tx_retries;
+ retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
+@@ -3507,10 +3646,10 @@
+ unsigned int rtscts_rate, unsigned int rtscts_duration)
+ {
+ u32 frame_type;
+- struct ath5k_hw_2w_tx_desc *tx_desc;
++ struct ath5k_hw_2w_tx_ctl *tx_ctl;
+ unsigned int frame_len;
+
+- tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
++ tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+
+ /*
+ * Validate input
+@@ -3529,12 +3668,8 @@
+ 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;
++ /* Clear descriptor */
++ memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
+
+ /* Setup control descriptor */
+
+@@ -3546,7 +3681,7 @@
+ if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+ return -EINVAL;
+
+- tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
++ tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+
+ /* Verify and set buffer length */
+
+@@ -3557,7 +3692,7 @@
+ if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+ return -EINVAL;
+
+- tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
++ tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+
+ /*
+ * Verify and set header length
+@@ -3566,7 +3701,7 @@
+ if (ah->ah_version == AR5K_AR5210) {
+ if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+ return -EINVAL;
+- tx_desc->tx_control_0 |=
++ tx_ctl->tx_control_0 |=
+ AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+ }
+
+@@ -3582,19 +3717,19 @@
+ frame_type = type /*<< 2 ?*/;
+ }
+
+- tx_desc->tx_control_0 |=
++ tx_ctl->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 |=
++ tx_ctl->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 |=
++ tx_ctl->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 |= \
++ tx_ctl->tx_control_##_c |= \
+ AR5K_2W_TX_DESC_CTL##_c##_##_flag
+
+ _TX_FLAGS(0, CLRDMASK);
+@@ -3609,9 +3744,9 @@
+ * WEP crap
+ */
+ if (key_index != AR5K_TXKEYIX_INVALID) {
+- tx_desc->tx_control_0 |=
++ tx_ctl->tx_control_0 |=
+ AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+- tx_desc->tx_control_1 |=
++ tx_ctl->tx_control_1 |=
+ AR5K_REG_SM(key_index,
+ AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+ }
+@@ -3621,7 +3756,7 @@
+ */
+ if ((ah->ah_version == AR5K_AR5210) &&
+ (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
+- tx_desc->tx_control_1 |= rtscts_duration &
++ tx_ctl->tx_control_1 |= rtscts_duration &
+ AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+
+ return 0;
+@@ -3637,13 +3772,11 @@
+ 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;
++ struct ath5k_hw_4w_tx_ctl *tx_ctl;
+ unsigned int frame_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];
++ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+
+ /*
+ * Validate input
+@@ -3662,14 +3795,8 @@
+ 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;
++ /* Clear descriptor */
++ memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
+
+ /* Setup control descriptor */
+
+@@ -3681,7 +3808,7 @@
+ if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+ return -EINVAL;
+
+- tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
++ tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+
+ /* Verify and set buffer length */
+
+@@ -3692,20 +3819,20 @@
+ if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+ return -EINVAL;
+
+- tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
++ tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+
+- tx_desc->tx_control_0 |=
++ tx_ctl->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,
++ tx_ctl->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,
++ tx_ctl->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;
++ tx_ctl->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 |= \
++ tx_ctl->tx_control_##_c |= \
+ AR5K_4W_TX_DESC_CTL##_c##_##_flag
+
+ _TX_FLAGS(0, CLRDMASK);
+@@ -3721,8 +3848,8 @@
+ * 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,
++ tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
++ tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
+ AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+ }
+
+@@ -3733,9 +3860,9 @@
+ if ((flags & AR5K_TXDESC_RTSENA) &&
+ (flags & AR5K_TXDESC_CTSENA))
+ return -EINVAL;
+- tx_desc->tx_control_2 |= rtscts_duration &
++ tx_ctl->tx_control_2 |= rtscts_duration &
+ AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+- tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
++ tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+ AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
+ }
+
+@@ -3750,7 +3877,7 @@
+ 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;
++ struct ath5k_hw_4w_tx_ctl *tx_ctl;
+
+ /*
+ * Rates can be 0 as long as the retry count is 0 too.
+@@ -3767,14 +3894,14 @@
+ }
+
+ if (ah->ah_version == AR5K_AR5212) {
+- tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
++ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+
+ #define _XTX_TRIES(_n) \
+ if (tx_tries##_n) { \
+- tx_desc->tx_control_2 |= \
++ tx_ctl->tx_control_2 |= \
+ AR5K_REG_SM(tx_tries##_n, \
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \
+- tx_desc->tx_control_3 |= \
++ tx_ctl->tx_control_3 |= \
+ AR5K_REG_SM(tx_rate##_n, \
+ AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \
+ }
+@@ -3795,13 +3922,15 @@
+ * 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_desc *desc, struct ath5k_tx_status *ts)
+ {
++ struct ath5k_hw_2w_tx_ctl *tx_ctl;
+ 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];
++ ATH5K_TRACE(ah->ah_sc);
++
++ tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
++ tx_status = &desc->ud.ds_tx5210.tx_stat;
+
+ /* No frame has been send or error */
+ if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
+@@ -3810,32 +3939,32 @@
+ /*
+ * Get descriptor status
+ */
+- desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
++ ts->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,
++ ts->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,
++ ts->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,
++ /*TODO: ts->ts_virtcol + test*/
++ ts->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,
++ ts->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,
++ ts->ts_antenna = 1;
++ ts->ts_status = 0;
++ ts->ts_rate = AR5K_REG_MS(tx_ctl->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;
++ ts->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;
++ ts->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;
++ ts->ts_status |= AR5K_TXERR_FILT;
+ }
+
+ return 0;
+@@ -3845,14 +3974,15 @@
+ * Proccess a tx descriptor on 5212
+ */
+ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
+- struct ath5k_desc *desc)
++ struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+ {
++ struct ath5k_hw_4w_tx_ctl *tx_ctl;
+ 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];
++
++ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
++ tx_status = &desc->ud.ds_tx5212.tx_stat;
+
+ /* No frame has been send or error */
+ if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
+@@ -3861,42 +3991,42 @@
+ /*
+ * Get descriptor status
+ */
+- desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
++ ts->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,
++ ts->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,
++ ts->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,
++ ts->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,
++ ts->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 &
++ ts->ts_antenna = (tx_status->tx_status_1 &
+ AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+- desc->ds_us.tx.ts_status = 0;
++ ts->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 &
++ ts->ts_rate = tx_ctl->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,
++ ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
+ AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
+- desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
++ ts->ts_longretry += AR5K_REG_MS(tx_ctl->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,
++ ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
+ AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
+- desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
++ ts->ts_longretry += AR5K_REG_MS(tx_ctl->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,
++ ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
+ AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
+- desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
++ ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
+ break;
+ }
+@@ -3904,13 +4034,13 @@
+ 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;
++ ts->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;
++ ts->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;
++ ts->ts_status |= AR5K_TXERR_FILT;
+ }
+
+ return 0;
+@@ -3926,31 +4056,27 @@
+ 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;
++ struct ath5k_hw_rx_ctl *rx_ctl;
+
+ ATH5K_TRACE(ah->ah_sc);
+- rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0;
++ rx_ctl = &desc->ud.ds_rx.rx_ctl;
+
+ /*
+- *Clear ds_hw
++ * Clear the descriptor
+ * 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;
++ memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
+
+ /* Setup descriptor */
+- rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
+- if (unlikely(rx_desc->rx_control_1 != size))
++ rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
++ if (unlikely(rx_ctl->rx_control_1 != size))
+ return -EINVAL;
+
+ if (flags & AR5K_RXDESC_INTREQ)
+- rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
++ rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
+
+ return 0;
+ }
+@@ -3958,67 +4084,68 @@
+ /*
+ * Proccess the rx status descriptor on 5210/5211
+ */
+-static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah,
+- struct ath5k_desc *desc)
++static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
++ struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+ {
+- struct ath5k_hw_old_rx_status *rx_status;
++ struct ath5k_hw_rx_status *rx_status;
+
+- rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0];
++ rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+ /* No frame received / not ready */
+- if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE)
++ if (unlikely((rx_status->rx_status_1 & AR5K_5210_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;
++ rs->rs_datalen = rx_status->rx_status_0 &
++ AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
++ rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
++ AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
++ rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
++ AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
++ rs->rs_antenna = rx_status->rx_status_0 &
++ AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA;
++ rs->rs_more = rx_status->rx_status_0 &
++ AR5K_5210_RX_DESC_STATUS0_MORE;
++ /* TODO: this timestamp is 13 bit, later on we assume 15 bit */
++ rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
++ AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
++ rs->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);
++ if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID)
++ rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
++ AR5K_5210_RX_DESC_STATUS1_KEY_INDEX);
+ else
+- desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
++ rs->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_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
++ if (rx_status->rx_status_1 &
++ AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
++ rs->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;
++ AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
++ rs->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);
++ AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
++ rs->rs_status |= AR5K_RXERR_PHY;
++ rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
++ AR5K_5210_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;
++ AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
++ rs->rs_status |= AR5K_RXERR_DECRYPT;
+ }
+
+ return 0;
+@@ -4027,71 +4154,72 @@
+ /*
+ * Proccess the rx status descriptor on 5212
+ */
+-static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah,
+- struct ath5k_desc *desc)
++static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
++ struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+ {
+- struct ath5k_hw_new_rx_status *rx_status;
++ struct ath5k_hw_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];
++ rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+ /* Overlay on error */
+- rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0];
++ rx_err = &desc->ud.ds_rx.u.rx_err;
+
+ /* No frame received / not ready */
+- if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE)
++ if (unlikely((rx_status->rx_status_1 & AR5K_5212_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;
++ rs->rs_datalen = rx_status->rx_status_0 &
++ AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
++ rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
++ AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
++ rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
++ AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
++ rs->rs_antenna = rx_status->rx_status_0 &
++ AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA;
++ rs->rs_more = rx_status->rx_status_0 &
++ AR5K_5212_RX_DESC_STATUS0_MORE;
++ rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
++ AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
++ rs->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);
++ if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
++ rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
++ AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
+ else
+- desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
++ rs->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;
++ AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
++ if (rx_status->rx_status_1 &
++ AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
++ rs->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_5212_RX_DESC_STATUS1_PHY_ERROR) {
++ rs->rs_status |= AR5K_RXERR_PHY;
++ rs->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;
++ AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
++ rs->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;
++ if (rx_status->rx_status_1 &
++ AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
++ rs->rs_status |= AR5K_RXERR_MIC;
+ }
+
+ return 0;
+@@ -4250,35 +4378,6 @@
+ }
+
+
+-/*********************************\
+- 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;
+-}
+
+
+ /****************\
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/hw.h linux-2.6.25/drivers/net/wireless/ath5k/hw.h
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/hw.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/hw.h 2008-04-19 13:54:59.000000000 +0200
+@@ -173,7 +173,10 @@
+ * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ */
+
+-struct ath5k_rx_desc {
++/*
++ * common hardware RX control descriptor
++ */
++struct ath5k_hw_rx_ctl {
+ u32 rx_control_0; /* RX control word 0 */
+
+ #define AR5K_DESC_RX_CTL0 0x00000000
+@@ -185,69 +188,63 @@
+ } __packed;
+
+ /*
+- * 5210/5211 rx status descriptor
++ * common hardware RX status descriptor
++ * 5210/11 and 5212 differ only in the flags defined below
+ */
+-struct ath5k_hw_old_rx_status {
++struct ath5k_hw_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;
+
++/* 5210/5211 */
++#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff
++#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000
++#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000
++#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15
++#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000
++#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19
++#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000
++#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27
++#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001
++#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
++#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004
++#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008
++#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010
++#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0
++#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5
++#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
++#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00
++#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9
++#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000
++#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15
++#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000
++
++/* 5212 */
++#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff
++#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000
++#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000
++#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000
++#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15
++#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000
++#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20
++#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000
++#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28
++#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001
++#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
++#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004
++#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008
++#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010
++#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020
++#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
++#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00
++#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9
++#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000
++#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16
++#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000
++
+ /*
+- * 5212 rx status descriptor
++ * common hardware RX error 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 */
+
+@@ -268,7 +265,10 @@
+ #define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0
+ #define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0
+
+-struct ath5k_hw_2w_tx_desc {
++/*
++ * 5210/5211 hardware 2-word TX control descriptor
++ */
++struct ath5k_hw_2w_tx_ctl {
+ u32 tx_control_0; /* TX control word 0 */
+
+ #define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff
+@@ -314,9 +314,9 @@
+ #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10
+
+ /*
+- * 5212 4-word tx control descriptor
++ * 5212 hardware 4-word TX control descriptor
+ */
+-struct ath5k_hw_4w_tx_desc {
++struct ath5k_hw_4w_tx_ctl {
+ u32 tx_control_0; /* TX control word 0 */
+
+ #define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff
+@@ -374,7 +374,7 @@
+ } __packed;
+
+ /*
+- * Common tx status descriptor
++ * Common TX status descriptor
+ */
+ struct ath5k_hw_tx_status {
+ u32 tx_status_0; /* TX status word 0 */
+@@ -415,6 +415,34 @@
+
+
+ /*
++ * 5210/5211 hardware TX descriptor
++ */
++struct ath5k_hw_5210_tx_desc {
++ struct ath5k_hw_2w_tx_ctl tx_ctl;
++ struct ath5k_hw_tx_status tx_stat;
++} __packed;
++
++/*
++ * 5212 hardware TX descriptor
++ */
++struct ath5k_hw_5212_tx_desc {
++ struct ath5k_hw_4w_tx_ctl tx_ctl;
++ struct ath5k_hw_tx_status tx_stat;
++} __packed;
++
++/*
++ * common hardware RX descriptor
++ */
++struct ath5k_hw_all_rx_desc {
++ struct ath5k_hw_rx_ctl rx_ctl;
++ union {
++ struct ath5k_hw_rx_status rx_stat;
++ struct ath5k_hw_rx_error rx_err;
++ } u;
++} __packed;
++
++
++/*
+ * AR5K REGISTER ACCESS
+ */
+
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/initvals.c linux-2.6.25/drivers/net/wireless/ath5k/initvals.c
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/initvals.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/initvals.c 2008-04-19 13:54:59.000000000 +0200
+@@ -678,8 +678,8 @@
+ { 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), 0x018830c6 },*/ /* 2413 */
+ { AR5K_PHY(648), 0x01831061 },
+ { AR5K_PHY(649), 0x00000400 },
+ /*{ AR5K_PHY(650), 0x000001b5 },*/
+@@ -1081,6 +1081,414 @@
+ { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
+ };
+
++/* Initial mode-specific settings for RF2413/2414 (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 rf2413_ini_mode_end[] = {
++ { AR5K_TXCFG,
++ /* b g gTurbo */
++ { 0x00000015, 0x00000015, 0x00000015 } },
++ { AR5K_USEC_5211,
++ { 0x04e01395, 0x12e013ab, 0x098813cf } },
++ { AR5K_PHY(10),
++ { 0x05020000, 0x0a020001, 0x0a020001 } },
++ { AR5K_PHY(13),
++ { 0x00000e00, 0x00000e00, 0x00000e00 } },
++ { AR5K_PHY(14),
++ { 0x0000000a, 0x0000000a, 0x0000000a } },
++ { AR5K_PHY(18),
++ { 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
++ { AR5K_PHY(20),
++ { 0x0de8b0da, 0x0c98b0da, 0x0c98b0da } },
++ { AR5K_PHY_SIG,
++ { 0x7ee80d2e, 0x7ec80d2e, 0x7ec80d2e } },
++ { AR5K_PHY_AGCCOARSE,
++ { 0x3137665e, 0x3139605e, 0x3139605e } },
++ { AR5K_PHY(27),
++ { 0x050cb081, 0x050cb081, 0x050cb081 } },
++ { AR5K_PHY_RX_DELAY,
++ { 0x0000044c, 0x00000898, 0x000007d0 } },
++ { AR5K_PHY_FRAME_CTL_5211,
++ { 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
++ { AR5K_PHY_CCKTXCTL,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { AR5K_PHY(642),
++ { 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
++ { AR5K_PHY_GAIN_2GHZ,
++ { 0x0042c140, 0x0042c140, 0x0042c140 } },
++ { 0xa21c,
++ { 0x1863800a, 0x1883800a, 0x1883800a } },
++ { AR5K_DCU_FP,
++ { 0x000003e0, 0x000003e0, 0x000003e0 } },
++ { 0x8060,
++ { 0x0000000f, 0x0000000f, 0x0000000f } },
++ { 0x8118,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x811c,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x8120,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x8124,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x8128,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x812c,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x8130,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x8134,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x8138,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x813c,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0x8140,
++ { 0x800000a8, 0x800000a8, 0x800000a8 } },
++ { 0x8144,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { AR5K_PHY_AGC,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { AR5K_PHY(11),
++ { 0x0000a000, 0x0000a000, 0x0000a000 } },
++ { AR5K_PHY(15),
++ { 0x00200400, 0x00200400, 0x00200400 } },
++ { AR5K_PHY(19),
++ { 0x1284233c, 0x1284233c, 0x1284233c } },
++ { AR5K_PHY_SCR,
++ { 0x0000001f, 0x0000001f, 0x0000001f } },
++ { AR5K_PHY_SLMT,
++ { 0x00000080, 0x00000080, 0x00000080 } },
++ { AR5K_PHY_SCAL,
++ { 0x0000000e, 0x0000000e, 0x0000000e } },
++ { AR5K_PHY(86),
++ { 0x000000ff, 0x000000ff, 0x000000ff } },
++ { AR5K_PHY(96),
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { AR5K_PHY(97),
++ { 0x02800000, 0x02800000, 0x02800000 } },
++ { AR5K_PHY(104),
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { AR5K_PHY(120),
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { AR5K_PHY(121),
++ { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } },
++ { AR5K_PHY(122),
++ { 0x3c466478, 0x3c466478, 0x3c466478 } },
++ { AR5K_PHY(123),
++ { 0x000000aa, 0x000000aa, 0x000000aa } },
++ { AR5K_PHY_SCLOCK,
++ { 0x0000000c, 0x0000000c, 0x0000000c } },
++ { AR5K_PHY_SDELAY,
++ { 0x000000ff, 0x000000ff, 0x000000ff } },
++ { AR5K_PHY_SPENDING,
++ { 0x00000014, 0x00000014, 0x00000014 } },
++ { 0xa228,
++ { 0x000009b5, 0x000009b5, 0x000009b5 } },
++ { 0xa23c,
++ { 0x93c889af, 0x93c889af, 0x93c889af } },
++ { 0xa24c,
++ { 0x00000001, 0x00000001, 0x00000001 } },
++ { 0xa250,
++ { 0x0000a000, 0x0000a000, 0x0000a000 } },
++ { 0xa254,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0xa258,
++ { 0x0cc75380, 0x0cc75380, 0x0cc75380 } },
++ { 0xa25c,
++ { 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } },
++ { 0xa260,
++ { 0x5f690f01, 0x5f690f01, 0x5f690f01 } },
++ { 0xa264,
++ { 0x00418a11, 0x00418a11, 0x00418a11 } },
++ { 0xa268,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0xa26c,
++ { 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } },
++ { 0xa270,
++ { 0x00820820, 0x00820820, 0x00820820 } },
++ { 0xa274,
++ { 0x001b7caa, 0x001b7caa, 0x001b7caa } },
++ { 0xa278,
++ { 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } },
++ { 0xa27c,
++ { 0x051701ce, 0x051701ce, 0x051701ce } },
++ { 0xa300,
++ { 0x18010000, 0x18010000, 0x18010000 } },
++ { 0xa304,
++ { 0x30032602, 0x30032602, 0x30032602 } },
++ { 0xa308,
++ { 0x48073e06, 0x48073e06, 0x48073e06 } },
++ { 0xa30c,
++ { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
++ { 0xa310,
++ { 0x641a600f, 0x641a600f, 0x641a600f } },
++ { 0xa314,
++ { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
++ { 0xa318,
++ { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
++ { 0xa31c,
++ { 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
++ { 0xa320,
++ { 0x9d4f970f, 0x9d4f970f, 0x9d4f970f } },
++ { 0xa324,
++ { 0xa5cfa18f, 0xa5cfa18f, 0xa5cfa18f } },
++ { 0xa328,
++ { 0xb55faf1f, 0xb55faf1f, 0xb55faf1f } },
++ { 0xa32c,
++ { 0xbddfb99f, 0xbddfb99f, 0xbddfb99f } },
++ { 0xa330,
++ { 0xcd7fc73f, 0xcd7fc73f, 0xcd7fc73f } },
++ { 0xa334,
++ { 0xd5ffd1bf, 0xd5ffd1bf, 0xd5ffd1bf } },
++ { 0xa338,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0xa33c,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0xa340,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0xa344,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 0xa348,
++ { 0x3fffffff, 0x3fffffff, 0x3fffffff } },
++ { 0xa34c,
++ { 0x3fffffff, 0x3fffffff, 0x3fffffff } },
++ { 0xa350,
++ { 0x3fffffff, 0x3fffffff, 0x3fffffff } },
++ { 0xa354,
++ { 0x0003ffff, 0x0003ffff, 0x0003ffff } },
++ { 0xa358,
++ { 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } },
++ { 0xa35c,
++ { 0x066c420f, 0x066c420f, 0x066c420f } },
++ { 0xa360,
++ { 0x0f282207, 0x0f282207, 0x0f282207 } },
++ { 0xa364,
++ { 0x17601685, 0x17601685, 0x17601685 } },
++ { 0xa368,
++ { 0x1f801104, 0x1f801104, 0x1f801104 } },
++ { 0xa36c,
++ { 0x37a00c03, 0x37a00c03, 0x37a00c03 } },
++ { 0xa370,
++ { 0x3fc40883, 0x3fc40883, 0x3fc40883 } },
++ { 0xa374,
++ { 0x57c00803, 0x57c00803, 0x57c00803 } },
++ { 0xa378,
++ { 0x5fd80682, 0x5fd80682, 0x5fd80682 } },
++ { 0xa37c,
++ { 0x7fe00482, 0x7fe00482, 0x7fe00482 } },
++ { 0xa380,
++ { 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } },
++ { 0xa384,
++ { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
++};
++
++/* Initial mode-specific settings for RF2425 (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 rf2425_ini_mode_end[] = {
++ { AR5K_TXCFG,
++ /* g gTurbo */
++ { 0x00000015, 0x00000015 } },
++ { AR5K_USEC_5211,
++ { 0x12e013ab, 0x098813cf } },
++ { AR5K_PHY_TURBO,
++ { 0x00000000, 0x00000003 } },
++ { AR5K_PHY(10),
++ { 0x0a020001, 0x0a020001 } },
++ { AR5K_PHY(13),
++ { 0x00000e0e, 0x00000e0e } },
++ { AR5K_PHY(14),
++ { 0x0000000b, 0x0000000b } },
++ { AR5K_PHY(17),
++ { 0x13721422, 0x13721422 } },
++ { AR5K_PHY(18),
++ { 0x00199a65, 0x00199a65 } },
++ { AR5K_PHY(20),
++ { 0x0c98b0da, 0x0c98b0da } },
++ { AR5K_PHY_SIG,
++ { 0x7ec80d2e, 0x7ec80d2e } },
++ { AR5K_PHY_AGCCOARSE,
++ { 0x3139605e, 0x3139605e } },
++ { AR5K_PHY(27),
++ { 0x050cb081, 0x050cb081 } },
++ { AR5K_PHY_RX_DELAY,
++ { 0x00000898, 0x000007d0 } },
++ { AR5K_PHY_FRAME_CTL_5211,
++ { 0xf7b81000, 0xf7b81000 } },
++ { AR5K_PHY_CCKTXCTL,
++ { 0x00000000, 0x00000000 } },
++ { AR5K_PHY(642),
++ { 0xd03e6788, 0xd03e6788 } },
++ { AR5K_PHY_GAIN_2GHZ,
++ { 0x0052c140, 0x0052c140 } },
++ { 0xa21c,
++ { 0x1883800a, 0x1883800a } },
++ { 0xa324,
++ { 0xa7cfa7cf, 0xa7cfa7cf } },
++ { 0xa328,
++ { 0xa7cfa7cf, 0xa7cfa7cf } },
++ { 0xa32c,
++ { 0xa7cfa7cf, 0xa7cfa7cf } },
++ { 0xa330,
++ { 0xa7cfa7cf, 0xa7cfa7cf } },
++ { 0xa334,
++ { 0xa7cfa7cf, 0xa7cfa7cf } },
++ { AR5K_DCU_FP,
++ { 0x000003e0, 0x000003e0 } },
++ { 0x8060,
++ { 0x0000000f, 0x0000000f } },
++ { 0x809c,
++ { 0x00000000, 0x00000000 } },
++ { 0x80a0,
++ { 0x00000000, 0x00000000 } },
++ { 0x8118,
++ { 0x00000000, 0x00000000 } },
++ { 0x811c,
++ { 0x00000000, 0x00000000 } },
++ { 0x8120,
++ { 0x00000000, 0x00000000 } },
++ { 0x8124,
++ { 0x00000000, 0x00000000 } },
++ { 0x8128,
++ { 0x00000000, 0x00000000 } },
++ { 0x812c,
++ { 0x00000000, 0x00000000 } },
++ { 0x8130,
++ { 0x00000000, 0x00000000 } },
++ { 0x8134,
++ { 0x00000000, 0x00000000 } },
++ { 0x8138,
++ { 0x00000000, 0x00000000 } },
++ { 0x813c,
++ { 0x00000000, 0x00000000 } },
++ { 0x8140,
++ { 0x800003f9, 0x800003f9 } },
++ { 0x8144,
++ { 0x00000000, 0x00000000 } },
++ { AR5K_PHY_AGC,
++ { 0x00000000, 0x00000000 } },
++ { AR5K_PHY(11),
++ { 0x0000a000, 0x0000a000 } },
++ { AR5K_PHY(15),
++ { 0x00200400, 0x00200400 } },
++ { AR5K_PHY(19),
++ { 0x1284233c, 0x1284233c } },
++ { AR5K_PHY_SCR,
++ { 0x0000001f, 0x0000001f } },
++ { AR5K_PHY_SLMT,
++ { 0x00000080, 0x00000080 } },
++ { AR5K_PHY_SCAL,
++ { 0x0000000e, 0x0000000e } },
++ { AR5K_PHY(86),
++ { 0x00081fff, 0x00081fff } },
++ { AR5K_PHY(96),
++ { 0x00000000, 0x00000000 } },
++ { AR5K_PHY(97),
++ { 0x02800000, 0x02800000 } },
++ { AR5K_PHY(104),
++ { 0x00000000, 0x00000000 } },
++ { AR5K_PHY(119),
++ { 0xfebadbe8, 0xfebadbe8 } },
++ { AR5K_PHY(120),
++ { 0x00000000, 0x00000000 } },
++ { AR5K_PHY(121),
++ { 0xaaaaaaaa, 0xaaaaaaaa } },
++ { AR5K_PHY(122),
++ { 0x3c466478, 0x3c466478 } },
++ { AR5K_PHY(123),
++ { 0x000000aa, 0x000000aa } },
++ { AR5K_PHY_SCLOCK,
++ { 0x0000000c, 0x0000000c } },
++ { AR5K_PHY_SDELAY,
++ { 0x000000ff, 0x000000ff } },
++ { AR5K_PHY_SPENDING,
++ { 0x00000014, 0x00000014 } },
++ { 0xa228,
++ { 0x000009b5, 0x000009b5 } },
++ { AR5K_PHY_TXPOWER_RATE3,
++ { 0x20202020, 0x20202020 } },
++ { AR5K_PHY_TXPOWER_RATE4,
++ { 0x20202020, 0x20202020 } },
++ { 0xa23c,
++ { 0x93c889af, 0x93c889af } },
++ { 0xa24c,
++ { 0x00000001, 0x00000001 } },
++ { 0xa250,
++ { 0x0000a000, 0x0000a000 } },
++ { 0xa254,
++ { 0x00000000, 0x00000000 } },
++ { 0xa258,
++ { 0x0cc75380, 0x0cc75380 } },
++ { 0xa25c,
++ { 0x0f0f0f01, 0x0f0f0f01 } },
++ { 0xa260,
++ { 0x5f690f01, 0x5f690f01 } },
++ { 0xa264,
++ { 0x00418a11, 0x00418a11 } },
++ { 0xa268,
++ { 0x00000000, 0x00000000 } },
++ { 0xa26c,
++ { 0x0c30c166, 0x0c30c166 } },
++ { 0xa270,
++ { 0x00820820, 0x00820820 } },
++ { 0xa274,
++ { 0x081a3caa, 0x081a3caa } },
++ { 0xa278,
++ { 0x1ce739ce, 0x1ce739ce } },
++ { 0xa27c,
++ { 0x051701ce, 0x051701ce } },
++ { 0xa300,
++ { 0x16010000, 0x16010000 } },
++ { 0xa304,
++ { 0x2c032402, 0x2c032402 } },
++ { 0xa308,
++ { 0x48433e42, 0x48433e42 } },
++ { 0xa30c,
++ { 0x5a0f500b, 0x5a0f500b } },
++ { 0xa310,
++ { 0x6c4b624a, 0x6c4b624a } },
++ { 0xa314,
++ { 0x7e8b748a, 0x7e8b748a } },
++ { 0xa318,
++ { 0x96cf8ccb, 0x96cf8ccb } },
++ { 0xa31c,
++ { 0xa34f9d0f, 0xa34f9d0f } },
++ { 0xa320,
++ { 0xa7cfa58f, 0xa7cfa58f } },
++ { 0xa348,
++ { 0x3fffffff, 0x3fffffff } },
++ { 0xa34c,
++ { 0x3fffffff, 0x3fffffff } },
++ { 0xa350,
++ { 0x3fffffff, 0x3fffffff } },
++ { 0xa354,
++ { 0x0003ffff, 0x0003ffff } },
++ { 0xa358,
++ { 0x79a8aa1f, 0x79a8aa1f } },
++ { 0xa35c,
++ { 0x066c420f, 0x066c420f } },
++ { 0xa360,
++ { 0x0f282207, 0x0f282207 } },
++ { 0xa364,
++ { 0x17601685, 0x17601685 } },
++ { 0xa368,
++ { 0x1f801104, 0x1f801104 } },
++ { 0xa36c,
++ { 0x37a00c03, 0x37a00c03 } },
++ { 0xa370,
++ { 0x3fc40883, 0x3fc40883 } },
++ { 0xa374,
++ { 0x57c00803, 0x57c00803 } },
++ { 0xa378,
++ { 0x5fd80682, 0x5fd80682 } },
++ { 0xa37c,
++ { 0x7fe00482, 0x7fe00482 } },
++ { 0xa380,
++ { 0x7f3c7bba, 0x7f3c7bba } },
++ { 0xa384,
++ { 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)
+@@ -1290,35 +1698,92 @@
+
+ /* 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);
++
++ ath5k_hw_ini_registers(ah,
++ ARRAY_SIZE(rf5112_ini_bbgain),
++ rf5112_ini_bbgain, change_channel);
++
++ } else if (ah->ah_radio == AR5K_RF2413) {
++
++ if (mode < 2) {
++ ATH5K_ERR(ah->ah_sc,
++ "unsupported channel mode: %d\n", mode);
++ return -EINVAL;
++ }
++ mode = mode - 2;
++
++ /* Override a setting from ar5212_ini */
++ ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648));
++
++ ath5k_hw_ini_mode_registers(ah,
++ ARRAY_SIZE(rf2413_ini_mode_end),
++ rf2413_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_RF2425) {
++
++ if (mode < 2) {
++ ATH5K_ERR(ah->ah_sc,
++ "unsupported channel mode: %d\n", mode);
++ return -EINVAL;
++ }
++
++ /* Map b to g */
++ if (mode == 2)
++ mode = 0;
++ else
++ mode = mode - 3;
++
++ /* Override a setting from ar5212_ini */
++ ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648));
++
++ ath5k_hw_ini_mode_registers(ah,
++ ARRAY_SIZE(rf2425_ini_mode_end),
++ rf2425_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);
++ /* AR5K_MODE_11B */
++ if (mode > 2) {
++ ATH5K_ERR(ah->ah_sc,
++ "unsupported channel mode: %d\n", mode);
+ return -EINVAL;
+ }
+
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/Kconfig linux-2.6.25/drivers/net/wireless/ath5k/Kconfig
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.25/drivers/net/wireless/ath5k/Kconfig 2008-04-19 13:54:59.000000000 +0200
+@@ -0,0 +1,37 @@
++config ATH5K
++ tristate "Atheros 5xxx wireless cards support"
++ depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
++ ---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.
++
++config ATH5K_DEBUG
++ bool "Atheros 5xxx debugging"
++ depends on ATH5K
++ ---help---
++ Atheros 5xxx debugging messages.
++
++ Say Y, if and you will get debug options for ath5k.
++ To use this, you need to mount debugfs:
++
++ mkdir /debug/
++ mount -t debugfs debug /debug/
++
++ You will get access to files under:
++ /debug/ath5k/phy0/
++
++ To enable debug, pass the debug level to the debug module
++ parameter. For example:
++
++ modprobe ath5k debug=0x00000400
++
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/Makefile linux-2.6.25/drivers/net/wireless/ath5k/Makefile
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/Makefile 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/Makefile 2008-04-19 13:54:59.000000000 +0200
+@@ -1,2 +1,6 @@
+-ath5k-objs = base.o hw.o regdom.o initvals.o phy.o debug.o
++ath5k-y += base.o
++ath5k-y += hw.o
++ath5k-y += initvals.o
++ath5k-y += phy.o
++ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
+ obj-$(CONFIG_ATH5K) += ath5k.o
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/phy.c linux-2.6.25/drivers/net/wireless/ath5k/phy.c
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/phy.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/phy.c 2008-04-19 13:54:59.000000000 +0200
+@@ -666,6 +666,153 @@
+ { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+ };
+
++/* RF2413/2414 mode-specific init registers */
++static const struct ath5k_ini_rf rfregs_2413[] = {
++ { 1, AR5K_RF_BUFFER_CONTROL_4,
++ /* mode b mode g mode gTurbo */
++ { 0x00000020, 0x00000020, 0x00000020 } },
++ { 2, AR5K_RF_BUFFER_CONTROL_3,
++ { 0x02001408, 0x02001408, 0x02001408 } },
++ { 3, AR5K_RF_BUFFER_CONTROL_6,
++ { 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0xf0000000, 0xf0000000, 0xf0000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x03000000, 0x03000000, 0x03000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x40400000, 0x40400000, 0x40400000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x65050000, 0x65050000, 0x65050000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00420000, 0x00420000, 0x00420000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00b50000, 0x00b50000, 0x00b50000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00030000, 0x00030000, 0x00030000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00f70000, 0x00f70000, 0x00f70000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x009d0000, 0x009d0000, 0x009d0000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00220000, 0x00220000, 0x00220000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x04220000, 0x04220000, 0x04220000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00230018, 0x00230018, 0x00230018 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00280050, 0x00280050, 0x00280050 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x005000c3, 0x005000c3, 0x005000c3 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x0004007f, 0x0004007f, 0x0004007f } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000458, 0x00000458, 0x00000458 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x0000c000, 0x0000c000, 0x0000c000 } },
++ { 6, AR5K_RF_BUFFER_CONTROL_5,
++ { 0x00400230, 0x00400230, 0x00400230 } },
++ { 7, AR5K_RF_BUFFER,
++ { 0x00006400, 0x00006400, 0x00006400 } },
++ { 7, AR5K_RF_BUFFER,
++ { 0x00000800, 0x00000800, 0x00000800 } },
++ { 7, AR5K_RF_BUFFER_CONTROL_2,
++ { 0x0000000e, 0x0000000e, 0x0000000e } },
++};
++
++/* RF2425 mode-specific init registers */
++static const struct ath5k_ini_rf rfregs_2425[] = {
++ { 1, AR5K_RF_BUFFER_CONTROL_4,
++ /* mode g mode gTurbo */
++ { 0x00000020, 0x00000020 } },
++ { 2, AR5K_RF_BUFFER_CONTROL_3,
++ { 0x02001408, 0x02001408 } },
++ { 3, AR5K_RF_BUFFER_CONTROL_6,
++ { 0x00e020c0, 0x00e020c0 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x10000000, 0x10000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x002a0000, 0x002a0000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00100000, 0x00100000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00020000, 0x00020000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00730000, 0x00730000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00f80000, 0x00f80000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00e70000, 0x00e70000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00140000, 0x00140000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00910040, 0x00910040 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x0007001a, 0x0007001a } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00410000, 0x00410000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00810060, 0x00810060 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00020803, 0x00020803 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00000000, 0x00000000 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00001660, 0x00001660 } },
++ { 6, AR5K_RF_BUFFER,
++ { 0x00001688, 0x00001688 } },
++ { 6, AR5K_RF_BUFFER_CONTROL_1,
++ { 0x00000001, 0x00000001 } },
++ { 7, AR5K_RF_BUFFER,
++ { 0x00006400, 0x00006400 } },
++ { 7, AR5K_RF_BUFFER,
++ { 0x00000800, 0x00000800 } },
++ { 7, AR5K_RF_BUFFER_CONTROL_2,
++ { 0x0000000e, 0x0000000e } },
++};
+
+ /* Initial RF Gain settings for RF5112 */
+ static const struct ath5k_ini_rfgain rfgain_5112[] = {
+@@ -805,6 +952,74 @@
+ { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } },
+ };
+
++/* Initial RF Gain settings for RF2413 */
++static const struct ath5k_ini_rfgain rfgain_2413[] = {
++ { AR5K_RF_GAIN(0), { 0x00000000 } },
++ { AR5K_RF_GAIN(1), { 0x00000040 } },
++ { AR5K_RF_GAIN(2), { 0x00000080 } },
++ { AR5K_RF_GAIN(3), { 0x00000181 } },
++ { AR5K_RF_GAIN(4), { 0x000001c1 } },
++ { AR5K_RF_GAIN(5), { 0x00000001 } },
++ { AR5K_RF_GAIN(6), { 0x00000041 } },
++ { AR5K_RF_GAIN(7), { 0x00000081 } },
++ { AR5K_RF_GAIN(8), { 0x00000168 } },
++ { AR5K_RF_GAIN(9), { 0x000001a8 } },
++ { AR5K_RF_GAIN(10), { 0x000001e8 } },
++ { AR5K_RF_GAIN(11), { 0x00000028 } },
++ { AR5K_RF_GAIN(12), { 0x00000068 } },
++ { AR5K_RF_GAIN(13), { 0x00000189 } },
++ { AR5K_RF_GAIN(14), { 0x000001c9 } },
++ { AR5K_RF_GAIN(15), { 0x00000009 } },
++ { AR5K_RF_GAIN(16), { 0x00000049 } },
++ { AR5K_RF_GAIN(17), { 0x00000089 } },
++ { AR5K_RF_GAIN(18), { 0x00000190 } },
++ { AR5K_RF_GAIN(19), { 0x000001d0 } },
++ { AR5K_RF_GAIN(20), { 0x00000010 } },
++ { AR5K_RF_GAIN(21), { 0x00000050 } },
++ { AR5K_RF_GAIN(22), { 0x00000090 } },
++ { AR5K_RF_GAIN(23), { 0x00000191 } },
++ { AR5K_RF_GAIN(24), { 0x000001d1 } },
++ { AR5K_RF_GAIN(25), { 0x00000011 } },
++ { AR5K_RF_GAIN(26), { 0x00000051 } },
++ { AR5K_RF_GAIN(27), { 0x00000091 } },
++ { AR5K_RF_GAIN(28), { 0x00000178 } },
++ { AR5K_RF_GAIN(29), { 0x000001b8 } },
++ { AR5K_RF_GAIN(30), { 0x000001f8 } },
++ { AR5K_RF_GAIN(31), { 0x00000038 } },
++ { AR5K_RF_GAIN(32), { 0x00000078 } },
++ { AR5K_RF_GAIN(33), { 0x00000199 } },
++ { AR5K_RF_GAIN(34), { 0x000001d9 } },
++ { AR5K_RF_GAIN(35), { 0x00000019 } },
++ { AR5K_RF_GAIN(36), { 0x00000059 } },
++ { AR5K_RF_GAIN(37), { 0x00000099 } },
++ { AR5K_RF_GAIN(38), { 0x000000d9 } },
++ { AR5K_RF_GAIN(39), { 0x000000f9 } },
++ { AR5K_RF_GAIN(40), { 0x000000f9 } },
++ { AR5K_RF_GAIN(41), { 0x000000f9 } },
++ { AR5K_RF_GAIN(42), { 0x000000f9 } },
++ { AR5K_RF_GAIN(43), { 0x000000f9 } },
++ { AR5K_RF_GAIN(44), { 0x000000f9 } },
++ { AR5K_RF_GAIN(45), { 0x000000f9 } },
++ { AR5K_RF_GAIN(46), { 0x000000f9 } },
++ { AR5K_RF_GAIN(47), { 0x000000f9 } },
++ { AR5K_RF_GAIN(48), { 0x000000f9 } },
++ { AR5K_RF_GAIN(49), { 0x000000f9 } },
++ { AR5K_RF_GAIN(50), { 0x000000f9 } },
++ { AR5K_RF_GAIN(51), { 0x000000f9 } },
++ { AR5K_RF_GAIN(52), { 0x000000f9 } },
++ { AR5K_RF_GAIN(53), { 0x000000f9 } },
++ { AR5K_RF_GAIN(54), { 0x000000f9 } },
++ { AR5K_RF_GAIN(55), { 0x000000f9 } },
++ { AR5K_RF_GAIN(56), { 0x000000f9 } },
++ { AR5K_RF_GAIN(57), { 0x000000f9 } },
++ { AR5K_RF_GAIN(58), { 0x000000f9 } },
++ { AR5K_RF_GAIN(59), { 0x000000f9 } },
++ { AR5K_RF_GAIN(60), { 0x000000f9 } },
++ { AR5K_RF_GAIN(61), { 0x000000f9 } },
++ { AR5K_RF_GAIN(62), { 0x000000f9 } },
++ { AR5K_RF_GAIN(63), { 0x000000f9 } },
++};
++
+ static const struct ath5k_gain_opt rfgain_opt_5112 = {
+ 1,
+ 8,
+@@ -844,14 +1059,14 @@
+ entry = ((first - 1) / 8) + offset;
+ position = (first - 1) % 8;
+
+- if (set == true)
++ if (set)
+ 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) {
++ if (set) {
+ rf[entry] &= ~mask;
+ rf[entry] |= ((data << position) << (col * 8)) & mask;
+ data >>= (8 - position);
+@@ -864,7 +1079,7 @@
+ left -= 8 - position;
+ }
+
+- data = set == true ? 1 : ath5k_hw_bitswap(data, bits);
++ data = set ? 1 : ath5k_hw_bitswap(data, bits);
+
+ return data;
+ }
+@@ -955,7 +1170,6 @@
+ go = &rfgain_opt_5111;
+ break;
+ case AR5K_RF5112:
+- case AR5K_RF5413: /* ??? */
+ go = &rfgain_opt_5112;
+ break;
+ default:
+@@ -1018,7 +1232,7 @@
+ int obdb = -1, bank = -1;
+ u32 ee_mode;
+
+- AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
++ AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX);
+
+ rf = ah->ah_rf_banks;
+
+@@ -1038,8 +1252,8 @@
+ }
+
+ /* Modify bank 0 */
+- if (channel->val & CHANNEL_2GHZ) {
+- if (channel->val & CHANNEL_CCK)
++ if (channel->hw_value & CHANNEL_2GHZ) {
++ if (channel->hw_value & CHANNEL_CCK)
+ ee_mode = AR5K_EEPROM_MODE_11B;
+ else
+ ee_mode = AR5K_EEPROM_MODE_11G;
+@@ -1058,10 +1272,10 @@
+ } 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)));
++ obdb = channel->center_freq >= 5725 ? 3 :
++ (channel->center_freq >= 5500 ? 2 :
++ (channel->center_freq >= 5260 ? 1 :
++ (channel->center_freq > 4000 ? 0 : -1)));
+
+ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+ ee->ee_pwd_84, 1, 51, 3, true))
+@@ -1119,12 +1333,12 @@
+ int obdb = -1, bank = -1;
+ u32 ee_mode;
+
+- AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
++ AR5K_ASSERT_ENTRY(mode, AR5K_MODE_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)){
++ && !test_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode)) {
+ rf_ini = rfregs_2112a;
+ rf_size = ARRAY_SIZE(rfregs_5112a);
+ if (mode < 2) {
+@@ -1156,8 +1370,8 @@
+ }
+
+ /* Modify bank 6 */
+- if (channel->val & CHANNEL_2GHZ) {
+- if (channel->val & CHANNEL_OFDM)
++ if (channel->hw_value & CHANNEL_2GHZ) {
++ if (channel->hw_value & CHANNEL_OFDM)
+ ee_mode = AR5K_EEPROM_MODE_11G;
+ else
+ ee_mode = AR5K_EEPROM_MODE_11B;
+@@ -1173,10 +1387,13 @@
+ } 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)));
++ obdb = channel->center_freq >= 5725 ? 3 :
++ (channel->center_freq >= 5500 ? 2 :
++ (channel->center_freq >= 5260 ? 1 :
++ (channel->center_freq > 4000 ? 0 : -1)));
++
++ if (obdb == -1)
++ return -EINVAL;
+
+ if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+ ee->ee_ob[ee_mode][obdb], 3, 279, 0, true))
+@@ -1209,7 +1426,8 @@
+ }
+
+ /*
+- * Initialize RF5413/5414
++ * Initialize RF5413/5414 and future chips
++ * (until we come up with a better solution)
+ */
+ static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel, unsigned int mode)
+@@ -1219,12 +1437,47 @@
+ unsigned int rf_size, i;
+ int bank = -1;
+
+- AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
++ AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX);
+
+ rf = ah->ah_rf_banks;
+
++ switch (ah->ah_radio) {
++ case AR5K_RF5413:
+ rf_ini = rfregs_5413;
+ rf_size = ARRAY_SIZE(rfregs_5413);
++ break;
++ case AR5K_RF2413:
++ rf_ini = rfregs_2413;
++ rf_size = ARRAY_SIZE(rfregs_2413);
++
++ if (mode < 2) {
++ ATH5K_ERR(ah->ah_sc,
++ "invalid channel mode: %i\n", mode);
++ return -EINVAL;
++ }
++
++ mode = mode - 2;
++ break;
++ case AR5K_RF2425:
++ rf_ini = rfregs_2425;
++ rf_size = ARRAY_SIZE(rfregs_2425);
++
++ if (mode < 2) {
++ ATH5K_ERR(ah->ah_sc,
++ "invalid channel mode: %i\n", mode);
++ return -EINVAL;
++ }
++
++ /* Map b to g */
++ if (mode == 2)
++ mode = 0;
++ else
++ mode = mode - 3;
++
++ break;
++ default:
++ return -EINVAL;
++ }
+
+ /* Copy values to modify them */
+ for (i = 0; i < rf_size; i++) {
+@@ -1283,6 +1536,14 @@
+ ah->ah_rf_banks_size = sizeof(rfregs_5413);
+ func = ath5k_hw_rf5413_rfregs;
+ break;
++ case AR5K_RF2413:
++ ah->ah_rf_banks_size = sizeof(rfregs_2413);
++ func = ath5k_hw_rf5413_rfregs;
++ break;
++ case AR5K_RF2425:
++ ah->ah_rf_banks_size = sizeof(rfregs_2425);
++ func = ath5k_hw_rf5413_rfregs;
++ break;
+ default:
+ return -EINVAL;
+ }
+@@ -1321,6 +1582,16 @@
+ ath5k_rfg = rfgain_5413;
+ size = ARRAY_SIZE(rfgain_5413);
+ break;
++ case AR5K_RF2413:
++ ath5k_rfg = rfgain_2413;
++ size = ARRAY_SIZE(rfgain_2413);
++ freq = 0; /* only 2Ghz */
++ break;
++ case AR5K_RF2425:
++ ath5k_rfg = rfgain_2413;
++ size = ARRAY_SIZE(rfgain_2413);
++ freq = 0; /* only 2Ghz */
++ break;
+ default:
+ return -EINVAL;
+ }
+@@ -1395,7 +1666,6 @@
+ 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];
+@@ -1445,9 +1715,10 @@
+ * 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;
+-
++ athchan = (ath5k_hw_bitswap(
++ (ieee80211_frequency_to_channel(
++ channel->center_freq) - 24) / 2, 5)
++ << 1) | (1 << 6) | 0x1;
+ return athchan;
+ }
+
+@@ -1506,7 +1777,8 @@
+ struct ieee80211_channel *channel)
+ {
+ struct ath5k_athchan_2ghz ath5k_channel_2ghz;
+- unsigned int ath5k_channel = channel->chan;
++ unsigned int ath5k_channel =
++ ieee80211_frequency_to_channel(channel->center_freq);
+ u32 data0, data1, clock;
+ int ret;
+
+@@ -1515,9 +1787,10 @@
+ */
+ data0 = data1 = 0;
+
+- if (channel->val & CHANNEL_2GHZ) {
++ if (channel->hw_value & CHANNEL_2GHZ) {
+ /* Map 2GHz channel to 5GHz Atheros channel ID */
+- ret = ath5k_hw_rf5111_chan2athchan(channel->chan,
++ ret = ath5k_hw_rf5111_chan2athchan(
++ ieee80211_frequency_to_channel(channel->center_freq),
+ &ath5k_channel_2ghz);
+ if (ret)
+ return ret;
+@@ -1555,7 +1828,7 @@
+ u16 c;
+
+ data = data0 = data1 = data2 = 0;
+- c = channel->freq;
++ c = channel->center_freq;
+
+ /*
+ * Set the channel on the RF5112 or newer
+@@ -1599,18 +1872,16 @@
+ 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)) {
++ * Check bounds supported by the PHY (we don't care about regultory
++ * restrictions at this point). Note: hw_value already has the band
++ * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
++ * of the band by that */
++ if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
+ ATH5K_ERR(ah->ah_sc,
+- "channel out of supported range (%u MHz)\n",
+- channel->freq);
++ "channel frequency (%u MHz) out of supported "
++ "band range\n",
++ channel->center_freq);
+ return -EINVAL;
+ }
+
+@@ -1632,9 +1903,9 @@
+ 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;
++ ah->ah_current_channel.center_freq = channel->center_freq;
++ ah->ah_current_channel.hw_value = channel->hw_value;
++ ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
+
+ return 0;
+ }
+@@ -1797,11 +2068,11 @@
+
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
+- channel->freq);
++ channel->center_freq);
+ return ret;
+ }
+
+- ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
++ ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+ if (ret)
+ return ret;
+
+@@ -1825,7 +2096,7 @@
+ s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
+ ATH5K_TRACE(ah->ah_sc);
+
+- if (ah->ah_calibration == false ||
++ if (!ah->ah_calibration ||
+ ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
+ goto done;
+
+@@ -1848,10 +2119,10 @@
+ ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+
+ done:
+- ath5k_hw_noise_floor_calibration(ah, channel->freq);
++ ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+
+ /* Request RF gain */
+- if (channel->val & CHANNEL_5GHZ) {
++ if (channel->hw_value & 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);
+@@ -2015,6 +2286,18 @@
+ return -EINVAL;
+ }
+
++ /*
++ * RF2413 for some reason can't
++ * transmit anything if we call
++ * this funtion, so we skip it
++ * until we fix txpower.
++ *
++ * XXX: Assume same for RF2425
++ * to be safe.
++ */
++ if ((ah->ah_radio == AR5K_RF2413) || (ah->ah_radio == AR5K_RF2425))
++ return 0;
++
+ /* Reset TX power values */
+ memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+ ah->ah_txpower.txp_tpc = tpc;
+@@ -2048,7 +2331,7 @@
+ 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)
++ if (ah->ah_txpower.txp_tpc)
+ ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
+ AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+ else
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/regdom.c linux-2.6.25/drivers/net/wireless/ath5k/regdom.c
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/regdom.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/regdom.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,121 +0,0 @@
+-/*
+- * Copyright (c) 2004, 2005 Reyk Floeter <reyk@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;
+-}
+-
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/regdom.h linux-2.6.25/drivers/net/wireless/ath5k/regdom.h
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/regdom.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/regdom.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,500 +0,0 @@
+-/*
+- * Copyright (c) 2004, 2005 Reyk Floeter <reyk@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 -Nbur linux-2.6.25.old/drivers/net/wireless/ath5k/reg.h linux-2.6.25/drivers/net/wireless/ath5k/reg.h
+--- linux-2.6.25.old/drivers/net/wireless/ath5k/reg.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/ath5k/reg.h 2008-04-19 13:54:59.000000000 +0200
+@@ -1923,7 +1923,9 @@
+ #define AR5K_PHY_SDELAY_32MHZ 0x000000ff
+ #define AR5K_PHY_SPENDING 0x99f8
+ #define AR5K_PHY_SPENDING_RF5111 0x00000018
+-#define AR5K_PHY_SPENDING_RF5112 0x00000014
++#define AR5K_PHY_SPENDING_RF5112 0x00000014 /* <- i 've only seen this on 2425 dumps ! */
++#define AR5K_PHY_SPENDING_RF5112A 0x0000000e /* but since i only have 5112A-based chips */
++#define AR5K_PHY_SPENDING_RF5424 0x00000012 /* to test it might be also for old 5112. */
+
+ /*
+ * Misc PHY/radio registers [5110 - 5111]
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/atmel.c linux-2.6.25/drivers/net/wireless/atmel.c
+--- linux-2.6.25.old/drivers/net/wireless/atmel.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/atmel.c 2008-04-19 13:54:59.000000000 +0200
+@@ -66,6 +66,7 @@
+ #include <linux/device.h>
+ #include <linux/moduleparam.h>
+ #include <linux/firmware.h>
++#include <linux/jiffies.h>
+ #include <net/ieee80211.h>
+ #include "atmel.h"
+
+@@ -516,7 +517,7 @@
+ SITE_SURVEY_IN_PROGRESS,
+ SITE_SURVEY_COMPLETED
+ } site_survey_state;
+- time_t last_survey;
++ unsigned long last_survey;
+
+ int station_was_associated, station_is_associated;
+ int fast_scan;
+@@ -2283,7 +2284,7 @@
+ return -EAGAIN;
+
+ /* Timeout old surveys. */
+- if ((jiffies - priv->last_survey) > (20 * HZ))
++ if (time_after(jiffies, priv->last_survey + 20 * HZ))
+ priv->site_survey_state = SITE_SURVEY_IDLE;
+ priv->last_survey = jiffies;
+
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/b43.h linux-2.6.25/drivers/net/wireless/b43/b43.h
+--- linux-2.6.25.old/drivers/net/wireless/b43/b43.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/b43.h 2008-04-19 13:54:59.000000000 +0200
+@@ -75,6 +75,23 @@
+ #define B43_MMIO_DMA64_BASE4 0x300
+ #define B43_MMIO_DMA64_BASE5 0x340
+
++/* PIO on core rev < 11 */
++#define B43_MMIO_PIO_BASE0 0x300
++#define B43_MMIO_PIO_BASE1 0x310
++#define B43_MMIO_PIO_BASE2 0x320
++#define B43_MMIO_PIO_BASE3 0x330
++#define B43_MMIO_PIO_BASE4 0x340
++#define B43_MMIO_PIO_BASE5 0x350
++#define B43_MMIO_PIO_BASE6 0x360
++#define B43_MMIO_PIO_BASE7 0x370
++/* PIO on core rev >= 11 */
++#define B43_MMIO_PIO11_BASE0 0x200
++#define B43_MMIO_PIO11_BASE1 0x240
++#define B43_MMIO_PIO11_BASE2 0x280
++#define B43_MMIO_PIO11_BASE3 0x2C0
++#define B43_MMIO_PIO11_BASE4 0x300
++#define B43_MMIO_PIO11_BASE5 0x340
++
+ #define B43_MMIO_PHY_VER 0x3E0
+ #define B43_MMIO_PHY_RADIO 0x3E2
+ #define B43_MMIO_PHY0 0x3E6
+@@ -94,11 +111,14 @@
+ #define B43_MMIO_GPIO_MASK 0x49E
+ #define B43_MMIO_TSF_CFP_START_LOW 0x604
+ #define B43_MMIO_TSF_CFP_START_HIGH 0x606
++#define B43_MMIO_TSF_CFP_PRETBTT 0x612
+ #define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */
+ #define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */
+ #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
+ #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
+ #define B43_MMIO_RNG 0x65A
++#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
++#define B43_MMIO_IFSCTL_USE_EDCF 0x0004
+ #define B43_MMIO_POWERUP_DELAY 0x6A8
+
+ /* SPROM boardflags_lo values */
+@@ -144,7 +164,8 @@
+ #define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
+ #define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
+ #define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
+-#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */
++#define B43_SHM_SH_HOSTFMI 0x0060 /* Hostflags for ucode options (middle) */
++#define B43_SHM_SH_HOSTFHI 0x0062 /* Hostflags for ucode options (high) */
+ #define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */
+ #define B43_SHM_SH_RADAR 0x0066 /* Radar register */
+ #define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
+@@ -232,31 +253,41 @@
+ #define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
+ /* HostFlags. See b43_hf_read/write() */
+-#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */
+-#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
+-#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */
+-#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */
+-#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */
+-#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */
+-#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */
+-#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */
+-#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */
+-#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */
+-#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */
+-#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */
+-#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */
+-#define B43_HF_RADARW 0x00002000 /* Radar workaround */
+-#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */
+-#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */
+-#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */
+-#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */
+-#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */
+-#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */
+-#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */
+-#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */
+-#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */
+-#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */
+-#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */
++#define B43_HF_ANTDIVHELP 0x000000000001ULL /* ucode antenna div helper */
++#define B43_HF_SYMW 0x000000000002ULL /* G-PHY SYM workaround */
++#define B43_HF_RXPULLW 0x000000000004ULL /* RX pullup workaround */
++#define B43_HF_CCKBOOST 0x000000000008ULL /* 4dB CCK power boost (exclusive with OFDM boost) */
++#define B43_HF_BTCOEX 0x000000000010ULL /* Bluetooth coexistance */
++#define B43_HF_GDCW 0x000000000020ULL /* G-PHY DC canceller filter bw workaround */
++#define B43_HF_OFDMPABOOST 0x000000000040ULL /* Enable PA gain boost for OFDM */
++#define B43_HF_ACPR 0x000000000080ULL /* Disable for Japan, channel 14 */
++#define B43_HF_EDCF 0x000000000100ULL /* on if WME and MAC suspended */
++#define B43_HF_TSSIRPSMW 0x000000000200ULL /* TSSI reset PSM ucode workaround */
++#define B43_HF_20IN40IQW 0x000000000200ULL /* 20 in 40 MHz I/Q workaround (rev >= 13 only) */
++#define B43_HF_DSCRQ 0x000000000400ULL /* Disable slow clock request in ucode */
++#define B43_HF_ACIW 0x000000000800ULL /* ACI workaround: shift bits by 2 on PHY CRS */
++#define B43_HF_2060W 0x000000001000ULL /* 2060 radio workaround */
++#define B43_HF_RADARW 0x000000002000ULL /* Radar workaround */
++#define B43_HF_USEDEFKEYS 0x000000004000ULL /* Enable use of default keys */
++#define B43_HF_AFTERBURNER 0x000000008000ULL /* Afterburner enabled */
++#define B43_HF_BT4PRIOCOEX 0x000000010000ULL /* Bluetooth 4-priority coexistance */
++#define B43_HF_FWKUP 0x000000020000ULL /* Fast wake-up ucode */
++#define B43_HF_VCORECALC 0x000000040000ULL /* Force VCO recalculation when powering up synthpu */
++#define B43_HF_PCISCW 0x000000080000ULL /* PCI slow clock workaround */
++#define B43_HF_4318TSSI 0x000000200000ULL /* 4318 TSSI */
++#define B43_HF_FBCMCFIFO 0x000000400000ULL /* Flush bcast/mcast FIFO immediately */
++#define B43_HF_HWPCTL 0x000000800000ULL /* Enable hardwarre power control */
++#define B43_HF_BTCOEXALT 0x000001000000ULL /* Bluetooth coexistance in alternate pins */
++#define B43_HF_TXBTCHECK 0x000002000000ULL /* Bluetooth check during transmission */
++#define B43_HF_SKCFPUP 0x000004000000ULL /* Skip CFP update */
++#define B43_HF_N40W 0x000008000000ULL /* N PHY 40 MHz workaround (rev >= 13 only) */
++#define B43_HF_ANTSEL 0x000020000000ULL /* Antenna selection (for testing antenna div.) */
++#define B43_HF_BT3COEXT 0x000020000000ULL /* Bluetooth 3-wire coexistence (rev >= 13 only) */
++#define B43_HF_BTCANT 0x000040000000ULL /* Bluetooth coexistence (antenna mode) (rev >= 13 only) */
++#define B43_HF_ANTSELEN 0x000100000000ULL /* Antenna selection enabled (rev >= 13 only) */
++#define B43_HF_ANTSELMODE 0x000200000000ULL /* Antenna selection mode (rev >= 13 only) */
++#define B43_HF_MLADVW 0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */
++#define B43_HF_PR45960W 0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */
+
+ /* MacFilter offsets. */
+ #define B43_MACFILTER_SELF 0x0000
+@@ -380,7 +411,6 @@
+
+ #define B43_IRQ_ALL 0xFFFFFFFF
+ #define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \
+- B43_IRQ_BEACON | \
+ B43_IRQ_TBTT_INDI | \
+ B43_IRQ_ATIM_END | \
+ B43_IRQ_PMQ | \
+@@ -429,7 +459,6 @@
+ };
+
+ struct b43_dmaring;
+-struct b43_pioqueue;
+
+ /* The firmware file header */
+ #define B43_FW_TYPE_UCODE 'u'
+@@ -458,20 +487,13 @@
+ } __attribute__((__packed__));
+
+
+-#define B43_PHYMODE(phytype) (1 << (phytype))
+-#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A)
+-#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B)
+-#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G)
+-
+ struct b43_phy {
+- /* Possible PHYMODEs on this PHY */
+- u8 possible_phymodes;
++ /* Band support flags. */
++ bool supports_2ghz;
++ bool supports_5ghz;
++
+ /* GMODE bit enabled? */
+ bool gmode;
+- /* Possible ieee80211 subsystem hwmodes for this PHY.
+- * Which mode is selected, depends on thr GMODE enabled bit */
+-#define B43_MAX_PHYHWMODES 2
+- struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
+
+ /* Analog Type */
+ u8 analog;
+@@ -583,15 +605,27 @@
+
+ /* Data structures for DMA transmission, per 80211 core. */
+ struct b43_dma {
+- struct b43_dmaring *tx_ring0;
+- struct b43_dmaring *tx_ring1;
+- struct b43_dmaring *tx_ring2;
+- struct b43_dmaring *tx_ring3;
+- struct b43_dmaring *tx_ring4;
+- struct b43_dmaring *tx_ring5;
++ struct b43_dmaring *tx_ring_AC_BK; /* Background */
++ struct b43_dmaring *tx_ring_AC_BE; /* Best Effort */
++ struct b43_dmaring *tx_ring_AC_VI; /* Video */
++ struct b43_dmaring *tx_ring_AC_VO; /* Voice */
++ struct b43_dmaring *tx_ring_mcast; /* Multicast */
++
++ struct b43_dmaring *rx_ring;
++};
++
++struct b43_pio_txqueue;
++struct b43_pio_rxqueue;
++
++/* Data structures for PIO transmission, per 80211 core. */
++struct b43_pio {
++ struct b43_pio_txqueue *tx_queue_AC_BK; /* Background */
++ struct b43_pio_txqueue *tx_queue_AC_BE; /* Best Effort */
++ struct b43_pio_txqueue *tx_queue_AC_VI; /* Video */
++ struct b43_pio_txqueue *tx_queue_AC_VO; /* Voice */
++ struct b43_pio_txqueue *tx_queue_mcast; /* Multicast */
+
+- struct b43_dmaring *rx_ring0;
+- struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */
++ struct b43_pio_rxqueue *rx_queue;
+ };
+
+ /* Context information for a noise calculation (Link Quality). */
+@@ -617,6 +651,35 @@
+ u8 algorithm;
+ };
+
++/* SHM offsets to the QOS data structures for the 4 different queues. */
++#define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \
++ (B43_NR_QOSPARAMS * sizeof(u16) * (queue)))
++#define B43_QOS_BACKGROUND B43_QOS_PARAMS(0)
++#define B43_QOS_BESTEFFORT B43_QOS_PARAMS(1)
++#define B43_QOS_VIDEO B43_QOS_PARAMS(2)
++#define B43_QOS_VOICE B43_QOS_PARAMS(3)
++
++/* QOS parameter hardware data structure offsets. */
++#define B43_NR_QOSPARAMS 22
++enum {
++ B43_QOSPARAM_TXOP = 0,
++ B43_QOSPARAM_CWMIN,
++ B43_QOSPARAM_CWMAX,
++ B43_QOSPARAM_CWCUR,
++ B43_QOSPARAM_AIFS,
++ B43_QOSPARAM_BSLOTS,
++ B43_QOSPARAM_REGGAP,
++ B43_QOSPARAM_STATUS,
++};
++
++/* QOS parameters for a queue. */
++struct b43_qos_params {
++ /* The QOS parameters */
++ struct ieee80211_tx_queue_params p;
++ /* Does this need to get uploaded to hardware? */
++ bool need_hw_update;
++};
++
+ struct b43_wldev;
+
+ /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
+@@ -667,8 +730,16 @@
+ /* The beacon we are currently using (AP or IBSS mode).
+ * This beacon stuff is protected by the irq_lock. */
+ struct sk_buff *current_beacon;
++ struct ieee80211_tx_control beacon_txctl;
+ bool beacon0_uploaded;
+ bool beacon1_uploaded;
++ struct work_struct beacon_update_trigger;
++
++ /* The current QOS parameters for the 4 queues.
++ * This is protected by the irq_lock. */
++ struct b43_qos_params qos_params[4];
++ /* Workqueue for updating QOS parameters in hardware. */
++ struct work_struct qos_update_work;
+ };
+
+ /* In-memory representation of a cached microcode file. */
+@@ -727,7 +798,6 @@
+
+ bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
+ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
+- bool short_preamble; /* TRUE, if short preamble is enabled. */
+ bool short_slot; /* TRUE, if short slot timing is enabled. */
+ bool radio_hw_enable; /* saved state of radio hardware enabled state */
+ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
+@@ -735,8 +805,15 @@
+ /* PHY/Radio device. */
+ struct b43_phy phy;
+
++ union {
+ /* DMA engines. */
+ struct b43_dma dma;
++ /* PIO engines. */
++ struct b43_pio pio;
++ };
++ /* Use b43_using_pio_transfers() to check whether we are using
++ * DMA or PIO data transfers. */
++ bool __using_pio_transfers;
+
+ /* Various statistics about the physical device. */
+ struct b43_stats stats;
+@@ -820,6 +897,22 @@
+ ssb_write32(dev->dev, offset, value);
+ }
+
++static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
++{
++#ifdef CONFIG_B43_PIO
++ return dev->__using_pio_transfers;
++#else
++ return 0;
++#endif
++}
++
++#ifdef CONFIG_B43_FORCE_PIO
++# define B43_FORCE_PIO 1
++#else
++# define B43_FORCE_PIO 0
++#endif
++
++
+ /* Message printing */
+ void b43info(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/dma.c linux-2.6.25/drivers/net/wireless/b43/dma.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/dma.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/dma.c 2008-04-19 16:24:28.000000000 +0200
+@@ -38,6 +38,7 @@
+ #include <linux/delay.h>
+ #include <linux/skbuff.h>
+ #include <linux/etherdevice.h>
++#include <asm/div64.h>
+
+
+ /* 32bit DMA ops. */
+@@ -291,52 +292,6 @@
+ return slot;
+ }
+
+-/* Mac80211-queue to b43-ring mapping */
+-static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
+- int queue_priority)
+-{
+- struct b43_dmaring *ring;
+-
+-/*FIXME: For now we always run on TX-ring-1 */
+- return dev->dma.tx_ring1;
+-
+- /* 0 = highest priority */
+- switch (queue_priority) {
+- default:
+- B43_WARN_ON(1);
+- /* fallthrough */
+- case 0:
+- ring = dev->dma.tx_ring3;
+- break;
+- case 1:
+- ring = dev->dma.tx_ring2;
+- break;
+- case 2:
+- ring = dev->dma.tx_ring1;
+- break;
+- case 3:
+- ring = dev->dma.tx_ring0;
+- break;
+- }
+-
+- return ring;
+-}
+-
+-/* b43-ring to mac80211-queue mapping */
+-static inline int txring_to_priority(struct b43_dmaring *ring)
+-{
+- static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
+- unsigned int index;
+-
+-/*FIXME: have only one queue, for now */
+- return 0;
+-
+- index = ring->index;
+- if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
+- index = 0;
+- return idx_to_prio[index];
+-}
+-
+ static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
+ {
+ static const u16 map64[] = {
+@@ -596,7 +551,6 @@
+ struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
+ {
+ struct b43_rxhdr_fw4 *rxhdr;
+- struct b43_hwtxstatus *txstat;
+ dma_addr_t dmaaddr;
+ struct sk_buff *skb;
+
+@@ -632,8 +586,6 @@
+
+ rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
+ rxhdr->frame_len = 0;
+- txstat = (struct b43_hwtxstatus *)(skb->data);
+- txstat->cookie = 0;
+
+ return 0;
+ }
+@@ -822,6 +774,18 @@
+ return DMA_30BIT_MASK;
+ }
+
++static enum b43_dmatype dma_mask_to_engine_type(u64 dmamask)
++{
++ if (dmamask == DMA_30BIT_MASK)
++ return B43_DMA_30BIT;
++ if (dmamask == DMA_32BIT_MASK)
++ return B43_DMA_32BIT;
++ if (dmamask == DMA_64BIT_MASK)
++ return B43_DMA_64BIT;
++ B43_WARN_ON(1);
++ return B43_DMA_30BIT;
++}
++
+ /* Main initialization function. */
+ static
+ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
+@@ -937,16 +901,52 @@
+ goto out;
+ }
+
++#define divide(a, b) ({ \
++ typeof(a) __a = a; \
++ do_div(__a, b); \
++ __a; \
++ })
++
++#define modulo(a, b) ({ \
++ typeof(a) __a = a; \
++ do_div(__a, b); \
++ })
++
+ /* Main cleanup function. */
+-static void b43_destroy_dmaring(struct b43_dmaring *ring)
++static void b43_destroy_dmaring(struct b43_dmaring *ring,
++ const char *ringname)
+ {
+ if (!ring)
+ return;
+
+- b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
+- (unsigned int)(ring->type),
+- ring->mmio_base,
+- (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
++#ifdef CONFIG_B43_DEBUG
++ {
++ /* Print some statistics. */
++ u64 failed_packets = ring->nr_failed_tx_packets;
++ u64 succeed_packets = ring->nr_succeed_tx_packets;
++ u64 nr_packets = failed_packets + succeed_packets;
++ u64 permille_failed = 0, average_tries = 0;
++
++ if (nr_packets)
++ permille_failed = divide(failed_packets * 1000, nr_packets);
++ if (nr_packets)
++ average_tries = divide(ring->nr_total_packet_tries * 100, nr_packets);
++
++ b43dbg(ring->dev->wl, "DMA-%u %s: "
++ "Used slots %d/%d, Failed frames %llu/%llu = %llu.%01llu%%, "
++ "Average tries %llu.%02llu\n",
++ (unsigned int)(ring->type), ringname,
++ ring->max_used_slots,
++ ring->nr_slots,
++ (unsigned long long)failed_packets,
++ (unsigned long long)nr_packets,
++ (unsigned long long)divide(permille_failed, 10),
++ (unsigned long long)modulo(permille_failed, 10),
++ (unsigned long long)divide(average_tries, 100),
++ (unsigned long long)modulo(average_tries, 100));
++ }
++#endif /* DEBUG */
++
+ /* Device IRQs are disabled prior entering this function,
+ * so no need to take care of concurrency with rx handler stuff.
+ */
+@@ -959,51 +959,36 @@
+ kfree(ring);
+ }
+
++#define destroy_ring(dma, ring) do { \
++ b43_destroy_dmaring((dma)->ring, __stringify(ring)); \
++ (dma)->ring = NULL; \
++ } while (0)
++
+ void b43_dma_free(struct b43_wldev *dev)
+ {
+- struct b43_dma *dma = &dev->dma;
++ struct b43_dma *dma;
+
+- b43_destroy_dmaring(dma->rx_ring3);
+- dma->rx_ring3 = NULL;
+- b43_destroy_dmaring(dma->rx_ring0);
+- dma->rx_ring0 = NULL;
+-
+- b43_destroy_dmaring(dma->tx_ring5);
+- dma->tx_ring5 = NULL;
+- b43_destroy_dmaring(dma->tx_ring4);
+- dma->tx_ring4 = NULL;
+- b43_destroy_dmaring(dma->tx_ring3);
+- dma->tx_ring3 = NULL;
+- b43_destroy_dmaring(dma->tx_ring2);
+- dma->tx_ring2 = NULL;
+- b43_destroy_dmaring(dma->tx_ring1);
+- dma->tx_ring1 = NULL;
+- b43_destroy_dmaring(dma->tx_ring0);
+- dma->tx_ring0 = NULL;
++ if (b43_using_pio_transfers(dev))
++ return;
++ dma = &dev->dma;
++
++ destroy_ring(dma, rx_ring);
++ destroy_ring(dma, tx_ring_AC_BK);
++ destroy_ring(dma, tx_ring_AC_BE);
++ destroy_ring(dma, tx_ring_AC_VI);
++ destroy_ring(dma, tx_ring_AC_VO);
++ destroy_ring(dma, tx_ring_mcast);
+ }
+
+ int b43_dma_init(struct b43_wldev *dev)
+ {
+ struct b43_dma *dma = &dev->dma;
+- struct b43_dmaring *ring;
+ int err;
+ u64 dmamask;
+ enum b43_dmatype type;
+
+ dmamask = supported_dma_mask(dev);
+- switch (dmamask) {
+- default:
+- B43_WARN_ON(1);
+- case DMA_30BIT_MASK:
+- type = B43_DMA_30BIT;
+- break;
+- case DMA_32BIT_MASK:
+- type = B43_DMA_32BIT;
+- break;
+- case DMA_64BIT_MASK:
+- type = B43_DMA_64BIT;
+- break;
+- }
++ type = dma_mask_to_engine_type(dmamask);
+ err = ssb_dma_set_mask(dev->dev, dmamask);
+ if (err) {
+ b43err(dev->wl, "The machine/kernel does not support "
+@@ -1015,83 +1000,57 @@
+
+ err = -ENOMEM;
+ /* setup TX DMA channels. */
+- ring = b43_setup_dmaring(dev, 0, 1, type);
+- if (!ring)
++ dma->tx_ring_AC_BK = b43_setup_dmaring(dev, 0, 1, type);
++ if (!dma->tx_ring_AC_BK)
+ goto out;
+- dma->tx_ring0 = ring;
+-
+- ring = b43_setup_dmaring(dev, 1, 1, type);
+- if (!ring)
+- goto err_destroy_tx0;
+- dma->tx_ring1 = ring;
+-
+- ring = b43_setup_dmaring(dev, 2, 1, type);
+- if (!ring)
+- goto err_destroy_tx1;
+- dma->tx_ring2 = ring;
+
+- ring = b43_setup_dmaring(dev, 3, 1, type);
+- if (!ring)
+- goto err_destroy_tx2;
+- dma->tx_ring3 = ring;
++ dma->tx_ring_AC_BE = b43_setup_dmaring(dev, 1, 1, type);
++ if (!dma->tx_ring_AC_BE)
++ goto err_destroy_bk;
++
++ dma->tx_ring_AC_VI = b43_setup_dmaring(dev, 2, 1, type);
++ if (!dma->tx_ring_AC_VI)
++ goto err_destroy_be;
++
++ dma->tx_ring_AC_VO = b43_setup_dmaring(dev, 3, 1, type);
++ if (!dma->tx_ring_AC_VO)
++ goto err_destroy_vi;
++
++ dma->tx_ring_mcast = b43_setup_dmaring(dev, 4, 1, type);
++ if (!dma->tx_ring_mcast)
++ goto err_destroy_vo;
++
++ /* setup RX DMA channel. */
++ dma->rx_ring = b43_setup_dmaring(dev, 0, 0, type);
++ if (!dma->rx_ring)
++ goto err_destroy_mcast;
+
+- ring = b43_setup_dmaring(dev, 4, 1, type);
+- if (!ring)
+- goto err_destroy_tx3;
+- dma->tx_ring4 = ring;
+-
+- ring = b43_setup_dmaring(dev, 5, 1, type);
+- if (!ring)
+- goto err_destroy_tx4;
+- dma->tx_ring5 = ring;
+-
+- /* setup RX DMA channels. */
+- ring = b43_setup_dmaring(dev, 0, 0, type);
+- if (!ring)
+- goto err_destroy_tx5;
+- dma->rx_ring0 = ring;
+-
+- if (dev->dev->id.revision < 5) {
+- ring = b43_setup_dmaring(dev, 3, 0, type);
+- if (!ring)
+- goto err_destroy_rx0;
+- dma->rx_ring3 = ring;
+- }
++ /* No support for the TX status DMA ring. */
++ B43_WARN_ON(dev->dev->id.revision < 5);
+
+ b43dbg(dev->wl, "%u-bit DMA initialized\n",
+ (unsigned int)type);
+ err = 0;
+- out:
++out:
+ return err;
+
+- err_destroy_rx0:
+- b43_destroy_dmaring(dma->rx_ring0);
+- dma->rx_ring0 = NULL;
+- err_destroy_tx5:
+- b43_destroy_dmaring(dma->tx_ring5);
+- dma->tx_ring5 = NULL;
+- err_destroy_tx4:
+- b43_destroy_dmaring(dma->tx_ring4);
+- dma->tx_ring4 = NULL;
+- err_destroy_tx3:
+- b43_destroy_dmaring(dma->tx_ring3);
+- dma->tx_ring3 = NULL;
+- err_destroy_tx2:
+- b43_destroy_dmaring(dma->tx_ring2);
+- dma->tx_ring2 = NULL;
+- err_destroy_tx1:
+- b43_destroy_dmaring(dma->tx_ring1);
+- dma->tx_ring1 = NULL;
+- err_destroy_tx0:
+- b43_destroy_dmaring(dma->tx_ring0);
+- dma->tx_ring0 = NULL;
+- goto out;
++err_destroy_mcast:
++ destroy_ring(dma, tx_ring_mcast);
++err_destroy_vo:
++ destroy_ring(dma, tx_ring_AC_VO);
++err_destroy_vi:
++ destroy_ring(dma, tx_ring_AC_VI);
++err_destroy_be:
++ destroy_ring(dma, tx_ring_AC_BE);
++err_destroy_bk:
++ destroy_ring(dma, tx_ring_AC_BK);
++ return err;
+ }
+
+ /* Generate a cookie for the TX header. */
+ static u16 generate_cookie(struct b43_dmaring *ring, int slot)
+ {
+- u16 cookie = 0x1000;
++ u16 cookie;
+
+ /* Use the upper 4 bits of the cookie as
+ * DMA controller ID and store the slot number
+@@ -1101,30 +1060,9 @@
+ * It can also not be 0xFFFF because that is special
+ * for multicast frames.
+ */
+- switch (ring->index) {
+- case 0:
+- cookie = 0x1000;
+- break;
+- case 1:
+- cookie = 0x2000;
+- break;
+- case 2:
+- cookie = 0x3000;
+- break;
+- case 3:
+- cookie = 0x4000;
+- break;
+- case 4:
+- cookie = 0x5000;
+- break;
+- case 5:
+- cookie = 0x6000;
+- break;
+- default:
+- B43_WARN_ON(1);
+- }
++ cookie = (((u16)ring->index + 1) << 12);
+ B43_WARN_ON(slot & ~0x0FFF);
+- cookie |= (u16) slot;
++ cookie |= (u16)slot;
+
+ return cookie;
+ }
+@@ -1138,22 +1076,19 @@
+
+ switch (cookie & 0xF000) {
+ case 0x1000:
+- ring = dma->tx_ring0;
++ ring = dma->tx_ring_AC_BK;
+ break;
+ case 0x2000:
+- ring = dma->tx_ring1;
++ ring = dma->tx_ring_AC_BE;
+ break;
+ case 0x3000:
+- ring = dma->tx_ring2;
++ ring = dma->tx_ring_AC_VI;
+ break;
+ case 0x4000:
+- ring = dma->tx_ring3;
++ ring = dma->tx_ring_AC_VO;
+ break;
+ case 0x5000:
+- ring = dma->tx_ring4;
+- break;
+- case 0x6000:
+- ring = dma->tx_ring5;
++ ring = dma->tx_ring_mcast;
+ break;
+ default:
+ B43_WARN_ON(1);
+@@ -1180,7 +1115,6 @@
+ size_t hdrsize = b43_txhdr_size(ring->dev);
+
+ #define SLOTS_PER_PACKET 2
+- B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+
+ old_top_slot = ring->current_slot;
+ old_used_slots = ring->used_slots;
+@@ -1285,6 +1219,37 @@
+ return 0;
+ }
+
++/* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */
++static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev,
++ u8 queue_prio)
++{
++ struct b43_dmaring *ring;
++
++ if (b43_modparam_qos) {
++ /* 0 = highest priority */
++ switch (queue_prio) {
++ default:
++ B43_WARN_ON(1);
++ /* fallthrough */
++ case 0:
++ ring = dev->dma.tx_ring_AC_VO;
++ break;
++ case 1:
++ ring = dev->dma.tx_ring_AC_VI;
++ break;
++ case 2:
++ ring = dev->dma.tx_ring_AC_BE;
++ break;
++ case 3:
++ ring = dev->dma.tx_ring_AC_BK;
++ break;
++ }
++ } else
++ ring = dev->dma.tx_ring_AC_BE;
++
++ return ring;
++}
++
+ int b43_dma_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+ {
+@@ -1293,21 +1258,16 @@
+ int err = 0;
+ unsigned long flags;
+
+- if (unlikely(skb->len < 2 + 2 + 6)) {
+- /* Too short, this can't be a valid frame. */
+- return -EINVAL;
+- }
+-
+ hdr = (struct ieee80211_hdr *)skb->data;
+ if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+ /* The multicast ring will be sent after the DTIM */
+- ring = dev->dma.tx_ring4;
++ ring = dev->dma.tx_ring_mcast;
+ /* Set the more-data bit. Ucode will clear it on
+ * the last frame for us. */
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+ } else {
+ /* Decide by priority where to put this frame. */
+- ring = priority_to_txring(dev, ctl->queue);
++ ring = select_ring_by_priority(dev, ctl->queue);
+ }
+
+ spin_lock_irqsave(&ring->lock, flags);
+@@ -1322,6 +1282,11 @@
+ * That would be a mac80211 bug. */
+ B43_WARN_ON(ring->stopped);
+
++ /* Assign the queue number to the ring (if not already done before)
++ * so TX status handling can use it. The queue to ring mapping is
++ * static, so we don't need to store it per frame. */
++ ring->queue_prio = ctl->queue;
++
+ err = dma_tx_fragment(ring, skb, ctl);
+ if (unlikely(err == -ENOKEY)) {
+ /* Drop this packet, as we don't have the encryption key
+@@ -1338,7 +1303,7 @@
+ if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+ should_inject_overflow(ring)) {
+ /* This TX ring is full. */
+- ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
++ ieee80211_stop_queue(dev->wl->hw, ctl->queue);
+ ring->stopped = 1;
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
+@@ -1359,6 +1324,7 @@
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ int slot;
++ bool frame_succeed;
+
+ ring = parse_cookie(dev, status->cookie, &slot);
+ if (unlikely(!ring))
+@@ -1385,18 +1351,15 @@
+ * status of the transmission.
+ * Some fields of txstat are already filled in dma_tx().
+ */
+- if (status->acked) {
+- meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+- } else {
+- if (!(meta->txstat.control.flags
+- & IEEE80211_TXCTL_NO_ACK))
+- meta->txstat.excessive_retries = 1;
+- }
+- if (status->frame_count == 0) {
+- /* The frame was not transmitted at all. */
+- meta->txstat.retry_count = 0;
+- } else
+- meta->txstat.retry_count = status->frame_count - 1;
++ frame_succeed = b43_fill_txstatus_report(
++ &(meta->txstat), status);
++#ifdef CONFIG_B43_DEBUG
++ if (frame_succeed)
++ ring->nr_succeed_tx_packets++;
++ else
++ ring->nr_failed_tx_packets++;
++ ring->nr_total_packet_tries += status->frame_count;
++#endif /* DEBUG */
+ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
+ &(meta->txstat));
+ /* skb is freed by ieee80211_tx_status_irqsafe() */
+@@ -1418,7 +1381,7 @@
+ dev->stats.last_tx = jiffies;
+ if (ring->stopped) {
+ B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+- ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
++ ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
+ ring->stopped = 0;
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
+@@ -1439,7 +1402,7 @@
+
+ for (i = 0; i < nr_queues; i++) {
+ data = &(stats->data[i]);
+- ring = priority_to_txring(dev, i);
++ ring = select_ring_by_priority(dev, i);
+
+ spin_lock_irqsave(&ring->lock, flags);
+ data->len = ring->used_slots / SLOTS_PER_PACKET;
+@@ -1465,25 +1428,6 @@
+ sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+ skb = meta->skb;
+
+- if (ring->index == 3) {
+- /* We received an xmit status. */
+- struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data;
+- int i = 0;
+-
+- while (hw->cookie == 0) {
+- if (i > 100)
+- break;
+- i++;
+- udelay(2);
+- barrier();
+- }
+- b43_handle_hwtxstatus(ring->dev, hw);
+- /* recycle the descriptor buffer. */
+- sync_descbuffer_for_device(ring, meta->dmaaddr,
+- ring->rx_buffersize);
+-
+- return;
+- }
+ rxhdr = (struct b43_rxhdr_fw4 *)skb->data;
+ len = le16_to_cpu(rxhdr->frame_len);
+ if (len == 0) {
+@@ -1540,7 +1484,7 @@
+ skb_pull(skb, ring->frameoffset);
+
+ b43_rx(ring->dev, skb, rxhdr);
+- drop:
++drop:
+ return;
+ }
+
+@@ -1586,21 +1530,55 @@
+ void b43_dma_tx_suspend(struct b43_wldev *dev)
+ {
+ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+- b43_dma_tx_suspend_ring(dev->dma.tx_ring0);
+- b43_dma_tx_suspend_ring(dev->dma.tx_ring1);
+- b43_dma_tx_suspend_ring(dev->dma.tx_ring2);
+- b43_dma_tx_suspend_ring(dev->dma.tx_ring3);
+- b43_dma_tx_suspend_ring(dev->dma.tx_ring4);
+- b43_dma_tx_suspend_ring(dev->dma.tx_ring5);
++ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BK);
++ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BE);
++ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VI);
++ b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VO);
++ b43_dma_tx_suspend_ring(dev->dma.tx_ring_mcast);
+ }
+
+ void b43_dma_tx_resume(struct b43_wldev *dev)
+ {
+- b43_dma_tx_resume_ring(dev->dma.tx_ring5);
+- b43_dma_tx_resume_ring(dev->dma.tx_ring4);
+- b43_dma_tx_resume_ring(dev->dma.tx_ring3);
+- b43_dma_tx_resume_ring(dev->dma.tx_ring2);
+- b43_dma_tx_resume_ring(dev->dma.tx_ring1);
+- b43_dma_tx_resume_ring(dev->dma.tx_ring0);
++ b43_dma_tx_resume_ring(dev->dma.tx_ring_mcast);
++ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VO);
++ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VI);
++ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BE);
++ b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BK);
+ b43_power_saving_ctl_bits(dev, 0);
+ }
++
++#ifdef CONFIG_B43_PIO
++static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type,
++ u16 mmio_base, bool enable)
++{
++ u32 ctl;
++
++ if (type == B43_DMA_64BIT) {
++ ctl = b43_read32(dev, mmio_base + B43_DMA64_RXCTL);
++ ctl &= ~B43_DMA64_RXDIRECTFIFO;
++ if (enable)
++ ctl |= B43_DMA64_RXDIRECTFIFO;
++ b43_write32(dev, mmio_base + B43_DMA64_RXCTL, ctl);
++ } else {
++ ctl = b43_read32(dev, mmio_base + B43_DMA32_RXCTL);
++ ctl &= ~B43_DMA32_RXDIRECTFIFO;
++ if (enable)
++ ctl |= B43_DMA32_RXDIRECTFIFO;
++ b43_write32(dev, mmio_base + B43_DMA32_RXCTL, ctl);
++ }
++}
++
++/* Enable/Disable Direct FIFO Receive Mode (PIO) on a RX engine.
++ * This is called from PIO code, so DMA structures are not available. */
++void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
++ unsigned int engine_index, bool enable)
++{
++ enum b43_dmatype type;
++ u16 mmio_base;
++
++ type = dma_mask_to_engine_type(supported_dma_mask(dev));
++
++ mmio_base = b43_dmacontroller_base(type, engine_index);
++ direct_fifo_rx(dev, type, mmio_base, enable);
++}
++#endif /* CONFIG_B43_PIO */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/dma.h linux-2.6.25/drivers/net/wireless/b43/dma.h
+--- linux-2.6.25.old/drivers/net/wireless/b43/dma.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/dma.h 2008-04-19 13:54:59.000000000 +0200
+@@ -245,6 +245,9 @@
+ enum b43_dmatype type;
+ /* Boolean. Is this ring stopped at ieee80211 level? */
+ bool stopped;
++ /* The QOS priority assigned to this ring. Only used for TX rings.
++ * This is the mac80211 "queue" value. */
++ u8 queue_prio;
+ /* Lock, only used for TX. */
+ spinlock_t lock;
+ struct b43_wldev *dev;
+@@ -253,6 +256,12 @@
+ int max_used_slots;
+ /* Last time we injected a ring overflow. */
+ unsigned long last_injected_overflow;
++ /* Statistics: Number of successfully transmitted packets */
++ u64 nr_succeed_tx_packets;
++ /* Statistics: Number of failed TX packets */
++ u64 nr_failed_tx_packets;
++ /* Statistics: Total number of TX plus all retries. */
++ u64 nr_total_packet_tries;
+ #endif /* CONFIG_B43_DEBUG */
+ };
+
+@@ -282,4 +291,7 @@
+
+ void b43_dma_rx(struct b43_dmaring *ring);
+
++void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
++ unsigned int engine_index, bool enable);
++
+ #endif /* B43_DMA_H_ */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/Kconfig linux-2.6.25/drivers/net/wireless/b43/Kconfig
+--- linux-2.6.25.old/drivers/net/wireless/b43/Kconfig 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/Kconfig 2008-04-19 13:54:59.000000000 +0200
+@@ -62,6 +62,14 @@
+
+ If unsure, say N.
+
++# Data transfers to the device via PIO
++# This is only needed on PCMCIA devices. All others can do DMA properly.
++config B43_PIO
++ bool
++ depends on B43 && (B43_PCMCIA || B43_FORCE_PIO)
++ select SSB_BLOCKIO
++ default y
++
+ config B43_NPHY
+ bool "Pre IEEE 802.11n support (BROKEN)"
+ depends on B43 && EXPERIMENTAL && BROKEN
+@@ -94,3 +102,13 @@
+
+ Say Y, if you want to find out why the driver does not
+ work for you.
++
++config B43_FORCE_PIO
++ bool "Force usage of PIO instead of DMA"
++ depends on B43 && B43_DEBUG
++ ---help---
++ This will disable DMA and always enable PIO instead.
++
++ Say N!
++ This is only for debugging the PIO engine code. You do
++ _NOT_ want to enable this.
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/main.c linux-2.6.25/drivers/net/wireless/b43/main.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/main.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/main.c 2008-04-19 13:54:59.000000000 +0200
+@@ -46,7 +46,9 @@
+ #include "main.h"
+ #include "debugfs.h"
+ #include "phy.h"
++#include "nphy.h"
+ #include "dma.h"
++#include "pio.h"
+ #include "sysfs.h"
+ #include "xmit.h"
+ #include "lo.h"
+@@ -78,6 +80,11 @@
+ module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
++int b43_modparam_qos = 1;
++module_param_named(qos, b43_modparam_qos, int, 0444);
++MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
++
++
+ static const struct ssb_device_id b43_ssb_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
+@@ -97,24 +104,28 @@
+ * get concurrency issues */
+ #define RATETAB_ENT(_rateid, _flags) \
+ { \
+- .rate = B43_RATE_TO_BASE100KBPS(_rateid), \
+- .val = (_rateid), \
+- .val2 = (_rateid), \
++ .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \
++ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
++
++/*
++ * NOTE: When changing this, sync with xmit.c's
++ * b43_plcp_get_bitrate_idx_* functions!
++ */
+ static struct ieee80211_rate __b43_ratetable[] = {
+- RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+- RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+- RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+- RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+- RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
++ RATETAB_ENT(B43_CCK_RATE_1MB, 0),
++ RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
++ RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
++ RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
++ RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
++ RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
++ RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
++ RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
++ RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
++ RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
++ RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
++ RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
+ };
+
+ #define b43_a_ratetable (__b43_ratetable + 4)
+@@ -124,53 +135,144 @@
+ #define b43_g_ratetable (__b43_ratetable + 0)
+ #define b43_g_ratetable_size 12
+
+-#define CHANTAB_ENT(_chanid, _freq) \
+- { \
+- .chan = (_chanid), \
+- .freq = (_freq), \
+- .val = (_chanid), \
+- .flag = IEEE80211_CHAN_W_SCAN | \
+- IEEE80211_CHAN_W_ACTIVE_SCAN | \
+- IEEE80211_CHAN_W_IBSS, \
+- .power_level = 0xFF, \
+- .antenna_max = 0xFF, \
+- }
++#define CHAN4G(_channel, _freq, _flags) { \
++ .band = IEEE80211_BAND_2GHZ, \
++ .center_freq = (_freq), \
++ .hw_value = (_channel), \
++ .flags = (_flags), \
++ .max_antenna_gain = 0, \
++ .max_power = 30, \
++}
+ static struct ieee80211_channel b43_2ghz_chantable[] = {
+- CHANTAB_ENT(1, 2412),
+- CHANTAB_ENT(2, 2417),
+- CHANTAB_ENT(3, 2422),
+- CHANTAB_ENT(4, 2427),
+- CHANTAB_ENT(5, 2432),
+- CHANTAB_ENT(6, 2437),
+- CHANTAB_ENT(7, 2442),
+- CHANTAB_ENT(8, 2447),
+- CHANTAB_ENT(9, 2452),
+- CHANTAB_ENT(10, 2457),
+- CHANTAB_ENT(11, 2462),
+- CHANTAB_ENT(12, 2467),
+- CHANTAB_ENT(13, 2472),
+- CHANTAB_ENT(14, 2484),
++ CHAN4G(1, 2412, 0),
++ CHAN4G(2, 2417, 0),
++ CHAN4G(3, 2422, 0),
++ CHAN4G(4, 2427, 0),
++ CHAN4G(5, 2432, 0),
++ CHAN4G(6, 2437, 0),
++ CHAN4G(7, 2442, 0),
++ CHAN4G(8, 2447, 0),
++ CHAN4G(9, 2452, 0),
++ CHAN4G(10, 2457, 0),
++ CHAN4G(11, 2462, 0),
++ CHAN4G(12, 2467, 0),
++ CHAN4G(13, 2472, 0),
++ CHAN4G(14, 2484, 0),
++};
++#undef CHAN4G
++
++#define CHAN5G(_channel, _flags) { \
++ .band = IEEE80211_BAND_5GHZ, \
++ .center_freq = 5000 + (5 * (_channel)), \
++ .hw_value = (_channel), \
++ .flags = (_flags), \
++ .max_antenna_gain = 0, \
++ .max_power = 30, \
++}
++static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
++ CHAN5G(32, 0), CHAN5G(34, 0),
++ CHAN5G(36, 0), CHAN5G(38, 0),
++ CHAN5G(40, 0), CHAN5G(42, 0),
++ CHAN5G(44, 0), CHAN5G(46, 0),
++ CHAN5G(48, 0), CHAN5G(50, 0),
++ CHAN5G(52, 0), CHAN5G(54, 0),
++ CHAN5G(56, 0), CHAN5G(58, 0),
++ CHAN5G(60, 0), CHAN5G(62, 0),
++ CHAN5G(64, 0), CHAN5G(66, 0),
++ CHAN5G(68, 0), CHAN5G(70, 0),
++ CHAN5G(72, 0), CHAN5G(74, 0),
++ CHAN5G(76, 0), CHAN5G(78, 0),
++ CHAN5G(80, 0), CHAN5G(82, 0),
++ CHAN5G(84, 0), CHAN5G(86, 0),
++ CHAN5G(88, 0), CHAN5G(90, 0),
++ CHAN5G(92, 0), CHAN5G(94, 0),
++ CHAN5G(96, 0), CHAN5G(98, 0),
++ CHAN5G(100, 0), CHAN5G(102, 0),
++ CHAN5G(104, 0), CHAN5G(106, 0),
++ CHAN5G(108, 0), CHAN5G(110, 0),
++ CHAN5G(112, 0), CHAN5G(114, 0),
++ CHAN5G(116, 0), CHAN5G(118, 0),
++ CHAN5G(120, 0), CHAN5G(122, 0),
++ CHAN5G(124, 0), CHAN5G(126, 0),
++ CHAN5G(128, 0), CHAN5G(130, 0),
++ CHAN5G(132, 0), CHAN5G(134, 0),
++ CHAN5G(136, 0), CHAN5G(138, 0),
++ CHAN5G(140, 0), CHAN5G(142, 0),
++ CHAN5G(144, 0), CHAN5G(145, 0),
++ CHAN5G(146, 0), CHAN5G(147, 0),
++ CHAN5G(148, 0), CHAN5G(149, 0),
++ CHAN5G(150, 0), CHAN5G(151, 0),
++ CHAN5G(152, 0), CHAN5G(153, 0),
++ CHAN5G(154, 0), CHAN5G(155, 0),
++ CHAN5G(156, 0), CHAN5G(157, 0),
++ CHAN5G(158, 0), CHAN5G(159, 0),
++ CHAN5G(160, 0), CHAN5G(161, 0),
++ CHAN5G(162, 0), CHAN5G(163, 0),
++ CHAN5G(164, 0), CHAN5G(165, 0),
++ CHAN5G(166, 0), CHAN5G(168, 0),
++ CHAN5G(170, 0), CHAN5G(172, 0),
++ CHAN5G(174, 0), CHAN5G(176, 0),
++ CHAN5G(178, 0), CHAN5G(180, 0),
++ CHAN5G(182, 0), CHAN5G(184, 0),
++ CHAN5G(186, 0), CHAN5G(188, 0),
++ CHAN5G(190, 0), CHAN5G(192, 0),
++ CHAN5G(194, 0), CHAN5G(196, 0),
++ CHAN5G(198, 0), CHAN5G(200, 0),
++ CHAN5G(202, 0), CHAN5G(204, 0),
++ CHAN5G(206, 0), CHAN5G(208, 0),
++ CHAN5G(210, 0), CHAN5G(212, 0),
++ CHAN5G(214, 0), CHAN5G(216, 0),
++ CHAN5G(218, 0), CHAN5G(220, 0),
++ CHAN5G(222, 0), CHAN5G(224, 0),
++ CHAN5G(226, 0), CHAN5G(228, 0),
+ };
+-#define b43_2ghz_chantable_size ARRAY_SIZE(b43_2ghz_chantable)
+
+-#if 0
+-static struct ieee80211_channel b43_5ghz_chantable[] = {
+- CHANTAB_ENT(36, 5180),
+- CHANTAB_ENT(40, 5200),
+- CHANTAB_ENT(44, 5220),
+- CHANTAB_ENT(48, 5240),
+- CHANTAB_ENT(52, 5260),
+- CHANTAB_ENT(56, 5280),
+- CHANTAB_ENT(60, 5300),
+- CHANTAB_ENT(64, 5320),
+- CHANTAB_ENT(149, 5745),
+- CHANTAB_ENT(153, 5765),
+- CHANTAB_ENT(157, 5785),
+- CHANTAB_ENT(161, 5805),
+- CHANTAB_ENT(165, 5825),
++static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
++ CHAN5G(34, 0), CHAN5G(36, 0),
++ CHAN5G(38, 0), CHAN5G(40, 0),
++ CHAN5G(42, 0), CHAN5G(44, 0),
++ CHAN5G(46, 0), CHAN5G(48, 0),
++ CHAN5G(52, 0), CHAN5G(56, 0),
++ CHAN5G(60, 0), CHAN5G(64, 0),
++ CHAN5G(100, 0), CHAN5G(104, 0),
++ CHAN5G(108, 0), CHAN5G(112, 0),
++ CHAN5G(116, 0), CHAN5G(120, 0),
++ CHAN5G(124, 0), CHAN5G(128, 0),
++ CHAN5G(132, 0), CHAN5G(136, 0),
++ CHAN5G(140, 0), CHAN5G(149, 0),
++ CHAN5G(153, 0), CHAN5G(157, 0),
++ CHAN5G(161, 0), CHAN5G(165, 0),
++ CHAN5G(184, 0), CHAN5G(188, 0),
++ CHAN5G(192, 0), CHAN5G(196, 0),
++ CHAN5G(200, 0), CHAN5G(204, 0),
++ CHAN5G(208, 0), CHAN5G(212, 0),
++ CHAN5G(216, 0),
++};
++#undef CHAN5G
++
++static struct ieee80211_supported_band b43_band_5GHz_nphy = {
++ .band = IEEE80211_BAND_5GHZ,
++ .channels = b43_5ghz_nphy_chantable,
++ .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable),
++ .bitrates = b43_a_ratetable,
++ .n_bitrates = b43_a_ratetable_size,
++};
++
++static struct ieee80211_supported_band b43_band_5GHz_aphy = {
++ .band = IEEE80211_BAND_5GHZ,
++ .channels = b43_5ghz_aphy_chantable,
++ .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable),
++ .bitrates = b43_a_ratetable,
++ .n_bitrates = b43_a_ratetable_size,
++};
++
++static struct ieee80211_supported_band b43_band_2GHz = {
++ .band = IEEE80211_BAND_2GHZ,
++ .channels = b43_2ghz_chantable,
++ .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
++ .bitrates = b43_g_ratetable,
++ .n_bitrates = b43_g_ratetable_size,
+ };
+-#define b43_5ghz_chantable_size ARRAY_SIZE(b43_5ghz_chantable)
+-#endif
+
+ static void b43_wireless_core_exit(struct b43_wldev *dev);
+ static int b43_wireless_core_init(struct b43_wldev *dev);
+@@ -370,24 +472,30 @@
+ }
+
+ /* Read HostFlags */
+-u32 b43_hf_read(struct b43_wldev * dev)
++u64 b43_hf_read(struct b43_wldev * dev)
+ {
+- u32 ret;
++ u64 ret;
+
+ ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
+ ret <<= 16;
++ ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
++ ret <<= 16;
+ ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
+
+ return ret;
+ }
+
+ /* Write HostFlags */
+-void b43_hf_write(struct b43_wldev *dev, u32 value)
++void b43_hf_write(struct b43_wldev *dev, u64 value)
+ {
+- b43_shm_write16(dev, B43_SHM_SHARED,
+- B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF));
+- b43_shm_write16(dev, B43_SHM_SHARED,
+- B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16));
++ u16 lo, mi, hi;
++
++ lo = (value & 0x00000000FFFFULL);
++ mi = (value & 0x0000FFFF0000ULL) >> 16;
++ hi = (value & 0xFFFF00000000ULL) >> 32;
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
+ }
+
+ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf)
+@@ -912,7 +1020,18 @@
+ /* Turn the Analog ON/OFF */
+ static void b43_switch_analog(struct b43_wldev *dev, int on)
+ {
++ switch (dev->phy.type) {
++ case B43_PHYTYPE_A:
++ case B43_PHYTYPE_G:
+ b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
++ break;
++ case B43_PHYTYPE_N:
++ b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
++ on ? 0 : 0x7FFF);
++ break;
++ default:
++ B43_WARN_ON(1);
++ }
+ }
+
+ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+@@ -1162,22 +1281,107 @@
+ size + sizeof(struct b43_plcp_hdr6));
+ }
+
++/* Check if the use of the antenna that ieee80211 told us to
++ * use is possible. This will fall back to DEFAULT.
++ * "antenna_nr" is the antenna identifier we got from ieee80211. */
++u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
++ u8 antenna_nr)
++{
++ u8 antenna_mask;
++
++ if (antenna_nr == 0) {
++ /* Zero means "use default antenna". That's always OK. */
++ return 0;
++ }
++
++ /* Get the mask of available antennas. */
++ if (dev->phy.gmode)
++ antenna_mask = dev->dev->bus->sprom.ant_available_bg;
++ else
++ antenna_mask = dev->dev->bus->sprom.ant_available_a;
++
++ if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
++ /* This antenna is not available. Fall back to default. */
++ return 0;
++ }
++
++ return antenna_nr;
++}
++
++static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
++{
++ antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
++ switch (antenna) {
++ case 0: /* default/diversity */
++ return B43_ANTENNA_DEFAULT;
++ case 1: /* Antenna 0 */
++ return B43_ANTENNA0;
++ case 2: /* Antenna 1 */
++ return B43_ANTENNA1;
++ case 3: /* Antenna 2 */
++ return B43_ANTENNA2;
++ case 4: /* Antenna 3 */
++ return B43_ANTENNA3;
++ default:
++ return B43_ANTENNA_DEFAULT;
++ }
++}
++
++/* Convert a b43 antenna number value to the PHY TX control value. */
++static u16 b43_antenna_to_phyctl(int antenna)
++{
++ switch (antenna) {
++ case B43_ANTENNA0:
++ return B43_TXH_PHY_ANT0;
++ case B43_ANTENNA1:
++ return B43_TXH_PHY_ANT1;
++ case B43_ANTENNA2:
++ return B43_TXH_PHY_ANT2;
++ case B43_ANTENNA3:
++ return B43_TXH_PHY_ANT3;
++ case B43_ANTENNA_AUTO:
++ return B43_TXH_PHY_ANT01AUTO;
++ }
++ B43_WARN_ON(1);
++ return 0;
++}
++
+ static void b43_write_beacon_template(struct b43_wldev *dev,
+ u16 ram_offset,
+- u16 shm_size_offset, u8 rate)
++ u16 shm_size_offset)
+ {
+ unsigned int i, len, variable_len;
+ const struct ieee80211_mgmt *bcn;
+ const u8 *ie;
+ bool tim_found = 0;
++ unsigned int rate;
++ u16 ctl;
++ int antenna;
+
+ bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
+ len = min((size_t) dev->wl->current_beacon->len,
+ 0x200 - sizeof(struct b43_plcp_hdr6));
++ rate = dev->wl->beacon_txctl.tx_rate->hw_value;
+
+ b43_write_template_common(dev, (const u8 *)bcn,
+ len, ram_offset, shm_size_offset, rate);
+
++ /* Write the PHY TX control parameters. */
++ antenna = b43_antenna_from_ieee80211(dev,
++ dev->wl->beacon_txctl.antenna_sel_tx);
++ antenna = b43_antenna_to_phyctl(antenna);
++ ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
++ /* We can't send beacons with short preamble. Would get PHY errors. */
++ ctl &= ~B43_TXH_PHY_SHORTPRMBL;
++ ctl &= ~B43_TXH_PHY_ANT;
++ ctl &= ~B43_TXH_PHY_ENC;
++ ctl |= antenna;
++ if (b43_is_cck_rate(rate))
++ ctl |= B43_TXH_PHY_ENC_CCK;
++ else
++ ctl |= B43_TXH_PHY_ENC_OFDM;
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
++
+ /* Find the position of the TIM and the DTIM_period value
+ * and write them to SHM. */
+ ie = bcn->u.beacon.variable;
+@@ -1218,21 +1422,23 @@
+ b43warn(dev->wl, "Did not find a valid TIM IE in "
+ "the beacon template packet. AP or IBSS operation "
+ "may be broken.\n");
+- }
++ } else
++ b43dbg(dev->wl, "Updated beacon template\n");
+ }
+
+ static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
+- u16 shm_offset, u16 size, u8 rate)
++ u16 shm_offset, u16 size,
++ struct ieee80211_rate *rate)
+ {
+ struct b43_plcp_hdr4 plcp;
+ u32 tmp;
+ __le16 dur;
+
+ plcp.data = 0;
+- b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
++ b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->vif, size,
+- B43_RATE_TO_BASE100KBPS(rate));
++ rate);
+ /* Write PLCP in two parts and timing for packet transfer */
+ tmp = le32_to_cpu(plcp.data);
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
+@@ -1247,7 +1453,8 @@
+ * 3) Stripping TIM
+ */
+ static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
+- u16 *dest_size, u8 rate)
++ u16 *dest_size,
++ struct ieee80211_rate *rate)
+ {
+ const u8 *src_data;
+ u8 *dest_data;
+@@ -1292,7 +1499,7 @@
+ IEEE80211_STYPE_PROBE_RESP);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->vif, *dest_size,
+- B43_RATE_TO_BASE100KBPS(rate));
++ rate);
+ hdr->duration_id = dur;
+
+ return dest_data;
+@@ -1300,7 +1507,8 @@
+
+ static void b43_write_probe_resp_template(struct b43_wldev *dev,
+ u16 ram_offset,
+- u16 shm_size_offset, u8 rate)
++ u16 shm_size_offset,
++ struct ieee80211_rate *rate)
+ {
+ const u8 *probe_resp_data;
+ u16 size;
+@@ -1313,20 +1521,89 @@
+ /* Looks like PLCP headers plus packet timings are stored for
+ * all possible basic rates
+ */
+- b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
+- b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
+- b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
+- b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
++ b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
++ b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
++ b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
++ b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
+
+ size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
+ b43_write_template_common(dev, probe_resp_data,
+- size, ram_offset, shm_size_offset, rate);
++ size, ram_offset, shm_size_offset,
++ rate->hw_value);
+ kfree(probe_resp_data);
+ }
+
++static void handle_irq_beacon(struct b43_wldev *dev)
++{
++ struct b43_wl *wl = dev->wl;
++ u32 cmd, beacon0_valid, beacon1_valid;
++
++ if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
++ return;
++
++ /* This is the bottom half of the asynchronous beacon update. */
++
++ /* Ignore interrupt in the future. */
++ dev->irq_savedstate &= ~B43_IRQ_BEACON;
++
++ cmd = b43_read32(dev, B43_MMIO_MACCMD);
++ beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
++ beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID);
++
++ /* Schedule interrupt manually, if busy. */
++ if (beacon0_valid && beacon1_valid) {
++ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
++ dev->irq_savedstate |= B43_IRQ_BEACON;
++ return;
++ }
++
++ if (!beacon0_valid) {
++ if (!wl->beacon0_uploaded) {
++ b43_write_beacon_template(dev, 0x68, 0x18);
++ b43_write_probe_resp_template(dev, 0x268, 0x4A,
++ &__b43_ratetable[3]);
++ wl->beacon0_uploaded = 1;
++ }
++ cmd = b43_read32(dev, B43_MMIO_MACCMD);
++ cmd |= B43_MACCMD_BEACON0_VALID;
++ b43_write32(dev, B43_MMIO_MACCMD, cmd);
++ } else if (!beacon1_valid) {
++ if (!wl->beacon1_uploaded) {
++ b43_write_beacon_template(dev, 0x468, 0x1A);
++ wl->beacon1_uploaded = 1;
++ }
++ cmd = b43_read32(dev, B43_MMIO_MACCMD);
++ cmd |= B43_MACCMD_BEACON1_VALID;
++ b43_write32(dev, B43_MMIO_MACCMD, cmd);
++ }
++}
++
++static void b43_beacon_update_trigger_work(struct work_struct *work)
++{
++ struct b43_wl *wl = container_of(work, struct b43_wl,
++ beacon_update_trigger);
++ struct b43_wldev *dev;
++
++ mutex_lock(&wl->mutex);
++ dev = wl->current_dev;
++ if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
++ spin_lock_irq(&wl->irq_lock);
++ /* update beacon right away or defer to irq */
++ dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
++ handle_irq_beacon(dev);
++ /* The handler might have updated the IRQ mask. */
++ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK,
++ dev->irq_savedstate);
++ mmiowb();
++ spin_unlock_irq(&wl->irq_lock);
++ }
++ mutex_unlock(&wl->mutex);
++}
++
+ /* Asynchronously update the packet templates in template RAM.
+ * Locking: Requires wl->irq_lock to be locked. */
+-static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
++static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon,
++ const struct ieee80211_tx_control *txctl)
+ {
+ /* This is the top half of the ansynchronous beacon update.
+ * The bottom half is the beacon IRQ.
+@@ -1337,8 +1614,10 @@
+ if (wl->current_beacon)
+ dev_kfree_skb_any(wl->current_beacon);
+ wl->current_beacon = beacon;
++ memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl));
+ wl->beacon0_uploaded = 0;
+ wl->beacon1_uploaded = 0;
++ queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
+ }
+
+ static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
+@@ -1364,44 +1643,14 @@
+ {
+ b43_time_lock(dev);
+ if (dev->dev->id.revision >= 3) {
+- b43_write32(dev, 0x188, (beacon_int << 16));
++ b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
++ b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
+ } else {
+ b43_write16(dev, 0x606, (beacon_int >> 6));
+ b43_write16(dev, 0x610, beacon_int);
+ }
+ b43_time_unlock(dev);
+-}
+-
+-static void handle_irq_beacon(struct b43_wldev *dev)
+-{
+- struct b43_wl *wl = dev->wl;
+- u32 cmd;
+-
+- if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+- return;
+-
+- /* This is the bottom half of the asynchronous beacon update. */
+-
+- cmd = b43_read32(dev, B43_MMIO_MACCMD);
+- if (!(cmd & B43_MACCMD_BEACON0_VALID)) {
+- if (!wl->beacon0_uploaded) {
+- b43_write_beacon_template(dev, 0x68, 0x18,
+- B43_CCK_RATE_1MB);
+- b43_write_probe_resp_template(dev, 0x268, 0x4A,
+- B43_CCK_RATE_11MB);
+- wl->beacon0_uploaded = 1;
+- }
+- cmd |= B43_MACCMD_BEACON0_VALID;
+- }
+- if (!(cmd & B43_MACCMD_BEACON1_VALID)) {
+- if (!wl->beacon1_uploaded) {
+- b43_write_beacon_template(dev, 0x468, 0x1A,
+- B43_CCK_RATE_1MB);
+- wl->beacon1_uploaded = 1;
+- }
+- cmd |= B43_MACCMD_BEACON1_VALID;
+- }
+- b43_write32(dev, B43_MMIO_MACCMD, cmd);
++ b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
+ }
+
+ static void handle_irq_ucode_debug(struct b43_wldev *dev)
+@@ -1483,12 +1732,15 @@
+ handle_irq_noise(dev);
+
+ /* Check the DMA reason registers for received data. */
+- if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
+- b43_dma_rx(dev->dma.rx_ring0);
+- if (dma_reason[3] & B43_DMAIRQ_RX_DONE)
+- b43_dma_rx(dev->dma.rx_ring3);
++ if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
++ if (b43_using_pio_transfers(dev))
++ b43_pio_rx(dev->pio.rx_queue);
++ else
++ b43_dma_rx(dev->dma.rx_ring);
++ }
+ B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
++ B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
+
+@@ -2045,7 +2297,7 @@
+ }
+
+ /* http://bcm-specs.sipsolutions.net/EnableMac */
+-void b43_mac_enable(struct b43_wldev *dev)
++static void b43_mac_enable(struct b43_wldev *dev)
+ {
+ dev->mac_suspended--;
+ B43_WARN_ON(dev->mac_suspended < 0);
+@@ -2068,7 +2320,7 @@
+ }
+
+ /* http://bcm-specs.sipsolutions.net/SuspendMAC */
+-void b43_mac_suspend(struct b43_wldev *dev)
++static void b43_mac_suspend(struct b43_wldev *dev)
+ {
+ int i;
+ u32 tmp;
+@@ -2091,6 +2343,13 @@
+ & ~B43_MACCTL_ENABLED);
+ /* force pci to flush the write */
+ b43_read32(dev, B43_MMIO_MACCTL);
++ for (i = 35; i; i--) {
++ tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
++ if (tmp & B43_IRQ_MAC_SUSPENDED)
++ goto out;
++ udelay(10);
++ }
++ /* Hm, it seems this will take some time. Use msleep(). */
+ for (i = 40; i; i--) {
+ tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (tmp & B43_IRQ_MAC_SUSPENDED)
+@@ -2196,38 +2455,28 @@
+ }
+ }
+
++/* Set the default values for the PHY TX Control Words. */
++static void b43_set_phytxctl_defaults(struct b43_wldev *dev)
++{
++ u16 ctl = 0;
++
++ ctl |= B43_TXH_PHY_ENC_CCK;
++ ctl |= B43_TXH_PHY_ANT01AUTO;
++ ctl |= B43_TXH_PHY_TXPWR;
++
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl);
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl);
++}
++
+ /* Set the TX-Antenna for management frames sent by firmware. */
+ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
+ {
+- u16 ant = 0;
++ u16 ant;
+ u16 tmp;
+
+- switch (antenna) {
+- case B43_ANTENNA0:
+- ant |= B43_TXH_PHY_ANT0;
+- break;
+- case B43_ANTENNA1:
+- ant |= B43_TXH_PHY_ANT1;
+- break;
+- case B43_ANTENNA2:
+- ant |= B43_TXH_PHY_ANT2;
+- break;
+- case B43_ANTENNA3:
+- ant |= B43_TXH_PHY_ANT3;
+- break;
+- case B43_ANTENNA_AUTO:
+- ant |= B43_TXH_PHY_ANT01AUTO;
+- break;
+- default:
+- B43_WARN_ON(1);
+- }
+-
+- /* FIXME We also need to set the other flags of the PHY control field somewhere. */
++ ant = b43_antenna_to_phyctl(antenna);
+
+- /* For Beacons */
+- tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
+- tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
+- b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
+ /* For ACK/CTS */
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
+ tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
+@@ -2589,11 +2838,20 @@
+ struct b43_wldev *dev = wl->current_dev;
+ int err = -ENODEV;
+
++ if (unlikely(skb->len < 2 + 2 + 6)) {
++ /* Too short, this can't be a valid frame. */
++ return -EINVAL;
++ }
++ B43_WARN_ON(skb_shinfo(skb)->nr_frags);
++
+ if (unlikely(!dev))
+ goto out;
+ if (unlikely(b43_status(dev) < B43_STAT_STARTED))
+ goto out;
+- /* DMA-TX is done without a global lock. */
++ /* TX is done without a global lock. */
++ if (b43_using_pio_transfers(dev))
++ err = b43_pio_tx(dev, skb, ctl);
++ else
+ err = b43_dma_tx(dev, skb, ctl);
+ out:
+ if (unlikely(err))
+@@ -2601,10 +2859,178 @@
+ return NETDEV_TX_OK;
+ }
+
++/* Locking: wl->irq_lock */
++static void b43_qos_params_upload(struct b43_wldev *dev,
++ const struct ieee80211_tx_queue_params *p,
++ u16 shm_offset)
++{
++ u16 params[B43_NR_QOSPARAMS];
++ int cw_min, cw_max, aifs, bslots, tmp;
++ unsigned int i;
++
++ const u16 aCWmin = 0x0001;
++ const u16 aCWmax = 0x03FF;
++
++ /* Calculate the default values for the parameters, if needed. */
++ switch (shm_offset) {
++ case B43_QOS_VOICE:
++ aifs = (p->aifs == -1) ? 2 : p->aifs;
++ cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min;
++ cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max;
++ break;
++ case B43_QOS_VIDEO:
++ aifs = (p->aifs == -1) ? 2 : p->aifs;
++ cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min;
++ cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max;
++ break;
++ case B43_QOS_BESTEFFORT:
++ aifs = (p->aifs == -1) ? 3 : p->aifs;
++ cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
++ cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
++ break;
++ case B43_QOS_BACKGROUND:
++ aifs = (p->aifs == -1) ? 7 : p->aifs;
++ cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
++ cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
++ break;
++ default:
++ B43_WARN_ON(1);
++ return;
++ }
++ if (cw_min <= 0)
++ cw_min = aCWmin;
++ if (cw_max <= 0)
++ cw_max = aCWmin;
++ bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min;
++
++ memset(&params, 0, sizeof(params));
++
++ params[B43_QOSPARAM_TXOP] = p->txop * 32;
++ params[B43_QOSPARAM_CWMIN] = cw_min;
++ params[B43_QOSPARAM_CWMAX] = cw_max;
++ params[B43_QOSPARAM_CWCUR] = cw_min;
++ params[B43_QOSPARAM_AIFS] = aifs;
++ params[B43_QOSPARAM_BSLOTS] = bslots;
++ params[B43_QOSPARAM_REGGAP] = bslots + aifs;
++
++ for (i = 0; i < ARRAY_SIZE(params); i++) {
++ if (i == B43_QOSPARAM_STATUS) {
++ tmp = b43_shm_read16(dev, B43_SHM_SHARED,
++ shm_offset + (i * 2));
++ /* Mark the parameters as updated. */
++ tmp |= 0x100;
++ b43_shm_write16(dev, B43_SHM_SHARED,
++ shm_offset + (i * 2),
++ tmp);
++ } else {
++ b43_shm_write16(dev, B43_SHM_SHARED,
++ shm_offset + (i * 2),
++ params[i]);
++ }
++ }
++}
++
++/* Update the QOS parameters in hardware. */
++static void b43_qos_update(struct b43_wldev *dev)
++{
++ struct b43_wl *wl = dev->wl;
++ struct b43_qos_params *params;
++ unsigned long flags;
++ unsigned int i;
++
++ /* Mapping of mac80211 queues to b43 SHM offsets. */
++ static const u16 qos_shm_offsets[] = {
++ [0] = B43_QOS_VOICE,
++ [1] = B43_QOS_VIDEO,
++ [2] = B43_QOS_BESTEFFORT,
++ [3] = B43_QOS_BACKGROUND,
++ };
++ BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params));
++
++ b43_mac_suspend(dev);
++ spin_lock_irqsave(&wl->irq_lock, flags);
++
++ for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
++ params = &(wl->qos_params[i]);
++ if (params->need_hw_update) {
++ b43_qos_params_upload(dev, &(params->p),
++ qos_shm_offsets[i]);
++ params->need_hw_update = 0;
++ }
++ }
++
++ spin_unlock_irqrestore(&wl->irq_lock, flags);
++ b43_mac_enable(dev);
++}
++
++static void b43_qos_clear(struct b43_wl *wl)
++{
++ struct b43_qos_params *params;
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
++ params = &(wl->qos_params[i]);
++
++ memset(&(params->p), 0, sizeof(params->p));
++ params->p.aifs = -1;
++ params->need_hw_update = 1;
++ }
++}
++
++/* Initialize the core's QOS capabilities */
++static void b43_qos_init(struct b43_wldev *dev)
++{
++ struct b43_wl *wl = dev->wl;
++ unsigned int i;
++
++ /* Upload the current QOS parameters. */
++ for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++)
++ wl->qos_params[i].need_hw_update = 1;
++ b43_qos_update(dev);
++
++ /* Enable QOS support. */
++ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
++ b43_write16(dev, B43_MMIO_IFSCTL,
++ b43_read16(dev, B43_MMIO_IFSCTL)
++ | B43_MMIO_IFSCTL_USE_EDCF);
++}
++
++static void b43_qos_update_work(struct work_struct *work)
++{
++ struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work);
++ struct b43_wldev *dev;
++
++ mutex_lock(&wl->mutex);
++ dev = wl->current_dev;
++ if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED)))
++ b43_qos_update(dev);
++ mutex_unlock(&wl->mutex);
++}
++
+ static int b43_op_conf_tx(struct ieee80211_hw *hw,
+- int queue,
++ int _queue,
+ const struct ieee80211_tx_queue_params *params)
+ {
++ struct b43_wl *wl = hw_to_b43_wl(hw);
++ unsigned long flags;
++ unsigned int queue = (unsigned int)_queue;
++ struct b43_qos_params *p;
++
++ if (queue >= ARRAY_SIZE(wl->qos_params)) {
++ /* Queue not available or don't support setting
++ * params on this queue. Return success to not
++ * confuse mac80211. */
++ return 0;
++ }
++
++ spin_lock_irqsave(&wl->irq_lock, flags);
++ p = &(wl->qos_params[queue]);
++ memcpy(&(p->p), params, sizeof(p->p));
++ p->need_hw_update = 1;
++ spin_unlock_irqrestore(&wl->irq_lock, flags);
++
++ queue_work(hw->workqueue, &wl->qos_update_work);
++
+ return 0;
+ }
+
+@@ -2620,6 +3046,9 @@
+ goto out;
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
++ if (b43_using_pio_transfers(dev))
++ b43_pio_get_tx_stats(dev, stats);
++ else
+ b43_dma_get_tx_stats(dev, stats);
+ err = 0;
+ }
+@@ -2641,45 +3070,6 @@
+ return 0;
+ }
+
+-static const char *phymode_to_string(unsigned int phymode)
+-{
+- switch (phymode) {
+- case B43_PHYMODE_A:
+- return "A";
+- case B43_PHYMODE_B:
+- return "B";
+- case B43_PHYMODE_G:
+- return "G";
+- default:
+- B43_WARN_ON(1);
+- }
+- return "";
+-}
+-
+-static int find_wldev_for_phymode(struct b43_wl *wl,
+- unsigned int phymode,
+- struct b43_wldev **dev, bool * gmode)
+-{
+- struct b43_wldev *d;
+-
+- list_for_each_entry(d, &wl->devlist, list) {
+- if (d->phy.possible_phymodes & phymode) {
+- /* Ok, this device supports the PHY-mode.
+- * Now figure out how the gmode bit has to be
+- * set to support it. */
+- if (phymode == B43_PHYMODE_A)
+- *gmode = 0;
+- else
+- *gmode = 1;
+- *dev = d;
+-
+- return 0;
+- }
+- }
+-
+- return -ESRCH;
+-}
+-
+ static void b43_put_phy_into_reset(struct b43_wldev *dev)
+ {
+ struct ssb_device *sdev = dev->dev;
+@@ -2699,28 +3089,64 @@
+ msleep(1);
+ }
+
++static const char * band_to_string(enum ieee80211_band band)
++{
++ switch (band) {
++ case IEEE80211_BAND_5GHZ:
++ return "5";
++ case IEEE80211_BAND_2GHZ:
++ return "2.4";
++ default:
++ break;
++ }
++ B43_WARN_ON(1);
++ return "";
++}
++
+ /* Expects wl->mutex locked */
+-static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
++static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
+ {
+- struct b43_wldev *up_dev;
++ struct b43_wldev *up_dev = NULL;
+ struct b43_wldev *down_dev;
++ struct b43_wldev *d;
+ int err;
+- bool gmode = 0;
++ bool gmode;
+ int prev_status;
+
+- err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
+- if (err) {
+- b43err(wl, "Could not find a device for %s-PHY mode\n",
+- phymode_to_string(new_mode));
+- return err;
++ /* Find a device and PHY which supports the band. */
++ list_for_each_entry(d, &wl->devlist, list) {
++ switch (chan->band) {
++ case IEEE80211_BAND_5GHZ:
++ if (d->phy.supports_5ghz) {
++ up_dev = d;
++ gmode = 0;
++ }
++ break;
++ case IEEE80211_BAND_2GHZ:
++ if (d->phy.supports_2ghz) {
++ up_dev = d;
++ gmode = 1;
++ }
++ break;
++ default:
++ B43_WARN_ON(1);
++ return -EINVAL;
++ }
++ if (up_dev)
++ break;
++ }
++ if (!up_dev) {
++ b43err(wl, "Could not find a device for %s-GHz band operation\n",
++ band_to_string(chan->band));
++ return -ENODEV;
+ }
+ if ((up_dev == wl->current_dev) &&
+ (!!wl->current_dev->phy.gmode == !!gmode)) {
+ /* This device is already running. */
+ return 0;
+ }
+- b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
+- phymode_to_string(new_mode));
++ b43dbg(wl, "Switching to %s-GHz band\n",
++ band_to_string(chan->band));
+ down_dev = wl->current_dev;
+
+ prev_status = b43_status(down_dev);
+@@ -2742,8 +3168,8 @@
+ err = b43_wireless_core_init(up_dev);
+ if (err) {
+ b43err(wl, "Fatal: Could not initialize device for "
+- "newly selected %s-PHY mode\n",
+- phymode_to_string(new_mode));
++ "selected %s-GHz band\n",
++ band_to_string(chan->band));
+ goto init_failure;
+ }
+ }
+@@ -2751,8 +3177,8 @@
+ err = b43_wireless_core_start(up_dev);
+ if (err) {
+ b43err(wl, "Fatal: Coult not start device for "
+- "newly selected %s-PHY mode\n",
+- phymode_to_string(new_mode));
++ "selected %s-GHz band\n",
++ band_to_string(chan->band));
+ b43_wireless_core_exit(up_dev);
+ goto init_failure;
+ }
+@@ -2762,86 +3188,26 @@
+ wl->current_dev = up_dev;
+
+ return 0;
+- init_failure:
++init_failure:
+ /* Whoops, failed to init the new core. No core is operating now. */
+ wl->current_dev = NULL;
+ return err;
+ }
+
+-/* Check if the use of the antenna that ieee80211 told us to
+- * use is possible. This will fall back to DEFAULT.
+- * "antenna_nr" is the antenna identifier we got from ieee80211. */
+-u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+- u8 antenna_nr)
+-{
+- u8 antenna_mask;
+-
+- if (antenna_nr == 0) {
+- /* Zero means "use default antenna". That's always OK. */
+- return 0;
+- }
+-
+- /* Get the mask of available antennas. */
+- if (dev->phy.gmode)
+- antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+- else
+- antenna_mask = dev->dev->bus->sprom.ant_available_a;
+-
+- if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
+- /* This antenna is not available. Fall back to default. */
+- return 0;
+- }
+-
+- return antenna_nr;
+-}
+-
+-static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
+-{
+- antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
+- switch (antenna) {
+- case 0: /* default/diversity */
+- return B43_ANTENNA_DEFAULT;
+- case 1: /* Antenna 0 */
+- return B43_ANTENNA0;
+- case 2: /* Antenna 1 */
+- return B43_ANTENNA1;
+- case 3: /* Antenna 2 */
+- return B43_ANTENNA2;
+- case 4: /* Antenna 3 */
+- return B43_ANTENNA3;
+- default:
+- return B43_ANTENNA_DEFAULT;
+- }
+-}
+-
+ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+ {
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+ struct b43_phy *phy;
+ unsigned long flags;
+- unsigned int new_phymode = 0xFFFF;
+ int antenna;
+ int err = 0;
+ u32 savedirqs;
+
+ mutex_lock(&wl->mutex);
+
+- /* Switch the PHY mode (if necessary). */
+- switch (conf->phymode) {
+- case MODE_IEEE80211A:
+- new_phymode = B43_PHYMODE_A;
+- break;
+- case MODE_IEEE80211B:
+- new_phymode = B43_PHYMODE_B;
+- break;
+- case MODE_IEEE80211G:
+- new_phymode = B43_PHYMODE_G;
+- break;
+- default:
+- B43_WARN_ON(1);
+- }
+- err = b43_switch_phymode(wl, new_phymode);
++ /* Switch the band (if necessary). This might change the active core. */
++ err = b43_switch_band(wl, conf->channel);
+ if (err)
+ goto out_unlock_mutex;
+ dev = wl->current_dev;
+@@ -2861,8 +3227,8 @@
+
+ /* Switch to the requested channel.
+ * The firmware takes care of races with the TX handler. */
+- if (conf->channel_val != phy->channel)
+- b43_radio_selectchannel(dev, conf->channel_val, 0);
++ if (conf->channel->hw_value != phy->channel)
++ b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
+
+ /* Enable/Disable ShortSlot timing. */
+ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
+@@ -3075,8 +3441,10 @@
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+ B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+- if (conf->beacon)
+- b43_update_templates(wl, conf->beacon);
++ if (conf->beacon) {
++ b43_update_templates(wl, conf->beacon,
++ conf->beacon_control);
++ }
+ }
+ b43_write_mac_bssid_templates(dev);
+ }
+@@ -3106,6 +3474,7 @@
+
+ b43_set_status(dev, B43_STAT_INITIALIZED);
+
++ b43_pio_stop(dev);
+ mutex_unlock(&wl->mutex);
+ /* Must unlock as it would otherwise deadlock. No races here.
+ * Cancel the possibly running self-rearming periodic work. */
+@@ -3400,6 +3769,41 @@
+ long_retry);
+ }
+
++static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
++{
++ u16 pu_delay;
++
++ /* The time value is in microseconds. */
++ if (dev->phy.type == B43_PHYTYPE_A)
++ pu_delay = 3700;
++ else
++ pu_delay = 1050;
++ if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
++ pu_delay = 500;
++ if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
++ pu_delay = max(pu_delay, (u16)2400);
++
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SPUWKUP, pu_delay);
++}
++
++/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */
++static void b43_set_pretbtt(struct b43_wldev *dev)
++{
++ u16 pretbtt;
++
++ /* The time value is in microseconds. */
++ if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) {
++ pretbtt = 2;
++ } else {
++ if (dev->phy.type == B43_PHYTYPE_A)
++ pretbtt = 120;
++ else
++ pretbtt = 250;
++ }
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt);
++ b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt);
++}
++
+ /* Shutdown a wireless core */
+ /* Locking: wl->mutex */
+ static void b43_wireless_core_exit(struct b43_wldev *dev)
+@@ -3423,6 +3827,7 @@
+ b43_rng_exit(dev->wl, false);
+ }
+ b43_dma_free(dev);
++ b43_pio_free(dev);
+ b43_chip_exit(dev);
+ b43_radio_turn_off(dev, 1);
+ b43_switch_analog(dev, 0);
+@@ -3510,6 +3915,7 @@
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
+
+ b43_rate_memory_init(dev);
++ b43_set_phytxctl_defaults(dev);
+
+ /* Minimum Contention Window */
+ if (phy->type == B43_PHYTYPE_B) {
+@@ -3520,18 +3926,17 @@
+ /* Maximum Contention Window */
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
+
++ if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) {
++ dev->__using_pio_transfers = 1;
++ err = b43_pio_init(dev);
++ } else {
++ dev->__using_pio_transfers = 0;
+ err = b43_dma_init(dev);
++ }
+ if (err)
+ goto err_chip_exit;
+ b43_qos_init(dev);
+-
+-//FIXME
+-#if 1
+- b43_write16(dev, 0x0612, 0x0050);
+- b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050);
+- b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4);
+-#endif
+-
++ b43_set_synth_pu_delay(dev, 1);
+ b43_bluetooth_coext_enable(dev);
+
+ ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+@@ -3591,6 +3996,8 @@
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
++ b43_set_pretbtt(dev);
++ b43_set_synth_pu_delay(dev, 0);
+ b43_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+@@ -3642,6 +4049,7 @@
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ wl->filter_flags = 0;
+ wl->radiotap_enabled = 0;
++ b43_qos_clear(wl);
+
+ /* First register RFkill.
+ * LEDs that are registered later depend on it. */
+@@ -3683,6 +4091,8 @@
+ struct b43_wldev *dev = wl->current_dev;
+
+ b43_rfkill_exit(dev);
++ cancel_work_sync(&(wl->qos_update_work));
++ cancel_work_sync(&(wl->beacon_update_trigger));
+
+ mutex_lock(&wl->mutex);
+ if (b43_status(dev) >= B43_STAT_STARTED)
+@@ -3716,16 +4126,17 @@
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct sk_buff *beacon;
+ unsigned long flags;
++ struct ieee80211_tx_control txctl;
+
+ /* We could modify the existing beacon and set the aid bit in
+ * the TIM field, but that would probably require resizing and
+ * moving of data within the beacon template.
+ * Simply request a new beacon and let mac80211 do the hard work. */
+- beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
++ beacon = ieee80211_beacon_get(hw, wl->vif, &txctl);
+ if (unlikely(!beacon))
+ return -ENOMEM;
+ spin_lock_irqsave(&wl->irq_lock, flags);
+- b43_update_templates(wl, beacon);
++ b43_update_templates(wl, beacon, &txctl);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+@@ -3739,12 +4150,22 @@
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+- b43_update_templates(wl, beacon);
++ b43_update_templates(wl, beacon, ctl);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+ }
+
++static void b43_op_sta_notify(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif,
++ enum sta_notify_cmd notify_cmd,
++ const u8 *addr)
++{
++ struct b43_wl *wl = hw_to_b43_wl(hw);
++
++ B43_WARN_ON(!vif || wl->vif != vif);
++}
++
+ static const struct ieee80211_ops b43_hw_ops = {
+ .tx = b43_op_tx,
+ .conf_tx = b43_op_conf_tx,
+@@ -3761,6 +4182,7 @@
+ .set_retry_limit = b43_op_set_retry_limit,
+ .set_tim = b43_op_beacon_set_tim,
+ .beacon_update = b43_op_ibss_beacon_update,
++ .sta_notify = b43_op_sta_notify,
+ };
+
+ /* Hard-reset the chip. Do not call this directly.
+@@ -3804,31 +4226,23 @@
+ b43info(wl, "Controller restarted\n");
+ }
+
+-static int b43_setup_modes(struct b43_wldev *dev,
++static int b43_setup_bands(struct b43_wldev *dev,
+ bool have_2ghz_phy, bool have_5ghz_phy)
+ {
+ struct ieee80211_hw *hw = dev->wl->hw;
+- struct ieee80211_hw_mode *mode;
+- struct b43_phy *phy = &dev->phy;
+- int err;
+
+- /* XXX: This function will go away soon, when mac80211
+- * band stuff is rewritten. So this is just a hack.
+- * For now we always claim GPHY mode, as there is no
+- * support for NPHY and APHY in the device, yet.
+- * This assumption is OK, as any B, N or A PHY will already
+- * have died a horrible sanity check death earlier. */
+-
+- mode = &phy->hwmodes[0];
+- mode->mode = MODE_IEEE80211G;
+- mode->num_channels = b43_2ghz_chantable_size;
+- mode->channels = b43_2ghz_chantable;
+- mode->num_rates = b43_g_ratetable_size;
+- mode->rates = b43_g_ratetable;
+- err = ieee80211_register_hwmode(hw, mode);
+- if (err)
+- return err;
+- phy->possible_phymodes |= B43_PHYMODE_G;
++ if (have_2ghz_phy)
++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
++ if (dev->phy.type == B43_PHYTYPE_N) {
++ if (have_5ghz_phy)
++ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy;
++ } else {
++ if (have_5ghz_phy)
++ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
++ }
++
++ dev->phy.supports_2ghz = have_2ghz_phy;
++ dev->phy.supports_5ghz = have_5ghz_phy;
+
+ return 0;
+ }
+@@ -3910,7 +4324,7 @@
+ err = b43_validate_chipaccess(dev);
+ if (err)
+ goto err_powerdown;
+- err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy);
++ err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
+ if (err)
+ goto err_powerdown;
+
+@@ -4040,7 +4454,7 @@
+ hw->max_signal = 100;
+ hw->max_rssi = -110;
+ hw->max_noise = -110;
+- hw->queues = 1; /* FIXME: hardware has more queues */
++ hw->queues = b43_modparam_qos ? 4 : 1;
+ SET_IEEE80211_DEV(hw, dev->dev);
+ if (is_valid_ether_addr(sprom->et1mac))
+ SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
+@@ -4056,6 +4470,8 @@
+ spin_lock_init(&wl->shm_lock);
+ mutex_init(&wl->mutex);
+ INIT_LIST_HEAD(&wl->devlist);
++ INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
++ INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
+
+ ssb_set_devtypedata(dev, wl);
+ b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/main.h linux-2.6.25/drivers/net/wireless/b43/main.h
+--- linux-2.6.25.old/drivers/net/wireless/b43/main.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/main.h 2008-04-19 13:54:59.000000000 +0200
+@@ -38,6 +38,10 @@
+ /* Magic helper macro to pad structures. Ignore those above. It's magic. */
+ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
+
++
++extern int b43_modparam_qos;
++
++
+ /* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+ static inline u8 b43_freq_to_channel_5ghz(int freq)
+ {
+@@ -95,16 +99,13 @@
+ void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
+ void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
+
+-u32 b43_hf_read(struct b43_wldev *dev);
+-void b43_hf_write(struct b43_wldev *dev, u32 value);
++u64 b43_hf_read(struct b43_wldev *dev);
++void b43_hf_write(struct b43_wldev *dev, u64 value);
+
+ void b43_dummy_transmission(struct b43_wldev *dev);
+
+ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
+
+-void b43_mac_suspend(struct b43_wldev *dev);
+-void b43_mac_enable(struct b43_wldev *dev);
+-
+ void b43_controller_restart(struct b43_wldev *dev, const char *reason);
+
+ #define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/Makefile linux-2.6.25/drivers/net/wireless/b43/Makefile
+--- linux-2.6.25.old/drivers/net/wireless/b43/Makefile 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/Makefile 2008-04-19 13:54:59.000000000 +0200
+@@ -1,13 +1,14 @@
+ b43-y += main.o
+ b43-y += tables.o
+-b43-y += tables_nphy.o
++b43-$(CONFIG_B43_NPHY) += tables_nphy.o
+ b43-y += phy.o
+-b43-y += nphy.o
++b43-$(CONFIG_B43_NPHY) += nphy.o
+ b43-y += sysfs.o
+ b43-y += xmit.o
+ b43-y += lo.o
+ b43-y += wa.o
+ b43-y += dma.o
++b43-$(CONFIG_B43_PIO) += pio.o
+ b43-$(CONFIG_B43_RFKILL) += rfkill.o
+ b43-$(CONFIG_B43_LEDS) += leds.o
+ b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/nphy.c linux-2.6.25/drivers/net/wireless/b43/nphy.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/nphy.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/nphy.c 2008-04-19 13:54:59.000000000 +0200
+@@ -240,7 +240,6 @@
+
+ b43_phy_set(dev, B43_NPHY_IQFLIP,
+ B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+- //FIXME the following condition is different in the specs.
+ if (1 /* FIXME band is 2.4GHz */) {
+ b43_phy_set(dev, B43_NPHY_CLASSCTL,
+ B43_NPHY_CLASSCTL_CCKEN);
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/nphy.h linux-2.6.25/drivers/net/wireless/b43/nphy.h
+--- linux-2.6.25.old/drivers/net/wireless/b43/nphy.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/nphy.h 2008-04-19 13:54:59.000000000 +0200
+@@ -919,6 +919,10 @@
+
+ struct b43_wldev;
+
++
++#ifdef CONFIG_B43_NPHY
++/* N-PHY support enabled */
++
+ int b43_phy_initn(struct b43_wldev *dev);
+
+ void b43_nphy_radio_turn_on(struct b43_wldev *dev);
+@@ -929,4 +933,40 @@
+ void b43_nphy_xmitpower(struct b43_wldev *dev);
+ void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
+
++
++#else /* CONFIG_B43_NPHY */
++/* N-PHY support disabled */
++
++
++static inline
++int b43_phy_initn(struct b43_wldev *dev)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline
++void b43_nphy_radio_turn_on(struct b43_wldev *dev)
++{
++}
++static inline
++void b43_nphy_radio_turn_off(struct b43_wldev *dev)
++{
++}
++
++static inline
++int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
++{
++ return -ENOSYS;
++}
++
++static inline
++void b43_nphy_xmitpower(struct b43_wldev *dev)
++{
++}
++static inline
++void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
++{
++}
++
++#endif /* CONFIG_B43_NPHY */
+ #endif /* B43_NPHY_H_ */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/pcmcia.c linux-2.6.25/drivers/net/wireless/b43/pcmcia.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/pcmcia.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/pcmcia.c 2008-04-19 16:24:28.000000000 +0200
+@@ -43,14 +43,16 @@
+ #ifdef CONFIG_PM
+ static int b43_pcmcia_suspend(struct pcmcia_device *dev)
+ {
+- //TODO
+- return 0;
++ struct ssb_bus *ssb = dev->priv;
++
++ return ssb_bus_suspend(ssb);
+ }
+
+ static int b43_pcmcia_resume(struct pcmcia_device *dev)
+ {
+- //TODO
+- return 0;
++ struct ssb_bus *ssb = dev->priv;
++
++ return ssb_bus_resume(ssb);
+ }
+ #else /* CONFIG_PM */
+ # define b43_pcmcia_suspend NULL
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/pio.c linux-2.6.25/drivers/net/wireless/b43/pio.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/pio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.25/drivers/net/wireless/b43/pio.c 2008-04-19 13:54:59.000000000 +0200
+@@ -0,0 +1,842 @@
++/*
++
++ Broadcom B43 wireless driver
++
++ PIO data transfer
++
++ Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
++
++ This program is free software; you can redistribute it 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 program 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; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++
++*/
++
++#include "b43.h"
++#include "pio.h"
++#include "dma.h"
++#include "main.h"
++#include "xmit.h"
++
++#include <linux/delay.h>
++
++
++static void b43_pio_rx_work(struct work_struct *work);
++
++
++static u16 generate_cookie(struct b43_pio_txqueue *q,
++ struct b43_pio_txpacket *pack)
++{
++ u16 cookie;
++
++ /* Use the upper 4 bits of the cookie as
++ * PIO controller ID and store the packet index number
++ * in the lower 12 bits.
++ * Note that the cookie must never be 0, as this
++ * is a special value used in RX path.
++ * It can also not be 0xFFFF because that is special
++ * for multicast frames.
++ */
++ cookie = (((u16)q->index + 1) << 12);
++ cookie |= pack->index;
++
++ return cookie;
++}
++
++static
++struct b43_pio_txqueue * parse_cookie(struct b43_wldev *dev,
++ u16 cookie,
++ struct b43_pio_txpacket **pack)
++{
++ struct b43_pio *pio = &dev->pio;
++ struct b43_pio_txqueue *q = NULL;
++ unsigned int pack_index;
++
++ switch (cookie & 0xF000) {
++ case 0x1000:
++ q = pio->tx_queue_AC_BK;
++ break;
++ case 0x2000:
++ q = pio->tx_queue_AC_BE;
++ break;
++ case 0x3000:
++ q = pio->tx_queue_AC_VI;
++ break;
++ case 0x4000:
++ q = pio->tx_queue_AC_VO;
++ break;
++ case 0x5000:
++ q = pio->tx_queue_mcast;
++ break;
++ }
++ if (B43_WARN_ON(!q))
++ return NULL;
++ pack_index = (cookie & 0x0FFF);
++ if (B43_WARN_ON(pack_index >= ARRAY_SIZE(q->packets)))
++ return NULL;
++ *pack = &q->packets[pack_index];
++
++ return q;
++}
++
++static u16 index_to_pioqueue_base(struct b43_wldev *dev,
++ unsigned int index)
++{
++ static const u16 bases[] = {
++ B43_MMIO_PIO_BASE0,
++ B43_MMIO_PIO_BASE1,
++ B43_MMIO_PIO_BASE2,
++ B43_MMIO_PIO_BASE3,
++ B43_MMIO_PIO_BASE4,
++ B43_MMIO_PIO_BASE5,
++ B43_MMIO_PIO_BASE6,
++ B43_MMIO_PIO_BASE7,
++ };
++ static const u16 bases_rev11[] = {
++ B43_MMIO_PIO11_BASE0,
++ B43_MMIO_PIO11_BASE1,
++ B43_MMIO_PIO11_BASE2,
++ B43_MMIO_PIO11_BASE3,
++ B43_MMIO_PIO11_BASE4,
++ B43_MMIO_PIO11_BASE5,
++ };
++
++ if (dev->dev->id.revision >= 11) {
++ B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11));
++ return bases_rev11[index];
++ }
++ B43_WARN_ON(index >= ARRAY_SIZE(bases));
++ return bases[index];
++}
++
++static u16 pio_txqueue_offset(struct b43_wldev *dev)
++{
++ if (dev->dev->id.revision >= 11)
++ return 0x18;
++ return 0;
++}
++
++static u16 pio_rxqueue_offset(struct b43_wldev *dev)
++{
++ if (dev->dev->id.revision >= 11)
++ return 0x38;
++ return 8;
++}
++
++static struct b43_pio_txqueue * b43_setup_pioqueue_tx(struct b43_wldev *dev,
++ unsigned int index)
++{
++ struct b43_pio_txqueue *q;
++ struct b43_pio_txpacket *p;
++ unsigned int i;
++
++ q = kzalloc(sizeof(*q), GFP_KERNEL);
++ if (!q)
++ return NULL;
++ spin_lock_init(&q->lock);
++ q->dev = dev;
++ q->rev = dev->dev->id.revision;
++ q->mmio_base = index_to_pioqueue_base(dev, index) +
++ pio_txqueue_offset(dev);
++ q->index = index;
++
++ q->free_packet_slots = B43_PIO_MAX_NR_TXPACKETS;
++ if (q->rev >= 8) {
++ q->buffer_size = 1920; //FIXME this constant is wrong.
++ } else {
++ q->buffer_size = b43_piotx_read16(q, B43_PIO_TXQBUFSIZE);
++ q->buffer_size -= 80;
++ }
++
++ INIT_LIST_HEAD(&q->packets_list);
++ for (i = 0; i < ARRAY_SIZE(q->packets); i++) {
++ p = &(q->packets[i]);
++ INIT_LIST_HEAD(&p->list);
++ p->index = i;
++ p->queue = q;
++ list_add(&p->list, &q->packets_list);
++ }
++
++ return q;
++}
++
++static struct b43_pio_rxqueue * b43_setup_pioqueue_rx(struct b43_wldev *dev,
++ unsigned int index)
++{
++ struct b43_pio_rxqueue *q;
++
++ q = kzalloc(sizeof(*q), GFP_KERNEL);
++ if (!q)
++ return NULL;
++ spin_lock_init(&q->lock);
++ q->dev = dev;
++ q->rev = dev->dev->id.revision;
++ q->mmio_base = index_to_pioqueue_base(dev, index) +
++ pio_rxqueue_offset(dev);
++ INIT_WORK(&q->rx_work, b43_pio_rx_work);
++
++ /* Enable Direct FIFO RX (PIO) on the engine. */
++ b43_dma_direct_fifo_rx(dev, index, 1);
++
++ return q;
++}
++
++static void b43_pio_cancel_tx_packets(struct b43_pio_txqueue *q)
++{
++ struct b43_pio_txpacket *pack;
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(q->packets); i++) {
++ pack = &(q->packets[i]);
++ if (pack->skb) {
++ dev_kfree_skb_any(pack->skb);
++ pack->skb = NULL;
++ }
++ }
++}
++
++static void b43_destroy_pioqueue_tx(struct b43_pio_txqueue *q,
++ const char *name)
++{
++ if (!q)
++ return;
++ b43_pio_cancel_tx_packets(q);
++ kfree(q);
++}
++
++static void b43_destroy_pioqueue_rx(struct b43_pio_rxqueue *q,
++ const char *name)
++{
++ if (!q)
++ return;
++ kfree(q);
++}
++
++#define destroy_queue_tx(pio, queue) do { \
++ b43_destroy_pioqueue_tx((pio)->queue, __stringify(queue)); \
++ (pio)->queue = NULL; \
++ } while (0)
++
++#define destroy_queue_rx(pio, queue) do { \
++ b43_destroy_pioqueue_rx((pio)->queue, __stringify(queue)); \
++ (pio)->queue = NULL; \
++ } while (0)
++
++void b43_pio_free(struct b43_wldev *dev)
++{
++ struct b43_pio *pio;
++
++ if (!b43_using_pio_transfers(dev))
++ return;
++ pio = &dev->pio;
++
++ destroy_queue_rx(pio, rx_queue);
++ destroy_queue_tx(pio, tx_queue_mcast);
++ destroy_queue_tx(pio, tx_queue_AC_VO);
++ destroy_queue_tx(pio, tx_queue_AC_VI);
++ destroy_queue_tx(pio, tx_queue_AC_BE);
++ destroy_queue_tx(pio, tx_queue_AC_BK);
++}
++
++void b43_pio_stop(struct b43_wldev *dev)
++{
++ if (!b43_using_pio_transfers(dev))
++ return;
++ cancel_work_sync(&dev->pio.rx_queue->rx_work);
++}
++
++int b43_pio_init(struct b43_wldev *dev)
++{
++ struct b43_pio *pio = &dev->pio;
++ int err = -ENOMEM;
++
++ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
++ & ~B43_MACCTL_BE);
++ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RXPADOFF, 0);
++
++ pio->tx_queue_AC_BK = b43_setup_pioqueue_tx(dev, 0);
++ if (!pio->tx_queue_AC_BK)
++ goto out;
++
++ pio->tx_queue_AC_BE = b43_setup_pioqueue_tx(dev, 1);
++ if (!pio->tx_queue_AC_BE)
++ goto err_destroy_bk;
++
++ pio->tx_queue_AC_VI = b43_setup_pioqueue_tx(dev, 2);
++ if (!pio->tx_queue_AC_VI)
++ goto err_destroy_be;
++
++ pio->tx_queue_AC_VO = b43_setup_pioqueue_tx(dev, 3);
++ if (!pio->tx_queue_AC_VO)
++ goto err_destroy_vi;
++
++ pio->tx_queue_mcast = b43_setup_pioqueue_tx(dev, 4);
++ if (!pio->tx_queue_mcast)
++ goto err_destroy_vo;
++
++ pio->rx_queue = b43_setup_pioqueue_rx(dev, 0);
++ if (!pio->rx_queue)
++ goto err_destroy_mcast;
++
++ b43dbg(dev->wl, "PIO initialized\n");
++ err = 0;
++out:
++ return err;
++
++err_destroy_mcast:
++ destroy_queue_tx(pio, tx_queue_mcast);
++err_destroy_vo:
++ destroy_queue_tx(pio, tx_queue_AC_VO);
++err_destroy_vi:
++ destroy_queue_tx(pio, tx_queue_AC_VI);
++err_destroy_be:
++ destroy_queue_tx(pio, tx_queue_AC_BE);
++err_destroy_bk:
++ destroy_queue_tx(pio, tx_queue_AC_BK);
++ return err;
++}
++
++/* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */
++static struct b43_pio_txqueue * select_queue_by_priority(struct b43_wldev *dev,
++ u8 queue_prio)
++{
++ struct b43_pio_txqueue *q;
++
++ if (b43_modparam_qos) {
++ /* 0 = highest priority */
++ switch (queue_prio) {
++ default:
++ B43_WARN_ON(1);
++ /* fallthrough */
++ case 0:
++ q = dev->pio.tx_queue_AC_VO;
++ break;
++ case 1:
++ q = dev->pio.tx_queue_AC_VI;
++ break;
++ case 2:
++ q = dev->pio.tx_queue_AC_BE;
++ break;
++ case 3:
++ q = dev->pio.tx_queue_AC_BK;
++ break;
++ }
++ } else
++ q = dev->pio.tx_queue_AC_BE;
++
++ return q;
++}
++
++static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
++ u16 ctl,
++ const void *_data,
++ unsigned int data_len)
++{
++ struct b43_wldev *dev = q->dev;
++ const u8 *data = _data;
++
++ ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI;
++ b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
++
++ ssb_block_write(dev->dev, data, (data_len & ~1),
++ q->mmio_base + B43_PIO_TXDATA,
++ sizeof(u16));
++ if (data_len & 1) {
++ /* Write the last byte. */
++ ctl &= ~B43_PIO_TXCTL_WRITEHI;
++ b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
++ b43_piotx_write16(q, B43_PIO_TXDATA, data[data_len - 1]);
++ }
++
++ return ctl;
++}
++
++static void pio_tx_frame_2byte_queue(struct b43_pio_txpacket *pack,
++ const u8 *hdr, unsigned int hdrlen)
++{
++ struct b43_pio_txqueue *q = pack->queue;
++ const char *frame = pack->skb->data;
++ unsigned int frame_len = pack->skb->len;
++ u16 ctl;
++
++ ctl = b43_piotx_read16(q, B43_PIO_TXCTL);
++ ctl |= B43_PIO_TXCTL_FREADY;
++ ctl &= ~B43_PIO_TXCTL_EOF;
++
++ /* Transfer the header data. */
++ ctl = tx_write_2byte_queue(q, ctl, hdr, hdrlen);
++ /* Transfer the frame data. */
++ ctl = tx_write_2byte_queue(q, ctl, frame, frame_len);
++
++ ctl |= B43_PIO_TXCTL_EOF;
++ b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
++}
++
++static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
++ u32 ctl,
++ const void *_data,
++ unsigned int data_len)
++{
++ struct b43_wldev *dev = q->dev;
++ const u8 *data = _data;
++
++ ctl |= B43_PIO8_TXCTL_0_7 | B43_PIO8_TXCTL_8_15 |
++ B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31;
++ b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
++
++ ssb_block_write(dev->dev, data, (data_len & ~3),
++ q->mmio_base + B43_PIO8_TXDATA,
++ sizeof(u32));
++ if (data_len & 3) {
++ u32 value = 0;
++
++ /* Write the last few bytes. */
++ ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 |
++ B43_PIO8_TXCTL_24_31);
++ data = &(data[data_len - 1]);
++ switch (data_len & 3) {
++ case 3:
++ ctl |= B43_PIO8_TXCTL_16_23;
++ value |= (u32)(*data) << 16;
++ data--;
++ case 2:
++ ctl |= B43_PIO8_TXCTL_8_15;
++ value |= (u32)(*data) << 8;
++ data--;
++ case 1:
++ value |= (u32)(*data);
++ }
++ b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
++ b43_piotx_write32(q, B43_PIO8_TXDATA, value);
++ }
++
++ return ctl;
++}
++
++static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack,
++ const u8 *hdr, unsigned int hdrlen)
++{
++ struct b43_pio_txqueue *q = pack->queue;
++ const char *frame = pack->skb->data;
++ unsigned int frame_len = pack->skb->len;
++ u32 ctl;
++
++ ctl = b43_piotx_read32(q, B43_PIO8_TXCTL);
++ ctl |= B43_PIO8_TXCTL_FREADY;
++ ctl &= ~B43_PIO8_TXCTL_EOF;
++
++ /* Transfer the header data. */
++ ctl = tx_write_4byte_queue(q, ctl, hdr, hdrlen);
++ /* Transfer the frame data. */
++ ctl = tx_write_4byte_queue(q, ctl, frame, frame_len);
++
++ ctl |= B43_PIO8_TXCTL_EOF;
++ b43_piotx_write32(q, B43_PIO_TXCTL, ctl);
++}
++
++static int pio_tx_frame(struct b43_pio_txqueue *q,
++ struct sk_buff *skb,
++ struct ieee80211_tx_control *ctl)
++{
++ struct b43_pio_txpacket *pack;
++ struct b43_txhdr txhdr;
++ u16 cookie;
++ int err;
++ unsigned int hdrlen;
++
++ B43_WARN_ON(list_empty(&q->packets_list));
++ pack = list_entry(q->packets_list.next,
++ struct b43_pio_txpacket, list);
++ memset(&pack->txstat, 0, sizeof(pack->txstat));
++ memcpy(&pack->txstat.control, ctl, sizeof(*ctl));
++
++ cookie = generate_cookie(q, pack);
++ hdrlen = b43_txhdr_size(q->dev);
++ err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data,
++ skb->len, ctl, cookie);
++ if (err)
++ return err;
++
++ if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
++ /* Tell the firmware about the cookie of the last
++ * mcast frame, so it can clear the more-data bit in it. */
++ b43_shm_write16(q->dev, B43_SHM_SHARED,
++ B43_SHM_SH_MCASTCOOKIE, cookie);
++ }
++
++ pack->skb = skb;
++ if (q->rev >= 8)
++ pio_tx_frame_4byte_queue(pack, (const u8 *)&txhdr, hdrlen);
++ else
++ pio_tx_frame_2byte_queue(pack, (const u8 *)&txhdr, hdrlen);
++
++ /* Remove it from the list of available packet slots.
++ * It will be put back when we receive the status report. */
++ list_del(&pack->list);
++
++ /* Update the queue statistics. */
++ q->buffer_used += roundup(skb->len + hdrlen, 4);
++ q->free_packet_slots -= 1;
++
++ return 0;
++}
++
++int b43_pio_tx(struct b43_wldev *dev,
++ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
++{
++ struct b43_pio_txqueue *q;
++ struct ieee80211_hdr *hdr;
++ unsigned long flags;
++ unsigned int hdrlen, total_len;
++ int err = 0;
++
++ hdr = (struct ieee80211_hdr *)skb->data;
++ if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
++ /* The multicast queue will be sent after the DTIM. */
++ q = dev->pio.tx_queue_mcast;
++ /* Set the frame More-Data bit. Ucode will clear it
++ * for us on the last frame. */
++ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
++ } else {
++ /* Decide by priority where to put this frame. */
++ q = select_queue_by_priority(dev, ctl->queue);
++ }
++
++ spin_lock_irqsave(&q->lock, flags);
++
++ hdrlen = b43_txhdr_size(dev);
++ total_len = roundup(skb->len + hdrlen, 4);
++
++ if (unlikely(total_len > q->buffer_size)) {
++ err = -ENOBUFS;
++ b43dbg(dev->wl, "PIO: TX packet longer than queue.\n");
++ goto out_unlock;
++ }
++ if (unlikely(q->free_packet_slots == 0)) {
++ err = -ENOBUFS;
++ b43warn(dev->wl, "PIO: TX packet overflow.\n");
++ goto out_unlock;
++ }
++ B43_WARN_ON(q->buffer_used > q->buffer_size);
++
++ if (total_len > (q->buffer_size - q->buffer_used)) {
++ /* Not enough memory on the queue. */
++ err = -EBUSY;
++ ieee80211_stop_queue(dev->wl->hw, ctl->queue);
++ q->stopped = 1;
++ goto out_unlock;
++ }
++
++ /* Assign the queue number to the ring (if not already done before)
++ * so TX status handling can use it. The mac80211-queue to b43-queue
++ * mapping is static, so we don't need to store it per frame. */
++ q->queue_prio = ctl->queue;
++
++ err = pio_tx_frame(q, skb, ctl);
++ if (unlikely(err == -ENOKEY)) {
++ /* Drop this packet, as we don't have the encryption key
++ * anymore and must not transmit it unencrypted. */
++ dev_kfree_skb_any(skb);
++ err = 0;
++ goto out_unlock;
++ }
++ if (unlikely(err)) {
++ b43err(dev->wl, "PIO transmission failure\n");
++ goto out_unlock;
++ }
++ q->nr_tx_packets++;
++
++ B43_WARN_ON(q->buffer_used > q->buffer_size);
++ if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) ||
++ (q->free_packet_slots == 0)) {
++ /* The queue is full. */
++ ieee80211_stop_queue(dev->wl->hw, ctl->queue);
++ q->stopped = 1;
++ }
++
++out_unlock:
++ spin_unlock_irqrestore(&q->lock, flags);
++
++ return err;
++}
++
++/* Called with IRQs disabled. */
++void b43_pio_handle_txstatus(struct b43_wldev *dev,
++ const struct b43_txstatus *status)
++{
++ struct b43_pio_txqueue *q;
++ struct b43_pio_txpacket *pack = NULL;
++ unsigned int total_len;
++
++ q = parse_cookie(dev, status->cookie, &pack);
++ if (unlikely(!q))
++ return;
++ B43_WARN_ON(!pack);
++
++ spin_lock(&q->lock); /* IRQs are already disabled. */
++
++ b43_fill_txstatus_report(&(pack->txstat), status);
++
++ total_len = pack->skb->len + b43_txhdr_size(dev);
++ total_len = roundup(total_len, 4);
++ q->buffer_used -= total_len;
++ q->free_packet_slots += 1;
++
++ ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb,
++ &(pack->txstat));
++ pack->skb = NULL;
++ list_add(&pack->list, &q->packets_list);
++
++ if (q->stopped) {
++ ieee80211_wake_queue(dev->wl->hw, q->queue_prio);
++ q->stopped = 0;
++ }
++
++ spin_unlock(&q->lock);
++}
++
++void b43_pio_get_tx_stats(struct b43_wldev *dev,
++ struct ieee80211_tx_queue_stats *stats)
++{
++ const int nr_queues = dev->wl->hw->queues;
++ struct b43_pio_txqueue *q;
++ struct ieee80211_tx_queue_stats_data *data;
++ unsigned long flags;
++ int i;
++
++ for (i = 0; i < nr_queues; i++) {
++ data = &(stats->data[i]);
++ q = select_queue_by_priority(dev, i);
++
++ spin_lock_irqsave(&q->lock, flags);
++ data->len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots;
++ data->limit = B43_PIO_MAX_NR_TXPACKETS;
++ data->count = q->nr_tx_packets;
++ spin_unlock_irqrestore(&q->lock, flags);
++ }
++}
++
++/* Returns whether we should fetch another frame. */
++static bool pio_rx_frame(struct b43_pio_rxqueue *q)
++{
++ struct b43_wldev *dev = q->dev;
++ struct b43_rxhdr_fw4 rxhdr;
++ u16 len;
++ u32 macstat;
++ unsigned int i, padding;
++ struct sk_buff *skb;
++ const char *err_msg = NULL;
++
++ memset(&rxhdr, 0, sizeof(rxhdr));
++
++ /* Check if we have data and wait for it to get ready. */
++ if (q->rev >= 8) {
++ u32 ctl;
++
++ ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
++ if (!(ctl & B43_PIO8_RXCTL_FRAMERDY))
++ return 0;
++ b43_piorx_write32(q, B43_PIO8_RXCTL,
++ B43_PIO8_RXCTL_FRAMERDY);
++ for (i = 0; i < 10; i++) {
++ ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
++ if (ctl & B43_PIO8_RXCTL_DATARDY)
++ goto data_ready;
++ udelay(10);
++ }
++ } else {
++ u16 ctl;
++
++ ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
++ if (!(ctl & B43_PIO_RXCTL_FRAMERDY))
++ return 0;
++ b43_piorx_write16(q, B43_PIO_RXCTL,
++ B43_PIO_RXCTL_FRAMERDY);
++ for (i = 0; i < 10; i++) {
++ ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
++ if (ctl & B43_PIO_RXCTL_DATARDY)
++ goto data_ready;
++ udelay(10);
++ }
++ }
++ b43dbg(q->dev->wl, "PIO RX timed out\n");
++ return 1;
++data_ready:
++
++ /* Get the preamble (RX header) */
++ if (q->rev >= 8) {
++ ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr),
++ q->mmio_base + B43_PIO8_RXDATA,
++ sizeof(u32));
++ } else {
++ ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr),
++ q->mmio_base + B43_PIO_RXDATA,
++ sizeof(u16));
++ }
++ /* Sanity checks. */
++ len = le16_to_cpu(rxhdr.frame_len);
++ if (unlikely(len > 0x700)) {
++ err_msg = "len > 0x700";
++ goto rx_error;
++ }
++ if (unlikely(len == 0)) {
++ err_msg = "len == 0";
++ goto rx_error;
++ }
++
++ macstat = le32_to_cpu(rxhdr.mac_status);
++ if (macstat & B43_RX_MAC_FCSERR) {
++ if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
++ /* Drop frames with failed FCS. */
++ err_msg = "Frame FCS error";
++ goto rx_error;
++ }
++ }
++
++ /* We always pad 2 bytes, as that's what upstream code expects
++ * due to the RX-header being 30 bytes. In case the frame is
++ * unaligned, we pad another 2 bytes. */
++ padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
++ skb = dev_alloc_skb(len + padding + 2);
++ if (unlikely(!skb)) {
++ err_msg = "Out of memory";
++ goto rx_error;
++ }
++ skb_reserve(skb, 2);
++ skb_put(skb, len + padding);
++ if (q->rev >= 8) {
++ ssb_block_read(dev->dev, skb->data + padding, (len & ~3),
++ q->mmio_base + B43_PIO8_RXDATA,
++ sizeof(u32));
++ if (len & 3) {
++ u32 value;
++ char *data;
++
++ /* Read the last few bytes. */
++ value = b43_piorx_read32(q, B43_PIO8_RXDATA);
++ data = &(skb->data[len + padding - 1]);
++ switch (len & 3) {
++ case 3:
++ *data = (value >> 16);
++ data--;
++ case 2:
++ *data = (value >> 8);
++ data--;
++ case 1:
++ *data = value;
++ }
++ }
++ } else {
++ ssb_block_read(dev->dev, skb->data + padding, (len & ~1),
++ q->mmio_base + B43_PIO_RXDATA,
++ sizeof(u16));
++ if (len & 1) {
++ u16 value;
++
++ /* Read the last byte. */
++ value = b43_piorx_read16(q, B43_PIO_RXDATA);
++ skb->data[len + padding - 1] = value;
++ }
++ }
++
++ b43_rx(q->dev, skb, &rxhdr);
++
++ return 1;
++
++rx_error:
++ if (err_msg)
++ b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg);
++ b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
++ return 1;
++}
++
++/* RX workqueue. We can sleep, yay! */
++static void b43_pio_rx_work(struct work_struct *work)
++{
++ struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue,
++ rx_work);
++ unsigned int budget = 50;
++ bool stop;
++
++ do {
++ spin_lock_irq(&q->lock);
++ stop = (pio_rx_frame(q) == 0);
++ spin_unlock_irq(&q->lock);
++ cond_resched();
++ if (stop)
++ break;
++ } while (--budget);
++}
++
++/* Called with IRQs disabled. */
++void b43_pio_rx(struct b43_pio_rxqueue *q)
++{
++ /* Due to latency issues we must run the RX path in
++ * a workqueue to be able to schedule between packets. */
++ queue_work(q->dev->wl->hw->workqueue, &q->rx_work);
++}
++
++static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&q->lock, flags);
++ if (q->rev >= 8) {
++ b43_piotx_write32(q, B43_PIO8_TXCTL,
++ b43_piotx_read32(q, B43_PIO8_TXCTL)
++ | B43_PIO8_TXCTL_SUSPREQ);
++ } else {
++ b43_piotx_write16(q, B43_PIO_TXCTL,
++ b43_piotx_read16(q, B43_PIO_TXCTL)
++ | B43_PIO_TXCTL_SUSPREQ);
++ }
++ spin_unlock_irqrestore(&q->lock, flags);
++}
++
++static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&q->lock, flags);
++ if (q->rev >= 8) {
++ b43_piotx_write32(q, B43_PIO8_TXCTL,
++ b43_piotx_read32(q, B43_PIO8_TXCTL)
++ & ~B43_PIO8_TXCTL_SUSPREQ);
++ } else {
++ b43_piotx_write16(q, B43_PIO_TXCTL,
++ b43_piotx_read16(q, B43_PIO_TXCTL)
++ & ~B43_PIO_TXCTL_SUSPREQ);
++ }
++ spin_unlock_irqrestore(&q->lock, flags);
++}
++
++void b43_pio_tx_suspend(struct b43_wldev *dev)
++{
++ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
++ b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BK);
++ b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BE);
++ b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VI);
++ b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VO);
++ b43_pio_tx_suspend_queue(dev->pio.tx_queue_mcast);
++}
++
++void b43_pio_tx_resume(struct b43_wldev *dev)
++{
++ b43_pio_tx_resume_queue(dev->pio.tx_queue_mcast);
++ b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VO);
++ b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VI);
++ b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BE);
++ b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BK);
++ b43_power_saving_ctl_bits(dev, 0);
++}
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/pio.h linux-2.6.25/drivers/net/wireless/b43/pio.h
+--- linux-2.6.25.old/drivers/net/wireless/b43/pio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.25/drivers/net/wireless/b43/pio.h 2008-04-19 13:54:59.000000000 +0200
+@@ -0,0 +1,220 @@
++#ifndef B43_PIO_H_
++#define B43_PIO_H_
++
++#include "b43.h"
++
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/list.h>
++#include <linux/skbuff.h>
++
++
++/*** Registers for PIO queues up to revision 7. ***/
++/* TX queue. */
++#define B43_PIO_TXCTL 0x00
++#define B43_PIO_TXCTL_WRITELO 0x0001
++#define B43_PIO_TXCTL_WRITEHI 0x0002
++#define B43_PIO_TXCTL_EOF 0x0004
++#define B43_PIO_TXCTL_FREADY 0x0008
++#define B43_PIO_TXCTL_FLUSHREQ 0x0020
++#define B43_PIO_TXCTL_FLUSHPEND 0x0040
++#define B43_PIO_TXCTL_SUSPREQ 0x0080
++#define B43_PIO_TXCTL_QSUSP 0x0100
++#define B43_PIO_TXCTL_COMMCNT 0xFC00
++#define B43_PIO_TXCTL_COMMCNT_SHIFT 10
++#define B43_PIO_TXDATA 0x02
++#define B43_PIO_TXQBUFSIZE 0x04
++/* RX queue. */
++#define B43_PIO_RXCTL 0x00
++#define B43_PIO_RXCTL_FRAMERDY 0x0001
++#define B43_PIO_RXCTL_DATARDY 0x0002
++#define B43_PIO_RXDATA 0x02
++
++/*** Registers for PIO queues revision 8 and later. ***/
++/* TX queue */
++#define B43_PIO8_TXCTL 0x00
++#define B43_PIO8_TXCTL_0_7 0x00000001
++#define B43_PIO8_TXCTL_8_15 0x00000002
++#define B43_PIO8_TXCTL_16_23 0x00000004
++#define B43_PIO8_TXCTL_24_31 0x00000008
++#define B43_PIO8_TXCTL_EOF 0x00000010
++#define B43_PIO8_TXCTL_FREADY 0x00000080
++#define B43_PIO8_TXCTL_SUSPREQ 0x00000100
++#define B43_PIO8_TXCTL_QSUSP 0x00000200
++#define B43_PIO8_TXCTL_FLUSHREQ 0x00000400
++#define B43_PIO8_TXCTL_FLUSHPEND 0x00000800
++#define B43_PIO8_TXDATA 0x04
++/* RX queue */
++#define B43_PIO8_RXCTL 0x00
++#define B43_PIO8_RXCTL_FRAMERDY 0x00000001
++#define B43_PIO8_RXCTL_DATARDY 0x00000002
++#define B43_PIO8_RXDATA 0x04
++
++
++/* The maximum number of TX-packets the HW can handle. */
++#define B43_PIO_MAX_NR_TXPACKETS 32
++
++
++#ifdef CONFIG_B43_PIO
++
++struct b43_pio_txpacket {
++ /* Pointer to the TX queue we belong to. */
++ struct b43_pio_txqueue *queue;
++ /* The TX data packet. */
++ struct sk_buff *skb;
++ /* The status meta data. */
++ struct ieee80211_tx_status txstat;
++ /* Index in the (struct b43_pio_txqueue)->packets array. */
++ u8 index;
++
++ struct list_head list;
++};
++
++struct b43_pio_txqueue {
++ struct b43_wldev *dev;
++ spinlock_t lock;
++ u16 mmio_base;
++
++ /* The device queue buffer size in bytes. */
++ u16 buffer_size;
++ /* The number of used bytes in the device queue buffer. */
++ u16 buffer_used;
++ /* The number of packets that can still get queued.
++ * This is decremented on queueing a packet and incremented
++ * after receiving the transmit status. */
++ u16 free_packet_slots;
++
++ /* True, if the mac80211 queue was stopped due to overflow at TX. */
++ bool stopped;
++ /* Our b43 queue index number */
++ u8 index;
++ /* The mac80211 QoS queue priority. */
++ u8 queue_prio;
++
++ /* Buffer for TX packet meta data. */
++ struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS];
++ struct list_head packets_list;
++
++ /* Total number of transmitted packets. */
++ unsigned int nr_tx_packets;
++
++ /* Shortcut to the 802.11 core revision. This is to
++ * avoid horrible pointer dereferencing in the fastpaths. */
++ u8 rev;
++};
++
++struct b43_pio_rxqueue {
++ struct b43_wldev *dev;
++ spinlock_t lock;
++ u16 mmio_base;
++
++ /* Work to reduce latency issues on RX. */
++ struct work_struct rx_work;
++
++ /* Shortcut to the 802.11 core revision. This is to
++ * avoid horrible pointer dereferencing in the fastpaths. */
++ u8 rev;
++};
++
++
++static inline u16 b43_piotx_read16(struct b43_pio_txqueue *q, u16 offset)
++{
++ return b43_read16(q->dev, q->mmio_base + offset);
++}
++
++static inline u32 b43_piotx_read32(struct b43_pio_txqueue *q, u16 offset)
++{
++ return b43_read32(q->dev, q->mmio_base + offset);
++}
++
++static inline void b43_piotx_write16(struct b43_pio_txqueue *q,
++ u16 offset, u16 value)
++{
++ b43_write16(q->dev, q->mmio_base + offset, value);
++}
++
++static inline void b43_piotx_write32(struct b43_pio_txqueue *q,
++ u16 offset, u32 value)
++{
++ b43_write32(q->dev, q->mmio_base + offset, value);
++}
++
++
++static inline u16 b43_piorx_read16(struct b43_pio_rxqueue *q, u16 offset)
++{
++ return b43_read16(q->dev, q->mmio_base + offset);
++}
++
++static inline u32 b43_piorx_read32(struct b43_pio_rxqueue *q, u16 offset)
++{
++ return b43_read32(q->dev, q->mmio_base + offset);
++}
++
++static inline void b43_piorx_write16(struct b43_pio_rxqueue *q,
++ u16 offset, u16 value)
++{
++ b43_write16(q->dev, q->mmio_base + offset, value);
++}
++
++static inline void b43_piorx_write32(struct b43_pio_rxqueue *q,
++ u16 offset, u32 value)
++{
++ b43_write32(q->dev, q->mmio_base + offset, value);
++}
++
++
++int b43_pio_init(struct b43_wldev *dev);
++void b43_pio_stop(struct b43_wldev *dev);
++void b43_pio_free(struct b43_wldev *dev);
++
++int b43_pio_tx(struct b43_wldev *dev,
++ struct sk_buff *skb, struct ieee80211_tx_control *ctl);
++void b43_pio_handle_txstatus(struct b43_wldev *dev,
++ const struct b43_txstatus *status);
++void b43_pio_get_tx_stats(struct b43_wldev *dev,
++ struct ieee80211_tx_queue_stats *stats);
++void b43_pio_rx(struct b43_pio_rxqueue *q);
++
++void b43_pio_tx_suspend(struct b43_wldev *dev);
++void b43_pio_tx_resume(struct b43_wldev *dev);
++
++
++#else /* CONFIG_B43_PIO */
++
++
++static inline int b43_pio_init(struct b43_wldev *dev)
++{
++ return 0;
++}
++static inline void b43_pio_free(struct b43_wldev *dev)
++{
++}
++static inline void b43_pio_stop(struct b43_wldev *dev)
++{
++}
++static inline int b43_pio_tx(struct b43_wldev *dev,
++ struct sk_buff *skb,
++ struct ieee80211_tx_control *ctl)
++{
++ return 0;
++}
++static inline void b43_pio_handle_txstatus(struct b43_wldev *dev,
++ const struct b43_txstatus *status)
++{
++}
++static inline void b43_pio_get_tx_stats(struct b43_wldev *dev,
++ struct ieee80211_tx_queue_stats *stats)
++{
++}
++static inline void b43_pio_rx(struct b43_pio_rxqueue *q)
++{
++}
++static inline void b43_pio_tx_suspend(struct b43_wldev *dev)
++{
++}
++static inline void b43_pio_tx_resume(struct b43_wldev *dev)
++{
++}
++
++#endif /* CONFIG_B43_PIO */
++#endif /* B43_PIO_H_ */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/sysfs.c linux-2.6.25/drivers/net/wireless/b43/sysfs.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/sysfs.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/sysfs.c 2008-04-19 13:54:59.000000000 +0200
+@@ -47,29 +47,6 @@
+ return ret;
+ }
+
+-static int get_boolean(const char *buf, size_t count)
+-{
+- if (count != 0) {
+- if (buf[0] == '1')
+- return 1;
+- if (buf[0] == '0')
+- return 0;
+- if (count >= 4 && memcmp(buf, "true", 4) == 0)
+- return 1;
+- if (count >= 5 && memcmp(buf, "false", 5) == 0)
+- return 0;
+- if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+- return 1;
+- if (count >= 2 && memcmp(buf, "no", 2) == 0)
+- return 0;
+- if (count >= 2 && memcmp(buf, "on", 2) == 0)
+- return 1;
+- if (count >= 3 && memcmp(buf, "off", 3) == 0)
+- return 0;
+- }
+- return -EINVAL;
+-}
+-
+ static ssize_t b43_attr_interfmode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+@@ -155,82 +132,18 @@
+ static DEVICE_ATTR(interference, 0644,
+ b43_attr_interfmode_show, b43_attr_interfmode_store);
+
+-static ssize_t b43_attr_preamble_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+- ssize_t count;
+-
+- if (!capable(CAP_NET_ADMIN))
+- return -EPERM;
+-
+- mutex_lock(&wldev->wl->mutex);
+-
+- if (wldev->short_preamble)
+- count =
+- snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
+- else
+- count =
+- snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
+-
+- mutex_unlock(&wldev->wl->mutex);
+-
+- return count;
+-}
+-
+-static ssize_t b43_attr_preamble_store(struct device *dev,
+- struct device_attribute *attr,
+- const char *buf, size_t count)
+-{
+- struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+- unsigned long flags;
+- int value;
+-
+- if (!capable(CAP_NET_ADMIN))
+- return -EPERM;
+-
+- value = get_boolean(buf, count);
+- if (value < 0)
+- return value;
+- mutex_lock(&wldev->wl->mutex);
+- spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+-
+- wldev->short_preamble = !!value;
+-
+- spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+- mutex_unlock(&wldev->wl->mutex);
+-
+- return count;
+-}
+-
+-static DEVICE_ATTR(shortpreamble, 0644,
+- b43_attr_preamble_show, b43_attr_preamble_store);
+-
+ int b43_sysfs_register(struct b43_wldev *wldev)
+ {
+ struct device *dev = wldev->dev->dev;
+- int err;
+
+ B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
+
+- err = device_create_file(dev, &dev_attr_interference);
+- if (err)
+- goto out;
+- err = device_create_file(dev, &dev_attr_shortpreamble);
+- if (err)
+- goto err_remove_interfmode;
+-
+- out:
+- return err;
+- err_remove_interfmode:
+- device_remove_file(dev, &dev_attr_interference);
+- goto out;
++ return device_create_file(dev, &dev_attr_interference);
+ }
+
+ void b43_sysfs_unregister(struct b43_wldev *wldev)
+ {
+ struct device *dev = wldev->dev->dev;
+
+- device_remove_file(dev, &dev_attr_shortpreamble);
+ device_remove_file(dev, &dev_attr_interference);
+ }
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/wa.c linux-2.6.25/drivers/net/wireless/b43/wa.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/wa.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/wa.c 2008-04-19 13:54:59.000000000 +0200
+@@ -204,42 +204,43 @@
+ b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]);
+ }
+
++static void b43_write_null_nst(struct b43_wldev *dev)
++{
++ int i;
++
++ for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
++ b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, 0);
++}
++
++static void b43_write_nst(struct b43_wldev *dev, const u16 *nst)
++{
++ int i;
++
++ for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
++ b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, nst[i]);
++}
++
+ static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */
+ {
+ struct b43_phy *phy = &dev->phy;
+- int i;
+
+ if (phy->type == B43_PHYTYPE_A) {
+ if (phy->rev <= 1)
+- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+- i, 0);
++ b43_write_null_nst(dev);
+ else if (phy->rev == 2)
+- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+- i, b43_tab_noisescalea2[i]);
++ b43_write_nst(dev, b43_tab_noisescalea2);
+ else if (phy->rev == 3)
+- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+- i, b43_tab_noisescalea3[i]);
++ b43_write_nst(dev, b43_tab_noisescalea3);
+ else
+- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+- i, b43_tab_noisescaleg3[i]);
++ b43_write_nst(dev, b43_tab_noisescaleg3);
+ } else {
+ if (phy->rev >= 6) {
+ if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+- i, b43_tab_noisescaleg3[i]);
++ b43_write_nst(dev, b43_tab_noisescaleg3);
+ else
+- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+- i, b43_tab_noisescaleg2[i]);
++ b43_write_nst(dev, b43_tab_noisescaleg2);
+ } else {
+- for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+- b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+- i, b43_tab_noisescaleg1[i]);
++ b43_write_nst(dev, b43_tab_noisescaleg1);
+ }
+ }
+ }
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/xmit.c linux-2.6.25/drivers/net/wireless/b43/xmit.c
+--- linux-2.6.25.old/drivers/net/wireless/b43/xmit.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/xmit.c 2008-04-19 13:54:59.000000000 +0200
+@@ -30,48 +30,51 @@
+ #include "xmit.h"
+ #include "phy.h"
+ #include "dma.h"
++#include "pio.h"
+
+
+-/* Extract the bitrate out of a CCK PLCP header. */
+-static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
++/* Extract the bitrate index out of a CCK PLCP header. */
++static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
+ {
+ switch (plcp->raw[0]) {
+ case 0x0A:
+- return B43_CCK_RATE_1MB;
++ return 0;
+ case 0x14:
+- return B43_CCK_RATE_2MB;
++ return 1;
+ case 0x37:
+- return B43_CCK_RATE_5MB;
++ return 2;
+ case 0x6E:
+- return B43_CCK_RATE_11MB;
++ return 3;
+ }
+ B43_WARN_ON(1);
+- return 0;
++ return -1;
+ }
+
+-/* Extract the bitrate out of an OFDM PLCP header. */
+-static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
++/* Extract the bitrate index out of an OFDM PLCP header. */
++static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
+ {
++ int base = aphy ? 0 : 4;
++
+ switch (plcp->raw[0] & 0xF) {
+ case 0xB:
+- return B43_OFDM_RATE_6MB;
++ return base + 0;
+ case 0xF:
+- return B43_OFDM_RATE_9MB;
++ return base + 1;
+ case 0xA:
+- return B43_OFDM_RATE_12MB;
++ return base + 2;
+ case 0xE:
+- return B43_OFDM_RATE_18MB;
++ return base + 3;
+ case 0x9:
+- return B43_OFDM_RATE_24MB;
++ return base + 4;
+ case 0xD:
+- return B43_OFDM_RATE_36MB;
++ return base + 5;
+ case 0x8:
+- return B43_OFDM_RATE_48MB;
++ return base + 6;
+ case 0xC:
+- return B43_OFDM_RATE_54MB;
++ return base + 7;
+ }
+ B43_WARN_ON(1);
+- return 0;
++ return -1;
+ }
+
+ u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
+@@ -191,6 +194,7 @@
+ (const struct ieee80211_hdr *)fragment_data;
+ int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ u16 fctl = le16_to_cpu(wlhdr->frame_control);
++ struct ieee80211_rate *fbrate;
+ u8 rate, rate_fb;
+ int rate_ofdm, rate_fb_ofdm;
+ unsigned int plcp_fragment_len;
+@@ -200,9 +204,11 @@
+
+ memset(txhdr, 0, sizeof(*txhdr));
+
+- rate = txctl->tx_rate;
++ WARN_ON(!txctl->tx_rate);
++ rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
+ rate_ofdm = b43_is_ofdm_rate(rate);
+- rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
++ fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
++ rate_fb = fbrate->hw_value;
+ rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
+
+ if (rate_ofdm)
+@@ -221,11 +227,10 @@
+ * use the original dur_id field. */
+ txhdr->dur_fb = wlhdr->duration_id;
+ } else {
+- int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
+ txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+ txctl->vif,
+ fragment_len,
+- fbrate_base100kbps);
++ fbrate);
+ }
+
+ plcp_fragment_len = fragment_len + FCS_LEN;
+@@ -287,7 +292,7 @@
+ phy_ctl |= B43_TXH_PHY_ENC_OFDM;
+ else
+ phy_ctl |= B43_TXH_PHY_ENC_CCK;
+- if (dev->short_preamble)
++ if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+ phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
+
+ switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
+@@ -332,7 +337,8 @@
+ int rts_rate_ofdm, rts_rate_fb_ofdm;
+ struct b43_plcp_hdr6 *plcp;
+
+- rts_rate = txctl->rts_cts_rate;
++ WARN_ON(!txctl->rts_cts_rate);
++ rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
+ rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
+ rts_rate_fb = b43_calc_fallback_rate(rts_rate);
+ rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
+@@ -506,7 +512,7 @@
+ u16 phystat0, phystat3, chanstat, mactime;
+ u32 macstat;
+ u16 chanid;
+- u8 jssi;
++ u16 phytype;
+ int padding;
+
+ memset(&status, 0, sizeof(status));
+@@ -514,10 +520,10 @@
+ /* Get metadata about the frame from the header. */
+ phystat0 = le16_to_cpu(rxhdr->phy_status0);
+ phystat3 = le16_to_cpu(rxhdr->phy_status3);
+- jssi = rxhdr->jssi;
+ macstat = le32_to_cpu(rxhdr->mac_status);
+ mactime = le16_to_cpu(rxhdr->mac_time);
+ chanstat = le16_to_cpu(rxhdr->channel);
++ phytype = chanstat & B43_RX_CHAN_PHYTYPE;
+
+ if (macstat & B43_RX_MAC_FCSERR)
+ dev->wl->ieee_stats.dot11FCSErrorCount++;
+@@ -567,26 +573,40 @@
+ }
+ }
+
+- status.ssi = b43_rssi_postprocess(dev, jssi,
++ /* Link quality statistics */
++ status.noise = dev->stats.link_noise;
++ if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) {
++// s8 rssi = max(rxhdr->power0, rxhdr->power1);
++ //TODO: Find out what the rssi value is (dBm or percentage?)
++ // and also find out what the maximum possible value is.
++ // Fill status.ssi and status.signal fields.
++ } else {
++ status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi,
+ (phystat0 & B43_RX_PHYST0_OFDM),
+ (phystat0 & B43_RX_PHYST0_GAINCTL),
+ (phystat3 & B43_RX_PHYST3_TRSTATE));
+- status.noise = dev->stats.link_noise;
+ /* the next line looks wrong, but is what mac80211 wants */
+- status.signal = (jssi * 100) / B43_RX_MAX_SSI;
++ status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
++ }
++
+ if (phystat0 & B43_RX_PHYST0_OFDM)
+- status.rate = b43_plcp_get_bitrate_ofdm(plcp);
++ status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
++ phytype == B43_PHYTYPE_A);
+ else
+- status.rate = b43_plcp_get_bitrate_cck(plcp);
++ status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
+ status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
+
+ /*
+- * If monitors are present get full 64-bit timestamp. This
+- * code assumes we get to process the packet within 16 bits
+- * of timestamp, i.e. about 65 milliseconds after the PHY
+- * received the first symbol.
++ * All frames on monitor interfaces and beacons always need a full
++ * 64-bit timestamp. Monitor interfaces need it for diagnostic
++ * purposes and beacons for IBSS merging.
++ * This code assumes we get to process the packet within 16 bits
++ * of timestamp, i.e. about 65 milliseconds after the PHY received
++ * the first symbol.
+ */
+- if (dev->wl->radiotap_enabled) {
++ if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
++ == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
++ dev->wl->radiotap_enabled) {
+ u16 low_mactime_now;
+
+ b43_tsf_read(dev, &status.mactime);
+@@ -601,29 +621,28 @@
+ chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
+ switch (chanstat & B43_RX_CHAN_PHYTYPE) {
+ case B43_PHYTYPE_A:
+- status.phymode = MODE_IEEE80211A;
++ status.band = IEEE80211_BAND_5GHZ;
+ B43_WARN_ON(1);
+ /* FIXME: We don't really know which value the "chanid" contains.
+ * So the following assignment might be wrong. */
+- status.channel = chanid;
+- status.freq = b43_channel_to_freq_5ghz(status.channel);
++ status.freq = b43_channel_to_freq_5ghz(chanid);
+ break;
+ case B43_PHYTYPE_G:
+- status.phymode = MODE_IEEE80211G;
++ status.band = IEEE80211_BAND_2GHZ;
+ /* chanid is the radio channel cookie value as used
+ * to tune the radio. */
+ status.freq = chanid + 2400;
+- status.channel = b43_freq_to_channel_2ghz(status.freq);
+ break;
+ case B43_PHYTYPE_N:
+- status.phymode = 0xDEAD /*FIXME MODE_IEEE80211N*/;
+ /* chanid is the SHM channel cookie. Which is the plain
+ * channel number in b43. */
+- status.channel = chanid;
+- if (chanstat & B43_RX_CHAN_5GHZ)
+- status.freq = b43_freq_to_channel_5ghz(status.freq);
+- else
+- status.freq = b43_freq_to_channel_2ghz(status.freq);
++ if (chanstat & B43_RX_CHAN_5GHZ) {
++ status.band = IEEE80211_BAND_5GHZ;
++ status.freq = b43_freq_to_channel_5ghz(chanid);
++ } else {
++ status.band = IEEE80211_BAND_2GHZ;
++ status.freq = b43_freq_to_channel_2ghz(chanid);
++ }
+ break;
+ default:
+ B43_WARN_ON(1);
+@@ -657,67 +676,54 @@
+ dev->wl->ieee_stats.dot11RTSSuccessCount++;
+ }
+
++ if (b43_using_pio_transfers(dev))
++ b43_pio_handle_txstatus(dev, status);
++ else
+ b43_dma_handle_txstatus(dev, status);
+ }
+
+-/* Handle TX status report as received through DMA/PIO queues */
+-void b43_handle_hwtxstatus(struct b43_wldev *dev,
+- const struct b43_hwtxstatus *hw)
+-{
+- struct b43_txstatus status;
+- u8 tmp;
+-
+- status.cookie = le16_to_cpu(hw->cookie);
+- status.seq = le16_to_cpu(hw->seq);
+- status.phy_stat = hw->phy_stat;
+- tmp = hw->count;
+- status.frame_count = (tmp >> 4);
+- status.rts_count = (tmp & 0x0F);
+- tmp = hw->flags;
+- status.supp_reason = ((tmp & 0x1C) >> 2);
+- status.pm_indicated = !!(tmp & 0x80);
+- status.intermediate = !!(tmp & 0x40);
+- status.for_ampdu = !!(tmp & 0x20);
+- status.acked = !!(tmp & 0x02);
++/* Fill out the mac80211 TXstatus report based on the b43-specific
++ * txstatus report data. This returns a boolean whether the frame was
++ * successfully transmitted. */
++bool b43_fill_txstatus_report(struct ieee80211_tx_status *report,
++ const struct b43_txstatus *status)
++{
++ bool frame_success = 1;
+
+- b43_handle_txstatus(dev, &status);
++ if (status->acked) {
++ /* The frame was ACKed. */
++ report->flags |= IEEE80211_TX_STATUS_ACK;
++ } else {
++ /* The frame was not ACKed... */
++ if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) {
++ /* ...but we expected an ACK. */
++ frame_success = 0;
++ report->excessive_retries = 1;
++ }
++ }
++ if (status->frame_count == 0) {
++ /* The frame was not transmitted at all. */
++ report->retry_count = 0;
++ } else
++ report->retry_count = status->frame_count - 1;
++
++ return frame_success;
+ }
+
+ /* Stop any TX operation on the device (suspend the hardware queues) */
+ void b43_tx_suspend(struct b43_wldev *dev)
+ {
++ if (b43_using_pio_transfers(dev))
++ b43_pio_tx_suspend(dev);
++ else
+ b43_dma_tx_suspend(dev);
+ }
+
+ /* Resume any TX operation on the device (resume the hardware queues) */
+ void b43_tx_resume(struct b43_wldev *dev)
+ {
++ if (b43_using_pio_transfers(dev))
++ b43_pio_tx_resume(dev);
++ else
+ b43_dma_tx_resume(dev);
+ }
+-
+-#if 0
+-static void upload_qos_parms(struct b43_wldev *dev,
+- const u16 * parms, u16 offset)
+-{
+- int i;
+-
+- for (i = 0; i < B43_NR_QOSPARMS; i++) {
+- b43_shm_write16(dev, B43_SHM_SHARED,
+- offset + (i * 2), parms[i]);
+- }
+-}
+-#endif
+-
+-/* Initialize the QoS parameters */
+-void b43_qos_init(struct b43_wldev *dev)
+-{
+- /* FIXME: This function must probably be called from the mac80211
+- * config callback. */
+- return;
+-
+- b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
+- //FIXME kill magic
+- b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
+-
+- /*TODO: We might need some stack support here to get the values. */
+-}
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43/xmit.h linux-2.6.25/drivers/net/wireless/b43/xmit.h
+--- linux-2.6.25.old/drivers/net/wireless/b43/xmit.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43/xmit.h 2008-04-19 13:54:59.000000000 +0200
+@@ -207,25 +207,24 @@
+ B43_TXST_SUPP_ABNACK, /* Afterburner NACK */
+ };
+
+-/* Transmit Status as received through DMA/PIO on old chips */
+-struct b43_hwtxstatus {
+- PAD_BYTES(4);
+- __le16 cookie;
+- u8 flags;
+- u8 count;
+- PAD_BYTES(2);
+- __le16 seq;
+- u8 phy_stat;
+- PAD_BYTES(1);
+-} __attribute__ ((__packed__));
+-
+ /* Receive header for v4 firmware. */
+ struct b43_rxhdr_fw4 {
+ __le16 frame_len; /* Frame length */
+ PAD_BYTES(2);
+ __le16 phy_status0; /* PHY RX Status 0 */
++ union {
++ /* RSSI for A/B/G-PHYs */
++ struct {
+ __u8 jssi; /* PHY RX Status 1: JSSI */
+ __u8 sig_qual; /* PHY RX Status 1: Signal Quality */
++ } __attribute__ ((__packed__));
++
++ /* RSSI for N-PHYs */
++ struct {
++ __s8 power0; /* PHY RX Status 1: Power 0 */
++ __s8 power1; /* PHY RX Status 1: Power 1 */
++ } __attribute__ ((__packed__));
++ } __attribute__ ((__packed__));
+ __le16 phy_status2; /* PHY RX Status 2 */
+ __le16 phy_status3; /* PHY RX Status 3 */
+ __le32 mac_status; /* MAC RX status */
+@@ -295,25 +294,12 @@
+
+ void b43_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+-
+-void b43_handle_hwtxstatus(struct b43_wldev *dev,
+- const struct b43_hwtxstatus *hw);
++bool b43_fill_txstatus_report(struct ieee80211_tx_status *report,
++ const struct b43_txstatus *status);
+
+ void b43_tx_suspend(struct b43_wldev *dev);
+ void b43_tx_resume(struct b43_wldev *dev);
+
+-#define B43_NR_QOSPARMS 22
+-enum {
+- B43_QOSPARM_TXOP = 0,
+- B43_QOSPARM_CWMIN,
+- B43_QOSPARM_CWMAX,
+- B43_QOSPARM_CWCUR,
+- B43_QOSPARM_AIFS,
+- B43_QOSPARM_BSLOTS,
+- B43_QOSPARM_REGGAP,
+- B43_QOSPARM_STATUS,
+-};
+-void b43_qos_init(struct b43_wldev *dev);
+
+ /* Helper functions for converting the key-table index from "firmware-format"
+ * to "raw-format" and back. The firmware API changed for this at some revision.
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43legacy/b43legacy.h linux-2.6.25/drivers/net/wireless/b43legacy/b43legacy.h
+--- linux-2.6.25.old/drivers/net/wireless/b43legacy/b43legacy.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43legacy/b43legacy.h 2008-04-19 13:54:59.000000000 +0200
+@@ -97,6 +97,7 @@
+ #define B43legacy_MMIO_RADIO_HWENABLED_LO 0x49A
+ #define B43legacy_MMIO_GPIO_CONTROL 0x49C
+ #define B43legacy_MMIO_GPIO_MASK 0x49E
++#define B43legacy_MMIO_TSF_CFP_PRETBTT 0x612
+ #define B43legacy_MMIO_TSF_0 0x632 /* core rev < 3 only */
+ #define B43legacy_MMIO_TSF_1 0x634 /* core rev < 3 only */
+ #define B43legacy_MMIO_TSF_2 0x636 /* core rev < 3 only */
+@@ -130,19 +131,27 @@
+ #define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */
+ /* SHM_SHARED crypto engine */
+ #define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */
+-/* SHM_SHARED beacon variables */
++/* SHM_SHARED beacon/AP variables */
++#define B43legacy_SHM_SH_DTIMP 0x0012 /* DTIM period */
++#define B43legacy_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
++#define B43legacy_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
++#define B43legacy_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
++#define B43legacy_SHM_SH_TIMPOS 0x001E /* TIM position in beacon */
+ #define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */
+ /* SHM_SHARED ACK/CTS control */
+ #define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */
+ /* SHM_SHARED probe response variables */
+-#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
++#define B43legacy_SHM_SH_PRTLEN 0x004A /* Probe Response template length */
+ #define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
++#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
+ /* SHM_SHARED rate tables */
+ /* SHM_SHARED microcode soft registers */
+ #define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
+ #define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
+ #define B43legacy_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
+ #define B43legacy_SHM_SH_UCODETIME 0x0006 /* Microcode time */
++#define B43legacy_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
++#define B43legacy_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
+
+ #define B43legacy_UCODEFLAGS_OFFSET 0x005E
+
+@@ -199,6 +208,13 @@
+ #define B43legacy_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */
+ #define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */
+
++/* MAC Command bitfield */
++#define B43legacy_MACCMD_BEACON0_VALID 0x00000001 /* Beacon 0 in template RAM is busy/valid */
++#define B43legacy_MACCMD_BEACON1_VALID 0x00000002 /* Beacon 1 in template RAM is busy/valid */
++#define B43legacy_MACCMD_DFQ_VALID 0x00000004 /* Directed frame queue valid (IBSS PS mode, ATIM) */
++#define B43legacy_MACCMD_CCA 0x00000008 /* Clear channel assessment */
++#define B43legacy_MACCMD_BGNOISE 0x00000010 /* Background noise */
++
+ /* 802.11 core specific TM State Low flags */
+ #define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
+ #define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */
+@@ -317,15 +333,7 @@
+ # undef assert
+ #endif
+ #ifdef CONFIG_B43LEGACY_DEBUG
+-# define B43legacy_WARN_ON(expr) \
+- do { \
+- if (unlikely((expr))) { \
+- printk(KERN_INFO PFX "Test (%s) failed at:" \
+- " %s:%d:%s()\n", \
+- #expr, __FILE__, \
+- __LINE__, __FUNCTION__); \
+- } \
+- } while (0)
++# define B43legacy_WARN_ON(x) WARN_ON(x)
+ # define B43legacy_BUG_ON(expr) \
+ do { \
+ if (unlikely((expr))) { \
+@@ -336,7 +344,9 @@
+ } while (0)
+ # define B43legacy_DEBUG 1
+ #else
+-# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0)
++/* This will evaluate the argument even if debugging is disabled. */
++static inline bool __b43legacy_warn_on_dummy(bool x) { return x; }
++# define B43legacy_WARN_ON(x) __b43legacy_warn_on_dummy(unlikely(!!(x)))
+ # define B43legacy_BUG_ON(x) do { /* nothing */ } while (0)
+ # define B43legacy_DEBUG 0
+ #endif
+@@ -392,10 +402,6 @@
+ u8 possible_phymodes;
+ /* GMODE bit enabled in MACCTL? */
+ bool gmode;
+- /* Possible ieee80211 subsystem hwmodes for this PHY.
+- * Which mode is selected, depends on thr GMODE enabled bit */
+-#define B43legacy_MAX_PHYHWMODES 2
+- struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES];
+
+ /* Analog Type */
+ u8 analog;
+@@ -598,6 +604,12 @@
+ u8 nr_devs;
+
+ bool radiotap_enabled;
++
++ /* The beacon we are currently using (AP or IBSS mode).
++ * This beacon stuff is protected by the irq_lock. */
++ struct sk_buff *current_beacon;
++ bool beacon0_uploaded;
++ bool beacon1_uploaded;
+ };
+
+ /* Pointers to the firmware data and meta information about it. */
+@@ -649,7 +661,7 @@
+
+ bool __using_pio; /* Using pio rather than dma. */
+ bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
+- bool reg124_set_0x4; /* Variable to keep track of IRQ. */
++ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM). */
+ bool short_preamble; /* TRUE if using short preamble. */
+ bool short_slot; /* TRUE if using short slot timing. */
+ bool radio_hw_enable; /* State of radio hardware enable bit. */
+@@ -696,9 +708,6 @@
+ u8 max_nr_keys;
+ struct b43legacy_key key[58];
+
+- /* Cached beacon template while uploading the template. */
+- struct sk_buff *cached_beacon;
+-
+ /* Firmware data */
+ struct b43legacy_firmware fw;
+
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43legacy/main.c linux-2.6.25/drivers/net/wireless/b43legacy/main.c
+--- linux-2.6.25.old/drivers/net/wireless/b43legacy/main.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43legacy/main.c 2008-04-19 16:24:28.000000000 +0200
+@@ -96,27 +96,28 @@
+ * get concurrency issues */
+ #define RATETAB_ENT(_rateid, _flags) \
+ { \
+- .rate = B43legacy_RATE_TO_100KBPS(_rateid), \
+- .val = (_rateid), \
+- .val2 = (_rateid), \
++ .bitrate = B43legacy_RATE_TO_100KBPS(_rateid), \
++ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
++/*
++ * NOTE: When changing this, sync with xmit.c's
++ * b43legacy_plcp_get_bitrate_idx_* functions!
++ */
+ static struct ieee80211_rate __b43legacy_ratetable[] = {
+- RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+- RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+- RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+- RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+- RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+- RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
++ RATETAB_ENT(B43legacy_CCK_RATE_1MB, 0),
++ RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
++ RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
++ RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
++ RATETAB_ENT(B43legacy_OFDM_RATE_6MB, 0),
++ RATETAB_ENT(B43legacy_OFDM_RATE_9MB, 0),
++ RATETAB_ENT(B43legacy_OFDM_RATE_12MB, 0),
++ RATETAB_ENT(B43legacy_OFDM_RATE_18MB, 0),
++ RATETAB_ENT(B43legacy_OFDM_RATE_24MB, 0),
++ RATETAB_ENT(B43legacy_OFDM_RATE_36MB, 0),
++ RATETAB_ENT(B43legacy_OFDM_RATE_48MB, 0),
++ RATETAB_ENT(B43legacy_OFDM_RATE_54MB, 0),
+ };
+-#define b43legacy_a_ratetable (__b43legacy_ratetable + 4)
+-#define b43legacy_a_ratetable_size 8
+ #define b43legacy_b_ratetable (__b43legacy_ratetable + 0)
+ #define b43legacy_b_ratetable_size 4
+ #define b43legacy_g_ratetable (__b43legacy_ratetable + 0)
+@@ -124,14 +125,8 @@
+
+ #define CHANTAB_ENT(_chanid, _freq) \
+ { \
+- .chan = (_chanid), \
+- .freq = (_freq), \
+- .val = (_chanid), \
+- .flag = IEEE80211_CHAN_W_SCAN | \
+- IEEE80211_CHAN_W_ACTIVE_SCAN | \
+- IEEE80211_CHAN_W_IBSS, \
+- .power_level = 0x0A, \
+- .antenna_max = 0xFF, \
++ .center_freq = (_freq), \
++ .hw_value = (_chanid), \
+ }
+ static struct ieee80211_channel b43legacy_bg_chantable[] = {
+ CHANTAB_ENT(1, 2412),
+@@ -149,7 +144,20 @@
+ CHANTAB_ENT(13, 2472),
+ CHANTAB_ENT(14, 2484),
+ };
+-#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable)
++
++static struct ieee80211_supported_band b43legacy_band_2GHz_BPHY = {
++ .channels = b43legacy_bg_chantable,
++ .n_channels = ARRAY_SIZE(b43legacy_bg_chantable),
++ .bitrates = b43legacy_b_ratetable,
++ .n_bitrates = b43legacy_b_ratetable_size,
++};
++
++static struct ieee80211_supported_band b43legacy_band_2GHz_GPHY = {
++ .channels = b43legacy_bg_chantable,
++ .n_channels = ARRAY_SIZE(b43legacy_bg_chantable),
++ .bitrates = b43legacy_g_ratetable,
++ .n_bitrates = b43legacy_g_ratetable_size,
++};
+
+ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev);
+ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev);
+@@ -797,9 +805,8 @@
+ {
+ b43legacy_jssi_write(dev, 0x7F7F7F7F);
+ b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+- b43legacy_read32(dev,
+- B43legacy_MMIO_MACCMD)
+- | (1 << 4));
++ b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
++ | B43legacy_MACCMD_BGNOISE);
+ B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
+ dev->phy.channel);
+ }
+@@ -888,18 +895,18 @@
+ if (1/*FIXME: the last PSpoll frame was sent successfully */)
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+ }
+- dev->reg124_set_0x4 = 0;
+ if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+- dev->reg124_set_0x4 = 1;
++ dev->dfq_valid = 1;
+ }
+
+ static void handle_irq_atim_end(struct b43legacy_wldev *dev)
+ {
+- if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
+- return;
++ if (dev->dfq_valid) {
+ b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+ b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
+- | 0x4);
++ | B43legacy_MACCMD_DFQ_VALID);
++ dev->dfq_valid = 0;
++ }
+ }
+
+ static void handle_irq_pmq(struct b43legacy_wldev *dev)
+@@ -955,32 +962,77 @@
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+ {
+- int len;
+- const u8 *data;
+
+- B43legacy_WARN_ON(!dev->cached_beacon);
+- len = min((size_t)dev->cached_beacon->len,
++ unsigned int i, len, variable_len;
++ const struct ieee80211_mgmt *bcn;
++ const u8 *ie;
++ bool tim_found = 0;
++
++ bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
++ len = min((size_t)dev->wl->current_beacon->len,
+ 0x200 - sizeof(struct b43legacy_plcp_hdr6));
+- data = (const u8 *)(dev->cached_beacon->data);
+- b43legacy_write_template_common(dev, data,
+- len, ram_offset,
++
++ b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset,
+ shm_size_offset, rate);
++
++ /* Find the position of the TIM and the DTIM_period value
++ * and write them to SHM. */
++ ie = bcn->u.beacon.variable;
++ variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
++ for (i = 0; i < variable_len - 2; ) {
++ uint8_t ie_id, ie_len;
++
++ ie_id = ie[i];
++ ie_len = ie[i + 1];
++ if (ie_id == 5) {
++ u16 tim_position;
++ u16 dtim_period;
++ /* This is the TIM Information Element */
++
++ /* Check whether the ie_len is in the beacon data range. */
++ if (variable_len < ie_len + 2 + i)
++ break;
++ /* A valid TIM is at least 4 bytes long. */
++ if (ie_len < 4)
++ break;
++ tim_found = 1;
++
++ tim_position = sizeof(struct b43legacy_plcp_hdr6);
++ tim_position += offsetof(struct ieee80211_mgmt,
++ u.beacon.variable);
++ tim_position += i;
++
++ dtim_period = ie[i + 3];
++
++ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
++ B43legacy_SHM_SH_TIMPOS, tim_position);
++ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
++ B43legacy_SHM_SH_DTIMP, dtim_period);
++ break;
++ }
++ i += ie_len + 2;
++ }
++ if (!tim_found) {
++ b43legacywarn(dev->wl, "Did not find a valid TIM IE in the "
++ "beacon template packet. AP or IBSS operation "
++ "may be broken.\n");
++ }
+ }
+
+ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
+ u16 shm_offset, u16 size,
+- u8 rate)
++ struct ieee80211_rate *rate)
+ {
+ struct b43legacy_plcp_hdr4 plcp;
+ u32 tmp;
+ __le16 dur;
+
+ plcp.data = 0;
+- b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
++ b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->vif,
+ size,
+- B43legacy_RATE_TO_100KBPS(rate));
++ rate);
+ /* Write PLCP in two parts and timing for packet transfer */
+ tmp = le32_to_cpu(plcp.data);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset,
+@@ -997,45 +1049,44 @@
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+-static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
+- u16 *dest_size, u8 rate)
++static const u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
++ u16 *dest_size,
++ struct ieee80211_rate *rate)
+ {
+ const u8 *src_data;
+ u8 *dest_data;
+- u16 src_size;
+- u16 elem_size;
+- u16 src_pos;
+- u16 dest_pos;
++ u16 src_size, elem_size, src_pos, dest_pos;
+ __le16 dur;
+ struct ieee80211_hdr *hdr;
++ size_t ie_start;
++
++ src_size = dev->wl->current_beacon->len;
++ src_data = (const u8 *)dev->wl->current_beacon->data;
++
++ /* Get the start offset of the variable IEs in the packet. */
++ ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
++ B43legacy_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt,
++ u.beacon.variable));
+
+- B43legacy_WARN_ON(!dev->cached_beacon);
+- src_size = dev->cached_beacon->len;
+- src_data = (const u8 *)dev->cached_beacon->data;
+-
+- if (unlikely(src_size < 0x24)) {
+- b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: "
+- "invalid beacon\n");
++ if (B43legacy_WARN_ON(src_size < ie_start))
+ return NULL;
+- }
+
+ dest_data = kmalloc(src_size, GFP_ATOMIC);
+ if (unlikely(!dest_data))
+ return NULL;
+
+- /* 0x24 is offset of first variable-len Information-Element
+- * in beacon frame.
+- */
+- memcpy(dest_data, src_data, 0x24);
+- src_pos = 0x24;
+- dest_pos = 0x24;
+- for (; src_pos < src_size - 2; src_pos += elem_size) {
++ /* Copy the static data and all Information Elements, except the TIM. */
++ memcpy(dest_data, src_data, ie_start);
++ src_pos = ie_start;
++ dest_pos = ie_start;
++ for ( ; src_pos < src_size - 2; src_pos += elem_size) {
+ elem_size = src_data[src_pos + 1] + 2;
+- if (src_data[src_pos] != 0x05) { /* TIM */
+- memcpy(dest_data + dest_pos, src_data + src_pos,
+- elem_size);
+- dest_pos += elem_size;
++ if (src_data[src_pos] == 5) {
++ /* This is the TIM. */
++ continue;
+ }
++ memcpy(dest_data + dest_pos, src_data + src_pos, elem_size);
++ dest_pos += elem_size;
+ }
+ *dest_size = dest_pos;
+ hdr = (struct ieee80211_hdr *)dest_data;
+@@ -1046,7 +1097,7 @@
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->vif,
+ *dest_size,
+- B43legacy_RATE_TO_100KBPS(rate));
++ rate);
+ hdr->duration_id = dur;
+
+ return dest_data;
+@@ -1054,13 +1105,13 @@
+
+ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
+ u16 ram_offset,
+- u16 shm_size_offset, u8 rate)
++ u16 shm_size_offset,
++ struct ieee80211_rate *rate)
+ {
+- u8 *probe_resp_data;
++ const u8 *probe_resp_data;
+ u16 size;
+
+- B43legacy_WARN_ON(!dev->cached_beacon);
+- size = dev->cached_beacon->len;
++ size = dev->wl->current_beacon->len;
+ probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate);
+ if (unlikely(!probe_resp_data))
+ return;
+@@ -1069,59 +1120,37 @@
+ * all possible basic rates
+ */
+ b43legacy_write_probe_resp_plcp(dev, 0x31A, size,
+- B43legacy_CCK_RATE_1MB);
++ &b43legacy_b_ratetable[0]);
+ b43legacy_write_probe_resp_plcp(dev, 0x32C, size,
+- B43legacy_CCK_RATE_2MB);
++ &b43legacy_b_ratetable[1]);
+ b43legacy_write_probe_resp_plcp(dev, 0x33E, size,
+- B43legacy_CCK_RATE_5MB);
++ &b43legacy_b_ratetable[2]);
+ b43legacy_write_probe_resp_plcp(dev, 0x350, size,
+- B43legacy_CCK_RATE_11MB);
++ &b43legacy_b_ratetable[3]);
+
+ size = min((size_t)size,
+ 0x200 - sizeof(struct b43legacy_plcp_hdr6));
+ b43legacy_write_template_common(dev, probe_resp_data,
+ size, ram_offset,
+- shm_size_offset, rate);
++ shm_size_offset, rate->bitrate);
+ kfree(probe_resp_data);
+ }
+
+-static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev,
++/* Asynchronously update the packet templates in template RAM.
++ * Locking: Requires wl->irq_lock to be locked. */
++static void b43legacy_update_templates(struct b43legacy_wl *wl,
+ struct sk_buff *beacon)
+ {
+- if (dev->cached_beacon)
+- kfree_skb(dev->cached_beacon);
+- dev->cached_beacon = beacon;
+-
+- return 0;
+-}
+-
+-static void b43legacy_update_templates(struct b43legacy_wldev *dev)
+-{
+- u32 status;
+-
+- B43legacy_WARN_ON(!dev->cached_beacon);
+-
+- b43legacy_write_beacon_template(dev, 0x68, 0x18,
+- B43legacy_CCK_RATE_1MB);
+- b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+- B43legacy_CCK_RATE_1MB);
+- b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
+- B43legacy_CCK_RATE_11MB);
+-
+- status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+- status |= 0x03;
+- b43legacy_write32(dev, B43legacy_MMIO_MACCMD, status);
+-}
+-
+-static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
+- struct sk_buff *beacon)
+-{
+- int err;
+-
+- err = b43legacy_refresh_cached_beacon(dev, beacon);
+- if (unlikely(err))
+- return;
+- b43legacy_update_templates(dev);
++ /* This is the top half of the ansynchronous beacon update. The bottom
++ * half is the beacon IRQ. Beacon update must be asynchronous to avoid
++ * sending an invalid beacon. This can happen for example, if the
++ * firmware transmits a beacon while we are updating it. */
++
++ if (wl->current_beacon)
++ dev_kfree_skb_any(wl->current_beacon);
++ wl->current_beacon = beacon;
++ wl->beacon0_uploaded = 0;
++ wl->beacon1_uploaded = 0;
+ }
+
+ static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
+@@ -1162,38 +1191,37 @@
+
+ static void handle_irq_beacon(struct b43legacy_wldev *dev)
+ {
+- u32 status;
++ struct b43legacy_wl *wl = dev->wl;
++ u32 cmd;
+
+- if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
++ if (!b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ return;
+
+- dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
+- status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
++ /* This is the bottom half of the asynchronous beacon update. */
+
+- if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+- /* ACK beacon IRQ. */
+- b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+- B43legacy_IRQ_BEACON);
+- dev->irq_savedstate |= B43legacy_IRQ_BEACON;
+- if (dev->cached_beacon)
+- kfree_skb(dev->cached_beacon);
+- dev->cached_beacon = NULL;
+- return;
+- }
+- if (!(status & 0x1)) {
+- b43legacy_write_beacon_template(dev, 0x68, 0x18,
++ cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
++ if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) {
++ if (!wl->beacon0_uploaded) {
++ b43legacy_write_beacon_template(dev, 0x68,
++ B43legacy_SHM_SH_BTL0,
+ B43legacy_CCK_RATE_1MB);
+- status |= 0x1;
+- b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+- status);
+- }
+- if (!(status & 0x2)) {
+- b43legacy_write_beacon_template(dev, 0x468, 0x1A,
++ b43legacy_write_probe_resp_template(dev, 0x268,
++ B43legacy_SHM_SH_PRTLEN,
++ &__b43legacy_ratetable[3]);
++ wl->beacon0_uploaded = 1;
++ }
++ cmd |= B43legacy_MACCMD_BEACON0_VALID;
++ }
++ if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) {
++ if (!wl->beacon1_uploaded) {
++ b43legacy_write_beacon_template(dev, 0x468,
++ B43legacy_SHM_SH_BTL1,
+ B43legacy_CCK_RATE_1MB);
+- status |= 0x2;
+- b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+- status);
++ wl->beacon1_uploaded = 1;
++ }
++ cmd |= B43legacy_MACCMD_BEACON1_VALID;
+ }
++ b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd);
+ }
+
+ static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
+@@ -2552,13 +2580,15 @@
+ antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
+
+ mutex_lock(&wl->mutex);
++ dev = wl->current_dev;
++ phy = &dev->phy;
+
+ /* Switch the PHY mode (if necessary). */
+- switch (conf->phymode) {
+- case MODE_IEEE80211B:
++ switch (conf->channel->band) {
++ case IEEE80211_BAND_2GHZ:
++ if (phy->type == B43legacy_PHYTYPE_B)
+ new_phymode = B43legacy_PHYMODE_B;
+- break;
+- case MODE_IEEE80211G:
++ else
+ new_phymode = B43legacy_PHYMODE_G;
+ break;
+ default:
+@@ -2567,8 +2597,6 @@
+ err = b43legacy_switch_phymode(wl, new_phymode);
+ if (err)
+ goto out_unlock_mutex;
+- dev = wl->current_dev;
+- phy = &dev->phy;
+
+ /* Disable IRQs while reconfiguring the device.
+ * This makes it possible to drop the spinlock throughout
+@@ -2584,8 +2612,8 @@
+
+ /* Switch to the requested channel.
+ * The firmware takes care of races with the TX handler. */
+- if (conf->channel_val != phy->channel)
+- b43legacy_radio_selectchannel(dev, conf->channel_val, 0);
++ if (conf->channel->hw_value != phy->channel)
++ b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0);
+
+ /* Enable/Disable ShortSlot timing. */
+ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
+@@ -2702,7 +2730,7 @@
+ B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
+ if (conf->beacon)
+- b43legacy_refresh_templates(dev, conf->beacon);
++ b43legacy_update_templates(wl, conf->beacon);
+ }
+ b43legacy_write_mac_bssid_templates(dev);
+ }
+@@ -2920,7 +2948,7 @@
+ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
+ {
+ /* Flags */
+- dev->reg124_set_0x4 = 0;
++ dev->dfq_valid = 0;
+
+ /* Stats */
+ memset(&dev->stats, 0, sizeof(dev->stats));
+@@ -2979,6 +3007,34 @@
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
+ }
+
++static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
++ bool idle) {
++ u16 pu_delay = 1050;
++
++ if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
++ pu_delay = 500;
++ if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
++ pu_delay = max(pu_delay, (u16)2400);
++
++ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
++ B43legacy_SHM_SH_SPUWKUP, pu_delay);
++}
++
++/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */
++static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev)
++{
++ u16 pretbtt;
++
++ /* The time value is in microseconds. */
++ if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
++ pretbtt = 2;
++ else
++ pretbtt = 250;
++ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
++ B43legacy_SHM_SH_PRETBTT, pretbtt);
++ b43legacy_write16(dev, B43legacy_MMIO_TSF_CFP_PRETBTT, pretbtt);
++}
++
+ /* Shutdown a wireless core */
+ /* Locking: wl->mutex */
+ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
+@@ -3015,6 +3071,11 @@
+ kfree(phy->tssi2dbm);
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
++ if (dev->wl->current_beacon) {
++ dev_kfree_skb_any(dev->wl->current_beacon);
++ dev->wl->current_beacon = NULL;
++ }
++
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(dev->dev->bus);
+ }
+@@ -3160,9 +3221,7 @@
+ if (err)
+ goto err_chip_exit;
+
+- b43legacy_write16(dev, 0x0612, 0x0050);
+- b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050);
+- b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
++ b43legacy_set_synth_pu_delay(dev, 1);
+
+ ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+ b43legacy_upload_card_macaddress(dev);
+@@ -3218,6 +3277,8 @@
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_adjust_opmode(dev);
++ b43legacy_set_pretbtt(dev);
++ b43legacy_set_synth_pu_delay(dev, 0);
+ b43legacy_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+@@ -3339,6 +3400,41 @@
+ return err;
+ }
+
++static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
++ int aid, int set)
++{
++ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
++ struct sk_buff *beacon;
++ unsigned long flags;
++
++ /* We could modify the existing beacon and set the aid bit in the TIM
++ * field, but that would probably require resizing and moving of data
++ * within the beacon template. Simply request a new beacon and let
++ * mac80211 do the hard work. */
++ beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
++ if (unlikely(!beacon))
++ return -ENOMEM;
++ spin_lock_irqsave(&wl->irq_lock, flags);
++ b43legacy_update_templates(wl, beacon);
++ spin_unlock_irqrestore(&wl->irq_lock, flags);
++
++ return 0;
++}
++
++static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
++ struct sk_buff *beacon,
++ struct ieee80211_tx_control *ctl)
++{
++ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
++ unsigned long flags;
++
++ spin_lock_irqsave(&wl->irq_lock, flags);
++ b43legacy_update_templates(wl, beacon);
++ spin_unlock_irqrestore(&wl->irq_lock, flags);
++
++ return 0;
++}
++
+ static const struct ieee80211_ops b43legacy_hw_ops = {
+ .tx = b43legacy_op_tx,
+ .conf_tx = b43legacy_op_conf_tx,
+@@ -3352,6 +3448,8 @@
+ .start = b43legacy_op_start,
+ .stop = b43legacy_op_stop,
+ .set_retry_limit = b43legacy_op_set_retry_limit,
++ .set_tim = b43legacy_op_beacon_set_tim,
++ .beacon_update = b43legacy_op_ibss_beacon_update,
+ };
+
+ /* Hard-reset the chip. Do not call this directly.
+@@ -3400,48 +3498,19 @@
+ int have_gphy)
+ {
+ struct ieee80211_hw *hw = dev->wl->hw;
+- struct ieee80211_hw_mode *mode;
+ struct b43legacy_phy *phy = &dev->phy;
+- int cnt = 0;
+- int err;
+
+ phy->possible_phymodes = 0;
+- for (; 1; cnt++) {
+ if (have_bphy) {
+- B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+- mode = &phy->hwmodes[cnt];
+-
+- mode->mode = MODE_IEEE80211B;
+- mode->num_channels = b43legacy_bg_chantable_size;
+- mode->channels = b43legacy_bg_chantable;
+- mode->num_rates = b43legacy_b_ratetable_size;
+- mode->rates = b43legacy_b_ratetable;
+- err = ieee80211_register_hwmode(hw, mode);
+- if (err)
+- return err;
+-
++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
++ &b43legacy_band_2GHz_BPHY;
+ phy->possible_phymodes |= B43legacy_PHYMODE_B;
+- have_bphy = 0;
+- continue;
+ }
+- if (have_gphy) {
+- B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+- mode = &phy->hwmodes[cnt];
+-
+- mode->mode = MODE_IEEE80211G;
+- mode->num_channels = b43legacy_bg_chantable_size;
+- mode->channels = b43legacy_bg_chantable;
+- mode->num_rates = b43legacy_g_ratetable_size;
+- mode->rates = b43legacy_g_ratetable;
+- err = ieee80211_register_hwmode(hw, mode);
+- if (err)
+- return err;
+
++ if (have_gphy) {
++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
++ &b43legacy_band_2GHz_GPHY;
+ phy->possible_phymodes |= B43legacy_PHYMODE_G;
+- have_gphy = 0;
+- continue;
+- }
+- break;
+ }
+
+ return 0;
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/b43legacy/xmit.c linux-2.6.25/drivers/net/wireless/b43legacy/xmit.c
+--- linux-2.6.25.old/drivers/net/wireless/b43legacy/xmit.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/b43legacy/xmit.c 2008-04-19 13:54:59.000000000 +0200
+@@ -37,45 +37,48 @@
+
+
+ /* Extract the bitrate out of a CCK PLCP header. */
+-static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp)
++static u8 b43legacy_plcp_get_bitrate_idx_cck(struct b43legacy_plcp_hdr6 *plcp)
+ {
+ switch (plcp->raw[0]) {
+ case 0x0A:
+- return B43legacy_CCK_RATE_1MB;
++ return 0;
+ case 0x14:
+- return B43legacy_CCK_RATE_2MB;
++ return 1;
+ case 0x37:
+- return B43legacy_CCK_RATE_5MB;
++ return 2;
+ case 0x6E:
+- return B43legacy_CCK_RATE_11MB;
++ return 3;
+ }
+ B43legacy_BUG_ON(1);
+- return 0;
++ return -1;
+ }
+
+ /* Extract the bitrate out of an OFDM PLCP header. */
+-static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp)
++static u8 b43legacy_plcp_get_bitrate_idx_ofdm(struct b43legacy_plcp_hdr6 *plcp,
++ bool aphy)
+ {
++ int base = aphy ? 0 : 4;
++
+ switch (plcp->raw[0] & 0xF) {
+ case 0xB:
+- return B43legacy_OFDM_RATE_6MB;
++ return base + 0;
+ case 0xF:
+- return B43legacy_OFDM_RATE_9MB;
++ return base + 1;
+ case 0xA:
+- return B43legacy_OFDM_RATE_12MB;
++ return base + 2;
+ case 0xE:
+- return B43legacy_OFDM_RATE_18MB;
++ return base + 3;
+ case 0x9:
+- return B43legacy_OFDM_RATE_24MB;
++ return base + 4;
+ case 0xD:
+- return B43legacy_OFDM_RATE_36MB;
++ return base + 5;
+ case 0x8:
+- return B43legacy_OFDM_RATE_48MB;
++ return base + 6;
+ case 0xC:
+- return B43legacy_OFDM_RATE_54MB;
++ return base + 7;
+ }
+ B43legacy_BUG_ON(1);
+- return 0;
++ return -1;
+ }
+
+ u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
+@@ -192,7 +195,7 @@
+ int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ u16 fctl;
+ u8 rate;
+- u8 rate_fb;
++ struct ieee80211_rate *rate_fb;
+ int rate_ofdm;
+ int rate_fb_ofdm;
+ unsigned int plcp_fragment_len;
+@@ -204,16 +207,16 @@
+
+ memset(txhdr, 0, sizeof(*txhdr));
+
+- rate = txctl->tx_rate;
++ rate = txctl->tx_rate->hw_value;
+ rate_ofdm = b43legacy_is_ofdm_rate(rate);
+- rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+- rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb);
++ rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate;
++ rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
+
+ txhdr->mac_frame_ctl = wlhdr->frame_control;
+ memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
+
+ /* Calculate duration for fallback rate */
+- if ((rate_fb == rate) ||
++ if ((rate_fb->hw_value == rate) ||
+ (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
+ (wlhdr->duration_id == cpu_to_le16(0))) {
+ /* If the fallback rate equals the normal rate or the
+@@ -221,11 +224,10 @@
+ * use the original dur_id field. */
+ txhdr->dur_fb = wlhdr->duration_id;
+ } else {
+- int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
+ txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+ txctl->vif,
+ fragment_len,
+- fbrate_base100kbps);
++ rate_fb);
+ }
+
+ plcp_fragment_len = fragment_len + FCS_LEN;
+@@ -266,7 +268,7 @@
+ rate);
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->plcp_fb), plcp_fragment_len,
+- rate_fb);
++ rate_fb->hw_value);
+
+ /* PHY TX Control word */
+ if (rate_ofdm)
+@@ -310,7 +312,7 @@
+ int rts_rate_ofdm;
+ int rts_rate_fb_ofdm;
+
+- rts_rate = txctl->rts_cts_rate;
++ rts_rate = txctl->rts_cts_rate->hw_value;
+ rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
+ rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
+ rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
+@@ -536,19 +538,24 @@
+ (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
+ status.noise = dev->stats.link_noise;
+ status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
++ /* change to support A PHY */
+ if (phystat0 & B43legacy_RX_PHYST0_OFDM)
+- status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp);
++ status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);
+ else
+- status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
++ status.rate_idx = b43legacy_plcp_get_bitrate_idx_cck(plcp);
+ status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
+
+ /*
+- * If monitors are present get full 64-bit timestamp. This
+- * code assumes we get to process the packet within 16 bits
+- * of timestamp, i.e. about 65 milliseconds after the PHY
+- * received the first symbol.
++ * All frames on monitor interfaces and beacons always need a full
++ * 64-bit timestamp. Monitor interfaces need it for diagnostic
++ * purposes and beacons for IBSS merging.
++ * This code assumes we get to process the packet within 16 bits
++ * of timestamp, i.e. about 65 milliseconds after the PHY received
++ * the first symbol.
+ */
+- if (dev->wl->radiotap_enabled) {
++ if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
++ == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
++ dev->wl->radiotap_enabled) {
+ u16 low_mactime_now;
+
+ b43legacy_tsf_read(dev, &status.mactime);
+@@ -564,14 +571,9 @@
+ B43legacy_RX_CHAN_ID_SHIFT;
+ switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
+ case B43legacy_PHYTYPE_B:
+- status.phymode = MODE_IEEE80211B;
+- status.freq = chanid + 2400;
+- status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+- break;
+ case B43legacy_PHYTYPE_G:
+- status.phymode = MODE_IEEE80211G;
++ status.band = IEEE80211_BAND_2GHZ;
+ status.freq = chanid + 2400;
+- status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+ break;
+ default:
+ b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c linux-2.6.25/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+--- linux-2.6.25.old/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,556 +0,0 @@
+-/*
+-
+- Broadcom BCM43xx wireless driver
+-
+- debugfs driver debugging code
+-
+- Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+-
+- This program is free software; you can redistribute it 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 program 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; see the file COPYING. If not, write to
+- the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+- Boston, MA 02110-1301, USA.
+-
+-*/
+-
+-
+-
+-#include <linux/fs.h>
+-#include <linux/debugfs.h>
+-#include <linux/slab.h>
+-#include <linux/netdevice.h>
+-#include <linux/pci.h>
+-#include <asm/io.h>
+-
+-#include "bcm43xx.h"
+-#include "bcm43xx_main.h"
+-#include "bcm43xx_debugfs.h"
+-#include "bcm43xx_dma.h"
+-#include "bcm43xx_pio.h"
+-#include "bcm43xx_xmit.h"
+-
+-#define REALLY_BIG_BUFFER_SIZE (1024*256)
+-
+-static struct bcm43xx_debugfs fs;
+-static char really_big_buffer[REALLY_BIG_BUFFER_SIZE];
+-static DECLARE_MUTEX(big_buffer_sem);
+-
+-
+-static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+- size_t count, loff_t *ppos)
+-{
+- return count;
+-}
+-
+-static int open_file_generic(struct inode *inode, struct file *file)
+-{
+- file->private_data = inode->i_private;
+- return 0;
+-}
+-
+-#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x)
+-
+-static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- const size_t len = REALLY_BIG_BUFFER_SIZE;
+-
+- struct bcm43xx_private *bcm = file->private_data;
+- char *buf = really_big_buffer;
+- size_t pos = 0;
+- ssize_t res;
+- struct net_device *net_dev;
+- struct pci_dev *pci_dev;
+- unsigned long flags;
+- u16 tmp16;
+- int i;
+-
+- down(&big_buffer_sem);
+-
+- mutex_lock(&bcm->mutex);
+- spin_lock_irqsave(&bcm->irq_lock, flags);
+- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+- fappend("Board not initialized.\n");
+- goto out;
+- }
+- net_dev = bcm->net_dev;
+- pci_dev = bcm->pci_dev;
+-
+- /* This is where the information is written to the "devinfo" file */
+- fappend("*** %s devinfo ***\n", net_dev->name);
+- fappend("vendor: 0x%04x device: 0x%04x\n",
+- pci_dev->vendor, pci_dev->device);
+- fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n",
+- pci_dev->subsystem_vendor, pci_dev->subsystem_device);
+- fappend("IRQ: %d\n", bcm->irq);
+- fappend("mmio_addr: 0x%p\n", bcm->mmio_addr);
+- fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
+- if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
+- fappend("Radio disabled by hardware!\n");
+- if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4)))
+- fappend("Radio disabled by hardware!\n");
+- fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor,
+- bcm->board_type);
+-
+- fappend("\nCores:\n");
+-#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \
+- "rev: 0x%02x, index: 0x%02x\n", \
+- (info).available \
+- ? "available" : "nonavailable", \
+- (info).enabled \
+- ? "enabled" : "disabled", \
+- (info).id, (info).rev, (info).index)
+- fappend_core("CHIPCOMMON", bcm->core_chipcommon);
+- fappend_core("PCI", bcm->core_pci);
+- fappend_core("first 80211", bcm->core_80211[0]);
+- fappend_core("second 80211", bcm->core_80211[1]);
+-#undef fappend_core
+- tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+- fappend("LEDs: ");
+- for (i = 0; i < BCM43xx_NR_LEDS; i++)
+- fappend("%d ", !!(tmp16 & (1 << i)));
+- fappend("\n");
+-
+-out:
+- spin_unlock_irqrestore(&bcm->irq_lock, flags);
+- mutex_unlock(&bcm->mutex);
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- up(&big_buffer_sem);
+- return res;
+-}
+-
+-static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- const size_t len = REALLY_BIG_BUFFER_SIZE;
+-
+- char *buf = really_big_buffer;
+- size_t pos = 0;
+- ssize_t res;
+-
+- down(&big_buffer_sem);
+-
+- /* This is where the information is written to the "driver" file */
+- fappend(KBUILD_MODNAME " driver\n");
+- fappend("Compiled at: %s %s\n", __DATE__, __TIME__);
+-
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- up(&big_buffer_sem);
+- return res;
+-}
+-
+-static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- const size_t len = REALLY_BIG_BUFFER_SIZE;
+-
+- struct bcm43xx_private *bcm = file->private_data;
+- char *buf = really_big_buffer;
+- size_t pos = 0;
+- ssize_t res;
+- unsigned long flags;
+-
+- down(&big_buffer_sem);
+- mutex_lock(&bcm->mutex);
+- spin_lock_irqsave(&bcm->irq_lock, flags);
+- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+- fappend("Board not initialized.\n");
+- goto out;
+- }
+-
+- /* This is where the information is written to the "sprom_dump" file */
+- fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
+-
+-out:
+- spin_unlock_irqrestore(&bcm->irq_lock, flags);
+- mutex_unlock(&bcm->mutex);
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- up(&big_buffer_sem);
+- return res;
+-}
+-
+-static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- const size_t len = REALLY_BIG_BUFFER_SIZE;
+-
+- struct bcm43xx_private *bcm = file->private_data;
+- char *buf = really_big_buffer;
+- size_t pos = 0;
+- ssize_t res;
+- unsigned long flags;
+- u64 tsf;
+-
+- down(&big_buffer_sem);
+- mutex_lock(&bcm->mutex);
+- spin_lock_irqsave(&bcm->irq_lock, flags);
+- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+- fappend("Board not initialized.\n");
+- goto out;
+- }
+- bcm43xx_tsf_read(bcm, &tsf);
+- fappend("0x%08x%08x\n",
+- (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+- (unsigned int)(tsf & 0xFFFFFFFFULL));
+-
+-out:
+- spin_unlock_irqrestore(&bcm->irq_lock, flags);
+- mutex_unlock(&bcm->mutex);
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- up(&big_buffer_sem);
+- return res;
+-}
+-
+-static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
+- size_t count, loff_t *ppos)
+-{
+- struct bcm43xx_private *bcm = file->private_data;
+- char *buf = really_big_buffer;
+- ssize_t buf_size;
+- ssize_t res;
+- unsigned long flags;
+- unsigned long long tsf;
+-
+- buf_size = min(count, sizeof (really_big_buffer) - 1);
+- down(&big_buffer_sem);
+- if (copy_from_user(buf, user_buf, buf_size)) {
+- res = -EFAULT;
+- goto out_up;
+- }
+- mutex_lock(&bcm->mutex);
+- spin_lock_irqsave(&bcm->irq_lock, flags);
+- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+- printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+- res = -EFAULT;
+- goto out_unlock;
+- }
+- if (sscanf(buf, "%lli", &tsf) != 1) {
+- printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n");
+- res = -EINVAL;
+- goto out_unlock;
+- }
+- bcm43xx_tsf_write(bcm, tsf);
+- mmiowb();
+- res = buf_size;
+-
+-out_unlock:
+- spin_unlock_irqrestore(&bcm->irq_lock, flags);
+- mutex_unlock(&bcm->mutex);
+-out_up:
+- up(&big_buffer_sem);
+- return res;
+-}
+-
+-static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
+- size_t count, loff_t *ppos)
+-{
+- const size_t len = REALLY_BIG_BUFFER_SIZE;
+-
+- struct bcm43xx_private *bcm = file->private_data;
+- char *buf = really_big_buffer;
+- size_t pos = 0;
+- ssize_t res;
+- unsigned long flags;
+- struct bcm43xx_dfsentry *e;
+- struct bcm43xx_xmitstatus *status;
+- int i, cnt, j = 0;
+-
+- down(&big_buffer_sem);
+- mutex_lock(&bcm->mutex);
+- spin_lock_irqsave(&bcm->irq_lock, flags);
+-
+- fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
+- BCM43xx_NR_LOGGED_XMITSTATUS);
+- e = bcm->dfsentry;
+- if (e->xmitstatus_printing == 0) {
+- /* At the beginning, make a copy of all data to avoid
+- * concurrency, as this function is called multiple
+- * times for big logs. Without copying, the data might
+- * change between reads. This would result in total trash.
+- */
+- e->xmitstatus_printing = 1;
+- e->saved_xmitstatus_ptr = e->xmitstatus_ptr;
+- e->saved_xmitstatus_cnt = e->xmitstatus_cnt;
+- memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer,
+- BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer)));
+- }
+- i = e->saved_xmitstatus_ptr - 1;
+- if (i < 0)
+- i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
+- cnt = e->saved_xmitstatus_cnt;
+- while (cnt) {
+- status = e->xmitstatus_print_buffer + i;
+- fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, "
+- "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, "
+- "unk: 0x%04x\n", j,
+- status->cookie, status->flags,
+- status->cnt1, status->cnt2, status->seq,
+- status->unknown);
+- j++;
+- cnt--;
+- i--;
+- if (i < 0)
+- i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
+- }
+-
+- spin_unlock_irqrestore(&bcm->irq_lock, flags);
+- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+- spin_lock_irqsave(&bcm->irq_lock, flags);
+- if (*ppos == pos) {
+- /* Done. Drop the copied data. */
+- e->xmitstatus_printing = 0;
+- }
+- spin_unlock_irqrestore(&bcm->irq_lock, flags);
+- mutex_unlock(&bcm->mutex);
+- up(&big_buffer_sem);
+- return res;
+-}
+-
+-static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
+- size_t count, loff_t *ppos)
+-{
+- struct bcm43xx_private *bcm = file->private_data;
+- char *buf = really_big_buffer;
+- ssize_t buf_size;
+- ssize_t res;
+- unsigned long flags;
+-
+- buf_size = min(count, sizeof (really_big_buffer) - 1);
+- down(&big_buffer_sem);
+- if (copy_from_user(buf, user_buf, buf_size)) {
+- res = -EFAULT;
+- goto out_up;
+- }
+- mutex_lock(&(bcm)->mutex);
+- spin_lock_irqsave(&(bcm)->irq_lock, flags);
+- if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+- printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+- res = -EFAULT;
+- goto out_unlock;
+- }
+- if (count > 0 && buf[0] == '1') {
+- bcm43xx_controller_restart(bcm, "manually restarted");
+- res = count;
+- } else
+- res = -EINVAL;
+-
+-out_unlock:
+- spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
+- mutex_unlock(&(bcm)->mutex);
+-out_up:
+- up(&big_buffer_sem);
+- return res;
+-}
+-
+-#undef fappend
+-
+-
+-static const struct file_operations devinfo_fops = {
+- .read = devinfo_read_file,
+- .write = write_file_dummy,
+- .open = open_file_generic,
+-};
+-
+-static const struct file_operations spromdump_fops = {
+- .read = spromdump_read_file,
+- .write = write_file_dummy,
+- .open = open_file_generic,
+-};
+-
+-static const struct file_operations drvinfo_fops = {
+- .read = drvinfo_read_file,
+- .write = write_file_dummy,
+- .open = open_file_generic,
+-};
+-
+-static const struct file_operations tsf_fops = {
+- .read = tsf_read_file,
+- .write = tsf_write_file,
+- .open = open_file_generic,
+-};
+-
+-static const struct file_operations txstat_fops = {
+- .read = txstat_read_file,
+- .write = write_file_dummy,
+- .open = open_file_generic,
+-};
+-
+-static const struct file_operations restart_fops = {
+- .write = restart_write_file,
+- .open = open_file_generic,
+-};
+-
+-
+-void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
+-{
+- struct bcm43xx_dfsentry *e;
+- char devdir[IFNAMSIZ];
+-
+- assert(bcm);
+- e = kzalloc(sizeof(*e), GFP_KERNEL);
+- if (!e) {
+- printk(KERN_ERR PFX "out of memory\n");
+- return;
+- }
+- e->bcm = bcm;
+- e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
+- * sizeof(*(e->xmitstatus_buffer)),
+- GFP_KERNEL);
+- if (!e->xmitstatus_buffer) {
+- printk(KERN_ERR PFX "out of memory\n");
+- kfree(e);
+- return;
+- }
+- e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
+- * sizeof(*(e->xmitstatus_buffer)),
+- GFP_KERNEL);
+- if (!e->xmitstatus_print_buffer) {
+- printk(KERN_ERR PFX "out of memory\n");
+- kfree(e);
+- return;
+- }
+-
+-
+- bcm->dfsentry = e;
+-
+- strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir));
+- e->subdir = debugfs_create_dir(devdir, fs.root);
+- e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir,
+- bcm, &devinfo_fops);
+- if (!e->dentry_devinfo)
+- printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir);
+- e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir,
+- bcm, &spromdump_fops);
+- if (!e->dentry_spromdump)
+- printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir);
+- e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir,
+- bcm, &tsf_fops);
+- if (!e->dentry_tsf)
+- printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
+- e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
+- bcm, &txstat_fops);
+- if (!e->dentry_txstat)
+- printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
+- e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
+- bcm, &restart_fops);
+- if (!e->dentry_restart)
+- printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
+-}
+-
+-void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
+-{
+- struct bcm43xx_dfsentry *e;
+-
+- if (!bcm)
+- return;
+-
+- e = bcm->dfsentry;
+- assert(e);
+- debugfs_remove(e->dentry_spromdump);
+- debugfs_remove(e->dentry_devinfo);
+- debugfs_remove(e->dentry_tsf);
+- debugfs_remove(e->dentry_txstat);
+- debugfs_remove(e->dentry_restart);
+- debugfs_remove(e->subdir);
+- kfree(e->xmitstatus_buffer);
+- kfree(e->xmitstatus_print_buffer);
+- kfree(e);
+-}
+-
+-void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+- struct bcm43xx_xmitstatus *status)
+-{
+- struct bcm43xx_dfsentry *e;
+- struct bcm43xx_xmitstatus *savedstatus;
+-
+- /* This is protected by bcm->_lock */
+- e = bcm->dfsentry;
+- assert(e);
+- savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr;
+- memcpy(savedstatus, status, sizeof(*status));
+- e->xmitstatus_ptr++;
+- if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS)
+- e->xmitstatus_ptr = 0;
+- if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS)
+- e->xmitstatus_cnt++;
+-}
+-
+-void bcm43xx_debugfs_init(void)
+-{
+- memset(&fs, 0, sizeof(fs));
+- fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+- if (!fs.root)
+- printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n");
+- fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
+- if (!fs.dentry_driverinfo)
+- printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n");
+-}
+-
+-void bcm43xx_debugfs_exit(void)
+-{
+- debugfs_remove(fs.dentry_driverinfo);
+- debugfs_remove(fs.root);
+-}
+-
+-void bcm43xx_printk_dump(const char *data,
+- size_t size,
+- const char *description)
+-{
+- size_t i;
+- char c;
+-
+- printk(KERN_INFO PFX "Data dump (%s, %zd bytes):",
+- description, size);
+- for (i = 0; i < size; i++) {
+- c = data[i];
+- if (i % 8 == 0)
+- printk("\n" KERN_INFO PFX "0x%08zx: 0x%02x, ", i, c & 0xff);
+- else
+- printk("0x%02x, ", c & 0xff);
+- }
+- printk("\n");
+-}
+-
+-void bcm43xx_printk_bitdump(const unsigned char *data,
+- size_t bytes, int msb_to_lsb,
+- const char *description)
+-{
+- size_t i;
+- int j;
+- const unsigned char *d;
+-
+- printk(KERN_INFO PFX "*** Bitdump (%s, %zd bytes, %s) ***",
+- description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
+- for (i = 0; i < bytes; i++) {
+- d = data + i;
+- if (i % 8 == 0)
+- printk("\n" KERN_INFO PFX "0x%08zx: ", i);
+- if (msb_to_lsb) {
+- for (j = 7; j >= 0; j--) {
+- if (*d & (1 << j))
+- printk("1");
+- else
+- printk("0");
+- }
+- } else {
+- for (j = 0; j < 8; j++) {
+- if (*d & (1 << j))
+- printk("1");
+- else
+- printk("0");
+- }
+- }
+- printk(" ");
+- }
+- printk("\n");
+-}
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h linux-2.6.25/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
+--- linux-2.6.25.old/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,118 +0,0 @@
+-#ifndef BCM43xx_DEBUGFS_H_
+-#define BCM43xx_DEBUGFS_H_
+-
+-struct bcm43xx_private;
+-struct bcm43xx_xmitstatus;
+-
+-#ifdef CONFIG_BCM43XX_DEBUG
+-
+-#include <linux/list.h>
+-#include <asm/semaphore.h>
+-
+-struct dentry;
+-
+-/* limited by the size of the "really_big_buffer" */
+-#define BCM43xx_NR_LOGGED_XMITSTATUS 100
+-
+-struct bcm43xx_dfsentry {
+- struct dentry *subdir;
+- struct dentry *dentry_devinfo;
+- struct dentry *dentry_spromdump;
+- struct dentry *dentry_tsf;
+- struct dentry *dentry_txstat;
+- struct dentry *dentry_restart;
+-
+- struct bcm43xx_private *bcm;
+-
+- /* saved xmitstatus. */
+- struct bcm43xx_xmitstatus *xmitstatus_buffer;
+- int xmitstatus_ptr;
+- int xmitstatus_cnt;
+- /* We need a seperate buffer while printing to avoid
+- * concurrency issues. (New xmitstatus can arrive
+- * while we are printing).
+- */
+- struct bcm43xx_xmitstatus *xmitstatus_print_buffer;
+- int saved_xmitstatus_ptr;
+- int saved_xmitstatus_cnt;
+- int xmitstatus_printing;
+-};
+-
+-struct bcm43xx_debugfs {
+- struct dentry *root;
+- struct dentry *dentry_driverinfo;
+-};
+-
+-void bcm43xx_debugfs_init(void);
+-void bcm43xx_debugfs_exit(void);
+-void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm);
+-void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm);
+-void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+- struct bcm43xx_xmitstatus *status);
+-
+-/* Debug helper: Dump binary data through printk. */
+-void bcm43xx_printk_dump(const char *data,
+- size_t size,
+- const char *description);
+-/* Debug helper: Dump bitwise binary data through printk. */
+-void bcm43xx_printk_bitdump(const unsigned char *data,
+- size_t bytes, int msb_to_lsb,
+- const char *description);
+-#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \
+- do { \
+- bcm43xx_printk_bitdump((const unsigned char *)(pointer), \
+- sizeof(*(pointer)), \
+- (msb_to_lsb), \
+- (description)); \
+- } while (0)
+-
+-#else /* CONFIG_BCM43XX_DEBUG*/
+-
+-static inline
+-void bcm43xx_debugfs_init(void) { }
+-static inline
+-void bcm43xx_debugfs_exit(void) { }
+-static inline
+-void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { }
+-static inline
+-void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { }
+-static inline
+-void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+- struct bcm43xx_xmitstatus *status) { }
+-
+-static inline
+-void bcm43xx_printk_dump(const char *data,
+- size_t size,
+- const char *description)
+-{
+-}
+-static inline
+-void bcm43xx_printk_bitdump(const unsigned char *data,
+- size_t bytes, int msb_to_lsb,
+- const char *description)
+-{
+-}
+-#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0)
+-
+-#endif /* CONFIG_BCM43XX_DEBUG*/
+-
+-/* Ugly helper macros to make incomplete code more verbose on runtime */
+-#ifdef TODO
+-# undef TODO
+-#endif
+-#define TODO() \
+- do { \
+- printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \
+- __FUNCTION__, __FILE__, __LINE__); \
+- } while (0)
+-
+-#ifdef FIXME
+-# undef FIXME
+-#endif
+-#define FIXME() \
+- do { \
+- printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \
+- __FUNCTION__, __FILE__, __LINE__); \
+- } while (0)
+-
+-#endif /* BCM43xx_DEBUGFS_H_ */
+diff -Nbur linux-2.6.25.old/drivers/net/wireless/bcm43xx/bcm43xx_dma.c linux-2.6.25/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+--- linux-2.6.25.old/drivers/net/wireless/bcm43xx/bcm43xx_dma.c 2008-04-17 04:49:44.000000000 +0200
++++ linux-2.6.25/drivers/net/wireless/bcm43xx/bcm43xx_dma.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,1263 +0,0 @@
+-/*
+-
+- Broadcom BCM43xx wireless driver
+-
+- DMA ringbuffer and descriptor allocation/management
+-
+- Copyright (c) 2005, 2006 Michael Buesch <mbuesch@freenet.de>
+-
+- Some code in this file is derived from the b44.c driver
+- Copyright (C) 2002 David S. Miller
+- Copyright (C) Pekka Pietikainen
+-
+- This program is free software; you can redistribute it 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 program 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; see the file COPYING. If not, write to
+- the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+- Boston, MA 02110-1301, USA.
+-
+-*/
+-
+-#include "bcm43xx.h"
+-#include "bcm43xx_dma.h"
+-#include "bcm43xx_main.h"
+-#include "bcm43xx_debugfs.h"
+-#include "bcm43xx_power.h"
+-#include "bcm43xx_xmit.h"
+-
+-#include <linux/dma-mapping.h>
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-#include <linux/skbuff.h>
+-
+-
+-static inline int free_slots(struct bcm43xx_dmaring *ring)
+-{
+- return (ring->nr_slots - ring->used_slots);
+-}
+-
+-static inline int next_slot(struct bcm43xx_dmaring *ring, int slot)
+-{
+- assert(slot >= -1 && slot <= ring->nr_slots - 1);
+- if (slot == ring->nr_slots - 1)
+- return 0;
+- return slot + 1;
+-}
+-
+-static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot)
+-{
+- assert(slot >= 0 && slot <= ring->nr_slots - 1);
+- if (slot == 0)
+- return ring->nr_slots - 1;
+- return slot - 1;
+-}
+-
+-/* Request a slot for usage. */
+-static inline
+-int request_slot(struct bcm43xx_dmaring *ring)
+-{
+- int slot;
+-
+- assert(ring->tx);
+- assert(!ring->suspended);
+- assert(free_slots(ring) != 0);
+-
+- slot = next_slot(ring, ring->current_slot);
+- ring->current_slot = slot;
+- ring->used_slots++;
+-
+- /* Check the number of available slots and suspend TX,
+- * if we are running low on free slots.
+- */
+- if (unlikely(free_slots(ring) < ring->suspend_mark)) {
+- netif_stop_queue(ring->bcm->net_dev);
+- ring->suspended = 1;
+- }
+-#ifdef CONFIG_BCM43XX_DEBUG
+- if (ring->used_slots > ring->max_used_slots)
+- ring->max_used_slots = ring->used_slots;
+-#endif /* CONFIG_BCM43XX_DEBUG*/
+-
+- return slot;
+-}
+-
+-/* Return a slot to the free slots. */
+-static inline
+-void return_slot(struct bcm43xx_dmaring *ring, int slot)
+-{
+- assert(ring->tx);
+-
+- ring->used_slots--;
+-
+- /* Check if TX is suspended and check if we have
+- * enough free slots to resume it again.
+- */
+- if (unlikely(ring->suspended)) {
+- if (free_slots(ring) >= ring->resume_mark) {
+- ring->suspended = 0;
+- netif_wake_queue(ring->bcm->net_dev);
+- }
+- }
+-}
+-
+-u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
+-{
+- static const u16 map64[] = {
+- BCM43xx_MMIO_DMA64_BASE0,
+- BCM43xx_MMIO_DMA64_BASE1,
+- BCM43xx_MMIO_DMA64_BASE2,
+- BCM43xx_MMIO_DMA64_BASE3,
+- BCM43xx_MMIO_DMA64_BASE4,
+- BCM43xx_MMIO_DMA64_BASE5,
+- };
+- static const u16 map32[] = {
+- BCM43xx_MMIO_DMA32_BASE0,
+- BCM43xx_MMIO_DMA32_BASE1,
+- BCM43xx_MMIO_DMA32_BASE2,
+- BCM43xx_MMIO_DMA32_BASE3,
+- BCM43xx_MMIO_DMA32_BASE4,
+- BCM43xx_MMIO_DMA32_BASE5,
+- };
+-
+- if (dma64bit) {
+- assert(controller_idx >= 0 &&
+- controller_idx < ARRAY_SIZE(map64));
+- return map64[controller_idx];
+- }
+- assert(controller_idx >= 0 &&
+- controller_idx < ARRAY_SIZE(map32));
+- return map32[controller_idx];
+-}
+-
+-static inline
+-dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
+- unsigned char *buf,
+- size_t len,
+- int tx)
+-{
+- dma_addr_t dmaaddr;
+- int direction = PCI_DMA_FROMDEVICE;
+-
+- if (tx)
+- direction = PCI_DMA_TODEVICE;
+-
+- dmaaddr = pci_map_single(ring->bcm->pci_dev,
+- buf, len,
+- direction);
+-
+- return dmaaddr;
+-}
+-
+-static inline
+-void unmap_descbuffer(struct bcm43xx_dmaring *ring,
+- dma_addr_t addr,
+- size_t len,
+- int tx)
+-{
+- if (tx) {
+- pci_unmap_single(ring->bcm->pci_dev,
+- addr, len,
+- PCI_DMA_TODEVICE);
+- } else {
+- pci_unmap_single(ring->bcm->pci_dev,
+- addr, len,
+- PCI_DMA_FROMDEVICE);
+- }
+-}
+-
+-static inline
+-void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
+- dma_addr_t addr,
+- size_t len)
+-{
+- assert(!ring->tx);
+-
+- pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+- addr, len, PCI_DMA_FROMDEVICE);
+-}
+-
+-static inline
+-void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
+- dma_addr_t addr,
+- size_t len)
+-{
+- assert(!ring->tx);
+-
+- pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+- addr, len, PCI_DMA_TODEVICE);
+-}
+-
+-/* Unmap and free a descriptor buffer. */
+-static inline
+-void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
+- struct bcm43xx_dmadesc_meta *meta,
+- int irq_context)
+-{
+- assert(meta->skb);
+- if (irq_context)
+- dev_kfree_skb_irq(meta->skb);
+- else
+- dev_kfree_skb(meta->skb);
+- meta->skb = NULL;
+-}
+-
+-static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
+-{
+- ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
+- &(ring->dmabase));
+- if (!ring->descbase) {
+- /* Allocation may have failed due to pci_alloc_consistent
+- insisting on use of GFP_DMA, which is more restrictive
+- than necessary... */
+- struct dma_desc *rx_ring;
+- dma_addr_t rx_ring_dma;
+-
+- rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
+- if (!rx_ring)
+- goto out_err;
+-
+- rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
+- BCM43xx_DMA_RINGMEMSIZE,
+- PCI_DMA_BIDIRECTIONAL);
+-
+- if (pci_dma_mapping_error(rx_ring_dma) ||
+- rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+- /* Sigh... */
+- if (!pci_dma_mapping_error(rx_ring_dma))
+- pci_unmap_single(ring->bcm->pci_dev,
+- rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+- PCI_DMA_BIDIRECTIONAL);
+- rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
+- rx_ring, BCM43xx_DMA_RINGMEMSIZE,
+- PCI_DMA_BIDIRECTIONAL);
+- if (pci_dma_mapping_error(rx_ring_dma) ||
+- rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+- assert(0);
+- if (!pci_dma_mapping_error(rx_ring_dma))
+- pci_unmap_single(ring->bcm->pci_dev,
+- rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+- PCI_DMA_BIDIRECTIONAL);
+- goto out_err;
+- }
+- }
+-
+- ring->descbase = rx_ring;
+- ring->dmabase = rx_ring_dma;
+- }
+- memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+-
+- return 0;
+-out_err:
+- printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+- return -ENOMEM;
+-}
+-
+-static void free_ringmemory(struct bcm43xx_dmaring *ring)
+-{
+- struct device *dev = &(ring->bcm->pci_dev->dev);
+-
+- dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+- ring->descbase, ring->dmabase);
+-}
+-
+-/* Reset the RX DMA channel */
+-int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+- u16 mmio_base, int dma64)
+-{
+- int i;
+- u32 value;
+- u16 offset;
+-
+- offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
+- bcm43xx_write32(bcm, mmio_base + offset, 0);
+- for (i = 0; i < 1000; i++) {
+- offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
+- value = bcm43xx_read32(bcm, mmio_base + offset);
+- if (dma64) {
+- value &= BCM43xx_DMA64_RXSTAT;
+- if (value == BCM43xx_DMA64_RXSTAT_DISABLED) {
+- i = -1;
+- break;
+- }
+- } else {
+- value &= BCM43xx_DMA32_RXSTATE;
+- if (value == BCM43xx_DMA32_RXSTAT_DISABLED) {
+- i = -1;
+- break;
+- }
+- }
+- udelay(10);
+- }
+- if (i != -1) {
+- printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n");
+- return -ENODEV;
+- }
+-
+- return 0;
+-}
+-
+-/* Reset the RX DMA channel */
+-int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+- u16 mmio_base, int dma64)
+-{
+- int i;
+- u32 value;
+- u16 offset;
+-
+- for (i = 0; i < 1000; i++) {
+- offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+- value = bcm43xx_read32(bcm, mmio_base + offset);
+- if (dma64) {
+- value &= BCM43xx_DMA64_TXSTAT;
+- if (value == BCM43xx_DMA64_TXSTAT_DISABLED ||
+- value == BCM43xx_DMA64_TXSTAT_IDLEWAIT ||
+- value == BCM43xx_DMA64_TXSTAT_STOPPED)
+- break;
+- } else {
+- value &= BCM43xx_DMA32_TXSTATE;
+- if (value == BCM43xx_DMA32_TXSTAT_DISABLED ||
+- value == BCM43xx_DMA32_TXSTAT_IDLEWAIT ||
+- value == BCM43xx_DMA32_TXSTAT_STOPPED)
+- break;
+- }
+- udelay(10);
+- }
+- offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
+- bcm43xx_write32(bcm, mmio_base + offset, 0);
+- for (i = 0; i < 1000; i++) {
+- offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+- value = bcm43xx_read32(bcm, mmio_base + offset);
+- if (dma64) {
+- value &= BCM43xx_DMA64_TXSTAT;
+- if (value == BCM43xx_DMA64_TXSTAT_DISABLED) {
+- i = -1;
+- break;
+- }
+- } else {
+- value &= BCM43xx_DMA32_TXSTATE;
+- if (value == BCM43xx_DMA32_TXSTAT_DISABLED) {
+- i = -1;
+- break;
+- }
+- }
+- udelay(10);
+- }
+- if (i != -1) {
+- printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n");
+- return -ENODEV;
+- }
+- /* ensure the reset is completed. */
+- udelay(300);
+-
+- return 0;
+-}
+-
+-static void fill_descriptor(struct bcm43xx_dmaring *ring,
+- struct bcm43xx_dmadesc_generic *desc,
+- dma_addr_t dmaaddr,
+- u16 bufsize,
+- int start, int end, int irq)
+-{
+- int slot;
+-
+- slot = bcm43xx_dma_desc2idx(ring, desc);
+- assert(slot >= 0 && slot < ring->nr_slots);
+-
+- if (ring->dma64) {
+- u32 ctl0 = 0, ctl1 = 0;
+- u32 addrlo, addrhi;
+- u32 addrext;
+-
+- addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
+- addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING);
+- addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+- addrhi |= ring->routing;
+- if (slot == ring->nr_slots - 1)
+- ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND;
+- if (start)
+- ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART;
+- if (end)
+- ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND;
+- if (irq)
+- ctl0 |= BCM43xx_DMA64_DCTL0_IRQ;
+- ctl1 |= (bufsize - ring->frameoffset)
+- & BCM43xx_DMA64_DCTL1_BYTECNT;
+- ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT)
+- & BCM43xx_DMA64_DCTL1_ADDREXT_MASK;
+-
+- desc->dma64.control0 = cpu_to_le32(ctl0);
+- desc->dma64.control1 = cpu_to_le32(ctl1);
+- desc->dma64.address_low = cpu_to_le32(addrlo);
+- desc->dma64.address_high = cpu_to_le32(addrhi);
+- } else {
+- u32 ctl;
+- u32 addr;
+- u32 addrext;
+-
+- addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING);
+- addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING)
+- >> BCM43xx_DMA32_ROUTING_SHIFT;
+- addr |= ring->routing;
+- ctl = (bufsize - ring->frameoffset)
+- & BCM43xx_DMA32_DCTL_BYTECNT;
+- if (slot == ring->nr_slots - 1)
+- ctl |= BCM43xx_DMA32_DCTL_DTABLEEND;
+- if (start)
+- ctl |= BCM43xx_DMA32_DCTL_FRAMESTART;
+- if (end)
+- ctl |= BCM43xx_DMA32_DCTL_FRAMEEND;
+- if (irq)
+- ctl |= BCM43xx_DMA32_DCTL_IRQ;
+- ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT)
+- & BCM43xx_DMA32_DCTL_ADDREXT_MASK;
+-
+- desc->dma32.control = cpu_to_le32(ctl);
+- desc->dma32.address = cpu_to_le32(addr);
+- }
+-}
+-
+-static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
+- struct bcm43xx_dmadesc_generic *desc,
+- struct bcm43xx_dmadesc_meta *meta,
+- gfp_t gfp_flags)
+-{
+- struct bcm43xx_rxhdr *rxhdr;
+- struct bcm43xx_hwxmitstatus *xmitstat;
+- dma_addr_t dmaaddr;
+- struct sk_buff *skb;
+-
+- assert(!ring->tx);
+-
+- skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+- if (unlikely(!skb))
+- return -ENOMEM;
+- dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+- /* This hardware bug work-around adapted from the b44 driver.
+- The chip may be unable to do PCI DMA to/from anything above 1GB */
+- if (pci_dma_mapping_error(dmaaddr) ||
+- dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+- /* This one has 30-bit addressing... */
+- if (!pci_dma_mapping_error(dmaaddr))
+- pci_unmap_single(ring->bcm->pci_dev,
+- dmaaddr, ring->rx_buffersize,
+- PCI_DMA_FROMDEVICE);
+- dev_kfree_skb_any(skb);
+- skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
+- if (skb == NULL)
+- return -ENOMEM;
+- dmaaddr = pci_map_single(ring->bcm->pci_dev,
+- skb->data, ring->rx_buffersize,
+- PCI_DMA_FROMDEVICE);
+- if (pci_dma_mapping_error(dmaaddr) ||
+- dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+- assert(0);
+- dev_kfree_skb_any(skb);
+- return -ENOMEM;
+- }
+- }
+- meta->skb = skb;
+- meta->dmaaddr = dmaaddr;
+- skb->dev = ring->bcm->net_dev;
+-
+- fill_descriptor(ring, desc, dmaaddr,
+- ring->rx_buffersize, 0, 0, 0);
+-
+- rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
+- rxhdr->frame_length = 0;
+- rxhdr->flags1 = 0;
+- xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data);
+- xmitstat->cookie = 0;
+-
+- return 0;
+-}
+-
+-/* Allocate the initial descbuffers.
+- * This is used for an RX ring only.
+- */
+-static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
+-{
+- int i, err = -ENOMEM;
+- struct bcm43xx_dmadesc_generic *desc;
+- struct bcm43xx_dmadesc_meta *meta;
+-
+- for (i = 0; i < ring->nr_slots; i++) {
+- desc = bcm43xx_dma_idx2desc(ring, i, &meta);
+-
+- err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+- if (err)
+- goto err_unwind;
+- }
+- mb();
+- ring->used_slots = ring->nr_slots;
+- err = 0;
+-out:
+- return err;
+-
+-err_unwind:
+- for (i--; i >= 0; i--) {
+- desc = bcm43xx_dma_idx2desc(ring, i, &meta);
+-
+- unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+- dev_kfree_skb(meta->skb);
+- }
+- goto out;
+-}
+-
+-/* Do initial setup of the DMA controller.
+- * Reset the controller, write the ring busaddress
+- * and switch the "enable" bit on.
+- */
+-static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
+-{
+- int err = 0;
+- u32 value;
+- u32 addrext;
+-
+- if (ring->tx) {
+- if (ring->dma64) {
+- u64 ringbase = (u64)(ring->dmabase);
+-
+- addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+- value = BCM43xx_DMA64_TXENABLE;
+- value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT)
+- & BCM43xx_DMA64_TXADDREXT_MASK;
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value);
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO,
+- (ringbase & 0xFFFFFFFF));
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI,
+- ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+- | ring->routing);
+- } else {
+- u32 ringbase = (u32)(ring->dmabase);
+-
+- addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+- value = BCM43xx_DMA32_TXENABLE;
+- value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT)
+- & BCM43xx_DMA32_TXADDREXT_MASK;
+- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value);
+- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING,
+- (ringbase & ~BCM43xx_DMA32_ROUTING)
+- | ring->routing);
+- }
+- } else {
+- err = alloc_initial_descbuffers(ring);
+- if (err)
+- goto out;
+- if (ring->dma64) {
+- u64 ringbase = (u64)(ring->dmabase);
+-
+- addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+- value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT);
+- value |= BCM43xx_DMA64_RXENABLE;
+- value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT)
+- & BCM43xx_DMA64_RXADDREXT_MASK;
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value);
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO,
+- (ringbase & 0xFFFFFFFF));
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI,
+- ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+- | ring->routing);
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200);
+- } else {
+- u32 ringbase = (u32)(ring->dmabase);
+-
+- addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+- value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT);
+- value |= BCM43xx_DMA32_RXENABLE;
+- value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT)
+- & BCM43xx_DMA32_RXADDREXT_MASK;
+- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value);
+- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING,
+- (ringbase & ~BCM43xx_DMA32_ROUTING)
+- | ring->routing);
+- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200);
+- }
+- }
+-
+-out:
+- return err;
+-}
+-
+-/* Shutdown the DMA controller. */
+-static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
+-{
+- if (ring->tx) {
+- bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+- if (ring->dma64) {
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0);
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0);
+- } else
+- bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0);
+- } else {
+- bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+- if (ring->dma64) {
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0);
+- bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0);
+- } else
+- bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0);
+- }
+-}
+-
+-static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
+-{
+- struct bcm43xx_dmadesc_generic *desc;
+- struct bcm43xx_dmadesc_meta *meta;
+- int i;
+-
+- if (!ring->used_slots)
+- return;
+- for (i = 0; i < ring->nr_slots; i++) {
+- desc = bcm43xx_dma_idx2desc(ring, i, &meta);
+-
+- if (!meta->skb) {
+- assert(ring->tx);
+- continue;
+- }
+- if (ring->tx) {
+- unmap_descbuffer(ring, meta->dmaaddr,
+- meta->skb->len, 1);
+- } else {
+- unmap_descbuffer(ring, meta->dmaaddr,
+- ring->rx_buffersize, 0);
+- }
+- free_descriptor_buffer(ring, meta, 0);
+- }
+-}
+-
+-/* Main initialization function. */
+-static
+-struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
+- int controller_index,
+- int for_tx,
+- int dma64)
+-{
+- struct bcm43xx_dmaring *ring;
+- int err;
+- int nr_slots;
+-
+- ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+- if (!ring)
+- goto out;
+-
+- nr_slots = BCM43xx_RXRING_SLOTS;
+- if (for_tx)
+- nr_slots = BCM43xx_TXRING_SLOTS;
+-
+- ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta),
+- GFP_KERNEL);
+- if (!ring->meta)
+- goto err_kfree_ring;
+-
+- ring->routing = BCM43xx_DMA32_CLIENTTRANS;
+- if (dma64)
+- ring->routing = BCM43xx_DMA64_CLIENTTRANS;
+-
+- ring->bcm = bcm;
+- ring->nr_slots = nr_slots;
+- ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
+- ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
+- assert(ring->suspend_mark < ring->resume_mark);
+- ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index);
+- ring->index = controller_index;
+- ring->dma64 = !!dma64;
+- if (for_tx) {
+- ring->tx = 1;
+- ring->current_slot = -1;
+- } else {
+- if (ring->index == 0) {
+- ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE;
+- ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET;
+- } else if (ring->index == 3) {
+- ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE;
+- ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET;
+- } else
+- assert(0);
+- }
+-
+- err = alloc_ringmemory(ring);
+- if (err)
+- goto err_kfree_meta;
+- err = dmacontroller_setup(ring);
+- if (err)
+- goto err_free_ringmemory;
+- return ring;
+-
+-out:
+- printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
+- return ring;
+-
+-err_free_ringmemory:
+- free_ringmemory(ring);
+-err_kfree_meta:
+- kfree(ring->meta);
+-err_kfree_ring:
+- kfree(ring);
+- ring = NULL;
+- goto out;
+-}
+-
+-/* Main cleanup function. */
+-static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
+-{
+- if (!ring)
+- return;
+-
+- dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
+- (ring->dma64) ? "64" : "32",
+- ring->mmio_base,
+- (ring->tx) ? "TX" : "RX",
+- ring->max_used_slots, ring->nr_slots);
+- /* Device IRQs are disabled prior entering this function,
+- * so no need to take care of concurrency with rx handler stuff.
+- */
+- dmacontroller_cleanup(ring);
+- free_all_descbuffers(ring);
+- free_ringmemory(ring);
+-
+- kfree(ring->meta);
+- kfree(ring);
+-}
+-
+-void bcm43xx_dma_free(struct bcm43xx_private *bcm)
+-{
+- struct bcm43xx_dma *dma;
+-
+- if (bcm43xx_using_pio(bcm))
+- return;
+- dma = bcm43xx_current_dma(bcm);
+-
+- bcm43xx_destroy_dmaring(dma->rx_ring3);
+- dma->rx_ring3 = NULL;
+- bcm43xx_destroy_dmaring(dma->rx_ring0);
+- dma->rx_ring0 = NULL;
+-
+- bcm43xx_destroy_dmaring(dma->tx_ring5);
+- dma->tx_ring5 = NULL;
+- bcm43xx_destroy_dmaring(dma->tx_ring4);
+- dma->tx_ring4 = NULL;
+- bcm43xx_destroy_dmaring(dma->tx_ring3);
+- dma->tx_ring3 = NULL;
+- bcm43xx_destroy_dmaring(dma->tx_ring2);
+- dma->tx_ring2 = NULL;
+- bcm43xx_destroy_dmaring(dma->tx_ring1);
+- dma->tx_ring1 = NULL;
+- bcm43xx_destroy_dmaring(dma->tx_ring0);
+- dma->tx_ring0 = NULL;
+-}
+-
+-int bcm43xx_dma_init(struct bcm43xx_private *bcm)
+-{
+- struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
+- struct bcm43xx_dmaring *ring;
+- int err = -ENOMEM;
+- int dma64 = 0;
+-
+- bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
+- if (bcm->dma_mask == DMA_64BIT_MASK)
+- dma64 = 1;
+- err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
+- if (err)
+- goto no_dma;
+- err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
+- if (err)
+- goto no_dma;
+-
+- /* setup TX DMA channels. */
+- ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
+- if (!ring)
+- goto out;
+- dma->tx_ring0 = ring;
+-
+- ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64);
+- if (!ring)
+- goto err_destroy_tx0;
+- dma->tx_ring1 = ring;
+-
+- ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64);
+- if (!ring)
+- goto err_destroy_tx1;
+- dma->tx_ring2 = ring;
+-
+- ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64);
+- if (!ring)
+- goto err_destroy_tx2;
+- dma->tx_ring3 = ring;
+-
+- ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64);
+- if (!ring)
+- goto err_destroy_tx3;
+- dma->tx_ring4 = ring;
+-
+- ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64);
+- if (!ring)
+- goto err_destroy_tx4;
+- dma->tx_ring5 = ring;
+-
+- /* setup RX DMA channels. */
+- ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64);
+- if (!ring)
+- goto err_destroy_tx5;
+- dma->rx_ring0 = ring;
+-
+- if (bcm->current_core->rev < 5) {
+- ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
+- if (!ring)
+- goto err_destroy_rx0;
+- dma->rx_ring3 = ring;
+- }
+-
+- dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
+- (bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
+- (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
+- err = 0;
+-out:
+- return err;
+-
+-err_destroy_rx0:
+- bcm43xx_destroy_dmaring(dma->rx_ring0);
+- dma->rx_ring0 = NULL;
+-err_destroy_tx5:
+- bcm43xx_destroy_dmaring(dma->tx_ring5);
+- dma->tx_ring5 = NULL;
+-err_destroy_tx4:
+- bcm43xx_destroy_dmaring(dma->tx_ring4);
+- dma->tx_ring4 = NULL;
+-err_destroy_tx3:
+- bcm43xx_destroy_dmaring(dma->tx_ring3);
+- dma->tx_ring3 = NULL;
+-err_destroy_tx2:
+- bcm43xx_destroy_dmaring(dma->tx_ring2);
+- dma->tx_ring2 = NULL;
+-err_destroy_tx1:
+- bcm43xx_destroy_dmaring(dma->tx_ring1);
+- dma->tx_ring1 = NULL;
+-err_destroy_tx0:
+- bcm43xx_destroy_dmaring(dma->tx_ring0);
+- dma->tx_ring0 = NULL;
+-no_dma:
+-#ifdef CONFIG_BCM43XX_PIO
+- printk(KERN_WARNING PFX "DMA not supported on this device."
+- " Falling back to PIO.\n");
+- bcm->__using_pio = 1;
+- return -ENOSYS;
+-#else
+- printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+- "Please recompile the driver with PIO support.\n");
+- return -ENODEV;
+-#endif /* CONFIG_BCM43XX_PIO */
+-}
+-
+-/* Generate a cookie for the TX header. */
+-static u16 generate_cookie(struct bcm43xx_dmaring *ring,
+- int slot)
+-{
+- u16 cookie = 0x1000;
+-
+- /* Use the upper 4 bits of the cookie as
+- * DMA controller ID and store the slot number
+- * in the lower 12 bits.
+- * Note that the cookie must never be 0, as this
+- * is a special value used in RX path.
+- */
+- switch (ring->index) {
+- case 0:
+- cookie = 0xA000;
+- break;
+- case 1:
+- cookie = 0xB000;
+- break;
+- case 2:
+- cookie = 0xC000;
+- break;
+- case 3:
+- cookie = 0xD000;
+- break;
+- case 4:
+- cookie = 0xE000;
+- break;
+- case 5:
+- cookie = 0xF000;
+- break;
+- }
+- assert(((u16)slot & 0xF000) == 0x0000);
+- cookie |= (u16)slot;
+-
+- return cookie;
+-}
+-
+-/* Inspect a cookie and find out to which controller/slot it belongs. */
+-static
+-struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
+- u16 cookie, int *slot)
+-{
+- struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
+- struct bcm43xx_dmaring *ring = NULL;
+-
+- switch (cookie & 0xF000) {
+- case 0xA000:
+- ring = dma->tx_ring0;
+- break;
+- case 0xB000:
+- ring = dma->tx_ring1;
+- break;
+- case 0xC000:
+- ring = dma->tx_ring2;
+- break;
+- case 0xD000:
+- ring = dma->tx_ring3;
+- break;
+- case 0xE000:
+- ring = dma->tx_ring4;
+- break;
+- case 0xF000:
+- ring = dma->tx_ring5;
+- break;
+- default:
+- assert(0);
+- }
+- *slot = (cookie & 0x0FFF);
+- assert(*slot >= 0 && *slot < ring->nr_slots);
+-
+- return ring;
+-}
+-
+-static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
+- int slot)
+-{
+- u16 offset;
+- int descsize;
+-
+- /* Everything is ready to start. Buffers are DMA mapped and
+- * associated with slots.
+- * "slot" is the last slot of the new frame we want to transmit.
+- * Close your seat belts now, please.