aboutsummaryrefslogtreecommitdiffstats
path: root/package/rt2x00/src
diff options
context:
space:
mode:
Diffstat (limited to 'package/rt2x00/src')
-rw-r--r--package/rt2x00/src/COPYING340
-rw-r--r--package/rt2x00/src/Makefile152
-rw-r--r--package/rt2x00/src/README548
-rw-r--r--package/rt2x00/src/THANKS54
-rw-r--r--package/rt2x00/src/config41
-rw-r--r--package/rt2x00/src/rt2400pci.c157
-rw-r--r--package/rt2x00/src/rt2400pci.h5
-rw-r--r--package/rt2x00/src/rt2500pci.c177
-rw-r--r--package/rt2x00/src/rt2500pci.h10
-rw-r--r--package/rt2x00/src/rt2500usb.c162
-rw-r--r--package/rt2x00/src/rt2500usb.h17
-rw-r--r--package/rt2x00/src/rt2x00.h138
-rw-r--r--package/rt2x00/src/rt2x00_compat.h6
-rw-r--r--package/rt2x00/src/rt2x00_config.h44
-rw-r--r--package/rt2x00/src/rt2x00debug.c1
-rw-r--r--package/rt2x00/src/rt2x00debug.h2
-rw-r--r--package/rt2x00/src/rt2x00dev.c96
-rw-r--r--package/rt2x00/src/rt2x00firmware.c11
-rw-r--r--package/rt2x00/src/rt2x00lib.h41
-rw-r--r--package/rt2x00/src/rt2x00mac.c138
-rw-r--r--package/rt2x00/src/rt2x00pci.c53
-rw-r--r--package/rt2x00/src/rt2x00pci.h16
-rw-r--r--package/rt2x00/src/rt2x00rfkill.c4
-rw-r--r--package/rt2x00/src/rt2x00usb.c155
-rw-r--r--package/rt2x00/src/rt61pci.c256
-rw-r--r--package/rt2x00/src/rt61pci.h23
-rw-r--r--package/rt2x00/src/rt73usb.c236
-rw-r--r--package/rt2x00/src/rt73usb.h27
28 files changed, 2063 insertions, 847 deletions
diff --git a/package/rt2x00/src/COPYING b/package/rt2x00/src/COPYING
new file mode 100644
index 0000000000..5b6e7c66c2
--- /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 0ed8321e36..84352c3963 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 0000000000..7f3f448eaa
--- /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 0000000000..81b88d21f9
--- /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 0000000000..8a099118b2
--- /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 aaed3b4ac0..824c8233e8 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, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, !enabled);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, !enabled);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, !enabled);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, !enabled);
+ rt2x00_set_field32(&reg, CSR8_RXDONE, !enabled);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
* Initialize all registers.
*/
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, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
- /*
* Enable interrupts.
*/
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
- rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
- rt2x00_set_field32(&reg, CSR8_RXDONE, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2400pci_toggle_irq(rt2x00dev, 1);
/*
* Enable LED
@@ -991,13 +1005,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable interrupts.
*/
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
- rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 1);
- rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 1);
- rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 1);
- rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 1);
- rt2x00_set_field32(&reg, CSR8_RXDONE, 1);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2400pci_toggle_irq(rt2x00dev, 0);
}
static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1163,59 +1171,40 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
- * Interrupt functions.
+ * RX control handlers
*/
-static void rt2400pci_rxdone(struct rt2x00_dev *rt2x00dev)
+static int rt2400pci_fill_rxdone(struct data_entry *entry,
+ int *signal, int *rssi, int *ofdm)
{
- struct data_ring *ring = rt2x00dev->rx;
- struct data_entry *entry;
- struct data_desc *rxd;
+ struct data_desc *rxd = entry->priv;
u32 word0;
u32 word2;
- int signal;
- int rssi;
- u16 size;
-
- while (1) {
- entry = rt2x00_get_data_entry(ring);
- rxd = entry->priv;
- rt2x00_desc_read(rxd, 0, &word0);
- rt2x00_desc_read(rxd, 2, &word2);
-
- if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
- break;
-
- /*
- * TODO: Don't we need to keep statistics
- * updated about events like CRC and physical errors?
- */
- if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
- rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
- goto skip_entry;
- /*
- * Obtain the status about this packet.
- */
- size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
- rssi = rt2x00_get_field32(word2, RXD_W2_RSSI);
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 2, &word2);
- /*
- * Send the packet to upper layer.
- */
- rt2x00lib_rxdone(entry, entry->data_addr, size,
- signal, rssi, 0);
+ /*
+ * TODO: Don't we need to keep statistics
+ * updated about these errors?
+ */
+ if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
+ rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ return -EINVAL;
-skip_entry:
- if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
- rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(rxd, 0, word0);
- }
+ /*
+ * Obtain the status about this packet.
+ */
+ *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+ *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ *ofdm = 0;
- rt2x00_ring_index_inc(ring);
- }
+ return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
}
+/*
+ * Interrupt functions.
+ */
static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
{
struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue);
@@ -1296,7 +1285,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
* 2 - Rx ring done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_RXDONE))
- rt2400pci_rxdone(rt2x00dev);
+ rt2x00pci_rxdone(rt2x00dev);
/*
* 3 - Atim ring transmit done interrupt.
@@ -1327,6 +1316,7 @@ static int rt2400pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
struct eeprom_93cx6 eeprom;
u32 reg;
u16 word;
+ u8 *mac;
/*
* Allocate the eeprom memory, check the eeprom width
@@ -1354,6 +1344,12 @@ static int rt2400pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Start validation of the data that has been read.
*/
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+ }
+
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
ERROR(rt2x00dev, "Invalid EEPROM data detected.\n");
@@ -1440,16 +1436,16 @@ static void rt2400pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_WEP_INCLUDE_IV |
IEEE80211_HW_DATA_NULLFUNC_ACK |
IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
- IEEE80211_HW_MONITOR_DURING_OPER;
+ IEEE80211_HW_MONITOR_DURING_OPER |
+ IEEE80211_HW_NO_PROBE_FILTERING;
rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->max_noise = MAX_RX_NOISE;
rt2x00dev->hw->queues = 2;
- /*
- * This device supports ATIM
- */
- __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
/*
* Set device specific, but channel independent RF values.
@@ -1470,7 +1466,6 @@ static void rt2400pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw_mode information.
*/
- spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
spec->num_modes = 1;
spec->num_rates = 4;
spec->num_channels = 14;
@@ -1501,6 +1496,16 @@ static int rt2400pci_init_hw(struct rt2x00_dev *rt2x00dev)
*/
rt2400pci_init_hw_mode(rt2x00dev);
+ /*
+ * This device supports ATIM
+ */
+ __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
return 0;
}
@@ -1599,8 +1604,6 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.tx = rt2x00lib_tx,
.reset = rt2x00lib_reset,
- .open = rt2x00lib_open,
- .stop = rt2x00lib_stop,
.add_interface = rt2x00lib_add_interface,
.remove_interface = rt2x00lib_remove_interface,
.config = rt2x00lib_config,
@@ -1629,6 +1632,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.write_tx_desc = rt2400pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2400pci_kick_tx_queue,
+ .fill_rxdone = rt2400pci_fill_rxdone,
.config_type = rt2400pci_config_type,
.config_phymode = rt2400pci_config_phymode,
.config_channel = rt2400pci_config_channel,
@@ -1679,14 +1683,11 @@ static struct pci_driver rt2400pci_driver = {
static int __init rt2400pci_init(void)
{
- printk(KERN_INFO "Loading module: %s - %s by %s.\n",
- DRV_NAME, DRV_VERSION, DRV_PROJECT);
return pci_register_driver(&rt2400pci_driver);
}
static void __exit rt2400pci_exit(void)
{
- printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
pci_unregister_driver(&rt2400pci_driver);
}
diff --git a/package/rt2x00/src/rt2400pci.h b/package/rt2x00/src/rt2400pci.h
index 097f4c9941..10fe48888b 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 61d7e74e61..d71e3c32a4 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, &reg);
+ rt2x00_set_field32(&reg, PCICSR_BIG_ENDIAN, 0);
+ rt2x00_set_field32(&reg, PCICSR_RX_TRESHOLD, 0);
+ rt2x00_set_field32(&reg, PCICSR_TX_TRESHOLD, 3);
+ rt2x00_set_field32(&reg, PCICSR_BURST_LENTH, 1);
+ rt2x00_set_field32(&reg, PCICSR_ENABLE_CLK, 1);
+ rt2x00_set_field32(&reg, PCICSR_READ_MULTIPLE, 1);
+ rt2x00_set_field32(&reg, PCICSR_WRITE_INVALID, 1);
+ rt2x00pci_register_write(rt2x00dev, PCICSR, reg);
rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
@@ -1079,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, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, !enabled);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, !enabled);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, !enabled);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, !enabled);
+ rt2x00_set_field32(&reg, CSR8_RXDONE, !enabled);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
* Initialize all registers.
*/
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, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
- /*
* Enable interrupts.
*/
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
- rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
- rt2x00_set_field32(&reg, CSR8_RXDONE, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2500pci_toggle_irq(rt2x00dev, 1);
/*
* Enable LED
@@ -1144,13 +1170,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable interrupts.
*/
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
- rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 1);
- rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 1);
- rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 1);
- rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 1);
- rt2x00_set_field32(&reg, CSR8_RXDONE, 1);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2500pci_toggle_irq(rt2x00dev, 0);
}
static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1300,61 +1320,37 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
- * Interrupt functions.
+ * RX control handlers
*/
-static void rt2500pci_rxdone(struct rt2x00_dev *rt2x00dev)
+static int rt2500pci_fill_rxdone(struct data_entry *entry,
+ int *signal, int *rssi, int *ofdm)
{
- struct data_ring *ring = rt2x00dev->rx;
- struct data_entry *entry;
- struct data_desc *rxd;
+ struct data_desc *rxd = entry->priv;
u32 word0;
u32 word2;
- int signal;
- int rssi;
- int ofdm;
- u16 size;
-
- while (1) {
- entry = rt2x00_get_data_entry(ring);
- rxd = entry->priv;
- rt2x00_desc_read(rxd, 0, &word0);
- rt2x00_desc_read(rxd, 2, &word2);
-
- if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
- break;
- /*
- * TODO: Don't we need to keep statistics
- * updated about events like CRC and physical errors?
- */
- if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
- rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
- goto skip_entry;
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 2, &word2);
- /*
- * Obtain the status about this packet.
- */
- size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
- rssi = rt2x00_get_field32(word2, RXD_W2_RSSI);
- ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
-
- /*
- * Send the packet to upper layer.
- */
- rt2x00lib_rxdone(entry, entry->data_addr, size,
- signal, rssi, ofdm);
+ /*
+ * TODO: Don't we need to keep statistics
+ * updated about these errors?
+ */
+ if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
+ rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ return -EINVAL;
-skip_entry:
- if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
- rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(rxd, 0, word0);
- }
+ *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+ *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
- rt2x00_ring_index_inc(ring);
- }
+ return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
}
+/*
+ * Interrupt functions.
+ */
static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
{
struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue);
@@ -1435,7 +1431,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
* 2 - Rx ring done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_RXDONE))
- rt2500pci_rxdone(rt2x00dev);
+ rt2x00pci_rxdone(rt2x00dev);
/*
* 3 - Atim ring transmit done interrupt.
@@ -1466,6 +1462,7 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
struct eeprom_93cx6 eeprom;
u32 reg;
u16 word;
+ u8 *mac;
/*
* Allocate the eeprom memory, check the eeprom width
@@ -1493,6 +1490,12 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Start validation of the data that has been read.
*/
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+ }
+
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1518,7 +1521,7 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
- MAX_RX_SSI);
+ DEFAULT_RSSI_OFFSET);
rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
}
@@ -1586,7 +1589,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Read the RSSI <-> dBm offset information.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
- rt2x00dev->hw->max_rssi =
+ rt2x00dev->rssi_offset =
rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
return 0;
@@ -1660,16 +1663,16 @@ static void rt2500pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_WEP_INCLUDE_IV |
IEEE80211_HW_DATA_NULLFUNC_ACK |
IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
- IEEE80211_HW_MONITOR_DURING_OPER;
+ IEEE80211_HW_MONITOR_DURING_OPER |
+ IEEE80211_HW_NO_PROBE_FILTERING;
rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->max_noise = MAX_RX_NOISE;
rt2x00dev->hw->queues = 2;
- /*
- * This device supports ATIM
- */
- __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
/*
* Set device specific, but channel independent RF values.
@@ -1692,7 +1695,6 @@ static void rt2500pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw_mode information.
*/
- spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
spec->num_modes = 2;
spec->num_rates = 12;
spec->num_channels = 14;
@@ -1738,6 +1740,11 @@ static int rt2500pci_init_hw(struct rt2x00_dev *rt2x00dev)
*/
rt2500pci_init_hw_mode(rt2x00dev);
+ /*
+ * This device supports ATIM
+ */
+ __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+
return 0;
}
@@ -1812,8 +1819,6 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.tx = rt2x00lib_tx,
.reset = rt2x00lib_reset,
- .open = rt2x00lib_open,
- .stop = rt2x00lib_stop,
.add_interface = rt2x00lib_add_interface,
.remove_interface = rt2x00lib_remove_interface,
.config = rt2x00lib_config,
@@ -1842,6 +1847,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.write_tx_desc = rt2500pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2500pci_kick_tx_queue,
+ .fill_rxdone = rt2500pci_fill_rxdone,
.config_type = rt2500pci_config_type,
.config_phymode = rt2500pci_config_phymode,
.config_channel = rt2500pci_config_channel,
@@ -1892,14 +1898,11 @@ static struct pci_driver rt2500pci_driver = {
static int __init rt2500pci_init(void)
{
- printk(KERN_INFO "Loading module: %s - %s by %s.\n",
- DRV_NAME, DRV_VERSION, DRV_PROJECT);
return pci_register_driver(&rt2500pci_driver);
}
static void __exit rt2500pci_exit(void)
{
- printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
pci_unregister_driver(&rt2500pci_driver);
}
diff --git a/package/rt2x00/src/rt2500pci.h b/package/rt2x00/src/rt2500pci.h
index e695a57da5..c70bcb790b 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 c5459b5082..3be51f0a36 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, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111);
rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11);
@@ -819,9 +781,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_write(rt2x00dev, MAC_CSR1, 0x0004);
- reg = 0;
- rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg >= 0x0003) {
+ if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
reg &= ~0x0002;
} else {
@@ -962,8 +922,7 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all registers.
*/
- if (rt2500usb_init_rings(rt2x00dev) ||
- rt2500usb_init_registers(rt2x00dev) ||
+ if (rt2500usb_init_registers(rt2x00dev) ||
rt2500usb_init_bbp(rt2x00dev)) {
ERROR(rt2x00dev, "Register initialization failed.\n");
return -EIO;
@@ -1107,7 +1066,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_OFDM,
test_bit(ENTRY_TXD_OFDM_RATE, &entry->flags));
rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
- test_bit(ENTRY_TXD_NEW_SEQ, &entry->flags));
+ control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT);
rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
@@ -1141,74 +1100,40 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
- * Interrupt functions.
+ * RX control handlers
*/
-static void rt2500usb_interrupt_rxdone(struct urb *urb)
+static int rt2500usb_fill_rxdone(struct data_entry *entry,
+ int *signal, int *rssi, int *ofdm)
{
- struct data_entry *entry = (struct data_entry*)urb->context;
- struct data_ring *ring = entry->ring;
- struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
- struct data_desc *rxd = (struct data_desc*)
- (entry->skb->data + urb->actual_length - ring->desc_size);
+ struct urb *urb = entry->priv;
+ struct data_desc *rxd = (struct data_desc*)(entry->skb->data +
+ (urb->actual_length - entry->ring->desc_size));
u32 word0;
u32 word1;
- int signal;
- int rssi;
- int ofdm;
- u16 size;
-
- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
- return;
-
- /*
- * Check if the received data is simply too small
- * to be actually valid, or if the urb is signaling
- * a problem.
- */
- if (urb->actual_length < entry->ring->desc_size || urb->status)
- goto skip_entry;
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
/*
* TODO: Don't we need to keep statistics
- * updated about events like CRC and physical errors?
+ * updated about these errors?
*/
if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
- goto skip_entry;
+ return -EINVAL;
/*
* Obtain the status about this packet.
*/
- size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT) - FCS_LEN;
- signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- rssi = rt2x00_get_field32(word1, RXD_W1_RSSI);
- ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
/*
- * Trim the skb_buffer to only contain the valid
- * frame data (so ignore the device's descriptor).
+ * rt2570 includes the FCS, so fix data length accordingly.
*/
- skb_trim(entry->skb, size);
-
- /*
- * Send the packet to upper layer, and update urb.
- */
- rt2x00lib_rxdone(entry, NULL, ring->data_size + ring->desc_size,
- signal, rssi, ofdm);
- urb->transfer_buffer = entry->skb->data;
- urb->transfer_buffer_length = entry->skb->len;
-
-skip_entry:
- if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
- __set_bit(ENTRY_OWNER_NIC, &entry->flags);
- usb_submit_urb(urb, GFP_ATOMIC);
- }
-
- rt2x00_ring_index_inc(ring);
+ return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT) - FCS_LEN;
}
/*
@@ -1217,6 +1142,7 @@ skip_entry:
static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
{
u16 word;
+ u8 *mac;
/*
* Allocate the eeprom memory, check the eeprom width
@@ -1234,6 +1160,12 @@ static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Start validation of the data that has been read.
*/
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+ }
+
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1259,7 +1191,7 @@ static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
- MAX_RX_SSI);
+ DEFAULT_RSSI_OFFSET);
rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
}
@@ -1366,7 +1298,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Read the RSSI <-> dBm offset information.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
- rt2x00dev->hw->max_rssi =
+ rt2x00dev->rssi_offset =
rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
return 0;
@@ -1443,16 +1375,16 @@ static void rt2500usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_WEP_INCLUDE_IV |
IEEE80211_HW_DATA_NULLFUNC_ACK |
IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
- IEEE80211_HW_MONITOR_DURING_OPER;
+ IEEE80211_HW_MONITOR_DURING_OPER |
+ IEEE80211_HW_NO_PROBE_FILTERING;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->max_noise = MAX_RX_NOISE;
rt2x00dev->hw->queues = 2;
- /*
- * This device supports ATIM
- */
- __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
/*
* Set device specific, but channel independent RF values.
@@ -1475,7 +1407,6 @@ static void rt2500usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw_mode information.
*/
- spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
spec->num_modes = 2;
spec->num_rates = 12;
spec->num_channels = 14;
@@ -1522,6 +1453,11 @@ static int rt2500usb_init_hw(struct rt2x00_dev *rt2x00dev)
*/
rt2500usb_init_hw_mode(rt2x00dev);
+ /*
+ * This device supports ATIM
+ */
+ __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags);
+
return 0;
}
@@ -1551,8 +1487,6 @@ static int rt2500usb_get_stats(struct ieee80211_hw *hw,
static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.tx = rt2x00lib_tx,
.reset = rt2x00lib_reset,
- .open = rt2x00lib_open,
- .stop = rt2x00lib_stop,
.add_interface = rt2x00lib_add_interface,
.remove_interface = rt2x00lib_remove_interface,
.config = rt2x00lib_config,
@@ -1573,6 +1507,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.write_tx_desc = rt2500usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
.kick_tx_queue = rt2500usb_kick_tx_queue,
+ .fill_rxdone = rt2500usb_fill_rxdone,
.config_type = rt2500usb_config_type,
.config_phymode = rt2500usb_config_phymode,
.config_channel = rt2500usb_config_channel,
@@ -1665,14 +1600,11 @@ static struct usb_driver rt2500usb_driver = {
static int __init rt2500usb_init(void)
{
- printk(KERN_INFO "Loading module: %s - %s by %s.\n",
- DRV_NAME, DRV_VERSION, DRV_PROJECT);
return usb_register(&rt2500usb_driver);
}
static void __exit rt2500usb_exit(void)
{
- printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
usb_deregister(&rt2500usb_driver);
}
diff --git a/package/rt2x00/src/rt2500usb.h b/package/rt2x00/src/rt2500usb.h
index e756d6eb6e..814bd0452e 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 dbea6acf6a..33b5094358 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 111c51ea36..83d4f9904d 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 5751dd1f79..e69de29bb2 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 cb618700ab..e2239fab8d 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 8c8f5a3e82..f987bc91f7 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 448f1bcade..043af31561 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 3aef1073d0..4c1ce4cdb4 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 c9b5ee7bf1..461d13db0f 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 349353bee5..8835df2e2e 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 4156ea36a9..33c724d441 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 291d0c0266..8595cbff4e 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 63062f1ec4..c08a2aa0ea 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 6b193d023c..4175aeffe9 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 fe90dd214c..627754802d 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, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, 0x9eb39eb3);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, 0x8a8b8c8d);
@@ -1312,10 +1327,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-
rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
@@ -1432,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, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, !enabled);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, !enabled);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_BEACON_DONE, !enabled);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, !enabled);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, !enabled);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, !enabled);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, !enabled);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_3, !enabled);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_4, !enabled);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, !enabled);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, !enabled);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, !enabled);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+}
+
+static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
* Initialize all registers.
*/
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, &reg);
- rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
-
- rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
- rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
-
- /*
* Enable interrupts.
*/
- reg = 0;
- rt2x00_set_field32(&reg, INT_MASK_CSR_TX_ABORT_DONE, 1);
- rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
-
- rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0x00000000);
+ rt61pci_toggle_irq(rt2x00dev, 1);
/*
* Enable RX.
@@ -1508,11 +1543,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable interrupts.
*/
- reg = 0xffffffff;
- rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, 0);
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
-
- rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0xffffffff);
+ rt61pci_toggle_irq(rt2x00dev, 0);
}
static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1681,60 +1712,80 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
- * Interrupt functions.
+ * RX control handlers
*/
-static void rt61pci_rxdone(struct rt2x00_dev *rt2x00dev)
+static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
{
- struct data_ring *ring = rt2x00dev->rx;
- struct data_entry *entry;
- struct data_desc *rxd;
- u32 word0;
- u32 word1;
- int signal;
- int rssi;
- int ofdm;
- u16 size;
+ u16 eeprom;
+ char offset;
+ char lna;
- while (1) {
- entry = rt2x00_get_data_entry(ring);
- rxd = entry->priv;
- rt2x00_desc_read(rxd, 0, &word0);
- rt2x00_desc_read(rxd, 1, &word1);
+ lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+ switch (lna) {
+ case 3:
+ offset = 90;
+ break;
+ case 2:
+ offset = 74;
+ break;
+ case 1:
+ offset = 64;
+ break;
+ default:
+ return 0;
+ }
- if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
- break;
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ offset += 14;
- /*
- * TODO: Don't we need to keep statistics
- * updated about events like CRC and physical errors?
- */
- if (rt2x00_get_field32(word0, RXD_W0_CRC))
- goto skip_entry;
+ if (lna == 3 || lna == 2)
+ offset += 10;
- /*
- * Obtain the status about this packet.
- */
- size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- rssi = rt2x00_get_field32(word1, RXD_W1_RSSI);
- ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ } else {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ offset += 14;
- /*
- * Send the packet to upper layer.
- */
- rt2x00lib_rxdone(entry, entry->data_addr, size,
- signal, rssi, ofdm);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ }
-skip_entry:
- if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
- rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(rxd, 0, word0);
- }
+ return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
- rt2x00_ring_index_inc(ring);
- }
+static int rt61pci_fill_rxdone(struct data_entry *entry,
+ int *signal, int *rssi, int *ofdm)
+{
+ struct data_desc *rxd = entry->priv;
+ u32 word0;
+ u32 word1;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 1, &word1);
+
+ /*
+ * TODO: Don't we need to keep statistics
+ * updated about these errors?
+ */
+ if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
+ rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
+ return -EINVAL;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
+ *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+
+ return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
}
+/*
+ * Interrupt functions.
+ */
static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
{
struct data_ring *ring;
@@ -1840,7 +1891,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
* 2 - Rx ring done interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
- rt61pci_rxdone(rt2x00dev);
+ rt2x00pci_rxdone(rt2x00dev);
/*
* 3 - Tx ring done interrupt.
@@ -1859,6 +1910,8 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
struct eeprom_93cx6 eeprom;
u32 reg;
u16 word;
+ u8 *mac;
+ char value;
/*
* Allocate the eeprom memory, check the eeprom width
@@ -1886,6 +1939,12 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Start validation of the data that has been read.
*/
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+ }
+
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1927,6 +1986,38 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
}
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ }
+
return 0;
}
@@ -2086,12 +2177,17 @@ static void rt61pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_WEP_INCLUDE_IV |
IEEE80211_HW_DATA_NULLFUNC_ACK |
IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
- IEEE80211_HW_MONITOR_DURING_OPER;
+ IEEE80211_HW_MONITOR_DURING_OPER |
+ IEEE80211_HW_NO_PROBE_FILTERING;
rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->max_noise = MAX_RX_NOISE;
rt2x00dev->hw->queues = 5;
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
+
/*
* Convert tx_power array in eeprom.
*/
@@ -2102,7 +2198,6 @@ static void rt61pci_init_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw_mode information.
*/
- spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
spec->num_modes = 2;
spec->num_rates = 12;
spec->num_channels = 14;
@@ -2150,10 +2245,15 @@ static int rt61pci_init_hw(struct rt2x00_dev *rt2x00dev)
rt61pci_init_hw_mode(rt2x00dev);
/*
- * rt61pci requires firmware
+ * This device requires firmware
*/
__set_bit(FIRMWARE_REQUIRED, &rt2x00dev->flags);
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
return 0;
}
@@ -2219,8 +2319,6 @@ static void rt61pci_reset_tsf(struct ieee80211_hw *hw)
static const struct ieee80211_ops rt61pci_mac80211_ops = {
.tx = rt2x00lib_tx,
.reset = rt2x00lib_reset,
- .open = rt2x00lib_open,
- .stop = rt2x00lib_stop,
.add_interface = rt2x00lib_add_interface,
.remove_interface = rt2x00lib_remove_interface,
.config = rt2x00lib_config,
@@ -2250,6 +2348,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.write_tx_desc = rt61pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt61pci_kick_tx_queue,
+ .fill_rxdone = rt61pci_fill_rxdone,
.config_type = rt61pci_config_type,
.config_phymode = rt61pci_config_phymode,
.config_channel = rt61pci_config_channel,
@@ -2309,14 +2408,11 @@ static struct pci_driver rt61pci_driver = {
static int __init rt61pci_init(void)
{
- printk(KERN_INFO "Loading module: %s - %s by %s.\n",
- DRV_NAME, DRV_VERSION, DRV_PROJECT);
return pci_register_driver(&rt61pci_driver);
}
static void __exit rt61pci_exit(void)
{
- printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
pci_unregister_driver(&rt61pci_driver);
}
diff --git a/package/rt2x00/src/rt61pci.h b/package/rt2x00/src/rt61pci.h
index 68347324c9..9dfd29356e 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 04261faa3b..c80bee1e5b 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, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
rt73usb_register_write(rt2x00dev, TXRX_CSR1, 0x9eaa9eaf);
rt73usb_register_write(rt2x00dev, TXRX_CSR2, 0x8a8b8c8d);
@@ -1049,10 +1019,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-
/*
* We must clear the error counters.
* These registers are cleared on read,
@@ -1164,8 +1130,7 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all registers.
*/
- if (rt73usb_init_rings(rt2x00dev) ||
- rt73usb_init_registers(rt2x00dev) ||
+ if (rt73usb_init_registers(rt2x00dev) ||
rt73usb_init_bbp(rt2x00dev)) {
ERROR(rt2x00dev, "Register initialization failed.\n");
return -EIO;
@@ -1344,74 +1309,84 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
- * Interrupt functions.
+ * RX control handlers
*/
-static void rt73usb_interrupt_rxdone(struct urb *urb)
+static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+ u16 eeprom;
+ char offset;
+ char lna;
+
+ lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+ switch (lna) {
+ case 3:
+ offset = 90;
+ break;
+ case 2:
+ offset = 74;
+ break;
+ case 1:
+ offset = 64;
+ break;
+ default:
+ return 0;
+ }
+
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (test_bit(CONFIG_EXTERNAL_LNA, &rt2x00dev->flags)) {
+ if (lna == 3 || lna == 2)
+ offset += 10;
+ } else {
+ if (lna == 3)
+ offset += 6;
+ else if (lna == 2)
+ offset += 8;
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ } else {
+ if (test_bit(CONFIG_EXTERNAL_LNA, &rt2x00dev->flags))
+ offset += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ }
+
+ return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static int rt73usb_fill_rxdone(struct data_entry *entry,
+ int *signal, int *rssi, int *ofdm)
{
- struct data_entry *entry = (struct data_entry*)urb->context;
- struct data_ring *ring = entry->ring;
- struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
struct data_desc *rxd = (struct data_desc*)entry->skb->data;
u32 word0;
u32 word1;
- int signal;
- int rssi;
- int ofdm;
- u16 size;
-
- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
- return;
-
- /*
- * Check if the received data is simply too small
- * to be actually valid, or if the urb is signaling
- * a problem.
- */
- if (urb->actual_length < entry->ring->desc_size || urb->status)
- goto skip_entry;
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
/*
* TODO: Don't we need to keep statistics
- * updated about events like CRC and physical errors?
+ * updated about these errors?
*/
if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
- goto skip_entry;
+ return -EINVAL;
/*
* Obtain the status about this packet.
*/
- size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- rssi = rt2x00_get_field32(word1, RXD_W1_RSSI);
- ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
+ *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
/*
- * Trim the skb_buffer to only contain the valid
- * frame data (so ignore the device's descriptor).
+ * Pull the skb to clear the descriptor area.
*/
- skb_pull(entry->skb, ring->desc_size);
- skb_trim(entry->skb, size);
+ skb_pull(entry->skb, entry->ring->desc_size);
- /*
- * Send the packet to upper layer, and update urb.
- */
- rt2x00lib_rxdone(entry, NULL, ring->data_size + ring->desc_size,
- signal, rssi, ofdm);
- urb->transfer_buffer = entry->skb->data;
- urb->transfer_buffer_length = entry->skb->len;
-
-skip_entry:
- if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
- __set_bit(ENTRY_OWNER_NIC, &entry->flags);
- usb_submit_urb(urb, GFP_ATOMIC);
- }
-
- rt2x00_ring_index_inc(ring);
+ return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
}
/*
@@ -1420,6 +1395,8 @@ skip_entry:
static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
{
u16 word;
+ u8 *mac;
+ char value;
/*
* Allocate the eeprom memory, check the eeprom width
@@ -1437,6 +1414,12 @@ static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Start validation of the data that has been read.
*/
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac));
+ }
+
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -1481,6 +1464,38 @@ static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev)
EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
}
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ }
+
return 0;
}
@@ -1612,12 +1627,17 @@ static void rt73usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_WEP_INCLUDE_IV |
IEEE80211_HW_DATA_NULLFUNC_ACK |
IEEE80211_HW_NO_TKIP_WMM_HWACCEL |
- IEEE80211_HW_MONITOR_DURING_OPER;
+ IEEE80211_HW_MONITOR_DURING_OPER |
+ IEEE80211_HW_NO_PROBE_FILTERING;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->max_noise = MAX_RX_NOISE;
rt2x00dev->hw->queues = 5;
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0));
+
/*
* Set device specific, but channel independent RF values.
*/
@@ -1638,7 +1658,6 @@ static void rt73usb_init_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw_mode information.
*/
- spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
spec->num_modes = 2;
spec->num_rates = 12;
spec->num_channels = 14;
@@ -1683,10 +1702,15 @@ static int rt73usb_init_hw(struct rt2x00_dev *rt2x00dev)
rt73usb_init_hw_mode(rt2x00dev);
/*
- * rt73usb requires firmware
+ * This device requires firmware
*/
__set_bit(FIRMWARE_REQUIRED, &rt2x00dev->flags);
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
return 0;
}
@@ -1752,8 +1776,6 @@ static void rt73usb_reset_tsf(struct ieee80211_hw *hw)
static const struct ieee80211_ops rt73usb_mac80211_ops = {
.tx = rt2x00lib_tx,
.reset = rt2x00lib_reset,
- .open = rt2x00lib_open,
- .stop = rt2x00lib_stop,
.add_interface = rt2x00lib_add_interface,
.remove_interface = rt2x00lib_remove_interface,
.config = rt2x00lib_config,
@@ -1779,6 +1801,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.write_tx_desc = rt73usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
.kick_tx_queue = rt73usb_kick_tx_queue,
+ .fill_rxdone = rt73usb_fill_rxdone,
.config_type = rt73usb_config_type,
.config_phymode = rt73usb_config_phymode,
.config_channel = rt73usb_config_channel,
@@ -1881,14 +1904,11 @@ static struct usb_driver rt73usb_driver = {
static int __init rt73usb_init(void)
{
- printk(KERN_INFO "Loading module: %s - %s by %s.\n",
- DRV_NAME, DRV_VERSION, DRV_PROJECT);
return usb_register(&rt73usb_driver);
}
static void __exit rt73usb_exit(void)
{
- printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME);
usb_deregister(&rt73usb_driver);
}
diff --git a/package/rt2x00/src/rt73usb.h b/package/rt2x00/src/rt73usb.h
index 7796656982..159240f1cb 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 */