hak5-wifi-coconut/libwifiuserspace/rt2800usb/rt2800usb.c

2491 lines
66 KiB
C

/*
* Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
* Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
* <http://rt2x00.serialmonkey.com>
*
* GPL-2.0-or-later
*
* Userspace port (C) 2019 Hak5 Inc
*
*/
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <windows.h>
#define usleep(x) Sleep((x) < 1000 ? 1 : (x) / 1000)
#endif
#include "kernel/cfg80211.h"
#include "kernel/endian.h"
#include "kernel/kernel.h"
#include "kernel/nl80211.h"
#include "kernel/types.h"
#include "rt2x00.h"
#include "rt2x00lib.h"
#include "rt2x00usb.h"
#include "rt2800.h"
#include "rt2800usb.h"
#include "rt2800lib.h"
#define CONFIG_RT2800USB_RT55XX
#define CONFIG_RT2800USB_RT33XX
#define CONFIG_RT2800USB_RT3573
#define CONFIG_RT2800USB_RT53XX
/*
* rt2800usb module information.
*/
static const struct usb_device_id rt2800usb_device_table[] = {
/* Abocom */
{ USB_DEVICE(0x07b8, 0x2870) },
{ USB_DEVICE(0x07b8, 0x2770) },
{ USB_DEVICE(0x07b8, 0x3070) },
{ USB_DEVICE(0x07b8, 0x3071) },
{ USB_DEVICE(0x07b8, 0x3072) },
{ USB_DEVICE(0x1482, 0x3c09) },
/* AirTies */
{ USB_DEVICE(0x1eda, 0x2012) },
{ USB_DEVICE(0x1eda, 0x2210) },
{ USB_DEVICE(0x1eda, 0x2310) },
/* Allwin */
{ USB_DEVICE(0x8516, 0x2070) },
{ USB_DEVICE(0x8516, 0x2770) },
{ USB_DEVICE(0x8516, 0x2870) },
{ USB_DEVICE(0x8516, 0x3070) },
{ USB_DEVICE(0x8516, 0x3071) },
{ USB_DEVICE(0x8516, 0x3072) },
/* Alpha Networks */
{ USB_DEVICE(0x14b2, 0x3c06) },
{ USB_DEVICE(0x14b2, 0x3c07) },
{ USB_DEVICE(0x14b2, 0x3c09) },
{ USB_DEVICE(0x14b2, 0x3c12) },
{ USB_DEVICE(0x14b2, 0x3c23) },
{ USB_DEVICE(0x14b2, 0x3c25) },
{ USB_DEVICE(0x14b2, 0x3c27) },
{ USB_DEVICE(0x14b2, 0x3c28) },
{ USB_DEVICE(0x14b2, 0x3c2c) },
/* Amit */
{ USB_DEVICE(0x15c5, 0x0008) },
/* Askey */
{ USB_DEVICE(0x1690, 0x0740) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x1731) },
{ USB_DEVICE(0x0b05, 0x1732) },
{ USB_DEVICE(0x0b05, 0x1742) },
{ USB_DEVICE(0x0b05, 0x1784) },
{ USB_DEVICE(0x1761, 0x0b05) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3247) },
{ USB_DEVICE(0x13d3, 0x3273) },
{ USB_DEVICE(0x13d3, 0x3305) },
{ USB_DEVICE(0x13d3, 0x3307) },
{ USB_DEVICE(0x13d3, 0x3321) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x8053) },
{ USB_DEVICE(0x050d, 0x805c) },
{ USB_DEVICE(0x050d, 0x815c) },
{ USB_DEVICE(0x050d, 0x825a) },
{ USB_DEVICE(0x050d, 0x825b) },
{ USB_DEVICE(0x050d, 0x935a) },
{ USB_DEVICE(0x050d, 0x935b) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x00e8) },
{ USB_DEVICE(0x0411, 0x0158) },
{ USB_DEVICE(0x0411, 0x015d) },
{ USB_DEVICE(0x0411, 0x016f) },
{ USB_DEVICE(0x0411, 0x01a2) },
{ USB_DEVICE(0x0411, 0x01ee) },
{ USB_DEVICE(0x0411, 0x01a8) },
{ USB_DEVICE(0x0411, 0x01fd) },
/* Corega */
{ USB_DEVICE(0x07aa, 0x002f) },
{ USB_DEVICE(0x07aa, 0x003c) },
{ USB_DEVICE(0x07aa, 0x003f) },
{ USB_DEVICE(0x18c5, 0x0012) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c09) },
{ USB_DEVICE(0x07d1, 0x3c0a) },
{ USB_DEVICE(0x07d1, 0x3c0d) },
{ USB_DEVICE(0x07d1, 0x3c0e) },
{ USB_DEVICE(0x07d1, 0x3c0f) },
{ USB_DEVICE(0x07d1, 0x3c11) },
{ USB_DEVICE(0x07d1, 0x3c13) },
{ USB_DEVICE(0x07d1, 0x3c15) },
{ USB_DEVICE(0x07d1, 0x3c16) },
{ USB_DEVICE(0x07d1, 0x3c17) },
{ USB_DEVICE(0x2001, 0x3317) },
{ USB_DEVICE(0x2001, 0x3c1b) },
{ USB_DEVICE(0x2001, 0x3c25) },
/* Draytek */
{ USB_DEVICE(0x07fa, 0x7712) },
/* DVICO */
{ USB_DEVICE(0x0fe9, 0xb307) },
/* Edimax */
{ USB_DEVICE(0x7392, 0x4085) },
{ USB_DEVICE(0x7392, 0x7711) },
{ USB_DEVICE(0x7392, 0x7717) },
{ USB_DEVICE(0x7392, 0x7718) },
{ USB_DEVICE(0x7392, 0x7722) },
/* Encore */
{ USB_DEVICE(0x203d, 0x1480) },
{ USB_DEVICE(0x203d, 0x14a9) },
/* EnGenius */
{ USB_DEVICE(0x1740, 0x9701) },
{ USB_DEVICE(0x1740, 0x9702) },
{ USB_DEVICE(0x1740, 0x9703) },
{ USB_DEVICE(0x1740, 0x9705) },
{ USB_DEVICE(0x1740, 0x9706) },
{ USB_DEVICE(0x1740, 0x9707) },
{ USB_DEVICE(0x1740, 0x9708) },
{ USB_DEVICE(0x1740, 0x9709) },
/* Gemtek */
{ USB_DEVICE(0x15a9, 0x0012) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800b) },
{ USB_DEVICE(0x1044, 0x800d) },
/* Hawking */
{ USB_DEVICE(0x0e66, 0x0001) },
{ USB_DEVICE(0x0e66, 0x0003) },
{ USB_DEVICE(0x0e66, 0x0009) },
{ USB_DEVICE(0x0e66, 0x000b) },
{ USB_DEVICE(0x0e66, 0x0013) },
{ USB_DEVICE(0x0e66, 0x0017) },
{ USB_DEVICE(0x0e66, 0x0018) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x0945) },
{ USB_DEVICE(0x04bb, 0x0947) },
{ USB_DEVICE(0x04bb, 0x0948) },
/* Linksys */
{ USB_DEVICE(0x13b1, 0x0031) },
{ USB_DEVICE(0x1737, 0x0070) },
{ USB_DEVICE(0x1737, 0x0071) },
{ USB_DEVICE(0x1737, 0x0077) },
{ USB_DEVICE(0x1737, 0x0078) },
/* Logitec */
{ USB_DEVICE(0x0789, 0x0162) },
{ USB_DEVICE(0x0789, 0x0163) },
{ USB_DEVICE(0x0789, 0x0164) },
{ USB_DEVICE(0x0789, 0x0166) },
/* Motorola */
{ USB_DEVICE(0x100d, 0x9031) },
/* MSI */
{ USB_DEVICE(0x0db0, 0x3820) },
{ USB_DEVICE(0x0db0, 0x3821) },
{ USB_DEVICE(0x0db0, 0x3822) },
{ USB_DEVICE(0x0db0, 0x3870) },
{ USB_DEVICE(0x0db0, 0x3871) },
{ USB_DEVICE(0x0db0, 0x6899) },
{ USB_DEVICE(0x0db0, 0x821a) },
{ USB_DEVICE(0x0db0, 0x822a) },
{ USB_DEVICE(0x0db0, 0x822b) },
{ USB_DEVICE(0x0db0, 0x822c) },
{ USB_DEVICE(0x0db0, 0x870a) },
{ USB_DEVICE(0x0db0, 0x871a) },
{ USB_DEVICE(0x0db0, 0x871b) },
{ USB_DEVICE(0x0db0, 0x871c) },
{ USB_DEVICE(0x0db0, 0x899a) },
/* Ovislink */
{ USB_DEVICE(0x1b75, 0x3070) },
{ USB_DEVICE(0x1b75, 0x3071) },
{ USB_DEVICE(0x1b75, 0x3072) },
{ USB_DEVICE(0x1b75, 0xa200) },
/* Para */
{ USB_DEVICE(0x20b8, 0x8888) },
/* Pegatron */
{ USB_DEVICE(0x1d4d, 0x0002) },
{ USB_DEVICE(0x1d4d, 0x000c) },
{ USB_DEVICE(0x1d4d, 0x000e) },
{ USB_DEVICE(0x1d4d, 0x0011) },
/* Philips */
{ USB_DEVICE(0x0471, 0x200f) },
/* Planex */
{ USB_DEVICE(0x2019, 0x5201) },
{ USB_DEVICE(0x2019, 0xab25) },
{ USB_DEVICE(0x2019, 0xed06) },
/* Quanta */
{ USB_DEVICE(0x1a32, 0x0304) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x2070) },
{ USB_DEVICE(0x148f, 0x2770) },
{ USB_DEVICE(0x148f, 0x2870) },
{ USB_DEVICE(0x148f, 0x3070) },
{ USB_DEVICE(0x148f, 0x3071) },
{ USB_DEVICE(0x148f, 0x3072) },
/* Samsung */
{ USB_DEVICE(0x04e8, 0x2018) },
/* Siemens */
{ USB_DEVICE(0x129b, 0x1828) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x0017) },
{ USB_DEVICE(0x0df6, 0x002b) },
{ USB_DEVICE(0x0df6, 0x002c) },
{ USB_DEVICE(0x0df6, 0x002d) },
{ USB_DEVICE(0x0df6, 0x0039) },
{ USB_DEVICE(0x0df6, 0x003b) },
{ USB_DEVICE(0x0df6, 0x003d) },
{ USB_DEVICE(0x0df6, 0x003e) },
{ USB_DEVICE(0x0df6, 0x003f) },
{ USB_DEVICE(0x0df6, 0x0040) },
{ USB_DEVICE(0x0df6, 0x0042) },
{ USB_DEVICE(0x0df6, 0x0047) },
{ USB_DEVICE(0x0df6, 0x0048) },
{ USB_DEVICE(0x0df6, 0x0051) },
{ USB_DEVICE(0x0df6, 0x005f) },
{ USB_DEVICE(0x0df6, 0x0060) },
/* SMC */
{ USB_DEVICE(0x083a, 0x6618) },
{ USB_DEVICE(0x083a, 0x7511) },
{ USB_DEVICE(0x083a, 0x7512) },
{ USB_DEVICE(0x083a, 0x7522) },
{ USB_DEVICE(0x083a, 0x8522) },
{ USB_DEVICE(0x083a, 0xa618) },
{ USB_DEVICE(0x083a, 0xa701) },
{ USB_DEVICE(0x083a, 0xa702) },
{ USB_DEVICE(0x083a, 0xa703) },
{ USB_DEVICE(0x083a, 0xb522) },
/* Sparklan */
{ USB_DEVICE(0x15a9, 0x0006) },
/* Sweex */
{ USB_DEVICE(0x177f, 0x0153) },
{ USB_DEVICE(0x177f, 0x0164) },
{ USB_DEVICE(0x177f, 0x0302) },
{ USB_DEVICE(0x177f, 0x0313) },
{ USB_DEVICE(0x177f, 0x0323) },
{ USB_DEVICE(0x177f, 0x0324) },
/* U-Media */
{ USB_DEVICE(0x157e, 0x300e) },
{ USB_DEVICE(0x157e, 0x3013) },
/* ZCOM */
{ USB_DEVICE(0x0cde, 0x0022) },
{ USB_DEVICE(0x0cde, 0x0025) },
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0280) },
{ USB_DEVICE(0x5a57, 0x0282) },
{ USB_DEVICE(0x5a57, 0x0283) },
{ USB_DEVICE(0x5a57, 0x5257) },
/* Zyxel */
{ USB_DEVICE(0x0586, 0x3416) },
{ USB_DEVICE(0x0586, 0x3418) },
{ USB_DEVICE(0x0586, 0x341a) },
{ USB_DEVICE(0x0586, 0x341e) },
{ USB_DEVICE(0x0586, 0x343e) },
#ifdef CONFIG_RT2800USB_RT33XX
/* Belkin */
{ USB_DEVICE(0x050d, 0x945b) },
/* D-Link */
{ USB_DEVICE(0x2001, 0x3c17) },
/* Panasonic */
{ USB_DEVICE(0x083a, 0xb511) },
/* Accton/Arcadyan/Epson */
{ USB_DEVICE(0x083a, 0xb512) },
/* Philips */
{ USB_DEVICE(0x0471, 0x20dd) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x3370) },
{ USB_DEVICE(0x148f, 0x8070) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x0050) },
/* Sweex */
{ USB_DEVICE(0x177f, 0x0163) },
{ USB_DEVICE(0x177f, 0x0165) },
#endif
#ifdef CONFIG_RT2800USB_RT35XX
/* Allwin */
{ USB_DEVICE(0x8516, 0x3572) },
/* Askey */
{ USB_DEVICE(0x1690, 0x0744) },
{ USB_DEVICE(0x1690, 0x0761) },
{ USB_DEVICE(0x1690, 0x0764) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x179d) },
/* Cisco */
{ USB_DEVICE(0x167b, 0x4001) },
/* EnGenius */
{ USB_DEVICE(0x1740, 0x9801) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x0944) },
/* Linksys */
{ USB_DEVICE(0x13b1, 0x002f) },
{ USB_DEVICE(0x1737, 0x0079) },
/* Logitec */
{ USB_DEVICE(0x0789, 0x0170) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x3572) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x0041) },
{ USB_DEVICE(0x0df6, 0x0062) },
{ USB_DEVICE(0x0df6, 0x0065) },
{ USB_DEVICE(0x0df6, 0x0066) },
{ USB_DEVICE(0x0df6, 0x0068) },
/* Toshiba */
{ USB_DEVICE(0x0930, 0x0a07) },
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0284) },
#endif
#ifdef CONFIG_RT2800USB_RT3573
/* AirLive */
{ USB_DEVICE(0x1b75, 0x7733) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x17bc) },
{ USB_DEVICE(0x0b05, 0x17ad) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x1103) },
/* Cameo */
{ USB_DEVICE(0x148f, 0xf301) },
/* D-Link */
{ USB_DEVICE(0x2001, 0x3c1f) },
/* Edimax */
{ USB_DEVICE(0x7392, 0x7733) },
/* Hawking */
{ USB_DEVICE(0x0e66, 0x0020) },
{ USB_DEVICE(0x0e66, 0x0021) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x094e) },
/* Linksys */
{ USB_DEVICE(0x13b1, 0x003b) },
/* Logitec */
{ USB_DEVICE(0x0789, 0x016b) },
/* NETGEAR */
{ USB_DEVICE(0x0846, 0x9012) },
{ USB_DEVICE(0x0846, 0x9013) },
{ USB_DEVICE(0x0846, 0x9019) },
/* Planex */
{ USB_DEVICE(0x2019, 0xed19) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x3573) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x0067) },
{ USB_DEVICE(0x0df6, 0x006a) },
{ USB_DEVICE(0x0df6, 0x006e) },
/* ZyXEL */
{ USB_DEVICE(0x0586, 0x3421) },
#endif
#ifdef CONFIG_RT2800USB_RT53XX
/* Arcadyan */
{ USB_DEVICE(0x043e, 0x7a12) },
{ USB_DEVICE(0x043e, 0x7a32) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x17e8) },
/* Azurewave */
{ USB_DEVICE(0x13d3, 0x3329) },
{ USB_DEVICE(0x13d3, 0x3365) },
/* D-Link */
{ USB_DEVICE(0x2001, 0x3c15) },
{ USB_DEVICE(0x2001, 0x3c19) },
{ USB_DEVICE(0x2001, 0x3c1c) },
{ USB_DEVICE(0x2001, 0x3c1d) },
{ USB_DEVICE(0x2001, 0x3c1e) },
{ USB_DEVICE(0x2001, 0x3c20) },
{ USB_DEVICE(0x2001, 0x3c22) },
{ USB_DEVICE(0x2001, 0x3c23) },
/* LG innotek */
{ USB_DEVICE(0x043e, 0x7a22) },
{ USB_DEVICE(0x043e, 0x7a42) },
/* Panasonic */
{ USB_DEVICE(0x04da, 0x1801) },
{ USB_DEVICE(0x04da, 0x1800) },
{ USB_DEVICE(0x04da, 0x23f6) },
/* Philips */
{ USB_DEVICE(0x0471, 0x2104) },
{ USB_DEVICE(0x0471, 0x2126) },
{ USB_DEVICE(0x0471, 0x2180) },
{ USB_DEVICE(0x0471, 0x2181) },
{ USB_DEVICE(0x0471, 0x2182) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x5370) },
{ USB_DEVICE(0x148f, 0x5372) },
#endif
#ifdef CONFIG_RT2800USB_RT55XX
/* Arcadyan */
{ USB_DEVICE(0x043e, 0x7a32) },
/* AVM GmbH */
{ USB_DEVICE(0x057c, 0x8501) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x0241) },
{ USB_DEVICE(0x0411, 0x0253) },
/* D-Link */
{ USB_DEVICE(0x2001, 0x3c1a) },
{ USB_DEVICE(0x2001, 0x3c21) },
/* Proware */
{ USB_DEVICE(0x043e, 0x7a13) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x5572) },
/* TRENDnet */
{ USB_DEVICE(0x20f4, 0x724a) },
#endif
#ifdef CONFIG_RT2800USB_UNKNOWN
/*
* Unclear what kind of devices these are (they aren't supported by the
* vendor linux driver).
*/
/* Abocom */
{ USB_DEVICE(0x07b8, 0x3073) },
{ USB_DEVICE(0x07b8, 0x3074) },
/* Alpha Networks */
{ USB_DEVICE(0x14b2, 0x3c08) },
{ USB_DEVICE(0x14b2, 0x3c11) },
/* Amigo */
{ USB_DEVICE(0x0e0b, 0x9031) },
{ USB_DEVICE(0x0e0b, 0x9041) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x166a) },
{ USB_DEVICE(0x0b05, 0x1760) },
{ USB_DEVICE(0x0b05, 0x1761) },
{ USB_DEVICE(0x0b05, 0x1790) },
{ USB_DEVICE(0x0b05, 0x17a7) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3262) },
{ USB_DEVICE(0x13d3, 0x3284) },
{ USB_DEVICE(0x13d3, 0x3322) },
{ USB_DEVICE(0x13d3, 0x3340) },
{ USB_DEVICE(0x13d3, 0x3399) },
{ USB_DEVICE(0x13d3, 0x3400) },
{ USB_DEVICE(0x13d3, 0x3401) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x1003) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x012e) },
{ USB_DEVICE(0x0411, 0x0148) },
{ USB_DEVICE(0x0411, 0x0150) },
/* Corega */
{ USB_DEVICE(0x07aa, 0x0041) },
{ USB_DEVICE(0x07aa, 0x0042) },
{ USB_DEVICE(0x18c5, 0x0008) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c0b) },
/* Encore */
{ USB_DEVICE(0x203d, 0x14a1) },
/* EnGenius */
{ USB_DEVICE(0x1740, 0x0600) },
{ USB_DEVICE(0x1740, 0x0602) },
/* Gemtek */
{ USB_DEVICE(0x15a9, 0x0010) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800c) },
/* Hercules */
{ USB_DEVICE(0x06f8, 0xe036) },
/* Huawei */
{ USB_DEVICE(0x148f, 0xf101) },
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x094b) },
/* LevelOne */
{ USB_DEVICE(0x1740, 0x0605) },
{ USB_DEVICE(0x1740, 0x0615) },
/* Logitec */
{ USB_DEVICE(0x0789, 0x0168) },
{ USB_DEVICE(0x0789, 0x0169) },
/* Motorola */
{ USB_DEVICE(0x100d, 0x9032) },
/* Pegatron */
{ USB_DEVICE(0x05a6, 0x0101) },
{ USB_DEVICE(0x1d4d, 0x0010) },
/* Planex */
{ USB_DEVICE(0x2019, 0xab24) },
{ USB_DEVICE(0x2019, 0xab29) },
/* Qcom */
{ USB_DEVICE(0x18e8, 0x6259) },
/* RadioShack */
{ USB_DEVICE(0x08b9, 0x1197) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x003c) },
{ USB_DEVICE(0x0df6, 0x004a) },
{ USB_DEVICE(0x0df6, 0x004d) },
{ USB_DEVICE(0x0df6, 0x0053) },
{ USB_DEVICE(0x0df6, 0x0069) },
{ USB_DEVICE(0x0df6, 0x006f) },
{ USB_DEVICE(0x0df6, 0x0078) },
/* SMC */
{ USB_DEVICE(0x083a, 0xa512) },
{ USB_DEVICE(0x083a, 0xc522) },
{ USB_DEVICE(0x083a, 0xd522) },
{ USB_DEVICE(0x083a, 0xf511) },
/* Sweex */
{ USB_DEVICE(0x177f, 0x0254) },
/* TP-LINK */
{ USB_DEVICE(0xf201, 0x5370) },
#endif
};
/*
* Firmware functions
*/
int rt2800usb_autorun_detect(struct rt2x00_dev *rt2x00dev) {
__le32 *reg;
u32 fw_mode;
int ret;
reg = (__le32 *) malloc(sizeof(__le32));
if (reg == NULL)
return -ENOMEM;
/* cannot use rt2x00usb_register_read here as it uses different
* mode (MULTI_READ vs. DEVICE_MODE) and does not pass the
* magic value USB_MODE_AUTORUN (0x11) to the device, thus the
* returned value would be invalid.
*/
ret = rt2x00usb_vendor_request(rt2x00dev, USB_DEVICE_MODE,
USB_VENDOR_REQUEST_IN, 0,
USB_MODE_AUTORUN, reg, sizeof(__le32),
REGISTER_TIMEOUT_FIRMWARE);
fw_mode = le32_to_cpu(*reg);
free(reg);
if (ret < 0)
return ret;
if ((fw_mode & 0x00000003) == 2)
return 1;
return 0;
}
static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) {
return FIRMWARE_RT2870;
}
static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len) {
int status;
u32 offset;
u32 length;
int retval;
/*
* Check which section of the firmware we need.
*/
if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2872) ||
rt2x00_rt(rt2x00dev, RT3070)) {
offset = 0;
length = 4096;
} else {
offset = 4096;
length = 4096;
}
/*
* Write firmware to device.
*/
retval = rt2800usb_autorun_detect(rt2x00dev);
if (retval < 0)
return retval;
if (retval) {
rt2x00_info(rt2x00dev,
"Firmware loading not required - NIC in AutoRun mode\n");
__clear_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
} else {
rt2x00_info(rt2x00dev, "Starting register_multiwrite for FIRMWARE_IMAGE_BASE at offset %d len %d sz %lu\n", offset, length, len);
rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
data + offset, length);
}
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
/*
* Send firmware request to device to load firmware,
* we need to specify a long timeout time.
*/
status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE,
0, USB_MODE_FIRMWARE,
REGISTER_TIMEOUT_FIRMWARE);
if (status < 0) {
rt2x00_err(rt2x00dev, "Failed to write Firmware to device\n");
return status;
}
usleep(10);
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
return 0;
}
/*
* Userspace modified start queue to only deal with triggering
* the rx registers and dropping the queue changes and linkages,
* modifying the device signature
*/
static void rt2800usb_start_queue(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2x00_info(rt2x00dev, "Starting RX queue\n");
reg = rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
}
/*
* Userspace modified stop queue to only deal with rx and
* registers, removing the rest and changing the function signature
*/
static void rt2800usb_stop_queue(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2x00_info(rt2x00dev, "Stopping RX queue\n");
reg = rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
}
/*
* Device state switch handlers.
*/
static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) {
u32 reg;
rt2x00_info(rt2x00dev, "rt2800usb_init_registers\n");
/*
* Wait until BBP and RF are ready.
*/
if (rt2800_wait_csr_ready(rt2x00dev))
return -EBUSY;
reg = rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL);
rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
reg = 0;
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
USB_MODE_RESET, REGISTER_TIMEOUT);
rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
return 0;
}
static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) {
u32 reg = 0;
if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev)))
return -EIO;
rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
/*
* Total room for RX frames in kilobytes, PBF might still exceed
* this limit so reduce the number to prevent errors.
*/
/*
* We don't implement real skb and queues and such in userspace
* so hardcode the rt2x00dev->rx->limit queue to 128
*/
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_LIMIT,
((128 * DATA_FRAME_SIZE)
/ 1024) - 3);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_EN, 1);
rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg);
return rt2800_enable_radio(rt2x00dev);
}
static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) {
rt2800_disable_radio(rt2x00dev);
}
static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev,
enum dev_state state) {
if (state == STATE_AWAKE)
rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 2);
else
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0xff, 2);
return 0;
}
static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
enum dev_state state) {
int retval = 0;
switch (state) {
case STATE_RADIO_ON:
rt2x00_info(rt2x00dev, "Setting radio on\n");
/*
* Before the radio can be enabled, the device first has
* to be woken up. After that it needs a bit of time
* to be fully awake and then the radio can be enabled.
*/
rt2800usb_set_state(rt2x00dev, STATE_AWAKE);
msleep(1);
retval = rt2800usb_enable_radio(rt2x00dev);
break;
case STATE_RADIO_OFF:
rt2x00_info(rt2x00dev, "Setting radio off\n");
/*
* After the radio has been disabled, the device should
* be put to sleep for powersaving.
*/
rt2800usb_disable_radio(rt2x00dev);
rt2800usb_set_state(rt2x00dev, STATE_SLEEP);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_OFF:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
case STATE_STANDBY:
case STATE_AWAKE:
rt2x00_info(rt2x00dev, "Setting state awake/standby/sleep\n");
retval = rt2800usb_set_state(rt2x00dev, state);
break;
default:
retval = -ENOTSUPP;
break;
}
if (unlikely(retval))
rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
state, retval);
return retval;
}
/*
* Device probe functions.
*/
static int rt2800usb_efuse_detect(struct rt2x00_dev *rt2x00dev) {
int retval;
retval = rt2800usb_autorun_detect(rt2x00dev);
if (retval < 0)
return retval;
if (retval)
return 1;
return rt2800_efuse_detect(rt2x00dev);
}
static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev) {
int retval;
retval = rt2800usb_efuse_detect(rt2x00dev);
if (retval < 0)
return retval;
if (retval)
retval = rt2800_read_eeprom_efuse(rt2x00dev);
else
retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
EEPROM_SIZE);
return retval;
}
static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = {
[EEPROM_CHIP_ID] = 0x0000,
[EEPROM_VERSION] = 0x0001,
[EEPROM_MAC_ADDR_0] = 0x0002,
[EEPROM_MAC_ADDR_1] = 0x0003,
[EEPROM_MAC_ADDR_2] = 0x0004,
[EEPROM_NIC_CONF0] = 0x001a,
[EEPROM_NIC_CONF1] = 0x001b,
[EEPROM_FREQ] = 0x001d,
[EEPROM_LED_AG_CONF] = 0x001e,
[EEPROM_LED_ACT_CONF] = 0x001f,
[EEPROM_LED_POLARITY] = 0x0020,
[EEPROM_NIC_CONF2] = 0x0021,
[EEPROM_LNA] = 0x0022,
[EEPROM_RSSI_BG] = 0x0023,
[EEPROM_RSSI_BG2] = 0x0024,
[EEPROM_TXMIXER_GAIN_BG] = 0x0024, /* overlaps with RSSI_BG2 */
[EEPROM_RSSI_A] = 0x0025,
[EEPROM_RSSI_A2] = 0x0026,
[EEPROM_TXMIXER_GAIN_A] = 0x0026, /* overlaps with RSSI_A2 */
[EEPROM_EIRP_MAX_TX_POWER] = 0x0027,
[EEPROM_TXPOWER_DELTA] = 0x0028,
[EEPROM_TXPOWER_BG1] = 0x0029,
[EEPROM_TXPOWER_BG2] = 0x0030,
[EEPROM_TSSI_BOUND_BG1] = 0x0037,
[EEPROM_TSSI_BOUND_BG2] = 0x0038,
[EEPROM_TSSI_BOUND_BG3] = 0x0039,
[EEPROM_TSSI_BOUND_BG4] = 0x003a,
[EEPROM_TSSI_BOUND_BG5] = 0x003b,
[EEPROM_TXPOWER_A1] = 0x003c,
[EEPROM_TXPOWER_A2] = 0x0053,
[EEPROM_TXPOWER_INIT] = 0x0068,
[EEPROM_TSSI_BOUND_A1] = 0x006a,
[EEPROM_TSSI_BOUND_A2] = 0x006b,
[EEPROM_TSSI_BOUND_A3] = 0x006c,
[EEPROM_TSSI_BOUND_A4] = 0x006d,
[EEPROM_TSSI_BOUND_A5] = 0x006e,
[EEPROM_TXPOWER_BYRATE] = 0x006f,
[EEPROM_BBP_START] = 0x0078,
};
static const unsigned int rt2800_eeprom_map_ext[EEPROM_WORD_COUNT] = {
[EEPROM_CHIP_ID] = 0x0000,
[EEPROM_VERSION] = 0x0001,
[EEPROM_MAC_ADDR_0] = 0x0002,
[EEPROM_MAC_ADDR_1] = 0x0003,
[EEPROM_MAC_ADDR_2] = 0x0004,
[EEPROM_NIC_CONF0] = 0x001a,
[EEPROM_NIC_CONF1] = 0x001b,
[EEPROM_NIC_CONF2] = 0x001c,
[EEPROM_EIRP_MAX_TX_POWER] = 0x0020,
[EEPROM_FREQ] = 0x0022,
[EEPROM_LED_AG_CONF] = 0x0023,
[EEPROM_LED_ACT_CONF] = 0x0024,
[EEPROM_LED_POLARITY] = 0x0025,
[EEPROM_LNA] = 0x0026,
[EEPROM_EXT_LNA2] = 0x0027,
[EEPROM_RSSI_BG] = 0x0028,
[EEPROM_RSSI_BG2] = 0x0029,
[EEPROM_RSSI_A] = 0x002a,
[EEPROM_RSSI_A2] = 0x002b,
[EEPROM_TXPOWER_BG1] = 0x0030,
[EEPROM_TXPOWER_BG2] = 0x0037,
[EEPROM_EXT_TXPOWER_BG3] = 0x003e,
[EEPROM_TSSI_BOUND_BG1] = 0x0045,
[EEPROM_TSSI_BOUND_BG2] = 0x0046,
[EEPROM_TSSI_BOUND_BG3] = 0x0047,
[EEPROM_TSSI_BOUND_BG4] = 0x0048,
[EEPROM_TSSI_BOUND_BG5] = 0x0049,
[EEPROM_TXPOWER_A1] = 0x004b,
[EEPROM_TXPOWER_A2] = 0x0065,
[EEPROM_EXT_TXPOWER_A3] = 0x007f,
[EEPROM_TSSI_BOUND_A1] = 0x009a,
[EEPROM_TSSI_BOUND_A2] = 0x009b,
[EEPROM_TSSI_BOUND_A3] = 0x009c,
[EEPROM_TSSI_BOUND_A4] = 0x009d,
[EEPROM_TSSI_BOUND_A5] = 0x009e,
[EEPROM_TXPOWER_BYRATE] = 0x00a0,
};
static unsigned int rt2800_eeprom_word_index(struct rt2x00_dev *rt2x00dev,
const enum rt2800_eeprom_word word)
{
const unsigned int *map;
unsigned int index;
if (word >= EEPROM_WORD_COUNT) {
rt2x00_info(rt2x00dev, "invalid EEPROM word %d\n", word);
return 0;
}
if (rt2x00_rt(rt2x00dev, RT3593) ||
rt2x00_rt(rt2x00dev, RT3883))
map = rt2800_eeprom_map_ext;
else
map = rt2800_eeprom_map;
index = map[word];
/* Index 0 is valid only for EEPROM_CHIP_ID.
* Otherwise it means that the offset of the
* given word is not initialized in the map,
* or that the field is not usable on the
* actual chipset.
*/
WARN_ONCE(word != EEPROM_CHIP_ID && index == 0,
"invalid access of EEPROM word %d\n", word);
return index;
}
#if 0
static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev,
const enum rt2800_eeprom_word word)
{
unsigned int index;
index = rt2800_eeprom_word_index(rt2x00dev, word);
return rt2x00_eeprom_addr(rt2x00dev, index);
}
#endif
static u16 rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev,
const enum rt2800_eeprom_word word)
{
unsigned int index;
index = rt2800_eeprom_word_index(rt2x00dev, word);
return rt2x00_eeprom_read(rt2x00dev, index);
}
#if 0
static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev,
const enum rt2800_eeprom_word word, u16 data)
{
unsigned int index;
index = rt2800_eeprom_word_index(rt2x00dev, word);
rt2x00_eeprom_write(rt2x00dev, index, data);
}
static u16 rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev,
const enum rt2800_eeprom_word array,
unsigned int offset)
{
unsigned int index;
index = rt2800_eeprom_word_index(rt2x00dev, array);
return rt2x00_eeprom_read(rt2x00dev, index + offset);
}
#endif
/*
* Driver initialization handlers.
*/
const struct rt2x00_rate rt2x00_supported_rates[12] = {
{
.flags = DEV_RATE_CCK,
.bitrate = 10,
.ratemask = BIT(0),
.plcp = 0x00,
.mcs = RATE_MCS(RATE_MODE_CCK, 0),
},
{
.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
.bitrate = 20,
.ratemask = BIT(1),
.plcp = 0x01,
.mcs = RATE_MCS(RATE_MODE_CCK, 1),
},
{
.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
.bitrate = 55,
.ratemask = BIT(2),
.plcp = 0x02,
.mcs = RATE_MCS(RATE_MODE_CCK, 2),
},
{
.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
.bitrate = 110,
.ratemask = BIT(3),
.plcp = 0x03,
.mcs = RATE_MCS(RATE_MODE_CCK, 3),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 60,
.ratemask = BIT(4),
.plcp = 0x0b,
.mcs = RATE_MCS(RATE_MODE_OFDM, 0),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 90,
.ratemask = BIT(5),
.plcp = 0x0f,
.mcs = RATE_MCS(RATE_MODE_OFDM, 1),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 120,
.ratemask = BIT(6),
.plcp = 0x0a,
.mcs = RATE_MCS(RATE_MODE_OFDM, 2),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 180,
.ratemask = BIT(7),
.plcp = 0x0e,
.mcs = RATE_MCS(RATE_MODE_OFDM, 3),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 240,
.ratemask = BIT(8),
.plcp = 0x09,
.mcs = RATE_MCS(RATE_MODE_OFDM, 4),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 360,
.ratemask = BIT(9),
.plcp = 0x0d,
.mcs = RATE_MCS(RATE_MODE_OFDM, 5),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 480,
.ratemask = BIT(10),
.plcp = 0x08,
.mcs = RATE_MCS(RATE_MODE_OFDM, 6),
},
{
.flags = DEV_RATE_OFDM,
.bitrate = 540,
.ratemask = BIT(11),
.plcp = 0x0c,
.mcs = RATE_MCS(RATE_MODE_OFDM, 7),
},
};
static void rt2x00lib_channel(struct ieee80211_channel *entry,
const int channel, const int tx_power,
const int value)
{
/* XXX: this assumption about the band is wrong for 802.11j */
entry->band = channel <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
entry->center_freq = ieee80211_channel_to_frequency(channel,
entry->band);
entry->hw_value = value;
entry->max_power = tx_power;
entry->max_antenna_gain = 0xff;
}
static void rt2x00lib_rate(struct ieee80211_rate *entry,
const u16 index, const struct rt2x00_rate *rate)
{
entry->flags = 0;
entry->bitrate = rate->bitrate;
entry->hw_value = index;
entry->hw_value_short = index;
if (rate->flags & DEV_RATE_SHORT_PREAMBLE)
entry->flags |= IEEE80211_RATE_SHORT_PREAMBLE;
}
static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
struct hw_mode_spec *spec)
{
struct ieee80211_channel *channels;
struct ieee80211_rate *rates;
unsigned int num_rates;
unsigned int i;
/*
* Modified to set the local copy of the bands but not populate an ieeehw
* record since we don't talk to the hw stack
*/
num_rates = 0;
if (spec->supported_rates & SUPPORT_RATE_CCK)
num_rates += 4;
if (spec->supported_rates & SUPPORT_RATE_OFDM)
num_rates += 8;
channels = (struct ieee80211_channel *) kcalloc(spec->num_channels, sizeof(struct ieee80211_channel), GFP_KERNEL);
if (!channels)
return -ENOMEM;
rates = (struct ieee80211_rate *) kcalloc(num_rates, sizeof(struct ieee80211_rate), GFP_KERNEL);
if (!rates)
goto exit_free_channels;
/*
* Initialize Rate list.
*/
for (i = 0; i < num_rates; i++)
rt2x00lib_rate(&rates[i], i, rt2x00_get_rate(i));
/*
* Initialize Channel list.
*/
for (i = 0; i < spec->num_channels; i++) {
rt2x00lib_channel(&channels[i],
spec->channels[i].channel,
spec->channels_info[i].max_power, i);
}
/*
* Intitialize 802.11b, 802.11g
* Rates: CCK, OFDM.
* Channels: 2.4 GHz
*/
if (spec->supported_bands & SUPPORT_BAND_2GHZ) {
rt2x00dev->bands[NL80211_BAND_2GHZ].n_channels = 14;
rt2x00dev->bands[NL80211_BAND_2GHZ].n_bitrates = num_rates;
rt2x00dev->bands[NL80211_BAND_2GHZ].channels = channels;
rt2x00dev->bands[NL80211_BAND_2GHZ].bitrates = rates;
}
/*
* Intitialize 802.11a
* Rates: OFDM.
* Channels: OFDM, UNII, HiperLAN2.
*/
if (spec->supported_bands & SUPPORT_BAND_5GHZ) {
rt2x00dev->bands[NL80211_BAND_5GHZ].n_channels =
spec->num_channels - 14;
rt2x00dev->bands[NL80211_BAND_5GHZ].n_bitrates =
num_rates - 4;
rt2x00dev->bands[NL80211_BAND_5GHZ].channels = &channels[14];
rt2x00dev->bands[NL80211_BAND_5GHZ].bitrates = &rates[4];
}
return 0;
exit_free_channels:
kfree(channels);
rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
return -ENOMEM;
}
/*
* RF value list for rt28xx
* Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
*/
static const struct rf_channel rf_vals[] = {
{ 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b },
{ 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f },
{ 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b },
{ 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f },
{ 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b },
{ 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f },
{ 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b },
{ 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f },
{ 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b },
{ 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f },
{ 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b },
{ 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f },
{ 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b },
{ 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 },
/* 802.11 UNI / HyperLan 2 */
{ 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 },
{ 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 },
{ 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 },
{ 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 },
{ 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b },
{ 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b },
{ 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 },
{ 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 },
{ 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b },
{ 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 },
{ 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 },
{ 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 },
/* 802.11 HyperLan 2 */
{ 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
{ 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
{ 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
{ 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
{ 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
{ 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
{ 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
{ 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 },
{ 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 },
{ 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 },
{ 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b },
{ 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 },
{ 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b },
{ 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 },
{ 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b },
{ 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 },
/* 802.11 UNII */
{ 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 },
{ 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 },
{ 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f },
{ 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f },
{ 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 },
{ 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 },
{ 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 },
{ 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f },
{ 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 },
{ 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 },
{ 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f },
/* 802.11 Japan */
{ 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b },
{ 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 },
{ 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b },
{ 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 },
{ 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 },
{ 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b },
{ 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 },
};
/*
* RF value list for rt3xxx
* Supports: 2.4 GHz (all) & 5.2 GHz (RF3052 & RF3053)
*/
static const struct rf_channel rf_vals_3x[] = {
{1, 241, 2, 2 },
{2, 241, 2, 7 },
{3, 242, 2, 2 },
{4, 242, 2, 7 },
{5, 243, 2, 2 },
{6, 243, 2, 7 },
{7, 244, 2, 2 },
{8, 244, 2, 7 },
{9, 245, 2, 2 },
{10, 245, 2, 7 },
{11, 246, 2, 2 },
{12, 246, 2, 7 },
{13, 247, 2, 2 },
{14, 248, 2, 4 },
/* 802.11 UNI / HyperLan 2 */
{36, 0x56, 0, 4},
{38, 0x56, 0, 6},
{40, 0x56, 0, 8},
{44, 0x57, 0, 0},
{46, 0x57, 0, 2},
{48, 0x57, 0, 4},
{52, 0x57, 0, 8},
{54, 0x57, 0, 10},
{56, 0x58, 0, 0},
{60, 0x58, 0, 4},
{62, 0x58, 0, 6},
{64, 0x58, 0, 8},
/* 802.11 HyperLan 2 */
{100, 0x5b, 0, 8},
{102, 0x5b, 0, 10},
{104, 0x5c, 0, 0},
{108, 0x5c, 0, 4},
{110, 0x5c, 0, 6},
{112, 0x5c, 0, 8},
{116, 0x5d, 0, 0},
{118, 0x5d, 0, 2},
{120, 0x5d, 0, 4},
{124, 0x5d, 0, 8},
{126, 0x5d, 0, 10},
{128, 0x5e, 0, 0},
{132, 0x5e, 0, 4},
{134, 0x5e, 0, 6},
{136, 0x5e, 0, 8},
{140, 0x5f, 0, 0},
/* 802.11 UNII */
{149, 0x5f, 0, 9},
{151, 0x5f, 0, 11},
{153, 0x60, 0, 1},
{157, 0x60, 0, 5},
{159, 0x60, 0, 7},
{161, 0x60, 0, 9},
{165, 0x61, 0, 1},
{167, 0x61, 0, 3},
{169, 0x61, 0, 5},
{171, 0x61, 0, 7},
{173, 0x61, 0, 9},
};
/*
* RF value list for rt3xxx with Xtal20MHz
* Supports: 2.4 GHz (all) (RF3322)
*/
static const struct rf_channel rf_vals_3x_xtal20[] = {
{1, 0xE2, 2, 0x14},
{2, 0xE3, 2, 0x14},
{3, 0xE4, 2, 0x14},
{4, 0xE5, 2, 0x14},
{5, 0xE6, 2, 0x14},
{6, 0xE7, 2, 0x14},
{7, 0xE8, 2, 0x14},
{8, 0xE9, 2, 0x14},
{9, 0xEA, 2, 0x14},
{10, 0xEB, 2, 0x14},
{11, 0xEC, 2, 0x14},
{12, 0xED, 2, 0x14},
{13, 0xEE, 2, 0x14},
{14, 0xF0, 2, 0x18},
};
static const struct rf_channel rf_vals_3853[] = {
{1, 241, 6, 2},
{2, 241, 6, 7},
{3, 242, 6, 2},
{4, 242, 6, 7},
{5, 243, 6, 2},
{6, 243, 6, 7},
{7, 244, 6, 2},
{8, 244, 6, 7},
{9, 245, 6, 2},
{10, 245, 6, 7},
{11, 246, 6, 2},
{12, 246, 6, 7},
{13, 247, 6, 2},
{14, 248, 6, 4},
{36, 0x56, 8, 4},
{38, 0x56, 8, 6},
{40, 0x56, 8, 8},
{44, 0x57, 8, 0},
{46, 0x57, 8, 2},
{48, 0x57, 8, 4},
{52, 0x57, 8, 8},
{54, 0x57, 8, 10},
{56, 0x58, 8, 0},
{60, 0x58, 8, 4},
{62, 0x58, 8, 6},
{64, 0x58, 8, 8},
{100, 0x5b, 8, 8},
{102, 0x5b, 8, 10},
{104, 0x5c, 8, 0},
{108, 0x5c, 8, 4},
{110, 0x5c, 8, 6},
{112, 0x5c, 8, 8},
{114, 0x5c, 8, 10},
{116, 0x5d, 8, 0},
{118, 0x5d, 8, 2},
{120, 0x5d, 8, 4},
{124, 0x5d, 8, 8},
{126, 0x5d, 8, 10},
{128, 0x5e, 8, 0},
{132, 0x5e, 8, 4},
{134, 0x5e, 8, 6},
{136, 0x5e, 8, 8},
{140, 0x5f, 8, 0},
{149, 0x5f, 8, 9},
{151, 0x5f, 8, 11},
{153, 0x60, 8, 1},
{157, 0x60, 8, 5},
{159, 0x60, 8, 7},
{161, 0x60, 8, 9},
{165, 0x61, 8, 1},
{167, 0x61, 8, 3},
{169, 0x61, 8, 5},
{171, 0x61, 8, 7},
{173, 0x61, 8, 9},
};
static const struct rf_channel rf_vals_5592_xtal20[] = {
/* Channel, N, K, mod, R */
{1, 482, 4, 10, 3},
{2, 483, 4, 10, 3},
{3, 484, 4, 10, 3},
{4, 485, 4, 10, 3},
{5, 486, 4, 10, 3},
{6, 487, 4, 10, 3},
{7, 488, 4, 10, 3},
{8, 489, 4, 10, 3},
{9, 490, 4, 10, 3},
{10, 491, 4, 10, 3},
{11, 492, 4, 10, 3},
{12, 493, 4, 10, 3},
{13, 494, 4, 10, 3},
{14, 496, 8, 10, 3},
{36, 172, 8, 12, 1},
{38, 173, 0, 12, 1},
{40, 173, 4, 12, 1},
{42, 173, 8, 12, 1},
{44, 174, 0, 12, 1},
{46, 174, 4, 12, 1},
{48, 174, 8, 12, 1},
{50, 175, 0, 12, 1},
{52, 175, 4, 12, 1},
{54, 175, 8, 12, 1},
{56, 176, 0, 12, 1},
{58, 176, 4, 12, 1},
{60, 176, 8, 12, 1},
{62, 177, 0, 12, 1},
{64, 177, 4, 12, 1},
{100, 183, 4, 12, 1},
{102, 183, 8, 12, 1},
{104, 184, 0, 12, 1},
{106, 184, 4, 12, 1},
{108, 184, 8, 12, 1},
{110, 185, 0, 12, 1},
{112, 185, 4, 12, 1},
{114, 185, 8, 12, 1},
{116, 186, 0, 12, 1},
{118, 186, 4, 12, 1},
{120, 186, 8, 12, 1},
{122, 187, 0, 12, 1},
{124, 187, 4, 12, 1},
{126, 187, 8, 12, 1},
{128, 188, 0, 12, 1},
{130, 188, 4, 12, 1},
{132, 188, 8, 12, 1},
{134, 189, 0, 12, 1},
{136, 189, 4, 12, 1},
{138, 189, 8, 12, 1},
{140, 190, 0, 12, 1},
{149, 191, 6, 12, 1},
{151, 191, 10, 12, 1},
{153, 192, 2, 12, 1},
{155, 192, 6, 12, 1},
{157, 192, 10, 12, 1},
{159, 193, 2, 12, 1},
{161, 193, 6, 12, 1},
{165, 194, 2, 12, 1},
{184, 164, 0, 12, 1},
{188, 164, 4, 12, 1},
{192, 165, 8, 12, 1},
{196, 166, 0, 12, 1},
};
static const struct rf_channel rf_vals_5592_xtal40[] = {
/* Channel, N, K, mod, R */
{1, 241, 2, 10, 3},
{2, 241, 7, 10, 3},
{3, 242, 2, 10, 3},
{4, 242, 7, 10, 3},
{5, 243, 2, 10, 3},
{6, 243, 7, 10, 3},
{7, 244, 2, 10, 3},
{8, 244, 7, 10, 3},
{9, 245, 2, 10, 3},
{10, 245, 7, 10, 3},
{11, 246, 2, 10, 3},
{12, 246, 7, 10, 3},
{13, 247, 2, 10, 3},
{14, 248, 4, 10, 3},
{36, 86, 4, 12, 1},
{38, 86, 6, 12, 1},
{40, 86, 8, 12, 1},
{42, 86, 10, 12, 1},
{44, 87, 0, 12, 1},
{46, 87, 2, 12, 1},
{48, 87, 4, 12, 1},
{50, 87, 6, 12, 1},
{52, 87, 8, 12, 1},
{54, 87, 10, 12, 1},
{56, 88, 0, 12, 1},
{58, 88, 2, 12, 1},
{60, 88, 4, 12, 1},
{62, 88, 6, 12, 1},
{64, 88, 8, 12, 1},
{100, 91, 8, 12, 1},
{102, 91, 10, 12, 1},
{104, 92, 0, 12, 1},
{106, 92, 2, 12, 1},
{108, 92, 4, 12, 1},
{110, 92, 6, 12, 1},
{112, 92, 8, 12, 1},
{114, 92, 10, 12, 1},
{116, 93, 0, 12, 1},
{118, 93, 2, 12, 1},
{120, 93, 4, 12, 1},
{122, 93, 6, 12, 1},
{124, 93, 8, 12, 1},
{126, 93, 10, 12, 1},
{128, 94, 0, 12, 1},
{130, 94, 2, 12, 1},
{132, 94, 4, 12, 1},
{134, 94, 6, 12, 1},
{136, 94, 8, 12, 1},
{138, 94, 10, 12, 1},
{140, 95, 0, 12, 1},
{149, 95, 9, 12, 1},
{151, 95, 11, 12, 1},
{153, 96, 1, 12, 1},
{155, 96, 3, 12, 1},
{157, 96, 5, 12, 1},
{159, 96, 7, 12, 1},
{161, 96, 9, 12, 1},
{165, 97, 1, 12, 1},
{184, 82, 0, 12, 1},
{188, 82, 4, 12, 1},
{192, 82, 8, 12, 1},
{196, 83, 0, 12, 1},
};
static const struct rf_channel rf_vals_7620[] = {
{1, 0x50, 0x99, 0x99, 1},
{2, 0x50, 0x44, 0x44, 2},
{3, 0x50, 0xEE, 0xEE, 2},
{4, 0x50, 0x99, 0x99, 3},
{5, 0x51, 0x44, 0x44, 0},
{6, 0x51, 0xEE, 0xEE, 0},
{7, 0x51, 0x99, 0x99, 1},
{8, 0x51, 0x44, 0x44, 2},
{9, 0x51, 0xEE, 0xEE, 2},
{10, 0x51, 0x99, 0x99, 3},
{11, 0x52, 0x44, 0x44, 0},
{12, 0x52, 0xEE, 0xEE, 0},
{13, 0x52, 0x99, 0x99, 1},
{14, 0x52, 0x33, 0x33, 3},
};
static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
unsigned int tx_chains, rx_chains;
u32 reg;
/*
* Gutted for userspace mode
* */
/*
* Initialize hw_mode information.
*/
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
switch (rt2x00dev->chip.rf) {
case RF2720:
case RF2820:
spec->num_channels = 14;
spec->channels = rf_vals;
break;
case RF2750:
case RF2850:
spec->num_channels = ARRAY_SIZE(rf_vals);
spec->channels = rf_vals;
break;
case RF2020:
case RF3020:
case RF3021:
case RF3022:
case RF3070:
case RF3290:
case RF3320:
case RF3322:
case RF5350:
case RF5360:
case RF5362:
case RF5370:
case RF5372:
case RF5390:
case RF5392:
spec->num_channels = 14;
if (rt2800_clk_is_20mhz(rt2x00dev))
spec->channels = rf_vals_3x_xtal20;
else
spec->channels = rf_vals_3x;
break;
case RF7620:
spec->num_channels = ARRAY_SIZE(rf_vals_7620);
spec->channels = rf_vals_7620;
break;
case RF3052:
case RF3053:
spec->num_channels = ARRAY_SIZE(rf_vals_3x);
spec->channels = rf_vals_3x;
break;
case RF3853:
spec->num_channels = ARRAY_SIZE(rf_vals_3853);
spec->channels = rf_vals_3853;
break;
case RF5592:
reg = rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX);
if (rt2x00_get_field32(reg, MAC_DEBUG_INDEX_XTAL)) {
spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal40);
spec->channels = rf_vals_5592_xtal40;
} else {
spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal20);
spec->channels = rf_vals_5592_xtal20;
}
break;
}
if (WARN_ON_ONCE(!spec->channels))
return -ENODEV;
spec->supported_bands = SUPPORT_BAND_2GHZ;
if (spec->num_channels > 14)
spec->supported_bands |= SUPPORT_BAND_5GHZ;
/*
* Initialize HT information.
*/
if (!rt2x00_rf(rt2x00dev, RF2020))
spec->ht.ht_supported = true;
else
spec->ht.ht_supported = false;
spec->ht.cap =
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40;
tx_chains = rt2x00dev->default_ant.tx_chain_num;
rx_chains = rt2x00dev->default_ant.rx_chain_num;
if (tx_chains >= 2)
spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
spec->ht.cap |= rx_chains << IEEE80211_HT_CAP_RX_STBC_SHIFT;
spec->ht.ampdu_factor = (rx_chains > 1) ? 3 : 2;
spec->ht.ampdu_density = 4;
spec->ht.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
if (tx_chains != rx_chains) {
spec->ht.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
spec->ht.mcs.tx_params |=
(tx_chains - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
}
switch (rx_chains) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
/* fall through */
case 2:
spec->ht.mcs.rx_mask[1] = 0xff;
/* fall through */
case 1:
spec->ht.mcs.rx_mask[0] = 0xff;
spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
break;
}
/*
* Create channel information array
*/
info = kcalloc(spec->num_channels, sizeof(struct channel_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
switch (rt2x00dev->chip.rf) {
case RF2020:
case RF3020:
case RF3021:
case RF3022:
case RF3320:
case RF3052:
case RF3053:
case RF3070:
case RF3290:
case RF3853:
case RF5350:
case RF5360:
case RF5362:
case RF5370:
case RF5372:
case RF5390:
case RF5392:
case RF5592:
case RF7620:
__set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
break;
}
return 0;
}
struct rt2800usb_userspace_firmware {
uint8_t *data;
size_t size;
};
int rt2800usb_userspace_load_firmware(struct rt2x00_dev *rt2x00dev,
struct rt2800usb_userspace_firmware **fw) {
struct userspace_wifi_context *userspace_context =
(struct userspace_wifi_context *) rt2x00dev->userspace_context;
int retval;
*fw = (struct rt2800usb_userspace_firmware *) malloc(sizeof(struct rt2800usb_userspace_firmware));
if (*fw == NULL) {
rt2x00_err(rt2x00dev, "Unable to allocate memory to read firmware file.");
return -ENOMEM;
}
retval = (*userspace_context->load_firmware_file)(userspace_context,
FIRMWARE_RT2870,
NULL, 0,
&(*fw)->data, &(*fw)->size);
if (retval != 0) {
rt2x00_err(rt2x00dev, "Could not load firmware %s, cannot continue.", FIRMWARE_RT2870);
return -1;
}
rt2x00_info(rt2x00dev, "Firmware detected - version: %d.%d\n",
(*fw)->data[(*fw)->size - 4], (*fw)->data[(*fw)->size - 3]);
retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, (*fw)->data, (*fw)->size);
switch (retval) {
case FW_OK:
break;
case FW_BAD_CRC:
rt2x00_err(rt2x00dev, "Firmware checksum error\n");
goto exit;
case FW_BAD_LENGTH:
rt2x00_err(rt2x00dev, "Invalid firmware file length (len=%zu)\n",
(*fw)->size);
goto exit;
case FW_BAD_VERSION:
rt2x00_err(rt2x00dev, "Current firmware does not support detected chipset\n");
goto exit;
}
return (*fw)->size;
exit:
free((*fw)->data);
free(*fw);
*fw = NULL;
return -EINVAL;
}
void rt2800usb_userspace_free_firmware(struct rt2800usb_userspace_firmware *fw) {
if (!fw)
return;
if (fw->data)
free(fw->data);
free(fw);
}
static const struct rt2800_ops rt2800usb_rt2800_ops = {
.register_read = rt2x00usb_register_read,
.register_read_lock = rt2x00usb_register_read_lock,
.register_write = rt2x00usb_register_write,
.register_write_lock = rt2x00usb_register_write_lock,
.register_multiread = rt2x00usb_register_multiread,
.register_multiwrite = rt2x00usb_register_multiwrite,
.regbusy_read = rt2x00usb_regbusy_read,
.read_eeprom = rt2800usb_read_eeprom,
.drv_write_firmware = rt2800usb_write_firmware,
.drv_init_registers = rt2800usb_init_registers,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.get_firmware_name = rt2800usb_get_firmware_name,
.check_firmware = rt2800_check_firmware,
.load_firmware = rt2800_load_firmware,
.initialize = rt2x00usb_initialize,
.set_device_state = rt2800usb_set_device_state,
.rfkill_poll = rt2800_rfkill_poll,
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.vco_calibration = rt2800_vco_calibration,
.config_filter = rt2800_config_filter,
.config_intf = rt2800_config_intf,
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
.start_queue = rt2800usb_start_queue,
.stop_queue = rt2800usb_stop_queue
};
static const struct rt2x00_ops rt2800usb_ops = {
.drv_data_size = sizeof(struct rt2800_drv_data),
.max_ap_intf = 8,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.lib = &rt2800usb_rt2x00_ops,
.drv = &rt2800usb_rt2800_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};
/*
* Userspace channel set function
*/
int rt2800usb_userspace_set_channel(struct userspace_wifi_dev *dev, int channel, enum nl80211_chan_width width) {
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *) dev->dev_data;
struct ieee80211_conf dot11conf;
enum nl80211_band band;
memset(&dot11conf, 0, sizeof(struct ieee80211_conf));
dot11conf.chandef.width = width;
/*
* TODO handle 5ghz
*/
if (channel >= 1 && channel <= 14) {
dot11conf.chandef.chan = &rt2x00dev->bands[NL80211_BAND_2GHZ].channels[channel - 1];
band = NL80211_BAND_2GHZ;
} else {
return -EINVAL;
}
/* Queue must be stopped to set the channel state */
rt2800usb_stop_queue(rt2x00dev);
/* Try to set the channel */
rt2x00lib_config(rt2x00dev, &dot11conf, IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_MONITOR);
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
/* Set the channel copy */
rt2x00dev->rf_channel = channel;
rt2x00dev->rf_band = band;
/* Try to start the RX engine */
rt2800usb_start_queue(rt2x00dev);
return 0;
}
/*
* Userspace LED control function
*/
int rt2800usb_userspace_set_led(struct userspace_wifi_dev *dev, bool enable) {
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *) dev->dev_data;
unsigned int ledmode =
rt2x00_get_field16(rt2x00dev->led_mcu_reg,
EEPROM_FREQ_LED_MODE);
rt2800_mcu_request(rt2x00dev, MCU_LED, 0xff, ledmode, enable ? 0x60 : 0x20);
return 1;
}
/*
* From rt2800lib
*/
void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev,
unsigned short *txwi_size,
unsigned short *rxwi_size)
{
switch (rt2x00dev->chip.rt) {
case RT3593:
case RT3883:
*txwi_size = TXWI_DESC_SIZE_4WORDS;
*rxwi_size = RXWI_DESC_SIZE_5WORDS;
break;
case RT5592:
case RT6352:
*txwi_size = TXWI_DESC_SIZE_5WORDS;
*rxwi_size = RXWI_DESC_SIZE_6WORDS;
break;
default:
*txwi_size = TXWI_DESC_SIZE_4WORDS;
*rxwi_size = RXWI_DESC_SIZE_4WORDS;
break;
}
}
/**
* _rt2x00_desc_read - Read a word from the hardware descriptor.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
*/
static inline __le32 _rt2x00_desc_read(__le32 *desc, const u8 word)
{
return desc[word];
}
/**
* rt2x00_desc_read - Read a word from the hardware descriptor, this
* function will take care of the byte ordering.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
*/
static inline u32 rt2x00_desc_read(__le32 *desc, const u8 word)
{
return le32_to_cpu(_rt2x00_desc_read(desc, word));
}
static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2)
{
s8 rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
s8 rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
s8 rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
u16 eeprom;
u8 offset0;
u8 offset1;
u8 offset2;
if (rt2x00dev->curr_band == NL80211_BAND_2GHZ) {
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG);
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2);
offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
} else {
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A);
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2);
offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
}
/*
* Convert the value from the descriptor into the RSSI value
* If the value in the descriptor is 0, it is considered invalid
* and the default (extremely low) rssi value is assumed
*/
rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
/*
* mac80211 only accepts a single RSSI value. Calculating the
* average doesn't deliver a fair answer either since -60:-60 would
* be considered equally good as -50:-70 while the second is the one
* which gives less energy...
*/
rssi0 = max(rssi0, rssi1);
return (int)max(rssi0, rssi2);
}
/* Function like the rt2x00 pull, but return the amount of data the caller
* needs to offset the buffer by */
unsigned int rt2x00queue_remove_l2pad(uint8_t *buf, unsigned int buf_len, unsigned int hdr_len)
{
unsigned int l2pad = (buf_len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
if (!l2pad)
return buf_len;
memmove(buf + l2pad, buf, hdr_len);
return l2pad;
}
/*
* LibUSB usb transfer completion
* RXI parsing extracted from rt2800usb_fill_rxdone and rt2800_process_rxwi
*/
void rt2800usb_libusb_transfer_fn(struct libusb_transfer *transfer) {
struct userspace_wifi_dev *dev = (struct userspace_wifi_dev *) transfer->user_data;
struct rt2x00_dev * rt2x00dev = (struct rt2x00_dev *) (dev)->dev_data;
/*
* Working buffer ptr we move around while emulating skb_trim and skb_pull
*/
unsigned char *workbuf = transfer->buffer;
unsigned int workbuf_len = transfer->actual_length;
__le32 *rxi = (__le32 *) workbuf;
__le32 *rxd;
u32 word;
unsigned int rx_pkt_len;
struct userspace_wifi_rx_signal rx_signal;
unsigned int mpdu_sz;
unsigned int pad = 0;
unsigned int header_len = 0;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
/* Timeout errors get re-submitted, other errors get bounced up */
if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
rt2x00_err(rt2x00dev, "Radio request failed: %d %s - device no longer available",
transfer->status, libusb_error_name(transfer->status));
} else if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) {
rt2x00_err(rt2x00dev, "Radio request failed: %d %s",
transfer->status, libusb_error_name(transfer->status));
}
userspace_wifi_lock(dev->context);
if (dev->usb_transfer_active)
libusb_submit_transfer(transfer);
userspace_wifi_unlock(dev->context);
return;
}
/*
* RX frame format is :
* | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
* |<------------ rx_pkt_len -------------->|
*/
if (transfer->actual_length < RXINFO_DESC_SIZE + rt2x00dev->rxwi_size) {
/*
* Silently ignore and re-queue on runt transfers
*/
userspace_wifi_lock(dev->context);
if (dev->usb_transfer_active)
libusb_submit_transfer(transfer);
userspace_wifi_unlock(dev->context);
return;
}
memset(&rx_signal, 0, sizeof(struct userspace_wifi_rx_signal));
rx_signal.channel = rt2x00dev->rf_channel;
rx_signal.band = rt2x00dev->rf_band;
/*
* Get packet length of RXWI + payload + pad from the header of the packet
*/
word = rt2x00_desc_read(rxi, 0);
rx_pkt_len = rt2x00_get_field32(word, RXINFO_W0_USB_DMA_RX_PKT_LEN);
if (rx_pkt_len == 0 || rx_pkt_len > (transfer->actual_length - RXINFO_DESC_SIZE)) {
/*
* Ignore errors in packet size and re-queue
*/
userspace_wifi_lock(dev->context);
if (dev->usb_transfer_active)
libusb_submit_transfer(transfer);
userspace_wifi_unlock(dev->context);
return;
}
workbuf = workbuf + RXINFO_DESC_SIZE;
workbuf_len -= RXINFO_DESC_SIZE;
rxd = (__le32 *)(workbuf + rx_pkt_len);
/*
* It is now safe to read the descriptor on all architectures.
*/
word = rt2x00_desc_read((__le32 *) rxd, 0);
if (rt2x00_get_field32(word, RXD_W0_L2PAD))
pad = 1;
if (rt2x00_get_field32(word, RXD_W0_CRC_ERROR))
rx_signal.crc_valid = false;
else
rx_signal.crc_valid = true;
/*
* Remove RXD descriptor from end of buffer.
*/
workbuf_len = rx_pkt_len;
/*
* Remove the padding from the end of the buffer
workbuf_len -= pad;
*/
rxi = (__le32 *) workbuf;
word = rt2x00_desc_read(rxi, 0);
mpdu_sz = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
word = rt2x00_desc_read(rxi, 1);
if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI)) {
rx_signal.short_gi = true;
}
if (rt2x00_get_field32(word, RXWI_W1_BW)) {
rx_signal.chan_width = NL80211_CHAN_WIDTH_40;
} else {
rx_signal.chan_width = NL80211_CHAN_WIDTH_20_NOHT;
}
/*
* Detect RX rate, always use MCS as signal type.
*/
rx_signal.mcs = rt2x00_get_field32(word, RXWI_W1_MCS);
/*
* Mask of 0x8 bit to remove the short preamble flag.
*/
if (rt2x00_get_field32(word, RXWI_W1_PHYMODE) == RATE_MODE_CCK)
rx_signal.mcs &= ~0x8;
word = rt2x00_desc_read(rxi, 2);
/*
* Convert descriptor AGC value to RSSI value.
*/
rx_signal.signal = rt2800_agc_to_rssi(rt2x00dev, word);
/*
* Remove the rxwi header
*/
workbuf = workbuf + rt2x00dev->rxwi_size;
workbuf_len -= rt2x00dev->rxwi_size;
if (mpdu_sz > workbuf_len) {
/*
* If we get a mpdu that can't fit in our rx, throw it out and re-queue a command
*/
userspace_wifi_lock(dev->context);
if (dev->usb_transfer_active)
libusb_submit_transfer(transfer);
userspace_wifi_unlock(dev->context);
}
/*
* The 802.11 header needs to be padded to 4 bytes; make sure it is.
*/
header_len = ieee80211_get_hdrlen_from_buf(workbuf, mpdu_sz);
if (header_len < workbuf_len && pad) {
pad = rt2x00queue_remove_l2pad(workbuf, workbuf_len, header_len);
workbuf = workbuf + pad;
}
/*
* Pass the data on to a callback. We use a stack-allocated signal because this
* is all iterative.
*/
if (dev->context->handle_packet_rx) {
dev->context->handle_packet_rx(dev->context, dev, &rx_signal, workbuf, mpdu_sz);
}
/*
* Resubmit the request
*/
userspace_wifi_lock(dev->context);
if (dev->usb_transfer_active)
libusb_submit_transfer(transfer);
userspace_wifi_unlock(dev->context);
}
int rt2800usb_userspace_start_capture(struct userspace_wifi_dev *dev) {
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *) (dev)->dev_data;
/* Set up the bulk transfer */
if (dev->usb_transfer_buffer == NULL) {
dev->usb_transfer_buffer = (unsigned char *) malloc(4000);
if (dev->usb_transfer_buffer == NULL)
return -ENOMEM;
}
if (dev->usb_transfer == NULL) {
dev->usb_transfer = libusb_alloc_transfer(0);
}
libusb_fill_bulk_transfer(dev->usb_transfer,
rt2x00dev->dev,
rt2x00dev->usb_bulk_in_endp,
dev->usb_transfer_buffer,
4000,
&rt2800usb_libusb_transfer_fn,
dev,
500);
rt2800usb_start_queue(rt2x00dev);
userspace_wifi_lock(dev->context);
dev->usb_transfer_active = true;
libusb_submit_transfer(dev->usb_transfer);
userspace_wifi_unlock(dev->context);
return 0;
}
void rt2800usb_userspace_stop_capture(struct userspace_wifi_dev *dev) {
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *) (dev)->dev_data;
userspace_wifi_lock(dev->context);
rt2800usb_stop_queue(rt2x00dev);
dev->usb_transfer_active = false;
libusb_cancel_transfer(dev->usb_transfer);
userspace_wifi_unlock(dev->context);
}
int rt2800usb_open_device(struct userspace_wifi_probe_dev *dev,
struct userspace_wifi_dev **udev) {
struct rt2x00_dev *rt2x00dev;
int r;
struct rt2800usb_userspace_firmware *firmware;
*udev = (struct userspace_wifi_dev *) malloc(sizeof(struct userspace_wifi_dev));
if (*udev == NULL)
return -ENOMEM;
memset(*udev, 0, sizeof(struct userspace_wifi_dev));
(*udev)->context = dev->context;
(*udev)->dev_data = malloc(sizeof(struct rt2x00_dev));
if ((*udev)->dev_data == NULL) {
free(*udev);
return -ENOMEM;
}
(*udev)->set_channel = rt2800usb_userspace_set_channel;
(*udev)->set_led = rt2800usb_userspace_set_led;
(*udev)->start_capture = rt2800usb_userspace_start_capture;
(*udev)->stop_capture = rt2800usb_userspace_stop_capture;
/*
* Populate the 2x00dev record w/ ops, copies of pointers to
* structures we need to pull in on deeper levels like usb and
* userspace context, etc
*/
rt2x00dev = (struct rt2x00_dev *) (*udev)->dev_data;
memset(rt2x00dev, 0, sizeof(struct rt2x00_dev));
rt2x00dev->userspace_dev = udev;
rt2x00dev->libusb_context = dev->context->libusb_context;
rt2x00dev->userspace_context = dev->context;
pthread_mutex_init(&rt2x00dev->usb_control_mutex, NULL);
pthread_cond_init(&rt2x00dev->usb_control_cond, NULL);
rt2x00dev->ops = &rt2800usb_ops;
rt2x00dev->base_dev = dev->dev;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
/*
* Allocate the low level cache ops
*/
r = rt2x00usb_alloc_reg(rt2x00dev);
if (r != 0) {
free(rt2x00dev);
free(*udev);
return r;
}
/*
* Open the usb device, disconnecting any kernel drivers and other attachments
*/
r = libusb_open(rt2x00dev->base_dev, &rt2x00dev->dev);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to open device: %s\n",
libusb_error_name(r));
rt2x00usb_free(rt2x00dev);
free(*udev);
return -EPIPE;
}
libusb_set_auto_detach_kernel_driver(rt2x00dev->dev, 1);
r = libusb_claim_interface(rt2x00dev->dev, 0);
if (r != LIBUSB_SUCCESS) {
rt2x00_err(rt2x00dev, "Failed to claim device: %s\n",
libusb_error_name(r));
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return -EPIPE;
}
/*
* initialize the lowlevel 2x00 and find the endpoints
*/
r = rt2x00usb_initialize(rt2x00dev);
if (r != 0) {
rt2x00_err(rt2x00dev, "Failed to initialize rt2x00 layer\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
}
/*
* flag the device as present
*/
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
r = rt2800_probe_rt(rt2x00dev);
if (r != 0) {
rt2x00_err(rt2x00dev, "Failed to probe rt info\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
}
/*
* Check if we're in autorun mode
*/
r = rt2800usb_autorun_detect(rt2x00dev);
/*
* Allocate eeprom data.
*/
memset(rt2x00dev->eeprom, 0, EEPROM_SIZE);
r = rt2800_validate_eeprom(rt2x00dev);
if (r) {
rt2x00_err(rt2x00dev, "Failed to validate eeprom\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
}
r = rt2800_init_eeprom(rt2x00dev);
if (r) {
rt2x00_err(rt2x00dev, "Failed to init eeprom\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
}
/* Propogate the mac up */
memcpy((*udev)->dev_mac, rt2x00dev->mac, 6);
/* Propogate the serial from the probe device to the final */
memcpy((*udev)->usb_serial, dev->usb_serial, 64);
#if 0
for (unsigned int x = 0; x < EEPROM_SIZE; x++)
printf("%02x ", ((uint8_t *) rt2x00dev->eeprom) [x] & 0xFF);
printf("\n");
printf("Radio MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
rt2x00dev->mac[0], rt2x00dev->mac[1], rt2x00dev->mac[2],
rt2x00dev->mac[3], rt2x00dev->mac[4], rt2x00dev->mac[5]);
#endif
/*
* Load and check our firmware file
*/
r = rt2800usb_userspace_load_firmware(rt2x00dev, &firmware);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to load firmware file on host\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
}
/*
* Load it into the device
*/
r = rt2800_load_firmware(rt2x00dev, firmware->data, firmware->size);
if (r < 0) {
rt2x00_err(rt2x00dev, "Firmware load failed: %d %s\n", r, strerror(r));
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
} else {
rt2x00_info(rt2x00dev, "Firmware load succeeded!\n");
}
/*
* Power on the MCU
*/
r = rt2800usb_set_device_state(rt2x00dev, STATE_AWAKE);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to awaken radio\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
} else {
rt2x00_info(rt2x00dev, "Radio woken up!\n");
}
/*
* Startup the device
*/
r = rt2x00lib_start(rt2x00dev);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to start device\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
} else {
rt2x00_info(rt2x00dev, "Device started!\n");
}
/*
* Enable the radio
*/
r = rt2800usb_enable_radio(rt2x00dev);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to enable the radio\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
} else {
rt2x00_info(rt2x00dev, "Radio enabled!\n");
}
rt2800_get_txwi_rxwi_size(rt2x00dev, &rt2x00dev->txwi_size, &rt2x00dev->rxwi_size);
/*
* probe hw modes
*/
r = rt2800_probe_hw_mode(rt2x00dev);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to probe 2800_hw_mode\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
} else {
rt2x00_info(rt2x00dev, "RT2800 Hw modes probed!\n");
}
r = rt2x00lib_probe_hw_modes(rt2x00dev, &rt2x00dev->spec);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to probe 2x00_hw_modes\n");
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
} else {
rt2x00_info(rt2x00dev, "RT2x00 Hw modes probed!\n");
}
/* Radio must be enabled, but rx disabled, to set the channel and antenna values */
rt2800usb_stop_queue(rt2x00dev);
struct ieee80211_hw hw;
memset(&hw, 0, sizeof(struct ieee80211_hw));
hw.priv = rt2x00dev;
struct ieee80211_vif vif;
memset(&vif, 0, sizeof(struct ieee80211_vif));
vif.type = NL80211_IFTYPE_MONITOR;
memcpy(vif.addr, rt2x00dev->mac, 6);
r = rt2x00mac_add_interface(&hw, &vif);
if (r < 0) {
rt2x00_err(rt2x00dev, "Failed to add vif... %s\n", strerror(errno));
libusb_close(rt2x00dev->dev);
rt2x00usb_free(rt2x00dev);
free(*udev);
return r;
} else {
rt2x00_info(rt2x00dev, "We think we added a vif...!\n");
}
/*
rt2800usb_userspace_set_channel(*udev, 1, NL80211_CHAN_WIDTH_20_NOHT);
*/
return 0;
}
int rt2800usb_probe_device(struct libusb_device_descriptor *desc,
struct userspace_wifi_probe_dev **probe_dev) {
unsigned int x;
for (x = 0; x < sizeof(rt2800usb_device_table) / sizeof(struct usb_device_id); x++) {
if (rt2800usb_device_table[x].match_flags != USB_DEVICE_ID_MATCH_DEVICE)
continue;
if (rt2800usb_device_table[x].idVendor == desc->idVendor &&
rt2800usb_device_table[x].idProduct == desc->idProduct) {
*probe_dev = (struct userspace_wifi_probe_dev *) malloc(sizeof(struct userspace_wifi_probe_dev));
(*probe_dev)->device_id_match = &(rt2800usb_device_table[x]);
(*probe_dev)->driver_name = strdup("rt2800usb");
(*probe_dev)->device_type = strdup("rt2800usb");
(*probe_dev)->open_device = &rt2800usb_open_device;
return 1;
}
}
return 0;
}