diff options
Diffstat (limited to 'package/rt2x00/src')
28 files changed, 2063 insertions, 847 deletions
diff --git a/package/rt2x00/src/COPYING b/package/rt2x00/src/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /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 0ed8321..84352c3 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 0000000..7f3f448 --- /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 0000000..81b88d2 --- /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 0000000..8a09911 --- /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 aaed3b4..824c823 100644 --- a/package/rt2x00/src/rt2400pci.c +++ b/package/rt2x00/src/rt2400pci.c @@ -42,6 +42,7 @@ #include <asm/io.h> #include "rt2x00.h" +#include "rt2x00lib.h" #include "rt2x00pci.h" #include "rt2400pci.h" @@ -614,7 +615,7 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev) /* * Link tuning */ -static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) +static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) { u8 reg; char false_cca_delta; @@ -623,7 +624,7 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) * The link tuner should not run longer then 60 seconds, * and should run once every 2 seconds. */ - if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count % 1)) + if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1)) return; /* @@ -649,6 +650,7 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) reg += 2; if (reg < 0x20) rt2400pci_bbp_write(rt2x00dev, 13, reg); + rt2x00dev->rx_status.noise = reg; } } @@ -926,11 +928,35 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); } -static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) +static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled) { u32 reg; /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (enabled) { + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, !enabled); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, !enabled); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, !enabled); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, !enabled); + rt2x00_set_field32(®, CSR8_RXDONE, !enabled); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* * Initialize all registers. */ if (rt2400pci_init_rings(rt2x00dev) || @@ -941,21 +967,9 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) } /* - * Clear interrupts. - */ - rt2x00pci_register_read(rt2x00dev, CSR7, ®); - rt2x00pci_register_write(rt2x00dev, CSR7, reg); - - /* * Enable interrupts. */ - rt2x00pci_register_read(rt2x00dev, CSR8, ®); - rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 0); - rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); - rt2x00_set_field32(®, CSR8_RXDONE, 0); - rt2x00pci_register_write(rt2x00dev, CSR8, reg); + rt2400pci_toggle_irq(rt2x00dev, 1); /* * Enable LED @@ -991,13 +1005,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Disable interrupts. */ - rt2x00pci_register_read(rt2x00dev, CSR8, ®); - rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 1); - rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 1); - rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 1); - rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 1); - rt2x00_set_field32(®, CSR8_RXDONE, 1); - rt2x00pci_register_write(rt2x00dev, CSR8, reg); + rt2400pci_toggle_irq(rt2x00dev, 0); } static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, @@ -1163,59 +1171,40 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue) } /* - * Interrupt functions. + * RX control handlers */ -static void rt2400pci_rxdone(struct rt2x00_dev *rt2x00dev) +static int rt2400pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm) { - struct data_ring *ring = rt2x00dev->rx; - struct data_entry *entry; - struct data_desc *rxd; + struct data_desc *rxd = entry->priv; u32 word0; u32 word2; - int signal; - int rssi; - u16 size; - - while (1) { - entry = rt2x00_get_data_entry(ring); - rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 2, &word2); - - if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC)) - break; - - /* - * TODO: Don't we need to keep statistics - * updated about events like CRC and physical errors? - */ - if (rt2x00_get_field32(word0, RXD_W0_CRC) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - goto skip_entry; - /* - * Obtain the status about this packet. - */ - size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - rssi = rt2x00_get_field32(word2, RXD_W2_RSSI); + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 2, &word2); - /* - * Send the packet to upper layer. - */ - rt2x00lib_rxdone(entry, entry->data_addr, size, - signal, rssi, 0); + /* + * TODO: Don't we need to keep statistics + * updated about these errors? + */ + if (rt2x00_get_field32(word0, RXD_W0_CRC) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + return -EINVAL; -skip_entry: - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word0); - } + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = 0; - rt2x00_ring_index_inc(ring); - } + return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } +/* + * Interrupt functions. + */ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) { struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue); @@ -1296,7 +1285,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) * 2 - Rx ring done interrupt. */ if (rt2x00_get_field32(reg, CSR7_RXDONE)) - rt2400pci_rxdone(rt2x00dev); + rt2x00pci_rxdone(rt2x00dev); /* * 3 - Atim ring transmit done interrupt. @@ -1327,6 +1316,7 @@ static int rt2400pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; u16 word; + u8 *mac; /* * Allocate the eeprom memory, check the eeprom width @@ -1354,6 +1344,12 @@ static int rt2400pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) /* * Start validation of the data that has been read. */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { ERROR(rt2x00dev, "Invalid EEPROM data detected.\n"); @@ -1440,16 +1436,16 @@ static void rt2400pci_init_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_WEP_INCLUDE_IV | IEEE80211_HW_DATA_NULLFUNC_ACK | IEEE80211_HW_NO_TKIP_WMM_HWACCEL | - IEEE80211_HW_MONITOR_DURING_OPER; + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->max_noise = MAX_RX_NOISE; rt2x00dev->hw->queues = 2; - /* - * This device supports ATIM - */ - __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags); + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); /* * Set device specific, but channel independent RF values. @@ -1470,7 +1466,6 @@ static void rt2400pci_init_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); spec->num_modes = 1; spec->num_rates = 4; spec->num_channels = 14; @@ -1501,6 +1496,16 @@ static int rt2400pci_init_hw(struct rt2x00_dev *rt2x00dev) */ rt2400pci_init_hw_mode(rt2x00dev); + /* + * This device supports ATIM + */ + __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + return 0; } @@ -1599,8 +1604,6 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2400pci_mac80211_ops = { .tx = rt2x00lib_tx, .reset = rt2x00lib_reset, - .open = rt2x00lib_open, - .stop = rt2x00lib_stop, .add_interface = rt2x00lib_add_interface, .remove_interface = rt2x00lib_remove_interface, .config = rt2x00lib_config, @@ -1629,6 +1632,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .write_tx_desc = rt2400pci_write_tx_desc, .write_tx_data = rt2x00pci_write_tx_data, .kick_tx_queue = rt2400pci_kick_tx_queue, + .fill_rxdone = rt2400pci_fill_rxdone, .config_type = rt2400pci_config_type, .config_phymode = rt2400pci_config_phymode, .config_channel = rt2400pci_config_channel, @@ -1679,14 +1683,11 @@ static struct pci_driver rt2400pci_driver = { static int __init rt2400pci_init(void) { - printk(KERN_INFO "Loading module: %s - %s by %s.\n", - DRV_NAME, DRV_VERSION, DRV_PROJECT); return pci_register_driver(&rt2400pci_driver); } static void __exit rt2400pci_exit(void) { - printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME); pci_unregister_driver(&rt2400pci_driver); } diff --git a/package/rt2x00/src/rt2400pci.h b/package/rt2x00/src/rt2400pci.h index 097f4c9..10fe488 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 61d7e74..d71e3c3 100644 --- a/package/rt2x00/src/rt2500pci.c +++ b/package/rt2x00/src/rt2500pci.c @@ -42,6 +42,7 @@ #include <asm/io.h> #include "rt2x00.h" +#include "rt2x00lib.h" #include "rt2x00pci.h" #include "rt2500pci.h" @@ -368,6 +369,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, u32 rf2 = value; u32 rf3 = rt2x00dev->rf3; u32 rf4 = rt2x00dev->rf4; + u8 r70; if (rt2x00_rf(&rt2x00dev->chip, RF2525) || rt2x00_rf(&rt2x00dev->chip, RF2525E)) @@ -435,7 +437,9 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * Channel 14 requires the Japan filter bit to be set. */ - rt2500pci_bbp_write(rt2x00dev, 70, (channel == 14) ? 0x4e : 0x46); + r70 = 0x46; + rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, channel == 14); + rt2500pci_bbp_write(rt2x00dev, 70, r70); msleep(1); @@ -692,8 +696,9 @@ static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev) /* * Link tuning */ -static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) +static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) { + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); u32 reg; u8 r17; @@ -722,7 +727,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) */ if (rssi < -80 && rt2x00dev->link.count > 20) { if (r17 >= 0x41) { - r17 = rt2x00dev->link.curr_noise; + r17 = rt2x00dev->rx_status.noise; rt2500pci_bbp_write(rt2x00dev, 17, r17); } return; @@ -751,7 +756,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) * to the dynamic tuning range. */ if (r17 >= 0x41) { - rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.curr_noise); + rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->rx_status.noise); return; } @@ -766,10 +771,10 @@ dynamic_cca_tune: if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) { rt2500pci_bbp_write(rt2x00dev, 17, ++r17); - rt2x00dev->link.curr_noise = r17; + rt2x00dev->rx_status.noise = r17; } else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) { rt2500pci_bbp_write(rt2x00dev, 17, --r17); - rt2x00dev->link.curr_noise = r17; + rt2x00dev->rx_status.noise = r17; } } @@ -898,7 +903,16 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) return -EBUSY; rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100); - rt2x00pci_register_write(rt2x00dev, PCICSR, 0x000003b8); + + rt2x00pci_register_read(rt2x00dev, PCICSR, ®); + rt2x00_set_field32(®, PCICSR_BIG_ENDIAN, 0); + rt2x00_set_field32(®, PCICSR_RX_TRESHOLD, 0); + rt2x00_set_field32(®, PCICSR_TX_TRESHOLD, 3); + rt2x00_set_field32(®, PCICSR_BURST_LENTH, 1); + rt2x00_set_field32(®, PCICSR_ENABLE_CLK, 1); + rt2x00_set_field32(®, PCICSR_READ_MULTIPLE, 1); + rt2x00_set_field32(®, PCICSR_WRITE_INVALID, 1); + rt2x00pci_register_write(rt2x00dev, PCICSR, reg); rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002); rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002); @@ -1079,11 +1093,35 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); } -static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) +static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled) { u32 reg; /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (enabled) { + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, !enabled); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, !enabled); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, !enabled); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, !enabled); + rt2x00_set_field32(®, CSR8_RXDONE, !enabled); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* * Initialize all registers. */ if (rt2500pci_init_rings(rt2x00dev) || @@ -1094,21 +1132,9 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) } /* - * Clear interrupts. - */ - rt2x00pci_register_read(rt2x00dev, CSR7, ®); - rt2x00pci_register_write(rt2x00dev, CSR7, reg); - - /* * Enable interrupts. */ - rt2x00pci_register_read(rt2x00dev, CSR8, ®); - rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 0); - rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); - rt2x00_set_field32(®, CSR8_RXDONE, 0); - rt2x00pci_register_write(rt2x00dev, CSR8, reg); + rt2500pci_toggle_irq(rt2x00dev, 1); /* * Enable LED @@ -1144,13 +1170,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Disable interrupts. */ - rt2x00pci_register_read(rt2x00dev, CSR8, ®); - rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, 1); - rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 1); - rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 1); - rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 1); - rt2x00_set_field32(®, CSR8_RXDONE, 1); - rt2x00pci_register_write(rt2x00dev, CSR8, reg); + rt2500pci_toggle_irq(rt2x00dev, 0); } static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, @@ -1300,61 +1320,37 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue) } /* - * Interrupt functions. + * RX control handlers */ -static void rt2500pci_rxdone(struct rt2x00_dev *rt2x00dev) +static int rt2500pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm) { - struct data_ring *ring = rt2x00dev->rx; - struct data_entry *entry; - struct data_desc *rxd; + struct data_desc *rxd = entry->priv; u32 word0; u32 word2; - int signal; - int rssi; - int ofdm; - u16 size; - - while (1) { - entry = rt2x00_get_data_entry(ring); - rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 2, &word2); - - if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC)) - break; - /* - * TODO: Don't we need to keep statistics - * updated about events like CRC and physical errors? - */ - if (rt2x00_get_field32(word0, RXD_W0_CRC) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - goto skip_entry; + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 2, &word2); - /* - * Obtain the status about this packet. - */ - size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - rssi = rt2x00_get_field32(word2, RXD_W2_RSSI); - ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - - /* - * Send the packet to upper layer. - */ - rt2x00lib_rxdone(entry, entry->data_addr, size, - signal, rssi, ofdm); + /* + * TODO: Don't we need to keep statistics + * updated about these errors? + */ + if (rt2x00_get_field32(word0, RXD_W0_CRC) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + return -EINVAL; -skip_entry: - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word0); - } + *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - rt2x00_ring_index_inc(ring); - } + return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } +/* + * Interrupt functions. + */ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) { struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue); @@ -1435,7 +1431,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) * 2 - Rx ring done interrupt. */ if (rt2x00_get_field32(reg, CSR7_RXDONE)) - rt2500pci_rxdone(rt2x00dev); + rt2x00pci_rxdone(rt2x00dev); /* * 3 - Atim ring transmit done interrupt. @@ -1466,6 +1462,7 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; u16 word; + u8 *mac; /* * Allocate the eeprom memory, check the eeprom width @@ -1493,6 +1490,12 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) /* * Start validation of the data that has been read. */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); @@ -1518,7 +1521,7 @@ static int rt2500pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, - MAX_RX_SSI); + DEFAULT_RSSI_OFFSET); rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word); EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word); } @@ -1586,7 +1589,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Read the RSSI <-> dBm offset information. */ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); - rt2x00dev->hw->max_rssi = + rt2x00dev->rssi_offset = rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); return 0; @@ -1660,16 +1663,16 @@ static void rt2500pci_init_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_WEP_INCLUDE_IV | IEEE80211_HW_DATA_NULLFUNC_ACK | IEEE80211_HW_NO_TKIP_WMM_HWACCEL | - IEEE80211_HW_MONITOR_DURING_OPER; + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->max_noise = MAX_RX_NOISE; rt2x00dev->hw->queues = 2; - /* - * This device supports ATIM - */ - __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags); + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); /* * Set device specific, but channel independent RF values. @@ -1692,7 +1695,6 @@ static void rt2500pci_init_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); spec->num_modes = 2; spec->num_rates = 12; spec->num_channels = 14; @@ -1738,6 +1740,11 @@ static int rt2500pci_init_hw(struct rt2x00_dev *rt2x00dev) */ rt2500pci_init_hw_mode(rt2x00dev); + /* + * This device supports ATIM + */ + __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags); + return 0; } @@ -1812,8 +1819,6 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2500pci_mac80211_ops = { .tx = rt2x00lib_tx, .reset = rt2x00lib_reset, - .open = rt2x00lib_open, - .stop = rt2x00lib_stop, .add_interface = rt2x00lib_add_interface, .remove_interface = rt2x00lib_remove_interface, .config = rt2x00lib_config, @@ -1842,6 +1847,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .write_tx_desc = rt2500pci_write_tx_desc, .write_tx_data = rt2x00pci_write_tx_data, .kick_tx_queue = rt2500pci_kick_tx_queue, + .fill_rxdone = rt2500pci_fill_rxdone, .config_type = rt2500pci_config_type, .config_phymode = rt2500pci_config_phymode, .config_channel = rt2500pci_config_channel, @@ -1892,14 +1898,11 @@ static struct pci_driver rt2500pci_driver = { static int __init rt2500pci_init(void) { - printk(KERN_INFO "Loading module: %s - %s by %s.\n", - DRV_NAME, DRV_VERSION, DRV_PROJECT); return pci_register_driver(&rt2500pci_driver); } static void __exit rt2500pci_exit(void) { - printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME); pci_unregister_driver(&rt2500pci_driver); } diff --git a/package/rt2x00/src/rt2500pci.h b/package/rt2x00/src/rt2500pci.h index e695a57..c70bcb7 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 c5459b5..3be51f0 100644 --- a/package/rt2x00/src/rt2500usb.c +++ b/package/rt2x00/src/rt2500usb.c @@ -38,6 +38,7 @@ #include <linux/etherdevice.h> #include "rt2x00.h" +#include "rt2x00lib.h" #include "rt2x00usb.h" #include "rt2500usb.h" @@ -638,8 +639,9 @@ static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev) /* * Link tuning */ -static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) +static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) { + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); u16 bbp_thresh; u16 cca_alarm; u16 vgc_bound; @@ -734,62 +736,19 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) if (r17 > up_bound) { rt2500usb_bbp_write(rt2x00dev, 17, up_bound); - rt2x00dev->link.curr_noise = up_bound; + rt2x00dev->rx_status.noise = up_bound; } else if (cca_alarm > 512 && r17 < up_bound) { rt2500usb_bbp_write(rt2x00dev, 17, ++r17); - rt2x00dev->link.curr_noise = r17; + rt2x00dev->rx_status.noise = r17; } else if (cca_alarm < 100 && r17 > low_bound) { rt2500usb_bbp_write(rt2x00dev, 17, --r17); - rt2x00dev->link.curr_noise = r17; + rt2x00dev->rx_status.noise = r17; } } /* * Initialization functions. */ -static void rt2500usb_init_rxring(struct rt2x00_dev *rt2x00dev) -{ - struct usb_device *usb_dev = - interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - unsigned int i; - - for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { - usb_fill_bulk_urb( - rt2x00dev->rx->entry[i].priv, - usb_dev, - usb_rcvbulkpipe(usb_dev, 1), - rt2x00dev->rx->entry[i].skb->data, - rt2x00dev->rx->entry[i].skb->len, - rt2500usb_interrupt_rxdone, - &rt2x00dev->rx->entry[i]); - } - - rt2x00_ring_index_clear(rt2x00dev->rx); -} - -static void rt2500usb_init_txring(struct rt2x00_dev *rt2x00dev, - const int queue) -{ - struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue); - unsigned int i; - - for (i = 0; i < ring->stats.limit; i++) - ring->entry[i].flags = 0; - - rt2x00_ring_index_clear(ring); -} - -static int rt2500usb_init_rings(struct rt2x00_dev *rt2x00dev) -{ - rt2500usb_init_rxring(rt2x00dev); - rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); - rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); - rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); - rt2500usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); - - return 0; -} - static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) { u16 reg; @@ -801,7 +760,10 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) USB_VENDOR_REQUEST_OUT, 0x0308, 0xf0, NULL, 0, REGISTER_TIMEOUT); - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, 0x0001); + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); + rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111); rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11); @@ -819,9 +781,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2500usb_register_write(rt2x00dev, MAC_CSR1, 0x0004); - reg = 0; - rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); - if (reg >= 0x0003) { + if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); reg &= ~0x0002; } else { @@ -962,8 +922,7 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt2500usb_init_rings(rt2x00dev) || - rt2500usb_init_registers(rt2x00dev) || + if (rt2500usb_init_registers(rt2x00dev) || rt2500usb_init_bbp(rt2x00dev)) { ERROR(rt2x00dev, "Register initialization failed.\n"); return -EIO; @@ -1107,7 +1066,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_OFDM, test_bit(ENTRY_TXD_OFDM_RATE, &entry->flags)); rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, - test_bit(ENTRY_TXD_NEW_SEQ, &entry->flags)); + control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT); rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); @@ -1141,74 +1100,40 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue) } /* - * Interrupt functions. + * RX control handlers */ -static void rt2500usb_interrupt_rxdone(struct urb *urb) +static int rt2500usb_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm) { - struct data_entry *entry = (struct data_entry*)urb->context; - struct data_ring *ring = entry->ring; - struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; - struct data_desc *rxd = (struct data_desc*) - (entry->skb->data + urb->actual_length - ring->desc_size); + struct urb *urb = entry->priv; + struct data_desc *rxd = (struct data_desc*)(entry->skb->data + + (urb->actual_length - entry->ring->desc_size)); u32 word0; u32 word1; - int signal; - int rssi; - int ofdm; - u16 size; - - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) - return; - - /* - * Check if the received data is simply too small - * to be actually valid, or if the urb is signaling - * a problem. - */ - if (urb->actual_length < entry->ring->desc_size || urb->status) - goto skip_entry; rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); /* * TODO: Don't we need to keep statistics - * updated about events like CRC and physical errors? + * updated about these errors? */ if (rt2x00_get_field32(word0, RXD_W0_CRC) || rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - goto skip_entry; + return -EINVAL; /* * Obtain the status about this packet. */ - size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT) - FCS_LEN; - signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rssi = rt2x00_get_field32(word1, RXD_W1_RSSI); - ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); /* - * Trim the skb_buffer to only contain the valid - * frame data (so ignore the device's descriptor). + * rt2570 includes the FCS, so fix data length accordingly. */ - skb_trim(entry->skb, size); - - /* - * Send the packet to upper layer, and update urb. - */ - rt2x00lib_rxdone(entry, NULL, ring->data_size + ring->desc_size, - signal, rssi, ofdm); - urb->transfer_buffer = entry->skb->data; - urb->transfer_buffer_length = entry->skb->len; - -skip_entry: - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_submit_urb(urb, GFP_ATOMIC); - } - - rt2x00_ring_index_inc(ring); + return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT) - FCS_LEN; } /* @@ -1217,6 +1142,7 @@ skip_entry: static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev) { u16 word; + u8 *mac; /* * Allocate the eeprom memory, check the eeprom width @@ -1234,6 +1160,12 @@ static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev) /* * Start validation of the data that has been read. */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); @@ -1259,7 +1191,7 @@ static int rt2500usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, - MAX_RX_SSI); + DEFAULT_RSSI_OFFSET); rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word); EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word); } @@ -1366,7 +1298,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Read the RSSI <-> dBm offset information. */ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); - rt2x00dev->hw->max_rssi = + rt2x00dev->rssi_offset = rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); return 0; @@ -1443,16 +1375,16 @@ static void rt2500usb_init_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_WEP_INCLUDE_IV | IEEE80211_HW_DATA_NULLFUNC_ACK | IEEE80211_HW_NO_TKIP_WMM_HWACCEL | - IEEE80211_HW_MONITOR_DURING_OPER; + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->max_noise = MAX_RX_NOISE; rt2x00dev->hw->queues = 2; - /* - * This device supports ATIM - */ - __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags); + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); /* * Set device specific, but channel independent RF values. @@ -1475,7 +1407,6 @@ static void rt2500usb_init_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); spec->num_modes = 2; spec->num_rates = 12; spec->num_channels = 14; @@ -1522,6 +1453,11 @@ static int rt2500usb_init_hw(struct rt2x00_dev *rt2x00dev) */ rt2500usb_init_hw_mode(rt2x00dev); + /* + * This device supports ATIM + */ + __set_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags); + return 0; } @@ -1551,8 +1487,6 @@ static int rt2500usb_get_stats(struct ieee80211_hw *hw, static const struct ieee80211_ops rt2500usb_mac80211_ops = { .tx = rt2x00lib_tx, .reset = rt2x00lib_reset, - .open = rt2x00lib_open, - .stop = rt2x00lib_stop, .add_interface = rt2x00lib_add_interface, .remove_interface = rt2x00lib_remove_interface, .config = rt2x00lib_config, @@ -1573,6 +1507,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .write_tx_desc = rt2500usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, .kick_tx_queue = rt2500usb_kick_tx_queue, + .fill_rxdone = rt2500usb_fill_rxdone, .config_type = rt2500usb_config_type, .config_phymode = rt2500usb_config_phymode, .config_channel = rt2500usb_config_channel, @@ -1665,14 +1600,11 @@ static struct usb_driver rt2500usb_driver = { static int __init rt2500usb_init(void) { - printk(KERN_INFO "Loading module: %s - %s by %s.\n", - DRV_NAME, DRV_VERSION, DRV_PROJECT); return usb_register(&rt2500usb_driver); } static void __exit rt2500usb_exit(void) { - printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME); usb_deregister(&rt2500usb_driver); } diff --git a/package/rt2x00/src/rt2500usb.h b/package/rt2x00/src/rt2500usb.h index e756d6e..814bd0452 100644 --- a/package/rt2x00/src/rt2500usb.h +++ b/package/rt2x00/src/rt2500usb.h @@ -38,10 +38,18 @@ #define RF5222 0x0010 /* - * Max RSSI value, required for RSSI <-> dBm conversion. + * RT2570 version */ -#define MAX_RX_SSI 120 +#define RT2570_VERSION_B 2 +#define RT2570_VERSION_C 3 +#define RT2570_VERSION_D 4 + +/* + * Signal information. + */ +#define MAX_RX_SSI -1 #define MAX_RX_NOISE -110 +#define DEFAULT_RSSI_OFFSET 120 /* * Register layout information. @@ -729,9 +737,4 @@ (__txpower)); \ }) -/* - * Interrupt functions. - */ -static void rt2500usb_interrupt_rxdone(struct urb *urb); - #endif /* RT2500USB_H */ diff --git a/package/rt2x00/src/rt2x00.h b/package/rt2x00/src/rt2x00.h index dbea6ac..33b5094 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 111c51e..83d4f99 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 5751dd1..e69de29 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 cb61870..e2239fa 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 8c8f5a3..f987bc9 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 448f1bc..043af31 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 3aef107..4c1ce4c 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 c9b5ee7..461d13d 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 349353b..8835df2 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 4156ea3..33c724d 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 291d0c0..8595cbf 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 63062f1..c08a2aa 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 6b193d0..4175aef 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 fe90dd2..6277548 100644 --- a/package/rt2x00/src/rt61pci.c +++ b/package/rt2x00/src/rt61pci.c @@ -42,6 +42,7 @@ #include <asm/io.h> #include "rt2x00.h" +#include "rt2x00lib.h" #include "rt2x00pci.h" #include "rt61pci.h" @@ -891,13 +892,19 @@ static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev) rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); } -static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, char rssi) +static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) { u8 led; if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) return; + /* + * Led handling requires a positive value for the rssi, + * to do that correctly we need to add the correction. + */ + rssi += rt2x00dev->rssi_offset; + if (rssi <= 30) led = 0; else if (rssi <= 39) @@ -917,8 +924,9 @@ static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, char rssi) /* * Link tuning */ -static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) +static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) { + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); u32 reg; u8 r17; u8 up_bound; @@ -1013,10 +1021,12 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) if (++r17 > up_bound) r17 = up_bound; rt61pci_bbp_write(rt2x00dev, 17, r17); + rt2x00dev->rx_status.noise = r17; } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { if (--r17 < low_bound) r17 = low_bound; rt61pci_bbp_write(rt2x00dev, 17, r17); + rt2x00dev->rx_status.noise = r17; } } @@ -1279,7 +1289,12 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00000718); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, 0x025eb032); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, 0x9eb39eb3); rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, 0x8a8b8c8d); @@ -1312,10 +1327,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); - rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0); rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c); rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606); @@ -1432,11 +1443,49 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); } -static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) +static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled) { u32 reg; /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (enabled) { + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, !enabled); + rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, !enabled); + rt2x00_set_field32(®, INT_MASK_CSR_BEACON_DONE, !enabled); + rt2x00_set_field32(®, INT_MASK_CSR_ENABLE_MITIGATION, !enabled); + rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, !enabled); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, !enabled); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, !enabled); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_3, !enabled); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_4, !enabled); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_5, !enabled); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_6, !enabled); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, !enabled); + rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); +} + +static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* * Initialize all registers. */ if (rt61pci_init_rings(rt2x00dev) || @@ -1447,23 +1496,9 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) } /* - * Clear interrupts. - */ - rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); - rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); - - rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); - rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); - - /* * Enable interrupts. */ - reg = 0; - rt2x00_set_field32(®, INT_MASK_CSR_TX_ABORT_DONE, 1); - rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); - rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); - - rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0x00000000); + rt61pci_toggle_irq(rt2x00dev, 1); /* * Enable RX. @@ -1508,11 +1543,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Disable interrupts. */ - reg = 0xffffffff; - rt2x00_set_field32(®, INT_MASK_CSR_ENABLE_MITIGATION, 0); - rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); - - rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0xffffffff); + rt61pci_toggle_irq(rt2x00dev, 0); } static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, @@ -1681,60 +1712,80 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue) } /* - * Interrupt functions. + * RX control handlers */ -static void rt61pci_rxdone(struct rt2x00_dev *rt2x00dev) +static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) { - struct data_ring *ring = rt2x00dev->rx; - struct data_entry *entry; - struct data_desc *rxd; - u32 word0; - u32 word1; - int signal; - int rssi; - int ofdm; - u16 size; + u16 eeprom; + char offset; + char lna; - while (1) { - entry = rt2x00_get_data_entry(ring); - rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 1, &word1); + lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); + switch (lna) { + case 3: + offset = 90; + break; + case 2: + offset = 74; + break; + case 1: + offset = 64; + break; + default: + return 0; + } - if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC)) - break; + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + offset += 14; - /* - * TODO: Don't we need to keep statistics - * updated about events like CRC and physical errors? - */ - if (rt2x00_get_field32(word0, RXD_W0_CRC)) - goto skip_entry; + if (lna == 3 || lna == 2) + offset += 10; - /* - * Obtain the status about this packet. - */ - size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rssi = rt2x00_get_field32(word1, RXD_W1_RSSI); - ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + offset += 14; - /* - * Send the packet to upper layer. - */ - rt2x00lib_rxdone(entry, entry->data_addr, size, - signal, rssi, ofdm); + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } -skip_entry: - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - rt2x00_set_field32(&word0, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word0); - } + return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; +} - rt2x00_ring_index_inc(ring); - } +static int rt61pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm) +{ + struct data_desc *rxd = entry->priv; + u32 word0; + u32 word1; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 1, &word1); + + /* + * TODO: Don't we need to keep statistics + * updated about these errors? + */ + if (rt2x00_get_field32(word0, RXD_W0_CRC) || + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + + return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } +/* + * Interrupt functions. + */ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_ring *ring; @@ -1840,7 +1891,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) * 2 - Rx ring done interrupt. */ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) - rt61pci_rxdone(rt2x00dev); + rt2x00pci_rxdone(rt2x00dev); /* * 3 - Tx ring done interrupt. @@ -1859,6 +1910,8 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; u16 word; + u8 *mac; + char value; /* * Allocate the eeprom memory, check the eeprom width @@ -1886,6 +1939,12 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) /* * Start validation of the data that has been read. */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); @@ -1927,6 +1986,38 @@ static int rt61pci_alloc_eeprom(struct rt2x00_dev *rt2x00dev) EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); } + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + } + return 0; } @@ -2086,12 +2177,17 @@ static void rt61pci_init_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_WEP_INCLUDE_IV | IEEE80211_HW_DATA_NULLFUNC_ACK | IEEE80211_HW_NO_TKIP_WMM_HWACCEL | - IEEE80211_HW_MONITOR_DURING_OPER; + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->max_noise = MAX_RX_NOISE; rt2x00dev->hw->queues = 5; + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); + /* * Convert tx_power array in eeprom. */ @@ -2102,7 +2198,6 @@ static void rt61pci_init_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); spec->num_modes = 2; spec->num_rates = 12; spec->num_channels = 14; @@ -2150,10 +2245,15 @@ static int rt61pci_init_hw(struct rt2x00_dev *rt2x00dev) rt61pci_init_hw_mode(rt2x00dev); /* - * rt61pci requires firmware + * This device requires firmware */ __set_bit(FIRMWARE_REQUIRED, &rt2x00dev->flags); + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + return 0; } @@ -2219,8 +2319,6 @@ static void rt61pci_reset_tsf(struct ieee80211_hw *hw) static const struct ieee80211_ops rt61pci_mac80211_ops = { .tx = rt2x00lib_tx, .reset = rt2x00lib_reset, - .open = rt2x00lib_open, - .stop = rt2x00lib_stop, .add_interface = rt2x00lib_add_interface, .remove_interface = rt2x00lib_remove_interface, .config = rt2x00lib_config, @@ -2250,6 +2348,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .write_tx_desc = rt61pci_write_tx_desc, .write_tx_data = rt2x00pci_write_tx_data, .kick_tx_queue = rt61pci_kick_tx_queue, + .fill_rxdone = rt61pci_fill_rxdone, .config_type = rt61pci_config_type, .config_phymode = rt61pci_config_phymode, .config_channel = rt61pci_config_channel, @@ -2309,14 +2408,11 @@ static struct pci_driver rt61pci_driver = { static int __init rt61pci_init(void) { - printk(KERN_INFO "Loading module: %s - %s by %s.\n", - DRV_NAME, DRV_VERSION, DRV_PROJECT); return pci_register_driver(&rt61pci_driver); } static void __exit rt61pci_exit(void) { - printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME); pci_unregister_driver(&rt61pci_driver); } diff --git a/package/rt2x00/src/rt61pci.h b/package/rt2x00/src/rt61pci.h index 6834732..9dfd293 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 04261fa..c80bee1 100644 --- a/package/rt2x00/src/rt73usb.c +++ b/package/rt2x00/src/rt73usb.c @@ -38,6 +38,7 @@ #include <linux/etherdevice.h> #include "rt2x00.h" +#include "rt2x00lib.h" #include "rt2x00usb.h" #include "rt73usb.h" @@ -745,13 +746,19 @@ static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev) 0x00, rt2x00dev->led_reg, NULL, 0, REGISTER_TIMEOUT); } -static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, char rssi) +static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) { u32 led; if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) return; + /* + * Led handling requires a positive value for the rssi, + * to do that correctly we need to add the correction. + */ + rssi += rt2x00dev->rssi_offset; + if (rssi <= 30) led = 0; else if (rssi <= 39) @@ -773,8 +780,9 @@ static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, char rssi) /* * Link tuning */ -static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) +static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) { + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); u32 reg; u8 r17; u8 up_bound; @@ -880,11 +888,13 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi) if (r17 > up_bound) r17 = up_bound; rt73usb_bbp_write(rt2x00dev, 17, r17); + rt2x00dev->rx_status.noise = r17; } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { r17 -= 4; if (r17 < low_bound) r17 = low_bound; rt73usb_bbp_write(rt2x00dev, 17, r17); + rt2x00dev->rx_status.noise = r17; } } @@ -952,51 +962,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, return 0; } -static void rt73usb_init_rxring(struct rt2x00_dev *rt2x00dev) -{ - struct usb_device *usb_dev = - interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - unsigned int i; - - for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { - usb_fill_bulk_urb( - rt2x00dev->rx->entry[i].priv, - usb_dev, - usb_rcvbulkpipe(usb_dev, 1), - rt2x00dev->rx->entry[i].skb->data, - rt2x00dev->rx->entry[i].skb->len, - rt73usb_interrupt_rxdone, - &rt2x00dev->rx->entry[i]); - } - - rt2x00_ring_index_clear(rt2x00dev->rx); -} - -static void rt73usb_init_txring(struct rt2x00_dev *rt2x00dev, - const int queue) -{ - struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue); - unsigned int i; - - for (i = 0; i < ring->stats.limit; i++) - ring->entry[i].flags = 0; - - rt2x00_ring_index_clear(ring); -} - -static int rt73usb_init_rings(struct rt2x00_dev *rt2x00dev) -{ - rt73usb_init_rxring(rt2x00dev); - rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); - rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); - rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2); - rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3); - rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4); - rt73usb_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); - - return 0; -} - static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -1006,7 +971,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, 0x025eb032); + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt73usb_register_write(rt2x00dev, TXRX_CSR1, 0x9eaa9eaf); rt73usb_register_write(rt2x00dev, TXRX_CSR2, 0x8a8b8c8d); @@ -1049,10 +1019,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); - /* * We must clear the error counters. * These registers are cleared on read, @@ -1164,8 +1130,7 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt73usb_init_rings(rt2x00dev) || - rt73usb_init_registers(rt2x00dev) || + if (rt73usb_init_registers(rt2x00dev) || rt73usb_init_bbp(rt2x00dev)) { ERROR(rt2x00dev, "Register initialization failed.\n"); return -EIO; @@ -1344,74 +1309,84 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue) } /* - * Interrupt functions. + * RX control handlers */ -static void rt73usb_interrupt_rxdone(struct urb *urb) +static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) +{ + u16 eeprom; + char offset; + char lna; + + lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); + switch (lna) { + case 3: + offset = 90; + break; + case 2: + offset = 74; + break; + case 1: + offset = 64; + break; + default: + return 0; + } + + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (test_bit(CONFIG_EXTERNAL_LNA, &rt2x00dev->flags)) { + if (lna == 3 || lna == 2) + offset += 10; + } else { + if (lna == 3) + offset += 6; + else if (lna == 2) + offset += 8; + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA, &rt2x00dev->flags)) + offset += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } + + return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; +} + +static int rt73usb_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm) { - struct data_entry *entry = (struct data_entry*)urb->context; - struct data_ring *ring = entry->ring; - struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; struct data_desc *rxd = (struct data_desc*)entry->skb->data; u32 word0; u32 word1; - int signal; - int rssi; - int ofdm; - u16 size; - - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) - return; - - /* - * Check if the received data is simply too small - * to be actually valid, or if the urb is signaling - * a problem. - */ - if (urb->actual_length < entry->ring->desc_size || urb->status) - goto skip_entry; rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); /* * TODO: Don't we need to keep statistics - * updated about events like CRC and physical errors? + * updated about these errors? */ if (rt2x00_get_field32(word0, RXD_W0_CRC) || rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - goto skip_entry; + return -EINVAL; /* * Obtain the status about this packet. */ - size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rssi = rt2x00_get_field32(word1, RXD_W1_RSSI); - ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); /* - * Trim the skb_buffer to only contain the valid - * frame data (so ignore the device's descriptor). + * Pull the skb to clear the descriptor area. */ - skb_pull(entry->skb, ring->desc_size); - skb_trim(entry->skb, size); + skb_pull(entry->skb, entry->ring->desc_size); - /* - * Send the packet to upper layer, and update urb. - */ - rt2x00lib_rxdone(entry, NULL, ring->data_size + ring->desc_size, - signal, rssi, ofdm); - urb->transfer_buffer = entry->skb->data; - urb->transfer_buffer_length = entry->skb->len; - -skip_entry: - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_submit_urb(urb, GFP_ATOMIC); - } - - rt2x00_ring_index_inc(ring); + return rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } /* @@ -1420,6 +1395,8 @@ skip_entry: static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev) { u16 word; + u8 *mac; + char value; /* * Allocate the eeprom memory, check the eeprom width @@ -1437,6 +1414,12 @@ static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev) /* * Start validation of the data that has been read. */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); @@ -1481,6 +1464,38 @@ static int rt73usb_alloc_eeprom(struct rt2x00_dev *rt2x00dev) EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); } + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + } + return 0; } @@ -1612,12 +1627,17 @@ static void rt73usb_init_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_WEP_INCLUDE_IV | IEEE80211_HW_DATA_NULLFUNC_ACK | IEEE80211_HW_NO_TKIP_WMM_HWACCEL | - IEEE80211_HW_MONITOR_DURING_OPER; + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_rssi = MAX_RX_SSI; rt2x00dev->hw->max_noise = MAX_RX_NOISE; rt2x00dev->hw->queues = 5; + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); + /* * Set device specific, but channel independent RF values. */ @@ -1638,7 +1658,6 @@ static void rt73usb_init_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->mac_addr = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); spec->num_modes = 2; spec->num_rates = 12; spec->num_channels = 14; @@ -1683,10 +1702,15 @@ static int rt73usb_init_hw(struct rt2x00_dev *rt2x00dev) rt73usb_init_hw_mode(rt2x00dev); /* - * rt73usb requires firmware + * This device requires firmware */ __set_bit(FIRMWARE_REQUIRED, &rt2x00dev->flags); + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + return 0; } @@ -1752,8 +1776,6 @@ static void rt73usb_reset_tsf(struct ieee80211_hw *hw) static const struct ieee80211_ops rt73usb_mac80211_ops = { .tx = rt2x00lib_tx, .reset = rt2x00lib_reset, - .open = rt2x00lib_open, - .stop = rt2x00lib_stop, .add_interface = rt2x00lib_add_interface, .remove_interface = rt2x00lib_remove_interface, .config = rt2x00lib_config, @@ -1779,6 +1801,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .write_tx_desc = rt73usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, .kick_tx_queue = rt73usb_kick_tx_queue, + .fill_rxdone = rt73usb_fill_rxdone, .config_type = rt73usb_config_type, .config_phymode = rt73usb_config_phymode, .config_channel = rt73usb_config_channel, @@ -1881,14 +1904,11 @@ static struct usb_driver rt73usb_driver = { static int __init rt73usb_init(void) { - printk(KERN_INFO "Loading module: %s - %s by %s.\n", - DRV_NAME, DRV_VERSION, DRV_PROJECT); return usb_register(&rt73usb_driver); } static void __exit rt73usb_exit(void) { - printk(KERN_INFO "Unloading module: %s.\n", DRV_NAME); usb_deregister(&rt73usb_driver); } diff --git a/package/rt2x00/src/rt73usb.h b/package/rt2x00/src/rt73usb.h index 7796656..159240f 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 */ |