You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
[RT2x00]: add driver for Ralink wireless hardware
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
b481de9ca0
commit
95ea36275f
@@ -665,6 +665,11 @@ D: Minor updates to SCSI types, added /proc/pid/maps protection
|
||||
S: (ask for current address)
|
||||
S: USA
|
||||
|
||||
N: Robin Cornelius
|
||||
E: robincornelius@users.sourceforge.net
|
||||
D: Ralink rt2x00 WLAN driver
|
||||
S: Cornwall, U.K.
|
||||
|
||||
N: Mark Corner
|
||||
E: mcorner@umich.edu
|
||||
W: http://www.eecs.umich.edu/~mcorner/
|
||||
@@ -679,6 +684,11 @@ D: Kernel module SMART utilities
|
||||
S: Santa Cruz, California
|
||||
S: USA
|
||||
|
||||
N: Luis Correia
|
||||
E: lfcorreia@users.sf.net
|
||||
D: Ralink rt2x00 WLAN driver
|
||||
S: Belas, Portugal
|
||||
|
||||
N: Alan Cox
|
||||
W: http://www.linux.org.uk/diary/
|
||||
D: Linux Networking (0.99.10->2.0.29)
|
||||
@@ -833,6 +843,12 @@ S: Lancs
|
||||
S: PR4 6AX
|
||||
S: United Kingdom
|
||||
|
||||
N: Ivo van Doorn
|
||||
E: IvDoorn@gmail.com
|
||||
W: http://www.mendiosus.nl
|
||||
D: Ralink rt2x00 WLAN driver
|
||||
S: Haarlem, The Netherlands
|
||||
|
||||
N: John G Dorsey
|
||||
E: john+@cs.cmu.edu
|
||||
D: ARM Linux ports to Assabet/Neponset, Spot
|
||||
@@ -3517,6 +3533,12 @@ S: Maastrichterweg 63
|
||||
S: 5554 GG Valkenswaard
|
||||
S: The Netherlands
|
||||
|
||||
N: Mark Wallis
|
||||
E: mwallis@serialmonkey.com
|
||||
W: http://mark.serialmonkey.com
|
||||
D: Ralink rt2x00 WLAN driver
|
||||
S: Newcastle, Australia
|
||||
|
||||
N: Peter Shaobo Wang
|
||||
E: pwang@mmdcorp.com
|
||||
W: http://www.mmdcorp.com/pw/linux
|
||||
@@ -3651,6 +3673,15 @@ S: Alte Regensburger Str. 11a
|
||||
S: 93149 Nittenau
|
||||
S: Germany
|
||||
|
||||
N: Gertjan van Wingerde
|
||||
E: gwingerde@home.nl
|
||||
D: Ralink rt2x00 WLAN driver
|
||||
D: Minix V2 file-system
|
||||
D: Misc fixes
|
||||
S: Geessinkweg 177
|
||||
S: 7544 TX Enschede
|
||||
S: The Netherlands
|
||||
|
||||
N: Lars Wirzenius
|
||||
E: liw@iki.fi
|
||||
D: Linux System Administrator's Guide, author, former maintainer
|
||||
|
||||
@@ -3147,6 +3147,14 @@ M: corey@world.std.com
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
RALINK RT2X00 WLAN DRIVER
|
||||
P: rt2x00 project
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: rt2400-devel@lists.sourceforge.net
|
||||
W: http://rt2x00.serialmonkey.com/
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/rt2x00/
|
||||
|
||||
RANDOM NUMBER DRIVER
|
||||
P: Matt Mackall
|
||||
M: mpm@selenic.com
|
||||
|
||||
@@ -583,5 +583,6 @@ source "drivers/net/wireless/bcm43xx/Kconfig"
|
||||
source "drivers/net/wireless/b43/Kconfig"
|
||||
source "drivers/net/wireless/b43legacy/Kconfig"
|
||||
source "drivers/net/wireless/zd1211rw/Kconfig"
|
||||
source "drivers/net/wireless/rt2x00/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -53,3 +53,4 @@ obj-$(CONFIG_RTL8187) += rtl8187.o
|
||||
obj-$(CONFIG_ADM8211) += adm8211.o
|
||||
|
||||
obj-$(CONFIG_IWLWIFI) += iwlwifi/
|
||||
obj-$(CONFIG_RT2X00) += rt2x00/
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
config RT2X00
|
||||
tristate "Ralink driver support"
|
||||
depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
|
||||
---help---
|
||||
This will enable the experimental support for the Ralink drivers,
|
||||
developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
|
||||
|
||||
These drivers will make use of the Devicescape ieee80211 stack.
|
||||
|
||||
When building one of the individual drivers, the rt2x00 library
|
||||
will also be created. That library (when the driver is built as
|
||||
a module) will be called "rt2x00lib.ko".
|
||||
|
||||
config RT2X00_LIB
|
||||
tristate
|
||||
depends on RT2X00
|
||||
|
||||
config RT2X00_LIB_PCI
|
||||
tristate
|
||||
depends on RT2X00
|
||||
select RT2X00_LIB
|
||||
|
||||
config RT2X00_LIB_USB
|
||||
tristate
|
||||
depends on RT2X00
|
||||
select RT2X00_LIB
|
||||
|
||||
config RT2X00_LIB_FIRMWARE
|
||||
boolean
|
||||
depends on RT2X00_LIB
|
||||
select CRC_ITU_T
|
||||
select FW_LOADER
|
||||
|
||||
config RT2X00_LIB_RFKILL
|
||||
boolean
|
||||
depends on RT2X00_LIB
|
||||
select RFKILL
|
||||
select INPUT_POLLDEV
|
||||
|
||||
config RT2400PCI
|
||||
tristate "Ralink rt2400 pci/pcmcia support"
|
||||
depends on RT2X00 && PCI
|
||||
select RT2X00_LIB_PCI
|
||||
select EEPROM_93CX6
|
||||
---help---
|
||||
This is an experimental driver for the Ralink rt2400 wireless chip.
|
||||
|
||||
When compiled as a module, this driver will be called "rt2400pci.ko".
|
||||
|
||||
config RT2400PCI_RFKILL
|
||||
bool "RT2400 rfkill support"
|
||||
depends on RT2400PCI
|
||||
select RT2X00_LIB_RFKILL
|
||||
---help---
|
||||
This adds support for integrated rt2400 devices that feature a
|
||||
hardware button to control the radio state.
|
||||
This feature depends on the RF switch subsystem rfkill.
|
||||
|
||||
config RT2500PCI
|
||||
tristate "Ralink rt2500 pci/pcmcia support"
|
||||
depends on RT2X00 && PCI
|
||||
select RT2X00_LIB_PCI
|
||||
select EEPROM_93CX6
|
||||
---help---
|
||||
This is an experimental driver for the Ralink rt2500 wireless chip.
|
||||
|
||||
When compiled as a module, this driver will be called "rt2500pci.ko".
|
||||
|
||||
config RT2500PCI_RFKILL
|
||||
bool "RT2500 rfkill support"
|
||||
depends on RT2500PCI
|
||||
select RT2X00_LIB_RFKILL
|
||||
---help---
|
||||
This adds support for integrated rt2500 devices that feature a
|
||||
hardware button to control the radio state.
|
||||
This feature depends on the RF switch subsystem rfkill.
|
||||
|
||||
config RT61PCI
|
||||
tristate "Ralink rt61 pci/pcmcia support"
|
||||
depends on RT2X00 && PCI
|
||||
select RT2X00_LIB_PCI
|
||||
select RT2X00_LIB_FIRMWARE
|
||||
select EEPROM_93CX6
|
||||
---help---
|
||||
This is an experimental driver for the Ralink rt61 wireless chip.
|
||||
|
||||
When compiled as a module, this driver will be called "rt61pci.ko".
|
||||
|
||||
config RT61PCI_RFKILL
|
||||
bool "RT61 rfkill support"
|
||||
depends on RT61PCI
|
||||
select RT2X00_LIB_RFKILL
|
||||
---help---
|
||||
This adds support for integrated rt61 devices that feature a
|
||||
hardware button to control the radio state.
|
||||
This feature depends on the RF switch subsystem rfkill.
|
||||
|
||||
config RT2500USB
|
||||
tristate "Ralink rt2500 usb support"
|
||||
depends on RT2X00 && USB
|
||||
select RT2X00_LIB_USB
|
||||
---help---
|
||||
This is an experimental driver for the Ralink rt2500 wireless chip.
|
||||
|
||||
When compiled as a module, this driver will be called "rt2500usb.ko".
|
||||
|
||||
config RT73USB
|
||||
tristate "Ralink rt73 usb support"
|
||||
depends on RT2X00 && USB
|
||||
select RT2X00_LIB_USB
|
||||
select RT2X00_LIB_FIRMWARE
|
||||
---help---
|
||||
This is an experimental driver for the Ralink rt73 wireless chip.
|
||||
|
||||
When compiled as a module, this driver will be called "rt73usb.ko".
|
||||
|
||||
config RT2X00_LIB_DEBUGFS
|
||||
bool "Ralink debugfs support"
|
||||
depends on RT2X00_LIB && MAC80211_DEBUGFS
|
||||
---help---
|
||||
Enable creation of debugfs files for the rt2x00 drivers.
|
||||
These debugfs files support both reading and writing of the
|
||||
most important register types of the rt2x00 devices.
|
||||
|
||||
config RT2X00_DEBUG
|
||||
bool "Ralink debug output"
|
||||
depends on RT2X00_LIB
|
||||
---help---
|
||||
Enable debugging output for all rt2x00 modules
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o
|
||||
|
||||
ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
|
||||
rt2x00lib-objs += rt2x00debug.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y)
|
||||
rt2x00lib-objs += rt2x00rfkill.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y)
|
||||
rt2x00lib-objs += rt2x00firmware.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
|
||||
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
|
||||
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Module: rt2x00lib
|
||||
Abstract: rt2x00 generic configuration routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set enviroment defines for rt2x00.h
|
||||
*/
|
||||
#define DRV_NAME "rt2x00lib"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "rt2x00.h"
|
||||
#include "rt2x00lib.h"
|
||||
|
||||
void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac)
|
||||
{
|
||||
if (mac)
|
||||
rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, mac);
|
||||
}
|
||||
|
||||
void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid)
|
||||
{
|
||||
if (bssid)
|
||||
rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid);
|
||||
}
|
||||
|
||||
void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter)
|
||||
{
|
||||
/*
|
||||
* Only configure the device when something has changed,
|
||||
* or if we are in RESUME state in which case all configuration
|
||||
* will be forced upon the device.
|
||||
*/
|
||||
if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) &&
|
||||
!test_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Write configuration to device and clear the update flag.
|
||||
*/
|
||||
rt2x00dev->ops->lib->config_packet_filter(rt2x00dev, filter);
|
||||
__clear_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags);
|
||||
}
|
||||
|
||||
void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type)
|
||||
{
|
||||
struct interface *intf = &rt2x00dev->interface;
|
||||
|
||||
/*
|
||||
* Fallback when a invalid interface is attempted to
|
||||
* be configured. If a monitor interface is present,
|
||||
* we are going configure that, otherwise exit.
|
||||
*/
|
||||
if (type == INVALID_INTERFACE) {
|
||||
if (is_monitor_present(intf))
|
||||
type = IEEE80211_IF_TYPE_MNTR;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only configure the device when something has changed,
|
||||
* or if we are in RESUME state in which case all configuration
|
||||
* will be forced upon the device.
|
||||
*/
|
||||
if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) &&
|
||||
(!(is_interface_present(intf) ^
|
||||
test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) &&
|
||||
!(is_monitor_present(intf) ^
|
||||
test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags))))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Configure device.
|
||||
*/
|
||||
rt2x00dev->ops->lib->config_type(rt2x00dev, type);
|
||||
|
||||
/*
|
||||
* Update the configuration flags.
|
||||
*/
|
||||
if (type != IEEE80211_IF_TYPE_MNTR) {
|
||||
if (is_interface_present(intf))
|
||||
__set_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
|
||||
else
|
||||
__clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
|
||||
} else {
|
||||
if (is_monitor_present(intf))
|
||||
__set_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags);
|
||||
else
|
||||
__clear_bit(INTERFACE_ENABLED_MONITOR,
|
||||
&rt2x00dev->flags);
|
||||
}
|
||||
}
|
||||
|
||||
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
/*
|
||||
* If we are in RESUME state we should
|
||||
* force all configuration options.
|
||||
*/
|
||||
if (test_bit(INTERFACE_RESUME, &rt2x00dev->flags)) {
|
||||
flags = CONFIG_UPDATE_ALL;
|
||||
goto config;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check which configuration options have been
|
||||
* updated and should be send to the device.
|
||||
*/
|
||||
if (rt2x00dev->rx_status.phymode != conf->phymode)
|
||||
flags |= CONFIG_UPDATE_PHYMODE;
|
||||
if (rt2x00dev->rx_status.channel != conf->channel)
|
||||
flags |= CONFIG_UPDATE_CHANNEL;
|
||||
if (rt2x00dev->tx_power != conf->power_level)
|
||||
flags |= CONFIG_UPDATE_TXPOWER;
|
||||
if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx)
|
||||
flags |= CONFIG_UPDATE_ANTENNA;
|
||||
|
||||
/*
|
||||
* The following configuration options are never
|
||||
* stored anywhere and will always be updated.
|
||||
*/
|
||||
flags |= CONFIG_UPDATE_SLOT_TIME;
|
||||
flags |= CONFIG_UPDATE_BEACON_INT;
|
||||
|
||||
config:
|
||||
rt2x00dev->ops->lib->config(rt2x00dev, flags, conf);
|
||||
|
||||
/*
|
||||
* Some configuration changes affect the link quality
|
||||
* which means we need to reset the link tuner.
|
||||
*/
|
||||
if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
|
||||
rt2x00lib_reset_link_tuner(rt2x00dev);
|
||||
|
||||
rt2x00dev->rx_status.phymode = conf->phymode;
|
||||
rt2x00dev->rx_status.freq = conf->freq;
|
||||
rt2x00dev->rx_status.channel = conf->channel;
|
||||
rt2x00dev->tx_power = conf->power_level;
|
||||
rt2x00dev->rx_status.antenna = conf->antenna_sel_rx;
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Module: rt2x00lib
|
||||
Abstract: rt2x00 debugfs specific routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set enviroment defines for rt2x00.h
|
||||
*/
|
||||
#define DRV_NAME "rt2x00lib"
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "rt2x00.h"
|
||||
#include "rt2x00lib.h"
|
||||
|
||||
#define PRINT_LINE_LEN_MAX 32
|
||||
|
||||
struct rt2x00debug_intf {
|
||||
/*
|
||||
* Pointer to driver structure where
|
||||
* this debugfs entry belongs to.
|
||||
*/
|
||||
struct rt2x00_dev *rt2x00dev;
|
||||
|
||||
/*
|
||||
* Reference to the rt2x00debug structure
|
||||
* which can be used to communicate with
|
||||
* the registers.
|
||||
*/
|
||||
const struct rt2x00debug *debug;
|
||||
|
||||
/*
|
||||
* Debugfs entries for:
|
||||
* - driver folder
|
||||
* - driver file
|
||||
* - chipset file
|
||||
* - register offset/value files
|
||||
* - eeprom offset/value files
|
||||
* - bbp offset/value files
|
||||
* - rf offset/value files
|
||||
*/
|
||||
struct dentry *driver_folder;
|
||||
struct dentry *driver_entry;
|
||||
struct dentry *chipset_entry;
|
||||
struct dentry *csr_off_entry;
|
||||
struct dentry *csr_val_entry;
|
||||
struct dentry *eeprom_off_entry;
|
||||
struct dentry *eeprom_val_entry;
|
||||
struct dentry *bbp_off_entry;
|
||||
struct dentry *bbp_val_entry;
|
||||
struct dentry *rf_off_entry;
|
||||
struct dentry *rf_val_entry;
|
||||
|
||||
/*
|
||||
* Driver and chipset files will use a data buffer
|
||||
* that has been created in advance. This will simplify
|
||||
* the code since we can use the debugfs functions.
|
||||
*/
|
||||
struct debugfs_blob_wrapper driver_blob;
|
||||
struct debugfs_blob_wrapper chipset_blob;
|
||||
|
||||
/*
|
||||
* Requested offset for each register type.
|
||||
*/
|
||||
unsigned int offset_csr;
|
||||
unsigned int offset_eeprom;
|
||||
unsigned int offset_bbp;
|
||||
unsigned int offset_rf;
|
||||
};
|
||||
|
||||
static int rt2x00debug_file_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct rt2x00debug_intf *intf = inode->i_private;
|
||||
|
||||
file->private_data = inode->i_private;
|
||||
|
||||
if (!try_module_get(intf->debug->owner))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt2x00debug_file_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct rt2x00debug_intf *intf = file->private_data;
|
||||
|
||||
module_put(intf->debug->owner);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
|
||||
static ssize_t rt2x00debug_read_##__name(struct file *file, \
|
||||
char __user *buf, \
|
||||
size_t length, \
|
||||
loff_t *offset) \
|
||||
{ \
|
||||
struct rt2x00debug_intf *intf = file->private_data; \
|
||||
const struct rt2x00debug *debug = intf->debug; \
|
||||
char line[16]; \
|
||||
size_t size; \
|
||||
__type value; \
|
||||
\
|
||||
if (*offset) \
|
||||
return 0; \
|
||||
\
|
||||
if (intf->offset_##__name >= debug->__name.word_count) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
debug->__name.read(intf->rt2x00dev, \
|
||||
intf->offset_##__name, &value); \
|
||||
\
|
||||
size = sprintf(line, __format, value); \
|
||||
\
|
||||
if (copy_to_user(buf, line, size)) \
|
||||
return -EFAULT; \
|
||||
\
|
||||
*offset += size; \
|
||||
return size; \
|
||||
}
|
||||
|
||||
#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
|
||||
static ssize_t rt2x00debug_write_##__name(struct file *file, \
|
||||
const char __user *buf,\
|
||||
size_t length, \
|
||||
loff_t *offset) \
|
||||
{ \
|
||||
struct rt2x00debug_intf *intf = file->private_data; \
|
||||
const struct rt2x00debug *debug = intf->debug; \
|
||||
char line[16]; \
|
||||
size_t size; \
|
||||
__type value; \
|
||||
\
|
||||
if (*offset) \
|
||||
return 0; \
|
||||
\
|
||||
if (!capable(CAP_NET_ADMIN)) \
|
||||
return -EPERM; \
|
||||
\
|
||||
if (intf->offset_##__name >= debug->__name.word_count) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (copy_from_user(line, buf, length)) \
|
||||
return -EFAULT; \
|
||||
\
|
||||
size = strlen(line); \
|
||||
value = simple_strtoul(line, NULL, 0); \
|
||||
\
|
||||
debug->__name.write(intf->rt2x00dev, \
|
||||
intf->offset_##__name, value); \
|
||||
\
|
||||
*offset += size; \
|
||||
return size; \
|
||||
}
|
||||
|
||||
#define RT2X00DEBUGFS_OPS(__name, __format, __type) \
|
||||
RT2X00DEBUGFS_OPS_READ(__name, __format, __type); \
|
||||
RT2X00DEBUGFS_OPS_WRITE(__name, __type); \
|
||||
\
|
||||
static const struct file_operations rt2x00debug_fop_##__name = {\
|
||||
.owner = THIS_MODULE, \
|
||||
.read = rt2x00debug_read_##__name, \
|
||||
.write = rt2x00debug_write_##__name, \
|
||||
.open = rt2x00debug_file_open, \
|
||||
.release = rt2x00debug_file_release, \
|
||||
};
|
||||
|
||||
RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);
|
||||
RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);
|
||||
RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);
|
||||
RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);
|
||||
|
||||
static struct dentry *rt2x00debug_create_file_driver(const char *name,
|
||||
struct rt2x00debug_intf
|
||||
*intf,
|
||||
struct debugfs_blob_wrapper
|
||||
*blob)
|
||||
{
|
||||
char *data;
|
||||
|
||||
data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
blob->data = data;
|
||||
data += sprintf(data, "driver: %s\n", intf->rt2x00dev->ops->name);
|
||||
data += sprintf(data, "version: %s\n", DRV_VERSION);
|
||||
data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
|
||||
blob->size = strlen(blob->data);
|
||||
|
||||
return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
|
||||
}
|
||||
|
||||
static struct dentry *rt2x00debug_create_file_chipset(const char *name,
|
||||
struct rt2x00debug_intf
|
||||
*intf,
|
||||
struct
|
||||
debugfs_blob_wrapper
|
||||
*blob)
|
||||
{
|
||||
const struct rt2x00debug *debug = intf->debug;
|
||||
char *data;
|
||||
|
||||
data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
blob->data = data;
|
||||
data += sprintf(data, "csr length: %d\n", debug->csr.word_count);
|
||||
data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count);
|
||||
data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count);
|
||||
data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
|
||||
blob->size = strlen(blob->data);
|
||||
|
||||
return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
|
||||
}
|
||||
|
||||
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
|
||||
struct rt2x00debug_intf *intf;
|
||||
|
||||
intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);
|
||||
if (!intf) {
|
||||
ERROR(rt2x00dev, "Failed to allocate debug handler.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
intf->debug = debug;
|
||||
intf->rt2x00dev = rt2x00dev;
|
||||
rt2x00dev->debugfs_intf = intf;
|
||||
|
||||
intf->driver_folder =
|
||||
debugfs_create_dir(intf->rt2x00dev->ops->name,
|
||||
rt2x00dev->hw->wiphy->debugfsdir);
|
||||
if (IS_ERR(intf->driver_folder))
|
||||
goto exit;
|
||||
|
||||
intf->driver_entry =
|
||||
rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
|
||||
if (IS_ERR(intf->driver_entry))
|
||||
goto exit;
|
||||
|
||||
intf->chipset_entry =
|
||||
rt2x00debug_create_file_chipset("chipset",
|
||||
intf, &intf->chipset_blob);
|
||||
if (IS_ERR(intf->chipset_entry))
|
||||
goto exit;
|
||||
|
||||
#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \
|
||||
({ \
|
||||
(__intf)->__name##_off_entry = \
|
||||
debugfs_create_u32(__stringify(__name) "_offset", \
|
||||
S_IRUGO | S_IWUSR, \
|
||||
(__intf)->driver_folder, \
|
||||
&(__intf)->offset_##__name); \
|
||||
if (IS_ERR((__intf)->__name##_off_entry)) \
|
||||
goto exit; \
|
||||
\
|
||||
(__intf)->__name##_val_entry = \
|
||||
debugfs_create_file(__stringify(__name) "_value", \
|
||||
S_IRUGO | S_IWUSR, \
|
||||
(__intf)->driver_folder, \
|
||||
(__intf), &rt2x00debug_fop_##__name);\
|
||||
if (IS_ERR((__intf)->__name##_val_entry)) \
|
||||
goto exit; \
|
||||
})
|
||||
|
||||
RT2X00DEBUGFS_CREATE_ENTRY(intf, csr);
|
||||
RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom);
|
||||
RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp);
|
||||
RT2X00DEBUGFS_CREATE_ENTRY(intf, rf);
|
||||
|
||||
#undef RT2X00DEBUGFS_CREATE_ENTRY
|
||||
|
||||
return;
|
||||
|
||||
exit:
|
||||
rt2x00debug_deregister(rt2x00dev);
|
||||
ERROR(rt2x00dev, "Failed to register debug handler.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
|
||||
|
||||
if (unlikely(!intf))
|
||||
return;
|
||||
|
||||
debugfs_remove(intf->rf_val_entry);
|
||||
debugfs_remove(intf->rf_off_entry);
|
||||
debugfs_remove(intf->bbp_val_entry);
|
||||
debugfs_remove(intf->bbp_off_entry);
|
||||
debugfs_remove(intf->eeprom_val_entry);
|
||||
debugfs_remove(intf->eeprom_off_entry);
|
||||
debugfs_remove(intf->csr_val_entry);
|
||||
debugfs_remove(intf->csr_off_entry);
|
||||
debugfs_remove(intf->chipset_entry);
|
||||
debugfs_remove(intf->driver_entry);
|
||||
debugfs_remove(intf->driver_folder);
|
||||
kfree(intf->chipset_blob.data);
|
||||
kfree(intf->driver_blob.data);
|
||||
kfree(intf);
|
||||
|
||||
rt2x00dev->debugfs_intf = NULL;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Module: rt2x00debug
|
||||
Abstract: Data structures for the rt2x00debug.
|
||||
*/
|
||||
|
||||
#ifndef RT2X00DEBUG_H
|
||||
#define RT2X00DEBUG_H
|
||||
|
||||
struct rt2x00_dev;
|
||||
|
||||
#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \
|
||||
struct reg##__name { \
|
||||
void (*read)(const struct rt2x00_dev *rt2x00dev, \
|
||||
const unsigned int word, __type *data); \
|
||||
void (*write)(const struct rt2x00_dev *rt2x00dev, \
|
||||
const unsigned int word, __type data); \
|
||||
\
|
||||
unsigned int word_size; \
|
||||
unsigned int word_count; \
|
||||
} __name
|
||||
|
||||
struct rt2x00debug {
|
||||
/*
|
||||
* Reference to the modules structure.
|
||||
*/
|
||||
struct module *owner;
|
||||
|
||||
/*
|
||||
* Register access entries.
|
||||
*/
|
||||
RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32);
|
||||
RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16);
|
||||
RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8);
|
||||
RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32);
|
||||
};
|
||||
|
||||
#endif /* RT2X00DEBUG_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Module: rt2x00lib
|
||||
Abstract: rt2x00 firmware loading routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set enviroment defines for rt2x00.h
|
||||
*/
|
||||
#define DRV_NAME "rt2x00lib"
|
||||
|
||||
#include <linux/crc-itu-t.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "rt2x00.h"
|
||||
#include "rt2x00lib.h"
|
||||
|
||||
static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
|
||||
const struct firmware *fw;
|
||||
char *fw_name;
|
||||
int retval;
|
||||
u16 crc;
|
||||
u16 tmp;
|
||||
|
||||
/*
|
||||
* Read correct firmware from harddisk.
|
||||
*/
|
||||
fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev);
|
||||
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);
|
||||
|
||||
retval = request_firmware(&fw, fw_name, device);
|
||||
if (retval) {
|
||||
ERROR(rt2x00dev, "Failed to request Firmware.\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!fw || !fw->size || !fw->data) {
|
||||
ERROR(rt2x00dev, "Failed to read Firmware.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the firmware using 16 bit CRC.
|
||||
* The last 2 bytes of the firmware are the CRC
|
||||
* so substract those 2 bytes from the CRC checksum,
|
||||
* and set those 2 bytes to 0 when calculating CRC.
|
||||
*/
|
||||
tmp = 0;
|
||||
crc = crc_itu_t(0, fw->data, fw->size - 2);
|
||||
crc = crc_itu_t(crc, (u8 *)&tmp, 2);
|
||||
|
||||
if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) {
|
||||
ERROR(rt2x00dev, "Firmware CRC error.\n");
|
||||
retval = -ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
|
||||
fw->data[fw->size - 4], fw->data[fw->size - 3]);
|
||||
|
||||
rt2x00dev->fw = fw;
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
release_firmware(fw);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!rt2x00dev->fw) {
|
||||
retval = rt2x00lib_request_firmware(rt2x00dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send firmware to the device.
|
||||
*/
|
||||
retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
|
||||
rt2x00dev->fw->data,
|
||||
rt2x00dev->fw->size);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
release_firmware(rt2x00dev->fw);
|
||||
rt2x00dev->fw = NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Module: rt2x00lib
|
||||
Abstract: Data structures and definitions for the rt2x00lib module.
|
||||
*/
|
||||
|
||||
#ifndef RT2X00LIB_H
|
||||
#define RT2X00LIB_H
|
||||
|
||||
/*
|
||||
* Interval defines
|
||||
*/
|
||||
#define LINK_TUNE_INTERVAL ( round_jiffies(HZ) )
|
||||
#define RFKILL_POLL_INTERVAL ( HZ / 4 )
|
||||
|
||||
/*
|
||||
* Radio control handlers.
|
||||
*/
|
||||
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable);
|
||||
void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev);
|
||||
|
||||
/*
|
||||
* Initialization handlers.
|
||||
*/
|
||||
int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev);
|
||||
|
||||
/*
|
||||
* Configuration handlers.
|
||||
*/
|
||||
void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
|
||||
void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
|
||||
void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter);
|
||||
void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type);
|
||||
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf);
|
||||
|
||||
/*
|
||||
* Firmware handlers.
|
||||
*/
|
||||
#ifdef CONFIG_RT2X00_LIB_FIRMWARE
|
||||
int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev);
|
||||
#else
|
||||
static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_RT2X00_LIB_FIRMWARE */
|
||||
|
||||
/*
|
||||
* Debugfs handlers.
|
||||
*/
|
||||
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
|
||||
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
|
||||
#else
|
||||
static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
|
||||
|
||||
/*
|
||||
* RFkill handlers.
|
||||
*/
|
||||
#ifdef CONFIG_RT2X00_LIB_RFKILL
|
||||
int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
|
||||
int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
|
||||
void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
|
||||
#else
|
||||
static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
/*
|
||||
* Force enable this flag, this will assure that
|
||||
* devices with a hardware button but without rfkill support
|
||||
* can still use their hardware.
|
||||
*/
|
||||
__set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_RT2X00_LIB_RFKILL */
|
||||
|
||||
#endif /* RT2X00LIB_H */
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Module: rt2x00mac
|
||||
Abstract: rt2x00 generic mac80211 routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set enviroment defines for rt2x00.h
|
||||
*/
|
||||
#define DRV_NAME "rt2x00lib"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "rt2x00.h"
|
||||
#include "rt2x00lib.h"
|
||||
|
||||
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
|
||||
struct data_ring *ring,
|
||||
struct sk_buff *frag_skb,
|
||||
struct ieee80211_tx_control *control)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int size;
|
||||
|
||||
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
|
||||
size = sizeof(struct ieee80211_cts);
|
||||
else
|
||||
size = sizeof(struct ieee80211_rts);
|
||||
|
||||
skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom);
|
||||
if (!skb) {
|
||||
WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
|
||||
skb_put(skb, size);
|
||||
|
||||
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
|
||||
ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id,
|
||||
frag_skb->data, frag_skb->len, control,
|
||||
(struct ieee80211_cts *)(skb->data));
|
||||
else
|
||||
ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id,
|
||||
frag_skb->data, frag_skb->len, control,
|
||||
(struct ieee80211_rts *)(skb->data));
|
||||
|
||||
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
|
||||
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ieee80211_tx_control *control)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct data_ring *ring;
|
||||
u16 frame_control;
|
||||
|
||||
/*
|
||||
* Determine which ring to put packet on.
|
||||
*/
|
||||
ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
|
||||
if (unlikely(!ring)) {
|
||||
ERROR(rt2x00dev,
|
||||
"Attempt to send packet over invalid queue %d.\n"
|
||||
"Please file bug report to %s.\n",
|
||||
control->queue, DRV_PROJECT);
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* If CTS/RTS is required. and this frame is not CTS or RTS,
|
||||
* create and queue that frame first. But make sure we have
|
||||
* at least enough entries available to send this CTS/RTS
|
||||
* frame as well as the data frame.
|
||||
*/
|
||||
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
|
||||
if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
|
||||
(control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
|
||||
IEEE80211_TXCTL_USE_CTS_PROTECT))) {
|
||||
if (rt2x00_ring_free(ring) <= 1)
|
||||
return NETDEV_TX_BUSY;
|
||||
|
||||
if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control))
|
||||
return NETDEV_TX_BUSY;
|
||||
|
||||
if (rt2x00dev->ops->lib->kick_tx_queue)
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_tx);
|
||||
|
||||
int rt2x00mac_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
int status;
|
||||
|
||||
if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If this is the first interface which is added,
|
||||
* we should load the firmware now.
|
||||
*/
|
||||
if (test_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
|
||||
status = rt2x00lib_load_firmware(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(rt2x00mac_start);
|
||||
|
||||
void rt2x00mac_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
||||
/*
|
||||
* Perhaps we can add something smarter here,
|
||||
* but for now just disabling the radio should do.
|
||||
*/
|
||||
rt2x00lib_disable_radio(rt2x00dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_stop);
|
||||
|
||||
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_if_init_conf *conf)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct interface *intf = &rt2x00dev->interface;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* We only support 1 non-monitor interface.
|
||||
*/
|
||||
if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf))
|
||||
return -ENOBUFS;
|
||||
|
||||
/*
|
||||
* HACK: Placeholder until start/stop handler has been
|
||||
* added to the mac80211 callback functions structure.
|
||||
*/
|
||||
retval = rt2x00mac_start(hw);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* We support muliple monitor mode interfaces.
|
||||
* All we need to do is increase the monitor_count.
|
||||
*/
|
||||
if (conf->type == IEEE80211_IF_TYPE_MNTR) {
|
||||
intf->monitor_count++;
|
||||
} else {
|
||||
intf->id = conf->if_id;
|
||||
intf->type = conf->type;
|
||||
if (conf->type == IEEE80211_IF_TYPE_AP)
|
||||
memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
|
||||
memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
|
||||
intf->filter = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure interface.
|
||||
* The MAC adddress must be configured after the device
|
||||
* has been initialized. Else the device can reset the
|
||||
* MAC registers.
|
||||
*/
|
||||
rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
|
||||
rt2x00lib_config_type(rt2x00dev, conf->type);
|
||||
rt2x00lib_config_packet_filter(rt2x00dev, intf->filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
|
||||
|
||||
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_if_init_conf *conf)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct interface *intf = &rt2x00dev->interface;
|
||||
|
||||
/*
|
||||
* We only support 1 non-monitor interface.
|
||||
*/
|
||||
if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf))
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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--;
|
||||
} else if (intf->type == conf->type) {
|
||||
intf->id = 0;
|
||||
intf->type = INVALID_INTERFACE;
|
||||
memset(&intf->bssid, 0x00, ETH_ALEN);
|
||||
memset(&intf->mac, 0x00, ETH_ALEN);
|
||||
intf->filter = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the bssid and mac address registers
|
||||
* are cleared to prevent false ACKing of frames.
|
||||
*/
|
||||
rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
|
||||
rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
|
||||
rt2x00lib_config_type(rt2x00dev, intf->type);
|
||||
|
||||
/*
|
||||
* HACK: Placeholder untill start/stop handler has been
|
||||
* added to the mac80211 callback functions structure.
|
||||
*/
|
||||
rt2x00mac_stop(hw);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
|
||||
|
||||
int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
||||
/*
|
||||
* If the device is not initialized we shouldn't accept
|
||||
* any configuration changes. Mac80211 might be calling
|
||||
* this function while we are trying to remove the device
|
||||
* or perhaps suspending it.
|
||||
*/
|
||||
if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Check if we need to disable the radio,
|
||||
* if this is not the case, at least the RX must be disabled.
|
||||
*/
|
||||
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
|
||||
if (!conf->radio_enabled)
|
||||
rt2x00lib_disable_radio(rt2x00dev);
|
||||
else
|
||||
rt2x00lib_toggle_rx(rt2x00dev, 0);
|
||||
}
|
||||
|
||||
rt2x00lib_config(rt2x00dev, conf);
|
||||
|
||||
/*
|
||||
* If promisc mode cannot be configured in irq context,
|
||||
* then it is now the time to configure it.
|
||||
*/
|
||||
if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags))
|
||||
rt2x00lib_config_packet_filter(rt2x00dev,
|
||||
rt2x00dev->interface.filter);
|
||||
|
||||
/*
|
||||
* Reenable RX only if the radio should be on.
|
||||
*/
|
||||
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
rt2x00lib_toggle_rx(rt2x00dev, 1);
|
||||
else if (conf->radio_enabled)
|
||||
return rt2x00lib_enable_radio(rt2x00dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_config);
|
||||
|
||||
int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
|
||||
struct ieee80211_if_conf *conf)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct interface *intf = &rt2x00dev->interface;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* If the device is not initialized we shouldn't accept
|
||||
* any configuration changes. Mac80211 might be calling
|
||||
* this function while we are trying to remove the device
|
||||
* or perhaps suspending it.
|
||||
*/
|
||||
if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Monitor mode does not need configuring.
|
||||
* If the given type does not match the configured type,
|
||||
* there has been a problem.
|
||||
*/
|
||||
if (conf->type == IEEE80211_IF_TYPE_MNTR)
|
||||
return 0;
|
||||
else if (conf->type != intf->type)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If the interface does not work in master mode,
|
||||
* then the bssid value in the interface structure
|
||||
* should now be set.
|
||||
*/
|
||||
if (conf->type != IEEE80211_IF_TYPE_AP)
|
||||
memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
|
||||
rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
|
||||
|
||||
/*
|
||||
* We only need to initialize the beacon when master mode is enabled.
|
||||
*/
|
||||
if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
|
||||
return 0;
|
||||
|
||||
status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
|
||||
conf->beacon,
|
||||
conf->beacon_control);
|
||||
if (status)
|
||||
dev_kfree_skb(conf->beacon);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_config_interface);
|
||||
|
||||
void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw,
|
||||
unsigned short flags, int mc_count)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
||||
/*
|
||||
* Check if the new state is different then the old state.
|
||||
*/
|
||||
if (rt2x00dev->interface.filter == flags)
|
||||
return;
|
||||
|
||||
rt2x00dev->interface.filter = flags;
|
||||
|
||||
/*
|
||||
* Raise the pending bit to indicate the
|
||||
* packet filter should be updated.
|
||||
*/
|
||||
__set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags);
|
||||
|
||||
/*
|
||||
* Check if Packet filter actions are allowed in
|
||||
* atomic context. If not, raise the pending flag and
|
||||
* let it be.
|
||||
*/
|
||||
if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) ||
|
||||
!in_atomic())
|
||||
rt2x00lib_config_packet_filter(rt2x00dev, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list);
|
||||
|
||||
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_low_level_stats *stats)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
||||
/*
|
||||
* The dot11ACKFailureCount, dot11RTSFailureCount and
|
||||
* dot11RTSSuccessCount are updated in interrupt time.
|
||||
* dot11FCSErrorCount is updated in the link tuner.
|
||||
*/
|
||||
memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
|
||||
|
||||
int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_queue_stats *stats)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < hw->queues; i++)
|
||||
memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
|
||||
sizeof(rt2x00dev->tx[i].stats));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
|
||||
|
||||
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct data_ring *ring;
|
||||
|
||||
ring = rt2x00lib_get_ring(rt2x00dev, queue);
|
||||
if (unlikely(!ring))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* The passed variables are stored as real value ((2^n)-1).
|
||||
* Ralink registers require to know the bit number 'n'.
|
||||
*/
|
||||
if (params->cw_min)
|
||||
ring->tx_params.cw_min = fls(params->cw_min);
|
||||
else
|
||||
ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */
|
||||
|
||||
if (params->cw_max)
|
||||
ring->tx_params.cw_max = fls(params->cw_max);
|
||||
else
|
||||
ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */
|
||||
|
||||
if (params->aifs)
|
||||
ring->tx_params.aifs = params->aifs;
|
||||
else
|
||||
ring->tx_params.aifs = 2;
|
||||
|
||||
INFO(rt2x00dev,
|
||||
"Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
|
||||
queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
|
||||
ring->tx_params.aifs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user