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

SVN-Revision: 8367
This commit is contained in:
Florian Fainelli 2007-08-07 09:12:49 +00:00
parent ce173e2094
commit 195c4d9a3d
29 changed files with 2073 additions and 856 deletions

View file

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

340
package/rt2x00/src/COPYING Normal file
View file

@ -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.

View file

@ -1,11 +1,147 @@
rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00firmware.o
# Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
# <http://rt2x00.serialmonkey.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
EXTRA_CFLAGS += -DCONFIG_RT2X00_LIB_FIRMWARE
# Module: Makefile
# Abstract: Makefile for rt2x00 kernel module
obj-m += rt2x00lib.o rt2x00pci.o rt2x00usb.o
#
# Set the enviroment variables.
#
ifndef SUBDIRS
SUBDIRS=$(shell pwd)
endif
obj-$(CONFIG_RT2400PCI) += rt2400pci.o
obj-$(CONFIG_RT2500PCI) += rt2500pci.o
obj-$(CONFIG_RT61PCI) += rt61pci.o
obj-$(CONFIG_RT2500USB) += rt2500usb.o
obj-$(CONFIG_RT73USB) += rt73usb.o
ifdef KERNDIR
KERNEL_SOURCES := $(KERNDIR)
else
KERNEL_SOURCES := /lib/modules/$(shell uname -r)/build
endif
ifdef KERNOUT
KERNEL_OUTPUT := KBUILD_OUTPUT=$(KERNOUT)
else
KERNEL_OUTPUT :=
endif
#
# Include kernel and rt2x00 config.
#
include $(KERNEL_SOURCES)/.config
include $(SUBDIRS)/config
#
# Determine if and with what options the rt2x00 drivers should be build
#
rt2x00lib-objs := rt2x00dev.o rt2x00mac.o
ifeq ($(CONFIG_RT2X00),y)
ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
rt2x00lib-objs += rt2x00debug.o
endif
ifeq ($(CONFIG_RT2400PCI),y)
obj-m += rt2400pci.o rt2x00pci.o rt2x00lib.o
ifeq ($(CONFIG_RT2400PCI_RFKILL),y)
rt2x00lib-objs += rt2x00rfkill.o
CFLAGS += -DCONFIG_RT2X00_LIB_RFKILL
endif
endif
ifeq ($(CONFIG_RT2500PCI),y)
obj-m += rt2500pci.o rt2x00pci.o rt2x00lib.o
ifeq ($(CONFIG_RT2500PCI_RFKILL),y)
rt2x00lib-objs += rt2x00rfkill.o
CFLAGS += -DCONFIG_RT2X00_LIB_RFKILL
endif
endif
ifeq ($(CONFIG_RT2500USB),y)
obj-m += rt2500usb.o rt2x00usb.o rt2x00lib.o
endif
ifeq ($(CONFIG_RT61PCI),y)
CFLAGS += -DCONFIG_RT2X00_LIB_FIRMWARE
rt2x00lib-objs += rt2x00firmware.o
obj-m += rt61pci.o rt2x00pci.o rt2x00lib.o
ifeq ($(CONFIG_RT61PCI_RFKILL),y)
rt2x00lib-objs += rt2x00rfkill.o
CFLAGS += -DCONFIG_RT2X00_LIB_RFKILL
endif
endif
ifeq ($(CONFIG_RT73USB),y)
CFLAGS += -DCONFIG_RT2X00_LIB_FIRMWARE
rt2x00lib-objs += rt2x00firmware.o
obj-m += rt73usb.o rt2x00usb.o rt2x00lib.o
endif
endif
MAKEFLAGS += --no-print-directory
CFLAGS := -include $(SUBDIRS)/rt2x00_compat.h $(CFLAGS)
all: default
config_header:
@if [ ! -f "rt2x00_config.h" ] || [ "rt2x00_config.h" -ot "config" ]; \
then \
awk -F = > rt2x00_config.h < config '/^CONFIG.*$\/ \
{ \
if($$2 == "y") { \
print "#ifndef " $$1; \
print "#define " $$1; \
print "#endif"; \
print "" \
} else { \
print "#undef " $$1; \
print ""; \
} \
}'; \
fi
default: config_header
@$(MAKE) -C $(KERNEL_SOURCES) SUBDIRS=$(SUBDIRS) $(KERNEL_OUTPUT) \
modules
sparse: config_header
@$(MAKE) -C $(KERNEL_SOURCES) SUBDIRS=$(SUBDIRS) $(KERNEL_OUTPUT) \
modules C=1 CF=-D__CHECK_ENDIAN__
install: config_header
@$(MAKE) -C $(KERNEL_SOURCES) SUBDIRS=$(SUBDIRS) $(KERNEL_OUTPUT) \
INSTALL_MOD_DIR=rt2x00 $(KERNEL_OUTPUT) modules_install
/sbin/depmod -a
clean:
@rm -f rt2x00_config.h
@rm -f Modules.symvers Module.symvers
@for folder in $(EXTMODDIRS); \
do \
rm -f $${folder}/*.o \
rm -f $${folder}/*.ko \
rm -f $${folder}/*.s \
rm -f $${folder}/*.mod.c \
rm -f $${folder}/.*.cmd \
rm -f $${folder}/.*.flags \
rm -f $${folder}/.*.o.d \
rm -f $${folder}/.*.s.d \
rm -f $${folder}/.#* \
rm -f $${folder}/*~ \
rm -fr $${folder}/.tmp_versions; \
done

548
package/rt2x00/src/README Normal file
View file

@ -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

54
package/rt2x00/src/THANKS Normal file
View file

@ -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.

41
package/rt2x00/src/config Normal file
View file

@ -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

View file

@ -42,6 +42,7 @@
#include <asm/io.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
#include "rt2x00pci.h"
#include "rt2400pci.h"
@ -614,7 +615,7 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
/*
* Link tuning
*/
static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
{
u8 reg;
char false_cca_delta;
@ -623,7 +624,7 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
* The link tuner should not run longer then 60 seconds,
* and should run once every 2 seconds.
*/
if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count % 1))
if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1))
return;
/*
@ -649,6 +650,7 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
reg += 2;
if (reg < 0x20)
rt2400pci_bbp_write(rt2x00dev, 13, reg);
rt2x00dev->rx_status.noise = reg;
}
}
@ -926,10 +928,34 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
}
static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled)
{
u32 reg;
/*
* When interrupts are being enabled, the interrupt registers
* should clear the register to assure a clean state.
*/
if (enabled) {
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
}
/*
* Only toggle the interrupts bits we are going to use.
* Non-checked interrupt bits are disabled by default.
*/
rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, !enabled);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, !enabled);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, !enabled);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, !enabled);
rt2x00_set_field32(&reg, CSR8_RXDONE, !enabled);
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
}
static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
* Initialize all registers.
*/
@ -940,22 +966,10 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
return -EIO;
}
/*
* Clear interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
/*
* Enable interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
rt2x00_set_field32(&reg, CSR8_RXDONE, 0);
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
rt2400pci_toggle_irq(rt2x00dev, 1);
/*
* Enable LED
@ -991,13 +1005,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 1);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 1);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 1);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 1);
rt2x00_set_field32(&reg, CSR8_RXDONE, 1);
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
rt2400pci_toggle_irq(rt2x00dev, 0);
}
static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
@ -1163,59 +1171,40 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
* Interrupt functions.
* RX control handlers
*/
static void rt2400pci_rxdone(struct rt2x00_dev *rt2x00dev)
static int rt2400pci_fill_rxdone(struct data_entry *entry,
int *signal, int *rssi, int *ofdm)
{
struct data_ring *ring = rt2x00dev->rx;
struct data_entry *entry;
struct data_desc *rxd;
struct data_desc *rxd = entry->priv;
u32 word0;
u32 word2;
int signal;
int rssi;
u16 size;
while (1) {
entry = rt2x00_get_data_entry(ring);
rxd = entry->priv;
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 2, &word2);
if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
break;
/*
* TODO: Don't we need to keep statistics
* updated about events like CRC and physical errors?
* 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);
signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
rssi = rt2x00_get_field32(word2, RXD_W2_RSSI);
*signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
*rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
entry->ring->rt2x00dev->rssi_offset;
*ofdm = 0;
/*
* Send the packet to upper layer.
*/
rt2x00lib_rxdone(entry, entry->data_addr, size,
signal, rssi, 0);
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);
}
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);
}

View file

@ -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.

View file

@ -42,6 +42,7 @@
#include <asm/io.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
#include "rt2x00pci.h"
#include "rt2500pci.h"
@ -368,6 +369,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
u32 rf2 = value;
u32 rf3 = rt2x00dev->rf3;
u32 rf4 = rt2x00dev->rf4;
u8 r70;
if (rt2x00_rf(&rt2x00dev->chip, RF2525) ||
rt2x00_rf(&rt2x00dev->chip, RF2525E))
@ -435,7 +437,9 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
/*
* Channel 14 requires the Japan filter bit to be set.
*/
rt2500pci_bbp_write(rt2x00dev, 70, (channel == 14) ? 0x4e : 0x46);
r70 = 0x46;
rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, channel == 14);
rt2500pci_bbp_write(rt2x00dev, 70, r70);
msleep(1);
@ -692,8 +696,9 @@ static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
/*
* Link tuning
*/
static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
{
int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
u32 reg;
u8 r17;
@ -722,7 +727,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
*/
if (rssi < -80 && rt2x00dev->link.count > 20) {
if (r17 >= 0x41) {
r17 = rt2x00dev->link.curr_noise;
r17 = rt2x00dev->rx_status.noise;
rt2500pci_bbp_write(rt2x00dev, 17, r17);
}
return;
@ -751,7 +756,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
* to the dynamic tuning range.
*/
if (r17 >= 0x41) {
rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.curr_noise);
rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->rx_status.noise);
return;
}
@ -766,10 +771,10 @@ dynamic_cca_tune:
if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) {
rt2500pci_bbp_write(rt2x00dev, 17, ++r17);
rt2x00dev->link.curr_noise = r17;
rt2x00dev->rx_status.noise = r17;
} else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) {
rt2500pci_bbp_write(rt2x00dev, 17, --r17);
rt2x00dev->link.curr_noise = r17;
rt2x00dev->rx_status.noise = r17;
}
}
@ -898,7 +903,16 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
return -EBUSY;
rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
rt2x00pci_register_write(rt2x00dev, PCICSR, 0x000003b8);
rt2x00pci_register_read(rt2x00dev, PCICSR, &reg);
rt2x00_set_field32(&reg, PCICSR_BIG_ENDIAN, 0);
rt2x00_set_field32(&reg, PCICSR_RX_TRESHOLD, 0);
rt2x00_set_field32(&reg, PCICSR_TX_TRESHOLD, 3);
rt2x00_set_field32(&reg, PCICSR_BURST_LENTH, 1);
rt2x00_set_field32(&reg, PCICSR_ENABLE_CLK, 1);
rt2x00_set_field32(&reg, PCICSR_READ_MULTIPLE, 1);
rt2x00_set_field32(&reg, PCICSR_WRITE_INVALID, 1);
rt2x00pci_register_write(rt2x00dev, PCICSR, reg);
rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
@ -1079,10 +1093,34 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
}
static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled)
{
u32 reg;
/*
* When interrupts are being enabled, the interrupt registers
* should clear the register to assure a clean state.
*/
if (enabled) {
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
}
/*
* Only toggle the interrupts bits we are going to use.
* Non-checked interrupt bits are disabled by default.
*/
rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, !enabled);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, !enabled);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, !enabled);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, !enabled);
rt2x00_set_field32(&reg, CSR8_RXDONE, !enabled);
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
}
static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
* Initialize all registers.
*/
@ -1093,22 +1131,10 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
return -EIO;
}
/*
* Clear interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
/*
* Enable interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
rt2x00_set_field32(&reg, CSR8_RXDONE, 0);
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
rt2500pci_toggle_irq(rt2x00dev, 1);
/*
* Enable LED
@ -1144,13 +1170,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, 1);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 1);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 1);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 1);
rt2x00_set_field32(&reg, CSR8_RXDONE, 1);
rt2x00pci_register_write(rt2x00dev, CSR8, reg);
rt2500pci_toggle_irq(rt2x00dev, 0);
}
static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
@ -1300,61 +1320,37 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
* Interrupt functions.
* RX control handlers
*/
static void rt2500pci_rxdone(struct rt2x00_dev *rt2x00dev)
static int rt2500pci_fill_rxdone(struct data_entry *entry,
int *signal, int *rssi, int *ofdm)
{
struct data_ring *ring = rt2x00dev->rx;
struct data_entry *entry;
struct data_desc *rxd;
struct data_desc *rxd = entry->priv;
u32 word0;
u32 word2;
int signal;
int rssi;
int ofdm;
u16 size;
while (1) {
entry = rt2x00_get_data_entry(ring);
rxd = entry->priv;
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 2, &word2);
if (rt2x00_get_field32(word0, RXD_W0_OWNER_NIC))
break;
/*
* TODO: Don't we need to keep statistics
* updated about events like CRC and physical errors?
* 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);
signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
rssi = rt2x00_get_field32(word2, RXD_W2_RSSI);
ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
*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);
/*
* 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(&word0, RXD_W0_OWNER_NIC, 1);
rt2x00_desc_write(rxd, 0, word0);
}
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);
}

View file

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

View file

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

View file

@ -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 */

View file

@ -29,21 +29,17 @@
#define RT2X00_H
#include <linux/bitops.h>
#include <linux/prefetch.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <net/mac80211.h>
#include "rt2x00lib.h"
#include "rt2x00debug.h"
/*
* Module information.
* DRV_NAME should be set within the individual module source files.
*/
#ifndef DRV_NAME
#define DRV_NAME "rt2x00"
#endif /* DRV_NAME */
#define DRV_VERSION "2.0.1"
#define DRV_VERSION "2.0.2"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
/*
@ -142,7 +138,7 @@
/*
* Interval defines
*/
#define LINK_TUNE_INTERVAL ( 1 * HZ )
#define LINK_TUNE_INTERVAL ( round_jiffies(HZ) )
#define RFKILL_POLL_INTERVAL ( HZ / 4 )
/*
@ -392,7 +388,6 @@ struct data_entry {
#define ENTRY_TXD_MORE_FRAG 5
#define ENTRY_TXD_REQ_TIMESTAMP 6
#define ENTRY_TXD_REQ_ACK 7
#define ENTRY_TXD_NEW_SEQ 8
/*
* Ring we belong to.
@ -569,17 +564,26 @@ struct link {
*/
u32 count;
/*
* RSSI statistics.
*/
u32 count_rssi;
u32 total_rssi;
/*
* Misc statistics.
* For the average RSSI value we use the "Walking average" approach.
* When adding RSSI to the average value the following calculation
* is needed:
*
* avg_rssi = ((avg_rssi * 7) + rssi) / 8;
*
* The advantage of this approach is that we only need 1 variable
* to store the average in (No need for a count and a total).
* But more importantly, normal average values will over time
* move less and less towards newly added values.
* This means that with link tuning, the device can have a very
* good RSSI for a few minutes but when the device is moved away
* from the AP the average will not decrease fast enough to
* compensate. The walking average compensates this and will
* move towards the new values correctly.
*/
u32 curr_noise;
u32 false_cca;
int avg_rssi;
int false_cca;
/*
* Work structure for scheduling periodic link tuning.
@ -636,6 +640,33 @@ static inline int is_monitor_present(struct interface *intf)
return !!intf->monitor_count;
}
/*
* Details about the supported modes, rates and channels
* of a particular chipset. This is used by rt2x00lib
* to build the ieee80211_hw_mode array for mac80211.
*/
struct hw_mode_spec {
/*
* Number of modes, rates and channels.
*/
int num_modes;
int num_rates;
int num_channels;
/*
* txpower values.
*/
const u8 *tx_power_a;
const u8 *tx_power_bg;
u8 tx_power_default;
/*
* Device/chipset specific value.
*/
const u32 *chan_val_a;
const u32 *chan_val_bg;
};
/*
* rt2x00lib callback functions.
*/
@ -665,7 +696,7 @@ struct rt2x00lib_ops {
int (*set_device_state)(struct rt2x00_dev *rt2x00dev,
enum dev_state state);
int (*rfkill_poll)(struct rt2x00_dev *rt2x00dev);
void (*link_tuner)(struct rt2x00_dev *rt2x00dev, int rssi);
void (*link_tuner)(struct rt2x00_dev *rt2x00dev);
/*
* TX control handlers
@ -680,6 +711,12 @@ struct rt2x00lib_ops {
struct ieee80211_tx_control *control);
void (*kick_tx_queue)(struct rt2x00_dev *rt2x00dev, int queue);
/*
* RX control handlers
*/
int (*fill_rxdone)(struct data_entry *entry,
int *signal, int *rssi, int *ofdm);
/*
* Configuration handlers.
*/
@ -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_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) \
for ((__entry) = (__dev)->rx; \
(__entry) != &(__dev)->bcn[1 + \
test_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags)]; \
(__entry)++)
ring_loop(__entry, (__dev)->rx, ring_end(__dev))
#define txring_for_each(__dev, __entry) \
for ((__entry) = (__dev)->tx; (__entry) != (__dev)->bcn; (__entry)++)
ring_loop(__entry, (__dev)->tx, (__dev)->bcn)
#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;
}
/*

View file

@ -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!

View file

@ -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

View file

@ -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" )

View file

@ -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);

View file

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

View file

@ -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)

View file

@ -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 */

View file

@ -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.
* Initialize interface, and enable the radio when this
* is the first interface that is brought up.
*/
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, conf->mac_addr);
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;
/*
* Enable periodic link tuning if this is a non-monitor interface.
* Before initialization, the mac address should
* be configured.
*/
if (conf->type != IEEE80211_IF_TYPE_MNTR)
rt2x00_start_link_tune(rt2x00dev);
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 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 (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))
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,
rt2x00dev->interface.type);
else
rt2x00lib_config_type(rt2x00dev,
IEEE80211_IF_TYPE_MNTR);
}
/*
* Check which interfaces have been disabled.
*/
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);
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);

View file

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

View file

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

View file

@ -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);
}

View file

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

View file

@ -42,6 +42,7 @@
#include <asm/io.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
#include "rt2x00pci.h"
#include "rt61pci.h"
@ -891,13 +892,19 @@ static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev)
rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
}
static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, char rssi)
static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
{
u8 led;
if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
return;
/*
* Led handling requires a positive value for the rssi,
* to do that correctly we need to add the correction.
*/
rssi += rt2x00dev->rssi_offset;
if (rssi <= 30)
led = 0;
else if (rssi <= 39)
@ -917,8 +924,9 @@ static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, char rssi)
/*
* Link tuning
*/
static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
{
int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
u32 reg;
u8 r17;
u8 up_bound;
@ -1013,10 +1021,12 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, int rssi)
if (++r17 > up_bound)
r17 = up_bound;
rt61pci_bbp_write(rt2x00dev, 17, r17);
rt2x00dev->rx_status.noise = r17;
} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
if (--r17 < low_bound)
r17 = low_bound;
rt61pci_bbp_write(rt2x00dev, 17, r17);
rt2x00dev->rx_status.noise = r17;
}
}
@ -1279,7 +1289,12 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, 0x025eb032);
rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, 0x9eb39eb3);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, 0x8a8b8c8d);
@ -1312,10 +1327,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
@ -1432,10 +1443,48 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
}
static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int enabled)
{
u32 reg;
/*
* When interrupts are being enabled, the interrupt registers
* should clear the register to assure a clean state.
*/
if (enabled) {
rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
}
/*
* Only toggle the interrupts bits we are going to use.
* Non-checked interrupt bits are disabled by default.
*/
rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, !enabled);
rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, !enabled);
rt2x00_set_field32(&reg, INT_MASK_CSR_BEACON_DONE, !enabled);
rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, !enabled);
rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, !enabled);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, !enabled);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, !enabled);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_3, !enabled);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_4, !enabled);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, !enabled);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, !enabled);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, !enabled);
rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
}
static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
* Initialize all registers.
*/
@ -1446,24 +1495,10 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
return -EIO;
}
/*
* Clear interrupts.
*/
rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
/*
* Enable interrupts.
*/
reg = 0;
rt2x00_set_field32(&reg, INT_MASK_CSR_TX_ABORT_DONE, 1);
rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0x00000000);
rt61pci_toggle_irq(rt2x00dev, 1);
/*
* Enable RX.
@ -1508,11 +1543,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable interrupts.
*/
reg = 0xffffffff;
rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, 0);
rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, 0xffffffff);
rt61pci_toggle_irq(rt2x00dev, 0);
}
static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev,
@ -1681,60 +1712,80 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, int queue)
}
/*
* Interrupt functions.
* RX control handlers
*/
static void rt61pci_rxdone(struct rt2x00_dev *rt2x00dev)
static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
{
struct data_ring *ring = rt2x00dev->rx;
struct data_entry *entry;
struct data_desc *rxd;
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_A, &rt2x00dev->flags))
offset += 14;
if (lna == 3 || lna == 2)
offset += 10;
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;
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 rt61pci_fill_rxdone(struct data_entry *entry,
int *signal, int *rssi, int *ofdm)
{
struct data_desc *rxd = entry->priv;
u32 word0;
u32 word1;
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, 1, &word1);
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?
* updated about these errors?
*/
if (rt2x00_get_field32(word0, RXD_W0_CRC))
goto skip_entry;
if (rt2x00_get_field32(word0, RXD_W0_CRC) ||
rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
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 = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
*ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
/*
* 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(&word0, RXD_W0_OWNER_NIC, 1);
rt2x00_desc_write(rxd, 0, word0);
}
rt2x00_ring_index_inc(ring);
}
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);
}

View file

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

View file

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

View file

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