diff options
29 files changed, 2069 insertions, 852 deletions
| diff --git a/package/rt2x00/Makefile b/package/rt2x00/Makefile index 4ab5a1221..1759f82bd 100644 --- a/package/rt2x00/Makefile +++ b/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 diff --git a/package/rt2x00/src/COPYING b/package/rt2x00/src/COPYING new file mode 100644 index 000000000..5b6e7c66c --- /dev/null +++ b/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. diff --git a/package/rt2x00/src/Makefile b/package/rt2x00/src/Makefile index 0ed8321e3..84352c396 100644 --- a/package/rt2x00/src/Makefile +++ b/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 diff --git a/package/rt2x00/src/README b/package/rt2x00/src/README new file mode 100644 index 000000000..7f3f448ea --- /dev/null +++ b/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: rt2400-general@lists.sourceforge.net +	# developers: rt2400-devel@lists.sourceforge.net + + - Sourceforge: +	# http://sourceforge.net/projects/rt2400 + diff --git a/package/rt2x00/src/THANKS b/package/rt2x00/src/THANKS new file mode 100644 index 000000000..81b88d21f --- /dev/null +++ b/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 - mwallis@serialmonkey.com +* Ivo van Doorn - IvDoorn@gmail.com +* Luis Correia - lfcorreia@users.sf.net +* Robin Cornelius - robin.cornelius@gmail.com +* Gertjan van Wingerde - gwingerde@kpnplanet.nl +* Romain - spy84464@hotmail.com + +Special thanks to the contributors of this project: +* Adisorn Ermongkonchai - moo7822-wlan@yahoo.com +* Amir Shalem - amir@boom.org.il +* Bernd Petrovitsch - bernd@firmix.at +* Bruno - bruno123@users.sf.net +* Chris Houston - chris.houston@atterotech.com +* Defekt - defekt@liquid-nexus.net +* Edvard - eaglenest@users.sourceforge.net +* Flavio Stanchina - flavio@stanchina.net +* Gregor Glomm - gg@seh.de +* Heikki Pernu - heikki.pernu@nekonet.fi +* Jerzy Kozera - nordom@tlen.pl +* Joachim Gleißner - jg@suse.de +* John Coppens - john@jcoppens.com +* Jonathan Hudson +* KrissN - krissn@op.pl +* Luca Tettamanti - kronos.it@gmail.com +* Magnus Damm - magnus.damm@gmail.com +* Mags +* Mathias Klien - ma_klein@gmx.de +* Meelis Roos - mroos@linux.ee +* Michal Ludvig - michal@logix.cz +* Miguel - miguel.marte2@verizon.net +* Mike Skinner +* Olivier Cornu - o.cornu@gmail.com +* Paul Hampson - Paul.Hampson@anu.edu.au +* Philippe Rousselot - amazilia@users.sourceforge.net +* Remco - remco@d-compu.dyndns.org +* Sergey Vlasov - vsu@altlinux.ru +* Stephen Warren - SWarren@nvidia.com +* Stuart Rackham - srackham@methods.co.nz +* Thor Harald Johansen - thorhajo@gmail.com +* Tor Petterson - 2r@manowar.dk + +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. diff --git a/package/rt2x00/src/config b/package/rt2x00/src/config new file mode 100644 index 000000000..8a099118b --- /dev/null +++ b/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 diff --git a/package/rt2x00/src/rt2400pci.c b/package/rt2x00/src/rt2400pci.c index aaed3b4ac..824c8233e 100644 --- a/package/rt2x00/src/rt2400pci.c +++ b/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,11 +928,35 @@ 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, ®); +		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, ®); +	rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, !enabled); +	rt2x00_set_field32(®, CSR8_TXDONE_TXRING, !enabled); +	rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, !enabled); +	rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, !enabled); +	rt2x00_set_field32(®, CSR8_RXDONE, !enabled); +	rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ +	/*  	 * Initialize all registers.  	 */  	if (rt2400pci_init_rings(rt2x00dev) || @@ -941,21 +967,9 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)  	}  	/* -	 * Clear interrupts. -	 */ -	rt2x00pci_register_read(rt2x00dev, CSR7, ®); -	rt2x00pci_register_write(rt2x00dev, CSR7, reg); - -	/*  	 * Enable interrupts.  	 */ -	rt2x00pci_register_read(rt2x00dev, CSR8, ®); -	rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 0); -	rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); -	rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); -	rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); -	rt2x00_set_field32(®, 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, ®); -	rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 1); -	rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 1); -	rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 1); -	rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 1); -	rt2x00_set_field32(®, 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);  } diff --git a/package/rt2x00/src/rt2400pci.h b/package/rt2x00/src/rt2400pci.h index 097f4c994..10fe48888 100644 --- a/package/rt2x00/src/rt2400pci.h +++ b/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. diff --git a/package/rt2x00/src/rt2500pci.c b/package/rt2x00/src/rt2500pci.c index 61d7e74e6..d71e3c32a 100644 --- a/package/rt2x00/src/rt2500pci.c +++ b/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, ®); +	rt2x00_set_field32(®, PCICSR_BIG_ENDIAN, 0); +	rt2x00_set_field32(®, PCICSR_RX_TRESHOLD, 0); +	rt2x00_set_field32(®, PCICSR_TX_TRESHOLD, 3); +	rt2x00_set_field32(®, PCICSR_BURST_LENTH, 1); +	rt2x00_set_field32(®, PCICSR_ENABLE_CLK, 1); +	rt2x00_set_field32(®, PCICSR_READ_MULTIPLE, 1); +	rt2x00_set_field32(®, PCICSR_WRITE_INVALID, 1); +	rt2x00pci_register_write(rt2x00dev, PCICSR, reg);  	rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);  	rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002); @@ -1079,11 +1093,35 @@ 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, ®); +		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, ®); +	rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, !enabled); +	rt2x00_set_field32(®, CSR8_TXDONE_TXRING, !enabled); +	rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, !enabled); +	rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, !enabled); +	rt2x00_set_field32(®, CSR8_RXDONE, !enabled); +	rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ +	/*  	 * Initialize all registers.  	 */  	if (rt2500pci_init_rings(rt2x00dev) || @@ -1094,21 +1132,9 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)  	}  	/* -	 * Clear interrupts. -	 */ -	rt2x00pci_register_read(rt2x00dev, CSR7, ®); -	rt2x00pci_register_write(rt2x00dev, CSR7, reg); - -	/*  	 * Enable interrupts.  	 */ -	rt2x00pci_register_read(rt2x00dev, CSR8, ®); -	rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 0); -	rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); -	rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); -	rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); -	rt2x00_set_field32(®, 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, ®); -	rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 1); -	rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 1); -	rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 1); -	rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 1); -	rt2x00_set_field32(®, 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);  } diff --git a/package/rt2x00/src/rt2500pci.h b/package/rt2x00/src/rt2500pci.h index e695a57da..c70bcb790 100644 --- a/package/rt2x00/src/rt2500pci.h +++ b/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. @@ -1046,6 +1047,11 @@  #define BBP_R14_RX_IQ_FLIP		FIELD8(0x04)  /* + * BBP_R70 + */ +#define BBP_R70_JAPAN_FILTER		FIELD8(0x08) + +/*   * DMA descriptor defines.   */  #define TXD_DESC_SIZE			( 11 * sizeof(struct data_desc) ) diff --git a/package/rt2x00/src/rt2500usb.c b/package/rt2x00/src/rt2500usb.c index c5459b508..3be51f0a3 100644 --- a/package/rt2x00/src/rt2500usb.c +++ b/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, ®); +	rt2x00_set_field16(®, 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, ®); -	if (reg >= 0x0003) { +	if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {  		rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®);  		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);  } diff --git a/package/rt2x00/src/rt2500usb.h b/package/rt2x00/src/rt2500usb.h index e756d6eb6..814bd0452 100644 --- a/package/rt2x00/src/rt2500usb.h +++ b/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 */ diff --git a/package/rt2x00/src/rt2x00.h b/package/rt2x00/src/rt2x00.h index dbea6acf6..33b509435 100644 --- a/package/rt2x00/src/rt2x00.h +++ b/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. @@ -570,16 +565,25 @@ 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. @@ -637,6 +641,33 @@ static inline int is_monitor_present(struct interface *intf)  }  /* + * 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.   */  struct rt2x00lib_ops { @@ -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 @@ -681,12 +712,18 @@ struct rt2x00lib_ops {  	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;  }  /* diff --git a/package/rt2x00/src/rt2x00_compat.h b/package/rt2x00/src/rt2x00_compat.h index 111c51ea3..83d4f9904 100644 --- a/package/rt2x00/src/rt2x00_compat.h +++ b/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! diff --git a/package/rt2x00/src/rt2x00_config.h b/package/rt2x00/src/rt2x00_config.h index 5751dd1f7..e69de29bb 100644 --- a/package/rt2x00/src/rt2x00_config.h +++ b/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 - diff --git a/package/rt2x00/src/rt2x00debug.c b/package/rt2x00/src/rt2x00debug.c index cb618700a..e2239fab8 100644 --- a/package/rt2x00/src/rt2x00debug.c +++ b/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" ) diff --git a/package/rt2x00/src/rt2x00debug.h b/package/rt2x00/src/rt2x00debug.h index 8c8f5a3e8..f987bc91f 100644 --- a/package/rt2x00/src/rt2x00debug.h +++ b/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); diff --git a/package/rt2x00/src/rt2x00dev.c b/package/rt2x00/src/rt2x00dev.c index 448f1bcad..043af3156 100644 --- a/package/rt2x00/src/rt2x00dev.c +++ b/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);  } @@ -423,23 +421,6 @@ static int rt2x00lib_init_hw(struct rt2x00_dev *rt2x00dev)  	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.  	 */  	status = rt2x00lib_init_hw_modes(rt2x00dev, spec); @@ -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;  } @@ -589,11 +570,6 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)  		return;  	/* -	 * Flush out all pending work. -	 */ -	flush_workqueue(rt2x00dev->workqueue); - -	/*  	 * Unregister rfkill.  	 */  	rt2x00lib_unregister_rfkill(rt2x00dev); @@ -606,7 +582,7 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)  	/*  	 * Free allocated datarings.  	 */ -	rt2x00lib_free_rings(rt2x00dev); +	rt2x00lib_free_ring_entries(rt2x00dev);  }  /* @@ -660,13 +636,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.  	 */  	retval = rt2x00dev->ops->lib->init_hw(rt2x00dev); @@ -764,14 +733,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.  	 */  	kfree(rt2x00dev->rx); @@ -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);  	/* @@ -1002,12 +956,6 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,  		__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.  	 */ diff --git a/package/rt2x00/src/rt2x00firmware.c b/package/rt2x00/src/rt2x00firmware.c index 3aef1073d..4c1ce4cdb 100644 --- a/package/rt2x00/src/rt2x00firmware.c +++ b/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) diff --git a/package/rt2x00/src/rt2x00lib.h b/package/rt2x00/src/rt2x00lib.h index c9b5ee7bf..461d13db0 100644 --- a/package/rt2x00/src/rt2x00lib.h +++ b/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 */ diff --git a/package/rt2x00/src/rt2x00mac.c b/package/rt2x00/src/rt2x00mac.c index 349353bee..8835df2e2 100644 --- a/package/rt2x00/src/rt2x00mac.c +++ b/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); diff --git a/package/rt2x00/src/rt2x00pci.c b/package/rt2x00/src/rt2x00pci.c index 4156ea36a..33c724d44 100644 --- a/package/rt2x00/src/rt2x00pci.c +++ b/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); @@ -134,6 +136,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.   */  #define priv_offset(__ring, __i)				\ @@ -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; diff --git a/package/rt2x00/src/rt2x00pci.h b/package/rt2x00/src/rt2x00pci.h index 291d0c026..8595cbff4 100644 --- a/package/rt2x00/src/rt2x00pci.h +++ b/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. @@ -94,6 +95,11 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,  	struct ieee80211_tx_control *control);  /* + * RX data handlers. + */ +void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); + +/*   * Device initialization handlers.   */  int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev); diff --git a/package/rt2x00/src/rt2x00rfkill.c b/package/rt2x00/src/rt2x00rfkill.c index 63062f1ec..c08a2aa0e 100644 --- a/package/rt2x00/src/rt2x00rfkill.c +++ b/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);  } diff --git a/package/rt2x00/src/rt2x00usb.c b/package/rt2x00/src/rt2x00usb.c index 6b193d023..4175aeffe 100644 --- a/package/rt2x00/src/rt2x00usb.c +++ b/package/rt2x00/src/rt2x00usb.c @@ -36,6 +36,7 @@  #include <linux/usb.h>  #include "rt2x00.h" +#include "rt2x00lib.h"  #include "rt2x00usb.h"  /* @@ -62,49 +63,14 @@ 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.   */  int rt2x00usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -329,6 +295,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.   */  static int rt2x00usb_alloc_ring(struct rt2x00_dev *rt2x00dev, @@ -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; diff --git a/package/rt2x00/src/rt61pci.c b/package/rt2x00/src/rt61pci.c index fe90dd214..627754802 100644 --- a/package/rt2x00/src/rt61pci.c +++ b/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, ®); +	rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); +	rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); +	rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); +	rt2x00_set_field32(®, 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(®, MAC_CSR9_CW_SELECT, 0);  	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); -	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); -	rt2x00_set_field32(®, 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,11 +1443,49 @@ 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, ®); +		rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + +		rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); +		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, ®); +	rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, !enabled); +	rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, !enabled); +	rt2x00_set_field32(®, INT_MASK_CSR_BEACON_DONE, !enabled); +	rt2x00_set_field32(®, INT_MASK_CSR_ENABLE_MITIGATION, !enabled); +	rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); +	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + +	rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); +	rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, !enabled); +	rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, !enabled); +	rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, !enabled); +	rt2x00_set_field32(®, MCU_INT_MASK_CSR_3, !enabled); +	rt2x00_set_field32(®, MCU_INT_MASK_CSR_4, !enabled); +	rt2x00_set_field32(®, MCU_INT_MASK_CSR_5, !enabled); +	rt2x00_set_field32(®, MCU_INT_MASK_CSR_6, !enabled); +	rt2x00_set_field32(®, 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.  	 */  	if (rt61pci_init_rings(rt2x00dev) || @@ -1447,23 +1496,9 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)  	}  	/* -	 * Clear interrupts. -	 */ -	rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); -	rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); - -	rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); -	rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); - -	/*  	 * Enable interrupts.  	 */ -	reg = 0; -	rt2x00_set_field32(®, INT_MASK_CSR_TX_ABORT_DONE, 1); -	rt2x00_set_field32(®, 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(®, 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);  } diff --git a/package/rt2x00/src/rt61pci.h b/package/rt2x00/src/rt61pci.h index 68347324c..9dfd29356 100644 --- a/package/rt2x00/src/rt61pci.h +++ b/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. @@ -1103,6 +1104,20 @@ struct hw_pairwise_ta_entry {  #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)  /* diff --git a/package/rt2x00/src/rt73usb.c b/package/rt2x00/src/rt73usb.c index 04261faa3..c80bee1e5 100644 --- a/package/rt2x00/src/rt73usb.c +++ b/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, ®); +	rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); +	rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); +	rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); +	rt2x00_set_field32(®, 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(®, MAC_CSR9_CW_SELECT, 0);  	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); -	rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); -	rt2x00_set_field32(®, 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);  } diff --git a/package/rt2x00/src/rt73usb.h b/package/rt2x00/src/rt73usb.h index 779665698..159240f1c 100644 --- a/package/rt2x00/src/rt73usb.h +++ b/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. @@ -749,6 +750,20 @@ struct hw_pairwise_ta_entry {  #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 */ | 
