Browse Source

Upgrade rt2x00 to a more recent snapshot, master mode now working, thanks to Daniel Gimpelevich

SVN-Revision: 8367
Florian Fainelli 18 years ago
parent
commit
195c4d9a3d

+ 6 - 5
package/rt2x00/Makefile

@@ -10,8 +10,7 @@ include $(TOPDIR)/rules.mk
 include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=rt2x00
-#PKG_VERSION:=cvs-20070725
-PKG_VERSION:=git-200706018
+PKG_VERSION:=cvs-20070712
 
 include $(INCLUDE_DIR)/package.mk
 
@@ -107,18 +106,20 @@ endef
 define Build/Prepare
 	$(call Build/Prepare/Default)
 	$(CP) -r src/* $(PKG_BUILD_DIR)/
-	sed 's/\$$$$(CONFIG_RT.*)/m\t\t/g' src/Makefile > $(PKG_BUILD_DIR)/Makefile
+	wget -N -P $(DL_DIR) http://www.ralinktech.com.tw/data/RT61_Firmware_V1.2.zip
+	wget -N -P $(DL_DIR) http://www.ralinktech.com.tw/data/RT71W_Firmware_V1.8.zip
+	unzip -jod $(PKG_BUILD_DIR) $(DL_DIR)/RT61_Firmware_V1.2.zip
+	unzip -jod $(PKG_BUILD_DIR) $(DL_DIR)/RT71W_Firmware_V1.8.zip
 endef
 
 define Build/Compile
-#	$(MAKE) -C "$(PKG_BUILD_DIR)" config_header
+	$(MAKE) -C "$(PKG_BUILD_DIR)" config_header
 	$(MAKE) -C "$(LINUX_DIR)" \
 		CROSS_COMPILE="$(TARGET_CROSS)" \
 		ARCH="$(LINUX_KARCH)" V="$(V)" \
 		SUBDIRS="$(PKG_BUILD_DIR)" \
 		KERNELVERSION="$(KERNEL)" \
 		KERNEL_SOURCE="$(LINUX_DIR)" \
-		CFLAGS_MODULE="-DMODULE -include $(PKG_BUILD_DIR)/rt2x00_compat.h" \
 		KDIR="$(LINUX_DIR)"
 endef
 

+ 340 - 0
package/rt2x00/src/COPYING

@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

+ 144 - 8
package/rt2x00/src/Makefile

@@ -1,11 +1,147 @@
-rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00firmware.o
+#	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+#	<http://rt2x00.serialmonkey.com>
+#
+#	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; if not, write to the
+#	Free Software Foundation, Inc.,
+#	59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-EXTRA_CFLAGS += -DCONFIG_RT2X00_LIB_FIRMWARE
+#	Module: Makefile
+#	Abstract: Makefile for rt2x00 kernel module
 
-obj-m				+= rt2x00lib.o rt2x00pci.o rt2x00usb.o
+#
+# Set the enviroment variables.
+#
+ifndef SUBDIRS
+	SUBDIRS=$(shell pwd)
+endif
 
-obj-$(CONFIG_RT2400PCI)		+= rt2400pci.o
-obj-$(CONFIG_RT2500PCI)		+= rt2500pci.o
-obj-$(CONFIG_RT61PCI)		+= rt61pci.o
-obj-$(CONFIG_RT2500USB)		+= rt2500usb.o
-obj-$(CONFIG_RT73USB)		+= rt73usb.o
+ifdef KERNDIR
+	KERNEL_SOURCES := $(KERNDIR)
+else
+	KERNEL_SOURCES := /lib/modules/$(shell uname -r)/build
+endif
+
+ifdef KERNOUT
+	KERNEL_OUTPUT := KBUILD_OUTPUT=$(KERNOUT)
+else
+	KERNEL_OUTPUT :=
+endif
+
+#
+# Include kernel and rt2x00 config.
+#
+include $(KERNEL_SOURCES)/.config
+include $(SUBDIRS)/config
+
+#
+# Determine if and with what options the rt2x00 drivers should be build
+#
+rt2x00lib-objs := rt2x00dev.o rt2x00mac.o
+
+ifeq ($(CONFIG_RT2X00),y)
+
+ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
+	rt2x00lib-objs += rt2x00debug.o
+endif
+
+ifeq ($(CONFIG_RT2400PCI),y)
+	obj-m += rt2400pci.o rt2x00pci.o rt2x00lib.o
+ifeq ($(CONFIG_RT2400PCI_RFKILL),y)
+	rt2x00lib-objs += rt2x00rfkill.o
+	CFLAGS += -DCONFIG_RT2X00_LIB_RFKILL
+endif
+endif
+
+ifeq ($(CONFIG_RT2500PCI),y)
+	obj-m += rt2500pci.o rt2x00pci.o rt2x00lib.o
+ifeq ($(CONFIG_RT2500PCI_RFKILL),y)
+	rt2x00lib-objs += rt2x00rfkill.o
+	CFLAGS += -DCONFIG_RT2X00_LIB_RFKILL
+endif
+endif
+
+ifeq ($(CONFIG_RT2500USB),y)
+	obj-m += rt2500usb.o rt2x00usb.o rt2x00lib.o
+endif
+
+ifeq ($(CONFIG_RT61PCI),y)
+	CFLAGS += -DCONFIG_RT2X00_LIB_FIRMWARE
+	rt2x00lib-objs += rt2x00firmware.o
+	obj-m += rt61pci.o rt2x00pci.o rt2x00lib.o
+ifeq ($(CONFIG_RT61PCI_RFKILL),y)
+	rt2x00lib-objs += rt2x00rfkill.o
+	CFLAGS += -DCONFIG_RT2X00_LIB_RFKILL
+endif
+endif
+
+ifeq ($(CONFIG_RT73USB),y)
+	CFLAGS += -DCONFIG_RT2X00_LIB_FIRMWARE
+	rt2x00lib-objs += rt2x00firmware.o
+	obj-m += rt73usb.o rt2x00usb.o rt2x00lib.o
+endif
+
+endif
+
+MAKEFLAGS += --no-print-directory
+CFLAGS := -include $(SUBDIRS)/rt2x00_compat.h $(CFLAGS)
+
+all: default
+
+config_header:
+	@if [ ! -f "rt2x00_config.h" ] || [ "rt2x00_config.h" -ot "config" ]; \
+	then \
+		awk -F = > rt2x00_config.h < config '/^CONFIG.*$\/ \
+		{ \
+			if($$2 == "y") { \
+				print "#ifndef " $$1; \
+				print "#define " $$1; \
+				print "#endif"; \
+				print "" \
+			} else { \
+				print "#undef " $$1; \
+				print ""; \
+			} \
+		}'; \
+	fi
+
+default: config_header
+	@$(MAKE) -C $(KERNEL_SOURCES) SUBDIRS=$(SUBDIRS) $(KERNEL_OUTPUT) \
+		modules
+
+sparse: config_header
+	@$(MAKE) -C $(KERNEL_SOURCES) SUBDIRS=$(SUBDIRS) $(KERNEL_OUTPUT) \
+		modules C=1 CF=-D__CHECK_ENDIAN__
+
+install: config_header
+	@$(MAKE) -C $(KERNEL_SOURCES) SUBDIRS=$(SUBDIRS) $(KERNEL_OUTPUT) \
+		INSTALL_MOD_DIR=rt2x00 $(KERNEL_OUTPUT) modules_install
+	/sbin/depmod -a
+
+clean:
+	@rm -f rt2x00_config.h
+	@rm -f Modules.symvers Module.symvers
+	@for folder in $(EXTMODDIRS); \
+	do \
+		rm -f $${folder}/*.o \
+		rm -f $${folder}/*.ko \
+		rm -f $${folder}/*.s \
+		rm -f $${folder}/*.mod.c \
+		rm -f $${folder}/.*.cmd \
+		rm -f $${folder}/.*.flags \
+		rm -f $${folder}/.*.o.d \
+		rm -f $${folder}/.*.s.d \
+		rm -f $${folder}/.#* \
+		rm -f $${folder}/*~ \
+		rm -fr $${folder}/.tmp_versions; \
+	done

+ 548 - 0
package/rt2x00/src/README

@@ -0,0 +1,548 @@
+===============================================================================
+ Installation and configuration instructions for the rt2x00 Modules
+===============================================================================
+
+===============================================================================
+ Table of contents:
+========================
+
+ - 1: Minimal requirements
+   - 1.1: kernel
+   - 1.2: gcc
+   - 1.3: make
+ - 2: Hardware
+   - 2.1: Chipsets
+   - 2.2: RF button
+ -  3: Module building & Installation
+   - 3.1: Introduction
+   - 3.2: Configure
+   - 3.3: Build
+   - 3.4: Installation
+ - 4: Firmware
+   - 4.1: Firmware files
+   - 4.2: Firmware installation
+   - 4.3: Firmware requirements
+ - 5: Module loading
+   - 5.1: Module load order
+   - 5.2: Module load options
+ - 6: Interfaces
+   - 6.1: Wireless interfaces
+   - 6.2: Input interface
+ - 7: Interface configuration
+   - 7.1: Minimal configuration
+   - 7.2: Configuration tools
+ - 8: Distribution specific notes
+   - 8.1: Debian & derivatives
+   - 8.2: Fedora
+   - 8.3: Gentoo
+   - 8.4: Mandriva
+ - 9: Problems & Troubleshooting
+   - 9.1: Debug information
+   - 9.2: Debugfs
+   - 9.3: Bug reporting
+ - 10: Problems & Workarounds
+   - 10.1: udev interface naming
+   - 10.2: BUG - ifdown & ifup radio failure
+ - 11: TODO list
+ - 12: Contact us
+
+
+===============================================================================
+ 1: Minimal requirements:
+=======================================
+
+===================
+ 1.1: kernel
+=========
+
+ - The minimal required kernel version is 2.6.22-rc1
+
+ - It is important that the installed kernel sources match
+   the running kernel. Unless you are crosscompiling and you
+   know what you are doing.
+
+ - Depending on what rt2x00 components will be built,
+   some kernel configuration options are mandatory.
+   It does however not matter if these options are compiled
+   into the kernel or compiled as module.
+
+	Kernel config option	Required for component
+	------------------------------------------------------------------
+	# CONFIG_NET_RADIO	all
+	# CONFIG_MAC80211	all
+	# CONFIG_WLAN_80211	all
+	# CONFIG_PCI		rt2400pci, rt2500pci, rt61pci
+	# CONFIG_USB		rt2500usb, rt73usb
+	# CONFIG_HOTPLUG	rt61pci, rt73usb
+	# CONFIG_FW_LOADER	rt61pci, rt73usb
+	# CONFIG_CRC_ITU_T	rt61pci, rt73usb
+	# CONFIG_DEBUG_FS	rt2x00 (optional, only for debug)
+	# CONFIG_RFKILL		rt2400pci, rt2500pci, rt61pci (optional,
+							only for button support)
+
+===================
+ 1.2: GCC
+=========
+
+ - For building the rt2x00 components the same gcc version is required
+   as was used to build your target kernel.
+
+===================
+ 1.3: make
+=========
+
+ - The program 'make' needs to be installed on the system. There are no
+   further special requirements for this program.
+
+===============================================================================
+ 2: Hardware
+=======================================
+
+===================
+ 2.1: Chipsets
+=========
+
+ Support for each Ralink wireless chipset has been split into separate drivers.
+
+	# rt2400pci
+		- chipset: rt2400
+		- supports: rt2460
+		- bus type: PCI/PCMCIA/miniPCI
+	# rt2500pci
+		- chipset: rt2500
+		- supports: rt2560
+		- bus type: PCI/PCMCIA/miniPCI
+	# rt2500usb
+		- chipset: rt2570
+		- supports: rt2570
+		- bus type: USB
+	# rt61pci
+		- chipset: rt61 (or rt2600)
+		- supports: rt2561, rt2561s, rt2661
+		- bus type: PCI/PCMCIA/miniPCI
+	# rt73usb
+		- chipset: rt73
+		- supports: rt2571(w), rt2573, rt2671
+		- bus type: USB
+
+===================
+ 2.2: RF button
+=========
+
+ On some occasions the Ralink chipset has been built into a laptop.
+ If that is the case, there usually is a hardware button that controls the
+ radio of the wireless interface.
+ If you have such a hardware device, make sure you enable hardware button
+ support for your device in the configuration before building the rt2x00
+ components.
+ Note: This feature requires the enabling of the rfkill driver in the kernel.
+
+===============================================================================
+ 3: Module building & Installation
+=======================================
+
+===================
+ 3.1: Introduction
+=========
+
+ The following steps in this chapter concerning module building and
+ installation need to be performed for each kernel. This means that
+ after each kernel upgrade the modules need to be rebuild and
+ reinstalled in order to make them work with the new kernel.
+
+===================
+ 3.2: Configure
+=========
+
+ Before starting to build the rt2x00 components it is recommended to look into
+ the 'config' file first. In this file you can configure which components of
+ rt2x00 should be built. And even more importantly, you can configure with
+ what options the components will be built.
+ To build all the rt2x00 drivers (with debug capabilities enabled) no changes
+ in the configuration file are required. For most users this would be
+ sufficient to start working with rt2x00.
+
+===================
+ 3.3: Build
+=========
+
+ To build all rt2x00 components which were enabled in the configuration file
+ simply run (root privileges not required):
+
+	# $ make
+
+ All modules (.ko files) will be created in the current directory.
+
+===================
+ 3.4: Installation
+=========
+
+ All rt2x00 modules can be installed by doing (with root privileges):
+
+	 # $ make install
+
+ With this command all rt2x00 modules (including rfkill and d80211) will be
+ created in a newly created folder named 'rt2x00' inside the kernel modules
+ directory (usually '/lib/modules/$(uname -r)/').
+
+
+==============================================================================
+ 4: Firmware
+=======================================
+
+===================
+ 4.1: Firmware files
+=========
+
+ rt61pci and rt73usb require firmware to be available while loading the module.
+ The following firmware files are available for each driver:
+
+	# rt61pci
+		- rt2561.bin
+		- rt2561s.bin
+		- rt2661.bin
+
+	# rt73usb
+		- rt73.bin
+
+===================
+ 4.2: Firmware installation
+=========
+
+ The latest firmware files are available in a separate .zip archive and can be
+ downloaded from the support page on the Ralink website at
+ http://www.ralinktech.com.
+ Note that by a high level of logic, Ralink has named their firmware for rt73
+ chipsets "rt71W" with a comment that it is for the rt2571W and rt2671 devices.
+ For rt61pci 3 seperate firmware files are available, which one is used depends
+ on which RT chip is on the device. Usually it is best to install all files.
+ To install the firmware the firmware files need to be manually copied to the
+ systems firmware folder (usually '/lib/firmware/') the exact folder depends
+ on the distribution. When in doubt consult the distributions documentation.
+
+===================
+ 4.3: Firmware requirements
+=========
+
+ To load firmware when the module is loaded the hotplug daemon should be
+ running. Make sure you either enable hotplugging manually before loading the
+ module, or make sure hotplugging is enabled during the system boot process.
+
+
+==============================================================================
+ 5: Module loading
+=======================================
+
+===================
+ 5.1: Module load order
+=========
+
+ When the modules have been properly installed by following the installation
+ instructions from the previous section, the module handlers (i.e. modprobe)
+ will automaticly resolve all module dependencies when loading the device
+ specific driver.
+
+ When loading the modules manually with insmod, you should load them in the
+ following order:
+
+	# eeprom_93cx6.ko (optional, only required for pci devices)
+	# rt2x00lib.ko
+ 	# rt2x00pci.ko (optional, only required for pci devices)
+ 	# rt2x00usb.ko (optional, only required for usb devices)
+	# rt2400pci.ko (optional, only required for rt2400 support)
+	# rt2500pci.ko (optional, only required for rt2500 support)
+	# rt2500usb.ko (optional, only required for rt2570 support)
+	# rt61pci.ko (optional, only required for rt61 support)
+	# rt73usb.ko (optional, only required for rt73 support)
+
+===================
+ 5.2: Module load options
+=========
+
+ None.
+
+
+==============================================================================
+ 6: Interfaces
+=======================================
+
+===================
+ 6.1: Wireless interfaces
+=========
+
+ After loading the modules two interfaces will now be visible in ifconfig and
+ iwconfig, namely wmaster0 and wlan0. The first device is the so called master
+ device which is can be used by some userspace tools, but normally can be
+ ignored by the user. The second interface wlan0 is the client interface which
+ the user can configure.
+ With rt2x00 it is possible to run multiple client interfaces with
+ only a single device. 1 client interface can run in adhoc, managed or master
+ mode while a second interface can run in monitor mode at the same time.
+ More client interfaces can be added by issuing the following command
+ (with root privileges):
+
+ 	# $ echo -n <name> > /sys/class/ieee80211/<dev>/add_iface
+
+ where the variable <name> is the name of the client interface that should be
+ added (i.e. wlan1), and <dev> is the physical device where the new client
+ interface should be attached to (i.e. phy0).
+
+===================
+ 6.2: Input interface
+=========
+
+ When the rfkill driver is being used a new input device with the name of the
+ device specific module where the button belongs to will have been created.
+ Whenever the user presses the hardware button the rfkill driver will
+ automatically make sure the hardware radio is being disabled or enabled
+ accordingly. When the user has opened the input device the radio will
+ not be automatically controlled, but instead the input device will
+ report all button events (KEY_RFKILL) to userspace where the user
+ could have setup script to do all the work that has to be executed.
+ This means that while the input device is opened, the user is responsible
+ for the correct behaviour.
+
+
+==============================================================================
+ 7: Interface configuration
+=======================================
+
+===================
+ 7.1: Minimal configuration
+=========
+
+ - After loading the modules the interface should be configured to start
+   an association or work in monitor mode. The following steps are required
+   for a minimal configuration to associate with a non-encrypted access point.
+
+ - Before bringing the client interface up, the working mode should be set:
+
+	# $ iwconfig wlan0 mode managed
+
+ - Configuration parts like essid and channel can be set before or after the
+   client interface has been brought up.
+
+ - It is usually a good idea to set the essid:
+
+	# $ iwconfig wlan0 essid myessid
+
+ - In some situations the device also requires the channel to be manually set:
+
+	# $ iwconfig wlan0 channel mychannel
+
+ - To bring the client interface up:
+
+	# $ ifconfig wlan0 up
+
+ - After the client interface has been brought up, scanning can be performed
+   to check if the desired AP is being detected.
+
+	# $ iwlist wlan0 scan
+
+ - To start an association attempt, the AP address should be set:
+
+	# $ iwconfig wlan0 ap mybssid
+
+===================
+ 7.2: Configuration tools
+=========
+
+ To configure the interface several tools are possible, the most basic tools
+ are the wireless-tools that provide the iwconfig, iwpriv and iwlist commands.
+ For WPA connections the wireless-tools are not sufficient, to configure the
+ interface for WPA wireless network wpa_supplicant is required.
+ For master mode functionality it is possible to only use the wireless-tools,
+ but it is recommended to use hostapd instead. This tool offers the best
+ functionality.
+ For all configuration tools (wireless-tools, wpa_supplicant and hostapd) are
+ manuals and howto's present in the manpages or on the internet. It is adviced
+ to have at least read the manpages before using the tools for a better
+ understanding on configuring the interface.
+
+
+==============================================================================
+ 8: Distribution specific notes
+=======================================
+
+===================
+ 8.1: Debian & derivatives
+=========
+
+ In some instances installing the rt2x00 drivers on debian will result
+ in the problem that the files are being copied into the wrong folder,
+ which results in the fact that the driver cannot be loaded.
+ Installing the drivers should be done manually in this case,
+ please refer to the distributions documentation regarding the proper
+ location of the kernel modules.
+
+===================
+ 8.2: Fedora
+=========
+
+ Although rt2x00 contains many backward compatibility fixes to ensure
+ that all rt2x00 components will be able to compile and run on all
+ systems that meet the minimal requirements, this does not work in all
+ situations when the Fedora kernels are being used.
+ The problem lies in the fact that Fedora (like most other distributions)
+ heavily patch their kernel for better stability and more features.
+ Unlike the other distributions however, Fedora does not pay attention to
+ compatibility for external kernel drivers. This means that compiling rt2x00
+ while using a Fedora kernel will result in compile errors regarding unknown
+ fields in structures or problems with function arguments.
+ For rt2x00 it is impossible to make all checks to support all Fedora kernel
+ releases. This means that when rt2x00 compilation is failing while using a
+ Fedora kernel we cannot give support for the compilation steps.
+ We recommend the user to complain to the Fedora developers when this problem
+ occurs.
+ If the user has managed to compile rt2x00 for a Fedora kernel we will
+ give support for possible problems while working with rt2x00. So the only
+ part we do not support is the building of rt2x00.
+ Please note that when you have edited the rt2x00 code to make it compile,
+ it is advised to state those changes in bugreports while reporting other
+ problems with rt2x00.
+
+===================
+ 8.3: Gentoo
+=========
+
+ rt2x00 can also be found in portage, both the beta releases and the cvs tree.
+ Because rt2x00 is still experimental these ebuild are still masked, this means
+ that before you can emerge them they first have to be unmasked.
+ Gentoo provides various instructions on how this can be done on their website.
+
+===================
+ 8.4: Mandriva
+=========
+
+ In some instances installing the rt2x00 drivers on Mandriva will result
+ in the problem that the files are being copied into the wrong folder,
+ which results in the fact that the driver cannot be loaded.
+ Installing the drivers should be done manually in this case,
+ please refer to the distributions documentation regarding the proper
+ location of the kernel modules.
+
+
+==============================================================================
+ 9: Problems & Troubleshooting
+=======================================
+
+===================
+ 9.1: Debug information
+=========
+
+ When reporting problems make sure the driver has been compiled with debug
+ enabled.
+ If you have done so, the debug output can be found in the output
+ of 'dmesg' and also in /var/log/messages and /var/log/syslog.
+
+===================
+ 9.2: Debugfs
+=========
+
+ rt2x00 provides several debugfs entries which can be used to help
+ provide more information about the interface.
+ To see the rt2x00 debugfs entries, debugfs should first be mounted,
+ to do this you should issue the following command:
+
+	 # $ mount -t debugfs none /debug
+
+ Where /debug is the directy on which the debugfs entries should appear,
+ make sure this directory exists when mounting debugfs.
+ With the debugfs folder, the rt2x00 folder with the rt2x00 debugfs entries
+ will be created. Within the rt2x00 folder, each physical device will be
+ represented by a folder named after the interface which belongs to this
+ device. Within the folder the following files can be found:
+
+	# register
+		- This file contains the register contents of the interface.
+	# eeprom
+		- This file contains the eeprom contents of the interface.
+
+===================
+ 9.3: Bug reporting
+=========
+
+ When reporting a bug or problem with the rt2x00 module,
+ make sure you report the following information:
+	# How to reproduce
+	# RT2x00 debug output, usually found in /var/log/messages
+	# Module version
+	# Wireless card chipset, model and manufacturer
+	# Kernel version (i.e. 2.6.17)
+	# Hardware architecture (i.e. x86, AMD64, Sparc)
+	# rt2x00 code changes done by the user
+	# Anything else you may think will help us resolve the issue
+
+
+==============================================================================
+ 10: Problems & Workarounds
+=======================================
+
+===================
+ 10.1: udev interface naming
+=========
+
+ In some cases when loading the rt2x00 drivers the interface names are
+ different from the names used in this README. This is usually caused by the
+ udev handler who has set some rules regarding the interface. These rules
+ are usually set up by the distribution and have been created especially for
+ for the legacy driver and their strange behavior.
+ To change the rules udev applies to your interface you should edit the udev
+ rules stored in /etc/udev/rules.d/ (exact location might be different
+ depending on distribution).
+ When editing this file, search for the line that contains something like this:
+
+	# ACTION=="add", SUBSYSTEM=="net", DRIVERS=="?*",
+	#	SYSFS{address}=="<mac address>", NAME="<interface>"
+	(line has been wrapped due to max line length limit)
+
+ Where <mac address> is the hardware address of your wireless networkcard,
+ and <interface> is the interface name the interface takes as soon as the
+ rt2x00 modules are loaded.
+ This line should be changed to look like:
+
+	# ACTION=="add", SUBSYSTEM=="net", DRIVERS=="?*",
+	#	SYSFS{address}=="<mac address>", SYSFS{type}=="801",
+	#	NAME="wmaster0"
+	# ACTION=="add", SUBSYSTEM=="net", DRIVERS=="?*",
+	#	SYSFS{address}=="<mac address>", NAME="wlan0"
+	(the 2 lines have been wrapped due to max line length limit)
+
+ Where <mac address> is the hardware address of your wireless networkcard,
+ and thus should be the same as on the original line.
+
+===================
+ 10.2: BUG - ifdown & ifup radio failure
+=========
+
+ It is a known issue (and BUG) that the driver will fail to correctly resume
+ its radio operations after the interface has been brought down and up again.
+ It is still unknown what the cause for this issue could be, besides the fact
+ that for some reason the device's registers have been incorrectly initialized.
+ This issue also has impact on the device status after a suspend/resume
+ operation. There is no known workaround for this yet.
+
+
+==============================================================================
+ 11: TODO list
+=======================================
+ See http://rt2x00.serialmonkey.com/wiki/index.php/Rt2x00_beta
+
+==============================================================================
+ 12: Contact us
+=======================================
+
+ - Website
+	# http://rt2x00.serialmonkey.com/
+	# http://rt2x00.serialmonkey.com/wiki/index.php/Rt2x00_beta
+
+ - Forums:
+	# http://rt2x00.serialmonkey.com/phpBB2/
+
+ - Mailing list:
+	# general: [email protected]
+	# developers: [email protected]
+
+ - Sourceforge:
+	# http://sourceforge.net/projects/rt2400
+

+ 54 - 0
package/rt2x00/src/THANKS

@@ -0,0 +1,54 @@
+A big thanks to all the developers, testers and supporters of
+the rt2x00 Linux source code.
+
+Thanks to the projects main developers:
+* Mark Wallis - [email protected]
+* Ivo van Doorn - [email protected]
+* Luis Correia - [email protected]
+* Robin Cornelius - [email protected]
+* Gertjan van Wingerde - [email protected]
+* Romain - [email protected]
+
+Special thanks to the contributors of this project:
+* Adisorn Ermongkonchai - [email protected]
+* Amir Shalem - [email protected]
+* Bernd Petrovitsch - [email protected]
+* Bruno - [email protected]
+* Chris Houston - [email protected]
+* Defekt - [email protected]
+* Edvard - [email protected]
+* Flavio Stanchina - [email protected]
+* Gregor Glomm - [email protected]
+* Heikki Pernu - [email protected]
+* Jerzy Kozera - [email protected]
+* Joachim Gleißner - [email protected]
+* John Coppens - [email protected]
+* Jonathan Hudson
+* KrissN - [email protected]
+* Luca Tettamanti - [email protected]
+* Magnus Damm - [email protected]
+* Mags
+* Mathias Klien - [email protected]
+* Meelis Roos - [email protected]
+* Michal Ludvig - [email protected]
+* Miguel - [email protected]
+* Mike Skinner
+* Olivier Cornu - [email protected]
+* Paul Hampson - [email protected]
+* Philippe Rousselot - [email protected]
+* Remco - [email protected]
+* Sergey Vlasov - [email protected]
+* Stephen Warren - [email protected]
+* Stuart Rackham - [email protected]
+* Thor Harald Johansen - [email protected]
+* Tor Petterson - [email protected]
+
+Special thanks:
+* Ralink - http://www.ralinktech.com.tw
+  For releasing their rt2400/rt2500/rt2570 drivers under the GPL,
+  and their assistance in providing documentation to help development.
+* Minitar - www.minitar.com
+  For working together with Ralink on releasing the
+  rt2400/rt2500/rt2570 drivers under the GPL.
+* All the people that have assisted with the rt2400/rt2500/rt2570 source
+  and hence progressed the rt2x00 along the way.

+ 41 - 0
package/rt2x00/src/config

@@ -0,0 +1,41 @@
+# rt2x00 configuration
+# All configuration options can be enabled
+# by setting the value to 'y'. To disable
+# the option it should be set to 'n'.
+
+#
+# RT2X00 generic support
+#
+
+# Enable rt2x00 support
+CONFIG_RT2X00=y
+# Enable rt2x00 debug output
+CONFIG_RT2X00_DEBUG=y
+# Enable rt2x00 debugfs support
+CONFIG_RT2X00_DEBUGFS=n
+# Enable rt2x00 asm file creation
+CONFIG_RT2X00_ASM=n
+
+#
+# RT2X00 driver support
+#
+# Enable rt2400pci support
+CONFIG_RT2400PCI=y
+# Enable rt2400pci hardware button support (requires rfkill)
+CONFIG_RT2400PCI_BUTTON=n
+
+# Enable rt2500pci support
+CONFIG_RT2500PCI=y
+# Enable rt2500pci hardware button support (requires rfkill)
+CONFIG_RT2500PCI_BUTTON=n
+
+# Enable rt2500usb support
+CONFIG_RT2500USB=y
+
+# Enable rt61pci support
+CONFIG_RT61PCI=y
+# Enable rt61pci hardware button support (requires rfkill)
+CONFIG_RT61PCI_BUTTON=n
+
+# Enable rt73usb support
+CONFIG_RT73USB=y

+ 79 - 78
package/rt2x00/src/rt2400pci.c

@@ -42,6 +42,7 @@
 #include <asm/io.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00pci.h"
 #include "rt2400pci.h"
 
@@ -614,7 +615,7 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
 /*
  * Link tuning
  */
-static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
+static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
 {
 	u8 reg;
 	char false_cca_delta;
@@ -623,7 +624,7 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
 	 * The link tuner should not run longer then 60 seconds,
 	 * and should run once every 2 seconds.
 	 */
-	if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count % 1))
+	if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1))
 		return;
 
 	/*
@@ -649,6 +650,7 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
 		reg += 2;
 		if (reg < 0x20)
 			rt2400pci_bbp_write(rt2x00dev, 13, reg);
+		rt2x00dev->rx_status.noise = reg;
 	}
 }
 
@@ -926,10 +928,34 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
 	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
 }
 
-static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled)
 {
 	u32 reg;
 
+	/*
+	 * When interrupts are being enabled, the interrupt registers
+	 * should clear the register to assure a clean state.
+	 */
+	if (enabled) {
+		rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+		rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+	}
+
+	/*
+	 * Only toggle the interrupts bits we are going to use.
+	 * Non-checked interrupt bits are disabled by default.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, !enabled);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, !enabled);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, !enabled);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, !enabled);
+	rt2x00_set_field32(&reg, CSR8_RXDONE, !enabled);
+	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
 	/*
 	 * Initialize all registers.
 	 */
@@ -940,22 +966,10 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 		return -EIO;
 	}
 
-	/*
-	 * Clear interrupts.
-	 */
-	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
-	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
 	/*
 	 * Enable interrupts.
 	 */
-	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
-	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
-	rt2x00_set_field32(&reg, CSR8_RXDONE, 0);
-	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+	rt2400pci_toggle_irq(rt2x00dev, 1);
 
 	/*
 	 * Enable LED
@@ -991,13 +1005,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Disable interrupts.
 	 */
-	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
-	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 1);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 1);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 1);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 1);
-	rt2x00_set_field32(&reg, CSR8_RXDONE, 1);
-	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+	rt2400pci_toggle_irq(rt2x00dev, 0);
 }
 
 static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1163,59 +1171,40 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
 }
 
 /*
- * Interrupt functions.
+ * RX control handlers
  */
-static void rt2400pci_rxdone(struct rt2x00_dev *rt2x00dev)
+static int rt2400pci_fill_rxdone(struct data_entry *entry,
+	int *signal, int *rssi, int *ofdm)
 {
-	struct data_ring *ring = rt2x00dev->rx;
-	struct data_entry *entry;
-	struct data_desc *rxd;
+	struct data_desc *rxd = entry->priv;
 	u32 word0;
 	u32 word2;
-	int signal;
-	int rssi;
-	u16 size;
-
-	while (1) {
-		entry = rt2x00_get_data_entry(ring);
-		rxd = entry->priv;
-		rt2x00_desc_read(rxd, 0, &word0);
-		rt2x00_desc_read(rxd, 2, &word2);
-
-		if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
-			break;
-
-		/*
-		 * TODO: Don't we need to keep statistics
-		 * updated about events like CRC and physical errors?
-		 */
-		if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
-		    rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
-			goto skip_entry;
 
-		/*
-		 * Obtain the status about this packet.
-		 */
-		size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-		signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
-		rssi = rt2x00_get_field32(word2, RXD_W2_RSSI);
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 2, &word2);
 
-		/*
-		 * Send the packet to upper layer.
-		 */
-		rt2x00lib_rxdone(entry, entry->data_addr, size,
-			signal, rssi, 0);
+	/*
+	 * TODO: Don't we need to keep statistics
+	 * updated about these errors?
+	 */
+	if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
+	    rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+		return -EINVAL;
 
-skip_entry:
-		if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
-			rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1);
-			rt2x00_desc_write(rxd, 0, word0);
-		}
+	/*
+	 * Obtain the status about this packet.
+	 */
+	*signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+	*rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+		entry->ring->rt2x00dev->rssi_offset;
+	*ofdm = 0;
 
-		rt2x00_ring_index_inc(ring);
-	}
+	return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 }
 
+/*
+ * Interrupt functions.
+ */
 static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
 {
 	struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue);
@@ -1296,7 +1285,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
 	 * 2 - Rx ring done interrupt.
 	 */
 	if (rt2x00_get_field32(reg, CSR7_RXDONE))
-		rt2400pci_rxdone(rt2x00dev);
+		rt2x00pci_rxdone(rt2x00dev);
 
 	/*
 	 * 3 - Atim ring transmit done interrupt.
@@ -1327,6 +1316,7 @@ static int rt2400pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	struct eeprom_93cx6 eeprom;
 	u32 reg;
 	u16 word;
+	u8 *mac;
 
 	/*
 	 * Allocate the eeprom memory, check the eeprom width
@@ -1354,6 +1344,12 @@ static int rt2400pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Start validation of the data that has been read.
 	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+	}
+
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		ERROR(rt2x00dev, "Invalid EEPROM data detected.\n");
@@ -1440,16 +1436,16 @@ static void rt2400pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 		IEEE80211_HW_WEP_INCLUDE_IV |
 		IEEE80211_HW_DATA_NULLFUNC_ACK |
 		IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
-		IEEE80211_HW_MONITOR_DURING_OPER;
+		IEEE80211_HW_MONITOR_DURING_OPER |
+		IEEE80211_HW_NO_PROBE_FILTERING;
 	rt2x00dev->hw->extra_tx_headroom = 0;
 	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 	rt2x00dev->hw->max_noise = MAX_RX_NOISE;
 	rt2x00dev->hw->queues = 2;
 
-	/*
-	 * This device supports ATIM
-	 */
-	__set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+		rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
 
 	/*
 	 * Set device specific, but channel independent RF values.
@@ -1470,7 +1466,6 @@ static void rt2400pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize hw_mode information.
 	 */
-	spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	spec->num_modes = 1;
 	spec->num_rates = 4;
 	spec->num_channels = 14;
@@ -1501,6 +1496,16 @@ static int rt2400pci_init_hw(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2400pci_init_hw_mode(rt2x00dev);
 
+	/*
+	 * This device supports ATIM
+	 */
+	__set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
 	return 0;
 }
 
@@ -1599,8 +1604,6 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
 static const struct ieee80211_ops rt2400pci_mac80211_ops = {
 	.tx			= rt2x00lib_tx,
 	.reset			= rt2x00lib_reset,
-	.open			= rt2x00lib_open,
-	.stop			= rt2x00lib_stop,
 	.add_interface		= rt2x00lib_add_interface,
 	.remove_interface	= rt2x00lib_remove_interface,
 	.config			= rt2x00lib_config,
@@ -1629,6 +1632,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 	.write_tx_desc		= rt2400pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
 	.kick_tx_queue		= rt2400pci_kick_tx_queue,
+	.fill_rxdone		= rt2400pci_fill_rxdone,
 	.config_type		= rt2400pci_config_type,
 	.config_phymode		= rt2400pci_config_phymode,
 	.config_channel		= rt2400pci_config_channel,
@@ -1679,14 +1683,11 @@ static struct pci_driver rt2400pci_driver = {
 
 static int __init rt2400pci_init(void)
 {
-	printk(KERN_INFO "Loading module: %s - %s by %s.\n",
-		DRV_NAME, DRV_VERSION, DRV_PROJECT);
 	return pci_register_driver(&rt2400pci_driver);
 }
 
 static void __exit rt2400pci_exit(void)
 {
-	printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
 	pci_unregister_driver(&rt2400pci_driver);
 }
 

+ 3 - 2
package/rt2x00/src/rt2400pci.h

@@ -34,10 +34,11 @@
 #define RF2421				0x0001
 
 /*
- * Max RSSI value, required for RSSI <-> dBm conversion.
+ * Signal information.
  */
-#define MAX_RX_SSI			100
+#define MAX_RX_SSI			-1
 #define MAX_RX_NOISE			-110
+#define DEFAULT_RSSI_OFFSET		100
 
 /*
  * Register layout information.

+ 90 - 87
package/rt2x00/src/rt2500pci.c

@@ -42,6 +42,7 @@
 #include <asm/io.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00pci.h"
 #include "rt2500pci.h"
 
@@ -368,6 +369,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
 	u32 rf2 = value;
 	u32 rf3 = rt2x00dev->rf3;
 	u32 rf4 = rt2x00dev->rf4;
+	u8 r70;
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF2525) ||
 	    rt2x00_rf(&rt2x00dev->chip, RF2525E))
@@ -435,7 +437,9 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Channel 14 requires the Japan filter bit to be set.
 	 */
-	rt2500pci_bbp_write(rt2x00dev, 70, (channel == 14) ? 0x4e : 0x46);
+	r70 = 0x46;
+	rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, channel == 14);
+	rt2500pci_bbp_write(rt2x00dev, 70, r70);
 
 	msleep(1);
 
@@ -692,8 +696,9 @@ static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
 /*
  * Link tuning
  */
-static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
+static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
 {
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
 	u32 reg;
 	u8 r17;
 
@@ -722,7 +727,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
 	 */
 	if (rssi < -80 && rt2x00dev->link.count > 20) {
 		if (r17 >= 0x41) {
-			r17 = rt2x00dev->link.curr_noise;
+			r17 = rt2x00dev->rx_status.noise;
 			rt2500pci_bbp_write(rt2x00dev, 17, r17);
 		}
 		return;
@@ -751,7 +756,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
 	 * to the dynamic tuning range.
 	 */
 	if (r17 >= 0x41) {
-		rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.curr_noise);
+		rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->rx_status.noise);
 		return;
 	}
 
@@ -766,10 +771,10 @@ dynamic_cca_tune:
 
 	if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) {
 		rt2500pci_bbp_write(rt2x00dev, 17, ++r17);
-		rt2x00dev->link.curr_noise = r17;
+		rt2x00dev->rx_status.noise = r17;
 	} else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) {
 		rt2500pci_bbp_write(rt2x00dev, 17, --r17);
-		rt2x00dev->link.curr_noise = r17;
+		rt2x00dev->rx_status.noise = r17;
 	}
 }
 
@@ -898,7 +903,16 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
 		return -EBUSY;
 
 	rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
-	rt2x00pci_register_write(rt2x00dev, PCICSR, 0x000003b8);
+
+	rt2x00pci_register_read(rt2x00dev, PCICSR, &reg);
+	rt2x00_set_field32(&reg, PCICSR_BIG_ENDIAN, 0);
+	rt2x00_set_field32(&reg, PCICSR_RX_TRESHOLD, 0);
+	rt2x00_set_field32(&reg, PCICSR_TX_TRESHOLD, 3);
+	rt2x00_set_field32(&reg, PCICSR_BURST_LENTH, 1);
+	rt2x00_set_field32(&reg, PCICSR_ENABLE_CLK, 1);
+	rt2x00_set_field32(&reg, PCICSR_READ_MULTIPLE, 1);
+	rt2x00_set_field32(&reg, PCICSR_WRITE_INVALID, 1);
+	rt2x00pci_register_write(rt2x00dev, PCICSR, reg);
 
 	rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
 	rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
@@ -1079,10 +1093,34 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
 	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
 }
 
-static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled)
 {
 	u32 reg;
 
+	/*
+	 * When interrupts are being enabled, the interrupt registers
+	 * should clear the register to assure a clean state.
+	 */
+	if (enabled) {
+		rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+		rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+	}
+
+	/*
+	 * Only toggle the interrupts bits we are going to use.
+	 * Non-checked interrupt bits are disabled by default.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, !enabled);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, !enabled);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, !enabled);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, !enabled);
+	rt2x00_set_field32(&reg, CSR8_RXDONE, !enabled);
+	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
 	/*
 	 * Initialize all registers.
 	 */
@@ -1093,22 +1131,10 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 		return -EIO;
 	}
 
-	/*
-	 * Clear interrupts.
-	 */
-	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
-	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
 	/*
 	 * Enable interrupts.
 	 */
-	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
-	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
-	rt2x00_set_field32(&reg, CSR8_RXDONE, 0);
-	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+	rt2500pci_toggle_irq(rt2x00dev, 1);
 
 	/*
 	 * Enable LED
@@ -1144,13 +1170,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Disable interrupts.
 	 */
-	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
-	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 1);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 1);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 1);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 1);
-	rt2x00_set_field32(&reg, CSR8_RXDONE, 1);
-	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+	rt2500pci_toggle_irq(rt2x00dev, 0);
 }
 
 static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1300,61 +1320,37 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
 }
 
 /*
- * Interrupt functions.
+ * RX control handlers
  */
-static void rt2500pci_rxdone(struct rt2x00_dev *rt2x00dev)
+static int rt2500pci_fill_rxdone(struct data_entry *entry,
+	int *signal, int *rssi, int *ofdm)
 {
-	struct data_ring *ring = rt2x00dev->rx;
-	struct data_entry *entry;
-	struct data_desc *rxd;
+	struct data_desc *rxd = entry->priv;
 	u32 word0;
 	u32 word2;
-	int signal;
-	int rssi;
-	int ofdm;
-	u16 size;
-
-	while (1) {
-		entry = rt2x00_get_data_entry(ring);
-		rxd = entry->priv;
-		rt2x00_desc_read(rxd, 0, &word0);
-		rt2x00_desc_read(rxd, 2, &word2);
-
-		if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
-			break;
 
-		/*
-		 * TODO: Don't we need to keep statistics
-		 * updated about events like CRC and physical errors?
-		 */
-		if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
-		    rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
-			goto skip_entry;
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 2, &word2);
 
-		/*
-		 * Obtain the status about this packet.
-		 */
-		size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-		signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
-		rssi = rt2x00_get_field32(word2, RXD_W2_RSSI);
-		ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
-
-		/*
-		 * Send the packet to upper layer.
-		 */
-		rt2x00lib_rxdone(entry, entry->data_addr, size,
-			signal, rssi, ofdm);
+	/*
+	 * TODO: Don't we need to keep statistics
+	 * updated about these errors?
+	 */
+	if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
+	    rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+		return -EINVAL;
 
-skip_entry:
-		if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
-			rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1);
-			rt2x00_desc_write(rxd, 0, word0);
-		}
+	*signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+	*rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+		entry->ring->rt2x00dev->rssi_offset;
+	*ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
 
-		rt2x00_ring_index_inc(ring);
-	}
+	return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 }
 
+/*
+ * Interrupt functions.
+ */
 static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
 {
 	struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue);
@@ -1435,7 +1431,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
 	 * 2 - Rx ring done interrupt.
 	 */
 	if (rt2x00_get_field32(reg, CSR7_RXDONE))
-		rt2500pci_rxdone(rt2x00dev);
+		rt2x00pci_rxdone(rt2x00dev);
 
 	/*
 	 * 3 - Atim ring transmit done interrupt.
@@ -1466,6 +1462,7 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	struct eeprom_93cx6 eeprom;
 	u32 reg;
 	u16 word;
+	u8 *mac;
 
 	/*
 	 * Allocate the eeprom memory, check the eeprom width
@@ -1493,6 +1490,12 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Start validation of the data that has been read.
 	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+	}
+
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1518,7 +1521,7 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
-			MAX_RX_SSI);
+			DEFAULT_RSSI_OFFSET);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
 		EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
 	}
@@ -1586,7 +1589,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	 * Read the RSSI <-> dBm offset information.
 	 */
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
-	rt2x00dev->hw->max_rssi =
+	rt2x00dev->rssi_offset =
 		rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
 
 	return 0;
@@ -1660,16 +1663,16 @@ static void rt2500pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 		IEEE80211_HW_WEP_INCLUDE_IV |
 		IEEE80211_HW_DATA_NULLFUNC_ACK |
 		IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
-		IEEE80211_HW_MONITOR_DURING_OPER;
+		IEEE80211_HW_MONITOR_DURING_OPER |
+		IEEE80211_HW_NO_PROBE_FILTERING;
 	rt2x00dev->hw->extra_tx_headroom = 0;
 	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 	rt2x00dev->hw->max_noise = MAX_RX_NOISE;
 	rt2x00dev->hw->queues = 2;
 
-	/*
-	 * This device supports ATIM
-	 */
-	__set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+		rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
 
 	/*
 	 * Set device specific, but channel independent RF values.
@@ -1692,7 +1695,6 @@ static void rt2500pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize hw_mode information.
 	 */
-	spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	spec->num_modes = 2;
 	spec->num_rates = 12;
 	spec->num_channels = 14;
@@ -1738,6 +1740,11 @@ static int rt2500pci_init_hw(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2500pci_init_hw_mode(rt2x00dev);
 
+	/*
+	 * This device supports ATIM
+	 */
+	__set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+
 	return 0;
 }
 
@@ -1812,8 +1819,6 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
 static const struct ieee80211_ops rt2500pci_mac80211_ops = {
 	.tx			= rt2x00lib_tx,
 	.reset			= rt2x00lib_reset,
-	.open			= rt2x00lib_open,
-	.stop			= rt2x00lib_stop,
 	.add_interface		= rt2x00lib_add_interface,
 	.remove_interface	= rt2x00lib_remove_interface,
 	.config			= rt2x00lib_config,
@@ -1842,6 +1847,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 	.write_tx_desc		= rt2500pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
 	.kick_tx_queue		= rt2500pci_kick_tx_queue,
+	.fill_rxdone		= rt2500pci_fill_rxdone,
 	.config_type		= rt2500pci_config_type,
 	.config_phymode		= rt2500pci_config_phymode,
 	.config_channel		= rt2500pci_config_channel,
@@ -1892,14 +1898,11 @@ static struct pci_driver rt2500pci_driver = {
 
 static int __init rt2500pci_init(void)
 {
-	printk(KERN_INFO "Loading module: %s - %s by %s.\n",
-		DRV_NAME, DRV_VERSION, DRV_PROJECT);
 	return pci_register_driver(&rt2500pci_driver);
 }
 
 static void __exit rt2500pci_exit(void)
 {
-	printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
 	pci_unregister_driver(&rt2500pci_driver);
 }
 

+ 8 - 2
package/rt2x00/src/rt2500pci.h

@@ -45,10 +45,11 @@
 #define RT2560_VERSION_D		4
 
 /*
- * Max RSSI value, required for RSSI <-> dBm conversion.
+ * Signal information.
  */
-#define MAX_RX_SSI			121
+#define MAX_RX_SSI			-1
 #define MAX_RX_NOISE			-110
+#define DEFAULT_RSSI_OFFSET		121
 
 /*
  * Register layout information.
@@ -1045,6 +1046,11 @@
 #define BBP_R14_RX_ANTENNA		FIELD8(0x03)
 #define BBP_R14_RX_IQ_FLIP		FIELD8(0x04)
 
+/*
+ * BBP_R70
+ */
+#define BBP_R70_JAPAN_FILTER		FIELD8(0x08)
+
 /*
  * DMA descriptor defines.
  */

+ 47 - 115
package/rt2x00/src/rt2500usb.c

@@ -38,6 +38,7 @@
 #include <linux/etherdevice.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00usb.h"
 #include "rt2500usb.h"
 
@@ -638,8 +639,9 @@ static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev)
 /*
  * Link tuning
  */
-static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
+static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev)
 {
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
 	u16 bbp_thresh;
 	u16 cca_alarm;
 	u16 vgc_bound;
@@ -734,62 +736,19 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
 
 	if (r17 > up_bound) {
 		rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
-		rt2x00dev->link.curr_noise = up_bound;
+		rt2x00dev->rx_status.noise = up_bound;
 	} else if (cca_alarm > 512 && r17 < up_bound) {
 		rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
-		rt2x00dev->link.curr_noise = r17;
+		rt2x00dev->rx_status.noise = r17;
 	} else if (cca_alarm < 100 && r17 > low_bound) {
 		rt2500usb_bbp_write(rt2x00dev, 17, --r17);
-		rt2x00dev->link.curr_noise = r17;
+		rt2x00dev->rx_status.noise = r17;
 	}
 }
 
 /*
  * Initialization functions.
  */
-static void rt2500usb_init_rxring(struct rt2x00_dev *rt2x00dev)
-{
-	struct usb_device *usb_dev =
-		interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
-	unsigned int i;
-
-	for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
-		usb_fill_bulk_urb(
-			rt2x00dev->rx->entry[i].priv,
-			usb_dev,
-			usb_rcvbulkpipe(usb_dev, 1),
-			rt2x00dev->rx->entry[i].skb->data,
-			rt2x00dev->rx->entry[i].skb->len,
-			rt2500usb_interrupt_rxdone,
-			&rt2x00dev->rx->entry[i]);
-	}
-
-	rt2x00_ring_index_clear(rt2x00dev->rx);
-}
-
-static void rt2500usb_init_txring(struct rt2x00_dev *rt2x00dev,
-	const int queue)
-{
-	struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue);
-	unsigned int i;
-
-	for (i = 0; i < ring->stats.limit; i++)
-		ring->entry[i].flags = 0;
-
-	rt2x00_ring_index_clear(ring);
-}
-
-static int rt2500usb_init_rings(struct rt2x00_dev *rt2x00dev)
-{
-	rt2500usb_init_rxring(rt2x00dev);
-	rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
-	rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
-	rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
-	rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
-
-	return 0;
-}
-
 static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
 {
 	u16 reg;
@@ -801,7 +760,10 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
 		USB_VENDOR_REQUEST_OUT, 0x0308, 0xf0, NULL, 0,
 		REGISTER_TIMEOUT);
 
-	rt2500usb_register_write(rt2x00dev, TXRX_CSR2, 0x0001);
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
 	rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111);
 	rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11);
 
@@ -819,9 +781,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
 
 	rt2500usb_register_write(rt2x00dev, MAC_CSR1, 0x0004);
 
-	reg = 0;
-	rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
-	if (reg >= 0x0003) {
+	if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
 		rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
 		reg &= ~0x0002;
 	} else {
@@ -962,8 +922,7 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize all registers.
 	 */
-	if (rt2500usb_init_rings(rt2x00dev) ||
-	    rt2500usb_init_registers(rt2x00dev) ||
+	if (rt2500usb_init_registers(rt2x00dev) ||
 	    rt2500usb_init_bbp(rt2x00dev)) {
 		ERROR(rt2x00dev, "Register initialization failed.\n");
 		return -EIO;
@@ -1107,7 +1066,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_OFDM,
 		test_bit(ENTRY_TXD_OFDM_RATE, &entry->flags));
 	rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
-		test_bit(ENTRY_TXD_NEW_SEQ, &entry->flags));
+		control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT);
 	rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
 	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
 	rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
@@ -1141,74 +1100,40 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
 }
 
 /*
- * Interrupt functions.
+ * RX control handlers
  */
-static void rt2500usb_interrupt_rxdone(struct urb *urb)
+static int rt2500usb_fill_rxdone(struct data_entry *entry,
+	int *signal, int *rssi, int *ofdm)
 {
-	struct data_entry *entry = (struct data_entry*)urb->context;
-	struct data_ring *ring = entry->ring;
-	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
-	struct data_desc *rxd = (struct data_desc*)
-		(entry->skb->data + urb->actual_length - ring->desc_size);
+	struct urb *urb = entry->priv;
+	struct data_desc *rxd = (struct data_desc*)(entry->skb->data +
+		(urb->actual_length - entry->ring->desc_size));
 	u32 word0;
 	u32 word1;
-	int signal;
-	int rssi;
-	int ofdm;
-	u16 size;
-
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
-	    !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
-		return;
-
-	/*
-	 * Check if the received data is simply too small
-	 * to be actually valid, or if the urb is signaling
-	 * a problem.
-	 */
-	if (urb->actual_length < entry->ring->desc_size || urb->status)
-		goto skip_entry;
 
 	rt2x00_desc_read(rxd, 0, &word0);
 	rt2x00_desc_read(rxd, 1, &word1);
 
 	/*
 	 * TODO: Don't we need to keep statistics
-	 * updated about events like CRC and physical errors?
+	 * updated about these errors?
 	 */
 	if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
 	    rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
-		goto skip_entry;
+		return -EINVAL;
 
 	/*
 	 * Obtain the status about this packet.
 	 */
-	size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT) - FCS_LEN;
-	signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-	rssi = rt2x00_get_field32(word1, RXD_W1_RSSI);
-	ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+	*signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+	*rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+		entry->ring->rt2x00dev->rssi_offset;
+	*ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
 
 	/*
-	 * Trim the skb_buffer to only contain the valid
-	 * frame data (so ignore the device's descriptor).
+	 * rt2570 includes the FCS, so fix data length accordingly.
 	 */
-	skb_trim(entry->skb, size);
-
-	/*
-	 * Send the packet to upper layer, and update urb.
-	 */
-	rt2x00lib_rxdone(entry, NULL, ring->data_size + ring->desc_size,
-		signal, rssi, ofdm);
-	urb->transfer_buffer = entry->skb->data;
-	urb->transfer_buffer_length = entry->skb->len;
-
-skip_entry:
-	if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
-		__set_bit(ENTRY_OWNER_NIC, &entry->flags);
-		usb_submit_urb(urb, GFP_ATOMIC);
-	}
-
-	rt2x00_ring_index_inc(ring);
+	return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT) - FCS_LEN;
 }
 
 /*
@@ -1217,6 +1142,7 @@ skip_entry:
 static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 {
 	u16 word;
+	u8 *mac;
 
 	/*
 	 * Allocate the eeprom memory, check the eeprom width
@@ -1234,6 +1160,12 @@ static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Start validation of the data that has been read.
 	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+	}
+
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1259,7 +1191,7 @@ static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
-			MAX_RX_SSI);
+			DEFAULT_RSSI_OFFSET);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
 		EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
 	}
@@ -1366,7 +1298,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	 * Read the RSSI <-> dBm offset information.
 	 */
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
-	rt2x00dev->hw->max_rssi =
+	rt2x00dev->rssi_offset =
 		rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
 
 	return 0;
@@ -1443,16 +1375,16 @@ static void rt2500usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 		IEEE80211_HW_WEP_INCLUDE_IV |
 		IEEE80211_HW_DATA_NULLFUNC_ACK |
 		IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
-		IEEE80211_HW_MONITOR_DURING_OPER;
+		IEEE80211_HW_MONITOR_DURING_OPER |
+		IEEE80211_HW_NO_PROBE_FILTERING;
 	rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
 	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 	rt2x00dev->hw->max_noise = MAX_RX_NOISE;
 	rt2x00dev->hw->queues = 2;
 
-	/*
-	 * This device supports ATIM
-	 */
-	__set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+		rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
 
 	/*
 	 * Set device specific, but channel independent RF values.
@@ -1475,7 +1407,6 @@ static void rt2500usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize hw_mode information.
 	 */
-	spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	spec->num_modes = 2;
 	spec->num_rates = 12;
 	spec->num_channels = 14;
@@ -1522,6 +1453,11 @@ static int rt2500usb_init_hw(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2500usb_init_hw_mode(rt2x00dev);
 
+	/*
+	 * This device supports ATIM
+	 */
+	__set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+
 	return 0;
 }
 
@@ -1551,8 +1487,6 @@ static int rt2500usb_get_stats(struct ieee80211_hw *hw,
 static const struct ieee80211_ops rt2500usb_mac80211_ops = {
 	.tx			= rt2x00lib_tx,
 	.reset			= rt2x00lib_reset,
-	.open			= rt2x00lib_open,
-	.stop			= rt2x00lib_stop,
 	.add_interface		= rt2x00lib_add_interface,
 	.remove_interface	= rt2x00lib_remove_interface,
 	.config			= rt2x00lib_config,
@@ -1573,6 +1507,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
 	.write_tx_desc		= rt2500usb_write_tx_desc,
 	.write_tx_data		= rt2x00usb_write_tx_data,
 	.kick_tx_queue		= rt2500usb_kick_tx_queue,
+	.fill_rxdone		= rt2500usb_fill_rxdone,
 	.config_type		= rt2500usb_config_type,
 	.config_phymode		= rt2500usb_config_phymode,
 	.config_channel		= rt2500usb_config_channel,
@@ -1665,14 +1600,11 @@ static struct usb_driver rt2500usb_driver = {
 
 static int __init rt2500usb_init(void)
 {
-	printk(KERN_INFO "Loading module: %s - %s by %s.\n",
-		DRV_NAME, DRV_VERSION, DRV_PROJECT);
 	return usb_register(&rt2500usb_driver);
 }
 
 static void __exit rt2500usb_exit(void)
 {
-	printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
 	usb_deregister(&rt2500usb_driver);
 }
 

+ 10 - 7
package/rt2x00/src/rt2500usb.h

@@ -38,10 +38,18 @@
 #define RF5222				0x0010
 
 /*
- * Max RSSI value, required for RSSI <-> dBm conversion.
+ * RT2570 version
  */
-#define MAX_RX_SSI			120
+#define RT2570_VERSION_B		2
+#define RT2570_VERSION_C		3
+#define RT2570_VERSION_D		4
+
+/*
+ * Signal information.
+ */
+#define MAX_RX_SSI			-1
 #define MAX_RX_NOISE			-110
+#define DEFAULT_RSSI_OFFSET		120
 
 /*
  * Register layout information.
@@ -729,9 +737,4 @@
 	(__txpower));					\
 })
 
-/*
- * Interrupt functions.
- */
-static void rt2500usb_interrupt_rxdone(struct urb *urb);
-
 #endif /* RT2500USB_H */

+ 86 - 52
package/rt2x00/src/rt2x00.h

@@ -29,21 +29,17 @@
 #define RT2X00_H
 
 #include <linux/bitops.h>
+#include <linux/prefetch.h>
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 
 #include <net/mac80211.h>
 
-#include "rt2x00lib.h"
-#include "rt2x00debug.h"
-
 /*
  * Module information.
+ * DRV_NAME should be set within the individual module source files.
  */
-#ifndef DRV_NAME
-#define DRV_NAME	"rt2x00"
-#endif /* DRV_NAME */
-#define DRV_VERSION	"2.0.1"
+#define DRV_VERSION	"2.0.2"
 #define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
 
 /*
@@ -142,7 +138,7 @@
 /*
  * Interval defines
  */
-#define LINK_TUNE_INTERVAL	( 1 * HZ )
+#define LINK_TUNE_INTERVAL	( round_jiffies(HZ) )
 #define RFKILL_POLL_INTERVAL	( HZ / 4 )
 
 /*
@@ -392,7 +388,6 @@ struct data_entry {
 #define ENTRY_TXD_MORE_FRAG	5
 #define ENTRY_TXD_REQ_TIMESTAMP	6
 #define ENTRY_TXD_REQ_ACK	7
-#define ENTRY_TXD_NEW_SEQ	8
 
 	/*
 	 * Ring we belong to.
@@ -569,17 +564,26 @@ struct link {
 	 */
 	u32 count;
 
-	/*
-	 * RSSI statistics.
-	 */
-	u32 count_rssi;
-	u32 total_rssi;
-
 	/*
 	 * Misc statistics.
+	 * For the average RSSI value we use the "Walking average" approach.
+	 * When adding RSSI to the average value the following calculation
+	 * is needed:
+	 *
+	 * 	avg_rssi = ((avg_rssi * 7) + rssi) / 8;
+	 *
+	 * The advantage of this approach is that we only need 1 variable
+	 * to store the average in (No need for a count and a total).
+	 * But more importantly, normal average values will over time
+	 * move less and less towards newly added values.
+	 * This means that with link tuning, the device can have a very
+	 * good RSSI for a few minutes but when the device is moved away
+	 * from the AP the average will not decrease fast enough to
+	 * compensate. The walking average compensates this and will
+	 * move towards the new values correctly.
 	 */
-	u32 curr_noise;
-	u32 false_cca;
+	int avg_rssi;
+	int false_cca;
 
 	/*
 	 * Work structure for scheduling periodic link tuning.
@@ -636,6 +640,33 @@ static inline int is_monitor_present(struct interface *intf)
 	return !!intf->monitor_count;
 }
 
+/*
+ * Details about the supported modes, rates and channels
+ * of a particular chipset. This is used by rt2x00lib
+ * to build the ieee80211_hw_mode array for mac80211.
+ */
+struct hw_mode_spec {
+	/*
+	 * Number of modes, rates and channels.
+	 */
+	int num_modes;
+	int num_rates;
+	int num_channels;
+
+	/*
+	 * txpower values.
+	 */
+	const u8 *tx_power_a;
+	const u8 *tx_power_bg;
+	u8 tx_power_default;
+
+	/*
+	 * Device/chipset specific value.
+	 */
+	const u32 *chan_val_a;
+	const u32 *chan_val_bg;
+};
+
 /*
  * rt2x00lib callback functions.
  */
@@ -665,7 +696,7 @@ struct rt2x00lib_ops {
 	int (*set_device_state)(struct rt2x00_dev *rt2x00dev,
 		enum dev_state state);
 	int (*rfkill_poll)(struct rt2x00_dev *rt2x00dev);
-	void (*link_tuner)(struct rt2x00_dev *rt2x00dev, int rssi);
+	void (*link_tuner)(struct rt2x00_dev *rt2x00dev);
 
 	/*
 	 * TX control handlers
@@ -680,13 +711,19 @@ struct rt2x00lib_ops {
 		struct ieee80211_tx_control *control);
 	void (*kick_tx_queue)(struct rt2x00_dev *rt2x00dev, int queue);
 
+	/*
+	 * RX control handlers
+	 */
+	int (*fill_rxdone)(struct data_entry *entry,
+		int *signal, int *rssi, int *ofdm);
+
 	/*
 	 * Configuration handlers.
 	 */
 	void (*config_type)(struct rt2x00_dev *rt2x00dev, const int type);
 	void (*config_phymode)(struct rt2x00_dev *rt2x00dev, const int phy);
 	void (*config_channel)(struct rt2x00_dev *rt2x00dev, const int value,
-	const int channel, const int txpower);
+		const int channel, const int txpower);
 	void (*config_mac_addr)(struct rt2x00_dev *rt2x00dev, u8 *mac);
 	void (*config_bssid)(struct rt2x00_dev *rt2x00dev, u8 *bssid);
 	void (*config_promisc)(struct rt2x00_dev *rt2x00dev, const int promisc);
@@ -723,7 +760,6 @@ struct rt2x00_dev {
 	 * macro's should be used for correct typecasting.
 	 */
 	void *dev;
-	struct device *device;
 #define rt2x00dev_pci(__dev)	( (struct pci_dev*)(__dev)->dev )
 #define rt2x00dev_usb(__dev)	( (struct usb_interface*)(__dev)->dev )
 
@@ -796,12 +832,9 @@ struct rt2x00_dev {
 	 * If enabled, the debugfs interface structures
 	 * required for deregistration of debugfs.
 	 */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
 	const struct rt2x00debug_intf *debugfs_intf;
-
-	/*
-	 * Queue for deferred work.
-	 */
-	struct workqueue_struct *workqueue;
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
 	/*
 	 * Interface configuration.
@@ -844,9 +877,9 @@ struct rt2x00_dev {
 	u8 led_mode;
 
 	/*
-	 * EEPROM bus width (PCI devices only).
+	 * Rssi <-> Dbm offset
 	 */
-	u8 eeprom_width;
+	u8 rssi_offset;
 
 	/*
 	 * Frequency offset (for rt61pci & rt73usb).
@@ -907,14 +940,22 @@ static inline struct data_ring* rt2x00_get_ring(
  * The 1 + Atim check will assure that the address directly after
  * the ring array is obtained and the for-each loop exits correctly.
  */
-#define ring_for_each(__dev, __entry)		\
-	for ((__entry) = (__dev)->rx;		\
-		(__entry) != &(__dev)->bcn[1 +	\
-			test_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags)]; \
-		(__entry)++)
+#define ring_end(__dev) \
+	&(__dev)->bcn[1 + test_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags)]
+
+#define ring_loop(__entry, __start, __end)			\
+	for ((__entry) = (__start);				\
+	     prefetch(&(__entry)[1]), (__entry) != (__end);	\
+	     (__entry) = &(__entry)[1])
+
+#define ring_for_each(__dev, __entry) \
+	ring_loop(__entry, (__dev)->rx, ring_end(__dev))
+
+#define txring_for_each(__dev, __entry) \
+	ring_loop(__entry, (__dev)->tx, (__dev)->bcn)
 
-#define txring_for_each(__dev, __entry)		\
-	for ((__entry) = (__dev)->tx; (__entry) != (__dev)->bcn; (__entry)++)
+#define txringall_for_each(__dev, __entry) \
+	ring_loop(__entry, (__dev)->tx, ring_end(__dev))
 
 /*
  * EEPROM access.
@@ -944,11 +985,10 @@ static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev,
 static inline void rt2x00_start_link_tune(struct rt2x00_dev *rt2x00dev)
 {
 	rt2x00dev->link.count = 0;
-	rt2x00dev->link.count_rssi = 0;
-	rt2x00dev->link.total_rssi = 0;
-	rt2x00dev->link.curr_noise = 0;
+	rt2x00dev->link.avg_rssi = 0;
+	rt2x00dev->link.false_cca = 0;
 
-	queue_delayed_work(rt2x00dev->workqueue,
+	queue_delayed_work(rt2x00dev->hw->workqueue,
 		&rt2x00dev->link.work, LINK_TUNE_INTERVAL);
 }
 
@@ -956,26 +996,20 @@ static inline void rt2x00_stop_link_tune(struct rt2x00_dev *rt2x00dev)
 {
 	if (work_pending(&rt2x00dev->link.work.work))
 		cancel_rearming_delayed_workqueue(
-			rt2x00dev->workqueue, &rt2x00dev->link.work);
+			rt2x00dev->hw->workqueue, &rt2x00dev->link.work);
 }
 
-static inline void rt2x00_update_link_rssi(struct link *link, u32 rssi)
+static inline void rt2x00_update_link_rssi(struct link *link, int rssi)
 {
-	link->count_rssi++;
-	link->total_rssi += rssi;
+	if (!link->avg_rssi)
+		link->avg_rssi = rssi;
+	else
+		link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8;
 }
 
-static inline u32 rt2x00_get_link_rssi(struct link *link)
+static inline int rt2x00_get_link_rssi(struct link *link)
 {
-	u32 average = 0;
-
-	if (link->count_rssi && link->total_rssi)
-		average = link->total_rssi / link->count_rssi;
-
-	link->count_rssi = 0;
-	link->total_rssi = 0;
-
-	return average;
+	return link->avg_rssi;
 }
 
 /*

+ 6 - 0
package/rt2x00/src/rt2x00_compat.h

@@ -51,6 +51,12 @@
 #endif
 #endif
 
+#if (defined(CONFIG_RT2X00_DEBUGFS))
+#if (!defined(CONFIG_MAC80211_DEBUGFS) && !defined(CONFIG_MAC80211_DEBUGFS_MODULE))
+#error mac80211 debugfs support has been disabled in your kernel!
+#endif
+#endif
+
 #if (defined(CONFIG_RT2400PCI_BUTTON) || defined(CONFIG_RT2500PCI_BUTTON) || defined(CONFIG_RT61PCI_BUTTON))
 #if (!defined(CONFIG_RFKILL) && !defined (CONFIG_RFKILL_MODULE))
 #error RFKILL has been disabled in your kernel!

+ 0 - 44
package/rt2x00/src/rt2x00_config.h

@@ -1,44 +0,0 @@
-#ifndef CONFIG_RT2X00
-#define CONFIG_RT2X00
-#endif
-
-#ifndef CONFIG_RT2X00_DEBUG
-#define CONFIG_RT2X00_DEBUG
-#endif
-
-#ifndef CONFIG_RT2X00_DEBUGFS
-#define CONFIG_RT2X00_DEBUGFS
-#endif
-
-#undef CONFIG_RT2X00_ASM
-
-#ifndef CONFIG_RT2X00_LIB_FIRMWARE
-#define CONFIG_RT2X00_LIB_FIRMWARE
-#endif
-
-#ifndef CONFIG_RT2400PCI
-#define CONFIG_RT2400PCI
-#endif
-
-#undef CONFIG_RT2400PCI_BUTTON
-
-#ifndef CONFIG_RT2500PCI
-#define CONFIG_RT2500PCI
-#endif
-
-#undef CONFIG_RT2500PCI_BUTTON
-
-#ifndef CONFIG_RT2500USB
-#define CONFIG_RT2500USB
-#endif
-
-#ifndef CONFIG_RT61PCI
-#define CONFIG_RT61PCI
-#endif
-
-#undef CONFIG_RT61PCI_BUTTON
-
-#ifndef CONFIG_RT73USB
-#define CONFIG_RT73USB
-#endif
-

+ 1 - 0
package/rt2x00/src/rt2x00debug.c

@@ -30,6 +30,7 @@
 #include <asm/uaccess.h>
 
 #include "rt2x00.h"
+#include "rt2x00debug.h"
 
 #define PRINT_REG8_STR		( "0x%.2x\n" )
 #define PRINT_REG16_STR		( "0x%.4x\n" )

+ 0 - 2
package/rt2x00/src/rt2x00debug.h

@@ -28,8 +28,6 @@
 #ifndef RT2X00DEBUG_H
 #define RT2X00DEBUG_H
 
-#include <net/wireless.h>
-
 typedef void (debug_access_t)(struct rt2x00_dev *rt2x00dev,
 	const unsigned long word, void *data);
 

+ 22 - 74
package/rt2x00/src/rt2x00dev.c

@@ -38,6 +38,7 @@
 #include <linux/etherdevice.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00dev.h"
 
 /*
@@ -67,6 +68,9 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
 
 	ieee80211_start_queues(rt2x00dev->hw);
 
+	if (is_interface_present(&rt2x00dev->interface))
+		rt2x00_start_link_tune(rt2x00dev);
+
 	return 0;
 }
 
@@ -75,6 +79,8 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
 	if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
+	rt2x00_stop_link_tune(rt2x00dev);
+
 	ieee80211_stop_queues(rt2x00dev->hw);
 
 	rt2x00lib_toggle_rx(rt2x00dev, 0);
@@ -87,7 +93,7 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable)
 	/*
 	 * When we are disabling the rx, we should also stop the link tuner.
 	 */
-	if (!enable && work_pending(&rt2x00dev->link.work.work))
+	if (!enable)
 		rt2x00_stop_link_tune(rt2x00dev);
 
 	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
@@ -96,7 +102,7 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable)
 	/*
 	 * When we are enabling the rx, we should also start the link tuner.
 	 */
-	if (enable)
+	if (enable && is_interface_present(&rt2x00dev->interface))
 		rt2x00_start_link_tune(rt2x00dev);
 }
 
@@ -104,7 +110,6 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
 {
 	struct rt2x00_dev *rt2x00dev =
 		container_of(work, struct rt2x00_dev, link.work.work);
-	int rssi;
 
 	/*
 	 * Update promisc mode (this function will first check
@@ -119,20 +124,13 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
 	if (test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
 		return;
 
-	/*
-	 * Retrieve link quality.
-	 * Also convert rssi to dBm using the max_rssi value.
-	 */
-	rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
-	rssi -= rt2x00dev->hw->max_rssi;
-
-	rt2x00dev->ops->lib->link_tuner(rt2x00dev, rssi);
+	rt2x00dev->ops->lib->link_tuner(rt2x00dev);
 
 	/*
 	 * Increase tuner counter, and reschedule the next link tuner run.
 	 */
 	rt2x00dev->link.count++;
-	queue_delayed_work(rt2x00dev->workqueue, &rt2x00dev->link.work,
+	queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
 		LINK_TUNE_INTERVAL);
 }
 
@@ -422,23 +420,6 @@ static int rt2x00lib_init_hw(struct rt2x00_dev *rt2x00dev)
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
 	int status;
 
-	/*
-	 * Initialize device.
-	 */
-	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->device);
-
-	/*
-	 * Initialize MAC address.
-	 */
-	if (!is_valid_ether_addr(spec->mac_addr)) {
-		ERROR(rt2x00dev, "Invalid MAC addr: " MAC_FMT ".\n",
-			MAC_ARG(spec->mac_addr));
-		return -EINVAL;
-	}
-
-	rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, spec->mac_addr);
-	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, spec->mac_addr);
-
 	/*
 	 * Initialize HW modes.
 	 */
@@ -463,7 +444,7 @@ static int rt2x00lib_init_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * Initialization/uninitialization handlers.
  */
-static int rt2x00lib_alloc_ring(struct data_ring *ring,
+static int rt2x00lib_alloc_ring_entries(struct data_ring *ring,
 	const u16 max_entries, const u16 data_size, const u16 desc_size)
 {
 	struct data_entry *entry;
@@ -491,14 +472,14 @@ static int rt2x00lib_alloc_ring(struct data_ring *ring,
 	return 0;
 }
 
-static int rt2x00lib_allocate_rings(struct rt2x00_dev *rt2x00dev)
+static int rt2x00lib_allocate_ring_entries(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_ring *ring;
 
 	/*
 	 * Allocate the RX ring.
 	 */
-	if (rt2x00lib_alloc_ring(rt2x00dev->rx,
+	if (rt2x00lib_alloc_ring_entries(rt2x00dev->rx,
 		RX_ENTRIES, DATA_FRAME_SIZE, rt2x00dev->ops->rxd_size))
 		return -ENOMEM;
 
@@ -506,7 +487,7 @@ static int rt2x00lib_allocate_rings(struct rt2x00_dev *rt2x00dev)
 	 * First allocate the TX rings.
 	 */
 	txring_for_each(rt2x00dev, ring) {
-		if (rt2x00lib_alloc_ring(ring,
+		if (rt2x00lib_alloc_ring_entries(ring,
 			TX_ENTRIES, DATA_FRAME_SIZE, rt2x00dev->ops->txd_size))
 			return -ENOMEM;
 	}
@@ -514,7 +495,7 @@ static int rt2x00lib_allocate_rings(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Allocate the BEACON ring.
 	 */
-	if (rt2x00lib_alloc_ring(&rt2x00dev->bcn[0],
+	if (rt2x00lib_alloc_ring_entries(&rt2x00dev->bcn[0],
 		BEACON_ENTRIES, MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size))
 		return -ENOMEM;
 
@@ -522,7 +503,7 @@ static int rt2x00lib_allocate_rings(struct rt2x00_dev *rt2x00dev)
 	 * Allocate the Atim ring.
 	 */
 	if (test_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags)) {
-		if (rt2x00lib_alloc_ring(&rt2x00dev->bcn[1],
+		if (rt2x00lib_alloc_ring_entries(&rt2x00dev->bcn[1],
 			ATIM_ENTRIES, DATA_FRAME_SIZE, rt2x00dev->ops->txd_size))
 			return -ENOMEM;
 	}
@@ -530,7 +511,7 @@ static int rt2x00lib_allocate_rings(struct rt2x00_dev *rt2x00dev)
 	return 0;
 }
 
-static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev)
+static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_ring *ring;
 
@@ -550,7 +531,7 @@ int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Allocate all data rings.
 	 */
-	status = rt2x00lib_allocate_rings(rt2x00dev);
+	status = rt2x00lib_allocate_ring_entries(rt2x00dev);
 	if (status) {
 		ERROR(rt2x00dev, "DMA allocation failed.\n");
 		return status;
@@ -578,7 +559,7 @@ exit_unitialize:
 	rt2x00lib_uninitialize(rt2x00dev);
 
 exit:
-	rt2x00lib_free_rings(rt2x00dev);
+	rt2x00lib_free_ring_entries(rt2x00dev);
 
 	return status;
 }
@@ -588,11 +569,6 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
 	if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
 		return;
 
-	/*
-	 * Flush out all pending work.
-	 */
-	flush_workqueue(rt2x00dev->workqueue);
-
 	/*
 	 * Unregister rfkill.
 	 */
@@ -606,7 +582,7 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Free allocated datarings.
 	 */
-	rt2x00lib_free_rings(rt2x00dev);
+	rt2x00lib_free_ring_entries(rt2x00dev);
 }
 
 /*
@@ -659,13 +635,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 {
 	int retval = -ENOMEM;
 
-	/*
-	 * Create workqueue.
-	 */
-	rt2x00dev->workqueue = create_singlethread_workqueue(DRV_NAME);
-	if (!rt2x00dev->workqueue)
-		goto exit;
-
 	/*
 	 * Let the driver probe the device to detect the capabilities.
 	 */
@@ -763,14 +732,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2x00lib_deinit_hw(rt2x00dev);
 
-	/*
-	 * Free workqueue.
-	 */
-	if (likely(rt2x00dev->workqueue)) {
-		destroy_workqueue(rt2x00dev->workqueue);
-		rt2x00dev->workqueue = NULL;
-	}
-
 	/*
 	 * Free ring structures.
 	 */
@@ -824,13 +785,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
 		return retval;
 	}
 
-	/*
-	 * Set device mode to awake for power management.
-	 */
-	retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE);
-	if (retval)
-		return retval;
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_resume);
@@ -914,14 +868,14 @@ void rt2x00lib_rxdone(struct data_entry *entry, char *data,
 			 */
 			if (signal & 0x08)
 				val = rate->val2;
-			val = rate->val;
+			else
+				val = rate->val;
 			break;
 		}
 	}
 
 	rx_status->rate = val;
 	rx_status->ssi = rssi;
-	rx_status->noise = rt2x00dev->link.curr_noise;
 	rt2x00_update_link_rssi(&rt2x00dev->link, rssi);
 
 	/*
@@ -1001,12 +955,6 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	if (ieee80211_get_morefrag(ieee80211hdr))
 		__set_bit(ENTRY_TXD_MORE_FRAG, &entry->flags);
 
-	/*
-	 * Check if this is a new sequence
-	 */
-	if ((seq_ctrl & IEEE80211_SCTL_FRAG) == 0)
-		__set_bit(ENTRY_TXD_NEW_SEQ, &entry->flags);
-
 	/*
 	 * Beacons and probe responses require the tsf timestamp
 	 * to be inserted into the frame.

+ 9 - 2
package/rt2x00/src/rt2x00firmware.c

@@ -29,10 +29,12 @@
  */
 #define DRV_NAME "rt2x00lib"
 
+#include <linux/delay.h>
 #include <linux/crc-itu-t.h>
 #include <linux/firmware.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00firmware.h"
 
 static void rt2x00lib_load_firmware_continued(const struct firmware *fw,
@@ -90,12 +92,17 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
 	 * Read correct firmware from harddisk.
 	 */
 	fw_name = rt2x00dev->ops->lib->get_fw_name(rt2x00dev);
-	BUG_ON(fw_name == NULL);
+	if (!fw_name) {
+		ERROR(rt2x00dev,
+			"Invalid firmware filename.\n"
+			"Please file bug report to %s.\n", DRV_PROJECT);
+		return -EINVAL;
+	}
 
 	INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name);
 
 	status = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
-		fw_name, rt2x00dev->device, rt2x00dev,
+		fw_name, wiphy_dev(rt2x00dev->hw->wiphy), rt2x00dev,
 		&rt2x00lib_load_firmware_continued);
 
 	if (status)

+ 2 - 39
package/rt2x00/src/rt2x00lib.h

@@ -28,43 +28,6 @@
 #ifndef RT2X00LIB_H
 #define RT2X00LIB_H
 
-struct rt2x00_dev;
-struct data_desc;
-struct data_entry_desc;
-struct data_entry;
-
-/*
- * Details about the supported modes, rates and channels
- * of a particular chipset. This is used by rt2x00lib
- * to build the ieee80211_hw_mode array for mac80211.
- */
-struct hw_mode_spec {
-	/*
-	 * Default mac address.
-	 */
-	char *mac_addr;
-
-	/*
-	 * Number of modes, rates and channels.
-	 */
-	int num_modes;
-	int num_rates;
-	int num_channels;
-
-	/*
-	 * txpower values.
-	 */
-	const u8 *tx_power_a;
-	const u8 *tx_power_bg;
-	u8 tx_power_default;
-
-	/*
-	 * Device/chipset specific value.
-	 */
-	const u32 *chan_val_a;
-	const u32 *chan_val_bg;
-};
-
 /*
  * Driver allocation handlers.
  */
@@ -99,8 +62,6 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	struct ieee80211_tx_control *control);
 int rt2x00lib_reset(struct ieee80211_hw *hw);
-int rt2x00lib_open(struct ieee80211_hw *hw);
-int rt2x00lib_stop(struct ieee80211_hw *hw);
 int rt2x00lib_add_interface(struct ieee80211_hw *hw,
 	struct ieee80211_if_init_conf *conf);
 void rt2x00lib_remove_interface(struct ieee80211_hw *hw,
@@ -115,4 +76,6 @@ int rt2x00lib_get_tx_stats(struct ieee80211_hw *hw,
 int rt2x00lib_conf_tx(struct ieee80211_hw *hw, int queue,
 	const struct ieee80211_tx_queue_params *params);
 
+#include "rt2x00debug.h"
+
 #endif /* RT2X00LIB_H */

+ 52 - 86
package/rt2x00/src/rt2x00mac.c

@@ -33,6 +33,7 @@
 #include <linux/netdevice.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00dev.h"
 
 static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
@@ -129,60 +130,18 @@ int rt2x00lib_reset(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_reset);
 
-int rt2x00lib_open(struct ieee80211_hw *hw)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	int status;
-
-	/*
-	 * We must wait on the firmware before
-	 * we can safely continue.
-	 */
-	status = rt2x00lib_load_firmware_wait(rt2x00dev);
-	if (status)
-		return status;
-
-	/*
-	 * Initialize the device.
-	 */
-	status = rt2x00lib_initialize(rt2x00dev);
-	if (status)
-		return status;
-
-	/*
-	 * Enable radio.
-	 */
-	status = rt2x00lib_enable_radio(rt2x00dev);
-	if (status) {
-		rt2x00lib_uninitialize(rt2x00dev);
-		return status;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00lib_open);
-
-int rt2x00lib_stop(struct ieee80211_hw *hw)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-
-	rt2x00lib_disable_radio(rt2x00dev);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00lib_stop);
-
 int rt2x00lib_add_interface(struct ieee80211_hw *hw,
 	struct ieee80211_if_init_conf *conf)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct interface *intf = &rt2x00dev->interface;
+	int status;
 
 	/*
 	 * We only support 1 non-monitor interface.
 	 */
 	if (conf->type != IEEE80211_IF_TYPE_MNTR &&
-	    is_interface_present(&rt2x00dev->interface))
+	    is_interface_present(intf))
 		return -ENOBUFS;
 
 	/*
@@ -200,17 +159,39 @@ int rt2x00lib_add_interface(struct ieee80211_hw *hw,
 	}
 
 	/*
-	 * If this is the first interface which is being added,
-	 * we should write the MAC address to the device.
-	 */
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
-		rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, conf->mac_addr);
-
-	/*
-	 * Enable periodic link tuning if this is a non-monitor interface.
+	 * Initialize interface, and enable the radio when this
+	 * is the first interface that is brought up.
 	 */
-	if (conf->type != IEEE80211_IF_TYPE_MNTR)
-		rt2x00_start_link_tune(rt2x00dev);
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
+		/*
+		 * We must wait on the firmware before
+		 * we can safely continue.
+		 */
+		status = rt2x00lib_load_firmware_wait(rt2x00dev);
+		if (status)
+			return status;
+
+		/*
+		 * Before initialization, the mac address should
+		 * be configured.
+		 */
+		rt2x00dev->ops->lib->config_mac_addr(rt2x00dev,
+			conf->mac_addr);
+ 
+		/*
+		 * Initialize the device.
+		 */
+		status = rt2x00lib_initialize(rt2x00dev);
+		if (status)
+			return status;
+
+		/*
+		 * Enable radio.
+		 */
+		status = rt2x00lib_enable_radio(rt2x00dev);
+		if (status)
+			return status;
+	}
 
 	return 0;
 }
@@ -226,12 +207,12 @@ void rt2x00lib_remove_interface(struct ieee80211_hw *hw,
 	 * We only support 1 non-monitor interface.
 	 */
 	if (conf->type != IEEE80211_IF_TYPE_MNTR &&
-	    !is_interface_present(&rt2x00dev->interface))
+	    !is_interface_present(intf))
 		return;
 
 	/*
-	 * We support muliple monitor mode interfaces.
-	 * All we need to do is decrease the monitor_count.
+	 * When removing an monitor interface, decrease monitor_count.
+	 * For non-monitor interfaces, all interface data needs to be reset.
 	 */
 	if (conf->type == IEEE80211_IF_TYPE_MNTR) {
 		intf->monitor_count--;
@@ -243,33 +224,18 @@ void rt2x00lib_remove_interface(struct ieee80211_hw *hw,
 	}
 
 	/*
-	 * When this is a non-monitor mode, stop the periodic link tuning.
-	 */
-	if (conf->type != IEEE80211_IF_TYPE_MNTR)
-		rt2x00_stop_link_tune(rt2x00dev);
-
-	/*
-	 * Check if we still have 1 non-monitor or a monitor
-	 * interface enabled. In that case we should update the
-	 * registers.
-	 */
-	if (is_monitor_present(&rt2x00dev->interface) ^
-	    is_interface_present(&rt2x00dev->interface)) {
-		if (is_interface_present(&rt2x00dev->interface))
-			rt2x00lib_config_type(rt2x00dev,
-				rt2x00dev->interface.type);
-		else
-			rt2x00lib_config_type(rt2x00dev,
-				IEEE80211_IF_TYPE_MNTR);
-	}
-
-	/*
-	 * Check which interfaces have been disabled.
+	 * If this was the last interface,
+	 * this is the time to disable the radio.
+	 * If this is not the last interface, then we should
+	 * check if we should switch completely to monitor
+	 * mode or completely switch to the non-monitor mode.
 	 */
-	if (!is_interface_present(&rt2x00dev->interface))
-		__clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
-	else if (!is_monitor_present(&rt2x00dev->interface))
-		__clear_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags);
+	if (!is_monitor_present(intf) && !is_interface_present(intf))
+		rt2x00lib_disable_radio(rt2x00dev);
+	else if (is_monitor_present(intf) ^ is_interface_present(intf))
+		rt2x00lib_config_type(rt2x00dev,
+			is_interface_present(intf) ?
+				intf->type : IEEE80211_IF_TYPE_MNTR);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_remove_interface);
 
@@ -373,10 +339,10 @@ void rt2x00lib_set_multicast_list(struct ieee80211_hw *hw,
 	 * Check if the new state is different then the old state.
 	 */
 	if (test_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags) ==
-	    (flags & IFF_PROMISC))
+	    !!(flags & IFF_PROMISC))
 		return;
 
-	rt2x00dev->interface.promisc = (flags & IFF_PROMISC);
+	rt2x00dev->interface.promisc = !!(flags & IFF_PROMISC);
 
 	/*
 	 * Schedule the link tuner if this does not run
@@ -384,7 +350,7 @@ void rt2x00lib_set_multicast_list(struct ieee80211_hw *hw,
 	 * switched off when it is not required.
 	 */
 	if (!work_pending(&rt2x00dev->link.work.work))
-		queue_work(rt2x00dev->workqueue, &rt2x00dev->link.work.work);
+		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work.work);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_set_multicast_list);
 

+ 49 - 4
package/rt2x00/src/rt2x00pci.c

@@ -36,6 +36,7 @@
 #include <linux/pci.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00pci.h"
 
 /*
@@ -109,7 +110,8 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 
 	rt2x00_desc_read(txd, 0, &word);
 
-	if (rt2x00_get_field32(word, TXD_ENTRY_AVAILABLE)) {
+	if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
+	    rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
 		ERROR(rt2x00dev,
 			"Arrived at non-free entry in the non-full queue %d.\n"
 			"Please file bug report to %s.\n",
@@ -118,11 +120,11 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 		return -EINVAL;
 	}
 
+	entry->skb = skb;
+	memcpy(&entry->tx_status.control, control, sizeof(*control));
 	memcpy(entry->data_addr, skb->data, skb->len);
 	rt2x00lib_write_tx_desc(rt2x00dev, entry, txd, ieee80211hdr,
 		skb->len, control);
-	memcpy(&entry->tx_status.control, control, sizeof(*control));
-	entry->skb = skb;
 
 	rt2x00_ring_index_inc(ring);
 
@@ -133,6 +135,50 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
 
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring = rt2x00dev->rx;
+	struct data_entry *entry;
+	struct data_desc *rxd;
+	u32 desc;
+	int signal;
+	int rssi;
+	int ofdm;
+	int size;
+
+	while (1) {
+		entry = rt2x00_get_data_entry(ring);
+		rxd = entry->priv;
+		rt2x00_desc_read(rxd, 0, &desc);
+
+		if (rt2x00_get_field32(desc, RXD_ENTRY_OWNER_NIC))
+			break;
+
+		size = rt2x00dev->ops->lib->fill_rxdone(
+			entry, &signal, &rssi, &ofdm);
+		if (size < 0)
+			goto skip_entry;
+
+		/*
+		 * Send the packet to upper layer.
+		 */
+		rt2x00lib_rxdone(entry, entry->data_addr, size,
+			signal, rssi, ofdm);
+
+skip_entry:
+		if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+			rt2x00_set_field32(&desc, RXD_ENTRY_OWNER_NIC, 1);
+			rt2x00_desc_write(rxd, 0, desc);
+		}
+
+		rt2x00_ring_index_inc(ring);
+	}
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+
 /*
  * Device initialization handlers.
  */
@@ -304,7 +350,6 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 
 	rt2x00dev = hw->priv;
 	rt2x00dev->dev = pci_dev;
-	rt2x00dev->device = &pci_dev->dev;
 	rt2x00dev->ops = ops;
 	rt2x00dev->hw = hw;
 

+ 11 - 5
package/rt2x00/src/rt2x00pci.h

@@ -43,12 +43,13 @@
 #define REGISTER_BUSY_DELAY	100
 
 /*
- * TX descriptor available flag.
- * This flag is the combination of the TXD_W0_OWNER_NIC
- * and TXD_W0_VALID flag which have the same value on all
- * PCI drivers.
+ * Descriptor availability flags.
+ * All PCI device descriptors have these 2 flags
+ * with the exact same definition.
  */
-#define TXD_ENTRY_AVAILABLE	FIELD32(0x00000003)
+#define TXD_ENTRY_OWNER_NIC	FIELD32(0x00000001)
+#define TXD_ENTRY_VALID		FIELD32(0x00000002)
+#define RXD_ENTRY_OWNER_NIC	FIELD32(0x00000001)
 
 /*
  * Register access.
@@ -93,6 +94,11 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 	struct data_ring *ring, struct sk_buff *skb,
 	struct ieee80211_tx_control *control);
 
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+
 /*
  * Device initialization handlers.
  */

+ 2 - 2
package/rt2x00/src/rt2x00rfkill.c

@@ -70,7 +70,7 @@ static void rt2x00lib_rfkill_poll(struct work_struct *work)
 	rfkill_switch_all(rt2x00dev->rfkill->type,
 		rt2x00dev->ops->lib->rfkill_poll(rt2x00dev));
 
-	queue_delayed_work(rt2x00dev->workqueue, &rt2x00dev->rfkill_work,
+	queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->rfkill_work,
 		RFKILL_POLL_INTERVAL);
 }
 
@@ -92,7 +92,7 @@ void rt2x00lib_unregister_rfkill(struct rt2x00_dev *rt2x00dev)
 {
 	if (delayed_work_pending(&rt2x00dev->rfkill_work))
 		cancel_rearming_delayed_workqueue(
-			rt2x00dev->workqueue, &rt2x00dev->rfkill_work);
+			rt2x00dev->hw->workqueue, &rt2x00dev->rfkill_work);
 
 	rfkill_unregister(rt2x00dev->rfkill);
 }

+ 117 - 38
package/rt2x00/src/rt2x00usb.c

@@ -36,6 +36,7 @@
 #include <linux/usb.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00usb.h"
 
 /*
@@ -62,48 +63,13 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
 			return 0;
 	}
 
-	ERROR(rt2x00dev, "vendor request error. Request 0x%02x failed "
-		"for offset 0x%04x with error %d.\n", request, offset, status);
+	ERROR(rt2x00dev, "Vendor Request 0x%02x failed for offset 0x%04x"
+		" with error %d.\n", request, offset, status);
 
 	return status;
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
 
-/*
- * Radio handlers
- */
-void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev)
-{
-	unsigned int i;
-
-	/*
-	 * Start the RX ring.
-	 */
-	for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
-		__set_bit(ENTRY_OWNER_NIC, &rt2x00dev->rx->entry[i].flags);
-		usb_submit_urb(rt2x00dev->rx->entry[i].priv, GFP_ATOMIC);
-	}
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio);
-
-void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
-{
-	struct data_ring *ring;
-	unsigned int i;
-
-	rt2x00usb_vendor_request(rt2x00dev, USB_RX_CONTROL,
-		USB_VENDOR_REQUEST_OUT, 0x00, 0x00, NULL, 0, REGISTER_TIMEOUT);
-
-	/*
-	 * Cancel all rings.
-	 */
-	ring_for_each(rt2x00dev, ring) {
-		for (i = 0; i < ring->stats.limit; i++)
-			usb_kill_urb(ring->entry[i].priv);
-	}
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
-
 /*
  * Beacon handlers.
  */
@@ -328,6 +294,120 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
 
+/*
+ * RX data handlers.
+ */
+static void rt2x00usb_interrupt_rxdone(struct urb *urb)
+{
+	struct data_entry *entry = (struct data_entry*)urb->context;
+	struct data_ring *ring = entry->ring;
+	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+	int signal;
+	int rssi;
+	int ofdm;
+	int size;
+
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	    !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+		return;
+
+	/*
+	 * Check if the received data is simply too small
+	 * to be actually valid, or if the urb is signaling
+	 * a problem.
+	 */
+	if (urb->actual_length < entry->ring->desc_size || urb->status)
+		goto skip_entry;
+
+	size = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, &rssi, &ofdm);
+	if (size < 0)
+		goto skip_entry;
+
+	/*
+	 * Trim the skb_buffer to only contain the valid
+	 * frame data (so ignore the device's descriptor).
+	 */
+	skb_trim(entry->skb, size);
+
+	/*
+	 * Send the packet to upper layer, and update urb.
+	 */
+	rt2x00lib_rxdone(entry, NULL, ring->data_size + ring->desc_size,
+		signal, rssi, ofdm);
+	urb->transfer_buffer = entry->skb->data;
+	urb->transfer_buffer_length = entry->skb->len;
+
+skip_entry:
+	if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+		__set_bit(ENTRY_OWNER_NIC, &entry->flags);
+		usb_submit_urb(urb, GFP_ATOMIC);
+	}
+
+	rt2x00_ring_index_inc(ring);
+}
+
+/*
+ * Radio handlers
+ */
+void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	struct usb_device *usb_dev =
+		interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+	struct data_ring *ring;
+	struct data_entry *entry;
+	unsigned int i;
+
+	/*
+	 * Initialize the TX rings
+	 */
+	txringall_for_each(rt2x00dev, ring) {
+		for (i = 0; i < ring->stats.limit; i++)
+			ring->entry[i].flags = 0;
+
+		rt2x00_ring_index_clear(ring);
+	}
+
+	/*
+	 * Initialize and start the RX ring.
+	 */
+	rt2x00_ring_index_clear(rt2x00dev->rx);
+
+	for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
+		entry = &rt2x00dev->rx->entry[i];
+
+		usb_fill_bulk_urb(
+			entry->priv,
+			usb_dev,
+			usb_rcvbulkpipe(usb_dev, 1),
+			entry->skb->data,
+			entry->skb->len,
+			rt2x00usb_interrupt_rxdone,
+			entry);
+
+		__set_bit(ENTRY_OWNER_NIC, &entry->flags);
+		usb_submit_urb(entry->priv, GFP_ATOMIC);
+	}
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio);
+
+void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+	unsigned int i;
+
+	rt2x00usb_vendor_request(rt2x00dev, USB_RX_CONTROL,
+		USB_VENDOR_REQUEST_OUT, 0x00, 0x00, NULL, 0, REGISTER_TIMEOUT);
+
+	/*
+	 * Cancel all rings.
+	 */
+	ring_for_each(rt2x00dev, ring) {
+		for (i = 0; i < ring->stats.limit; i++)
+			usb_kill_urb(ring->entry[i].priv);
+	}
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
+
 /*
  * Device initialization handlers.
  */
@@ -433,7 +513,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
 
 	rt2x00dev = hw->priv;
 	rt2x00dev->dev = usb_intf;
-	rt2x00dev->device = &usb_intf->dev;
 	rt2x00dev->ops = ops;
 	rt2x00dev->hw = hw;
 

+ 176 - 80
package/rt2x00/src/rt61pci.c

@@ -42,6 +42,7 @@
 #include <asm/io.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00pci.h"
 #include "rt61pci.h"
 
@@ -891,13 +892,19 @@ static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev)
 	rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
 }
 
-static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, char rssi)
+static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
 {
 	u8 led;
 
 	if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
 		return;
 
+	/*
+	 * Led handling requires a positive value for the rssi,
+	 * to do that correctly we need to add the correction.
+	 */
+	rssi += rt2x00dev->rssi_offset;
+
 	if (rssi <= 30)
 		led = 0;
 	else if (rssi <= 39)
@@ -917,8 +924,9 @@ static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, char rssi)
 /*
  * Link tuning
  */
-static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
+static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
 {
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
 	u32 reg;
 	u8 r17;
 	u8 up_bound;
@@ -1013,10 +1021,12 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
 		if (++r17 > up_bound)
 			r17 = up_bound;
 		rt61pci_bbp_write(rt2x00dev, 17, r17);
+		rt2x00dev->rx_status.noise = r17;
 	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
 		if (--r17 < low_bound)
 			r17 = low_bound;
 		rt61pci_bbp_write(rt2x00dev, 17, r17);
+		rt2x00dev->rx_status.noise = r17;
 	}
 }
 
@@ -1279,7 +1289,12 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
 
 	rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
 
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, 0x025eb032);
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
 
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, 0x9eb39eb3);
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, 0x8a8b8c8d);
@@ -1312,10 +1327,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
 	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
 
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-
 	rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
 	rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
 	rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
@@ -1432,10 +1443,48 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
 }
 
-static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled)
 {
 	u32 reg;
 
+	/*
+	 * When interrupts are being enabled, the interrupt registers
+	 * should clear the register to assure a clean state.
+	 */
+	if (enabled) {
+		rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+		rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+		rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
+		rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
+	}
+
+	/*
+	 * Only toggle the interrupts bits we are going to use.
+	 * Non-checked interrupt bits are disabled by default.
+	 */
+	rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, !enabled);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, !enabled);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_BEACON_DONE, !enabled);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, !enabled);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
+	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, !enabled);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, !enabled);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, !enabled);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_3, !enabled);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_4, !enabled);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, !enabled);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, !enabled);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, !enabled);
+	rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+}
+
+static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
 	/*
 	 * Initialize all registers.
 	 */
@@ -1446,24 +1495,10 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 		return -EIO;
 	}
 
-	/*
-	 * Clear interrupts.
-	 */
-	rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
-	rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
-
-	rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
-	rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
-
 	/*
 	 * Enable interrupts.
 	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, INT_MASK_CSR_TX_ABORT_DONE, 1);
-	rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
-	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
-
-	rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0x00000000);
+	rt61pci_toggle_irq(rt2x00dev, 1);
 
 	/*
 	 * Enable RX.
@@ -1508,11 +1543,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Disable interrupts.
 	 */
-	reg = 0xffffffff;
-	rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, 0);
-	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
-
-	rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0xffffffff);
+	rt61pci_toggle_irq(rt2x00dev, 0);
 }
 
 static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1681,60 +1712,80 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
 }
 
 /*
- * Interrupt functions.
+ * RX control handlers
  */
-static void rt61pci_rxdone(struct rt2x00_dev *rt2x00dev)
+static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
 {
-	struct data_ring *ring = rt2x00dev->rx;
-	struct data_entry *entry;
-	struct data_desc *rxd;
-	u32 word0;
-	u32 word1;
-	int signal;
-	int rssi;
-	int ofdm;
-	u16 size;
+	u16 eeprom;
+	char offset;
+	char lna;
 
-	while (1) {
-		entry = rt2x00_get_data_entry(ring);
-		rxd = entry->priv;
-		rt2x00_desc_read(rxd, 0, &word0);
-		rt2x00_desc_read(rxd, 1, &word1);
+	lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+	switch (lna) {
+		case 3:
+			offset = 90;
+		break;
+		case 2:
+			offset = 74;
+		break;
+		case 1:
+			offset = 64;
+		break;
+		default:
+			return 0;
+	}
 
-		if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
-			break;
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+			offset += 14;
 
-		/*
-		 * TODO: Don't we need to keep statistics
-		 * updated about events like CRC and physical errors?
-		 */
-		if (rt2x00_get_field32(word0, RXD_W0_CRC))
-			goto skip_entry;
+		if (lna == 3 || lna == 2)
+			offset += 10;
 
-		/*
-		 * Obtain the status about this packet.
-		 */
-		size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-		signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-		rssi = rt2x00_get_field32(word1, RXD_W1_RSSI);
-		ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	} else {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			offset += 14;
 
-		/*
-		 * Send the packet to upper layer.
-		 */
-		rt2x00lib_rxdone(entry, entry->data_addr, size,
-			signal, rssi, ofdm);
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	}
 
-skip_entry:
-		if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
-			rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1);
-			rt2x00_desc_write(rxd, 0, word0);
-		}
+	return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
 
-		rt2x00_ring_index_inc(ring);
-	}
+static int rt61pci_fill_rxdone(struct data_entry *entry,
+	int *signal, int *rssi, int *ofdm)
+{
+	struct data_desc *rxd = entry->priv;
+	u32 word0;
+	u32 word1;
+
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 1, &word1);
+
+	/*
+	 * TODO: Don't we need to keep statistics
+	 * updated about these errors?
+	 */
+	if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
+	    rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
+		return -EINVAL;
+
+	/*
+	 * Obtain the status about this packet.
+	 */
+	*signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+	*rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
+	*ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+
+	return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 }
 
+/*
+ * Interrupt functions.
+ */
 static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_ring *ring;
@@ -1840,7 +1891,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
 	 * 2 - Rx ring done interrupt.
 	 */
 	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
-		rt61pci_rxdone(rt2x00dev);
+		rt2x00pci_rxdone(rt2x00dev);
 
 	/*
 	 * 3 - Tx ring done interrupt.
@@ -1859,6 +1910,8 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	struct eeprom_93cx6 eeprom;
 	u32 reg;
 	u16 word;
+	u8 *mac;
+	char value;
 
 	/*
 	 * Allocate the eeprom memory, check the eeprom width
@@ -1886,6 +1939,12 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Start validation of the data that has been read.
 	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+	}
+
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1927,6 +1986,38 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 		EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
 	}
 
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+	}
+
 	return 0;
 }
 
@@ -2086,12 +2177,17 @@ static void rt61pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 		IEEE80211_HW_WEP_INCLUDE_IV |
 		IEEE80211_HW_DATA_NULLFUNC_ACK |
 		IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
-		IEEE80211_HW_MONITOR_DURING_OPER;
+		IEEE80211_HW_MONITOR_DURING_OPER |
+		IEEE80211_HW_NO_PROBE_FILTERING;
 	rt2x00dev->hw->extra_tx_headroom = 0;
 	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 	rt2x00dev->hw->max_noise = MAX_RX_NOISE;
 	rt2x00dev->hw->queues = 5;
 
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+		rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
+
 	/*
 	 * Convert tx_power array in eeprom.
 	 */
@@ -2102,7 +2198,6 @@ static void rt61pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize hw_mode information.
 	 */
-	spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	spec->num_modes = 2;
 	spec->num_rates = 12;
 	spec->num_channels = 14;
@@ -2150,10 +2245,15 @@ static int rt61pci_init_hw(struct rt2x00_dev *rt2x00dev)
 	rt61pci_init_hw_mode(rt2x00dev);
 
 	/*
-	 * rt61pci requires firmware
+	 * This device requires firmware
 	 */
 	__set_bit(FIRMWARE_REQUIRED, &rt2x00dev->flags);
 
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
 	return 0;
 }
 
@@ -2219,8 +2319,6 @@ static void rt61pci_reset_tsf(struct ieee80211_hw *hw)
 static const struct ieee80211_ops rt61pci_mac80211_ops = {
 	.tx			= rt2x00lib_tx,
 	.reset			= rt2x00lib_reset,
-	.open			= rt2x00lib_open,
-	.stop			= rt2x00lib_stop,
 	.add_interface		= rt2x00lib_add_interface,
 	.remove_interface	= rt2x00lib_remove_interface,
 	.config			= rt2x00lib_config,
@@ -2250,6 +2348,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 	.write_tx_desc		= rt61pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
 	.kick_tx_queue		= rt61pci_kick_tx_queue,
+	.fill_rxdone		= rt61pci_fill_rxdone,
 	.config_type		= rt61pci_config_type,
 	.config_phymode		= rt61pci_config_phymode,
 	.config_channel		= rt61pci_config_channel,
@@ -2309,14 +2408,11 @@ static struct pci_driver rt61pci_driver = {
 
 static int __init rt61pci_init(void)
 {
-	printk(KERN_INFO "Loading module: %s - %s by %s.\n",
-		DRV_NAME, DRV_VERSION, DRV_PROJECT);
 	return pci_register_driver(&rt61pci_driver);
 }
 
 static void __exit rt61pci_exit(void)
 {
-	printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
 	pci_unregister_driver(&rt61pci_driver);
 }
 

+ 19 - 4
package/rt2x00/src/rt61pci.h

@@ -36,10 +36,11 @@
 #define RF2529				0x0004
 
 /*
- * Max RSSI value, required for RSSI <-> dBm conversion.
+ * Signal information.
  */
-#define MAX_RX_SSI			120
+#define MAX_RX_SSI			-1
 #define MAX_RX_NOISE			-110
+#define DEFAULT_RSSI_OFFSET		120
 
 /*
  * Register layout information.
@@ -1102,6 +1103,20 @@ struct hw_pairwise_ta_entry {
 #define EEPROM_TXPOWER_A_1		FIELD16(0x00ff)
 #define EEPROM_TXPOWER_A_2		FIELD16(0xff00)
 
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG		0x004d
+#define EEPROM_RSSI_OFFSET_BG_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2		FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A		0x004e
+#define EEPROM_RSSI_OFFSET_A_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2		FIELD16(0xff00)
+
 /*
  * BBP content.
  * The wordsize of the BBP is 8 bits.
@@ -1285,10 +1300,10 @@ struct hw_pairwise_ta_entry {
 /*
  * Word1
  * SIGNAL: RX raw data rate reported by BBP.
- * RSSI: RSSI reported by BBP.
  */
 #define RXD_W1_SIGNAL			FIELD32(0x000000ff)
-#define RXD_W1_RSSI			FIELD32(0x0000ff00)
+#define RXD_W1_RSSI_AGC			FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA			FIELD32(0x00006000)
 #define RXD_W1_FRAME_OFFSET		FIELD32(0x7f000000)
 
 /*

+ 128 - 108
package/rt2x00/src/rt73usb.c

@@ -38,6 +38,7 @@
 #include <linux/etherdevice.h>
 
 #include "rt2x00.h"
+#include "rt2x00lib.h"
 #include "rt2x00usb.h"
 #include "rt73usb.h"
 
@@ -745,13 +746,19 @@ static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev)
 		0x00, rt2x00dev->led_reg, NULL, 0, REGISTER_TIMEOUT);
 }
 
-static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, char rssi)
+static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
 {
 	u32 led;
 
 	if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
 		return;
 
+	/*
+	 * Led handling requires a positive value for the rssi,
+	 * to do that correctly we need to add the correction.
+	 */
+	rssi += rt2x00dev->rssi_offset;
+
 	if (rssi <= 30)
 		led = 0;
 	else if (rssi <= 39)
@@ -773,8 +780,9 @@ static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, char rssi)
 /*
  * Link tuning
  */
-static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
+static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
 {
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
 	u32 reg;
 	u8 r17;
 	u8 up_bound;
@@ -880,11 +888,13 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
 		if (r17 > up_bound)
 			r17 = up_bound;
 		rt73usb_bbp_write(rt2x00dev, 17, r17);
+		rt2x00dev->rx_status.noise = r17;
 	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
 		r17 -= 4;
 		if (r17 < low_bound)
 			r17 = low_bound;
 		rt73usb_bbp_write(rt2x00dev, 17, r17);
+		rt2x00dev->rx_status.noise = r17;
 	}
 }
 
@@ -952,51 +962,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
 	return 0;
 }
 
-static void rt73usb_init_rxring(struct rt2x00_dev *rt2x00dev)
-{
-	struct usb_device *usb_dev =
-		interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
-	unsigned int i;
-
-	for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
-		usb_fill_bulk_urb(
-			rt2x00dev->rx->entry[i].priv,
-			usb_dev,
-			usb_rcvbulkpipe(usb_dev, 1),
-			rt2x00dev->rx->entry[i].skb->data,
-			rt2x00dev->rx->entry[i].skb->len,
-			rt73usb_interrupt_rxdone,
-			&rt2x00dev->rx->entry[i]);
-	}
-
-	rt2x00_ring_index_clear(rt2x00dev->rx);
-}
-
-static void rt73usb_init_txring(struct rt2x00_dev *rt2x00dev,
-	const int queue)
-{
-	struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue);
-	unsigned int i;
-
-	for (i = 0; i < ring->stats.limit; i++)
-		ring->entry[i].flags = 0;
-
-	rt2x00_ring_index_clear(ring);
-}
-
-static int rt73usb_init_rings(struct rt2x00_dev *rt2x00dev)
-{
-	rt73usb_init_rxring(rt2x00dev);
-	rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
-	rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
-	rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2);
-	rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3);
-	rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4);
-	rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
-
-	return 0;
-}
-
 static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
@@ -1006,7 +971,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 
 	rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
 
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, 0x025eb032);
+	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
 	rt73usb_register_write(rt2x00dev, TXRX_CSR1, 0x9eaa9eaf);
 	rt73usb_register_write(rt2x00dev, TXRX_CSR2, 0x8a8b8c8d);
@@ -1049,10 +1019,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
 	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-
 	/*
 	 * We must clear the error counters.
 	 * These registers are cleared on read,
@@ -1164,8 +1130,7 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize all registers.
 	 */
-	if (rt73usb_init_rings(rt2x00dev) ||
-	    rt73usb_init_registers(rt2x00dev) ||
+	if (rt73usb_init_registers(rt2x00dev) ||
 	    rt73usb_init_bbp(rt2x00dev)) {
 		ERROR(rt2x00dev, "Register initialization failed.\n");
 		return -EIO;
@@ -1344,74 +1309,84 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
 }
 
 /*
- * Interrupt functions.
+ * RX control handlers
  */
-static void rt73usb_interrupt_rxdone(struct urb *urb)
+static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+	u16 eeprom;
+	char offset;
+	char lna;
+
+	lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+	switch (lna) {
+		case 3:
+			offset = 90;
+		break;
+		case 2:
+			offset = 74;
+		break;
+		case 1:
+			offset = 64;
+		break;
+		default:
+			return 0;
+	}
+
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+		if (test_bit(CONFIG_EXTERNAL_LNA, &rt2x00dev->flags)) {
+			if (lna == 3 || lna == 2)
+				offset += 10;
+		} else {
+			if (lna == 3)
+				offset += 6;
+			else if (lna == 2)
+				offset += 8;
+		}
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	} else {
+		if (test_bit(CONFIG_EXTERNAL_LNA, &rt2x00dev->flags))
+			offset += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	}
+
+	return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static int rt73usb_fill_rxdone(struct data_entry *entry,
+	int *signal, int *rssi, int *ofdm)
 {
-	struct data_entry *entry = (struct data_entry*)urb->context;
-	struct data_ring *ring = entry->ring;
-	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
 	struct data_desc *rxd = (struct data_desc*)entry->skb->data;
 	u32 word0;
 	u32 word1;
-	int signal;
-	int rssi;
-	int ofdm;
-	u16 size;
-
-	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
-	    !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
-		return;
-
-	/*
-	 * Check if the received data is simply too small
-	 * to be actually valid, or if the urb is signaling
-	 * a problem.
-	 */
-	if (urb->actual_length < entry->ring->desc_size || urb->status)
-		goto skip_entry;
 
 	rt2x00_desc_read(rxd, 0, &word0);
 	rt2x00_desc_read(rxd, 1, &word1);
 
 	/*
 	 * TODO: Don't we need to keep statistics
-	 * updated about events like CRC and physical errors?
+	 * updated about these errors?
 	 */
 	if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
 	    rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
-		goto skip_entry;
+		return -EINVAL;
 
 	/*
 	 * Obtain the status about this packet.
 	 */
-	size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-	signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-	rssi = rt2x00_get_field32(word1, RXD_W1_RSSI);
-	ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+	*signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+	*rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
+	*ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
 
 	/*
-	 * Trim the skb_buffer to only contain the valid
-	 * frame data (so ignore the device's descriptor).
+	 * Pull the skb to clear the descriptor area.
 	 */
-	skb_pull(entry->skb, ring->desc_size);
-	skb_trim(entry->skb, size);
+	skb_pull(entry->skb, entry->ring->desc_size);
 
-	/*
-	 * Send the packet to upper layer, and update urb.
-	 */
-	rt2x00lib_rxdone(entry, NULL, ring->data_size + ring->desc_size,
-		signal, rssi, ofdm);
-	urb->transfer_buffer = entry->skb->data;
-	urb->transfer_buffer_length = entry->skb->len;
-
-skip_entry:
-	if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
-		__set_bit(ENTRY_OWNER_NIC, &entry->flags);
-		usb_submit_urb(urb, GFP_ATOMIC);
-	}
-
-	rt2x00_ring_index_inc(ring);
+	return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 }
 
 /*
@@ -1420,6 +1395,8 @@ skip_entry:
 static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 {
 	u16 word;
+	u8 *mac;
+	char value;
 
 	/*
 	 * Allocate the eeprom memory, check the eeprom width
@@ -1437,6 +1414,12 @@ static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Start validation of the data that has been read.
 	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+	}
+
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1481,6 +1464,38 @@ static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
 		EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
 	}
 
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+	}
+
 	return 0;
 }
 
@@ -1612,12 +1627,17 @@ static void rt73usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 		IEEE80211_HW_WEP_INCLUDE_IV |
 		IEEE80211_HW_DATA_NULLFUNC_ACK |
 		IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
-		IEEE80211_HW_MONITOR_DURING_OPER;
+		IEEE80211_HW_MONITOR_DURING_OPER |
+		IEEE80211_HW_NO_PROBE_FILTERING;
 	rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
 	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 	rt2x00dev->hw->max_noise = MAX_RX_NOISE;
 	rt2x00dev->hw->queues = 5;
 
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+		rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
+
 	/*
 	 * Set device specific, but channel independent RF values.
 	 */
@@ -1638,7 +1658,6 @@ static void rt73usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize hw_mode information.
 	 */
-	spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	spec->num_modes = 2;
 	spec->num_rates = 12;
 	spec->num_channels = 14;
@@ -1683,10 +1702,15 @@ static int rt73usb_init_hw(struct rt2x00_dev *rt2x00dev)
 	rt73usb_init_hw_mode(rt2x00dev);
 
 	/*
-	 * rt73usb requires firmware
+	 * This device requires firmware
 	 */
 	__set_bit(FIRMWARE_REQUIRED, &rt2x00dev->flags);
 
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
 	return 0;
 }
 
@@ -1752,8 +1776,6 @@ static void rt73usb_reset_tsf(struct ieee80211_hw *hw)
 static const struct ieee80211_ops rt73usb_mac80211_ops = {
 	.tx			= rt2x00lib_tx,
 	.reset			= rt2x00lib_reset,
-	.open			= rt2x00lib_open,
-	.stop			= rt2x00lib_stop,
 	.add_interface		= rt2x00lib_add_interface,
 	.remove_interface	= rt2x00lib_remove_interface,
 	.config			= rt2x00lib_config,
@@ -1779,6 +1801,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 	.write_tx_desc		= rt73usb_write_tx_desc,
 	.write_tx_data		= rt2x00usb_write_tx_data,
 	.kick_tx_queue		= rt73usb_kick_tx_queue,
+	.fill_rxdone		= rt73usb_fill_rxdone,
 	.config_type		= rt73usb_config_type,
 	.config_phymode		= rt73usb_config_phymode,
 	.config_channel		= rt73usb_config_channel,
@@ -1881,14 +1904,11 @@ static struct usb_driver rt73usb_driver = {
 
 static int __init rt73usb_init(void)
 {
-	printk(KERN_INFO "Loading module: %s - %s by %s.\n",
-		DRV_NAME, DRV_VERSION, DRV_PROJECT);
 	return usb_register(&rt73usb_driver);
 }
 
 static void __exit rt73usb_exit(void)
 {
-	printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
 	usb_deregister(&rt73usb_driver);
 }
 

+ 19 - 8
package/rt2x00/src/rt73usb.h

@@ -36,10 +36,11 @@
 #define RF2527				0x0004
 
 /*
- * Max RSSI value, required for RSSI <-> dBm conversion.
+ * Signal information.
  */
-#define MAX_RX_SSI			120
+#define MAX_RX_SSI			-1
 #define MAX_RX_NOISE			-110
+#define DEFAULT_RSSI_OFFSET		120
 
 /*
  * Register layout information.
@@ -748,6 +749,20 @@ struct hw_pairwise_ta_entry {
 #define EEPROM_TXPOWER_A_1		FIELD16(0x00ff)
 #define EEPROM_TXPOWER_A_2		FIELD16(0xff00)
 
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG		0x004d
+#define EEPROM_RSSI_OFFSET_BG_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2		FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A		0x004e
+#define EEPROM_RSSI_OFFSET_A_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2		FIELD16(0xff00)
+
 /*
  * BBP content.
  * The wordsize of the BBP is 8 bits.
@@ -886,7 +901,8 @@ struct hw_pairwise_ta_entry {
  * RSSI: RSSI reported by BBP.
  */
 #define RXD_W1_SIGNAL			FIELD32(0x000000ff)
-#define RXD_W1_RSSI			FIELD32(0x0000ff00)
+#define RXD_W1_RSSI_AGC			FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA			FIELD32(0x00006000)
 #define RXD_W1_FRAME_OFFSET		FIELD32(0x7f000000)
 
 /*
@@ -939,9 +955,4 @@ struct hw_pairwise_ta_entry {
 	(__txpower));					\
 })
 
-/*
- * Interrupt functions.
- */
-static void rt73usb_interrupt_rxdone(struct urb *urb);
-
 #endif /* RT73USB_H */