diff options
author | 2015-08-04 12:17:53 -0700 | |
---|---|---|
committer | 2015-08-04 15:44:42 -0700 | |
commit | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch) | |
tree | 1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/drivers/staging/rtl8712 | |
parent | 98260f3884f4a202f9ca5eabed40b1354c489b29 (diff) |
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base.
It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and
the base is:
commit 0917f823c59692d751951bf5ea699a2d1e2f26a2
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Sat Jul 25 12:13:34 2015 +0200
Prepare v4.1.3-rt3
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
We lose all the git history this way and it's not good. We
should apply another opnfv project repo in future.
Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/drivers/staging/rtl8712')
101 files changed, 30490 insertions, 0 deletions
diff --git a/kernel/drivers/staging/rtl8712/Kconfig b/kernel/drivers/staging/rtl8712/Kconfig new file mode 100644 index 000000000..f160eee52 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/Kconfig @@ -0,0 +1,17 @@ +config R8712U + tristate "RealTek RTL8712U (RTL8192SU) Wireless LAN NIC driver" + depends on WLAN && USB + select WIRELESS_EXT + select WEXT_PRIV + select FW_LOADER + ---help--- + This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130. + If built as a module, it will be called r8712u. + +config R8712_TX_AGGR + bool "Realtek RTL8712U Transmit Aggregation code" + depends on R8712U && BROKEN + ---help--- + This option provides transmit aggregation for the Realtek RTL8712 USB device. + + diff --git a/kernel/drivers/staging/rtl8712/Makefile b/kernel/drivers/staging/rtl8712/Makefile new file mode 100644 index 000000000..6f8500c2d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/Makefile @@ -0,0 +1,34 @@ +r8712u-y := \ + rtl871x_cmd.o \ + rtl8712_cmd.o \ + rtl871x_security.o \ + rtl871x_eeprom.o \ + rtl8712_efuse.o \ + hal_init.o \ + usb_halinit.o \ + usb_ops.o \ + usb_ops_linux.o \ + rtl871x_io.o \ + rtl8712_io.o \ + rtl871x_ioctl_linux.o \ + rtl871x_ioctl_rtl.o \ + rtl871x_ioctl_set.o \ + rtl8712_led.o \ + rtl871x_mlme.o \ + ieee80211.o \ + rtl871x_mp_ioctl.o \ + rtl871x_mp.o \ + mlme_linux.o \ + recv_linux.o \ + xmit_linux.o \ + usb_intf.o \ + os_intfs.o \ + rtl871x_pwrctrl.o \ + rtl8712_recv.o \ + rtl871x_recv.o \ + rtl871x_sta_mgt.o \ + rtl871x_xmit.o \ + rtl8712_xmit.o + +obj-$(CONFIG_R8712U) := r8712u.o + diff --git a/kernel/drivers/staging/rtl8712/TODO b/kernel/drivers/staging/rtl8712/TODO new file mode 100644 index 000000000..d8dfe5bfe --- /dev/null +++ b/kernel/drivers/staging/rtl8712/TODO @@ -0,0 +1,13 @@ +TODO: +- merge Realtek's bugfixes and new features into the driver +- switch to use LIB80211 +- switch to use MAC80211 +- checkpatch.pl fixes - only a few remain + +Please send any patches to Greg Kroah-Hartman <greg@kroah.com>, +Larry Finger <Larry.Finger@lwfinger.net> and +Florian Schilhabel <florian.c.schilhabel@googlemail.com>. + + + + diff --git a/kernel/drivers/staging/rtl8712/basic_types.h b/kernel/drivers/staging/rtl8712/basic_types.h new file mode 100644 index 000000000..7561bed5d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/basic_types.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __BASIC_TYPES_H__ +#define __BASIC_TYPES_H__ + +#define SUCCESS 0 +#define FAIL (-1) + +#include <linux/types.h> + +#define SIZE_T __kernel_size_t +#define sint signed int +#define FIELD_OFFSET(s, field) ((addr_t)&((s *)(0))->field) + +/* Should we extend this to be host_addr_t and target_addr_t for case: + * host : x86_64 + * target : mips64 + */ +#define addr_t unsigned long + +#define MEM_ALIGNMENT_OFFSET (sizeof(SIZE_T)) +#define MEM_ALIGNMENT_PADDING (sizeof(SIZE_T) - 1) + +#endif /*__BASIC_TYPES_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/drv_types.h b/kernel/drivers/staging/rtl8712/drv_types.h new file mode 100644 index 000000000..e62543d22 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/drv_types.h @@ -0,0 +1,193 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +/*--------------------------------------------------------------------- + + For type defines and data structure defines + +-----------------------------------------------------------------------*/ +#ifndef __DRV_TYPES_H__ +#define __DRV_TYPES_H__ + +struct _adapter; + +#include "osdep_service.h" +#include "wlan_bssdef.h" +#include "rtl8712_spec.h" +#include "rtl8712_hal.h" +#include <linux/mutex.h> +#include <linux/completion.h> + +enum _NIC_VERSION { + RTL8711_NIC, + RTL8712_NIC, + RTL8713_NIC, + RTL8716_NIC +}; + +struct _adapter; + +struct qos_priv { + /* bit mask option: u-apsd, s-apsd, ts, block ack... */ + unsigned int qos_option; +}; + +#include "rtl871x_ht.h" +#include "rtl871x_cmd.h" +#include "rtl871x_xmit.h" +#include "rtl871x_recv.h" +#include "rtl871x_security.h" +#include "rtl871x_pwrctrl.h" +#include "rtl871x_io.h" +#include "rtl871x_eeprom.h" +#include "sta_info.h" +#include "rtl871x_mlme.h" +#include "rtl871x_mp.h" +#include "rtl871x_debug.h" +#include "rtl871x_rf.h" +#include "rtl871x_event.h" +#include "rtl871x_led.h" + +#define SPEC_DEV_ID_DISABLE_HT BIT(1) + +struct specific_device_id { + u32 flags; + u16 idVendor; + u16 idProduct; + +}; + +struct registry_priv { + u8 chip_version; + u8 rfintfs; + u8 lbkmode; + u8 hci; + u8 network_mode; /*infra, ad-hoc, auto*/ + struct ndis_802_11_ssid ssid; + u8 channel;/* ad-hoc support requirement */ + u8 wireless_mode;/* A, B, G, auto */ + u8 vrtl_carrier_sense; /*Enable, Disable, Auto*/ + u8 vcs_type;/*RTS/CTS, CTS-to-self*/ + u16 rts_thresh; + u16 frag_thresh; + u8 preamble;/*long, short, auto*/ + u8 scan_mode;/*active, passive*/ + u8 adhoc_tx_pwr; + u8 soft_ap; + u8 smart_ps; + u8 power_mgnt; + u8 radio_enable; + u8 long_retry_lmt; + u8 short_retry_lmt; + u16 busy_thresh; + u8 ack_policy; + u8 mp_mode; + u8 software_encrypt; + u8 software_decrypt; + /* UAPSD */ + u8 wmm_enable; + u8 uapsd_enable; + u8 uapsd_max_sp; + u8 uapsd_acbk_en; + u8 uapsd_acbe_en; + u8 uapsd_acvi_en; + u8 uapsd_acvo_en; + + struct wlan_bssid_ex dev_network; + + u8 ht_enable; + u8 cbw40_enable; + u8 ampdu_enable;/*for tx*/ + u8 rf_config; + u8 low_power; + u8 wifi_test; +}; + +struct dvobj_priv { + struct _adapter *padapter; + u32 nr_endpoint; + u8 ishighspeed; + uint (*inirp_init)(struct _adapter *adapter); + uint (*inirp_deinit)(struct _adapter *adapter); + struct usb_device *pusbdev; +}; + +/** + * struct _adapter - the main adapter structure for this device. + * + * bup: True indicates that the interface is up. + */ +struct _adapter { + struct dvobj_priv dvobjpriv; + struct mlme_priv mlmepriv; + struct cmd_priv cmdpriv; + struct evt_priv evtpriv; + struct io_queue *pio_queue; + struct xmit_priv xmitpriv; + struct recv_priv recvpriv; + struct sta_priv stapriv; + struct security_priv securitypriv; + struct registry_priv registrypriv; + struct wlan_acl_pool acl_list; + struct pwrctrl_priv pwrctrlpriv; + struct eeprom_priv eeprompriv; + struct hal_priv halpriv; + struct led_priv ledpriv; + struct mp_priv mppriv; + s32 bDriverStopped; + s32 bSurpriseRemoved; + u32 IsrContent; + u32 ImrContent; + u8 EepromAddressSize; + u8 hw_init_completed; + struct task_struct *cmdThread; + pid_t evtThread; + struct task_struct *xmitThread; + pid_t recvThread; + uint (*dvobj_init)(struct _adapter *adapter); + void (*dvobj_deinit)(struct _adapter *adapter); + struct net_device *pnetdev; + int bup; + struct net_device_stats stats; + struct iw_statistics iwstats; + int pid; /*process id from UI*/ + struct work_struct wkFilterRxFF0; + u8 blnEnableRxFF0Filter; + spinlock_t lockRxFF0Filter; + const struct firmware *fw; + struct usb_interface *pusb_intf; + struct mutex mutex_start; + struct completion rtl8712_fw_ready; +}; + +static inline u8 *myid(struct eeprom_priv *peepriv) +{ + return peepriv->mac_addr; +} + +u8 r8712_usb_hal_bus_init(struct _adapter *adapter); + +#endif /*__DRV_TYPES_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/ethernet.h b/kernel/drivers/staging/rtl8712/ethernet.h new file mode 100644 index 000000000..fad173f40 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/ethernet.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __INC_ETHERNET_H +#define __INC_ETHERNET_H + +#define ETHERNET_HEADER_SIZE 14 /*!< Ethernet Header Length*/ +#define LLC_HEADER_SIZE 6 /*!< LLC Header Length*/ + +#endif /* #ifndef __INC_ETHERNET_H */ + diff --git a/kernel/drivers/staging/rtl8712/hal_init.c b/kernel/drivers/staging/rtl8712/hal_init.c new file mode 100644 index 000000000..0a1c6313e --- /dev/null +++ b/kernel/drivers/staging/rtl8712/hal_init.c @@ -0,0 +1,396 @@ +/****************************************************************************** + * hal_init.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _HAL_INIT_C_ + +#include <linux/usb.h> +#include <linux/device.h> +#include <linux/usb/ch9.h> +#include <linux/firmware.h> +#include <linux/module.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "usb_osintf.h" + +#define FWBUFF_ALIGN_SZ 512 +#define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/ + +static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context) +{ + struct _adapter *padapter = context; + + complete(&padapter->rtl8712_fw_ready); + if (!firmware) { + struct usb_device *udev = padapter->dvobjpriv.pusbdev; + struct usb_interface *pusb_intf = padapter->pusb_intf; + + dev_err(&udev->dev, "r8712u: Firmware request failed\n"); + usb_put_dev(udev); + usb_set_intfdata(pusb_intf, NULL); + return; + } + padapter->fw = firmware; + /* firmware available - start netdev */ + register_netdev(padapter->pnetdev); +} + +static const char firmware_file[] = "rtlwifi/rtl8712u.bin"; + +int rtl871x_load_fw(struct _adapter *padapter) +{ + struct device *dev = &padapter->dvobjpriv.pusbdev->dev; + int rc; + + init_completion(&padapter->rtl8712_fw_ready); + dev_info(dev, "r8712u: Loading firmware from \"%s\"\n", firmware_file); + rc = request_firmware_nowait(THIS_MODULE, 1, firmware_file, dev, + GFP_KERNEL, padapter, rtl871x_load_fw_cb); + if (rc) + dev_err(dev, "r8712u: Firmware request error %d\n", rc); + return rc; +} +MODULE_FIRMWARE("rtlwifi/rtl8712u.bin"); + +static u32 rtl871x_open_fw(struct _adapter *padapter, const u8 **ppmappedfw) +{ + const struct firmware **praw = &padapter->fw; + + if (padapter->fw->size > 200000) { + dev_err(&padapter->pnetdev->dev, "r8172u: Badfw->size of %d\n", + (int)padapter->fw->size); + return 0; + } + *ppmappedfw = (*praw)->data; + return (*praw)->size; +} + +static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv) +{ + struct dvobj_priv *pdvobj = &padapter->dvobjpriv; + struct registry_priv *pregpriv = &padapter->registrypriv; + + memset(pfwpriv, 0, sizeof(struct fw_priv)); + /* todo: check if needs endian conversion */ + pfwpriv->hci_sel = RTL8712_HCI_TYPE_72USB; + pfwpriv->usb_ep_num = (u8)pdvobj->nr_endpoint; + pfwpriv->bw_40MHz_en = pregpriv->cbw40_enable; + switch (pregpriv->rf_config) { + case RTL8712_RF_1T1R: + pfwpriv->rf_config = RTL8712_RFC_1T1R; + break; + case RTL8712_RF_2T2R: + pfwpriv->rf_config = RTL8712_RFC_2T2R; + break; + case RTL8712_RF_1T2R: + default: + pfwpriv->rf_config = RTL8712_RFC_1T2R; + } + pfwpriv->mp_mode = (pregpriv->mp_mode == 1) ? 1 : 0; + pfwpriv->vcsType = pregpriv->vrtl_carrier_sense; /* 0:off 1:on 2:auto */ + pfwpriv->vcsMode = pregpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */ + /* default enable turboMode */ + pfwpriv->turboMode = ((pregpriv->wifi_test == 1) ? 0 : 1); + pfwpriv->lowPowerMode = pregpriv->low_power; +} + +static void update_fwhdr(struct fw_hdr *pfwhdr, const u8 *pmappedfw) +{ + pfwhdr->signature = le16_to_cpu(*(u16 *)pmappedfw); + pfwhdr->version = le16_to_cpu(*(u16 *)(pmappedfw+2)); + /* define the size of boot loader */ + pfwhdr->dmem_size = le32_to_cpu(*(uint *)(pmappedfw+4)); + /* define the size of FW in IMEM */ + pfwhdr->img_IMEM_size = le32_to_cpu(*(uint *)(pmappedfw+8)); + /* define the size of FW in SRAM */ + pfwhdr->img_SRAM_size = le32_to_cpu(*(uint *)(pmappedfw+12)); + /* define the size of DMEM variable */ + pfwhdr->fw_priv_sz = le32_to_cpu(*(uint *)(pmappedfw+16)); +} + +static u8 chk_fwhdr(struct fw_hdr *pfwhdr, u32 ulfilelength) +{ + u32 fwhdrsz, fw_sz; + + /* check signature */ + if ((pfwhdr->signature != 0x8712) && (pfwhdr->signature != 0x8192)) + return _FAIL; + /* check fw_priv_sze & sizeof(struct fw_priv) */ + if (pfwhdr->fw_priv_sz != sizeof(struct fw_priv)) + return _FAIL; + /* check fw_sz & image_fw_sz */ + fwhdrsz = FIELD_OFFSET(struct fw_hdr, fwpriv) + pfwhdr->fw_priv_sz; + fw_sz = fwhdrsz + pfwhdr->img_IMEM_size + pfwhdr->img_SRAM_size + + pfwhdr->dmem_size; + if (fw_sz != ulfilelength) + return _FAIL; + return _SUCCESS; +} + +static u8 rtl8712_dl_fw(struct _adapter *padapter) +{ + sint i; + u8 tmp8, tmp8_a; + u16 tmp16; + u32 maxlen = 0; /* for compare usage */ + uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */ + struct fw_hdr fwhdr; + u32 ulfilelength; /* FW file size */ + const u8 *pmappedfw = NULL; + u8 *ptmpchar = NULL, *ppayload, *ptr; + struct tx_desc *ptx_desc; + u32 txdscp_sz = sizeof(struct tx_desc); + u8 ret = _FAIL; + + ulfilelength = rtl871x_open_fw(padapter, &pmappedfw); + if (pmappedfw && (ulfilelength > 0)) { + update_fwhdr(&fwhdr, pmappedfw); + if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL) + return ret; + fill_fwpriv(padapter, &fwhdr.fwpriv); + /* firmware check ok */ + maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ? + fwhdr.img_IMEM_size : fwhdr.img_SRAM_size; + maxlen += txdscp_sz; + ptmpchar = kmalloc(maxlen + FWBUFF_ALIGN_SZ, GFP_ATOMIC); + if (ptmpchar == NULL) + return ret; + + ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ - + ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1))); + ppayload = (u8 *)(ptx_desc) + txdscp_sz; + ptr = (u8 *)pmappedfw + FIELD_OFFSET(struct fw_hdr, fwpriv) + + fwhdr.fw_priv_sz; + /* Download FirmWare */ + /* 1. determine IMEM code size and Load IMEM Code Section */ + imem_sz = fwhdr.img_IMEM_size; + do { + memset(ptx_desc, 0, TXDESC_SIZE); + if (imem_sz > MAX_DUMP_FWSZ/*49152*/) + dump_imem_sz = MAX_DUMP_FWSZ; + else { + dump_imem_sz = imem_sz; + ptx_desc->txdw0 |= cpu_to_le32(BIT(28)); + } + ptx_desc->txdw0 |= cpu_to_le32(dump_imem_sz & + 0x0000ffff); + memcpy(ppayload, ptr, dump_imem_sz); + r8712_write_mem(padapter, RTL8712_DMA_VOQ, + dump_imem_sz + TXDESC_SIZE, + (u8 *)ptx_desc); + ptr += dump_imem_sz; + imem_sz -= dump_imem_sz; + } while (imem_sz > 0); + i = 10; + tmp16 = r8712_read16(padapter, TCR); + while (((tmp16 & _IMEM_CODE_DONE) == 0) && (i > 0)) { + udelay(10); + tmp16 = r8712_read16(padapter, TCR); + i--; + } + if (i == 0 || (tmp16 & _IMEM_CHK_RPT) == 0) + goto exit_fail; + + /* 2.Download EMEM code size and Load EMEM Code Section */ + emem_sz = fwhdr.img_SRAM_size; + do { + memset(ptx_desc, 0, TXDESC_SIZE); + if (emem_sz > MAX_DUMP_FWSZ) /* max=48k */ + dump_emem_sz = MAX_DUMP_FWSZ; + else { + dump_emem_sz = emem_sz; + ptx_desc->txdw0 |= cpu_to_le32(BIT(28)); + } + ptx_desc->txdw0 |= cpu_to_le32(dump_emem_sz & + 0x0000ffff); + memcpy(ppayload, ptr, dump_emem_sz); + r8712_write_mem(padapter, RTL8712_DMA_VOQ, + dump_emem_sz+TXDESC_SIZE, (u8 *)ptx_desc); + ptr += dump_emem_sz; + emem_sz -= dump_emem_sz; + } while (emem_sz > 0); + i = 5; + tmp16 = r8712_read16(padapter, TCR); + while (((tmp16 & _EMEM_CODE_DONE) == 0) && (i > 0)) { + udelay(10); + tmp16 = r8712_read16(padapter, TCR); + i--; + } + if (i == 0 || (tmp16 & _EMEM_CHK_RPT) == 0) + goto exit_fail; + + /* 3.Enable CPU */ + tmp8 = r8712_read8(padapter, SYS_CLKR); + r8712_write8(padapter, SYS_CLKR, tmp8|BIT(2)); + tmp8_a = r8712_read8(padapter, SYS_CLKR); + if (tmp8_a != (tmp8|BIT(2))) + goto exit_fail; + + tmp8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + r8712_write8(padapter, SYS_FUNC_EN+1, tmp8|BIT(2)); + tmp8_a = r8712_read8(padapter, SYS_FUNC_EN + 1); + if (tmp8_a != (tmp8|BIT(2))) + goto exit_fail; + + r8712_read32(padapter, TCR); + + /* 4.polling IMEM Ready */ + i = 100; + tmp16 = r8712_read16(padapter, TCR); + while (((tmp16 & _IMEM_RDY) == 0) && (i > 0)) { + msleep(20); + tmp16 = r8712_read16(padapter, TCR); + i--; + } + if (i == 0) { + r8712_write16(padapter, 0x10250348, 0xc000); + r8712_write16(padapter, 0x10250348, 0xc001); + r8712_write16(padapter, 0x10250348, 0x2000); + r8712_write16(padapter, 0x10250348, 0x2001); + r8712_write16(padapter, 0x10250348, 0x2002); + r8712_write16(padapter, 0x10250348, 0x2003); + goto exit_fail; + } + /* 5.Download DMEM code size and Load EMEM Code Section */ + memset(ptx_desc, 0, TXDESC_SIZE); + ptx_desc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz&0x0000ffff); + ptx_desc->txdw0 |= cpu_to_le32(BIT(28)); + memcpy(ppayload, &fwhdr.fwpriv, fwhdr.fw_priv_sz); + r8712_write_mem(padapter, RTL8712_DMA_VOQ, + fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)ptx_desc); + + /* polling dmem code done */ + i = 100; + tmp16 = r8712_read16(padapter, TCR); + while (((tmp16 & _DMEM_CODE_DONE) == 0) && (i > 0)) { + msleep(20); + tmp16 = r8712_read16(padapter, TCR); + i--; + } + if (i == 0) + goto exit_fail; + + tmp8 = r8712_read8(padapter, 0x1025000A); + if (tmp8 & BIT(4)) /* When boot from EEPROM, + & FW need more time to read EEPROM */ + i = 60; + else /* boot from EFUSE */ + i = 30; + tmp16 = r8712_read16(padapter, TCR); + while (((tmp16 & _FWRDY) == 0) && (i > 0)) { + msleep(100); + tmp16 = r8712_read16(padapter, TCR); + i--; + } + if (i == 0) + goto exit_fail; + } else + goto exit_fail; + ret = _SUCCESS; + +exit_fail: + kfree(ptmpchar); + return ret; +} + +uint rtl8712_hal_init(struct _adapter *padapter) +{ + u32 val32; + int i; + + /* r8712 firmware download */ + if (rtl8712_dl_fw(padapter) != _SUCCESS) + return _FAIL; + + netdev_info(padapter->pnetdev, "1 RCR=0x%x\n", + r8712_read32(padapter, RCR)); + val32 = r8712_read32(padapter, RCR); + r8712_write32(padapter, RCR, (val32 | BIT(26))); /* Enable RX TCP + Checksum offload */ + netdev_info(padapter->pnetdev, "2 RCR=0x%x\n", + r8712_read32(padapter, RCR)); + val32 = r8712_read32(padapter, RCR); + r8712_write32(padapter, RCR, (val32|BIT(25))); /* Append PHY status */ + val32 = 0; + val32 = r8712_read32(padapter, 0x10250040); + r8712_write32(padapter, 0x10250040, (val32&0x00FFFFFF)); + /* for usb rx aggregation */ + r8712_write8(padapter, 0x102500B5, r8712_read8(padapter, 0x102500B5) | + BIT(0)); /* page = 128bytes */ + r8712_write8(padapter, 0x102500BD, r8712_read8(padapter, 0x102500BD) | + BIT(7)); /* enable usb rx aggregation */ + r8712_write8(padapter, 0x102500D9, 1); /* TH=1 => means that invalidate + * usb rx aggregation */ + r8712_write8(padapter, 0x1025FE5B, 0x04); /* 1.7ms/4 */ + /* Fix the RX FIFO issue(USB error) */ + r8712_write8(padapter, 0x1025fe5C, r8712_read8(padapter, 0x1025fe5C) + | BIT(7)); + for (i = 0; i < 6; i++) + padapter->eeprompriv.mac_addr[i] = r8712_read8(padapter, + MACID + i); + return _SUCCESS; +} + +uint rtl8712_hal_deinit(struct _adapter *padapter) +{ + r8712_write8(padapter, RF_CTRL, 0x00); + /* Turn off BB */ + msleep(20); + /* Turn off MAC */ + r8712_write8(padapter, SYS_CLKR+1, 0x38); /* Switch Control Path */ + r8712_write8(padapter, SYS_FUNC_EN+1, 0x70); + r8712_write8(padapter, PMC_FSM, 0x06); /* Enable Loader Data Keep */ + r8712_write8(padapter, SYS_ISO_CTRL, 0xF9); /* Isolation signals from + * CORE, PLL */ + r8712_write8(padapter, SYS_ISO_CTRL+1, 0xe8); /* Enable EFUSE 1.2V */ + r8712_write8(padapter, AFE_PLL_CTRL, 0x00); /* Disable AFE PLL. */ + r8712_write8(padapter, LDOA15_CTRL, 0x54); /* Disable A15V */ + r8712_write8(padapter, SYS_FUNC_EN+1, 0x50); /* Disable E-Fuse 1.2V */ + r8712_write8(padapter, LDOV12D_CTRL, 0x24); /* Disable LDO12(for CE) */ + r8712_write8(padapter, AFE_MISC, 0x30); /* Disable AFE BG&MB */ + /* Option for Disable 1.6V LDO. */ + r8712_write8(padapter, SPS0_CTRL, 0x56); /* Disable 1.6V LDO */ + r8712_write8(padapter, SPS0_CTRL+1, 0x43); /* Set SW PFM */ + return _SUCCESS; +} + +uint rtl871x_hal_init(struct _adapter *padapter) +{ + padapter->hw_init_completed = false; + if (padapter->halpriv.hal_bus_init == NULL) + return _FAIL; + if (padapter->halpriv.hal_bus_init(padapter) != _SUCCESS) + return _FAIL; + if (rtl8712_hal_init(padapter) == _SUCCESS) + padapter->hw_init_completed = true; + else { + padapter->hw_init_completed = false; + return _FAIL; + } + return _SUCCESS; +} diff --git a/kernel/drivers/staging/rtl8712/ieee80211.c b/kernel/drivers/staging/rtl8712/ieee80211.c new file mode 100644 index 000000000..57868085c --- /dev/null +++ b/kernel/drivers/staging/rtl8712/ieee80211.c @@ -0,0 +1,418 @@ +/****************************************************************************** + * ieee80211.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _IEEE80211_C + +#include "drv_types.h" +#include "ieee80211.h" +#include "wifi.h" +#include "osdep_service.h" +#include "wlan_bssdef.h" + +static const u8 WPA_OUI_TYPE[] = {0x00, 0x50, 0xf2, 1}; +static const u8 WPA_CIPHER_SUITE_NONE[] = {0x00, 0x50, 0xf2, 0}; +static const u8 WPA_CIPHER_SUITE_WEP40[] = {0x00, 0x50, 0xf2, 1}; +static const u8 WPA_CIPHER_SUITE_TKIP[] = {0x00, 0x50, 0xf2, 2}; +static const u8 WPA_CIPHER_SUITE_CCMP[] = {0x00, 0x50, 0xf2, 4}; +static const u8 WPA_CIPHER_SUITE_WEP104[] = {0x00, 0x50, 0xf2, 5}; + +static const u8 RSN_CIPHER_SUITE_NONE[] = {0x00, 0x0f, 0xac, 0}; +static const u8 RSN_CIPHER_SUITE_WEP40[] = {0x00, 0x0f, 0xac, 1}; +static const u8 RSN_CIPHER_SUITE_TKIP[] = {0x00, 0x0f, 0xac, 2}; +static const u8 RSN_CIPHER_SUITE_CCMP[] = {0x00, 0x0f, 0xac, 4}; +static const u8 RSN_CIPHER_SUITE_WEP104[] = {0x00, 0x0f, 0xac, 5}; + +/*----------------------------------------------------------- + * for adhoc-master to generate ie and provide supported-rate to fw + *----------------------------------------------------------- + */ + +static u8 WIFI_CCKRATES[] = { + (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK) +}; + +static u8 WIFI_OFDMRATES[] = { + (IEEE80211_OFDM_RATE_6MB), + (IEEE80211_OFDM_RATE_9MB), + (IEEE80211_OFDM_RATE_12MB), + (IEEE80211_OFDM_RATE_18MB), + (IEEE80211_OFDM_RATE_24MB), + (IEEE80211_OFDM_RATE_36MB), + (IEEE80211_OFDM_RATE_48MB), + (IEEE80211_OFDM_RATE_54MB) +}; + +uint r8712_is_cckrates_included(u8 *rate) +{ + u32 i = 0; + + while (rate[i] != 0) { + if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || + (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) + return true; + i++; + } + return false; +} + +uint r8712_is_cckratesonly_included(u8 *rate) +{ + u32 i = 0; + + while (rate[i] != 0) { + if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && + (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) + return false; + i++; + } + return true; +} + +/* r8712_set_ie will update frame length */ +u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen) +{ + *pbuf = (u8)index; + *(pbuf + 1) = (u8)len; + if (len > 0) + memcpy((void *)(pbuf + 2), (void *)source, len); + *frlen = *frlen + (len + 2); + return pbuf + len + 2; +} + +/*---------------------------------------------------------------------------- +index: the information element id index, limit is the limit for search +-----------------------------------------------------------------------------*/ +u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit) +{ + sint tmp, i; + u8 *p; + + if (limit < 1) + return NULL; + p = pbuf; + i = 0; + *len = 0; + while (1) { + if (*p == index) { + *len = *(p + 1); + return p; + } + tmp = *(p + 1); + p += (tmp + 2); + i += (tmp + 2); + if (i >= limit) + break; + } + return NULL; +} + +static void set_supported_rate(u8 *SupportedRates, uint mode) +{ + memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); + switch (mode) { + case WIRELESS_11B: + memcpy(SupportedRates, WIFI_CCKRATES, + IEEE80211_CCK_RATE_LEN); + break; + case WIRELESS_11G: + case WIRELESS_11A: + memcpy(SupportedRates, WIFI_OFDMRATES, + IEEE80211_NUM_OFDM_RATESLEN); + break; + case WIRELESS_11BG: + memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); + memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, + IEEE80211_NUM_OFDM_RATESLEN); + break; + } +} + +static uint r8712_get_rateset_len(u8 *rateset) +{ + uint i = 0; + + while (1) { + if ((rateset[i]) == 0) + break; + if (i > 12) + break; + i++; + } + return i; +} + +int r8712_generate_ie(struct registry_priv *pregistrypriv) +{ + int sz = 0, rateLen; + struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; + u8 *ie = pdev_network->IEs; + + /*timestamp will be inserted by hardware*/ + sz += 8; + ie += sz; + /*beacon interval : 2bytes*/ + *(u16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod); + sz += 2; + ie += 2; + /*capability info*/ + *(u16 *)ie = 0; + *(u16 *)ie |= cpu_to_le16(cap_IBSS); + if (pregistrypriv->preamble == PREAMBLE_SHORT) + *(u16 *)ie |= cpu_to_le16(cap_ShortPremble); + if (pdev_network->Privacy) + *(u16 *)ie |= cpu_to_le16(cap_Privacy); + sz += 2; + ie += 2; + /*SSID*/ + ie = r8712_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, + pdev_network->Ssid.Ssid, &sz); + /*supported rates*/ + set_supported_rate(pdev_network->SupportedRates, + pregistrypriv->wireless_mode); + rateLen = r8712_get_rateset_len(pdev_network->SupportedRates); + if (rateLen > 8) { + ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 8, + pdev_network->SupportedRates, &sz); + ie = r8712_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), + (pdev_network->SupportedRates + 8), &sz); + } else + ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, + rateLen, pdev_network->SupportedRates, &sz); + /*DS parameter set*/ + ie = r8712_set_ie(ie, _DSSET_IE_, 1, + (u8 *)&(pdev_network->Configuration.DSConfig), &sz); + /*IBSS Parameter Set*/ + ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2, + (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz); + return sz; +} + +unsigned char *r8712_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) +{ + int len; + u16 val16; + unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; + u8 *pbuf = pie; + + while (1) { + pbuf = r8712_get_ie(pbuf, _WPA_IE_ID_, &len, limit); + if (pbuf) { + /*check if oui matches...*/ + if (memcmp((pbuf + 2), wpa_oui_type, + sizeof(wpa_oui_type))) + goto check_next_ie; + /*check version...*/ + memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16)); + val16 = le16_to_cpu(val16); + if (val16 != 0x0001) + goto check_next_ie; + *wpa_ie_len = *(pbuf + 1); + return pbuf; + } + *wpa_ie_len = 0; + return NULL; +check_next_ie: + limit = limit - (pbuf - pie) - 2 - len; + if (limit <= 0) + break; + pbuf += (2 + len); + } + *wpa_ie_len = 0; + return NULL; +} + +unsigned char *r8712_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) +{ + return r8712_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); +} + +static int r8712_get_wpa_cipher_suite(u8 *s) +{ + if (!memcmp(s, (void *)WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN)) + return WPA_CIPHER_NONE; + if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN)) + return WPA_CIPHER_WEP40; + if (!memcmp(s, (void *)WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN)) + return WPA_CIPHER_TKIP; + if (!memcmp(s, (void *)WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN)) + return WPA_CIPHER_CCMP; + if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN)) + return WPA_CIPHER_WEP104; + return 0; +} + +static int r8712_get_wpa2_cipher_suite(u8 *s) +{ + if (!memcmp(s, (void *)RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN)) + return WPA_CIPHER_NONE; + if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN)) + return WPA_CIPHER_WEP40; + if (!memcmp(s, (void *)RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN)) + return WPA_CIPHER_TKIP; + if (!memcmp(s, (void *)RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN)) + return WPA_CIPHER_CCMP; + if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN)) + return WPA_CIPHER_WEP104; + return 0; +} + +int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, + int *pairwise_cipher) +{ + int i; + int left, count; + u8 *pos; + + if (wpa_ie_len <= 0) { + /* No WPA IE - fail silently */ + return _FAIL; + } + if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) + || (memcmp(wpa_ie + 2, (void *)WPA_OUI_TYPE, WPA_SELECTOR_LEN))) + return _FAIL; + pos = wpa_ie; + pos += 8; + left = wpa_ie_len - 8; + /*group_cipher*/ + if (left >= WPA_SELECTOR_LEN) { + *group_cipher = r8712_get_wpa_cipher_suite(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } else if (left > 0) + return _FAIL; + /*pairwise_cipher*/ + if (left >= 2) { + count = le16_to_cpu(*(u16 *)pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * WPA_SELECTOR_LEN) + return _FAIL; + for (i = 0; i < count; i++) { + *pairwise_cipher |= r8712_get_wpa_cipher_suite(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + } else if (left == 1) + return _FAIL; + return _SUCCESS; +} + +int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, + int *pairwise_cipher) +{ + int i; + int left, count; + u8 *pos; + + if (rsn_ie_len <= 0) { + /* No RSN IE - fail silently */ + return _FAIL; + } + if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2))) + return _FAIL; + pos = rsn_ie; + pos += 4; + left = rsn_ie_len - 4; + /*group_cipher*/ + if (left >= RSN_SELECTOR_LEN) { + *group_cipher = r8712_get_wpa2_cipher_suite(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } else if (left > 0) + return _FAIL; + /*pairwise_cipher*/ + if (left >= 2) { + count = le16_to_cpu(*(u16 *)pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * RSN_SELECTOR_LEN) + return _FAIL; + for (i = 0; i < count; i++) { + *pairwise_cipher |= r8712_get_wpa2_cipher_suite(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + } else if (left == 1) + return _FAIL; + return _SUCCESS; +} + +int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, + u8 *wpa_ie, u16 *wpa_len) +{ + u8 authmode; + u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; + uint cnt; + + /*Search required WPA or WPA2 IE and copy to sec_ie[ ]*/ + cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); + while (cnt < in_len) { + authmode = in_ie[cnt]; + if ((authmode == _WPA_IE_ID_) && + (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) { + memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + *wpa_len = in_ie[cnt+1]+2; + cnt += in_ie[cnt + 1] + 2; /*get next */ + } else { + if (authmode == _WPA2_IE_ID_) { + memcpy(rsn_ie, &in_ie[cnt], + in_ie[cnt + 1] + 2); + *rsn_len = in_ie[cnt+1] + 2; + cnt += in_ie[cnt+1] + 2; /*get next*/ + } else + cnt += in_ie[cnt+1] + 2; /*get next*/ + } + } + return *rsn_len + *wpa_len; +} + +int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) +{ + int match; + uint cnt; + u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; + + cnt = 12; + match = false; + while (cnt < in_len) { + eid = in_ie[cnt]; + if ((eid == _WPA_IE_ID_) && + (!memcmp(&in_ie[cnt+2], wps_oui, 4))) { + memcpy(wps_ie, &in_ie[cnt], in_ie[cnt+1]+2); + *wps_ielen = in_ie[cnt+1]+2; + cnt += in_ie[cnt+1]+2; + match = true; + break; + } + cnt += in_ie[cnt+1]+2; /* goto next */ + } + return match; +} diff --git a/kernel/drivers/staging/rtl8712/ieee80211.h b/kernel/drivers/staging/rtl8712/ieee80211.h new file mode 100644 index 000000000..8269be804 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/ieee80211.h @@ -0,0 +1,796 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __IEEE80211_H +#define __IEEE80211_H + +#include "osdep_service.h" +#include "drv_types.h" +#include "wifi.h" +#include <linux/compiler.h> +#include <linux/wireless.h> + +#define MGMT_QUEUE_NUM 5 +#define ETH_ALEN 6 +#define IEEE_CMD_SET_WPA_PARAM 1 +#define IEEE_CMD_SET_WPA_IE 2 +#define IEEE_CMD_SET_ENCRYPTION 3 +#define IEEE_CMD_MLME 4 + +#define IEEE_PARAM_WPA_ENABLED 1 +#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 +#define IEEE_PARAM_DROP_UNENCRYPTED 3 +#define IEEE_PARAM_PRIVACY_INVOKED 4 +#define IEEE_PARAM_AUTH_ALGS 5 +#define IEEE_PARAM_IEEE_802_1X 6 +#define IEEE_PARAM_WPAX_SELECT 7 + +#define AUTH_ALG_OPEN_SYSTEM 0x1 +#define AUTH_ALG_SHARED_KEY 0x2 +#define AUTH_ALG_LEAP 0x00000004 + +#define IEEE_MLME_STA_DEAUTH 1 +#define IEEE_MLME_STA_DISASSOC 2 + +#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 +#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 +#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 +#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 +#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 +#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 + + +#define IEEE_CRYPT_ALG_NAME_LEN 16 + +#define WPA_CIPHER_NONE BIT(0) +#define WPA_CIPHER_WEP40 BIT(1) +#define WPA_CIPHER_WEP104 BIT(2) +#define WPA_CIPHER_TKIP BIT(3) +#define WPA_CIPHER_CCMP BIT(4) + + + +#define WPA_SELECTOR_LEN 4 +#define RSN_HEADER_LEN 4 + +#define RSN_SELECTOR_LEN 4 + +enum NETWORK_TYPE { + WIRELESS_INVALID = 0, + WIRELESS_11B = 1, + WIRELESS_11G = 2, + WIRELESS_11BG = (WIRELESS_11B | WIRELESS_11G), + WIRELESS_11A = 4, + WIRELESS_11N = 8, + WIRELESS_11GN = (WIRELESS_11G | WIRELESS_11N), + WIRELESS_11BGN = (WIRELESS_11B | WIRELESS_11G | WIRELESS_11N), +}; + + +struct ieee_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 name; + u32 value; + } wpa_param; + struct { + u32 len; + u8 reserved[32]; + u8 data[0]; + } wpa_ie; + struct { + int command; + int reason_code; + } mlme; + struct { + u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; + u8 set_tx; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; + } u; +}; + +#define IEEE80211_DATA_LEN 2304 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + The figure in section 7.1.2 suggests a body size of up to 2312 + bytes is allowed, which is a bit confusing, I suspect this + represents the 2304 bytes of real data, plus a possible 8 bytes of + WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ + +#define IEEE80211_HLEN 30 +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) + +/* this is stolen from ipw2200 driver */ +#define IEEE_IBSS_MAC_HASH_SIZE 31 + +struct ieee_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; + +struct ieee80211_hdr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 addr4[ETH_ALEN]; +} __packed; + +struct ieee80211_hdr_3addr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; +} __packed; + + +struct ieee80211_hdr_qos { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 addr4[ETH_ALEN]; + u16 qc; +} __packed; + +struct ieee80211_hdr_3addr_qos { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u16 qc; +} __packed; + +struct eapol { + u8 snap[6]; + u16 ethertype; + u8 version; + u8 type; + u16 length; +} __packed; + + +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, + EAPOL_LOGOFF, + EAPOL_KEY, + EAPOL_ENCAP_ASF_ALERT +}; + +#define IEEE80211_3ADDR_LEN 24 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_FCS_LEN 4 + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U + +/* Frame control field constants */ +#define IEEE80211_FCTL_VERS 0x0002 +#define IEEE80211_FCTL_FTYPE 0x000c +#define IEEE80211_FCTL_STYPE 0x00f0 +#define IEEE80211_FCTL_TODS 0x0100 +#define IEEE80211_FCTL_FROMDS 0x0200 +#define IEEE80211_FCTL_MOREFRAGS 0x0400 +#define IEEE80211_FCTL_RETRY 0x0800 +#define IEEE80211_FCTL_PM 0x1000 +#define IEEE80211_FCTL_MOREDATA 0x2000 +#define IEEE80211_FCTL_WEP 0x4000 +#define IEEE80211_FCTL_ORDER 0x8000 + +#define IEEE80211_FTYPE_MGMT 0x0000 +#define IEEE80211_FTYPE_CTL 0x0004 +#define IEEE80211_FTYPE_DATA 0x0008 + +/* management */ +#define IEEE80211_STYPE_ASSOC_REQ 0x0000 +#define IEEE80211_STYPE_ASSOC_RESP 0x0010 +#define IEEE80211_STYPE_REASSOC_REQ 0x0020 +#define IEEE80211_STYPE_REASSOC_RESP 0x0030 +#define IEEE80211_STYPE_PROBE_REQ 0x0040 +#define IEEE80211_STYPE_PROBE_RESP 0x0050 +#define IEEE80211_STYPE_BEACON 0x0080 +#define IEEE80211_STYPE_ATIM 0x0090 +#define IEEE80211_STYPE_DISASSOC 0x00A0 +#define IEEE80211_STYPE_AUTH 0x00B0 +#define IEEE80211_STYPE_DEAUTH 0x00C0 + +/* control */ +#define IEEE80211_STYPE_PSPOLL 0x00A0 +#define IEEE80211_STYPE_RTS 0x00B0 +#define IEEE80211_STYPE_CTS 0x00C0 +#define IEEE80211_STYPE_ACK 0x00D0 +#define IEEE80211_STYPE_CFEND 0x00E0 +#define IEEE80211_STYPE_CFENDACK 0x00F0 + +/* data */ +#define IEEE80211_STYPE_DATA 0x0000 +#define IEEE80211_STYPE_DATA_CFACK 0x0010 +#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 +#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 +#define IEEE80211_STYPE_NULLFUNC 0x0040 +#define IEEE80211_STYPE_CFACK 0x0050 +#define IEEE80211_STYPE_CFPOLL 0x0060 +#define IEEE80211_STYPE_CFACKPOLL 0x0070 +#define IEEE80211_QOS_DATAGRP 0x0080 +#define IEEE80211_QoS_DATAGRP IEEE80211_QOS_DATAGRP + +#define IEEE80211_SCTL_FRAG 0x000F +#define IEEE80211_SCTL_SEQ 0xFFF0 + +/* QoS,QOS */ +#define NORMAL_ACK 0 +#define NO_ACK 1 +#define NON_EXPLICIT_ACK 2 +#define BLOCK_ACK 3 + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ + +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + +#define ETH_P_ECONET 0x0018 + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct ieee80211_snap_hdr { + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ +} __packed; + +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) + +#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ) + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_BSS (1<<0) +#define WLAN_CAPABILITY_IBSS (1<<1) +#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) +#define WLAN_CAPABILITY_PRIVACY (1<<4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) +#define WLAN_CAPABILITY_PBCC (1<<6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) +#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) + +/* Status codes */ +#define WLAN_STATUS_SUCCESS 0 +#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 +#define WLAN_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 +#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 +#define WLAN_STATUS_CHALLENGE_FAIL 15 +#define WLAN_STATUS_AUTH_TIMEOUT 16 +#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 +#define WLAN_STATUS_ASSOC_DENIED_RATES 18 +/* 802.11b */ +#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 +#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 +#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 + +/* Reason codes */ +#define WLAN_REASON_UNSPECIFIED 1 +#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 +#define WLAN_REASON_DEAUTH_LEAVING 3 +#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 +#define WLAN_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 +#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 +#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 +#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 + + +/* Information Element IDs */ +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARAMS 2 +#define WLAN_EID_DS_PARAMS 3 +#define WLAN_EID_CF_PARAMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARAMS 6 +#define WLAN_EID_CHALLENGE 16 +#define WLAN_EID_RSN 48 +#define WLAN_EID_GENERIC 221 + +#define IEEE80211_MGMT_HDR_LEN 24 +#define IEEE80211_DATA_HDR3_LEN 24 +#define IEEE80211_DATA_HDR4_LEN 30 + + +#define IEEE80211_STATMASK_SIGNAL (1<<0) +#define IEEE80211_STATMASK_RSSI (1<<1) +#define IEEE80211_STATMASK_NOISE (1<<2) +#define IEEE80211_STATMASK_RATE (1<<3) +#define IEEE80211_STATMASK_WEMASK 0x7 + + +#define IEEE80211_CCK_MODULATION (1<<0) +#define IEEE80211_OFDM_MODULATION (1<<1) + +#define IEEE80211_24GHZ_BAND (1<<0) +#define IEEE80211_52GHZ_BAND (1<<1) + +#define IEEE80211_CCK_RATE_LEN 4 +#define IEEE80211_NUM_OFDM_RATESLEN 8 + + +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_LEN 8 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + +#define IEEE80211_NUM_OFDM_RATES 8 +#define IEEE80211_NUM_CCK_RATES 4 +#define IEEE80211_OFDM_SHIFT_MASK_A 4 + + + + +/* NOTE: This data is for statistical purposes; not all hardware provides this + * information for frames received. Not setting these will not cause + * any adverse affects. */ +struct ieee80211_rx_stats { + s8 rssi; + u8 signal; + u8 noise; + u8 received_channel; + u16 rate; /* in 100 kbps */ + u8 mask; + u8 freq; + u16 len; +}; + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ +#define IEEE80211_FRAG_CACHE_LEN 4 + +struct ieee80211_frag_entry { + u32 first_frag_time; + uint seq; + uint last_frag; + uint qos; /*jackson*/ + uint tid; /*jackson*/ + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct ieee80211_stats { + uint tx_unicast_frames; + uint tx_multicast_frames; + uint tx_fragments; + uint tx_unicast_octets; + uint tx_multicast_octets; + uint tx_deferred_transmissions; + uint tx_single_retry_frames; + uint tx_multiple_retry_frames; + uint tx_retry_limit_exceeded; + uint tx_discards; + uint rx_unicast_frames; + uint rx_multicast_frames; + uint rx_fragments; + uint rx_unicast_octets; + uint rx_multicast_octets; + uint rx_fcs_errors; + uint rx_discards_no_buffer; + uint tx_discards_wrong_sa; + uint rx_discards_undecryptable; + uint rx_message_in_msg_fragments; + uint rx_message_in_bad_msg_fragments; +}; + +struct ieee80211_softmac_stats { + uint rx_ass_ok; + uint rx_ass_err; + uint rx_probe_rq; + uint tx_probe_rs; + uint tx_beacons; + uint rx_auth_rq; + uint rx_auth_rs_ok; + uint rx_auth_rs_err; + uint tx_auth_rq; + uint no_auth_rs; + uint no_ass_rs; + uint tx_ass_rq; + uint rx_ass_rq; + uint tx_probe_rq; + uint reassoc; + uint swtxstop; + uint swtxawake; +}; + +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) + +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 + +struct ieee80211_security { + u16 active_key:2, + enabled:1, + auth_mode:2, + auth_algo:4, + unicast_uses_group:1; + u8 key_sizes[WEP_KEYS]; + u8 keys[WEP_KEYS][WEP_KEY_LEN]; + u8 level; + u16 flags; +} __packed; + +/* + + 802.11 data frame from AP + + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `-------------------------------------------------------------------' + +Total: 28-2340 bytes + +*/ + +struct ieee80211_header_data { + u16 frame_ctl; + u16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + u16 seq_ctrl; +}; + +#define BEACON_PROBE_SSID_ID_POSITION 12 + +/* Management Frame Information Element Types */ +#define MFIE_TYPE_SSID 0 +#define MFIE_TYPE_RATES 1 +#define MFIE_TYPE_FH_SET 2 +#define MFIE_TYPE_DS_SET 3 +#define MFIE_TYPE_CF_SET 4 +#define MFIE_TYPE_TIM 5 +#define MFIE_TYPE_IBSS_SET 6 +#define MFIE_TYPE_CHALLENGE 16 +#define MFIE_TYPE_ERP 42 +#define MFIE_TYPE_RSN 48 +#define MFIE_TYPE_RATES_EX 50 +#define MFIE_TYPE_GENERIC 221 + +struct ieee80211_info_element_hdr { + u8 id; + u8 len; +} __packed; + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __packed; + +/* + * These are the data types that can make up management packets + * + u16 auth_algorithm; + u16 auth_sequence; + u16 beacon_interval; + u16 capability; + u8 current_ap[ETH_ALEN]; + u16 listen_interval; + struct { + u16 association_id:14, reserved:2; + } __packed; + u32 time_stamp[2]; + u16 reason; + u16 status; +*/ + +#define IEEE80211_DEFAULT_TX_ESSID "Penguin" +#define IEEE80211_DEFAULT_BASIC_RATE 10 + +struct ieee80211_authentication { + struct ieee80211_header_data header; + u16 algorithm; + u16 transaction; + u16 status; +} __packed; + +struct ieee80211_probe_response { + struct ieee80211_header_data header; + u32 time_stamp[2]; + u16 beacon_interval; + u16 capability; + struct ieee80211_info_element info_element; +} __packed; + +struct ieee80211_probe_request { + struct ieee80211_header_data header; +} __packed; + +struct ieee80211_assoc_request_frame { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 listen_interval; + struct ieee80211_info_element_hdr info_element; +} __packed; + +struct ieee80211_assoc_response_frame { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 status; + u16 aid; +} __packed; + +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; + u16 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + +/* SWEEP TABLE ENTRIES NUMBER*/ +#define MAX_SWEEP_TAB_ENTRIES 42 +#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_NETWORK_COUNT 128 +#define MAX_CHANNEL_NUMBER 161 +#define IEEE80211_SOFTMAC_SCAN_TIME 400 +/*(HZ / 2)*/ +#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 128 + +#define NETWORK_EMPTY_ESSID (1<<0) +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +#define IEEE80211_DTIM_MBCAST 4 +#define IEEE80211_DTIM_UCAST 2 +#define IEEE80211_DTIM_VALID 1 +#define IEEE80211_DTIM_INVALID 0 + +#define IEEE80211_PS_DISABLED 0 +#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST +#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST +#define IW_ESSID_MAX_SIZE 32 +/* + * join_res: + * -1: authentication fail + * -2: association fail + * > 0: TID + */ + +enum ieee80211_state { + /* the card is not linked at all */ + IEEE80211_NOLINK = 0, + /* IEEE80211_ASSOCIATING* are for BSS client mode + * the driver shall not perform RX filtering unless + * the state is LINKED. + * The driver shall just check for the state LINKED and + * defaults to NOLINK for ALL the other states (including + * LINKED_SCANNING) + */ + /* the association procedure will start (wq scheduling)*/ + IEEE80211_ASSOCIATING, + IEEE80211_ASSOCIATING_RETRY, + /* the association procedure is sending AUTH request*/ + IEEE80211_ASSOCIATING_AUTHENTICATING, + /* the association procedure has successfully authenticated + * and is sending association request + */ + IEEE80211_ASSOCIATING_AUTHENTICATED, + /* the link is ok. the card associated to a BSS or linked + * to a ibss cell or acting as an AP and creating the bss + */ + IEEE80211_LINKED, + /* same as LINKED, but the driver shall apply RX filter + * rules as we are in NO_LINK mode. As the card is still + * logically linked, but it is doing a syncro site survey + * then it will be back to LINKED state. + */ + IEEE80211_LINKED_SCANNING, +}; + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 + +#define CFG_IEEE80211_RESERVE_FCS (1<<0) +#define CFG_IEEE80211_COMPUTE_FCS (1<<1) + +#define MAXTID 16 + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +static inline int ieee80211_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + return 1; +} + +static inline int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if (fc & IEEE80211_QOS_DATAGRP) + hdrlen += 2; + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen += 6; /* Addr4 */ + break; + case IEEE80211_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case IEEE80211_STYPE_CTS: + case IEEE80211_STYPE_ACK: + hdrlen = 10; + break; + default: + hdrlen = 16; + break; + } + break; + } + return hdrlen; +} + +struct registry_priv; + +u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen); +u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit); +unsigned char *r8712_get_wpa_ie(unsigned char *pie, int *rsn_ie_len, int limit); +unsigned char *r8712_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, + int limit); +int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, + int *pairwise_cipher); +int r8712_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, + int *pairwise_cipher); +int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, + u8 *wpa_ie, u16 *wpa_len); +int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); +int r8712_generate_ie(struct registry_priv *pregistrypriv); +uint r8712_is_cckrates_included(u8 *rate); +uint r8712_is_cckratesonly_included(u8 *rate); + +#endif /* IEEE80211_H */ + diff --git a/kernel/drivers/staging/rtl8712/mlme_linux.c b/kernel/drivers/staging/rtl8712/mlme_linux.c new file mode 100644 index 000000000..8c5a475f0 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/mlme_linux.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * mlme_linux.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _MLME_OSDEP_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "mlme_osdep.h" + +static void sitesurvey_ctrl_handler(unsigned long data) +{ + struct _adapter *adapter = (struct _adapter *)data; + + _r8712_sitesurvey_ctrl_handler(adapter); + mod_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, + jiffies + msecs_to_jiffies(3000)); +} + +static void join_timeout_handler (unsigned long data) +{ + struct _adapter *adapter = (struct _adapter *)data; + + _r8712_join_timeout_handler(adapter); +} + +static void _scan_timeout_handler (unsigned long data) +{ + struct _adapter *adapter = (struct _adapter *)data; + + r8712_scan_timeout_handler(adapter); +} + +static void dhcp_timeout_handler (unsigned long data) +{ + struct _adapter *adapter = (struct _adapter *)data; + + _r8712_dhcp_timeout_handler(adapter); +} + +static void wdg_timeout_handler (unsigned long data) +{ + struct _adapter *adapter = (struct _adapter *)data; + + _r8712_wdg_timeout_handler(adapter); + + mod_timer(&adapter->mlmepriv.wdg_timer, + jiffies + msecs_to_jiffies(2000)); +} + +void r8712_init_mlme_timer(struct _adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + setup_timer(&pmlmepriv->assoc_timer, join_timeout_handler, + (unsigned long)padapter); + setup_timer(&pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer, + sitesurvey_ctrl_handler, + (unsigned long)padapter); + setup_timer(&pmlmepriv->scan_to_timer, _scan_timeout_handler, + (unsigned long)padapter); + setup_timer(&pmlmepriv->dhcp_timer, dhcp_timeout_handler, + (unsigned long)padapter); + setup_timer(&pmlmepriv->wdg_timer, wdg_timeout_handler, + (unsigned long)padapter); +} + +void r8712_os_indicate_connect(struct _adapter *adapter) +{ + r8712_indicate_wx_assoc_event(adapter); + netif_carrier_on(adapter->pnetdev); +} + +static struct RT_PMKID_LIST backupPMKIDList[NUM_PMKID_CACHE]; +void r8712_os_indicate_disconnect(struct _adapter *adapter) +{ + u8 backupPMKIDIndex = 0; + u8 backupTKIPCountermeasure = 0x00; + + r8712_indicate_wx_disassoc_event(adapter); + netif_carrier_off(adapter->pnetdev); + if (adapter->securitypriv.AuthAlgrthm == 2) { /*/802.1x*/ + /* We have to backup the PMK information for WiFi PMK Caching + * test item. Backup the btkip_countermeasure information. + * When the countermeasure is trigger, the driver have to + * disconnect with AP for 60 seconds. + */ + + memcpy(&backupPMKIDList[0], &adapter->securitypriv. + PMKIDList[0], sizeof(struct RT_PMKID_LIST) * + NUM_PMKID_CACHE); + backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; + backupTKIPCountermeasure = adapter->securitypriv. + btkip_countermeasure; + memset((unsigned char *)&adapter->securitypriv, 0, + sizeof(struct security_priv)); + setup_timer(&adapter->securitypriv.tkip_timer, + r8712_use_tkipkey_handler, + (unsigned long)adapter); + /* Restore the PMK information to securitypriv structure + * for the following connection. */ + memcpy(&adapter->securitypriv.PMKIDList[0], + &backupPMKIDList[0], + sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); + adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; + adapter->securitypriv.btkip_countermeasure = + backupTKIPCountermeasure; + } else { /*reset values in securitypriv*/ + struct security_priv *psec_priv = &adapter->securitypriv; + + psec_priv->AuthAlgrthm = 0; /*open system*/ + psec_priv->PrivacyAlgrthm = _NO_PRIVACY_; + psec_priv->PrivacyKeyIndex = 0; + psec_priv->XGrpPrivacy = _NO_PRIVACY_; + psec_priv->XGrpKeyid = 1; + psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; + psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; + psec_priv->wps_phase = false; + } +} + +void r8712_report_sec_ie(struct _adapter *adapter, u8 authmode, u8 *sec_ie) +{ + uint len; + u8 *buff, *p, i; + union iwreq_data wrqu; + + buff = NULL; + if (authmode == _WPA_IE_ID_) { + buff = kzalloc(IW_CUSTOM_MAX, GFP_ATOMIC); + if (buff == NULL) + return; + p = buff; + p += sprintf(p, "ASSOCINFO(ReqIEs="); + len = sec_ie[1] + 2; + len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX - 1; + for (i = 0; i < len; i++) + p += sprintf(p, "%02x", sec_ie[i]); + p += sprintf(p, ")"); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = p-buff; + wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? + wrqu.data.length : IW_CUSTOM_MAX; + wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff); + kfree(buff); + } +} diff --git a/kernel/drivers/staging/rtl8712/mlme_osdep.h b/kernel/drivers/staging/rtl8712/mlme_osdep.h new file mode 100644 index 000000000..a20fe81f9 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/mlme_osdep.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __MLME_OSDEP_H_ +#define __MLME_OSDEP_H_ + +#include "osdep_service.h" +#include "drv_types.h" + +void r8712_init_mlme_timer(struct _adapter *padapter); +void r8712_os_indicate_disconnect(struct _adapter *adapter); +void r8712_os_indicate_connect(struct _adapter *adapter); +void r8712_report_sec_ie(struct _adapter *adapter, u8 authmode, u8 *sec_ie); +int r8712_recv_indicatepkts_in_order(struct _adapter *adapter, + struct recv_reorder_ctrl *precvreorder_ctrl, + int bforced); +void r8712_indicate_wx_assoc_event(struct _adapter *padapter); +void r8712_indicate_wx_disassoc_event(struct _adapter *padapter); + +#endif /*_MLME_OSDEP_H_*/ + diff --git a/kernel/drivers/staging/rtl8712/mp_custom_oid.h b/kernel/drivers/staging/rtl8712/mp_custom_oid.h new file mode 100644 index 000000000..40510089b --- /dev/null +++ b/kernel/drivers/staging/rtl8712/mp_custom_oid.h @@ -0,0 +1,299 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __CUSTOM_OID_H +#define __CUSTOM_OID_H + +/* 0xFF818000 - 0xFF81802F RTL8180 Mass Production Kit + * 0xFF818500 - 0xFF81850F RTL8185 Setup Utility + * 0xFF818580 - 0xFF81858F RTL8185 Phy Status Utility + * + * by Owen for Production Kit + * For Production Kit with Agilent Equipments + * in order to make our custom oids hopefully somewhat unique + * we will use 0xFF (indicating implementation specific OID) + * 81(first byte of non zero Realtek unique identifier) + * 80 (second byte of non zero Realtek unique identifier) + * XX (the custom OID number - providing 255 possible custom oids) + */ +#define OID_RT_PRO_RESET_DUT 0xFF818000 +#define OID_RT_PRO_SET_DATA_RATE 0xFF818001 +#define OID_RT_PRO_START_TEST 0xFF818002 +#define OID_RT_PRO_STOP_TEST 0xFF818003 +#define OID_RT_PRO_SET_PREAMBLE 0xFF818004 +#define OID_RT_PRO_SET_SCRAMBLER 0xFF818005 +#define OID_RT_PRO_SET_FILTER_BB 0xFF818006 +#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB 0xFF818007 +#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL 0xFF818008 +#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL 0xFF818009 +#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL 0xFF81800A + +#define OID_RT_PRO_SET_TX_ANTENNA_BB 0xFF81800D +#define OID_RT_PRO_SET_ANTENNA_BB 0xFF81800E +#define OID_RT_PRO_SET_CR_SCRAMBLER 0xFF81800F +#define OID_RT_PRO_SET_CR_NEW_FILTER 0xFF818010 +#define OID_RT_PRO_SET_TX_POWER_CONTROL 0xFF818011 +#define OID_RT_PRO_SET_CR_TX_CONFIG 0xFF818012 +#define OID_RT_PRO_GET_TX_POWER_CONTROL 0xFF818013 +#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY 0xFF818014 +#define OID_RT_PRO_SET_CR_SETPOINT 0xFF818015 +#define OID_RT_PRO_SET_INTEGRATOR 0xFF818016 +#define OID_RT_PRO_SET_SIGNAL_QUALITY 0xFF818017 +#define OID_RT_PRO_GET_INTEGRATOR 0xFF818018 +#define OID_RT_PRO_GET_SIGNAL_QUALITY 0xFF818019 +#define OID_RT_PRO_QUERY_EEPROM_TYPE 0xFF81801A +#define OID_RT_PRO_WRITE_MAC_ADDRESS 0xFF81801B +#define OID_RT_PRO_READ_MAC_ADDRESS 0xFF81801C +#define OID_RT_PRO_WRITE_CIS_DATA 0xFF81801D +#define OID_RT_PRO_READ_CIS_DATA 0xFF81801E +#define OID_RT_PRO_WRITE_POWER_CONTROL 0xFF81801F +#define OID_RT_PRO_READ_POWER_CONTROL 0xFF818020 +#define OID_RT_PRO_WRITE_EEPROM 0xFF818021 +#define OID_RT_PRO_READ_EEPROM 0xFF818022 +#define OID_RT_PRO_RESET_TX_PACKET_SENT 0xFF818023 +#define OID_RT_PRO_QUERY_TX_PACKET_SENT 0xFF818024 +#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED 0xFF818025 +#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED 0xFF818026 +#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR 0xFF818027 +#define OID_RT_PRO_QUERY_CURRENT_ADDRESS 0xFF818028 +#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS 0xFF818029 +#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS 0xFF81802A +#define OID_RT_PRO_RECEIVE_PACKET 0xFF81802C +#define OID_RT_PRO_WRITE_EEPROM_BYTE 0xFF81802D +#define OID_RT_PRO_READ_EEPROM_BYTE 0xFF81802E +#define OID_RT_PRO_SET_MODULATION 0xFF81802F +#define OID_RT_DRIVER_OPTION 0xFF818080 +#define OID_RT_RF_OFF 0xFF818081 +#define OID_RT_AUTH_STATUS 0xFF818082 +#define OID_RT_PRO_SET_CONTINUOUS_TX 0xFF81800B +#define OID_RT_PRO_SET_SINGLE_CARRIER_TX 0xFF81800C +#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX 0xFF81802B +#define OID_RT_PRO_SET_SINGLE_TONE_TX 0xFF818043 +#define OID_RT_UTILITY_FALSE_ALARM_COUNTERS 0xFF818580 +#define OID_RT_UTILITY_SELECT_DEBUG_MODE 0xFF818581 +#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER 0xFF818582 +#define OID_RT_UTILITY_GET_RSSI_STATUS 0xFF818583 +#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS 0xFF818584 +#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS \ + 0xFF818585 +#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS 0xFF818586 +#define OID_RT_WIRELESS_MODE 0xFF818500 +#define OID_RT_SUPPORTED_RATES 0xFF818501 +#define OID_RT_DESIRED_RATES 0xFF818502 +#define OID_RT_WIRELESS_MODE_STARTING_ADHOC 0xFF818503 +#define OID_RT_GET_CONNECT_STATE 0xFF030001 +#define OID_RT_RESCAN 0xFF030002 +#define OID_RT_SET_KEY_LENGTH 0xFF030003 +#define OID_RT_SET_DEFAULT_KEY_ID 0xFF030004 +#define OID_RT_SET_CHANNEL 0xFF010182 +#define OID_RT_SET_SNIFFER_MODE 0xFF010183 +#define OID_RT_GET_SIGNAL_QUALITY 0xFF010184 +#define OID_RT_GET_SMALL_PACKET_CRC 0xFF010185 +#define OID_RT_GET_MIDDLE_PACKET_CRC 0xFF010186 +#define OID_RT_GET_LARGE_PACKET_CRC 0xFF010187 +#define OID_RT_GET_TX_RETRY 0xFF010188 +#define OID_RT_GET_RX_RETRY 0xFF010189 +#define OID_RT_PRO_SET_FW_DIG_STATE 0xFF01018A +#define OID_RT_PRO_SET_FW_RA_STATE 0xFF01018B +#define OID_RT_GET_RX_TOTAL_PACKET 0xFF010190 +#define OID_RT_GET_TX_BEACON_OK 0xFF010191 +#define OID_RT_GET_TX_BEACON_ERR 0xFF010192 +#define OID_RT_GET_RX_ICV_ERR 0xFF010193 +#define OID_RT_SET_ENCRYPTION_ALGORITHM 0xFF010194 +#define OID_RT_SET_NO_AUTO_RESCAN 0xFF010195 +#define OID_RT_GET_PREAMBLE_MODE 0xFF010196 +#define OID_RT_GET_DRIVER_UP_DELTA_TIME 0xFF010197 +#define OID_RT_GET_AP_IP 0xFF010198 +#define OID_RT_GET_CHANNELPLAN 0xFF010199 +#define OID_RT_SET_PREAMBLE_MODE 0xFF01019A +#define OID_RT_SET_BCN_INTVL 0xFF01019B +#define OID_RT_GET_RF_VENDER 0xFF01019C +#define OID_RT_DEDICATE_PROBE 0xFF01019D +#define OID_RT_PRO_RX_FILTER_PATTERN 0xFF01019E +#define OID_RT_GET_DCST_CURRENT_THRESHOLD 0xFF01019F +#define OID_RT_GET_CCA_ERR 0xFF0101A0 +#define OID_RT_GET_CCA_UPGRADE_THRESHOLD 0xFF0101A1 +#define OID_RT_GET_CCA_FALLBACK_THRESHOLD 0xFF0101A2 +#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES 0xFF0101A3 +#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES 0xFF0101A4 +#define OID_RT_SET_RATE_ADAPTIVE 0xFF0101A5 +#define OID_RT_GET_DCST_EVALUATE_PERIOD 0xFF0101A5 +#define OID_RT_GET_DCST_TIME_UNIT_INDEX 0xFF0101A6 +#define OID_RT_GET_TOTAL_TX_BYTES 0xFF0101A7 +#define OID_RT_GET_TOTAL_RX_BYTES 0xFF0101A8 +#define OID_RT_CURRENT_TX_POWER_LEVEL 0xFF0101A9 +#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT 0xFF0101AA +#define OID_RT_GET_ENC_KEY_MATCH_COUNT 0xFF0101AB +#define OID_RT_GET_CHANNEL 0xFF0101AC +#define OID_RT_SET_CHANNELPLAN 0xFF0101AD +#define OID_RT_GET_HARDWARE_RADIO_OFF 0xFF0101AE +#define OID_RT_CHANNELPLAN_BY_COUNTRY 0xFF0101AF +#define OID_RT_SCAN_AVAILABLE_BSSID 0xFF0101B0 +#define OID_RT_GET_HARDWARE_VERSION 0xFF0101B1 +#define OID_RT_GET_IS_ROAMING 0xFF0101B2 +#define OID_RT_GET_IS_PRIVACY 0xFF0101B3 +#define OID_RT_GET_KEY_MISMATCH 0xFF0101B4 +#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH 0xFF0101B5 +#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH 0xFF0101B6 +#define OID_RT_RESET_LOG 0xFF0101B7 +#define OID_RT_GET_LOG 0xFF0101B8 +#define OID_RT_SET_INDICATE_HIDDEN_AP 0xFF0101B9 +#define OID_RT_GET_HEADER_FAIL 0xFF0101BA +#define OID_RT_SUPPORTED_WIRELESS_MODE 0xFF0101BB +#define OID_RT_GET_CHANNEL_LIST 0xFF0101BC +#define OID_RT_GET_SCAN_IN_PROGRESS 0xFF0101BD +#define OID_RT_GET_TX_INFO 0xFF0101BE +#define OID_RT_RF_READ_WRITE_OFFSET 0xFF0101BF +#define OID_RT_RF_READ_WRITE 0xFF0101C0 +#define OID_RT_FORCED_DATA_RATE 0xFF0101C1 +#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST 0xFF0101C2 +#define OID_RT_GET_BSS_WIRELESS_MODE 0xFF0101C3 +#define OID_RT_SCAN_WITH_MAGIC_PACKET 0xFF0101C4 +#define OID_RT_PRO_RX_FILTER 0xFF0111C0 +#define OID_CE_USB_WRITE_REGISTRY 0xFF0111C1 +#define OID_CE_USB_READ_REGISTRY 0xFF0111C2 +#define OID_RT_PRO_SET_INITIAL_GAIN 0xFF0111C3 +#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE 0xFF0111C4 +#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE 0xFF0111C5 +#define OID_RT_PRO_SET_TX_CHARGE_PUMP 0xFF0111C6 +#define OID_RT_PRO_SET_RX_CHARGE_PUMP 0xFF0111C7 +#define OID_RT_PRO_RF_WRITE_REGISTRY 0xFF0111C8 +#define OID_RT_PRO_RF_READ_REGISTRY 0xFF0111C9 +#define OID_RT_PRO_QUERY_RF_TYPE 0xFF0111CA +#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST 0xFF010300 +#define OID_RT_AP_GET_CURRENT_TIME_STAMP 0xFF010301 +#define OID_RT_AP_SWITCH_INTO_AP_MODE 0xFF010302 +#define OID_RT_AP_SET_DTIM_PERIOD 0xFF010303 +#define OID_RT_AP_SUPPORTED 0xFF010304 +#define OID_RT_AP_SET_PASSPHRASE 0xFF010305 +#define OID_RT_PRO8187_WI_POLL 0xFF818780 +#define OID_RT_PRO_WRITE_BB_REG 0xFF818781 +#define OID_RT_PRO_READ_BB_REG 0xFF818782 +#define OID_RT_PRO_WRITE_RF_REG 0xFF818783 +#define OID_RT_PRO_READ_RF_REG 0xFF818784 +#define OID_RT_MH_VENDER_ID 0xFFEDC100 +#define OID_RT_PRO8711_JOIN_BSS 0xFF871100 +#define OID_RT_PRO_READ_REGISTER 0xFF871101 +#define OID_RT_PRO_WRITE_REGISTER 0xFF871102 +#define OID_RT_PRO_BURST_READ_REGISTER 0xFF871103 +#define OID_RT_PRO_BURST_WRITE_REGISTER 0xFF871104 +#define OID_RT_PRO_WRITE_TXCMD 0xFF871105 +#define OID_RT_PRO_READ16_EEPROM 0xFF871106 +#define OID_RT_PRO_WRITE16_EEPROM 0xFF871107 +#define OID_RT_PRO_H2C_SET_COMMAND 0xFF871108 +#define OID_RT_PRO_H2C_QUERY_RESULT 0xFF871109 +#define OID_RT_PRO8711_WI_POLL 0xFF87110A +#define OID_RT_PRO8711_PKT_LOSS 0xFF87110B +#define OID_RT_RD_ATTRIB_MEM 0xFF87110C +#define OID_RT_WR_ATTRIB_MEM 0xFF87110D +/*Method 2 for H2C/C2H*/ +#define OID_RT_PRO_H2C_CMD_MODE 0xFF871110 +#define OID_RT_PRO_H2C_CMD_RSP_MODE 0xFF871111 +#define OID_RT_PRO_H2C_CMD_EVENT_MODE 0xFF871112 +#define OID_RT_PRO_WAIT_C2H_EVENT 0xFF871113 +#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST 0xFF871114 +#define OID_RT_PRO_SCSI_ACCESS_TEST 0xFF871115 +#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT 0xFF871116 +#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN 0xFF871117 +#define OID_RT_RRO_RX_PKT_VIA_IOCTRL 0xFF871118 +#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL 0xFF871119 +#define OID_RT_RPO_SET_PWRMGT_TEST 0xFF87111A +#define OID_RT_PRO_QRY_PWRMGT_TEST 0XFF87111B +#define OID_RT_RPO_ASYNC_RWIO_TEST 0xFF87111C +#define OID_RT_RPO_ASYNC_RWIO_POLL 0xFF87111D +#define OID_RT_PRO_SET_RF_INTFS 0xFF87111E +#define OID_RT_POLL_RX_STATUS 0xFF87111F +#define OID_RT_PRO_CFG_DEBUG_MESSAGE 0xFF871120 +#define OID_RT_PRO_SET_DATA_RATE_EX 0xFF871121 +#define OID_RT_PRO_SET_BASIC_RATE 0xFF871122 +#define OID_RT_PRO_READ_TSSI 0xFF871123 +#define OID_RT_PRO_SET_POWER_TRACKING 0xFF871124 +#define OID_RT_PRO_QRY_PWRSTATE 0xFF871150 +#define OID_RT_PRO_SET_PWRSTATE 0xFF871151 +/*Method 2 , using workitem */ +#define OID_RT_SET_READ_REG 0xFF871181 +#define OID_RT_SET_WRITE_REG 0xFF871182 +#define OID_RT_SET_BURST_READ_REG 0xFF871183 +#define OID_RT_SET_BURST_WRITE_REG 0xFF871184 +#define OID_RT_SET_WRITE_TXCMD 0xFF871185 +#define OID_RT_SET_READ16_EEPROM 0xFF871186 +#define OID_RT_SET_WRITE16_EEPROM 0xFF871187 +#define OID_RT_QRY_POLL_WKITEM 0xFF871188 + +/*For SDIO INTERFACE only*/ +#define OID_RT_PRO_SYNCPAGERW_SRAM 0xFF8711A0 +#define OID_RT_PRO_871X_DRV_EXT 0xFF8711A1 + +/*For USB INTERFACE only*/ +#define OID_RT_PRO_USB_VENDOR_REQ 0xFF8711B0 +#define OID_RT_PRO_SCSI_AUTO_TEST 0xFF8711B1 +#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE 0xFF8711B2 +#define OID_RT_PRO_USB_MAC_RX_FIFO_READ 0xFF8711B3 +#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING 0xFF8711B4 + +#define OID_RT_PRO_H2C_SET_RATE_TABLE 0xFF8711FB +#define OID_RT_PRO_H2C_GET_RATE_TABLE 0xFF8711FC +#define OID_RT_PRO_H2C_C2H_LBK_TEST 0xFF8711FE + +#define OID_RT_PRO_ENCRYPTION_CTRL 0xFF871200 +#define OID_RT_PRO_ADD_STA_INFO 0xFF871201 +#define OID_RT_PRO_DELE_STA_INFO 0xFF871202 +#define OID_RT_PRO_QUERY_DR_VARIABLE 0xFF871203 + +#define OID_RT_PRO_RX_PACKET_TYPE 0xFF871204 + +#define OID_RT_PRO_READ_EFUSE 0xFF871205 +#define OID_RT_PRO_WRITE_EFUSE 0xFF871206 +#define OID_RT_PRO_RW_EFUSE_PGPKT 0xFF871207 +#define OID_RT_GET_EFUSE_CURRENT_SIZE 0xFF871208 + +#define OID_RT_SET_BANDWIDTH 0xFF871209 +#define OID_RT_SET_CRYSTAL_CAP 0xFF87120A + +#define OID_RT_SET_RX_PACKET_TYPE 0xFF87120B + +#define OID_RT_GET_EFUSE_MAX_SIZE 0xFF87120C + +#define OID_RT_PRO_SET_TX_AGC_OFFSET 0xFF87120D + +#define OID_RT_PRO_SET_PKT_TEST_MODE 0xFF87120E + +#define OID_RT_PRO_FOR_EVM_TEST_SETTING 0xFF87120F + +#define OID_RT_PRO_GET_THERMAL_METER 0xFF871210 + +#define OID_RT_RESET_PHY_RX_PACKET_COUNT 0xFF871211 +#define OID_RT_GET_PHY_RX_PACKET_RECEIVED 0xFF871212 +#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR 0xFF871213 + +#define OID_RT_SET_POWER_DOWN 0xFF871214 + +#define OID_RT_GET_POWER_MODE 0xFF871215 + +#define OID_RT_PRO_EFUSE 0xFF871216 +#define OID_RT_PRO_EFUSE_MAP 0xFF871217 + +#endif /*#ifndef __CUSTOM_OID_H */ + diff --git a/kernel/drivers/staging/rtl8712/os_intfs.c b/kernel/drivers/staging/rtl8712/os_intfs.c new file mode 100644 index 000000000..6e776e543 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/os_intfs.c @@ -0,0 +1,478 @@ +/****************************************************************************** + * os_intfs.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _OS_INTFS_C_ + +#include <linux/module.h> +#include <linux/kthread.h> +#include <linux/firmware.h> +#include "osdep_service.h" +#include "drv_types.h" +#include "xmit_osdep.h" +#include "recv_osdep.h" +#include "rtl871x_ioctl.h" +#include "usb_osintf.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("rtl871x wireless lan driver"); +MODULE_AUTHOR("Larry Finger"); + +static char ifname[IFNAMSIZ] = "wlan%d"; + +/* module param defaults */ +static int chip_version = RTL8712_2ndCUT; +static int rfintfs = HWPI; +static int lbkmode = RTL8712_AIR_TRX; +static int hci = RTL8712_USB; +static int ampdu_enable = 1;/*for enable tx_ampdu*/ + +/* The video_mode variable is for video mode.*/ +/* It may be specify when inserting module with video_mode=1 parameter.*/ +static int video_mode = 1; /* enable video mode*/ + +/*Ndis802_11Infrastructure; infra, ad-hoc, auto*/ +static int network_mode = Ndis802_11IBSS; +static int channel = 1;/*ad-hoc support requirement*/ +static int wireless_mode = WIRELESS_11BG; +static int vrtl_carrier_sense = AUTO_VCS; +static int vcs_type = RTS_CTS; +static int frag_thresh = 2346; +static int preamble = PREAMBLE_LONG;/*long, short, auto*/ +static int scan_mode = 1;/*active, passive*/ +static int adhoc_tx_pwr = 1; +static int soft_ap; +static int smart_ps = 1; +static int power_mgnt = PS_MODE_ACTIVE; +static int radio_enable = 1; +static int long_retry_lmt = 7; +static int short_retry_lmt = 7; +static int busy_thresh = 40; +static int ack_policy = NORMAL_ACK; +static int mp_mode; +static int software_encrypt; +static int software_decrypt; + +static int wmm_enable;/* default is set to disable the wmm.*/ +static int uapsd_enable; +static int uapsd_max_sp = NO_LIMIT; +static int uapsd_acbk_en; +static int uapsd_acbe_en; +static int uapsd_acvi_en; +static int uapsd_acvo_en; + +static int ht_enable = 1; +static int cbw40_enable = 1; +static int rf_config = RTL8712_RF_1T2R; /* 1T2R*/ +static int low_power; +/* mac address to use instead of the one stored in Efuse */ +char *r8712_initmac; +static char *initmac; +/* if wifi_test = 1, driver will disable the turbo mode and pass it to + * firmware private. + */ +static int wifi_test; + +module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR); +module_param(wifi_test, int, 0644); +module_param(initmac, charp, 0644); +module_param(video_mode, int, 0644); +module_param(chip_version, int, 0644); +module_param(rfintfs, int, 0644); +module_param(lbkmode, int, 0644); +module_param(hci, int, 0644); +module_param(network_mode, int, 0644); +module_param(channel, int, 0644); +module_param(mp_mode, int, 0644); +module_param(wmm_enable, int, 0644); +module_param(vrtl_carrier_sense, int, 0644); +module_param(vcs_type, int, 0644); +module_param(busy_thresh, int, 0644); +module_param(ht_enable, int, 0644); +module_param(cbw40_enable, int, 0644); +module_param(ampdu_enable, int, 0644); +module_param(rf_config, int, 0644); +module_param(power_mgnt, int, 0644); +module_param(low_power, int, 0644); + +MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default"); +MODULE_PARM_DESC(initmac, "MAC-Address, default: use FUSE"); + +static uint loadparam(struct _adapter *padapter, struct net_device *pnetdev); +static int netdev_open(struct net_device *pnetdev); +static int netdev_close(struct net_device *pnetdev); + +static uint loadparam(struct _adapter *padapter, struct net_device *pnetdev) +{ + uint status = _SUCCESS; + struct registry_priv *registry_par = &padapter->registrypriv; + + registry_par->chip_version = (u8)chip_version; + registry_par->rfintfs = (u8)rfintfs; + registry_par->lbkmode = (u8)lbkmode; + registry_par->hci = (u8)hci; + registry_par->network_mode = (u8)network_mode; + memcpy(registry_par->ssid.Ssid, "ANY", 3); + registry_par->ssid.SsidLength = 3; + registry_par->channel = (u8)channel; + registry_par->wireless_mode = (u8)wireless_mode; + registry_par->vrtl_carrier_sense = (u8)vrtl_carrier_sense; + registry_par->vcs_type = (u8)vcs_type; + registry_par->frag_thresh = (u16)frag_thresh; + registry_par->preamble = (u8)preamble; + registry_par->scan_mode = (u8)scan_mode; + registry_par->adhoc_tx_pwr = (u8)adhoc_tx_pwr; + registry_par->soft_ap = (u8)soft_ap; + registry_par->smart_ps = (u8)smart_ps; + registry_par->power_mgnt = (u8)power_mgnt; + registry_par->radio_enable = (u8)radio_enable; + registry_par->long_retry_lmt = (u8)long_retry_lmt; + registry_par->short_retry_lmt = (u8)short_retry_lmt; + registry_par->busy_thresh = (u16)busy_thresh; + registry_par->ack_policy = (u8)ack_policy; + registry_par->mp_mode = (u8)mp_mode; + registry_par->software_encrypt = (u8)software_encrypt; + registry_par->software_decrypt = (u8)software_decrypt; + /*UAPSD*/ + registry_par->wmm_enable = (u8)wmm_enable; + registry_par->uapsd_enable = (u8)uapsd_enable; + registry_par->uapsd_max_sp = (u8)uapsd_max_sp; + registry_par->uapsd_acbk_en = (u8)uapsd_acbk_en; + registry_par->uapsd_acbe_en = (u8)uapsd_acbe_en; + registry_par->uapsd_acvi_en = (u8)uapsd_acvi_en; + registry_par->uapsd_acvo_en = (u8)uapsd_acvo_en; + registry_par->ht_enable = (u8)ht_enable; + registry_par->cbw40_enable = (u8)cbw40_enable; + registry_par->ampdu_enable = (u8)ampdu_enable; + registry_par->rf_config = (u8)rf_config; + registry_par->low_power = (u8)low_power; + registry_par->wifi_test = (u8) wifi_test; + r8712_initmac = initmac; + return status; +} + +static int r871x_net_set_mac_address(struct net_device *pnetdev, void *p) +{ + struct _adapter *padapter = netdev_priv(pnetdev); + struct sockaddr *addr = p; + + if (padapter->bup == false) + memcpy(pnetdev->dev_addr, addr->sa_data, ETH_ALEN); + return 0; +} + +static struct net_device_stats *r871x_net_get_stats(struct net_device *pnetdev) +{ + struct _adapter *padapter = netdev_priv(pnetdev); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct recv_priv *precvpriv = &(padapter->recvpriv); + + padapter->stats.tx_packets = pxmitpriv->tx_pkts; + padapter->stats.rx_packets = precvpriv->rx_pkts; + padapter->stats.tx_dropped = pxmitpriv->tx_drop; + padapter->stats.rx_dropped = precvpriv->rx_drop; + padapter->stats.tx_bytes = pxmitpriv->tx_bytes; + padapter->stats.rx_bytes = precvpriv->rx_bytes; + return &padapter->stats; +} + +static const struct net_device_ops rtl8712_netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = r8712_xmit_entry, + .ndo_set_mac_address = r871x_net_set_mac_address, + .ndo_get_stats = r871x_net_get_stats, + .ndo_do_ioctl = r871x_ioctl, +}; + +struct net_device *r8712_init_netdev(void) +{ + struct _adapter *padapter; + struct net_device *pnetdev; + + pnetdev = alloc_etherdev(sizeof(struct _adapter)); + if (!pnetdev) + return NULL; + if (dev_alloc_name(pnetdev, ifname) < 0) { + strcpy(ifname, "wlan%d"); + dev_alloc_name(pnetdev, ifname); + } + padapter = netdev_priv(pnetdev); + padapter->pnetdev = pnetdev; + pr_info("r8712u: register rtl8712_netdev_ops to netdev_ops\n"); + pnetdev->netdev_ops = &rtl8712_netdev_ops; + pnetdev->watchdog_timeo = HZ; /* 1 second timeout */ + pnetdev->wireless_handlers = (struct iw_handler_def *) + &r871x_handlers_def; + /*step 2.*/ + loadparam(padapter, pnetdev); + netif_carrier_off(pnetdev); + padapter->pid = 0; /* Initial the PID value used for HW PBC.*/ + return pnetdev; +} + +static u32 start_drv_threads(struct _adapter *padapter) +{ + padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s", + padapter->pnetdev->name); + if (IS_ERR(padapter->cmdThread)) + return _FAIL; + return _SUCCESS; +} + +void r8712_stop_drv_threads(struct _adapter *padapter) +{ + /*Below is to terminate r8712_cmd_thread & event_thread...*/ + up(&padapter->cmdpriv.cmd_queue_sema); + if (padapter->cmdThread) + _down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); + padapter->cmdpriv.cmd_seq = 1; +} + +static void start_drv_timers(struct _adapter *padapter) +{ + mod_timer(&padapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, + jiffies + msecs_to_jiffies(5000)); + mod_timer(&padapter->mlmepriv.wdg_timer, + jiffies + msecs_to_jiffies(2000)); +} + +void r8712_stop_drv_timers(struct _adapter *padapter) +{ + del_timer_sync(&padapter->mlmepriv.assoc_timer); + del_timer_sync(&padapter->securitypriv.tkip_timer); + del_timer_sync(&padapter->mlmepriv.scan_to_timer); + del_timer_sync(&padapter->mlmepriv.dhcp_timer); + del_timer_sync(&padapter->mlmepriv.wdg_timer); + del_timer_sync(&padapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer); +} + +static u8 init_default_value(struct _adapter *padapter) +{ + u8 ret = _SUCCESS; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + /*xmit_priv*/ + pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; + pxmitpriv->vcs = pregistrypriv->vcs_type; + pxmitpriv->vcs_type = pregistrypriv->vcs_type; + pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; + pxmitpriv->frag_len = pregistrypriv->frag_thresh; + /* mlme_priv */ + /* Maybe someday we should rename this variable to "active_mode"(Jeff)*/ + pmlmepriv->passive_mode = 1; /* 1: active, 0: passive. */ + /*ht_priv*/ + { + int i; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + phtpriv->ampdu_enable = false;/*set to disabled*/ + for (i = 0; i < 16; i++) + phtpriv->baddbareq_issued[i] = false; + } + /*security_priv*/ + psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt; + psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt; + psecuritypriv->binstallGrpkey = _FAIL; + /*pwrctrl_priv*/ + /*registry_priv*/ + r8712_init_registrypriv_dev_network(padapter); + r8712_update_registrypriv_dev_network(padapter); + /*misc.*/ + return ret; +} + +u8 r8712_init_drv_sw(struct _adapter *padapter) +{ + if ((r8712_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) + return _FAIL; + padapter->cmdpriv.padapter = padapter; + if ((r8712_init_evt_priv(&padapter->evtpriv)) == _FAIL) + return _FAIL; + if (r8712_init_mlme_priv(padapter) == _FAIL) + return _FAIL; + _r8712_init_xmit_priv(&padapter->xmitpriv, padapter); + _r8712_init_recv_priv(&padapter->recvpriv, padapter); + memset((unsigned char *)&padapter->securitypriv, 0, + sizeof(struct security_priv)); + setup_timer(&padapter->securitypriv.tkip_timer, + r8712_use_tkipkey_handler, (unsigned long)padapter); + _r8712_init_sta_priv(&padapter->stapriv); + padapter->stapriv.padapter = padapter; + r8712_init_bcmc_stainfo(padapter); + r8712_init_pwrctrl_priv(padapter); + mp871xinit(padapter); + if (init_default_value(padapter) != _SUCCESS) + return _FAIL; + r8712_InitSwLeds(padapter); + return _SUCCESS; +} + +u8 r8712_free_drv_sw(struct _adapter *padapter) +{ + struct net_device *pnetdev = (struct net_device *)padapter->pnetdev; + + r8712_free_cmd_priv(&padapter->cmdpriv); + r8712_free_evt_priv(&padapter->evtpriv); + r8712_DeInitSwLeds(padapter); + r8712_free_mlme_priv(&padapter->mlmepriv); + r8712_free_io_queue(padapter); + _free_xmit_priv(&padapter->xmitpriv); + _r8712_free_sta_priv(&padapter->stapriv); + _r8712_free_recv_priv(&padapter->recvpriv); + mp871xdeinit(padapter); + if (pnetdev) + free_netdev(pnetdev); + return _SUCCESS; +} + + +static void enable_video_mode(struct _adapter *padapter, int cbw40_value) +{ + /* bit 8: + * 1 -> enable video mode to 96B AP + * 0 -> disable video mode to 96B AP + * bit 9: + * 1 -> enable 40MHz mode + * 0 -> disable 40MHz mode + * bit 10: + * 1 -> enable STBC + * 0 -> disable STBC + */ + u32 intcmd = 0xf4000500; /* enable bit8, bit10*/ + + if (cbw40_value) { + /* if the driver supports the 40M bandwidth, + * we can enable the bit 9.*/ + intcmd |= 0x200; + } + r8712_fw_cmd(padapter, intcmd); +} + +/** + * + * This function intends to handle the activation of an interface + * i.e. when it is brought Up/Active from a Down state. + * + */ +static int netdev_open(struct net_device *pnetdev) +{ + struct _adapter *padapter = netdev_priv(pnetdev); + + mutex_lock(&padapter->mutex_start); + if (padapter->bup == false) { + padapter->bDriverStopped = false; + padapter->bSurpriseRemoved = false; + padapter->bup = true; + if (rtl871x_hal_init(padapter) != _SUCCESS) + goto netdev_open_error; + if (r8712_initmac == NULL) + /* Use the mac address stored in the Efuse */ + memcpy(pnetdev->dev_addr, + padapter->eeprompriv.mac_addr, ETH_ALEN); + else { + /* We have to inform f/w to use user-supplied MAC + * address. + */ + msleep(200); + r8712_setMacAddr_cmd(padapter, (u8 *)pnetdev->dev_addr); + /* + * The "myid" function will get the wifi mac address + * from eeprompriv structure instead of netdev + * structure. So, we have to overwrite the mac_addr + * stored in the eeprompriv structure. In this case, + * the real mac address won't be used anymore. So that, + * the eeprompriv.mac_addr should store the mac which + * users specify. + */ + memcpy(padapter->eeprompriv.mac_addr, + pnetdev->dev_addr, ETH_ALEN); + } + if (start_drv_threads(padapter) != _SUCCESS) + goto netdev_open_error; + if (padapter->dvobjpriv.inirp_init == NULL) + goto netdev_open_error; + else + padapter->dvobjpriv.inirp_init(padapter); + r8712_set_ps_mode(padapter, padapter->registrypriv.power_mgnt, + padapter->registrypriv.smart_ps); + } + if (!netif_queue_stopped(pnetdev)) + netif_start_queue(pnetdev); + else + netif_wake_queue(pnetdev); + + if (video_mode) + enable_video_mode(padapter, cbw40_enable); + /* start driver mlme relation timer */ + start_drv_timers(padapter); + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); + mutex_unlock(&padapter->mutex_start); + return 0; +netdev_open_error: + padapter->bup = false; + netif_carrier_off(pnetdev); + netif_stop_queue(pnetdev); + mutex_unlock(&padapter->mutex_start); + return -1; +} + +/** + * + * This function intends to handle the shutdown of an interface + * i.e. when it is brought Down from an Up/Active state. + * + */ +static int netdev_close(struct net_device *pnetdev) +{ + struct _adapter *padapter = netdev_priv(pnetdev); + + /* Close LED*/ + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_POWER_OFF); + msleep(200); + + /*s1.*/ + if (pnetdev) { + if (!netif_queue_stopped(pnetdev)) + netif_stop_queue(pnetdev); + } + /*s2.*/ + /*s2-1. issue disassoc_cmd to fw*/ + r8712_disassoc_cmd(padapter); + /*s2-2. indicate disconnect to os*/ + r8712_ind_disconnect(padapter); + /*s2-3.*/ + r8712_free_assoc_resources(padapter); + /*s2-4.*/ + r8712_free_network_queue(padapter); + return 0; +} + +#include "mlme_osdep.h" diff --git a/kernel/drivers/staging/rtl8712/osdep_intf.h b/kernel/drivers/staging/rtl8712/osdep_intf.h new file mode 100644 index 000000000..aa0ec74af --- /dev/null +++ b/kernel/drivers/staging/rtl8712/osdep_intf.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __OSDEP_INTF_H_ +#define __OSDEP_INTF_H_ + +#include "osdep_service.h" +#include "drv_types.h" + +#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0 : 1)) << 2) + +struct intf_priv { + u8 *intf_dev; + /* when in USB, IO is through interrupt in/out endpoints */ + struct usb_device *udev; + struct urb *piorw_urb; + struct semaphore io_retevt; +}; + +int r871x_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +#endif /*_OSDEP_INTF_H_*/ diff --git a/kernel/drivers/staging/rtl8712/osdep_service.h b/kernel/drivers/staging/rtl8712/osdep_service.h new file mode 100644 index 000000000..0a7f58c59 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/osdep_service.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __OSDEP_SERVICE_H_ +#define __OSDEP_SERVICE_H_ + +#define _SUCCESS 1 +#define _FAIL 0 + +#include <linux/spinlock.h> + +#include <linux/interrupt.h> +#include <linux/semaphore.h> +#include <linux/sched.h> +#include <linux/sem.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <net/iw_handler.h> +#include <linux/proc_fs.h> /* Necessary because we use the proc fs */ + +#include "basic_types.h" + +struct __queue { + struct list_head queue; + spinlock_t lock; +}; + +#define _pkt struct sk_buff +#define _buffer unsigned char +#define thread_exit() complete_and_exit(NULL, 0) + +#define _init_queue(pqueue) \ + do { \ + INIT_LIST_HEAD(&((pqueue)->queue)); \ + spin_lock_init(&((pqueue)->lock)); \ + } while (0) + +#define LIST_CONTAINOR(ptr, type, member) \ + ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) + +#ifndef BIT + #define BIT(x) (1 << (x)) +#endif + +static inline u32 _down_sema(struct semaphore *sema) +{ + if (down_interruptible(sema)) + return _FAIL; + return _SUCCESS; +} + +static inline u32 end_of_queue_search(struct list_head *head, + struct list_head *plist) +{ + return (head == plist); +} + +static inline void sleep_schedulable(int ms) +{ + u32 delta; + + delta = msecs_to_jiffies(ms);/*(ms)*/ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(delta); +} + +static inline void flush_signals_thread(void) +{ + if (signal_pending(current)) + flush_signals(current); +} + +#endif + diff --git a/kernel/drivers/staging/rtl8712/recv_linux.c b/kernel/drivers/staging/rtl8712/recv_linux.c new file mode 100644 index 000000000..799a0f9a5 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/recv_linux.c @@ -0,0 +1,153 @@ +/****************************************************************************** + * recv_linux.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RECV_OSDEP_C_ + +#include <linux/usb.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "wifi.h" +#include "recv_osdep.h" +#include "osdep_intf.h" +#include "ethernet.h" +#include <linux/if_arp.h> +#include "usb_ops.h" + +/*init os related resource in struct recv_priv*/ +/*alloc os related resource in union recv_frame*/ +int r8712_os_recv_resource_alloc(struct _adapter *padapter, + union recv_frame *precvframe) +{ + precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL; + return _SUCCESS; +} + +/*alloc os related resource in struct recv_buf*/ +int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter, + struct recv_buf *precvbuf) +{ + int res = _SUCCESS; + + precvbuf->irp_pending = false; + precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); + if (precvbuf->purb == NULL) + res = _FAIL; + precvbuf->pskb = NULL; + precvbuf->reuse = false; + precvbuf->pallocated_buf = NULL; + precvbuf->pbuf = NULL; + precvbuf->pdata = NULL; + precvbuf->phead = NULL; + precvbuf->ptail = NULL; + precvbuf->pend = NULL; + precvbuf->transfer_len = 0; + precvbuf->len = 0; + return res; +} + +/*free os related resource in struct recv_buf*/ +int r8712_os_recvbuf_resource_free(struct _adapter *padapter, + struct recv_buf *precvbuf) +{ + if (precvbuf->pskb) + dev_kfree_skb_any(precvbuf->pskb); + if (precvbuf->purb) { + usb_kill_urb(precvbuf->purb); + usb_free_urb(precvbuf->purb); + } + return _SUCCESS; +} + +void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup) +{ + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + memset(&ev, 0x00, sizeof(ev)); + if (bgroup) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + ev.src_addr.sa_family = ARPHRD_ETHER; + ether_addr_copy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0]); + memset(&wrqu, 0x00, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu, + (char *)&ev); +} + +void r8712_recv_indicatepkt(struct _adapter *padapter, + union recv_frame *precv_frame) +{ + struct recv_priv *precvpriv; + struct __queue *pfree_recv_queue; + _pkt *skb; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + + precvpriv = &(padapter->recvpriv); + pfree_recv_queue = &(precvpriv->free_recv_queue); + skb = precv_frame->u.hdr.pkt; + if (skb == NULL) + goto _recv_indicatepkt_drop; + skb->data = precv_frame->u.hdr.rx_data; + skb->len = precv_frame->u.hdr.len; + skb_set_tail_pointer(skb, skb->len); + if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + skb->dev = padapter->pnetdev; + skb->protocol = eth_type_trans(skb, padapter->pnetdev); + netif_rx(skb); + precv_frame->u.hdr.pkt = NULL; /* pointers to NULL before + * r8712_free_recvframe() */ + r8712_free_recvframe(precv_frame, pfree_recv_queue); + return; +_recv_indicatepkt_drop: + /*enqueue back to free_recv_queue*/ + if (precv_frame) + r8712_free_recvframe(precv_frame, pfree_recv_queue); + precvpriv->rx_drop++; +} + +static void _r8712_reordering_ctrl_timeout_handler (unsigned long data) +{ + struct recv_reorder_ctrl *preorder_ctrl = + (struct recv_reorder_ctrl *)data; + + r8712_reordering_ctrl_timeout_handler(preorder_ctrl); +} + +void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl) +{ + setup_timer(&preorder_ctrl->reordering_ctrl_timer, + _r8712_reordering_ctrl_timeout_handler, + (unsigned long)preorder_ctrl); +} diff --git a/kernel/drivers/staging/rtl8712/recv_osdep.h b/kernel/drivers/staging/rtl8712/recv_osdep.h new file mode 100644 index 000000000..1f4986e94 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/recv_osdep.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RECV_OSDEP_H_ +#define __RECV_OSDEP_H_ + +#include "osdep_service.h" +#include "drv_types.h" +#include <linux/skbuff.h> + +sint _r8712_init_recv_priv(struct recv_priv *precvpriv, + struct _adapter *padapter); +void _r8712_free_recv_priv(struct recv_priv *precvpriv); +s32 r8712_recv_entry(union recv_frame *precv_frame); +void r8712_recv_indicatepkt(struct _adapter *adapter, + union recv_frame *precv_frame); +void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup); +int r8712_init_recv_priv(struct recv_priv *precvpriv, + struct _adapter *padapter); +void r8712_free_recv_priv(struct recv_priv *precvpriv); +int r8712_os_recv_resource_alloc(struct _adapter *padapter, + union recv_frame *precvframe); +int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter, + struct recv_buf *precvbuf); +int r8712_os_recvbuf_resource_free(struct _adapter *padapter, + struct recv_buf *precvbuf); +void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); + +#endif diff --git a/kernel/drivers/staging/rtl8712/rtl8712_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_bitdef.h new file mode 100644 index 000000000..bff57a8ee --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_bitdef.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + +#ifndef __RTL8712_BITDEF_H__ +#define __RTL8712_BITDEF_H__ + +#include "rtl8712_cmdctrl_bitdef.h" +#include "rtl8712_syscfg_bitdef.h" +#include "rtl8712_macsetting_bitdef.h" +#include "rtl8712_timectrl_bitdef.h" +#include "rtl8712_fifoctrl_bitdef.h" +#include "rtl8712_ratectrl_bitdef.h" +#include "rtl8712_edcasetting_bitdef.h" +#include "rtl8712_wmac_bitdef.h" +#include "rtl8712_security_bitdef.h" +#include "rtl8712_powersave_bitdef.h" +#include "rtl8712_gp_bitdef.h" +#include "rtl8712_interrupt_bitdef.h" +#include "rtl8712_debugctrl_bitdef.h" + +#endif /* __RTL8712_BITDEF_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_cmd.c b/kernel/drivers/staging/rtl8712/rtl8712_cmd.c new file mode 100644 index 000000000..007f0a3ab --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_cmd.c @@ -0,0 +1,469 @@ +/****************************************************************************** + * rtl8712_cmd.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL8712_CMD_C_ + +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kref.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/usb.h> +#include <linux/usb/ch9.h> +#include <linux/circ_buf.h> +#include <linux/uaccess.h> +#include <asm/byteorder.h> +#include <linux/atomic.h> +#include <linux/semaphore.h> +#include <linux/rtnetlink.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "recv_osdep.h" +#include "mlme_osdep.h" +#include "rtl871x_ioctl_set.h" + +static void check_hw_pbc(struct _adapter *padapter) +{ + u8 tmp1byte; + + r8712_write8(padapter, MAC_PINMUX_CTRL, (GPIOMUX_EN | GPIOSEL_GPIO)); + tmp1byte = r8712_read8(padapter, GPIO_IO_SEL); + tmp1byte &= ~(HAL_8192S_HW_GPIO_WPS_BIT); + r8712_write8(padapter, GPIO_IO_SEL, tmp1byte); + tmp1byte = r8712_read8(padapter, GPIO_CTRL); + if (tmp1byte == 0xff) + return; + if (tmp1byte&HAL_8192S_HW_GPIO_WPS_BIT) { + /* Here we only set bPbcPressed to true + * After trigger PBC, the variable will be set to false */ + DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n"); + /* 0 is the default value and it means the application monitors + * the HW PBC doesn't provide its pid to driver. */ + if (padapter->pid == 0) + return; + kill_pid(find_vpid(padapter->pid), SIGUSR1, 1); + } +} + +/* query rx phy status from fw. + * Adhoc mode: beacon. + * Infrastructure mode: beacon , data. */ +static void query_fw_rx_phy_status(struct _adapter *padapter) +{ + u32 val32 = 0; + int pollingcnts = 50; + + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == true) { + r8712_write32(padapter, IOCMD_CTRL_REG, 0xf4000001); + msleep(100); + /* Wait FW complete IO Cmd */ + while ((r8712_read32(padapter, IOCMD_CTRL_REG)) && + (pollingcnts > 0)) { + pollingcnts--; + msleep(20); + } + if (pollingcnts != 0) + val32 = r8712_read32(padapter, IOCMD_DATA_REG); + else /* time out */ + val32 = 0; + val32 >>= 4; + padapter->recvpriv.fw_rssi = + (u8)r8712_signal_scale_mapping(val32); + } +} + +/* check mlme, hw, phy, or dynamic algorithm status. */ +static void StatusWatchdogCallback(struct _adapter *padapter) +{ + check_hw_pbc(padapter); + query_fw_rx_phy_status(padapter); +} + +static void r871x_internal_cmd_hdl(struct _adapter *padapter, u8 *pbuf) +{ + struct drvint_cmd_parm *pdrvcmd; + + if (!pbuf) + return; + pdrvcmd = (struct drvint_cmd_parm *)pbuf; + switch (pdrvcmd->i_cid) { + case WDG_WK_CID: + StatusWatchdogCallback(padapter); + break; + default: + break; + } + kfree(pdrvcmd->pbuf); +} + +static u8 read_macreg_hdl(struct _adapter *padapter, u8 *pbuf) +{ + void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; + + /* invoke cmd->callback function */ + pcmd_callback = cmd_callback[pcmd->cmdcode].callback; + if (pcmd_callback == NULL) + r8712_free_cmd_obj(pcmd); + else + pcmd_callback(padapter, pcmd); + return H2C_SUCCESS; +} + +static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf) +{ + void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; + + /* invoke cmd->callback function */ + pcmd_callback = cmd_callback[pcmd->cmdcode].callback; + if (pcmd_callback == NULL) + r8712_free_cmd_obj(pcmd); + else + pcmd_callback(padapter, pcmd); + return H2C_SUCCESS; +} + +static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) +{ + u32 val; + void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; + + if (pcmd->rsp && pcmd->rspsz > 0) + memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz); + pcmd_callback = cmd_callback[pcmd->cmdcode].callback; + if (pcmd_callback == NULL) + r8712_free_cmd_obj(pcmd); + else + pcmd_callback(padapter, pcmd); + return H2C_SUCCESS; +} + +static u8 write_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) +{ + void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; + + pcmd_callback = cmd_callback[pcmd->cmdcode].callback; + if (pcmd_callback == NULL) + r8712_free_cmd_obj(pcmd); + else + pcmd_callback(padapter, pcmd); + return H2C_SUCCESS; +} + +static u8 read_rfreg_hdl(struct _adapter *padapter, u8 *pbuf) +{ + u32 val; + void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; + + if (pcmd->rsp && pcmd->rspsz > 0) + memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz); + pcmd_callback = cmd_callback[pcmd->cmdcode].callback; + if (pcmd_callback == NULL) + r8712_free_cmd_obj(pcmd); + else + pcmd_callback(padapter, pcmd); + return H2C_SUCCESS; +} + +static u8 write_rfreg_hdl(struct _adapter *padapter, u8 *pbuf) +{ + void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; + + pcmd_callback = cmd_callback[pcmd->cmdcode].callback; + if (pcmd_callback == NULL) + r8712_free_cmd_obj(pcmd); + else + pcmd_callback(padapter, pcmd); + return H2C_SUCCESS; +} + +static u8 sys_suspend_hdl(struct _adapter *padapter, u8 *pbuf) +{ + struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; + + r8712_free_cmd_obj(pcmd); + return H2C_SUCCESS; +} + +static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter, + struct cmd_obj *pcmd) +{ + struct cmd_obj *pcmd_r; + + if (pcmd == NULL) + return pcmd; + pcmd_r = NULL; + + switch (pcmd->cmdcode) { + case GEN_CMD_CODE(_Read_MACREG): + read_macreg_hdl(padapter, (u8 *)pcmd); + pcmd_r = pcmd; + break; + case GEN_CMD_CODE(_Write_MACREG): + write_macreg_hdl(padapter, (u8 *)pcmd); + pcmd_r = pcmd; + break; + case GEN_CMD_CODE(_Read_BBREG): + read_bbreg_hdl(padapter, (u8 *)pcmd); + break; + case GEN_CMD_CODE(_Write_BBREG): + write_bbreg_hdl(padapter, (u8 *)pcmd); + break; + case GEN_CMD_CODE(_Read_RFREG): + read_rfreg_hdl(padapter, (u8 *)pcmd); + break; + case GEN_CMD_CODE(_Write_RFREG): + write_rfreg_hdl(padapter, (u8 *)pcmd); + break; + case GEN_CMD_CODE(_SetUsbSuspend): + sys_suspend_hdl(padapter, (u8 *)pcmd); + break; + case GEN_CMD_CODE(_JoinBss): + r8712_joinbss_reset(padapter); + /* Before set JoinBss_CMD to FW, driver must ensure FW is in + * PS_MODE_ACTIVE. Directly write rpwm to radio on and assign + * new pwr_mode to Driver, instead of use workitem to change + * state. */ + if (padapter->pwrctrlpriv.pwr_mode > PS_MODE_ACTIVE) { + padapter->pwrctrlpriv.pwr_mode = PS_MODE_ACTIVE; + _enter_pwrlock(&(padapter->pwrctrlpriv.lock)); + r8712_set_rpwm(padapter, PS_STATE_S4); + up(&(padapter->pwrctrlpriv.lock)); + } + pcmd_r = pcmd; + break; + case _DRV_INT_CMD_: + r871x_internal_cmd_hdl(padapter, pcmd->parmbuf); + r8712_free_cmd_obj(pcmd); + pcmd_r = NULL; + break; + default: + pcmd_r = pcmd; + break; + } + return pcmd_r; /* if returning pcmd_r == NULL, pcmd must be free. */ +} + +static u8 check_cmd_fifo(struct _adapter *padapter, uint sz) +{ + return _SUCCESS; +} + +u8 r8712_fw_cmd(struct _adapter *pAdapter, u32 cmd) +{ + int pollingcnts = 50; + + r8712_write32(pAdapter, IOCMD_CTRL_REG, cmd); + msleep(100); + while ((0 != r8712_read32(pAdapter, IOCMD_CTRL_REG)) && + (pollingcnts > 0)) { + pollingcnts--; + msleep(20); + } + if (pollingcnts == 0) + return false; + return true; +} + +void r8712_fw_cmd_data(struct _adapter *pAdapter, u32 *value, u8 flag) +{ + if (flag == 0) /* set */ + r8712_write32(pAdapter, IOCMD_DATA_REG, *value); + else /* query */ + *value = r8712_read32(pAdapter, IOCMD_DATA_REG); +} + +int r8712_cmd_thread(void *context) +{ + struct cmd_obj *pcmd; + unsigned int cmdsz, wr_sz, *pcmdbuf; + struct tx_desc *pdesc; + void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); + struct _adapter *padapter = (struct _adapter *)context; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + + allow_signal(SIGTERM); + while (1) { + if ((_down_sema(&(pcmdpriv->cmd_queue_sema))) == _FAIL) + break; + if ((padapter->bDriverStopped == true) || + (padapter->bSurpriseRemoved == true)) + break; + if (r8712_register_cmd_alive(padapter) != _SUCCESS) + continue; +_next: + pcmd = r8712_dequeue_cmd(&(pcmdpriv->cmd_queue)); + if (!(pcmd)) { + r8712_unregister_cmd_alive(padapter); + continue; + } + pcmdbuf = (unsigned int *)pcmdpriv->cmd_buf; + pdesc = (struct tx_desc *)pcmdbuf; + memset(pdesc, 0, TXDESC_SIZE); + pcmd = cmd_hdl_filter(padapter, pcmd); + if (pcmd) { /* if pcmd != NULL, cmd will be handled by f/w */ + struct dvobj_priv *pdvobj = (struct dvobj_priv *) + &padapter->dvobjpriv; + u8 blnPending = 0; + + pcmdpriv->cmd_issued_cnt++; + cmdsz = round_up(pcmd->cmdsz, 8); + wr_sz = TXDESC_SIZE + 8 + cmdsz; + pdesc->txdw0 |= cpu_to_le32((wr_sz-TXDESC_SIZE) & + 0x0000ffff); + if (pdvobj->ishighspeed) { + if ((wr_sz % 512) == 0) + blnPending = 1; + } else { + if ((wr_sz % 64) == 0) + blnPending = 1; + } + if (blnPending) /* 32 bytes for TX Desc - 8 offset */ + pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + + OFFSET_SZ + 8) << OFFSET_SHT) & + 0x00ff0000); + else { + pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + + OFFSET_SZ) << + OFFSET_SHT) & + 0x00ff0000); + } + pdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); + pdesc->txdw1 |= cpu_to_le32((0x13 << QSEL_SHT) & + 0x00001f00); + pcmdbuf += (TXDESC_SIZE >> 2); + *pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) | + (pcmd->cmdcode << 16) | + (pcmdpriv->cmd_seq << 24)); + pcmdbuf += 2; /* 8 bytes alignment */ + memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); + while (check_cmd_fifo(padapter, wr_sz) == _FAIL) { + if ((padapter->bDriverStopped == true) || + (padapter->bSurpriseRemoved == true)) + break; + msleep(100); + continue; + } + if (blnPending) + wr_sz += 8; /* Append 8 bytes */ + r8712_write_mem(padapter, RTL8712_DMA_H2CCMD, wr_sz, + (u8 *)pdesc); + pcmdpriv->cmd_seq++; + if (pcmd->cmdcode == GEN_CMD_CODE(_CreateBss)) { + pcmd->res = H2C_SUCCESS; + pcmd_callback = cmd_callback[pcmd-> + cmdcode].callback; + if (pcmd_callback) + pcmd_callback(padapter, pcmd); + continue; + } + if (pcmd->cmdcode == GEN_CMD_CODE(_SetPwrMode)) { + if (padapter->pwrctrlpriv.bSleep) { + _enter_pwrlock(&(padapter-> + pwrctrlpriv.lock)); + r8712_set_rpwm(padapter, PS_STATE_S2); + up(&padapter->pwrctrlpriv.lock); + } + } + r8712_free_cmd_obj(pcmd); + if (list_empty(&pcmdpriv->cmd_queue.queue)) { + r8712_unregister_cmd_alive(padapter); + continue; + } else + goto _next; + } else + goto _next; + flush_signals_thread(); + } + /* free all cmd_obj resources */ + do { + pcmd = r8712_dequeue_cmd(&(pcmdpriv->cmd_queue)); + if (pcmd == NULL) + break; + r8712_free_cmd_obj(pcmd); + } while (1); + up(&pcmdpriv->terminate_cmdthread_sema); + thread_exit(); +} + +void r8712_event_handle(struct _adapter *padapter, uint *peventbuf) +{ + u8 evt_code, evt_seq; + u16 evt_sz; + void (*event_callback)(struct _adapter *dev, u8 *pbuf); + struct evt_priv *pevt_priv = &(padapter->evtpriv); + + if (peventbuf == NULL) + goto _abort_event_; + evt_sz = (u16)(le32_to_cpu(*peventbuf) & 0xffff); + evt_seq = (u8)((le32_to_cpu(*peventbuf) >> 24) & 0x7f); + evt_code = (u8)((le32_to_cpu(*peventbuf) >> 16) & 0xff); + /* checking event sequence... */ + if ((evt_seq & 0x7f) != pevt_priv->event_seq) { + pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); + goto _abort_event_; + } + /* checking if event code is valid */ + if (evt_code >= MAX_C2HEVT) { + pevt_priv->event_seq = ((evt_seq+1) & 0x7f); + goto _abort_event_; + } else if ((evt_code == GEN_EVT_CODE(_Survey)) && + (evt_sz > sizeof(struct wlan_bssid_ex))) { + pevt_priv->event_seq = ((evt_seq+1)&0x7f); + goto _abort_event_; + } + /* checking if event size match the event parm size */ + if ((wlanevents[evt_code].parmsize) && + (wlanevents[evt_code].parmsize != evt_sz)) { + pevt_priv->event_seq = ((evt_seq+1)&0x7f); + goto _abort_event_; + } else if ((evt_sz == 0) && (evt_code != GEN_EVT_CODE(_WPS_PBC))) { + pevt_priv->event_seq = ((evt_seq+1)&0x7f); + goto _abort_event_; + } + pevt_priv->event_seq++; /* update evt_seq */ + if (pevt_priv->event_seq > 127) + pevt_priv->event_seq = 0; + /* move to event content, 8 bytes alignment */ + peventbuf = peventbuf + 2; + event_callback = wlanevents[evt_code].event_callback; + if (event_callback) + event_callback(padapter, (u8 *)peventbuf); + pevt_priv->evt_done_cnt++; +_abort_event_: + return; +} diff --git a/kernel/drivers/staging/rtl8712/rtl8712_cmd.h b/kernel/drivers/staging/rtl8712/rtl8712_cmd.h new file mode 100644 index 000000000..67e9e910a --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_cmd.h @@ -0,0 +1,244 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_CMD_H_ +#define __RTL8712_CMD_H_ + +#define CMD_HDR_SZ 8 + +u8 r8712_fw_cmd(struct _adapter *pAdapter, u32 cmd); +void r8712_fw_cmd_data(struct _adapter *pAdapter, u32 *value, u8 flag); + +struct cmd_hdr { + u32 cmd_dw0; + u32 cmd_dw1; +}; + +enum rtl8712_h2c_cmd { + GEN_CMD_CODE(_Read_MACREG), /*0*/ + GEN_CMD_CODE(_Write_MACREG), + GEN_CMD_CODE(_Read_BBREG), + GEN_CMD_CODE(_Write_BBREG), + GEN_CMD_CODE(_Read_RFREG), + GEN_CMD_CODE(_Write_RFREG), /*5*/ + GEN_CMD_CODE(_Read_EEPROM), + GEN_CMD_CODE(_Write_EEPROM), + GEN_CMD_CODE(_Read_EFUSE), + GEN_CMD_CODE(_Write_EFUSE), + + GEN_CMD_CODE(_Read_CAM), /*10*/ + GEN_CMD_CODE(_Write_CAM), + GEN_CMD_CODE(_setBCNITV), + GEN_CMD_CODE(_setMBIDCFG), + GEN_CMD_CODE(_JoinBss), /*14*/ + GEN_CMD_CODE(_DisConnect), /*15*/ + GEN_CMD_CODE(_CreateBss), + GEN_CMD_CODE(_SetOpMode), + GEN_CMD_CODE(_SiteSurvey), /*18*/ + GEN_CMD_CODE(_SetAuth), + + GEN_CMD_CODE(_SetKey), /*20*/ + GEN_CMD_CODE(_SetStaKey), + GEN_CMD_CODE(_SetAssocSta), + GEN_CMD_CODE(_DelAssocSta), + GEN_CMD_CODE(_SetStaPwrState), + GEN_CMD_CODE(_SetBasicRate), /*25*/ + GEN_CMD_CODE(_GetBasicRate), + GEN_CMD_CODE(_SetDataRate), + GEN_CMD_CODE(_GetDataRate), + GEN_CMD_CODE(_SetPhyInfo), + + GEN_CMD_CODE(_GetPhyInfo), /*30*/ + GEN_CMD_CODE(_SetPhy), + GEN_CMD_CODE(_GetPhy), + GEN_CMD_CODE(_readRssi), + GEN_CMD_CODE(_readGain), + GEN_CMD_CODE(_SetAtim), /*35*/ + GEN_CMD_CODE(_SetPwrMode), + GEN_CMD_CODE(_JoinbssRpt), + GEN_CMD_CODE(_SetRaTable), + GEN_CMD_CODE(_GetRaTable), + + GEN_CMD_CODE(_GetCCXReport), /*40*/ + GEN_CMD_CODE(_GetDTMReport), + GEN_CMD_CODE(_GetTXRateStatistics), + GEN_CMD_CODE(_SetUsbSuspend), + GEN_CMD_CODE(_SetH2cLbk), + GEN_CMD_CODE(_AddBAReq), /*45*/ + + GEN_CMD_CODE(_SetChannel), /*46*/ +/* MP_OFFLOAD Start (47~54)*/ + GEN_CMD_CODE(_SetTxPower), + GEN_CMD_CODE(_SwitchAntenna), + GEN_CMD_CODE(_SetCrystalCap), + GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/ + GEN_CMD_CODE(_SetSingleToneTx), + GEN_CMD_CODE(_SetCarrierSuppressionTx), + GEN_CMD_CODE(_SetContinuousTx), + GEN_CMD_CODE(_SwitchBandwidth), /*54*/ +/* MP_OFFLOAD End*/ + GEN_CMD_CODE(_TX_Beacon), /*55*/ + GEN_CMD_CODE(_SetPowerTracking), + GEN_CMD_CODE(_AMSDU_TO_AMPDU), /*57*/ + GEN_CMD_CODE(_SetMacAddress), /*58*/ + + GEN_CMD_CODE(_DisconnectCtrl), /*59*/ + GEN_CMD_CODE(_SetChannelPlan), /*60*/ + GEN_CMD_CODE(_DisconnectCtrlEx), /*61*/ + + /* To do, modify these h2c cmd, add or delete */ + GEN_CMD_CODE(_GetH2cLbk), + + /* WPS extra IE */ + GEN_CMD_CODE(_SetProbeReqExtraIE), + GEN_CMD_CODE(_SetAssocReqExtraIE), + GEN_CMD_CODE(_SetProbeRspExtraIE), + GEN_CMD_CODE(_SetAssocRspExtraIE), + + /* the following is driver will do */ + GEN_CMD_CODE(_GetCurDataRate), + + GEN_CMD_CODE(_GetTxRetrycnt), /* to record times that Tx retry to + * transmit packet after association + */ + GEN_CMD_CODE(_GetRxRetrycnt), /* to record total number of the + * received frame with ReTry bit set in + * the WLAN header + */ + + GEN_CMD_CODE(_GetBCNOKcnt), + GEN_CMD_CODE(_GetBCNERRcnt), + GEN_CMD_CODE(_GetCurTxPwrLevel), + + GEN_CMD_CODE(_SetDIG), + GEN_CMD_CODE(_SetRA), + GEN_CMD_CODE(_SetPT), + GEN_CMD_CODE(_ReadTSSI), + + MAX_H2CCMD +}; + + +#define _GetBBReg_CMD_ _Read_BBREG_CMD_ +#define _SetBBReg_CMD_ _Write_BBREG_CMD_ +#define _GetRFReg_CMD_ _Read_RFREG_CMD_ +#define _SetRFReg_CMD_ _Write_RFREG_CMD_ +#define _DRV_INT_CMD_ (MAX_H2CCMD+1) +#define _SetRFIntFs_CMD_ (MAX_H2CCMD+2) + +#ifdef _RTL8712_CMD_C_ +static struct _cmd_callback cmd_callback[] = { + {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ + {GEN_CMD_CODE(_Write_MACREG), NULL}, + {GEN_CMD_CODE(_Read_BBREG), &r8712_getbbrfreg_cmdrsp_callback}, + {GEN_CMD_CODE(_Write_BBREG), NULL}, + {GEN_CMD_CODE(_Read_RFREG), &r8712_getbbrfreg_cmdrsp_callback}, + {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ + {GEN_CMD_CODE(_Read_EEPROM), NULL}, + {GEN_CMD_CODE(_Write_EEPROM), NULL}, + {GEN_CMD_CODE(_Read_EFUSE), NULL}, + {GEN_CMD_CODE(_Write_EFUSE), NULL}, + + {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/ + {GEN_CMD_CODE(_Write_CAM), NULL}, + {GEN_CMD_CODE(_setBCNITV), NULL}, + {GEN_CMD_CODE(_setMBIDCFG), NULL}, + {GEN_CMD_CODE(_JoinBss), &r8712_joinbss_cmd_callback}, /*14*/ + {GEN_CMD_CODE(_DisConnect), &r8712_disassoc_cmd_callback}, /*15*/ + {GEN_CMD_CODE(_CreateBss), &r8712_createbss_cmd_callback}, + {GEN_CMD_CODE(_SetOpMode), NULL}, + {GEN_CMD_CODE(_SiteSurvey), &r8712_survey_cmd_callback}, /*18*/ + {GEN_CMD_CODE(_SetAuth), NULL}, + + {GEN_CMD_CODE(_SetKey), NULL}, /*20*/ + {GEN_CMD_CODE(_SetStaKey), &r8712_setstaKey_cmdrsp_callback}, + {GEN_CMD_CODE(_SetAssocSta), &r8712_setassocsta_cmdrsp_callback}, + {GEN_CMD_CODE(_DelAssocSta), NULL}, + {GEN_CMD_CODE(_SetStaPwrState), NULL}, + {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/ + {GEN_CMD_CODE(_GetBasicRate), NULL}, + {GEN_CMD_CODE(_SetDataRate), NULL}, + {GEN_CMD_CODE(_GetDataRate), NULL}, + {GEN_CMD_CODE(_SetPhyInfo), NULL}, + + {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/ + {GEN_CMD_CODE(_SetPhy), NULL}, + {GEN_CMD_CODE(_GetPhy), NULL}, + {GEN_CMD_CODE(_readRssi), NULL}, + {GEN_CMD_CODE(_readGain), NULL}, + {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/ + {GEN_CMD_CODE(_SetPwrMode), NULL}, + {GEN_CMD_CODE(_JoinbssRpt), NULL}, + {GEN_CMD_CODE(_SetRaTable), NULL}, + {GEN_CMD_CODE(_GetRaTable), NULL}, + + {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/ + {GEN_CMD_CODE(_GetDTMReport), NULL}, + {GEN_CMD_CODE(_GetTXRateStatistics), NULL}, + {GEN_CMD_CODE(_SetUsbSuspend), NULL}, + {GEN_CMD_CODE(_SetH2cLbk), NULL}, + {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/ + + {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/ +/* MP_OFFLOAD Start (47~54)*/ + {GEN_CMD_CODE(_SetTxPower), NULL}, + {GEN_CMD_CODE(_SwitchAntenna), NULL}, + {GEN_CMD_CODE(_SetCrystalCap), NULL}, + {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/ + {GEN_CMD_CODE(_SetSingleToneTx), NULL}, + {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL}, + {GEN_CMD_CODE(_SetContinuousTx), NULL}, + {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/ +/* MP_OFFLOAD End*/ + {GEN_CMD_CODE(_TX_Beacon), NULL}, /*55*/ + {GEN_CMD_CODE(_SetPowerTracking), NULL}, + {GEN_CMD_CODE(_AMSDU_TO_AMPDU), NULL}, /*57*/ + {GEN_CMD_CODE(_SetMacAddress), NULL}, /*58*/ + + {GEN_CMD_CODE(_DisconnectCtrl), NULL}, /*59*/ + {GEN_CMD_CODE(_SetChannelPlan), NULL}, /*60*/ + {GEN_CMD_CODE(_DisconnectCtrlEx), NULL}, /*61*/ + + /* To do, modify these h2c cmd, add or delete */ + {GEN_CMD_CODE(_GetH2cLbk), NULL}, + + {_SetProbeReqExtraIE_CMD_, NULL}, + {_SetAssocReqExtraIE_CMD_, NULL}, + {_SetProbeRspExtraIE_CMD_, NULL}, + {_SetAssocRspExtraIE_CMD_, NULL}, + {_GetCurDataRate_CMD_, NULL}, + {_GetTxRetrycnt_CMD_, NULL}, + {_GetRxRetrycnt_CMD_, NULL}, + {_GetBCNOKcnt_CMD_, NULL}, + {_GetBCNERRcnt_CMD_, NULL}, + {_GetCurTxPwrLevel_CMD_, NULL}, + {_SetDIG_CMD_, NULL}, + {_SetRA_CMD_, NULL}, + {_SetPT_CMD_, NULL}, + {GEN_CMD_CODE(_ReadTSSI), &r8712_readtssi_cmdrsp_callback} +}; +#endif + +#endif diff --git a/kernel/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h new file mode 100644 index 000000000..8dffe101b --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h @@ -0,0 +1,108 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_CMDCTRL_BITDEF_H__ +#define __RTL8712_CMDCTRL_BITDEF_H__ + +/* + * 2. Command Control Registers (Offset: 0x0040 - 0x004F)*/ +/*--------------------------------------------------------------------------*/ +/* 8192S (CMD) command register bits (Offset 0x40, 16 bits)*/ +/*--------------------------------------------------------------------------*/ +#define _APSDOFF_STATUS BIT(15) +#define _APSDOFF BIT(14) +#define _BBRSTn BIT(13) /*Enable OFDM/CCK*/ +#define _BB_GLB_RSTn BIT(12) /*Enable BB*/ +#define _SCHEDULE_EN BIT(10) /*Enable MAC scheduler*/ +#define _MACRXEN BIT(9) +#define _MACTXEN BIT(8) +#define _DDMA_EN BIT(7) /*FW off load function enable*/ +#define _FW2HW_EN BIT(6) /*MAC every module reset */ +#define _RXDMA_EN BIT(5) +#define _TXDMA_EN BIT(4) +#define _HCI_RXDMA_EN BIT(3) +#define _HCI_TXDMA_EN BIT(2) + +/*TXPAUSE*/ +#define _STOPHCCA BIT(6) +#define _STOPHIGH BIT(5) +#define _STOPMGT BIT(4) +#define _STOPVO BIT(3) +#define _STOPVI BIT(2) +#define _STOPBE BIT(1) +#define _STOPBK BIT(0) + +/*TCR*/ +#define _DISCW BIT(20) +#define _ICV BIT(19) +#define _CFEND_FMT BIT(17) +#define _CRC BIT(16) +#define _FWRDY BIT(7) +#define _BASECHG BIT(6) +#define _IMEM_RDY BIT(5) +#define _DMEM_CODE_DONE BIT(4) +#define _EMEM_CHK_RPT BIT(3) +#define _EMEM_CODE_DONE BIT(2) +#define _IMEM_CHK_RPT BIT(1) +#define _IMEM_CODE_DONE BIT(0) + +#define _TXDMA_INIT_VALUE (_IMEM_CHK_RPT|_EMEM_CHK_RPT) + +/*RCR*/ +#define _ENMBID BIT(27) +#define _APP_PHYST_RXFF BIT(25) +#define _APP_PHYST_STAFF BIT(24) +#define _CBSSID BIT(23) +#define _APWRMGT BIT(22) +#define _ADD3 BIT(21) +#define _AMF BIT(20) +#define _ACF BIT(19) +#define _ADF BIT(18) +#define _APP_MIC BIT(17) +#define _APP_ICV BIT(16) +#define _RXFTH_MSK 0x0000E000 +#define _RXFTH_SHT 13 +#define _AICV BIT(12) +#define _RXPKTLMT_MSK 0x00000FC0 +#define _RXPKTLMT_SHT 6 +#define _ACRC32 BIT(5) +#define _AB BIT(3) +#define _AM BIT(2) +#define _APM BIT(1) +#define _AAP BIT(0) + +/*MSR*/ +#define _NETTYPE_MSK 0x03 +#define _NETTYPE_SHT 0 + +/*BT*/ +#define _BTMODE_MSK 0x06 +#define _BTMODE_SHT 1 +#define _ENBT BIT(0) + +/*MBIDCTRL*/ +#define _ENMBID_MODE BIT(15) +#define _BCNNO_MSK 0x7000 +#define _BCNNO_SHT 12 +#define _BCNSPACE_MSK 0x0FFF +#define _BCNSPACE_SHT 0 + + +#endif /* __RTL8712_CMDCTRL_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h new file mode 100644 index 000000000..9374f1c48 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_CMDCTRL_REGDEF_H__ +#define __RTL8712_CMDCTRL_REGDEF_H__ + + +#define CR (RTL8712_CMDCTRL_ + 0x0000) +#define TXPAUSE (RTL8712_CMDCTRL_ + 0x0002) +#define TCR (RTL8712_CMDCTRL_ + 0x0004) +#define RCR (RTL8712_CMDCTRL_ + 0x0008) +#define MSR (RTL8712_CMDCTRL_ + 0x000C) +#define SYSF_CFG (RTL8712_CMDCTRL_ + 0x000D) +#define MBIDCTRL (RTL8712_CMDCTRL_ + 0x000E) + + +#endif /* __RTL8712_CMDCTRL_REGDEF_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h new file mode 100644 index 000000000..8bd483795 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_DEBUGCTRL_BITDEF_H__ +#define __RTL8712_DEBUGCTRL_BITDEF_H__ + +/*BIST*/ +#define _BIST_RST BIT(0) + +/*LMS*/ +#define _LMS_MSK 0x03 + +/*WDG_CTRL*/ +#define _OVSEL_MSK 0x0600 +#define _OVSEL_SHT 9 +#define _WDGCLR BIT(8) +#define _WDGEN_MSK 0x00FF +#define _WDGEN_SHT 0 + +/*INTM*/ +#define _TXTIMER_MSK 0xF000 +#define _TXTIMER_SHT 12 +#define _TXNUM_MSK 0x0F00 +#define _TXNUM_SHT 8 +#define _RXTIMER_MSK 0x00F0 +#define _RXTIMER_SHT 4 +#define _RXNUM_MSK 0x000F +#define _RXNUM_SHT 0 + +/*FDLOCKTURN0*/ +/*FDLOCKTURN1*/ +#define _TURN1 BIT(0) + +/*FDLOCKFLAG0*/ +/*FDLOCKFLAG1*/ +#define _LOCKFLAG1_MSK 0x03 + + +#endif /* __RTL8712_DEBUGCTRL_BITDEF_H__ */ diff --git a/kernel/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h new file mode 100644 index 000000000..43630bb06 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_DEBUGCTRL_REGDEF_H__ +#define __RTL8712_DEBUGCTRL_REGDEF_H__ + +#define BIST (RTL8712_DEBUGCTRL_ + 0x00) +#define DBS (RTL8712_DEBUGCTRL_ + 0x04) +#define LMS (RTL8712_DEBUGCTRL_ + 0x05) +#define CPUINST (RTL8712_DEBUGCTRL_ + 0x08) +#define CPUCAUSE (RTL8712_DEBUGCTRL_ + 0x0C) +#define LBUS_ERR_ADDR (RTL8712_DEBUGCTRL_ + 0x10) +#define LBUS_ERR_CMD (RTL8712_DEBUGCTRL_ + 0x14) +#define LBUS_ERR_DATA_L (RTL8712_DEBUGCTRL_ + 0x18) +#define LBUS_ERR_DATA_H (RTL8712_DEBUGCTRL_ + 0x1C) +#define LBUS_EXCEPTION_ADDR (RTL8712_DEBUGCTRL_ + 0x20) +#define WDG_CTRL (RTL8712_DEBUGCTRL_ + 0x24) +#define INTMTU (RTL8712_DEBUGCTRL_ + 0x28) +#define INTM (RTL8712_DEBUGCTRL_ + 0x2A) +#define FDLOCKTURN0 (RTL8712_DEBUGCTRL_ + 0x2C) +#define FDLOCKTURN1 (RTL8712_DEBUGCTRL_ + 0x2D) +#define FDLOCKFLAG0 (RTL8712_DEBUGCTRL_ + 0x2E) +#define FDLOCKFLAG1 (RTL8712_DEBUGCTRL_ + 0x2F) +#define TRXPKTBUF_DBG_DATA (RTL8712_DEBUGCTRL_ + 0x30) +#define TRXPKTBUF_DBG_CTRL (RTL8712_DEBUGCTRL_ + 0x38) +#define DPLL_MON (RTL8712_DEBUGCTRL_ + 0x3A) + + + +#endif /* __RTL8712_DEBUGCTRL_REGDEF_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h new file mode 100644 index 000000000..32dab81f1 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_EDCASETTING_BITDEF_H__ +#define __RTL8712_EDCASETTING_BITDEF_H__ + +/*EDCAPARAM*/ +#define _TXOPLIMIT_MSK 0xFFFF0000 +#define _TXOPLIMIT_SHT 16 +#define _ECWIN_MSK 0x0000FF00 +#define _ECWIN_SHT 8 +#define _AIFS_MSK 0x000000FF +#define _AIFS_SHT 0 + +/*BCNTCFG*/ +#define _BCNECW_MSK 0xFF00 +#define _BCNECW_SHT 8 +#define _BCNIFS_MSK 0x00FF +#define _BCNIFS_SHT 0 + +/*CWRR*/ +#define _CWRR_MSK 0x03FF + +/*ACMAVG*/ +#define _AVG_TIME_UP BIT(3) +#define _AVGPERIOD_MSK 0x03 + +/*ACMHWCTRL*/ +#define _VOQ_ACM_STATUS BIT(6) +#define _VIQ_ACM_STATUS BIT(5) +#define _BEQ_ACM_STATUS BIT(4) +#define _VOQ_ACM_EN BIT(3) +#define _VIQ_ACM_EN BIT(2) +#define _BEQ_ACM_EN BIT(1) +#define _ACMHWEN BIT(0) + +/*VO_ADMTIME*/ +#define _VO_ACM_RUT BIT(18) +#define _VO_ADMTIME_MSK 0x0003FFF + +/*VI_ADMTIME*/ +#define _VI_ACM_RUT BIT(18) +#define _VI_ADMTIME_MSK 0x0003FFF + +/*BE_ADMTIME*/ +#define _BE_ACM_RUT BIT(18) +#define _BE_ADMTIME_MSK 0x0003FFF + +/*Retry limit reg*/ +#define _SRL_MSK 0xFF00 +#define _SRL_SHT 8 +#define _LRL_MSK 0x00FF +#define _LRL_SHT 0 + +#endif /* __RTL8712_EDCASETTING_BITDEF_H__*/ diff --git a/kernel/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h new file mode 100644 index 000000000..d992cb8b1 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_EDCASETTING_REGDEF_H__ +#define __RTL8712_EDCASETTING_REGDEF_H__ + +#define EDCA_VO_PARAM (RTL8712_EDCASETTING_ + 0x00) +#define EDCA_VI_PARAM (RTL8712_EDCASETTING_ + 0x04) +#define EDCA_BE_PARAM (RTL8712_EDCASETTING_ + 0x08) +#define EDCA_BK_PARAM (RTL8712_EDCASETTING_ + 0x0C) +#define BCNTCFG (RTL8712_EDCASETTING_ + 0x10) +#define CWRR (RTL8712_EDCASETTING_ + 0x12) +#define ACMAVG (RTL8712_EDCASETTING_ + 0x16) +#define ACMHWCTRL (RTL8712_EDCASETTING_ + 0x17) +#define VO_ADMTIME (RTL8712_EDCASETTING_ + 0x18) +#define VI_ADMTIME (RTL8712_EDCASETTING_ + 0x1C) +#define BE_ADMTIME (RTL8712_EDCASETTING_ + 0x20) +#define RL (RTL8712_EDCASETTING_ + 0x24) + +#endif /* __RTL8712_EDCASETTING_REGDEF_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_efuse.c b/kernel/drivers/staging/rtl8712/rtl8712_efuse.c new file mode 100644 index 000000000..d95716999 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_efuse.c @@ -0,0 +1,574 @@ +/* + * rtl8712_efuse.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL8712_EFUSE_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "rtl8712_efuse.h" + +/* reserve 3 bytes for HW stop read */ +static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 /*0x1FD*/; + +static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn) +{ + u8 tmpu8 = 0; + + if (true == bPowerOn) { + /* -----------------e-fuse pwr & clk reg ctrl --------------- + * Enable LDOE25 Macro Block + */ + tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3); + tmpu8 |= 0x80; + r8712_write8(padapter, EFUSE_TEST + 3, tmpu8); + msleep(20); /* for some platform , need some delay time */ + /* Change Efuse Clock for write action to 40MHZ */ + r8712_write8(padapter, EFUSE_CLK_CTRL, 0x03); + msleep(20); /* for some platform , need some delay time */ + } else { + /* -----------------e-fuse pwr & clk reg ctrl ----------------- + * Disable LDOE25 Macro Block + */ + tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3); + tmpu8 &= 0x7F; + r8712_write8(padapter, EFUSE_TEST + 3, tmpu8); + /* Change Efuse Clock for write action to 500K */ + r8712_write8(padapter, EFUSE_CLK_CTRL, 0x02); + } +} + +/* + * Before write E-Fuse, this function must be called. + */ +u8 r8712_efuse_reg_init(struct _adapter *padapter) +{ + return true; +} + +void r8712_efuse_reg_uninit(struct _adapter *padapter) +{ + efuse_reg_ctrl(padapter, false); +} + +static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data) +{ + u8 tmpidx = 0, bResult; + + /* -----------------e-fuse reg ctrl --------------------------------- */ + r8712_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xFF)); /* address */ + r8712_write8(padapter, EFUSE_CTRL+2, ((u8)((addr>>8)&0x03)) | + (r8712_read8(padapter, EFUSE_CTRL+2)&0xFC)); + r8712_write8(padapter, EFUSE_CTRL+3, 0x72); /* read cmd */ + /* wait for complete */ + while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 100)) + tmpidx++; + if (tmpidx < 100) { + *data = r8712_read8(padapter, EFUSE_CTRL); + bResult = true; + } else { + *data = 0xff; + bResult = false; + } + return bResult; +} + +static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data) +{ + u8 tmpidx = 0, bResult; + + /* -----------------e-fuse reg ctrl -------------------------------- */ + r8712_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xFF)); /* address */ + r8712_write8(padapter, EFUSE_CTRL+2, ((u8)((addr>>8)&0x03)) | + (r8712_read8(padapter, EFUSE_CTRL+2)&0xFC)); + r8712_write8(padapter, EFUSE_CTRL, data); /* data */ + r8712_write8(padapter, EFUSE_CTRL+3, 0xF2); /* write cmd */ + /* wait for complete */ + while ((0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) && (tmpidx < 100)) + tmpidx++; + if (tmpidx < 100) + bResult = true; + else + bResult = false; + return bResult; +} + +static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr, + u8 *data) +{ + u8 tmpidx = 0, tmpv8 = 0, bResult; + + /* -----------------e-fuse reg ctrl --------------------------------- */ + r8712_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xFF)); /* address */ + tmpv8 = ((u8)((addr >> 8) & 0x03)) | + (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC); + r8712_write8(padapter, EFUSE_CTRL+2, tmpv8); + if (true == bRead) { + r8712_write8(padapter, EFUSE_CTRL+3, 0x72); /* read cmd */ + while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) && + (tmpidx < 100)) + tmpidx++; + if (tmpidx < 100) { + *data = r8712_read8(padapter, EFUSE_CTRL); + bResult = true; + } else { + *data = 0; + bResult = false; + } + } else { + r8712_write8(padapter, EFUSE_CTRL, *data); /* data */ + r8712_write8(padapter, EFUSE_CTRL+3, 0xF2); /* write cmd */ + while ((0x80 & r8712_read8(padapter, EFUSE_CTRL+3)) && + (tmpidx < 100)) + tmpidx++; + if (tmpidx < 100) + bResult = true; + else + bResult = false; + } + return bResult; +} + +static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty) +{ + u8 value, ret = true; + + /* read one byte to check if E-Fuse is empty */ + if (efuse_one_byte_rw(padapter, true, 0, &value) == true) { + if (0xFF == value) + *empty = true; + else + *empty = false; + } else + ret = false; + return ret; +} + +void r8712_efuse_change_max_size(struct _adapter *padapter) +{ + u16 pre_pg_data_saddr = 0x1FB; + u16 i; + u16 pre_pg_data_size = 5; + u8 pre_pg_data[5]; + + for (i = 0; i < pre_pg_data_size; i++) + efuse_one_byte_read(padapter, pre_pg_data_saddr + i, + &pre_pg_data[i]); + if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) && + (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) && + (pre_pg_data[4] == 0x0C)) + efuse_available_max_size -= pre_pg_data_size; +} + +int r8712_efuse_get_max_size(struct _adapter *padapter) +{ + return efuse_available_max_size; +} + +static u8 calculate_word_cnts(const u8 word_en) +{ + u8 word_cnts = 0; + u8 word_idx; + + for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) + if (!(word_en & BIT(word_idx))) + word_cnts++; /* 0 : write enable */ + return word_cnts; +} + +static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata, + u8 *targetdata) +{ + u8 tmpindex = 0; + u8 word_idx, byte_idx; + + for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) { + if (!(word_en&BIT(word_idx))) { + byte_idx = word_idx * 2; + targetdata[byte_idx] = sourdata[tmpindex++]; + targetdata[byte_idx + 1] = sourdata[tmpindex++]; + } + } +} + +u16 r8712_efuse_get_current_size(struct _adapter *padapter) +{ + int bContinual = true; + u16 efuse_addr = 0; + u8 hworden = 0; + u8 efuse_data, word_cnts = 0; + + while (bContinual && efuse_one_byte_read(padapter, efuse_addr, + &efuse_data) && (efuse_addr < efuse_available_max_size)) { + if (efuse_data != 0xFF) { + hworden = efuse_data & 0x0F; + word_cnts = calculate_word_cnts(hworden); + /* read next header */ + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + } else + bContinual = false; + } + return efuse_addr; +} + +u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data) +{ + u8 hoffset = 0, hworden = 0, word_cnts = 0; + u16 efuse_addr = 0; + u8 efuse_data; + u8 tmpidx = 0; + u8 tmpdata[PGPKT_DATA_SIZE]; + u8 ret = true; + + if (data == NULL) + return false; + if (offset > 0x0f) + return false; + memset(data, 0xFF, sizeof(u8)*PGPKT_DATA_SIZE); + while (efuse_addr < efuse_available_max_size) { + if (efuse_one_byte_read(padapter, efuse_addr, &efuse_data) == + true) { + if (efuse_data == 0xFF) + break; + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + word_cnts = calculate_word_cnts(hworden); + if (hoffset == offset) { + memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); + for (tmpidx = 0; tmpidx < word_cnts * 2; + tmpidx++) { + if (efuse_one_byte_read(padapter, + efuse_addr+1+tmpidx, &efuse_data) == + true) { + tmpdata[tmpidx] = efuse_data; + } else + ret = false; + } + pgpacket_copy_data(hworden, tmpdata, data); + } + efuse_addr += 1 + (word_cnts*2); + } else { + ret = false; + break; + } + } + return ret; +} + +static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr) +{ + struct PGPKT_STRUCT pkt; + u8 offset, word_en, value; + u16 addr; + int i; + u8 ret = true; + + pkt.offset = GET_EFUSE_OFFSET(header); + pkt.word_en = GET_EFUSE_WORD_EN(header); + addr = header_addr + 1 + calculate_word_cnts(pkt.word_en) * 2; + if (addr > efuse_available_max_size) + return false; + /* retrieve original data */ + addr = 0; + while (addr < header_addr) { + if (efuse_one_byte_read(padapter, addr++, &value) == false) { + ret = false; + break; + } + offset = GET_EFUSE_OFFSET(value); + word_en = GET_EFUSE_WORD_EN(value); + if (pkt.offset != offset) { + addr += calculate_word_cnts(word_en)*2; + continue; + } + for (i = 0; i < PGPKG_MAX_WORDS; i++) { + if (BIT(i) & word_en) { + if (BIT(i) & pkt.word_en) { + if (efuse_one_byte_read( + padapter, addr, + &value) == true) + pkt.data[i*2] = value; + else + return false; + if (efuse_one_byte_read( + padapter, + addr + 1, + &value) == true) + pkt.data[i*2 + 1] = + value; + else + return false; + } + addr += 2; + } + } + } + if (addr != header_addr) + return false; + addr++; + /* fill original data */ + for (i = 0; i < PGPKG_MAX_WORDS; i++) { + if (BIT(i) & pkt.word_en) { + efuse_one_byte_write(padapter, addr, pkt.data[i*2]); + efuse_one_byte_write(padapter, addr+1, + pkt.data[i*2 + 1]); + /* additional check */ + if (efuse_one_byte_read(padapter, addr, &value) + == false) + ret = false; + else if (pkt.data[i*2] != value) { + ret = false; + if (0xFF == value) /* write again */ + efuse_one_byte_write(padapter, addr, + pkt.data[i * 2]); + } + if (efuse_one_byte_read(padapter, addr+1, &value) == + false) + ret = false; + else if (pkt.data[i*2 + 1] != value) { + ret = false; + if (0xFF == value) /* write again */ + efuse_one_byte_write(padapter, addr+1, + pkt.data[i*2 + 1]); + } + } + addr += 2; + } + return ret; +} + +u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset, + const u8 word_en, const u8 *data) +{ + u8 pg_header = 0; + u16 efuse_addr = 0, curr_size = 0; + u8 efuse_data, target_word_cnts = 0; + static int repeat_times; + int sub_repeat; + u8 bResult = true; + + /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */ + efuse_data = r8712_read8(padapter, EFUSE_CLK_CTRL); + if (efuse_data != 0x03) + return false; + pg_header = MAKE_EFUSE_HEADER(offset, word_en); + target_word_cnts = calculate_word_cnts(word_en); + repeat_times = 0; + efuse_addr = 0; + while (efuse_addr < efuse_available_max_size) { + curr_size = r8712_efuse_get_current_size(padapter); + if ((curr_size + 1 + target_word_cnts * 2) > + efuse_available_max_size) + return false; /*target_word_cnts + pg header(1 byte)*/ + efuse_addr = curr_size; /* current size is also the last addr*/ + efuse_one_byte_write(padapter, efuse_addr, pg_header); /*hdr*/ + sub_repeat = 0; + /* check if what we read is what we write */ + while (efuse_one_byte_read(padapter, efuse_addr, + &efuse_data) == false) { + if (++sub_repeat > _REPEAT_THRESHOLD_) { + bResult = false; /* continue to blind write */ + break; /* continue to blind write */ + } + } + if ((sub_repeat > _REPEAT_THRESHOLD_) || + (pg_header == efuse_data)) { + /* write header ok OR can't check header(creep) */ + u8 i; + + /* go to next address */ + efuse_addr++; + for (i = 0; i < target_word_cnts*2; i++) { + efuse_one_byte_write(padapter, + efuse_addr + i, + *(data + i)); + if (efuse_one_byte_read(padapter, + efuse_addr + i, &efuse_data) == false) + bResult = false; + else if (*(data+i) != efuse_data) /* fail */ + bResult = false; + } + break; + } + /* write header fail */ + bResult = false; + if (0xFF == efuse_data) + return bResult; /* nothing damaged. */ + /* call rescue procedure */ + if (!fix_header(padapter, efuse_data, efuse_addr)) + return false; /* rescue fail */ + + if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */ + break; + /* otherwise, take another risk... */ + } + return bResult; +} + +u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr, + u16 cnts, u8 *data) +{ + int i; + u8 res = true; + + if (start_addr > EFUSE_MAX_SIZE) + return false; + if ((bRead == false) && ((start_addr + cnts) > + efuse_available_max_size)) + return false; + if ((false == bRead) && (r8712_efuse_reg_init(padapter) == false)) + return false; + /* -----------------e-fuse one byte read / write ---------------------*/ + for (i = 0; i < cnts; i++) { + if ((start_addr + i) > EFUSE_MAX_SIZE) { + res = false; + break; + } + res = efuse_one_byte_rw(padapter, bRead, start_addr + i, + data + i); + if ((false == bRead) && (false == res)) + break; + } + if (false == bRead) + r8712_efuse_reg_uninit(padapter); + return res; +} + +u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data) +{ + u8 offset, ret = true; + u8 pktdata[PGPKT_DATA_SIZE]; + int i, idx; + + if ((addr + cnts) > EFUSE_MAP_MAX_SIZE) + return false; + if ((efuse_is_empty(padapter, &offset) == true) && (offset == + true)) { + for (i = 0; i < cnts; i++) + data[i] = 0xFF; + return ret; + } + offset = (addr >> 3) & 0xF; + ret = r8712_efuse_pg_packet_read(padapter, offset, pktdata); + i = addr & 0x7; /* pktdata index */ + idx = 0; /* data index */ + + do { + for (; i < PGPKT_DATA_SIZE; i++) { + data[idx++] = pktdata[i]; + if (idx == cnts) + return ret; + } + offset++; + if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata)) + ret = false; + i = 0; + } while (1); + return ret; +} + +u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts, + u8 *data) +{ + u8 offset, word_en, empty; + u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE]; + int i, j, idx; + + if ((addr + cnts) > EFUSE_MAP_MAX_SIZE) + return false; + /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */ + empty = r8712_read8(padapter, EFUSE_CLK_CTRL); + if (empty != 0x03) + return false; + if (efuse_is_empty(padapter, &empty) == true) { + if (true == empty) + memset(pktdata, 0xFF, PGPKT_DATA_SIZE); + } else + return false; + offset = (addr >> 3) & 0xF; + if (empty == false) + if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata)) + return false; + word_en = 0xF; + memset(newdata, 0xFF, PGPKT_DATA_SIZE); + i = addr & 0x7; /* pktdata index */ + j = 0; /* newdata index */ + idx = 0; /* data index */ + + if (i & 0x1) { + /* odd start */ + if (data[idx] != pktdata[i]) { + word_en &= ~BIT(i >> 1); + newdata[j++] = pktdata[i - 1]; + newdata[j++] = data[idx]; + } + i++; + idx++; + } + do { + for (; i < PGPKT_DATA_SIZE; i += 2) { + if ((cnts - idx) == 1) { + if (data[idx] != pktdata[i]) { + word_en &= ~BIT(i >> 1); + newdata[j++] = data[idx]; + newdata[j++] = pktdata[1 + 1]; + } + idx++; + break; + } + + if ((data[idx] != pktdata[i]) || (data[idx+1] != + pktdata[i+1])) { + word_en &= ~BIT(i >> 1); + newdata[j++] = data[idx]; + newdata[j++] = data[idx + 1]; + } + idx += 2; + + if (idx == cnts) + break; + } + + if (word_en != 0xF) + if (r8712_efuse_pg_packet_write(padapter, offset, + word_en, newdata) == false) + return false; + if (idx == cnts) + break; + offset++; + if (empty == false) + if (!r8712_efuse_pg_packet_read(padapter, offset, + pktdata)) + return false; + i = 0; + j = 0; + word_en = 0xF; + memset(newdata, 0xFF, PGPKT_DATA_SIZE); + } while (1); + + return true; +} diff --git a/kernel/drivers/staging/rtl8712/rtl8712_efuse.h b/kernel/drivers/staging/rtl8712/rtl8712_efuse.h new file mode 100644 index 000000000..6a64f91ad --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_efuse.h @@ -0,0 +1,43 @@ +#ifndef __RTL8712_EFUSE_H__ +#define __RTL8712_EFUSE_H__ + +#include "osdep_service.h" + + +#define _REPEAT_THRESHOLD_ 3 + +#define EFUSE_MAX_SIZE 512 +#define EFUSE_MAP_MAX_SIZE 128 + +#define PGPKG_MAX_WORDS 4 +#define PGPKT_DATA_SIZE 8 /* PGPKG_MAX_WORDS*2; BYTES sizeof(u8)*8*/ +#define MAX_PGPKT_SIZE 9 /* 1 + PGPKT_DATA_SIZE; header + 2 * 4 words (BYTES)*/ + +#define GET_EFUSE_OFFSET(header) ((header & 0xF0) >> 4) +#define GET_EFUSE_WORD_EN(header) (header & 0x0F) +#define MAKE_EFUSE_HEADER(offset, word_en) (((offset & 0x0F) << 4) | \ + (word_en & 0x0F)) +/*--------------------------------------------------------------------------*/ +struct PGPKT_STRUCT { + u8 offset; + u8 word_en; + u8 data[PGPKT_DATA_SIZE]; +}; +/*--------------------------------------------------------------------------*/ +u8 r8712_efuse_reg_init(struct _adapter *padapter); +void r8712_efuse_reg_uninit(struct _adapter *padapter); +u16 r8712_efuse_get_current_size(struct _adapter *padapter); +int r8712_efuse_get_max_size(struct _adapter *padapter); +void r8712_efuse_change_max_size(struct _adapter *padapter); +u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, + u8 offset, u8 *data); +u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, + const u8 offset, const u8 word_en, + const u8 *data); +u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, + u16 start_addr, u16 cnts, u8 *data); +u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, + u16 cnts, u8 *data); +u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, + u16 cnts, u8 *data); +#endif diff --git a/kernel/drivers/staging/rtl8712/rtl8712_event.h b/kernel/drivers/staging/rtl8712/rtl8712_event.h new file mode 100644 index 000000000..29a4c23a0 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_event.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL8712_EVENT_H_ +#define _RTL8712_EVENT_H_ + +void r8712_event_handle(struct _adapter *padapter, uint *peventbuf); +void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf); + +enum rtl8712_c2h_event { + GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/ + GEN_EVT_CODE(_Read_BBREG), + GEN_EVT_CODE(_Read_RFREG), + GEN_EVT_CODE(_Read_EEPROM), + GEN_EVT_CODE(_Read_EFUSE), + GEN_EVT_CODE(_Read_CAM), /*5*/ + GEN_EVT_CODE(_Get_BasicRate), + GEN_EVT_CODE(_Get_DataRate), + GEN_EVT_CODE(_Survey), /*8*/ + GEN_EVT_CODE(_SurveyDone), /*9*/ + + GEN_EVT_CODE(_JoinBss), /*10*/ + GEN_EVT_CODE(_AddSTA), + GEN_EVT_CODE(_DelSTA), + GEN_EVT_CODE(_AtimDone), + GEN_EVT_CODE(_TX_Report), + GEN_EVT_CODE(_CCX_Report), /*15*/ + GEN_EVT_CODE(_DTM_Report), + GEN_EVT_CODE(_TX_Rate_Statistics), + GEN_EVT_CODE(_C2HLBK), + GEN_EVT_CODE(_FWDBG), + GEN_EVT_CODE(_C2HFEEDBACK), /*20*/ + GEN_EVT_CODE(_ADDBA), + GEN_EVT_CODE(_C2HBCN), + GEN_EVT_CODE(_ReportPwrState), /*filen: only for PCIE, USB*/ + GEN_EVT_CODE(_WPS_PBC), /*24*/ + GEN_EVT_CODE(_ADDBAReq_Report), /*25*/ + MAX_C2HEVT +}; + + +#ifdef _RTL8712_CMD_C_ + +static struct fwevent wlanevents[] = { + {0, NULL}, /*0*/ + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, &r8712_survey_event_callback}, /*8*/ + {sizeof(struct surveydone_event), + &r8712_surveydone_event_callback}, /*9*/ + + {0, &r8712_joinbss_event_callback}, /*10*/ + {sizeof(struct stassoc_event), &r8712_stassoc_event_callback}, + {sizeof(struct stadel_event), &r8712_stadel_event_callback}, + {0, &r8712_atimdone_event_callback}, + {0, NULL}, + {0, NULL}, /*15*/ + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, /*fwdbg_event_callback},*/ + {0, NULL}, /*20*/ + {0, NULL}, + {0, NULL}, + {0, &r8712_cpwm_event_callback}, + {0, &r8712_wpspbc_event_callback}, + {0, &r8712_got_addbareq_event_callback}, +}; + +#endif/*_RTL8712_CMD_C_*/ + +#endif diff --git a/kernel/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h new file mode 100644 index 000000000..c564dc862 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h @@ -0,0 +1,145 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_FIFOCTRL_BITDEF_H__ +#define __RTL8712_FIFOCTRL_BITDEF_H__ + +/*PBP*/ +#define _PSTX_MSK 0xF0 +#define _PSTX_SHT 4 +#define _PSRX_MSK 0x0F +#define _PSRX_SHT 0 + +/*TXFF_STATUS*/ +#define _TXSTATUS_OVF BIT(15) + +/*RXFF_STATUS*/ +#define _STATUSFF1_OVF BIT(7) +#define _STATUSFF1_EMPTY BIT(6) +#define _STATUSFF0_OVF BIT(5) +#define _STATUSFF0_EMPTY BIT(4) +#define _RXFF1_OVF BIT(3) +#define _RXFF1_EMPTY BIT(2) +#define _RXFF0_OVF BIT(1) +#define _RXFF0_EMPTY BIT(0) + +/*TXFF_EMPTY_TH*/ +#define _BKQ_EMPTY_TH_MSK 0x0F0000 +#define _BKQ_EMPTY_TH_SHT 16 +#define _BEQ_EMPTY_TH_MSK 0x00F000 +#define _BEQ_EMPTY_TH_SHT 12 +#define _VIQ_EMPTY_TH_MSK 0x000F00 +#define _VIQ_EMPTY_TH_SHT 8 +#define _VOQ_EMPTY_TH_MSK 0x0000F0 +#define _VOQ_EMPTY_TH_SHT 4 +#define _BMCQ_EMPTY_TH_MSK 0x00000F +#define _BMCQ_EMPTY_TH_SHT 0 + +/*SDIO_RX_BLKSZ*/ +#define _SDIO_RX_BLKSZ_MSK 0x07 + +/*RXDMA_CTRL*/ +#define _C2HFF_POLL BIT(4) +#define _RXPKT_POLL BIT(0) + +/*RXPKT_NUM*/ +#define _RXCMD_NUM_MSK 0xFF00 +#define _RXCMD_NUM_SHT 8 +#define _RXFF0_NUM_MSK 0x00FF +#define _RXFF0_NUM_SHT 0 + +/*FIFOPAGE2*/ +#define _PUB_AVAL_PG_MSK 0xFFFF0000 +#define _PUB_AVAL_PG_SHT 16 +#define _BCN_AVAL_PG_MSK 0x0000FFFF +#define _BCN_AVAL_PG_SHT 0 + +/*RX0PKTNUM*/ +#define _RXFF0_DEC_POLL BIT(15) +#define _RXFF0_PKT_DEC_NUM_MSK 0x3F00 +#define _RXFF0_PKT_DEC_NUM_SHT 8 +#define _RXFF0_PKTNUM_RPT_MSK 0x00FF +#define _RXFF0_PKTNUM_RPT_SHT 0 + +/*RX1PKTNUM*/ +#define _RXFF1_DEC_POLL BIT(15) +#define _RXFF1_PKT_DEC_NUM_MSK 0x3F00 +#define _RXFF1_PKT_DEC_NUM_SHT 8 +#define _RXFF1_PKTNUM_RPT_MSK 0x00FF +#define _RXFF1_PKTNUM_RPT_SHT 0 + +/*RXFLTMAP0*/ +#define _MGTFLT13EN BIT(13) +#define _MGTFLT12EN BIT(12) +#define _MGTFLT11EN BIT(11) +#define _MGTFLT10EN BIT(10) +#define _MGTFLT9EN BIT(9) +#define _MGTFLT8EN BIT(8) +#define _MGTFLT5EN BIT(5) +#define _MGTFLT4EN BIT(4) +#define _MGTFLT3EN BIT(3) +#define _MGTFLT2EN BIT(2) +#define _MGTFLT1EN BIT(1) +#define _MGTFLT0EN BIT(0) + +/*RXFLTMAP1*/ +#define _CTRLFLT15EN BIT(15) +#define _CTRLFLT14EN BIT(14) +#define _CTRLFLT13EN BIT(13) +#define _CTRLFLT12EN BIT(12) +#define _CTRLFLT11EN BIT(11) +#define _CTRLFLT10EN BIT(10) +#define _CTRLFLT9EN BIT(9) +#define _CTRLFLT8EN BIT(8) +#define _CTRLFLT7EN BIT(7) +#define _CTRLFLT6EN BIT(6) + +/*RXFLTMAP2*/ +#define _DATAFLT15EN BIT(15) +#define _DATAFLT14EN BIT(14) +#define _DATAFLT13EN BIT(13) +#define _DATAFLT12EN BIT(12) +#define _DATAFLT11EN BIT(11) +#define _DATAFLT10EN BIT(10) +#define _DATAFLT9EN BIT(9) +#define _DATAFLT8EN BIT(8) +#define _DATAFLT7EN BIT(7) +#define _DATAFLT6EN BIT(6) +#define _DATAFLT5EN BIT(5) +#define _DATAFLT4EN BIT(4) +#define _DATAFLT3EN BIT(3) +#define _DATAFLT2EN BIT(2) +#define _DATAFLT1EN BIT(1) +#define _DATAFLT0EN BIT(0) + +/*RXFLTMAP3*/ +#define _MESHAFLT1EN BIT(1) +#define _MESHAFLT0EN BIT(0) + +/*TXPKT_NUM_CTRL*/ +#define _TXPKTNUM_DEC BIT(8) +#define _TXPKTNUM_MSK 0x00FF +#define _TXPKTNUM_SHT 0 + +/*TXFF_PG_NUM*/ +#define _TXFF_PG_NUM_MSK 0x0FFF + + +#endif /* __RTL8712_FIFOCTRL_BITDEF_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h new file mode 100644 index 000000000..29b89c45c --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_FIFOCTRL_REGDEF_H__ +#define __RTL8712_FIFOCTRL_REGDEF_H__ + +#define RQPN (RTL8712_FIFOCTRL_ + 0x00) +#define RXFF_BNDY (RTL8712_FIFOCTRL_ + 0x0C) +#define RXRPT_BNDY (RTL8712_FIFOCTRL_ + 0x10) +#define TXPKTBUF_PGBNDY (RTL8712_FIFOCTRL_ + 0x14) +#define PBP (RTL8712_FIFOCTRL_ + 0x15) +#define RX_DRVINFO_SZ (RTL8712_FIFOCTRL_ + 0x16) +#define TXFF_STATUS (RTL8712_FIFOCTRL_ + 0x17) +#define RXFF_STATUS (RTL8712_FIFOCTRL_ + 0x18) +#define TXFF_EMPTY_TH (RTL8712_FIFOCTRL_ + 0x19) +#define SDIO_RX_BLKSZ (RTL8712_FIFOCTRL_ + 0x1C) +#define RXDMA_RXCTRL (RTL8712_FIFOCTRL_ + 0x1D) +#define RXPKT_NUM (RTL8712_FIFOCTRL_ + 0x1E) +#define RXPKT_NUM_C2H (RTL8712_FIFOCTRL_ + 0x1F) +#define C2HCMD_UDT_SIZE (RTL8712_FIFOCTRL_ + 0x20) +#define C2HCMD_UDT_ADDR (RTL8712_FIFOCTRL_ + 0x22) +#define FIFOPAGE2 (RTL8712_FIFOCTRL_ + 0x24) +#define FIFOPAGE1 (RTL8712_FIFOCTRL_ + 0x28) +#define FW_RSVD_PG_CTRL (RTL8712_FIFOCTRL_ + 0x30) +#define TXRPTFF_RDPTR (RTL8712_FIFOCTRL_ + 0x40) +#define TXRPTFF_WTPTR (RTL8712_FIFOCTRL_ + 0x44) +#define C2HFF_RDPTR (RTL8712_FIFOCTRL_ + 0x48) +#define C2HFF_WTPTR (RTL8712_FIFOCTRL_ + 0x4C) +#define RXFF0_RDPTR (RTL8712_FIFOCTRL_ + 0x50) +#define RXFF0_WTPTR (RTL8712_FIFOCTRL_ + 0x54) +#define RXFF1_RDPTR (RTL8712_FIFOCTRL_ + 0x58) +#define RXFF1_WTPTR (RTL8712_FIFOCTRL_ + 0x5C) +#define RXRPT0FF_RDPTR (RTL8712_FIFOCTRL_ + 0x60) +#define RXRPT0FF_WTPTR (RTL8712_FIFOCTRL_ + 0x64) +#define RXRPT1FF_RDPTR (RTL8712_FIFOCTRL_ + 0x68) +#define RXRPT1FF_WTPTR (RTL8712_FIFOCTRL_ + 0x6C) +#define RX0PKTNUM (RTL8712_FIFOCTRL_ + 0x72) +#define RX1PKTNUM (RTL8712_FIFOCTRL_ + 0x74) +#define RXFLTMAP0 (RTL8712_FIFOCTRL_ + 0x76) +#define RXFLTMAP1 (RTL8712_FIFOCTRL_ + 0x78) +#define RXFLTMAP2 (RTL8712_FIFOCTRL_ + 0x7A) +#define RXFLTMAP3 (RTL8712_FIFOCTRL_ + 0x7c) +#define TBDA (RTL8712_FIFOCTRL_ + 0x84) +#define THPDA (RTL8712_FIFOCTRL_ + 0x88) +#define TCDA (RTL8712_FIFOCTRL_ + 0x8C) +#define TMDA (RTL8712_FIFOCTRL_ + 0x90) +#define HDA (RTL8712_FIFOCTRL_ + 0x94) +#define TVODA (RTL8712_FIFOCTRL_ + 0x98) +#define TVIDA (RTL8712_FIFOCTRL_ + 0x9C) +#define TBEDA (RTL8712_FIFOCTRL_ + 0xA0) +#define TBKDA (RTL8712_FIFOCTRL_ + 0xA4) +#define RCDA (RTL8712_FIFOCTRL_ + 0xA8) +#define RDSA (RTL8712_FIFOCTRL_ + 0xAC) +#define TXPKT_NUM_CTRL (RTL8712_FIFOCTRL_ + 0xB0) +#define TXQ_PGADD (RTL8712_FIFOCTRL_ + 0xB3) +#define TXFF_PG_NUM (RTL8712_FIFOCTRL_ + 0xB4) + + + +#endif /* __RTL8712_FIFOCTRL_REGDEF_H__ */ diff --git a/kernel/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_gp_bitdef.h new file mode 100644 index 000000000..138ea453d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_gp_bitdef.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_GP_BITDEF_H__ +#define __RTL8712_GP_BITDEF_H__ + +/*GPIO_CTRL*/ +#define _GPIO_MOD_MSK 0xFF000000 +#define _GPIO_MOD_SHT 24 +#define _GPIO_IO_SEL_MSK 0x00FF0000 +#define _GPIO_IO_SEL_SHT 16 +#define _GPIO_OUT_MSK 0x0000FF00 +#define _GPIO_OUT_SHT 8 +#define _GPIO_IN_MSK 0x000000FF +#define _GPIO_IN_SHT 0 + +/*SYS_PINMUX_CFG*/ +#define _GPIOSEL_MSK 0x0003 +#define _GPIOSEL_SHT 0 + +/*LED_CFG*/ +#define _LED1SV BIT(7) +#define _LED1CM_MSK 0x0070 +#define _LED1CM_SHT 4 +#define _LED0SV BIT(3) +#define _LED0CM_MSK 0x0007 +#define _LED0CM_SHT 0 + +/*PHY_REG*/ +#define _HST_RDRDY_SHT 0 +#define _HST_RDRDY_MSK 0xFF +#define _HST_RDRDY BIT(_HST_RDRDY_SHT) +#define _CPU_WTBUSY_SHT 1 +#define _CPU_WTBUSY_MSK 0xFF +#define _CPU_WTBUSY BIT(_CPU_WTBUSY_SHT) + +/* 11. General Purpose Registers (Offset: 0x02E0 - 0x02FF)*/ + +/* 8192S GPIO Config Setting (offset 0x2F1, 1 byte)*/ + +/*----------------------------------------------------------------------------*/ + +#define GPIOMUX_EN BIT(3) /* When this bit is set to "1", + * GPIO PINs will switch to MAC + * GPIO Function*/ +#define GPIOSEL_GPIO 0 /* UART or JTAG or pure GPIO*/ +#define GPIOSEL_PHYDBG 1 /* PHYDBG*/ +#define GPIOSEL_BT 2 /* BT_coex*/ +#define GPIOSEL_WLANDBG 3 /* WLANDBG*/ +#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1))) +/* HW Radio OFF switch (GPIO BIT) */ +#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3) +#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 +#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4) + +#endif /*__RTL8712_GP_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_gp_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_gp_regdef.h new file mode 100644 index 000000000..8fc68f6a2 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_gp_regdef.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_GP_REGDEF_H__ +#define __RTL8712_GP_REGDEF_H__ + +#define PSTIMER (RTL8712_GP_ + 0x00) +#define TIMER1 (RTL8712_GP_ + 0x04) +#define TIMER2 (RTL8712_GP_ + 0x08) +#define GPIO_CTRL (RTL8712_GP_ + 0x0C) +#define GPIO_IO_SEL (RTL8712_GP_ + 0x0E) +#define GPIO_INTCTRL (RTL8712_GP_ + 0x10) +#define MAC_PINMUX_CTRL (RTL8712_GP_ + 0x11) +#define LEDCFG (RTL8712_GP_ + 0x12) +#define PHY_REG_RPT (RTL8712_GP_ + 0x13) +#define PHY_REG_DATA (RTL8712_GP_ + 0x14) + + +#endif /*__RTL8712_GP_REGDEF_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_hal.h b/kernel/drivers/staging/rtl8712/rtl8712_hal.h new file mode 100644 index 000000000..4c51fa373 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_hal.h @@ -0,0 +1,150 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_HAL_H__ +#define __RTL8712_HAL_H__ + +enum _HW_VERSION { + RTL8712_FPGA, + RTL8712_1stCUT, /*A Cut (RTL8712_ASIC)*/ + RTL8712_2ndCUT, /*B Cut*/ + RTL8712_3rdCUT, /*C Cut*/ +}; + +enum _LOOPBACK_TYPE { + RTL8712_AIR_TRX = 0, + RTL8712_MAC_LBK, + RTL8712_BB_LBK, + RTL8712_MAC_FW_LBK = 4, + RTL8712_BB_FW_LBK = 8, +}; + +enum RTL871X_HCI_TYPE { + RTL8712_SDIO, + RTL8712_USB, +}; + +enum RTL8712_RF_CONFIG { + RTL8712_RF_1T1R, + RTL8712_RF_1T2R, + RTL8712_RF_2T2R +}; + +enum _RTL8712_HCI_TYPE_ { + RTL8712_HCI_TYPE_PCIE = 0x01, + RTL8712_HCI_TYPE_AP_PCIE = 0x81, + RTL8712_HCI_TYPE_USB = 0x02, + RTL8712_HCI_TYPE_92USB = 0x02, + RTL8712_HCI_TYPE_AP_USB = 0x82, + RTL8712_HCI_TYPE_72USB = 0x12, + RTL8712_HCI_TYPE_SDIO = 0x04, + RTL8712_HCI_TYPE_72SDIO = 0x14 +}; + +struct fw_priv { /*8-bytes alignment required*/ + /*--- long word 0 ----*/ + unsigned char signature_0; /*0x12: CE product, 0x92: IT product*/ + unsigned char signature_1; /*0x87: CE product, 0x81: IT product*/ + unsigned char hci_sel; /*0x81: PCI-AP, 01:PCIe, 02: 92S-U, 0x82: USB-AP, + * 0x12: 72S-U, 03:SDIO*/ + unsigned char chip_version; /*the same value as register value*/ + unsigned char customer_ID_0; /*customer ID low byte*/ + unsigned char customer_ID_1; /*customer ID high byte*/ + unsigned char rf_config; /*0x11: 1T1R, 0x12: 1T2R, 0x92: 1T2R turbo, + * 0x22: 2T2R*/ + unsigned char usb_ep_num; /* 4: 4EP, 6: 6EP, 11: 11EP*/ + /*--- long word 1 ----*/ + unsigned char regulatory_class_0; /*regulatory class bit map 0*/ + unsigned char regulatory_class_1; /*regulatory class bit map 1*/ + unsigned char regulatory_class_2; /*regulatory class bit map 2*/ + unsigned char regulatory_class_3; /*regulatory class bit map 3*/ + unsigned char rfintfs; /* 0:SWSI, 1:HWSI, 2:HWPI*/ + unsigned char def_nettype; + unsigned char turboMode; + unsigned char lowPowerMode;/* 0: normal mode, 1: low power mode*/ + /*--- long word 2 ----*/ + unsigned char lbk_mode; /*0x00: normal, 0x03: MACLBK, 0x01: PHYLBK*/ + unsigned char mp_mode; /* 1: for MP use, 0: for normal driver */ + unsigned char vcsType; /* 0:off 1:on 2:auto */ + unsigned char vcsMode; /* 1:RTS/CTS 2:CTS to self */ + unsigned char rsvd022; + unsigned char rsvd023; + unsigned char rsvd024; + unsigned char rsvd025; + /*--- long word 3 ----*/ + unsigned char qos_en; /*1: QoS enable*/ + unsigned char bw_40MHz_en; /*1: 40MHz BW enable*/ + unsigned char AMSDU2AMPDU_en; /*1: 4181 convert AMSDU to AMPDU, + * 0: disable*/ + unsigned char AMPDU_en; /*1: 11n AMPDU enable*/ + unsigned char rate_control_offload; /*1: FW offloads,0: driver handles*/ + unsigned char aggregation_offload; /*1: FW offloads,0: driver handles*/ + unsigned char rsvd030; + unsigned char rsvd031; + /*--- long word 4 ----*/ + unsigned char beacon_offload; /* 1. FW offloads, 0: driver handles*/ + unsigned char MLME_offload; /* 2. FW offloads, 0: driver handles*/ + unsigned char hwpc_offload; /* 3. FW offloads, 0: driver handles*/ + unsigned char tcp_checksum_offload; /*4. FW offloads,0: driver handles*/ + unsigned char tcp_offload; /* 5. FW offloads, 0: driver handles*/ + unsigned char ps_control_offload; /* 6. FW offloads, 0: driver handles*/ + unsigned char WWLAN_offload; /* 7. FW offloads, 0: driver handles*/ + unsigned char rsvd040; + /*--- long word 5 ----*/ + unsigned char tcp_tx_frame_len_L; /*tcp tx packet length low byte*/ + unsigned char tcp_tx_frame_len_H; /*tcp tx packet length high byte*/ + unsigned char tcp_rx_frame_len_L; /*tcp rx packet length low byte*/ + unsigned char tcp_rx_frame_len_H; /*tcp rx packet length high byte*/ + unsigned char rsvd050; + unsigned char rsvd051; + unsigned char rsvd052; + unsigned char rsvd053; +}; + +struct fw_hdr {/*8-byte alignment required*/ + unsigned short signature; + unsigned short version; /*0x8000 ~ 0x8FFF for FPGA version, + *0x0000 ~ 0x7FFF for ASIC version,*/ + unsigned int dmem_size; /*define the size of boot loader*/ + unsigned int img_IMEM_size; /*define the size of FW in IMEM*/ + unsigned int img_SRAM_size; /*define the size of FW in SRAM*/ + unsigned int fw_priv_sz; /*define the size of DMEM variable*/ + unsigned short efuse_addr; + unsigned short h2ccnd_resp_addr; + unsigned int SVNRevision; + unsigned int release_time; /*Mon:Day:Hr:Min*/ + struct fw_priv fwpriv; +}; + +struct hal_priv { + /*Endpoint handles*/ + struct net_device *pipehdls_r8712[10]; + u8 (*hal_bus_init)(struct _adapter *adapter); +}; + +uint rtl8712_hal_init(struct _adapter *padapter); +int rtl871x_load_fw(struct _adapter *padapter); + +#endif diff --git a/kernel/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h new file mode 100644 index 000000000..49598c314 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_INTERRUPT_BITDEF_H__ +#define __RTL8712_INTERRUPT_BITDEF_H__ + +/*HIMR*/ +/*HISR*/ +#define _CPUERR BIT(29) +#define _ATIMEND BIT(28) +#define _TXBCNOK BIT(27) +#define _TXBCNERR BIT(26) +#define _BCNDMAINT4 BIT(25) +#define _BCNDMAINT3 BIT(24) +#define _BCNDMAINT2 BIT(23) +#define _BCNDMAINT1 BIT(22) +#define _BCNDOK4 BIT(21) +#define _BCNDOK3 BIT(20) +#define _BCNDOK2 BIT(19) +#define _BCNDOK1 BIT(18) +#define _TIMEOUT2 BIT(17) +#define _TIMEOUT1 BIT(16) +#define _TXFOVW BIT(15) +#define _PSTIMEOUT BIT(14) +#define _BCNDMAINT0 BIT(13) +#define _FOVW BIT(12) +#define _RDU BIT(11) +#define _RXCMDOK BIT(10) +#define _BCNDOK0 BIT(9) +#define _HIGHDOK BIT(8) +#define _COMDOK BIT(7) +#define _MGTDOK BIT(6) +#define _HCCADOK BIT(5) +#define _BKDOK BIT(4) +#define _BEDOK BIT(3) +#define _VIDOK BIT(2) +#define _VODOK BIT(1) +#define _RXOK BIT(0) + + +#endif /*__RTL8712_INTERRUPT_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_io.c b/kernel/drivers/staging/rtl8712/rtl8712_io.c new file mode 100644 index 000000000..921fcffb3 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_io.c @@ -0,0 +1,146 @@ +/****************************************************************************** + * rtl8712_io.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com>. + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL8712_IO_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "rtl871x_io.h" +#include "osdep_intf.h" +#include "usb_ops.h" + +u8 r8712_read8(struct _adapter *adapter, u32 addr) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); + + _read8 = pintfhdl->io_ops._read8; + return _read8(pintfhdl, addr); +} + +u16 r8712_read16(struct _adapter *adapter, u32 addr) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); + + _read16 = pintfhdl->io_ops._read16; + return _read16(pintfhdl, addr); +} + +u32 r8712_read32(struct _adapter *adapter, u32 addr) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); + + _read32 = pintfhdl->io_ops._read32; + return _read32(pintfhdl, addr); +} + +void r8712_write8(struct _adapter *adapter, u32 addr, u8 val) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + void (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); + + _write8 = pintfhdl->io_ops._write8; + _write8(pintfhdl, addr, val); +} + +void r8712_write16(struct _adapter *adapter, u32 addr, u16 val) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + void (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); + + _write16 = pintfhdl->io_ops._write16; + _write16(pintfhdl, addr, val); +} + +void r8712_write32(struct _adapter *adapter, u32 addr, u32 val) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = (struct intf_hdl *)(&(pio_queue->intf)); + + void (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + + _write32 = pintfhdl->io_ops._write32; + _write32(pintfhdl, addr, val); +} + +void r8712_read_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + + void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); + if ((adapter->bDriverStopped == true) || + (adapter->bSurpriseRemoved == true)) + return; + _read_mem = pintfhdl->io_ops._read_mem; + _read_mem(pintfhdl, addr, cnt, pmem); +} + +void r8712_write_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); + + _write_mem = pintfhdl->io_ops._write_mem; + _write_mem(pintfhdl, addr, cnt, pmem); +} + +void r8712_read_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + + u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); + if ((adapter->bDriverStopped == true) || + (adapter->bSurpriseRemoved == true)) + return; + _read_port = pintfhdl->io_ops._read_port; + _read_port(pintfhdl, addr, cnt, pmem); +} + +void r8712_write_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; + struct intf_hdl *pintfhdl = &(pio_queue->intf); + + u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); + _write_port = pintfhdl->io_ops._write_port; + _write_port(pintfhdl, addr, cnt, pmem); +} diff --git a/kernel/drivers/staging/rtl8712/rtl8712_led.c b/kernel/drivers/staging/rtl8712/rtl8712_led.c new file mode 100644 index 000000000..ada8d5daf --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_led.c @@ -0,0 +1,1834 @@ +/****************************************************************************** + * rtl8712_led.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#include "drv_types.h" + +/*=========================================================================== + * Constant. + *=========================================================================== + + * + * Default LED behavior. + */ +#define LED_BLINK_NORMAL_INTERVAL 100 +#define LED_BLINK_SLOWLY_INTERVAL 200 +#define LED_BLINK_LONG_INTERVAL 400 + +#define LED_BLINK_NO_LINK_INTERVAL_ALPHA 1000 +#define LED_BLINK_LINK_INTERVAL_ALPHA 500 +#define LED_BLINK_SCAN_INTERVAL_ALPHA 180 +#define LED_BLINK_FASTER_INTERVAL_ALPHA 50 +#define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA 5000 + +/*=========================================================================== + * LED object. + *=========================================================================== + */ +enum _LED_STATE_871x { + LED_UNKNOWN = 0, + LED_ON = 1, + LED_OFF = 2, + LED_BLINK_NORMAL = 3, + LED_BLINK_SLOWLY = 4, + LED_POWER_ON_BLINK = 5, + LED_SCAN_BLINK = 6, /* LED is blinking during scanning period, + * the # of times to blink is depend on time + * for scanning. */ + LED_NO_LINK_BLINK = 7, /* LED is blinking during no link state. */ + LED_BLINK_StartToBlink = 8,/* Customized for Sercomm Printer + * Server case */ + LED_BLINK_WPS = 9, /* LED is blinkg during WPS communication */ + LED_TXRX_BLINK = 10, + LED_BLINK_WPS_STOP = 11, /*for ALPHA */ + LED_BLINK_WPS_STOP_OVERLAP = 12, /*for BELKIN */ +}; + +/*=========================================================================== + * Prototype of protected function. + *=========================================================================== + */ +static void BlinkTimerCallback(unsigned long data); + +static void BlinkWorkItemCallback(struct work_struct *work); +/*=========================================================================== + * LED_819xUsb routines. + *=========================================================================== + * + * + * + * Description: + * Initialize an LED_871x object. + */ +static void InitLed871x(struct _adapter *padapter, struct LED_871x *pLed, + enum LED_PIN_871x LedPin) +{ + struct net_device *nic; + + nic = padapter->pnetdev; + pLed->padapter = padapter; + pLed->LedPin = LedPin; + pLed->CurrLedState = LED_OFF; + pLed->bLedOn = false; + pLed->bLedBlinkInProgress = false; + pLed->BlinkTimes = 0; + pLed->BlinkingLedState = LED_UNKNOWN; + setup_timer(&pLed->BlinkTimer, BlinkTimerCallback, + (unsigned long)pLed); + INIT_WORK(&pLed->BlinkWorkItem, BlinkWorkItemCallback); +} + +/* + * Description: + * DeInitialize an LED_871x object. + */ +static void DeInitLed871x(struct LED_871x *pLed) +{ + del_timer_sync(&pLed->BlinkTimer); + /* We should reset bLedBlinkInProgress if we cancel + * the LedControlTimer, */ + pLed->bLedBlinkInProgress = false; +} + +/* + * Description: + * Turn on LED according to LedPin specified. + */ +static void SwLedOn(struct _adapter *padapter, struct LED_871x *pLed) +{ + u8 LedCfg; + + if ((padapter->bSurpriseRemoved == true) || + (padapter->bDriverStopped == true)) + return; + LedCfg = r8712_read8(padapter, LEDCFG); + switch (pLed->LedPin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + /* SW control led0 on.*/ + r8712_write8(padapter, LEDCFG, LedCfg&0xf0); + break; + case LED_PIN_LED1: + /* SW control led1 on.*/ + r8712_write8(padapter, LEDCFG, LedCfg&0x0f); + break; + default: + break; + } + pLed->bLedOn = true; +} + +/* + * Description: + * Turn off LED according to LedPin specified. + */ +static void SwLedOff(struct _adapter *padapter, struct LED_871x *pLed) +{ + u8 LedCfg; + + if ((padapter->bSurpriseRemoved == true) || + (padapter->bDriverStopped == true)) + return; + LedCfg = r8712_read8(padapter, LEDCFG); + switch (pLed->LedPin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + LedCfg &= 0xf0; /* Set to software control.*/ + r8712_write8(padapter, LEDCFG, (LedCfg|BIT(3))); + break; + case LED_PIN_LED1: + LedCfg &= 0x0f; /* Set to software control.*/ + r8712_write8(padapter, LEDCFG, (LedCfg|BIT(7))); + break; + default: + break; + } + pLed->bLedOn = false; +} + +/*=========================================================================== + * Interface to manipulate LED objects. + *=========================================================================== + * + * Description: + * Initialize all LED_871x objects. + */ +void r8712_InitSwLeds(struct _adapter *padapter) +{ + struct led_priv *pledpriv = &(padapter->ledpriv); + + pledpriv->LedControlHandler = LedControl871x; + InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0); + InitLed871x(padapter, &(pledpriv->SwLed1), LED_PIN_LED1); +} + +/* Description: + * DeInitialize all LED_819xUsb objects. + */ +void r8712_DeInitSwLeds(struct _adapter *padapter) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + + DeInitLed871x(&(ledpriv->SwLed0)); + DeInitLed871x(&(ledpriv->SwLed1)); +} + +/* Description: + * Implementation of LED blinking behavior. + * It toggle off LED and schedule corresponding timer if necessary. + */ +static void SwLedBlink(struct LED_871x *pLed) +{ + struct _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == LED_ON) + SwLedOn(padapter, pLed); + else + SwLedOff(padapter, pLed); + /* Determine if we shall change LED state again. */ + pLed->BlinkTimes--; + switch (pLed->CurrLedState) { + case LED_BLINK_NORMAL: + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + break; + case LED_BLINK_StartToBlink: + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && + (pmlmepriv->fw_state & WIFI_STATION_STATE)) + bStopBlinking = true; + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && + ((pmlmepriv->fw_state & WIFI_ADHOC_STATE) || + (pmlmepriv->fw_state & WIFI_ADHOC_MASTER_STATE))) + bStopBlinking = true; + else if (pLed->BlinkTimes == 0) + bStopBlinking = true; + break; + case LED_BLINK_WPS: + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + break; + default: + bStopBlinking = true; + break; + } + if (bStopBlinking) { + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && + (pLed->bLedOn == false)) + SwLedOn(padapter, pLed); + else if ((check_fwstate(pmlmepriv, _FW_LINKED) == + true) && pLed->bLedOn == true) + SwLedOff(padapter, pLed); + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = false; + } else { + /* Assign LED state to toggle. */ + if (pLed->BlinkingLedState == LED_ON) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + + /* Schedule a timer to toggle LED state. */ + switch (pLed->CurrLedState) { + case LED_BLINK_NORMAL: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + break; + case LED_BLINK_SLOWLY: + case LED_BLINK_StartToBlink: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + break; + case LED_BLINK_WPS: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LONG_INTERVAL)); + break; + default: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + break; + } + } +} + +static void SwLedBlink1(struct LED_871x *pLed) +{ + struct _adapter *padapter = pLed->padapter; + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct eeprom_priv *peeprompriv = &(padapter->eeprompriv); + struct LED_871x *pLed1 = &(ledpriv->SwLed1); + u8 bStopBlinking = false; + + if (peeprompriv->CustomerID == RT_CID_819x_CAMEO) + pLed = &(ledpriv->SwLed1); + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == LED_ON) + SwLedOn(padapter, pLed); + else + SwLedOff(padapter, pLed); + if (peeprompriv->CustomerID == RT_CID_DEFAULT) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + if (!pLed1->bSWLedCtrl) { + SwLedOn(padapter, pLed1); + pLed1->bSWLedCtrl = true; + } else if (!pLed1->bLedOn) + SwLedOn(padapter, pLed1); + } else { + if (!pLed1->bSWLedCtrl) { + SwLedOff(padapter, pLed1); + pLed1->bSWLedCtrl = true; + } else if (pLed1->bLedOn) + SwLedOff(padapter, pLed1); + } + } + switch (pLed->CurrLedState) { + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + break; + case LED_BLINK_NORMAL: + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); + break; + case LED_SCAN_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + } + pLed->bLedScanBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_TXRX_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + } + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + break; + case LED_BLINK_WPS_STOP: /* WPS success */ + if (pLed->BlinkingLedState == LED_ON) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA)); + bStopBlinking = false; + } else + bStopBlinking = true; + if (bStopBlinking) { + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); + } + pLed->bLedWPSBlinkInProgress = false; + break; + default: + break; + } +} + +static void SwLedBlink2(struct LED_871x *pLed) +{ + struct _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == LED_ON) + SwLedOn(padapter, pLed); + else + SwLedOff(padapter, pLed); + switch (pLed->CurrLedState) { + case LED_SCAN_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + SwLedOn(padapter, pLed); + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + SwLedOff(padapter, pLed); + } + pLed->bLedScanBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_TXRX_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + SwLedOn(padapter, pLed); + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + SwLedOff(padapter, pLed); + } + pLed->bLedBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + default: + break; + } +} + +static void SwLedBlink3(struct LED_871x *pLed) +{ + struct _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == LED_ON) + SwLedOn(padapter, pLed); + else + if (pLed->CurrLedState != LED_BLINK_WPS_STOP) + SwLedOff(padapter, pLed); + switch (pLed->CurrLedState) { + case LED_SCAN_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + if (!pLed->bLedOn) + SwLedOn(padapter, pLed); + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedOn) + SwLedOff(padapter, pLed); + } + pLed->bLedScanBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_TXRX_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + if (!pLed->bLedOn) + SwLedOn(padapter, pLed); + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedOn) + SwLedOff(padapter, pLed); + } + pLed->bLedBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + break; + case LED_BLINK_WPS_STOP: /*WPS success*/ + if (pLed->BlinkingLedState == LED_ON) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA)); + bStopBlinking = false; + } else + bStopBlinking = true; + if (bStopBlinking) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + SwLedOn(padapter, pLed); + pLed->bLedWPSBlinkInProgress = false; + } + break; + default: + break; + } +} + +static void SwLedBlink4(struct LED_871x *pLed) +{ + struct _adapter *padapter = pLed->padapter; + struct led_priv *ledpriv = &(padapter->ledpriv); + struct LED_871x *pLed1 = &(ledpriv->SwLed1); + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == LED_ON) + SwLedOn(padapter, pLed); + else + SwLedOff(padapter, pLed); + if (!pLed1->bLedWPSBlinkInProgress && + pLed1->BlinkingLedState == LED_UNKNOWN) { + pLed1->BlinkingLedState = LED_OFF; + pLed1->CurrLedState = LED_OFF; + SwLedOff(padapter, pLed1); + } + switch (pLed->CurrLedState) { + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + break; + case LED_BLINK_StartToBlink: + if (pLed->bLedOn) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + } else { + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + } + break; + case LED_SCAN_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + pLed->bLedScanBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_TXRX_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + pLed->bLedBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_BLINK_WPS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + } else { + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + } + break; + case LED_BLINK_WPS_STOP: /*WPS authentication fail*/ + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + break; + case LED_BLINK_WPS_STOP_OVERLAP: /*WPS session overlap */ + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) { + if (pLed->bLedOn) + pLed->BlinkTimes = 1; + else + bStopBlinking = true; + } + if (bStopBlinking) { + pLed->BlinkTimes = 10; + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + } + break; + default: + break; + } +} + +static void SwLedBlink5(struct LED_871x *pLed) +{ + struct _adapter *padapter = pLed->padapter; + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == LED_ON) + SwLedOn(padapter, pLed); + else + SwLedOff(padapter, pLed); + switch (pLed->CurrLedState) { + case LED_SCAN_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + if (!pLed->bLedOn) + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + pLed->bLedScanBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_TXRX_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + if (!pLed->bLedOn) + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + pLed->bLedBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + default: + break; + } +} + +static void SwLedBlink6(struct LED_871x *pLed) +{ + struct _adapter *padapter = pLed->padapter; + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == LED_ON) + SwLedOn(padapter, pLed); + else + SwLedOff(padapter, pLed); + switch (pLed->CurrLedState) { + case LED_TXRX_BLINK: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + if (!pLed->bLedOn) + SwLedOn(padapter, pLed); + pLed->bLedBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + break; + + default: + break; + } +} + +/* Description: + * Callback function of LED BlinkTimer, + * it just schedules to corresponding BlinkWorkItem. + */ +static void BlinkTimerCallback(unsigned long data) +{ + struct LED_871x *pLed = (struct LED_871x *)data; + + /* This fixed the crash problem on Fedora 12 when trying to do the + * insmod;ifconfig up;rmmod commands. */ + if ((pLed->padapter->bSurpriseRemoved == true) || + (pLed->padapter->bDriverStopped == true)) + return; + schedule_work(&pLed->BlinkWorkItem); +} + +/* Description: + * Callback function of LED BlinkWorkItem. + * We dispatch actual LED blink action according to LedStrategy. + */ +static void BlinkWorkItemCallback(struct work_struct *work) +{ + struct LED_871x *pLed = container_of(work, struct LED_871x, + BlinkWorkItem); + struct led_priv *ledpriv = &(pLed->padapter->ledpriv); + + switch (ledpriv->LedStrategy) { + case SW_LED_MODE0: + SwLedBlink(pLed); + break; + case SW_LED_MODE1: + SwLedBlink1(pLed); + break; + case SW_LED_MODE2: + SwLedBlink2(pLed); + break; + case SW_LED_MODE3: + SwLedBlink3(pLed); + break; + case SW_LED_MODE4: + SwLedBlink4(pLed); + break; + case SW_LED_MODE5: + SwLedBlink5(pLed); + break; + case SW_LED_MODE6: + SwLedBlink6(pLed); + break; + default: + SwLedBlink(pLed); + break; + } +} + +/*============================================================================ + * Default LED behavior. + *============================================================================ + * + * Description: + * Implement each led action for SW_LED_MODE0. + * This is default strategy. + */ + +static void SwLedControlMode1(struct _adapter *padapter, + enum LED_CTL_MODE LedAction) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct LED_871x *pLed = &(ledpriv->SwLed0); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct sitesurvey_ctrl *psitesurveyctrl = &(pmlmepriv->sitesurveyctrl); + + if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO) + pLed = &(ledpriv->SwLed1); + switch (LedAction) { + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (pLed->bLedNoLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + } + break; + case LED_CTL_LINK: + if (pLed->bLedLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); + } + break; + case LED_CTL_SITE_SURVEY: + if ((psitesurveyctrl->traffic_busy) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) + ; /* dummy branch */ + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_SCAN_BLINK; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == false) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_TXRX_BLINK; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_START_WPS: /*wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_CTL_STOP_WPS: + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) + del_timer(&pLed->BlinkTimer); + else + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA)); + } else { + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + break; + case LED_CTL_STOP_WPS_FAIL: + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + break; + case LED_CTL_POWER_OFF: + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedNoLinkBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + default: + break; + } +} + +static void SwLedControlMode2(struct _adapter *padapter, + enum LED_CTL_MODE LedAction) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct LED_871x *pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_SITE_SURVEY: + if (pmlmepriv->sitesurveyctrl.traffic_busy) + ; /* dummy branch */ + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_SCAN_BLINK; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if ((pLed->bLedBlinkInProgress == false) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_TXRX_BLINK; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_LINK: + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + + case LED_CTL_START_WPS: /*wait until xinpin finish*/ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + break; + + case LED_CTL_STOP_WPS: + pLed->bLedWPSBlinkInProgress = false; + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + + case LED_CTL_STOP_WPS_FAIL: + pLed->bLedWPSBlinkInProgress = false; + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (!IS_LED_BLINKING(pLed)) { + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + break; + case LED_CTL_POWER_OFF: + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + default: + break; + } +} + +static void SwLedControlMode3(struct _adapter *padapter, + enum LED_CTL_MODE LedAction) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct LED_871x *pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_SITE_SURVEY: + if (pmlmepriv->sitesurveyctrl.traffic_busy) + ; /* dummy branch */ + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_SCAN_BLINK; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_CTL_TX: + case LED_CTL_RX: + if ((pLed->bLedBlinkInProgress == false) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_TXRX_BLINK; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_CTL_LINK: + if (IS_LED_WPS_BLINKING(pLed)) + return; + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_CTL_STOP_WPS: + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } else + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA)); + } else { + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + break; + case LED_CTL_STOP_WPS_FAIL: + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (!IS_LED_BLINKING(pLed)) { + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + break; + case LED_CTL_POWER_OFF: + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + default: + break; + } +} + +static void SwLedControlMode4(struct _adapter *padapter, + enum LED_CTL_MODE LedAction) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct LED_871x *pLed = &(ledpriv->SwLed0); + struct LED_871x *pLed1 = &(ledpriv->SwLed1); + + switch (LedAction) { + case LED_CTL_START_TO_LINK: + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = false; + del_timer(&pLed1->BlinkTimer); + pLed1->BlinkingLedState = LED_OFF; + pLed1->CurrLedState = LED_OFF; + if (pLed1->bLedOn) + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + if (pLed->bLedStartToLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + pLed->bLedStartToLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_StartToBlink; + if (pLed->bLedOn) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + } else { + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + } + } + break; + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + /*LED1 settings*/ + if (LedAction == LED_CTL_LINK) { + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = false; + del_timer(&pLed1->BlinkTimer); + pLed1->BlinkingLedState = LED_OFF; + pLed1->CurrLedState = LED_OFF; + if (pLed1->bLedOn) + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + } + if (pLed->bLedNoLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + } + break; + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->sitesurveyctrl.traffic_busy) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) + ; + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_SCAN_BLINK; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == false) { + if (pLed->CurrLedState == LED_SCAN_BLINK || + IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_TXRX_BLINK; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_CTL_START_WPS: /*wait until xinpin finish*/ + case LED_CTL_START_WPS_BOTTON: + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = false; + del_timer(&pLed1->BlinkTimer); + pLed1->BlinkingLedState = LED_OFF; + pLed1->CurrLedState = LED_OFF; + if (pLed1->bLedOn) + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + } + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) { + pLed->BlinkingLedState = LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + } else { + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + } + } + break; + case LED_CTL_STOP_WPS: /*WPS connect success*/ + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + break; + case LED_CTL_STOP_WPS_FAIL: /*WPS authentication fail*/ + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + /*LED1 settings*/ + if (pLed1->bLedWPSBlinkInProgress) + del_timer(&pLed1->BlinkTimer); + else + pLed1->bLedWPSBlinkInProgress = true; + pLed1->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = LED_OFF; + else + pLed1->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + break; + case LED_CTL_STOP_WPS_FAIL_OVERLAP: /*WPS session overlap*/ + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + /*LED1 settings*/ + if (pLed1->bLedWPSBlinkInProgress) + del_timer(&pLed1->BlinkTimer); + else + pLed1->bLedWPSBlinkInProgress = true; + pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; + pLed1->BlinkTimes = 10; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = LED_OFF; + else + pLed1->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + break; + case LED_CTL_POWER_OFF: + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedNoLinkBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedStartToLinkBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedStartToLinkBlinkInProgress = false; + } + if (pLed1->bLedWPSBlinkInProgress) { + del_timer(&pLed1->BlinkTimer); + pLed1->bLedWPSBlinkInProgress = false; + } + pLed1->BlinkingLedState = LED_UNKNOWN; + SwLedOff(padapter, pLed); + SwLedOff(padapter, pLed1); + break; + default: + break; + } +} + +static void SwLedControlMode5(struct _adapter *padapter, + enum LED_CTL_MODE LedAction) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct LED_871x *pLed = &(ledpriv->SwLed0); + + if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO) + pLed = &(ledpriv->SwLed1); + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_NO_LINK: + case LED_CTL_LINK: /* solid blue */ + if (pLed->CurrLedState == LED_SCAN_BLINK) + return; + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + pLed->bLedBlinkInProgress = false; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->sitesurveyctrl.traffic_busy) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) + ; /* dummy branch */ + else if (pLed->bLedScanBlinkInProgress == false) { + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_SCAN_BLINK; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == false) { + if (pLed->CurrLedState == LED_SCAN_BLINK) + return; + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_TXRX_BLINK; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_CTL_POWER_OFF: + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + SwLedOff(padapter, pLed); + break; + default: + break; + } +} + + +static void SwLedControlMode6(struct _adapter *padapter, + enum LED_CTL_MODE LedAction) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct LED_871x *pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_NO_LINK: + case LED_CTL_LINK: /*solid blue*/ + case LED_CTL_SITE_SURVEY: + if (IS_LED_WPS_BLINKING(pLed)) + return; + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + pLed->bLedBlinkInProgress = false; + mod_timer(&(pLed->BlinkTimer), jiffies + msecs_to_jiffies(0)); + break; + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == false && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_TXRX_BLINK; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + case LED_CTL_START_WPS: /*wait until xinpin finish*/ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedBlinkInProgress == true) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = LED_OFF; + else + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + case LED_CTL_STOP_WPS_FAIL: + case LED_CTL_STOP_WPS: + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + pLed->CurrLedState = LED_ON; + pLed->BlinkingLedState = LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(0)); + break; + case LED_CTL_POWER_OFF: + pLed->CurrLedState = LED_OFF; + pLed->BlinkingLedState = LED_OFF; + if (pLed->bLedBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + SwLedOff(padapter, pLed); + break; + default: + break; + } +} + +/* Description: + * Dispatch LED action according to pHalData->LedStrategy. + */ +void LedControl871x(struct _adapter *padapter, enum LED_CTL_MODE LedAction) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + + if (ledpriv->bRegUseLed == false) + return; + switch (ledpriv->LedStrategy) { + case SW_LED_MODE0: + break; + case SW_LED_MODE1: + SwLedControlMode1(padapter, LedAction); + break; + case SW_LED_MODE2: + SwLedControlMode2(padapter, LedAction); + break; + case SW_LED_MODE3: + SwLedControlMode3(padapter, LedAction); + break; + case SW_LED_MODE4: + SwLedControlMode4(padapter, LedAction); + break; + case SW_LED_MODE5: + SwLedControlMode5(padapter, LedAction); + break; + case SW_LED_MODE6: + SwLedControlMode6(padapter, LedAction); + break; + default: + break; + } +} diff --git a/kernel/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h new file mode 100644 index 000000000..28e0a7ebc --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_MACSETTING_BITDEF_H__ +#define __RTL8712_MACSETTING_BITDEF_H__ + + +/*MACID*/ +/*BSSID*/ + +/*HWVID*/ +#define _HWVID_MSK 0x0F + +/*MAR*/ +/*MBIDCANCONTENT*/ + +/*MBIDCANCFG*/ +#define _POOLING BIT(31) +#define _WRITE_EN BIT(16) +#define _CAM_ADDR_MSK 0x001F +#define _CAM_ADDR_SHT 0 + +/*BUILDTIME*/ +#define _BUILDTIME_MSK 0x3FFFFFFF + +/*BUILDUSER*/ + + + +#endif /* __RTL8712_MACSETTING_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h new file mode 100644 index 000000000..ced0da933 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_MACSETTING_REGDEF_H__ +#define __RTL8712_MACSETTING_REGDEF_H__ + +#define MACID (RTL8712_MACIDSETTING_ + 0x0000) +#define BSSIDR (RTL8712_MACIDSETTING_ + 0x0008) +#define HWVID (RTL8712_MACIDSETTING_ + 0x000E) +#define MAR (RTL8712_MACIDSETTING_ + 0x0010) +#define MBIDCANCONTENT (RTL8712_MACIDSETTING_ + 0x0018) +#define MBIDCANCFG (RTL8712_MACIDSETTING_ + 0x0020) +#define BUILDTIME (RTL8712_MACIDSETTING_ + 0x0024) +#define BUILDUSER (RTL8712_MACIDSETTING_ + 0x0028) + + + +#endif /*__RTL8712_MACSETTING_REGDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h new file mode 100644 index 000000000..8fc689416 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_POWERSAVE_BITDEF_H__ +#define __RTL8712_POWERSAVE_BITDEF_H__ + +/*WOWCTRL*/ +#define _UWF BIT(3) +#define _MAGIC BIT(2) +#define _WOW_EN BIT(1) +#define _PMEN BIT(0) + +/*PSSTATUS*/ +#define _PSSTATUS_SEL_MSK 0x0F + +/*PSSWITCH*/ +#define _PSSWITCH_ACT BIT(7) +#define _PSSWITCH_SEL_MSK 0x0F +#define _PSSWITCH_SEL_SHT 0 + +/*LPNAV_CTRL*/ +#define _LPNAV_EN BIT(31) +#define _LPNAV_EARLY_MSK 0x7FFF0000 +#define _LPNAV_EARLY_SHT 16 +#define _LPNAV_TH_MSK 0x0000FFFF +#define _LPNAV_TH_SHT 0 + +/*RPWM*/ +/*CPWM*/ +#define _TOGGLING BIT(7) +#define _WWLAN BIT(3) +#define _RPS_ST BIT(2) +#define _WLAN_TRX BIT(1) +#define _SYS_CLK BIT(0) + +#endif /* __RTL8712_POWERSAVE_BITDEF_H__*/ diff --git a/kernel/drivers/staging/rtl8712/rtl8712_powersave_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_powersave_regdef.h new file mode 100644 index 000000000..4632ddd5d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_powersave_regdef.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_POWERSAVE_REGDEF_H__ +#define __RTL8712_POWERSAVE_REGDEF_H__ + +#define WOWCTRL (RTL8712_POWERSAVE_ + 0x00) +#define PSSTATUS (RTL8712_POWERSAVE_ + 0x01) +#define PSSWITCH (RTL8712_POWERSAVE_ + 0x02) +#define MIMOPS_WAITPERIOD (RTL8712_POWERSAVE_ + 0x03) +#define LPNAV_CTRL (RTL8712_POWERSAVE_ + 0x04) +#define WFM0 (RTL8712_POWERSAVE_ + 0x10) +#define WFM1 (RTL8712_POWERSAVE_ + 0x20) +#define WFM2 (RTL8712_POWERSAVE_ + 0x30) +#define WFM3 (RTL8712_POWERSAVE_ + 0x40) +#define WFM4 (RTL8712_POWERSAVE_ + 0x50) +#define WFM5 (RTL8712_POWERSAVE_ + 0x60) +#define WFCRC (RTL8712_POWERSAVE_ + 0x70) +#define RPWM (RTL8712_POWERSAVE_ + 0x7C) +#define CPWM (RTL8712_POWERSAVE_ + 0x7D) + +#endif /* __RTL8712_POWERSAVE_REGDEF_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h new file mode 100644 index 000000000..6d3d6e852 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_RATECTRL_BITDEF_H__ +#define __RTL8712_RATECTRL_BITDEF_H__ + +/*INIRTSMCS_SEL*/ +#define _INIRTSMCS_SEL_MSK 0x3F + +/* RRSR*/ +#define _RRSR_SHORT BIT(23) +#define _RRSR_RSC_MSK 0x600000 +#define _RRSR_RSC_SHT 21 +#define _RRSR_BITMAP_MSK 0x0FFFFF +#define _RRSR_BITMAP_SHT 0 + +/* AGGLEN_LMT_H*/ +#define _AGGLMT_MCS32_MSK 0xF0 +#define _AGGLMT_MCS32_SHT 4 +#define _AGGLMT_MCS15_SGI_MSK 0x0F +#define _AGGLMT_MCS15_SGI_SHT 0 + +/* DARFRC*/ +/* RARFRC*/ +/* MCS_TXAGC*/ +/* CCK_TXAGC*/ +#define _CCK_MSK 0xFF00 +#define _CCK_SHT 8 +#define _BARKER_MSK 0x00FF +#define _BARKER_SHT 0 + +#endif /* __RTL8712_RATECTRL_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h new file mode 100644 index 000000000..73dfc3610 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_RATECTRL_REGDEF_H__ +#define __RTL8712_RATECTRL_REGDEF_H__ + +#define INIMCS_SEL (RTL8712_RATECTRL_ + 0x00) +#define INIRTSMCS_SEL (RTL8712_RATECTRL_ + 0x20) +#define RRSR (RTL8712_RATECTRL_ + 0x21) +#define ARFR0 (RTL8712_RATECTRL_ + 0x24) +#define ARFR1 (RTL8712_RATECTRL_ + 0x28) +#define ARFR2 (RTL8712_RATECTRL_ + 0x2C) +#define ARFR3 (RTL8712_RATECTRL_ + 0x30) +#define ARFR4 (RTL8712_RATECTRL_ + 0x34) +#define ARFR5 (RTL8712_RATECTRL_ + 0x38) +#define ARFR6 (RTL8712_RATECTRL_ + 0x3C) +#define ARFR7 (RTL8712_RATECTRL_ + 0x40) +#define AGGLEN_LMT_H (RTL8712_RATECTRL_ + 0x47) +#define AGGLEN_LMT_L (RTL8712_RATECTRL_ + 0x48) +#define DARFRC (RTL8712_RATECTRL_ + 0x50) +#define RARFRC (RTL8712_RATECTRL_ + 0x58) +#define MCS_TXAGC0 (RTL8712_RATECTRL_ + 0x60) +#define MCS_TXAGC1 (RTL8712_RATECTRL_ + 0x61) +#define MCS_TXAGC2 (RTL8712_RATECTRL_ + 0x62) +#define MCS_TXAGC3 (RTL8712_RATECTRL_ + 0x63) +#define MCS_TXAGC4 (RTL8712_RATECTRL_ + 0x64) +#define MCS_TXAGC5 (RTL8712_RATECTRL_ + 0x65) +#define MCS_TXAGC6 (RTL8712_RATECTRL_ + 0x66) +#define MCS_TXAGC7 (RTL8712_RATECTRL_ + 0x67) +#define CCK_TXAGC (RTL8712_RATECTRL_ + 0x68) + + +#endif /*__RTL8712_RATECTRL_REGDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_recv.c b/kernel/drivers/staging/rtl8712/rtl8712_recv.c new file mode 100644 index 000000000..50227b598 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_recv.c @@ -0,0 +1,1117 @@ +/****************************************************************************** + * rtl8712_recv.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL8712_RECV_C_ + +#include <linux/if_ether.h> +#include <linux/ip.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "recv_osdep.h" +#include "mlme_osdep.h" +#include "ethernet.h" +#include "usb_ops.h" +#include "wifi.h" + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static u8 bridge_tunnel_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; + +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static u8 rfc1042_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; + +static void recv_tasklet(void *priv); + +int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter) +{ + int i; + struct recv_buf *precvbuf; + int res = _SUCCESS; + addr_t tmpaddr = 0; + int alignment = 0; + struct sk_buff *pskb = NULL; + + /*init recv_buf*/ + _init_queue(&precvpriv->free_recv_buf_queue); + precvpriv->pallocated_recv_buf = kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4, + GFP_ATOMIC); + if (precvpriv->pallocated_recv_buf == NULL) + return _FAIL; + precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 - + ((addr_t) (precvpriv->pallocated_recv_buf) & 3); + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + for (i = 0; i < NR_RECVBUFF; i++) { + INIT_LIST_HEAD(&precvbuf->list); + spin_lock_init(&precvbuf->recvbuf_lock); + res = r8712_os_recvbuf_resource_alloc(padapter, precvbuf); + if (res == _FAIL) + break; + precvbuf->ref_cnt = 0; + precvbuf->adapter = padapter; + list_add_tail(&precvbuf->list, + &(precvpriv->free_recv_buf_queue.queue)); + precvbuf++; + } + precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; + tasklet_init(&precvpriv->recv_tasklet, + (void(*)(unsigned long))recv_tasklet, + (unsigned long)padapter); + skb_queue_head_init(&precvpriv->rx_skb_queue); + + skb_queue_head_init(&precvpriv->free_recv_skb_queue); + for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) { + pskb = netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ + + RECVBUFF_ALIGN_SZ); + if (pskb) { + tmpaddr = (addr_t)pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); + skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + } + pskb = NULL; + } + return res; +} + +void r8712_free_recv_priv(struct recv_priv *precvpriv) +{ + int i; + struct recv_buf *precvbuf; + struct _adapter *padapter = precvpriv->adapter; + + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + for (i = 0; i < NR_RECVBUFF; i++) { + r8712_os_recvbuf_resource_free(padapter, precvbuf); + precvbuf++; + } + kfree(precvpriv->pallocated_recv_buf); + skb_queue_purge(&precvpriv->rx_skb_queue); + if (skb_queue_len(&precvpriv->rx_skb_queue)) + netdev_warn(padapter->pnetdev, "r8712u: rx_skb_queue not empty\n"); + skb_queue_purge(&precvpriv->free_recv_skb_queue); + if (skb_queue_len(&precvpriv->free_recv_skb_queue)) + netdev_warn(padapter->pnetdev, "r8712u: free_recv_skb_queue not empty %d\n", + skb_queue_len(&precvpriv->free_recv_skb_queue)); +} + +int r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf) +{ + precvbuf->transfer_len = 0; + precvbuf->len = 0; + precvbuf->ref_cnt = 0; + if (precvbuf->pbuf) { + precvbuf->pdata = precvbuf->pbuf; + precvbuf->phead = precvbuf->pbuf; + precvbuf->ptail = precvbuf->pbuf; + precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ; + } + return _SUCCESS; +} + +int r8712_free_recvframe(union recv_frame *precvframe, + struct __queue *pfree_recv_queue) +{ + unsigned long irqL; + struct _adapter *padapter = precvframe->u.hdr.adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + + if (precvframe->u.hdr.pkt) { + dev_kfree_skb_any(precvframe->u.hdr.pkt);/*free skb by driver*/ + precvframe->u.hdr.pkt = NULL; + } + spin_lock_irqsave(&pfree_recv_queue->lock, irqL); + list_del_init(&(precvframe->u.hdr.list)); + list_add_tail(&(precvframe->u.hdr.list), &pfree_recv_queue->queue); + if (padapter != NULL) { + if (pfree_recv_queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt++; + } + spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL); + return _SUCCESS; +} + +static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib, + struct recv_stat *prxstat) +{ + u16 drvinfo_sz = 0; + + drvinfo_sz = (le32_to_cpu(prxstat->rxdw0)&0x000f0000)>>16; + drvinfo_sz <<= 3; + /*TODO: + * Offset 0 */ + pattrib->bdecrypted = ((le32_to_cpu(prxstat->rxdw0) & BIT(27)) >> 27) + ? 0 : 1; + pattrib->crc_err = (le32_to_cpu(prxstat->rxdw0) & BIT(14)) >> 14; + /*Offset 4*/ + /*Offset 8*/ + /*Offset 12*/ + if (le32_to_cpu(prxstat->rxdw3) & BIT(13)) { + pattrib->tcpchk_valid = 1; /* valid */ + if (le32_to_cpu(prxstat->rxdw3) & BIT(11)) + pattrib->tcp_chkrpt = 1; /* correct */ + else + pattrib->tcp_chkrpt = 0; /* incorrect */ + if (le32_to_cpu(prxstat->rxdw3) & BIT(12)) + pattrib->ip_chkrpt = 1; /* correct */ + else + pattrib->ip_chkrpt = 0; /* incorrect */ + } else + pattrib->tcpchk_valid = 0; /* invalid */ + pattrib->mcs_rate = (u8)((le32_to_cpu(prxstat->rxdw3)) & 0x3f); + pattrib->htc = (u8)((le32_to_cpu(prxstat->rxdw3) >> 14) & 0x1); + /*Offset 16*/ + /*Offset 20*/ + /*phy_info*/ +} + +/*perform defrag*/ +static union recv_frame *recvframe_defrag(struct _adapter *adapter, + struct __queue *defrag_q) +{ + struct list_head *plist, *phead; + u8 wlanhdr_offset; + u8 curfragnum; + struct recv_frame_hdr *pfhdr, *pnfhdr; + union recv_frame *prframe, *pnextrframe; + struct __queue *pfree_recv_queue; + + pfree_recv_queue = &adapter->recvpriv.free_recv_queue; + phead = &defrag_q->queue; + plist = phead->next; + prframe = LIST_CONTAINOR(plist, union recv_frame, u); + list_del_init(&prframe->u.list); + pfhdr = &prframe->u.hdr; + curfragnum = 0; + if (curfragnum != pfhdr->attrib.frag_num) { + /*the first fragment number must be 0 + *free the whole queue*/ + r8712_free_recvframe(prframe, pfree_recv_queue); + r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); + return NULL; + } + curfragnum++; + plist = &defrag_q->queue; + plist = plist->next; + while (end_of_queue_search(phead, plist) == false) { + pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u); + pnfhdr = &pnextrframe->u.hdr; + /*check the fragment sequence (2nd ~n fragment frame) */ + if (curfragnum != pnfhdr->attrib.frag_num) { + /* the fragment number must increase (after decache) + * release the defrag_q & prframe */ + r8712_free_recvframe(prframe, pfree_recv_queue); + r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); + return NULL; + } + curfragnum++; + /* copy the 2nd~n fragment frame's payload to the first fragment + * get the 2nd~last fragment frame's payload */ + wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; + recvframe_pull(pnextrframe, wlanhdr_offset); + /* append to first fragment frame's tail (if privacy frame, + * pull the ICV) */ + recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); + memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); + recvframe_put(prframe, pnfhdr->len); + pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; + plist = plist->next; + } + /* free the defrag_q queue and return the prframe */ + r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); + return prframe; +} + +/* check if need to defrag, if needed queue the frame to defrag_q */ +union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter, + union recv_frame *precv_frame) +{ + u8 ismfrag; + u8 fragnum; + u8 *psta_addr; + struct recv_frame_hdr *pfhdr; + struct sta_info *psta; + struct sta_priv *pstapriv; + struct list_head *phead; + union recv_frame *prtnframe = NULL; + struct __queue *pfree_recv_queue, *pdefrag_q; + + pstapriv = &padapter->stapriv; + pfhdr = &precv_frame->u.hdr; + pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + /* need to define struct of wlan header frame ctrl */ + ismfrag = pfhdr->attrib.mfrag; + fragnum = pfhdr->attrib.frag_num; + psta_addr = pfhdr->attrib.ta; + psta = r8712_get_stainfo(pstapriv, psta_addr); + if (psta == NULL) + pdefrag_q = NULL; + else + pdefrag_q = &psta->sta_recvpriv.defrag_q; + + if ((ismfrag == 0) && (fragnum == 0)) + prtnframe = precv_frame;/*isn't a fragment frame*/ + if (ismfrag == 1) { + /* 0~(n-1) fragment frame + * enqueue to defraf_g */ + if (pdefrag_q != NULL) { + if (fragnum == 0) { + /*the first fragment*/ + if (!list_empty(&pdefrag_q->queue)) { + /*free current defrag_q */ + r8712_free_recvframe_queue(pdefrag_q, + pfree_recv_queue); + } + } + /* Then enqueue the 0~(n-1) fragment to the defrag_q */ + phead = &pdefrag_q->queue; + list_add_tail(&pfhdr->list, phead); + prtnframe = NULL; + } else { + /* can't find this ta's defrag_queue, so free this + * recv_frame */ + r8712_free_recvframe(precv_frame, pfree_recv_queue); + prtnframe = NULL; + } + + } + if ((ismfrag == 0) && (fragnum != 0)) { + /* the last fragment frame + * enqueue the last fragment */ + if (pdefrag_q != NULL) { + phead = &pdefrag_q->queue; + list_add_tail(&pfhdr->list, phead); + /*call recvframe_defrag to defrag*/ + precv_frame = recvframe_defrag(padapter, pdefrag_q); + prtnframe = precv_frame; + } else { + /* can't find this ta's defrag_queue, so free this + * recv_frame */ + r8712_free_recvframe(precv_frame, pfree_recv_queue); + prtnframe = NULL; + } + } + if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) { + /* after defrag we must check tkip mic code */ + if (r8712_recvframe_chkmic(padapter, prtnframe) == _FAIL) { + r8712_free_recvframe(prtnframe, pfree_recv_queue); + prtnframe = NULL; + } + } + return prtnframe; +} + +static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe) +{ + int a_len, padding_len; + u16 eth_type, nSubframe_Length; + u8 nr_subframes, i; + unsigned char *data_ptr, *pdata; + struct rx_pkt_attrib *pattrib; + _pkt *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue); + + nr_subframes = 0; + pattrib = &prframe->u.hdr.attrib; + recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen); + if (prframe->u.hdr.attrib.iv_len > 0) + recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len); + a_len = prframe->u.hdr.len; + pdata = prframe->u.hdr.rx_data; + while (a_len > ETH_HLEN) { + /* Offset 12 denote 2 mac address */ + nSubframe_Length = *((u16 *)(pdata + 12)); + /*==m==>change the length order*/ + nSubframe_Length = (nSubframe_Length >> 8) + + (nSubframe_Length << 8); + if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { + netdev_warn(padapter->pnetdev, "r8712u: nRemain_Length is %d and nSubframe_Length is: %d\n", + a_len, nSubframe_Length); + goto exit; + } + /* move the data point to data content */ + pdata += ETH_HLEN; + a_len -= ETH_HLEN; + /* Allocate new skb for releasing to upper layer */ + sub_skb = dev_alloc_skb(nSubframe_Length + 12); + if (!sub_skb) + break; + skb_reserve(sub_skb, 12); + data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); + memcpy(data_ptr, pdata, nSubframe_Length); + subframes[nr_subframes++] = sub_skb; + if (nr_subframes >= MAX_SUBFRAME_COUNT) { + netdev_warn(padapter->pnetdev, "r8712u: ParseSubframe(): Too many Subframes! Packets dropped!\n"); + break; + } + pdata += nSubframe_Length; + a_len -= nSubframe_Length; + if (a_len != 0) { + padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & 3); + if (padding_len == 4) + padding_len = 0; + if (a_len < padding_len) + goto exit; + pdata += padding_len; + a_len -= padding_len; + } + } + for (i = 0; i < nr_subframes; i++) { + sub_skb = subframes[i]; + /* convert hdr + possible LLC headers into Ethernet header */ + eth_type = (sub_skb->data[6] << 8) | sub_skb->data[7]; + if (sub_skb->len >= 8 && + ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) && + eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || + !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(sub_skb, SNAP_SIZE); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, + ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, + ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + len = htons(sub_skb->len); + memcpy(skb_push(sub_skb, 2), &len, 2); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, + ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, + ETH_ALEN); + } + /* Indicate the packets to upper layer */ + if (sub_skb) { + sub_skb->protocol = + eth_type_trans(sub_skb, padapter->pnetdev); + sub_skb->dev = padapter->pnetdev; + if ((pattrib->tcpchk_valid == 1) && + (pattrib->tcp_chkrpt == 1)) { + sub_skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + sub_skb->ip_summed = CHECKSUM_NONE; + netif_rx(sub_skb); + } + } +exit: + prframe->u.hdr.len = 0; + r8712_free_recvframe(prframe, pfree_recv_queue); + return _SUCCESS; +} + +void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf) +{ + uint voffset; + u8 *poffset; + u16 cmd_len, drvinfo_sz; + struct recv_stat *prxstat; + + poffset = (u8 *)prxcmdbuf; + voffset = *(uint *)poffset; + prxstat = (struct recv_stat *)prxcmdbuf; + drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16; + drvinfo_sz <<= 3; + poffset += RXDESC_SIZE + drvinfo_sz; + do { + voffset = *(uint *)poffset; + cmd_len = (u16)(le32_to_cpu(voffset) & 0xffff); + r8712_event_handle(padapter, (uint *)poffset); + poffset += (cmd_len + 8);/*8 bytes alignment*/ + } while (le32_to_cpu(voffset) & BIT(31)); + +} + +static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, + u16 seq_num) +{ + u8 wsize = preorder_ctrl->wsize_b; + u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) % 4096; + + /* Rx Reorder initialize condition.*/ + if (preorder_ctrl->indicate_seq == 0xffff) + preorder_ctrl->indicate_seq = seq_num; + /* Drop out the packet which SeqNum is smaller than WinStart */ + if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) + return false; + /* + * Sliding window manipulation. Conditions includes: + * 1. Incoming SeqNum is equal to WinStart =>Window shift 1 + * 2. Incoming SeqNum is larger than the WinEnd => Window shift N + */ + if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + + 1) % 4096; + else if (SN_LESS(wend, seq_num)) { + if (seq_num >= (wsize - 1)) + preorder_ctrl->indicate_seq = seq_num + 1 - wsize; + else + preorder_ctrl->indicate_seq = 4095 - (wsize - + (seq_num + 1)) + 1; + } + return true; +} + +static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, + union recv_frame *prframe) +{ + struct list_head *phead, *plist; + union recv_frame *pnextrframe; + struct rx_pkt_attrib *pnextattrib; + struct __queue *ppending_recvframe_queue = + &preorder_ctrl->pending_recvframe_queue; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + + phead = &ppending_recvframe_queue->queue; + plist = phead->next; + while (end_of_queue_search(phead, plist) == false) { + pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u); + pnextattrib = &pnextrframe->u.hdr.attrib; + if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) + plist = plist->next; + else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) + return false; + else + break; + } + list_del_init(&(prframe->u.hdr.list)); + list_add_tail(&(prframe->u.hdr.list), plist); + return true; +} + +int r8712_recv_indicatepkts_in_order(struct _adapter *padapter, + struct recv_reorder_ctrl *preorder_ctrl, + int bforced) +{ + struct list_head *phead, *plist; + union recv_frame *prframe; + struct rx_pkt_attrib *pattrib; + int bPktInBuf = false; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct __queue *ppending_recvframe_queue = + &preorder_ctrl->pending_recvframe_queue; + + phead = &ppending_recvframe_queue->queue; + plist = phead->next; + /* Handling some condition for forced indicate case.*/ + if (bforced == true) { + if (list_empty(phead)) + return true; + + prframe = LIST_CONTAINOR(plist, union recv_frame, u); + pattrib = &prframe->u.hdr.attrib; + preorder_ctrl->indicate_seq = pattrib->seq_num; + } + /* Prepare indication list and indication. + * Check if there is any packet need indicate. */ + while (!list_empty(phead)) { + prframe = LIST_CONTAINOR(plist, union recv_frame, u); + pattrib = &prframe->u.hdr.attrib; + if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { + plist = plist->next; + list_del_init(&(prframe->u.hdr.list)); + if (SN_EQUAL(preorder_ctrl->indicate_seq, + pattrib->seq_num)) + preorder_ctrl->indicate_seq = + (preorder_ctrl->indicate_seq + 1) % 4096; + /*indicate this recv_frame*/ + if (!pattrib->amsdu) { + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) { + /* indicate this recv_frame */ + r8712_recv_indicatepkt(padapter, + prframe); + } + } else if (pattrib->amsdu == 1) { + if (amsdu_to_msdu(padapter, prframe) != + _SUCCESS) + r8712_free_recvframe(prframe, + &precvpriv->free_recv_queue); + } + /* Update local variables. */ + bPktInBuf = false; + } else { + bPktInBuf = true; + break; + } + } + return bPktInBuf; +} + +static int recv_indicatepkt_reorder(struct _adapter *padapter, + union recv_frame *prframe) +{ + unsigned long irql; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl; + struct __queue *ppending_recvframe_queue = + &preorder_ctrl->pending_recvframe_queue; + + if (!pattrib->amsdu) { + /* s1. */ + r8712_wlanhdr_to_ethhdr(prframe); + if (pattrib->qos != 1) { + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) { + r8712_recv_indicatepkt(padapter, prframe); + return _SUCCESS; + } else + return _FAIL; + } + } + spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); + /*s2. check if winstart_b(indicate_seq) needs to be updated*/ + if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) + goto _err_exit; + /*s3. Insert all packet into Reorder Queue to maintain its ordering.*/ + if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) + goto _err_exit; + /*s4. + * Indication process. + * After Packet dropping and Sliding Window shifting as above, we can + * now just indicate the packets with the SeqNum smaller than latest + * WinStart and buffer other packets. + * + * For Rx Reorder condition: + * 1. All packets with SeqNum smaller than WinStart => Indicate + * 2. All packets with SeqNum larger than or equal to + * WinStart => Buffer it. + */ + if (r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, false) == + true) { + mod_timer(&preorder_ctrl->reordering_ctrl_timer, + jiffies + msecs_to_jiffies(REORDER_WAIT_TIME)); + spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); + } else { + spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); + del_timer(&preorder_ctrl->reordering_ctrl_timer); + } + return _SUCCESS; +_err_exit: + spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); + return _FAIL; +} + +void r8712_reordering_ctrl_timeout_handler(void *pcontext) +{ + unsigned long irql; + struct recv_reorder_ctrl *preorder_ctrl = + (struct recv_reorder_ctrl *)pcontext; + struct _adapter *padapter = preorder_ctrl->padapter; + struct __queue *ppending_recvframe_queue = + &preorder_ctrl->pending_recvframe_queue; + + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + return; + spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); + r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, true); + spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); +} + +static int r8712_process_recv_indicatepkts(struct _adapter *padapter, + union recv_frame *prframe) +{ + int retval = _SUCCESS; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + if (phtpriv->ht_option == 1) { /*B/G/N Mode*/ + if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) { + /* including perform A-MPDU Rx Ordering Buffer Control*/ + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) + return _FAIL; + } + } else { /*B/G mode*/ + retval = r8712_wlanhdr_to_ethhdr(prframe); + if (retval != _SUCCESS) + return retval; + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) { + /* indicate this recv_frame */ + r8712_recv_indicatepkt(padapter, prframe); + } else + return _FAIL; + } + return retval; +} + +static u8 query_rx_pwr_percentage(s8 antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 evm_db2percentage(s8 value) +{ + /* + * -33dB~0dB to 0%~99% + */ + s8 ret_val; + + ret_val = value; + if (ret_val >= 0) + ret_val = 0; + if (ret_val <= -33) + ret_val = -33; + ret_val = -ret_val; + ret_val *= 3; + if (ret_val == 99) + ret_val = 100; + return ret_val; +} + +s32 r8712_signal_scale_mapping(s32 cur_sig) +{ + s32 ret_sig; + + if (cur_sig >= 51 && cur_sig <= 100) + ret_sig = 100; + else if (cur_sig >= 41 && cur_sig <= 50) + ret_sig = 80 + ((cur_sig - 40) * 2); + else if (cur_sig >= 31 && cur_sig <= 40) + ret_sig = 66 + (cur_sig - 30); + else if (cur_sig >= 21 && cur_sig <= 30) + ret_sig = 54 + (cur_sig - 20); + else if (cur_sig >= 10 && cur_sig <= 20) + ret_sig = 42 + (((cur_sig - 10) * 2) / 3); + else if (cur_sig >= 5 && cur_sig <= 9) + ret_sig = 22 + (((cur_sig - 5) * 3) / 2); + else if (cur_sig >= 1 && cur_sig <= 4) + ret_sig = 6 + (((cur_sig - 1) * 3) / 2); + else + ret_sig = cur_sig; + return ret_sig; +} + +static s32 translate2dbm(struct _adapter *padapter, u8 signal_strength_idx) +{ + s32 signal_power; /* in dBm.*/ + /* Translate to dBm (x=0.5y-95).*/ + signal_power = (s32)((signal_strength_idx + 1) >> 1); + signal_power -= 95; + return signal_power; +} + +static void query_rx_phy_status(struct _adapter *padapter, + union recv_frame *prframe) +{ + u8 i, max_spatial_stream, evm; + struct recv_stat *prxstat = (struct recv_stat *)prframe->u.hdr.rx_head; + struct phy_stat *pphy_stat = (struct phy_stat *)(prxstat + 1); + u8 *pphy_head = (u8 *)(prxstat + 1); + s8 rx_pwr[4], rx_pwr_all; + u8 pwdb_all; + u32 rssi, total_rssi = 0; + u8 bcck_rate = 0, rf_rx_num = 0, cck_highpwr = 0; + struct phy_cck_rx_status *pcck_buf; + u8 sq; + + /* Record it for next packet processing*/ + bcck_rate = (prframe->u.hdr.attrib.mcs_rate <= 3 ? 1 : 0); + if (bcck_rate) { + u8 report; + + /* CCK Driver info Structure is not the same as OFDM packet.*/ + pcck_buf = (struct phy_cck_rx_status *)pphy_stat; + /* (1)Hardware does not provide RSSI for CCK + * (2)PWDB, Average PWDB cacluated by hardware + * (for rate adaptive) + */ + if (!cck_highpwr) { + report = pcck_buf->cck_agc_rpt & 0xc0; + report >>= 6; + switch (report) { + /* Modify the RF RNA gain value to -40, -20, + * -2, 14 by Jenyu's suggestion + * Note: different RF with the different + * RNA gain. */ + case 0x3: + rx_pwr_all = -40 - (pcck_buf->cck_agc_rpt & + 0x3e); + break; + case 0x2: + rx_pwr_all = -20 - (pcck_buf->cck_agc_rpt & + 0x3e); + break; + case 0x1: + rx_pwr_all = -2 - (pcck_buf->cck_agc_rpt & + 0x3e); + break; + case 0x0: + rx_pwr_all = 14 - (pcck_buf->cck_agc_rpt & + 0x3e); + break; + } + } else { + report = ((u8)(le32_to_cpu(pphy_stat->phydw1) >> 8)) & + 0x60; + report >>= 5; + switch (report) { + case 0x3: + rx_pwr_all = -40 - ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -20 - ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -2 - ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 14 - ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + } + } + pwdb_all = query_rx_pwr_percentage(rx_pwr_all); + /* CCK gain is smaller than OFDM/MCS gain,*/ + /* so we add gain diff by experiences, the val is 6 */ + pwdb_all += 6; + if (pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same gain index with OFDM.*/ + if (pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if (pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if (pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if (pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + /* + * (3) Get Signal Quality (EVM) + */ + if (pwdb_all > 40) + sq = 100; + else { + sq = pcck_buf->sq_rpt; + if (pcck_buf->sq_rpt > 64) + sq = 0; + else if (pcck_buf->sq_rpt < 20) + sq = 100; + else + sq = ((64-sq) * 100) / 44; + } + prframe->u.hdr.attrib.signal_qual = sq; + prframe->u.hdr.attrib.rx_mimo_signal_qual[0] = sq; + prframe->u.hdr.attrib.rx_mimo_signal_qual[1] = -1; + } else { + /* (1)Get RSSI for HT rate */ + for (i = 0; i < ((padapter->registrypriv.rf_config) & + 0x0f); i++) { + rf_rx_num++; + rx_pwr[i] = ((pphy_head[PHY_STAT_GAIN_TRSW_SHT + i] + & 0x3F) * 2) - 110; + /* Translate DBM to percentage. */ + rssi = query_rx_pwr_percentage(rx_pwr[i]); + total_rssi += rssi; + } + /* (2)PWDB, Average PWDB cacluated by hardware (for + * rate adaptive) */ + rx_pwr_all = (((pphy_head[PHY_STAT_PWDB_ALL_SHT]) >> 1) & 0x7f) + - 106; + pwdb_all = query_rx_pwr_percentage(rx_pwr_all); + + { + /* (3)EVM of HT rate */ + if (prframe->u.hdr.attrib.htc && + prframe->u.hdr.attrib.mcs_rate >= 20 && + prframe->u.hdr.attrib.mcs_rate <= 27) { + /* both spatial stream make sense */ + max_spatial_stream = 2; + } else { + /* only spatial stream 1 makes sense */ + max_spatial_stream = 1; + } + for (i = 0; i < max_spatial_stream; i++) { + evm = evm_db2percentage((pphy_head + [PHY_STAT_RXEVM_SHT + i]));/*dbm*/ + prframe->u.hdr.attrib.signal_qual = + (u8)(evm & 0xff); + prframe->u.hdr.attrib.rx_mimo_signal_qual[i] = + (u8)(evm & 0xff); + } + } + } + /* UI BSS List signal strength(in percentage), make it good looking, + * from 0~100. It is assigned to the BSS List in + * GetValueFromBeaconOrProbeRsp(). */ + if (bcck_rate) + prframe->u.hdr.attrib.signal_strength = + (u8)r8712_signal_scale_mapping(pwdb_all); + else { + if (rf_rx_num != 0) + prframe->u.hdr.attrib.signal_strength = + (u8)(r8712_signal_scale_mapping(total_rssi /= + rf_rx_num)); + } +} + +static void process_link_qual(struct _adapter *padapter, + union recv_frame *prframe) +{ + u32 last_evm = 0, tmpVal; + struct rx_pkt_attrib *pattrib; + + if (prframe == NULL || padapter == NULL) + return; + pattrib = &prframe->u.hdr.attrib; + if (pattrib->signal_qual != 0) { + /* + * 1. Record the general EVM to the sliding window. + */ + if (padapter->recvpriv.signal_qual_data.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + padapter->recvpriv.signal_qual_data.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = padapter->recvpriv.signal_qual_data.elements + [padapter->recvpriv.signal_qual_data.index]; + padapter->recvpriv.signal_qual_data.total_val -= + last_evm; + } + padapter->recvpriv.signal_qual_data.total_val += + pattrib->signal_qual; + padapter->recvpriv.signal_qual_data.elements[padapter-> + recvpriv.signal_qual_data.index++] = + pattrib->signal_qual; + if (padapter->recvpriv.signal_qual_data.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + padapter->recvpriv.signal_qual_data.index = 0; + + /* <1> Showed on UI for user, in percentage. */ + tmpVal = padapter->recvpriv.signal_qual_data.total_val / + padapter->recvpriv.signal_qual_data.total_num; + padapter->recvpriv.signal = (u8)tmpVal; + } +} + +static void process_rssi(struct _adapter *padapter, union recv_frame *prframe) +{ + u32 last_rssi, tmp_val; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + + if (padapter->recvpriv.signal_strength_data.total_num++ >= + PHY_RSSI_SLID_WIN_MAX) { + padapter->recvpriv.signal_strength_data.total_num = + PHY_RSSI_SLID_WIN_MAX; + last_rssi = padapter->recvpriv.signal_strength_data.elements + [padapter->recvpriv.signal_strength_data.index]; + padapter->recvpriv.signal_strength_data.total_val -= last_rssi; + } + padapter->recvpriv.signal_strength_data.total_val += + pattrib->signal_strength; + padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv. + signal_strength_data.index++] = + pattrib->signal_strength; + if (padapter->recvpriv.signal_strength_data.index >= + PHY_RSSI_SLID_WIN_MAX) + padapter->recvpriv.signal_strength_data.index = 0; + tmp_val = padapter->recvpriv.signal_strength_data.total_val / + padapter->recvpriv.signal_strength_data.total_num; + padapter->recvpriv.rssi = (s8)translate2dbm(padapter, (u8)tmp_val); +} + +static void process_phy_info(struct _adapter *padapter, + union recv_frame *prframe) +{ + query_rx_phy_status(padapter, prframe); + process_rssi(padapter, prframe); + process_link_qual(padapter, prframe); +} + +int recv_func(struct _adapter *padapter, void *pcontext) +{ + struct rx_pkt_attrib *pattrib; + union recv_frame *prframe, *orig_prframe; + int retval = _SUCCESS; + struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + prframe = (union recv_frame *)pcontext; + orig_prframe = prframe; + pattrib = &prframe->u.hdr.attrib; + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + if (pattrib->crc_err == 1) + padapter->mppriv.rx_crcerrpktcount++; + else + padapter->mppriv.rx_pktcount++; + if (check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE) == false) { + /* free this recv_frame */ + r8712_free_recvframe(orig_prframe, pfree_recv_queue); + goto _exit_recv_func; + } + } + /* check the frame crtl field and decache */ + retval = r8712_validate_recv_frame(padapter, prframe); + if (retval != _SUCCESS) { + /* free this recv_frame */ + r8712_free_recvframe(orig_prframe, pfree_recv_queue); + goto _exit_recv_func; + } + process_phy_info(padapter, prframe); + prframe = r8712_decryptor(padapter, prframe); + if (prframe == NULL) { + retval = _FAIL; + goto _exit_recv_func; + } + prframe = r8712_recvframe_chk_defrag(padapter, prframe); + if (prframe == NULL) + goto _exit_recv_func; + prframe = r8712_portctrl(padapter, prframe); + if (prframe == NULL) { + retval = _FAIL; + goto _exit_recv_func; + } + retval = r8712_process_recv_indicatepkts(padapter, prframe); + if (retval != _SUCCESS) { + r8712_free_recvframe(orig_prframe, pfree_recv_queue); + goto _exit_recv_func; + } +_exit_recv_func: + return retval; +} + +static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb) +{ + u8 *pbuf, shift_sz = 0; + u8 frag, mf; + uint pkt_len; + u32 transfer_len; + struct recv_stat *prxstat; + u16 pkt_cnt, drvinfo_sz, pkt_offset, tmp_len, alloc_sz; + struct __queue *pfree_recv_queue; + _pkt *pkt_copy = NULL; + union recv_frame *precvframe = NULL; + struct recv_priv *precvpriv = &padapter->recvpriv; + + pfree_recv_queue = &(precvpriv->free_recv_queue); + pbuf = pskb->data; + prxstat = (struct recv_stat *)pbuf; + pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16)&0xff; + pkt_len = le32_to_cpu(prxstat->rxdw0)&0x00003fff; + transfer_len = pskb->len; + /* Test throughput with Netgear 3700 (No security) with Chariot 3T3R + * pairs. The packet count will be a big number so that the containing + * packet will effect the Rx reordering. */ + if (transfer_len < pkt_len) { + /* In this case, it means the MAX_RECVBUF_SZ is too small to + * get the data from 8712u. */ + return _FAIL; + } + do { + prxstat = (struct recv_stat *)pbuf; + pkt_len = le32_to_cpu(prxstat->rxdw0)&0x00003fff; + /* more fragment bit */ + mf = (le32_to_cpu(prxstat->rxdw1) >> 27) & 0x1; + /* ragmentation number */ + frag = (le32_to_cpu(prxstat->rxdw2) >> 12) & 0xf; + /* uint 2^3 = 8 bytes */ + drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16; + drvinfo_sz <<= 3; + if (pkt_len <= 0) + goto _exit_recvbuf2recvframe; + /* Qos data, wireless lan header length is 26 */ + if ((le32_to_cpu(prxstat->rxdw0) >> 23) & 0x01) + shift_sz = 2; + precvframe = r8712_alloc_recvframe(pfree_recv_queue); + if (precvframe == NULL) + goto _exit_recvbuf2recvframe; + INIT_LIST_HEAD(&precvframe->u.hdr.list); + precvframe->u.hdr.precvbuf = NULL; /*can't access the precvbuf*/ + precvframe->u.hdr.len = 0; + tmp_len = pkt_len + drvinfo_sz + RXDESC_SIZE; + pkt_offset = (u16)round_up(tmp_len, 128); + /* for first fragment packet, driver need allocate 1536 + + * drvinfo_sz + RXDESC_SIZE to defrag packet. */ + if ((mf == 1) && (frag == 0)) + alloc_sz = 1658;/*1658+6=1664, 1664 is 128 alignment.*/ + else + alloc_sz = tmp_len; + /* 2 is for IP header 4 bytes alignment in QoS packet case. + * 4 is for skb->data 4 bytes alignment. */ + alloc_sz += 6; + pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz); + if (pkt_copy) { + precvframe->u.hdr.pkt = pkt_copy; + skb_reserve(pkt_copy, 4 - ((addr_t)(pkt_copy->data) + % 4)); + skb_reserve(pkt_copy, shift_sz); + memcpy(pkt_copy->data, pbuf, tmp_len); + precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = + precvframe->u.hdr.rx_tail = pkt_copy->data; + precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz; + } else { + precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC); + if (!precvframe->u.hdr.pkt) + return _FAIL; + precvframe->u.hdr.rx_head = pbuf; + precvframe->u.hdr.rx_data = pbuf; + precvframe->u.hdr.rx_tail = pbuf; + precvframe->u.hdr.rx_end = pbuf + alloc_sz; + } + recvframe_put(precvframe, tmp_len); + recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); + /* because the endian issue, driver avoid reference to the + * rxstat after calling update_recvframe_attrib_from_recvstat(); + */ + update_recvframe_attrib_from_recvstat(&precvframe->u.hdr.attrib, + prxstat); + r8712_recv_entry(precvframe); + transfer_len -= pkt_offset; + pbuf += pkt_offset; + pkt_cnt--; + precvframe = NULL; + pkt_copy = NULL; + } while ((transfer_len > 0) && pkt_cnt > 0); +_exit_recvbuf2recvframe: + return _SUCCESS; +} + +static void recv_tasklet(void *priv) +{ + struct sk_buff *pskb; + struct _adapter *padapter = (struct _adapter *)priv; + struct recv_priv *precvpriv = &padapter->recvpriv; + + while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) { + recvbuf2recvframe(padapter, pskb); + skb_reset_tail_pointer(pskb); + pskb->len = 0; + if (!skb_cloned(pskb)) + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + else + consume_skb(pskb); + } +} diff --git a/kernel/drivers/staging/rtl8712/rtl8712_recv.h b/kernel/drivers/staging/rtl8712/rtl8712_recv.h new file mode 100644 index 000000000..fd9e3fc4c --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_recv.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL8712_RECV_H_ +#define _RTL8712_RECV_H_ + +#include "osdep_service.h" +#include "drv_types.h" + +/* Realtek's v2.6.6 reduced this to 4. However, under heavy network and CPU + * loads, even 8 receive buffers might not be enough; cutting it to 4 seemed + * unwise. + */ +#define NR_RECVBUFF (8) + +#define NR_PREALLOC_RECV_SKB (8) +#define RXDESC_SIZE 24 +#define RXDESC_OFFSET RXDESC_SIZE +#define RECV_BLK_SZ 512 +#define RECV_BLK_CNT 16 +#define RECV_BLK_TH RECV_BLK_CNT +#define MAX_RECVBUF_SZ 9100 +#define RECVBUFF_ALIGN_SZ 512 +#define RSVD_ROOM_SZ (0) +/*These definition is used for Rx packet reordering.*/ +#define SN_LESS(a, b) (((a-b) & 0x800) != 0) +#define SN_EQUAL(a, b) (a == b) +#define REORDER_WAIT_TIME 30 /* (ms)*/ + +struct recv_stat { + unsigned int rxdw0; + unsigned int rxdw1; + unsigned int rxdw2; + unsigned int rxdw3; + unsigned int rxdw4; + unsigned int rxdw5; +}; + +struct phy_cck_rx_status { + /* For CCK rate descriptor. This is a unsigned 8:1 variable. + * LSB bit present 0.5. And MSB 7 bts present a signed value. + * Range from -64~+63.5. */ + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +struct phy_stat { + unsigned int phydw0; + unsigned int phydw1; + unsigned int phydw2; + unsigned int phydw3; + unsigned int phydw4; + unsigned int phydw5; + unsigned int phydw6; + unsigned int phydw7; +}; +#define PHY_STAT_GAIN_TRSW_SHT 0 +#define PHY_STAT_PWDB_ALL_SHT 4 +#define PHY_STAT_CFOSHO_SHT 5 +#define PHY_STAT_CCK_AGC_RPT_SHT 5 +#define PHY_STAT_CFOTAIL_SHT 9 +#define PHY_STAT_RXEVM_SHT 13 +#define PHY_STAT_RXSNR_SHT 15 +#define PHY_STAT_PDSNR_SHT 19 +#define PHY_STAT_CSI_CURRENT_SHT 21 +#define PHY_STAT_CSI_TARGET_SHT 23 +#define PHY_STAT_SIGEVM_SHT 25 +#define PHY_STAT_MAX_EX_PWR_SHT 26 + +union recvstat { + struct recv_stat recv_stat; + unsigned int value[RXDESC_SIZE>>2]; +}; + + +struct recv_buf { + struct list_head list; + spinlock_t recvbuf_lock; + u32 ref_cnt; + struct _adapter *adapter; + struct urb *purb; + _pkt *pskb; + u8 reuse; + u8 irp_pending; + u32 transfer_len; + uint len; + u8 *phead; + u8 *pdata; + u8 *ptail; + u8 *pend; + u8 *pbuf; + u8 *pallocated_buf; +}; + +/* + head -----> + data -----> + payload + tail -----> + end -----> + len = (unsigned int )(tail - data); +*/ +struct recv_frame_hdr { + struct list_head list; + _pkt *pkt; + _pkt *pkt_newalloc; + struct _adapter *adapter; + u8 fragcnt; + struct rx_pkt_attrib attrib; + uint len; + u8 *rx_head; + u8 *rx_data; + u8 *rx_tail; + u8 *rx_end; + void *precvbuf; + struct sta_info *psta; + /*for A-MPDU Rx reordering buffer control*/ + struct recv_reorder_ctrl *preorder_ctrl; +}; + +union recv_frame { + union { + struct list_head list; + struct recv_frame_hdr hdr; + } u; +}; + +int r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf); +void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf); +s32 r8712_signal_scale_mapping(s32 cur_sig); +void r8712_reordering_ctrl_timeout_handler(void *pcontext); + +#endif + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_regdef.h new file mode 100644 index 000000000..e7bca55b5 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_regdef.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_REGDEF_H__ +#define __RTL8712_REGDEF_H__ + +#include "rtl8712_syscfg_regdef.h" +#include "rtl8712_cmdctrl_regdef.h" +#include "rtl8712_macsetting_regdef.h" +#include "rtl8712_timectrl_regdef.h" +#include "rtl8712_fifoctrl_regdef.h" +#include "rtl8712_ratectrl_regdef.h" +#include "rtl8712_edcasetting_regdef.h" +#include "rtl8712_wmac_regdef.h" +#include "rtl8712_powersave_regdef.h" +#include "rtl8712_gp_regdef.h" +#include "rtl8712_debugctrl_regdef.h" + +#define HIMR (RTL8712_INTERRUPT_ + 0x08) + +#endif /* __RTL8712_REGDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_security_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_security_bitdef.h new file mode 100644 index 000000000..05dafa0c3 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_security_bitdef.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_SECURITY_BITDEF_H__ +#define __RTL8712_SECURITY_BITDEF_H__ + +/*CAMCMD*/ +#define _SECCAM_POLLING BIT(31) +#define _SECCAM_CLR BIT(30) +#define _SECCAM_WE BIT(16) +#define _SECCAM_ADR_MSK 0x000000FF +#define _SECCAM_ADR_SHT 0 + +/*CAMDBG*/ +#define _SECCAM_INFO BIT(31) +#define _SEC_KEYFOUND BIT(30) +#define _SEC_CONFIG_MSK 0x3F000000 +#define _SEC_CONFIG_SHT 24 +#define _SEC_KEYCONTENT_MSK 0x00FFFFFF +#define _SEC_KEYCONTENT_SHT 0 + +/*SECCFG*/ +#define _NOSKMC BIT(5) +#define _SKBYA2 BIT(4) +#define _RXDEC BIT(3) +#define _TXENC BIT(2) +#define _RXUSEDK BIT(1) +#define _TXUSEDK BIT(0) + + +#endif /*__RTL8712_SECURITY_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_spec.h b/kernel/drivers/staging/rtl8712/rtl8712_spec.h new file mode 100644 index 000000000..af11b44b1 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_spec.h @@ -0,0 +1,135 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_SPEC_H__ +#define __RTL8712_SPEC_H__ + +#define RTL8712_IOBASE_TXPKT 0x10200000 /*IOBASE_TXPKT*/ +#define RTL8712_IOBASE_RXPKT 0x10210000 /*IOBASE_RXPKT*/ +#define RTL8712_IOBASE_RXCMD 0x10220000 /*IOBASE_RXCMD*/ +#define RTL8712_IOBASE_TXSTATUS 0x10230000 /*IOBASE_TXSTATUS*/ +#define RTL8712_IOBASE_RXSTATUS 0x10240000 /*IOBASE_RXSTATUS*/ +#define RTL8712_IOBASE_IOREG 0x10250000 /*IOBASE_IOREG ADDR*/ +#define RTL8712_IOBASE_SCHEDULER 0x10260000 /*IOBASE_SCHEDULE*/ + +#define RTL8712_IOBASE_TRXDMA 0x10270000 /*IOBASE_TRXDMA*/ +#define RTL8712_IOBASE_TXLLT 0x10280000 /*IOBASE_TXLLT*/ +#define RTL8712_IOBASE_WMAC 0x10290000 /*IOBASE_WMAC*/ +#define RTL8712_IOBASE_FW2HW 0x102A0000 /*IOBASE_FW2HW*/ +#define RTL8712_IOBASE_ACCESS_PHYREG 0x102B0000 /*IOBASE_ACCESS_PHYREG*/ + +#define RTL8712_IOBASE_FF 0x10300000 /*IOBASE_FIFO 0x1031000~0x103AFFFF*/ + + +/*IOREG Offset for 8712*/ +#define RTL8712_SYSCFG_ RTL8712_IOBASE_IOREG +#define RTL8712_CMDCTRL_ (RTL8712_IOBASE_IOREG + 0x40) +#define RTL8712_MACIDSETTING_ (RTL8712_IOBASE_IOREG + 0x50) +#define RTL8712_TIMECTRL_ (RTL8712_IOBASE_IOREG + 0x80) +#define RTL8712_FIFOCTRL_ (RTL8712_IOBASE_IOREG + 0xA0) +#define RTL8712_RATECTRL_ (RTL8712_IOBASE_IOREG + 0x160) +#define RTL8712_EDCASETTING_ (RTL8712_IOBASE_IOREG + 0x1D0) +#define RTL8712_WMAC_ (RTL8712_IOBASE_IOREG + 0x200) +#define RTL8712_SECURITY_ (RTL8712_IOBASE_IOREG + 0x240) +#define RTL8712_POWERSAVE_ (RTL8712_IOBASE_IOREG + 0x260) +#define RTL8712_GP_ (RTL8712_IOBASE_IOREG + 0x2E0) +#define RTL8712_INTERRUPT_ (RTL8712_IOBASE_IOREG + 0x300) +#define RTL8712_DEBUGCTRL_ (RTL8712_IOBASE_IOREG + 0x310) +#define RTL8712_OFFLOAD_ (RTL8712_IOBASE_IOREG + 0x2D0) + + +/*FIFO for 8712*/ +#define RTL8712_DMA_BCNQ (RTL8712_IOBASE_FF + 0x10000) +#define RTL8712_DMA_MGTQ (RTL8712_IOBASE_FF + 0x20000) +#define RTL8712_DMA_BMCQ (RTL8712_IOBASE_FF + 0x30000) +#define RTL8712_DMA_VOQ (RTL8712_IOBASE_FF + 0x40000) +#define RTL8712_DMA_VIQ (RTL8712_IOBASE_FF + 0x50000) +#define RTL8712_DMA_BEQ (RTL8712_IOBASE_FF + 0x60000) +#define RTL8712_DMA_BKQ (RTL8712_IOBASE_FF + 0x70000) +#define RTL8712_DMA_RX0FF (RTL8712_IOBASE_FF + 0x80000) +#define RTL8712_DMA_H2CCMD (RTL8712_IOBASE_FF + 0x90000) +#define RTL8712_DMA_C2HCMD (RTL8712_IOBASE_FF + 0xA0000) + + +/*------------------------------*/ + +/*BIT 16 15*/ +#define DID_SDIO_LOCAL 0 /* 0 0*/ +#define DID_WLAN_IOREG 1 /* 0 1*/ +#define DID_WLAN_FIFO 3 /* 1 1*/ +#define DID_UNDEFINE (-1) + +#define CMD_ADDR_MAPPING_SHIFT 2 /*SDIO CMD ADDR MAPPING, + *shift 2 bit for match + * offset[14:2]*/ + +/*Offset for SDIO LOCAL*/ +#define OFFSET_SDIO_LOCAL 0x0FFF + +/*Offset for WLAN IOREG*/ +#define OFFSET_WLAN_IOREG 0x0FFF + +/*Offset for WLAN FIFO*/ +#define OFFSET_TX_BCNQ 0x0300 +#define OFFSET_TX_HIQ 0x0310 +#define OFFSET_TX_CMDQ 0x0320 +#define OFFSET_TX_MGTQ 0x0330 +#define OFFSET_TX_HCCAQ 0x0340 +#define OFFSET_TX_VOQ 0x0350 +#define OFFSET_TX_VIQ 0x0360 +#define OFFSET_TX_BEQ 0x0370 +#define OFFSET_TX_BKQ 0x0380 +#define OFFSET_RX_RX0FFQ 0x0390 +#define OFFSET_RX_C2HFFQ 0x03A0 + +#define BK_QID_01 1 +#define BK_QID_02 2 +#define BE_QID_01 0 +#define BE_QID_02 3 +#define VI_QID_01 4 +#define VI_QID_02 5 +#define VO_QID_01 6 +#define VO_QID_02 7 +#define HCCA_QID_01 8 +#define HCCA_QID_02 9 +#define HCCA_QID_03 10 +#define HCCA_QID_04 11 +#define HCCA_QID_05 12 +#define HCCA_QID_06 13 +#define HCCA_QID_07 14 +#define HCCA_QID_08 15 +#define HI_QID 17 +#define CMD_QID 19 +#define MGT_QID 18 +#define BCN_QID 16 + +#include "rtl8712_regdef.h" + +#include "rtl8712_bitdef.h" + +#include "basic_types.h" + +#endif /* __RTL8712_SPEC_H__ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h new file mode 100644 index 000000000..eed09c872 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h @@ -0,0 +1,170 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_SYSCFG_BITDEF_H__ +#define __RTL8712_SYSCFG_BITDEF_H__ + +/*SYS_PWR_CTRL*/ +/*SRCTRL0*/ +/*SRCTRL1*/ +/*SYS_CLKR*/ + +/*SYS_IOS_CTRL*/ +#define iso_LDR2RP_SHT 8 /* EE Loader to Retention Path*/ +#define iso_LDR2RP BIT(iso_LDR2RP_SHT) /* 1:isolation, 0:attach*/ + +/*SYS_CTRL*/ +#define FEN_DIO_SDIO_SHT 0 +#define FEN_DIO_SDIO BIT(FEN_DIO_SDIO_SHT) +#define FEN_SDIO_SHT 1 +#define FEN_SDIO BIT(FEN_SDIO_SHT) +#define FEN_USBA_SHT 2 +#define FEN_USBA BIT(FEN_USBA_SHT) +#define FEN_UPLL_SHT 3 +#define FEN_UPLL BIT(FEN_UPLL_SHT) +#define FEN_USBD_SHT 4 +#define FEN_USBD BIT(FEN_USBD_SHT) +#define FEN_DIO_PCIE_SHT 5 +#define FEN_DIO_PCIE BIT(FEN_DIO_PCIE_SHT) +#define FEN_PCIEA_SHT 6 +#define FEN_PCIEA BIT(FEN_PCIEA_SHT) +#define FEN_PPLL_SHT 7 +#define FEN_PPLL BIT(FEN_PPLL_SHT) +#define FEN_PCIED_SHT 8 +#define FEN_PCIED BIT(FEN_PCIED_SHT) +#define FEN_CPUEN_SHT 10 +#define FEN_CPUEN BIT(FEN_CPUEN_SHT) +#define FEN_DCORE_SHT 11 +#define FEN_DCORE BIT(FEN_DCORE_SHT) +#define FEN_ELDR_SHT 12 +#define FEN_ELDR BIT(FEN_ELDR_SHT) +#define PWC_DV2LDR_SHT 13 +#define PWC_DV2LDR BIT(PWC_DV2LDR_SHT) /* Loader Power Enable*/ + +/*=== SYS_CLKR ===*/ +#define SYS_CLKSEL_SHT 0 +#define SYS_CLKSEL BIT(SYS_CLKSEL_SHT) /* System Clock 80MHz*/ +#define PS_CLKSEL_SHT 1 +#define PS_CLKSEL BIT(PS_CLKSEL_SHT) /*System power save + * clock select.*/ +#define CPU_CLKSEL_SHT 2 +#define CPU_CLKSEL BIT(CPU_CLKSEL_SHT) /* System Clock select, + * 1: AFE source, + * 0: System clock(L-Bus)*/ +#define INT32K_EN_SHT 3 +#define INT32K_EN BIT(INT32K_EN_SHT) +#define MACSLP_SHT 4 +#define MACSLP BIT(MACSLP_SHT) +#define MAC_CLK_EN_SHT 11 +#define MAC_CLK_EN BIT(MAC_CLK_EN_SHT) /* MAC Clock Enable.*/ +#define SYS_CLK_EN_SHT 12 +#define SYS_CLK_EN BIT(SYS_CLK_EN_SHT) +#define RING_CLK_EN_SHT 13 +#define RING_CLK_EN BIT(RING_CLK_EN_SHT) +#define SWHW_SEL_SHT 14 +#define SWHW_SEL BIT(SWHW_SEL_SHT) /* Load done, + * control path switch.*/ +#define FWHW_SEL_SHT 15 +#define FWHW_SEL BIT(FWHW_SEL_SHT) /* Sleep exit, + * control path switch.*/ + +/*9346CR*/ +#define _VPDIDX_MSK 0xFF00 +#define _VPDIDX_SHT 8 +#define _EEM_MSK 0x00C0 +#define _EEM_SHT 6 +#define _EEM0 BIT(6) +#define _EEM1 BIT(7) +#define _EEPROM_EN BIT(5) +#define _9356SEL BIT(4) +#define _EECS BIT(3) +#define _EESK BIT(2) +#define _EEDI BIT(1) +#define _EEDO BIT(0) + +/*AFE_MISC*/ +#define AFE_MISC_USB_MBEN_SHT 7 +#define AFE_MISC_USB_MBEN BIT(AFE_MISC_USB_MBEN_SHT) +#define AFE_MISC_USB_BGEN_SHT 6 +#define AFE_MISC_USB_BGEN BIT(AFE_MISC_USB_BGEN_SHT) +#define AFE_MISC_LD12_VDAJ_SHT 4 +#define AFE_MISC_LD12_VDAJ_MSK 0X0030 +#define AFE_MISC_LD12_VDAJ BIT(AFE_MISC_LD12_VDAJ_SHT) +#define AFE_MISC_I32_EN_SHT 3 +#define AFE_MISC_I32_EN BIT(AFE_MISC_I32_EN_SHT) +#define AFE_MISC_E32_EN_SHT 2 +#define AFE_MISC_E32_EN BIT(AFE_MISC_E32_EN_SHT) +#define AFE_MISC_MBEN_SHT 1 +#define AFE_MISC_MBEN BIT(AFE_MISC_MBEN_SHT)/* Enable AFE Macro + * Block's Mbias.*/ +#define AFE_MISC_BGEN_SHT 0 +#define AFE_MISC_BGEN BIT(AFE_MISC_BGEN_SHT)/* Enable AFE Macro + * Block's Bandgap.*/ + + +/*--------------------------------------------------------------------------*/ +/* SPS1_CTRL bits (Offset 0x18-1E, 56bits)*/ +/*--------------------------------------------------------------------------*/ +#define SPS1_SWEN BIT(1) /* Enable vsps18 SW Macro Block.*/ +#define SPS1_LDEN BIT(0) /* Enable VSPS12 LDO Macro block.*/ + + +/*----------------------------------------------------------------------------*/ +/* LDOA15_CTRL bits (Offset 0x20, 8bits)*/ +/*----------------------------------------------------------------------------*/ +#define LDA15_EN BIT(0) /* Enable LDOA15 Macro Block*/ + + +/*----------------------------------------------------------------------------*/ +/* 8192S LDOV12D_CTRL bit (Offset 0x21, 8bits)*/ +/*----------------------------------------------------------------------------*/ +#define LDV12_EN BIT(0) /* Enable LDOVD12 Macro Block*/ +#define LDV12_SDBY BIT(1) /* LDOVD12 standby mode*/ + +/*CLK_PS_CTRL*/ +#define _CLK_GATE_EN BIT(0) + + +/* EFUSE_CTRL*/ +#define EF_FLAG BIT(31) /* Access Flag, Write:1; + * Read:0*/ +#define EF_PGPD 0x70000000 /* E-fuse Program time*/ +#define EF_RDT 0x0F000000 /* E-fuse read time: in the + * unit of cycle time*/ +#define EF_PDN_EN BIT(19) /* EFuse Power down enable*/ +#define ALD_EN BIT(18) /* Autoload Enable*/ +#define EF_ADDR 0x0003FF00 /* Access Address*/ +#define EF_DATA 0x000000FF /* Access Data*/ + +/* EFUSE_TEST*/ +#define LDOE25_EN BIT(31) /* Enable LDOE25 Macro Block*/ + +/* EFUSE_CLK_CTRL*/ +#define EFUSE_CLK_EN BIT(1) /* E-Fuse Clock Enable*/ +#define EFUSE_CLK_SEL BIT(0) /* E-Fuse Clock Select, + * 0:500K, 1:40M*/ + +#endif /*__RTL8712_SYSCFG_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h new file mode 100644 index 000000000..767dfdf8d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_SYSCFG_REGDEF_H__ +#define __RTL8712_SYSCFG_REGDEF_H__ + + +#define SYS_ISO_CTRL (RTL8712_SYSCFG_ + 0x0000) +#define SYS_FUNC_EN (RTL8712_SYSCFG_ + 0x0002) +#define PMC_FSM (RTL8712_SYSCFG_ + 0x0004) +#define SYS_CLKR (RTL8712_SYSCFG_ + 0x0008) +#define EE_9346CR (RTL8712_SYSCFG_ + 0x000A) +#define EE_VPD (RTL8712_SYSCFG_ + 0x000C) +#define AFE_MISC (RTL8712_SYSCFG_ + 0x0010) +#define SPS0_CTRL (RTL8712_SYSCFG_ + 0x0011) +#define SPS1_CTRL (RTL8712_SYSCFG_ + 0x0018) +#define RF_CTRL (RTL8712_SYSCFG_ + 0x001F) +#define LDOA15_CTRL (RTL8712_SYSCFG_ + 0x0020) +#define LDOV12D_CTRL (RTL8712_SYSCFG_ + 0x0021) +#define LDOHCI12_CTRL (RTL8712_SYSCFG_ + 0x0022) +#define LDO_USB_CTRL (RTL8712_SYSCFG_ + 0x0023) +#define LPLDO_CTRL (RTL8712_SYSCFG_ + 0x0024) +#define AFE_XTAL_CTRL (RTL8712_SYSCFG_ + 0x0026) +#define AFE_PLL_CTRL (RTL8712_SYSCFG_ + 0x0028) +#define EFUSE_CTRL (RTL8712_SYSCFG_ + 0x0030) +#define EFUSE_TEST (RTL8712_SYSCFG_ + 0x0034) +#define PWR_DATA (RTL8712_SYSCFG_ + 0x0038) +#define DPS_TIMER (RTL8712_SYSCFG_ + 0x003C) +#define RCLK_MON (RTL8712_SYSCFG_ + 0x003E) +#define EFUSE_CLK_CTRL (RTL8712_SYSCFG_ + 0x02F8) + + +#endif /*__RTL8712_SYSCFG_REGDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h new file mode 100644 index 000000000..724421582 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_TIMECTRL_BITDEF_H__ +#define __RTL8712_TIMECTRL_BITDEF_H__ + +/*TSFTR*/ +/*SLOT*/ +/*USTIME*/ + +/*TUBASE*/ +#define _TUBASE_MSK 0x07FF + +/*SIFS_CCK*/ +#define _SIFS_CCK_TRX_MSK 0xFF00 +#define _SIFS_CCK_TRX_SHT 0x8 +#define _SIFS_CCK_CTX_MSK 0x00FF +#define _SIFS_CCK_CTX_SHT 0 + +/*SIFS_OFDM*/ +#define _SIFS_OFDM_TRX_MSK 0xFF00 +#define _SIFS_OFDM_TRX_SHT 0x8 +#define _SIFS_OFDM_CTX_MSK 0x00FF +#define _SIFS_OFDM_CTX_SHT 0 + +/*PIFS*/ +/*ACKTO*/ +/*EIFS*/ +/*BCNITV*/ +/*ATIMWND*/ + +/*DRVERLYINT*/ +#define _ENSWBCN BIT(15) +#define _DRVERLY_TU_MSK 0x0FF0 +#define _DRVERLY_TU_SHT 4 +#define _DRVERLY_US_MSK 0x000F +#define _DRVERLY_US_SHT 0 + +/*BCNDMATIM*/ +#define _BCNDMATIM_MSK 0x03FF + +/*BCNERRTH*/ +/*MLT*/ + + +#endif /* __RTL8712_TIMECTRL_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h new file mode 100644 index 000000000..106916c7e --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL8712_TIMECTRL_REGDEF_H__ +#define __RTL8712_TIMECTRL_REGDEF_H__ + +#define TSFTR (RTL8712_TIMECTRL_ + 0x00) +#define USTIME (RTL8712_TIMECTRL_ + 0x08) +#define SLOT (RTL8712_TIMECTRL_ + 0x09) +#define TUBASE (RTL8712_TIMECTRL_ + 0x0A) +#define SIFS_CCK (RTL8712_TIMECTRL_ + 0x0C) +#define SIFS_OFDM (RTL8712_TIMECTRL_ + 0x0E) +#define PIFS (RTL8712_TIMECTRL_ + 0x10) +#define ACKTO (RTL8712_TIMECTRL_ + 0x11) +#define EIFS (RTL8712_TIMECTRL_ + 0x12) +#define BCNITV (RTL8712_TIMECTRL_ + 0x14) +#define ATIMWND (RTL8712_TIMECTRL_ + 0x16) +#define DRVERLYINT (RTL8712_TIMECTRL_ + 0x18) +#define BCNDMATIM (RTL8712_TIMECTRL_ + 0x1A) +#define BCNERRTH (RTL8712_TIMECTRL_ + 0x1C) +#define MLT (RTL8712_TIMECTRL_ + 0x1D) + +#endif /* __RTL8712_TIMECTRL_REGDEF_H__ */ diff --git a/kernel/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h b/kernel/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h new file mode 100644 index 000000000..61a3603aa --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_WMAC_BITDEF_H__ +#define __RTL8712_WMAC_BITDEF_H__ + +/*NAVCTRL*/ +#define _NAV_UPPER_EN BIT(18) +#define _NAV_MTO_EN BIT(17) +#define _NAV_UPPER BIT(16) +#define _NAV_MTO_MSK 0xFF00 +#define _NAV_MTO_SHT 8 +#define _RTSRST_MSK 0x00FF +#define _RTSRST_SHT 0 + +/*BWOPMODE*/ +#define _20MHZBW BIT(2) + +/*BACAMCMD*/ +#define _BACAM_POLL BIT(31) +#define _BACAM_RST BIT(17) +#define _BACAM_RW BIT(16) +#define _BACAM_ADDR_MSK 0x0000007F +#define _BACAM_ADDR_SHT 0 + +/*LBDLY*/ +#define _LBDLY_MSK 0x1F + +/*FWDLY*/ +#define _FWDLY_MSK 0x0F + +/*RXERR_RPT*/ +#define _RXERR_RPT_SEL_MSK 0xF0000000 +#define _RXERR_RPT_SEL_SHT 28 +#define _RPT_CNT_MSK 0x000FFFFF +#define _RPT_CNT_SHT 0 + + +#endif /*__RTL8712_WMAC_BITDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_wmac_regdef.h b/kernel/drivers/staging/rtl8712/rtl8712_wmac_regdef.h new file mode 100644 index 000000000..d9f8347ab --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_wmac_regdef.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_WMAC_REGDEF_H__ +#define __RTL8712_WMAC_REGDEF_H__ + +#define NAVCTRL (RTL8712_WMAC_ + 0x00) +#define BWOPMODE (RTL8712_WMAC_ + 0x03) +#define BACAMCMD (RTL8712_WMAC_ + 0x04) +#define BACAMCONTENT (RTL8712_WMAC_ + 0x08) +#define LBDLY (RTL8712_WMAC_ + 0x10) +#define FWDLY (RTL8712_WMAC_ + 0x11) +#define HWPC_RX_CTRL (RTL8712_WMAC_ + 0x18) +#define MQ (RTL8712_WMAC_ + 0x20) +#define MA (RTL8712_WMAC_ + 0x22) +#define MS (RTL8712_WMAC_ + 0x24) +#define CLM_RESULT (RTL8712_WMAC_ + 0x27) +#define NHM_RPI_CNT (RTL8712_WMAC_ + 0x28) +#define RXERR_RPT (RTL8712_WMAC_ + 0x30) +#define NAV_PROT_LEN (RTL8712_WMAC_ + 0x34) +#define CFEND_TH (RTL8712_WMAC_ + 0x36) +#define AMPDU_MIN_SPACE (RTL8712_WMAC_ + 0x37) +#define TXOP_STALL_CTRL (RTL8712_WMAC_ + 0x38) + + +#endif /*__RTL8712_WMAC_REGDEF_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl8712_xmit.c b/kernel/drivers/staging/rtl8712/rtl8712_xmit.c new file mode 100644 index 000000000..a3093ac12 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_xmit.c @@ -0,0 +1,764 @@ +/****************************************************************************** + * rtl8712_xmit.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL8712_XMIT_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "wifi.h" +#include "osdep_intf.h" +#include "usb_ops.h" + +static void dump_xframe(struct _adapter *padapter, + struct xmit_frame *pxmitframe); +static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz); + +sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag) +{ + phw_txqueue->ac_tag = ac_tag; + switch (ac_tag) { + case BE_QUEUE_INX: + phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ; + break; + case BK_QUEUE_INX: + phw_txqueue->ff_hwaddr = RTL8712_DMA_BKQ; + break; + case VI_QUEUE_INX: + phw_txqueue->ff_hwaddr = RTL8712_DMA_VIQ; + break; + case VO_QUEUE_INX: + phw_txqueue->ff_hwaddr = RTL8712_DMA_VOQ; + break; + case BMC_QUEUE_INX: + phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ; + break; + } + return _SUCCESS; +} + +int r8712_txframes_sta_ac_pending(struct _adapter *padapter, + struct pkt_attrib *pattrib) +{ + struct sta_info *psta; + struct tx_servq *ptxservq; + int priority = pattrib->priority; + + psta = pattrib->psta; + switch (priority) { + case 1: + case 2: + ptxservq = &(psta->sta_xmitpriv.bk_q); + break; + case 4: + case 5: + ptxservq = &(psta->sta_xmitpriv.vi_q); + break; + case 6: + case 7: + ptxservq = &(psta->sta_xmitpriv.vo_q); + break; + case 0: + case 3: + default: + ptxservq = &(psta->sta_xmitpriv.be_q); + break; + } + return ptxservq->qcnt; +} + +static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe) +{ + u32 addr = 0; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct _adapter *padapter = pxmitframe->padapter; + struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; + + if (pxmitframe->frame_tag == TXAGG_FRAMETAG) + addr = RTL8712_DMA_H2CCMD; + else if (pxmitframe->frame_tag == MGNT_FRAMETAG) + addr = RTL8712_DMA_MGTQ; + else if (pdvobj->nr_endpoint == 6) { + switch (pattrib->priority) { + case 0: + case 3: + addr = RTL8712_DMA_BEQ; + break; + case 1: + case 2: + addr = RTL8712_DMA_BKQ; + break; + case 4: + case 5: + addr = RTL8712_DMA_VIQ; + break; + case 6: + case 7: + addr = RTL8712_DMA_VOQ; + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + addr = RTL8712_DMA_H2CCMD; + break; + default: + addr = RTL8712_DMA_BEQ; + break; + } + } else if (pdvobj->nr_endpoint == 4) { + switch (pattrib->qsel) { + case 0: + case 3: + case 1: + case 2: + addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/ + break; + case 4: + case 5: + case 6: + case 7: + addr = RTL8712_DMA_VOQ;/*RTL8712_EP_HI;*/ + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + addr = RTL8712_DMA_H2CCMD; + break; + default: + addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/ + break; + } + } + return addr; +} + +static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, + struct hw_xmit *phwxmit, + struct tx_servq *ptxservq, + struct __queue *pframe_queue) +{ + struct list_head *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + + xmitframe_phead = &pframe_queue->queue; + xmitframe_plist = xmitframe_phead->next; + if ((end_of_queue_search(xmitframe_phead, xmitframe_plist)) == false) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, + struct xmit_frame, list); + list_del_init(&pxmitframe->list); + ptxservq->qcnt--; + phwxmit->txcmdcnt++; + } + return pxmitframe; +} + +static struct xmit_frame *dequeue_xframe_ex(struct xmit_priv *pxmitpriv, + struct hw_xmit *phwxmit_i, sint entry) +{ + unsigned long irqL0; + struct list_head *sta_plist, *sta_phead; + struct hw_xmit *phwxmit; + struct tx_servq *ptxservq = NULL; + struct __queue *pframe_queue = NULL; + struct xmit_frame *pxmitframe = NULL; + int i, inx[4]; + int j, tmp, acirp_cnt[4]; + + /*entry indx: 0->vo, 1->vi, 2->be, 3->bk.*/ + inx[0] = 0; acirp_cnt[0] = pxmitpriv->voq_cnt; + inx[1] = 1; acirp_cnt[1] = pxmitpriv->viq_cnt; + inx[2] = 2; acirp_cnt[2] = pxmitpriv->beq_cnt; + inx[3] = 3; acirp_cnt[3] = pxmitpriv->bkq_cnt; + for (i = 0; i < 4; i++) { + for (j = i + 1; j < 4; j++) { + if (acirp_cnt[j] < acirp_cnt[i]) { + tmp = acirp_cnt[i]; + acirp_cnt[i] = acirp_cnt[j]; + acirp_cnt[j] = tmp; + tmp = inx[i]; + inx[i] = inx[j]; + inx[j] = tmp; + } + } + } + spin_lock_irqsave(&pxmitpriv->lock, irqL0); + for (i = 0; i < entry; i++) { + phwxmit = phwxmit_i + inx[i]; + sta_phead = &phwxmit->sta_queue->queue; + sta_plist = sta_phead->next; + while ((end_of_queue_search(sta_phead, sta_plist)) == false) { + ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, + tx_pending); + pframe_queue = &ptxservq->sta_pending; + pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, + ptxservq, pframe_queue); + if (pxmitframe) { + phwxmit->accnt--; + goto exit_dequeue_xframe_ex; + } + sta_plist = sta_plist->next; + /*Remove sta node when there are no pending packets.*/ + if (list_empty(&pframe_queue->queue)) { + /* must be done after sta_plist->next + * and before break + */ + list_del_init(&ptxservq->tx_pending); + } + } + } +exit_dequeue_xframe_ex: + spin_unlock_irqrestore(&pxmitpriv->lock, irqL0); + return pxmitframe; +} + +void r8712_do_queue_select(struct _adapter *padapter, + struct pkt_attrib *pattrib) +{ + unsigned int qsel = 0; + struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; + + if (pdvobj->nr_endpoint == 6) + qsel = (unsigned int) pattrib->priority; + else if (pdvobj->nr_endpoint == 4) { + qsel = (unsigned int) pattrib->priority; + if (qsel == 0 || qsel == 3) + qsel = 3; + else if (qsel == 1 || qsel == 2) + qsel = 1; + else if (qsel == 4 || qsel == 5) + qsel = 5; + else if (qsel == 6 || qsel == 7) + qsel = 7; + else + qsel = 3; + } + pattrib->qsel = qsel; +} + +#ifdef CONFIG_R8712_TX_AGGR +u8 r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf) +{ + struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; + + /* Fill up TxCmd Descriptor according as USB FW Tx Aaggregation info.*/ + /* dw0 */ + ptx_desc->txdw0 = cpu_to_le32(CMD_HDR_SZ&0xffff); + ptx_desc->txdw0 |= + cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); + ptx_desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); + + /* dw1 */ + ptx_desc->txdw1 |= cpu_to_le32((0x13<<QSEL_SHT)&0x00001f00); + + return _SUCCESS; +} + +u8 r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf) +{ + struct xmit_frame *pxmitframe = (struct xmit_frame *) + pxmitbuf->priv_data; + struct _adapter *padapter = pxmitframe->padapter; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) + (pxmitbuf->pbuf + TXDESC_SIZE); + + /* Fill up Cmd Header for USB FW Tx Aggregation.*/ + /* dw0 */ + pcmd_hdr->cmd_dw0 = cpu_to_le32((GEN_CMD_CODE(_AMSDU_TO_AMPDU) << 16) | + (pcmdpriv->cmd_seq << 24)); + pcmdpriv->cmd_seq++; + + return _SUCCESS; +} + +u8 r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + struct _adapter *padapter = pxmitframe->padapter; + struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; + int last_txcmdsz = 0; + int padding_sz = 0; + + /* 802.3->802.11 convertor */ + r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); + /* free skb struct */ + r8712_xmit_complete(padapter, pxmitframe); + if (pxmitframe->attrib.ether_type != 0x0806) { + if ((pxmitframe->attrib.ether_type != 0x888e) && + (pxmitframe->attrib.dhcp_pkt != 1)) { + r8712_issue_addbareq_cmd(padapter, + pxmitframe->attrib.priority); + } + } + pxmitframe->last[0] = 1; + update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr), + pxmitframe->attrib.last_txcmdsz); + /*padding zero */ + last_txcmdsz = pxmitframe->attrib.last_txcmdsz; + padding_sz = (8 - (last_txcmdsz % 8)); + if ((last_txcmdsz % 8) != 0) { + int i; + + for (i = 0; i < padding_sz; i++) + *(pxmitframe->buf_addr+TXDESC_SIZE+last_txcmdsz+i) = 0; + } + /* Add the new mpdu's length */ + ptx_desc->txdw0 = cpu_to_le32((ptx_desc->txdw0&0xffff0000) | + ((ptx_desc->txdw0&0x0000ffff)+ + ((TXDESC_SIZE+last_txcmdsz+padding_sz)&0x0000ffff))); + + return _SUCCESS; +} + + +u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + /* linux complete context doesnt need to protect */ + pxmitframe->pxmitbuf = pxmitbuf; + pxmitbuf->priv_data = pxmitframe; + pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; + /* buffer addr assoc */ + pxmitframe->buf_addr = pxmitbuf->pbuf+TXDESC_SIZE+CMD_HDR_SZ; + /*RTL8712_DMA_H2CCMD */ + r8712_construct_txaggr_cmd_desc(pxmitbuf); + r8712_construct_txaggr_cmd_hdr(pxmitbuf); + if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) + pxmitbuf->aggr_nr = 1; + + return _SUCCESS; +} + +u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + pxmitframe->pxmitbuf = pxmitbuf; + pxmitbuf->priv_data = pxmitframe; + pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; + /* buffer addr assoc */ + pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE + + (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); + if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) { + r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv, + pxmitframe); + pxmitbuf->aggr_nr++; + } + + return TXDESC_SIZE + + (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); +} + +u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + struct _adapter *padapter = pxmitframe->padapter; + struct dvobj_priv *pdvobj = (struct dvobj_priv *) &padapter->dvobjpriv; + struct tx_desc *ptxdesc = (struct tx_desc *)pxmitbuf->pbuf; + struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) + (pxmitbuf->pbuf + TXDESC_SIZE); + u16 total_length = (u16) (ptxdesc->txdw0 & 0xffff); + + /* use 1st xmitframe as media */ + xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); + pcmd_hdr->cmd_dw0 = cpu_to_le32(((total_length-CMD_HDR_SZ)&0x0000ffff)| + (pcmd_hdr->cmd_dw0&0xffff0000)); + + /* urb length in cmd_dw1 */ + pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff)| + ((total_length+TXDESC_SIZE) << 16)); + pxmitframe->last[0] = 1; + pxmitframe->bpending[0] = false; + pxmitframe->mem_addr = pxmitbuf->pbuf; + + if ((pdvobj->ishighspeed && ((total_length+TXDESC_SIZE)%0x200) == 0) || + ((!pdvobj->ishighspeed && + ((total_length+TXDESC_SIZE)%0x40) == 0))) { + ptxdesc->txdw0 |= cpu_to_le32 + (((TXDESC_SIZE+OFFSET_SZ+8)<<OFFSET_SHT)&0x00ff0000); + /*32 bytes for TX Desc + 8 bytes pending*/ + } else { + ptxdesc->txdw0 |= cpu_to_le32 + (((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); + /*default = 32 bytes for TX Desc*/ + } + r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD, + total_length+TXDESC_SIZE, (u8 *)pxmitframe); + + return _SUCCESS; +} + +#endif + +static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) +{ + uint qsel; + struct _adapter *padapter = pxmitframe->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct tx_desc *ptxdesc = (struct tx_desc *)pmem; + struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; +#ifdef CONFIG_R8712_TX_AGGR + struct cmd_priv *pcmdpriv = (struct cmd_priv *)&padapter->cmdpriv; +#endif + u8 blnSetTxDescOffset; + sint bmcst = IS_MCAST(pattrib->ra); + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct tx_desc txdesc_mp; + + memcpy(&txdesc_mp, ptxdesc, sizeof(struct tx_desc)); + memset(ptxdesc, 0, sizeof(struct tx_desc)); + /* offset 0 */ + ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff); + if (pdvobj->ishighspeed) { + if (((sz + TXDESC_SIZE) % 512) == 0) + blnSetTxDescOffset = 1; + else + blnSetTxDescOffset = 0; + } else { + if (((sz + TXDESC_SIZE) % 64) == 0) + blnSetTxDescOffset = 1; + else + blnSetTxDescOffset = 0; + } + if (blnSetTxDescOffset) { + /* 32 bytes for TX Desc + 8 bytes pending */ + ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ + 8) << + OFFSET_SHT) & 0x00ff0000); + } else { + /* default = 32 bytes for TX Desc */ + ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ) << + OFFSET_SHT) & 0x00ff0000); + } + ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); + if (pxmitframe->frame_tag == DATA_FRAMETAG) { + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32((pattrib->mac_id)&0x1f); + +#ifdef CONFIG_R8712_TX_AGGR + /* dirty workaround, need to check if it is aggr cmd. */ + if ((u8 *)pmem != (u8 *)pxmitframe->pxmitbuf->pbuf) { + ptxdesc->txdw0 |= cpu_to_le32 + ((0x3 << TYPE_SHT)&TYPE_MSK); + qsel = (uint)(pattrib->qsel & 0x0000001f); + if (qsel == 2) + qsel = 0; + ptxdesc->txdw1 |= cpu_to_le32 + ((qsel << QSEL_SHT) & 0x00001f00); + ptxdesc->txdw2 = cpu_to_le32 + ((qsel << RTS_RC_SHT)&0x001f0000); + ptxdesc->txdw6 |= cpu_to_le32 + ((0x5 << RSVD6_SHT)&RSVD6_MSK); + } else { + ptxdesc->txdw0 |= cpu_to_le32 + ((0x3 << TYPE_SHT)&TYPE_MSK); + ptxdesc->txdw1 |= cpu_to_le32 + ((0x13 << QSEL_SHT) & 0x00001f00); + qsel = (uint)(pattrib->qsel & 0x0000001f); + if (qsel == 2) + qsel = 0; + ptxdesc->txdw2 = cpu_to_le32 + ((qsel << RTS_RC_SHT)&0x0001f000); + ptxdesc->txdw7 |= cpu_to_le32 + (pcmdpriv->cmd_seq << 24); + pcmdpriv->cmd_seq++; + } + pattrib->qsel = 0x13; +#else + qsel = (uint)(pattrib->qsel & 0x0000001f); + ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); +#endif + if (!pqospriv->qos_option) + ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/*Non-QoS*/ + if ((pattrib->encrypt > 0) && !pattrib->bswenc) { + switch (pattrib->encrypt) { /*SEC_TYPE*/ + case _WEP40_: + case _WEP104_: + ptxdesc->txdw1 |= cpu_to_le32((0x01 << 22) & + 0x00c00000); + /*KEY_ID when WEP is used;*/ + ptxdesc->txdw1 |= cpu_to_le32((psecuritypriv-> + PrivacyKeyIndex << 17) & + 0x00060000); + break; + case _TKIP_: + case _TKIP_WTMIC_: + ptxdesc->txdw1 |= cpu_to_le32((0x02 << 22) & + 0x00c00000); + break; + case _AES_: + ptxdesc->txdw1 |= cpu_to_le32((0x03 << 22) & + 0x00c00000); + break; + case _NO_PRIVACY_: + default: + break; + } + } + /*offset 8*/ + if (bmcst) + ptxdesc->txdw2 |= cpu_to_le32(BMC); + + /*offset 12*/ + /* f/w will increase the seqnum by itself, driver pass the + * correct priority to fw + * fw will check the correct priority for increasing the + * seqnum per tid. about usb using 4-endpoint, qsel points out + * the correct mapping between AC&Endpoint, + * the purpose is that correct mapping lets the MAC release + * the AC Queue list correctly. */ + ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & + 0x0fff0000); + if ((pattrib->ether_type != 0x888e) && + (pattrib->ether_type != 0x0806) && + (pattrib->dhcp_pkt != 1)) { + /*Not EAP & ARP type data packet*/ + if (phtpriv->ht_option == 1) { /*B/G/N Mode*/ + if (phtpriv->ampdu_enable != true) + ptxdesc->txdw2 |= cpu_to_le32(BK); + } + } else { + /* EAP data packet and ARP packet. + * Use the 1M data rate to send the EAP/ARP packet. + * This will maybe make the handshake smooth. + */ + /*driver uses data rate*/ + ptxdesc->txdw4 = cpu_to_le32(0x80000000); + ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/*1M*/ + } + if (pattrib->pctrl == 1) { /* mp tx packets */ + struct tx_desc *ptxdesc_mp; + + ptxdesc_mp = &txdesc_mp; + /* offset 8 */ + ptxdesc->txdw2 = cpu_to_le32(ptxdesc_mp->txdw2); + if (bmcst) + ptxdesc->txdw2 |= cpu_to_le32(BMC); + ptxdesc->txdw2 |= cpu_to_le32(BK); + /* offset 16 */ + ptxdesc->txdw4 = cpu_to_le32(ptxdesc_mp->txdw4); + /* offset 20 */ + ptxdesc->txdw5 = cpu_to_le32(ptxdesc_mp->txdw5); + pattrib->pctrl = 0;/* reset to zero; */ + } + } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { + /* offset 4 */ + ptxdesc->txdw1 |= (0x05) & 0x1f;/*CAM_ID(MAC_ID), default=5;*/ + qsel = (uint)(pattrib->qsel & 0x0000001f); + ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); + ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/* Non-QoS */ + /* offset 8 */ + if (bmcst) + ptxdesc->txdw2 |= cpu_to_le32(BMC); + /* offset 12 */ + /* f/w will increase the seqnum by itself, driver pass the + * correct priority to fw + * fw will check the correct priority for increasing the seqnum + * per tid. about usb using 4-endpoint, qsel points out the + * correct mapping between AC&Endpoint, + * the purpose is that correct mapping let the MAC releases + * the AC Queue list correctly. */ + ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & + 0x0fff0000); + /* offset 16 */ + ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ + /* offset 20 */ + ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/* gtest 1M */ + } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { + /* offset 4 */ + qsel = 0x13; + ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); + } else { + /* offset 4 */ + qsel = (uint)(pattrib->priority&0x0000001f); + ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); + /*offset 8*/ + /*offset 12*/ + ptxdesc->txdw3 = cpu_to_le32((pattrib->seqnum << SEQ_SHT) & + 0x0fff0000); + /*offset 16*/ + ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ + /*offset 20*/ + ptxdesc->txdw5 = cpu_to_le32(0x001f9600);/*gtest*/ + } +} + +int r8712_xmitframe_complete(struct _adapter *padapter, + struct xmit_priv *pxmitpriv, + struct xmit_buf *pxmitbuf) +{ + struct hw_xmit *phwxmits; + sint hwentry; + struct xmit_frame *pxmitframe = NULL; +#ifdef CONFIG_R8712_TX_AGGR + struct xmit_frame *p2ndxmitframe = NULL; +#else + int res = _SUCCESS, xcnt = 0; +#endif + + phwxmits = pxmitpriv->hwxmits; + hwentry = pxmitpriv->hwxmit_entry; + if (pxmitbuf == NULL) { + pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); + if (!pxmitbuf) + return false; +#ifdef CONFIG_R8712_TX_AGGR + pxmitbuf->aggr_nr = 0; +#endif + } + /* 1st frame dequeued */ + pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); + /* need to remember the 1st frame */ + if (pxmitframe != NULL) { + +#ifdef CONFIG_R8712_TX_AGGR + /* 1. dequeue 2nd frame + * 2. aggr if 2nd xframe is dequeued, else dump directly + */ + if (AGGR_NR_HIGH_BOUND > 1) + p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, + hwentry); + if (pxmitframe->frame_tag != DATA_FRAMETAG) { + r8712_free_xmitbuf(pxmitpriv, pxmitbuf); + return false; + } + if (p2ndxmitframe != NULL) + if (p2ndxmitframe->frame_tag != DATA_FRAMETAG) { + r8712_free_xmitbuf(pxmitpriv, pxmitbuf); + return false; + } + r8712_xmitframe_aggr_1st(pxmitbuf, pxmitframe); + if (p2ndxmitframe != NULL) { + u16 total_length; + + total_length = r8712_xmitframe_aggr_next( + pxmitbuf, p2ndxmitframe); + do { + p2ndxmitframe = dequeue_xframe_ex( + pxmitpriv, phwxmits, hwentry); + if (p2ndxmitframe != NULL) + total_length = + r8712_xmitframe_aggr_next( + pxmitbuf, + p2ndxmitframe); + else + break; + } while (total_length <= 0x1800 && + pxmitbuf->aggr_nr <= AGGR_NR_HIGH_BOUND); + } + if (pxmitbuf->aggr_nr > 0) + r8712_dump_aggr_xframe(pxmitbuf, pxmitframe); + +#else + + xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); + if (pxmitframe->frame_tag == DATA_FRAMETAG) { + if (pxmitframe->attrib.priority <= 15) + res = r8712_xmitframe_coalesce(padapter, + pxmitframe->pkt, pxmitframe); + /* always return ndis_packet after + * r8712_xmitframe_coalesce */ + r8712_xmit_complete(padapter, pxmitframe); + } + if (res == _SUCCESS) + dump_xframe(padapter, pxmitframe); + else + r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); + xcnt++; +#endif + + } else { /* pxmitframe == NULL && p2ndxmitframe == NULL */ + r8712_free_xmitbuf(pxmitpriv, pxmitbuf); + return false; + } + return true; +} + +static void dump_xframe(struct _adapter *padapter, + struct xmit_frame *pxmitframe) +{ + int t, sz, w_sz; + u8 *mem_addr; + u32 ff_hwaddr; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + if (pxmitframe->attrib.ether_type != 0x0806) { + if (pxmitframe->attrib.ether_type != 0x888e) + r8712_issue_addbareq_cmd(padapter, pattrib->priority); + } + mem_addr = pxmitframe->buf_addr; + for (t = 0; t < pattrib->nr_frags; t++) { + if (t != (pattrib->nr_frags - 1)) { + sz = pxmitpriv->frag_len; + sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : + pattrib->icv_len); + pxmitframe->last[t] = 0; + } else { + sz = pattrib->last_txcmdsz; + pxmitframe->last[t] = 1; + } + update_txdesc(pxmitframe, (uint *)mem_addr, sz); + w_sz = sz + TXDESC_SIZE; + pxmitframe->mem_addr = mem_addr; + pxmitframe->bpending[t] = false; + ff_hwaddr = get_ff_hwaddr(pxmitframe); +#ifdef CONFIG_R8712_TX_AGGR + r8712_write_port(padapter, RTL8712_DMA_H2CCMD, w_sz, + (unsigned char *)pxmitframe); +#else + r8712_write_port(padapter, ff_hwaddr, w_sz, + (unsigned char *)pxmitframe); +#endif + mem_addr += w_sz; + mem_addr = (u8 *)RND4(((addr_t)(mem_addr))); + } +} + +int r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe) +{ + int res = _SUCCESS; + + res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); + pxmitframe->pkt = NULL; + if (res == _SUCCESS) + dump_xframe(padapter, pxmitframe); + return res; +} + +int r8712_xmit_enqueue(struct _adapter *padapter, struct xmit_frame *pxmitframe) +{ + if (r8712_xmit_classifier(padapter, pxmitframe) == _FAIL) { + pxmitframe->pkt = NULL; + return _FAIL; + } + return _SUCCESS; +} diff --git a/kernel/drivers/staging/rtl8712/rtl8712_xmit.h b/kernel/drivers/staging/rtl8712/rtl8712_xmit.h new file mode 100644 index 000000000..b50e7a1f3 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl8712_xmit.h @@ -0,0 +1,123 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL8712_XMIT_H_ +#define _RTL8712_XMIT_H_ + +#define HWXMIT_ENTRY 4 + +#define VO_QUEUE_INX 0 +#define VI_QUEUE_INX 1 +#define BE_QUEUE_INX 2 +#define BK_QUEUE_INX 3 +#define TS_QUEUE_INX 4 +#define MGT_QUEUE_INX 5 +#define BMC_QUEUE_INX 6 +#define BCN_QUEUE_INX 7 + +#define HW_QUEUE_ENTRY 8 + +#define TXDESC_SIZE 32 +#define TXDESC_OFFSET TXDESC_SIZE + +#define NR_AMSDU_XMITFRAME 8 +#define NR_TXAGG_XMITFRAME 8 + +#define MAX_AMSDU_XMITBUF_SZ 8704 +#define MAX_TXAGG_XMITBUF_SZ 16384 /*16k*/ + + +#define tx_cmd tx_desc + + +/* + *defined for TX DESC Operation + */ + +#define MAX_TID (15) + +/*OFFSET 0*/ +#define OFFSET_SZ (0) +#define OFFSET_SHT (16) +#define OWN BIT(31) +#define FSG BIT(27) +#define LSG BIT(26) +#define TYPE_SHT (24) +#define TYPE_MSK (0x03000000) + +/*OFFSET 4*/ +#define PKT_OFFSET_SZ (0) +#define QSEL_SHT (8) +#define HWPC BIT(31) + +/*OFFSET 8*/ +#define BMC BIT(7) +#define BK BIT(30) +#define AGG_EN BIT(29) +#define RTS_RC_SHT (16) + +/*OFFSET 12*/ +#define SEQ_SHT (16) + +/*OFFSET 16*/ +#define TXBW BIT(18) + +/*OFFSET 20*/ +#define DISFB BIT(15) +#define RSVD6_MSK (0x00E00000) +#define RSVD6_SHT (21) + +struct tx_desc { + /*DWORD 0*/ + unsigned int txdw0; + unsigned int txdw1; + unsigned int txdw2; + unsigned int txdw3; + unsigned int txdw4; + unsigned int txdw5; + unsigned int txdw6; + unsigned int txdw7; +}; + + +union txdesc { + struct tx_desc txdesc; + unsigned int value[TXDESC_SIZE>>2]; +}; + +int r8712_xmitframe_complete(struct _adapter *padapter, + struct xmit_priv *pxmitpriv, + struct xmit_buf *pxmitbuf); +void r8712_do_queue_select(struct _adapter *padapter, + struct pkt_attrib *pattrib); + +#ifdef CONFIG_R8712_TX_AGGR +u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe); +u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe); +#endif + +#endif diff --git a/kernel/drivers/staging/rtl8712/rtl871x_cmd.c b/kernel/drivers/staging/rtl8712/rtl871x_cmd.c new file mode 100644 index 000000000..e35854d28 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_cmd.c @@ -0,0 +1,1042 @@ +/****************************************************************************** + * rtl871x_cmd.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_CMD_C_ + +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kref.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/usb.h> +#include <linux/usb/ch9.h> +#include <linux/circ_buf.h> +#include <linux/uaccess.h> +#include <asm/byteorder.h> +#include <linux/atomic.h> +#include <linux/semaphore.h> +#include <linux/rtnetlink.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "recv_osdep.h" +#include "mlme_osdep.h" + +/* +Caller and the r8712_cmd_thread can protect cmd_q by spin_lock. +No irqsave is necessary. +*/ + +static sint _init_cmd_priv(struct cmd_priv *pcmdpriv) +{ + sema_init(&(pcmdpriv->cmd_queue_sema), 0); + sema_init(&(pcmdpriv->terminate_cmdthread_sema), 0); + + _init_queue(&(pcmdpriv->cmd_queue)); + + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + pcmdpriv->cmd_seq = 1; + pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ, + GFP_ATOMIC); + if (pcmdpriv->cmd_allocated_buf == NULL) + return _FAIL; + pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - + ((addr_t)(pcmdpriv->cmd_allocated_buf) & + (CMDBUFF_ALIGN_SZ-1)); + pcmdpriv->rsp_allocated_buf = kmalloc(MAX_RSPSZ + 4, GFP_ATOMIC); + if (pcmdpriv->rsp_allocated_buf == NULL) + return _FAIL; + pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - + ((addr_t)(pcmdpriv->rsp_allocated_buf) & 3); + pcmdpriv->cmd_issued_cnt = 0; + pcmdpriv->cmd_done_cnt = 0; + pcmdpriv->rsp_cnt = 0; + return _SUCCESS; +} + +static sint _init_evt_priv(struct evt_priv *pevtpriv) +{ + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + pevtpriv->event_seq = 0; + pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC); + + if (pevtpriv->evt_allocated_buf == NULL) + return _FAIL; + pevtpriv->evt_buf = pevtpriv->evt_allocated_buf + 4 - + ((addr_t)(pevtpriv->evt_allocated_buf) & 3); + pevtpriv->evt_done_cnt = 0; + return _SUCCESS; +} + +static void _free_evt_priv(struct evt_priv *pevtpriv) +{ + kfree(pevtpriv->evt_allocated_buf); +} + +static void _free_cmd_priv(struct cmd_priv *pcmdpriv) +{ + if (pcmdpriv) { + kfree(pcmdpriv->cmd_allocated_buf); + kfree(pcmdpriv->rsp_allocated_buf); + } +} + +/* +Calling Context: + +_enqueue_cmd can only be called between kernel thread, +since only spin_lock is used. + +ISR/Call-Back functions can't call this sub-function. + +*/ + +static sint _enqueue_cmd(struct __queue *queue, struct cmd_obj *obj) +{ + unsigned long irqL; + + if (obj == NULL) + return _SUCCESS; + spin_lock_irqsave(&queue->lock, irqL); + list_add_tail(&obj->list, &queue->queue); + spin_unlock_irqrestore(&queue->lock, irqL); + return _SUCCESS; +} + +static struct cmd_obj *_dequeue_cmd(struct __queue *queue) +{ + unsigned long irqL; + struct cmd_obj *obj; + + spin_lock_irqsave(&(queue->lock), irqL); + if (list_empty(&(queue->queue))) + obj = NULL; + else { + obj = LIST_CONTAINOR(queue->queue.next, + struct cmd_obj, list); + list_del_init(&obj->list); + } + spin_unlock_irqrestore(&(queue->lock), irqL); + return obj; +} + +u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv) +{ + return _init_cmd_priv(pcmdpriv); +} + +u32 r8712_init_evt_priv(struct evt_priv *pevtpriv) +{ + return _init_evt_priv(pevtpriv); +} + +void r8712_free_evt_priv(struct evt_priv *pevtpriv) +{ + _free_evt_priv(pevtpriv); +} + +void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv) +{ + _free_cmd_priv(pcmdpriv); +} + +u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj) +{ + int res; + + if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag == true) + return _FAIL; + res = _enqueue_cmd(&pcmdpriv->cmd_queue, obj); + up(&pcmdpriv->cmd_queue_sema); + return res; +} + +u32 r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj) +{ + unsigned long irqL; + struct __queue *queue; + + if (obj == NULL) + return _SUCCESS; + if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag == true) + return _FAIL; + queue = &pcmdpriv->cmd_queue; + spin_lock_irqsave(&queue->lock, irqL); + list_add_tail(&obj->list, &queue->queue); + spin_unlock_irqrestore(&queue->lock, irqL); + up(&pcmdpriv->cmd_queue_sema); + return _SUCCESS; +} + +struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue) +{ + return _dequeue_cmd(queue); +} + +void r8712_free_cmd_obj(struct cmd_obj *pcmd) +{ + if ((pcmd->cmdcode != _JoinBss_CMD_) && + (pcmd->cmdcode != _CreateBss_CMD_)) + kfree(pcmd->parmbuf); + if (pcmd->rsp != NULL) { + if (pcmd->rspsz != 0) + kfree(pcmd->rsp); + } + kfree(pcmd); +} + +/* +r8712_sitesurvey_cmd(~) + ### NOTE:#### (!!!!) + MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, + YOU SHOULD HAVE LOCKED pmlmepriv->lock +*/ +u8 r8712_sitesurvey_cmd(struct _adapter *padapter, + struct ndis_802_11_ssid *pssid) +{ + struct cmd_obj *ph2c; + struct sitesurvey_parm *psurveyPara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psurveyPara = kmalloc(sizeof(*psurveyPara), GFP_ATOMIC); + if (psurveyPara == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, + GEN_CMD_CODE(_SiteSurvey)); + psurveyPara->bsslimit = cpu_to_le32(48); + psurveyPara->passive_mode = cpu_to_le32(pmlmepriv->passive_mode); + psurveyPara->ss_ssidlen = 0; + memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1); + if ((pssid != NULL) && (pssid->SsidLength)) { + memcpy(psurveyPara->ss_ssid, pssid->Ssid, pssid->SsidLength); + psurveyPara->ss_ssidlen = cpu_to_le32(pssid->SsidLength); + } + set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); + r8712_enqueue_cmd(pcmdpriv, ph2c); + mod_timer(&pmlmepriv->scan_to_timer, + jiffies + msecs_to_jiffies(SCANNING_TIMEOUT)); + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_SITE_SURVEY); + padapter->blnEnableRxFF0Filter = 0; + return _SUCCESS; +} + +u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset) +{ + struct cmd_obj *ph2c; + struct setdatarate_parm *pbsetdataratepara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC); + if (pbsetdataratepara == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, + GEN_CMD_CODE(_SetDataRate)); + pbsetdataratepara->mac_id = 5; + memcpy(pbsetdataratepara->datarates, rateset, NumRates); + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan) +{ + struct cmd_obj *ph2c; + struct SetChannelPlan_param *psetchplanpara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC); + if (psetchplanpara == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara, + GEN_CMD_CODE(_SetChannelPlan)); + psetchplanpara->ChannelPlan = chplan; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setbasicrate_cmd(struct _adapter *padapter, u8 *rateset) +{ + struct cmd_obj *ph2c; + struct setbasicrate_parm *pssetbasicratepara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + pssetbasicratepara = kmalloc(sizeof(*pssetbasicratepara), GFP_ATOMIC); + if (pssetbasicratepara == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, + _SetBasicRate_CMD_); + memcpy(pssetbasicratepara->basicrates, rateset, NumRates); + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +/* power tracking mechanism setting */ +u8 r8712_setptm_cmd(struct _adapter *padapter, u8 type) +{ + struct cmd_obj *ph2c; + struct writePTM_parm *pwriteptmparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC); + if (pwriteptmparm == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetPT)); + pwriteptmparm->type = type; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type) +{ + struct cmd_obj *ph2c; + struct writePTM_parm *pwriteptmparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC); + if (pwriteptmparm == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetDIG)); + pwriteptmparm->type = type; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type) +{ + struct cmd_obj *ph2c; + struct writePTM_parm *pwriteptmparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC); + if (pwriteptmparm == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetRA)); + pwriteptmparm->type = type; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val) +{ + struct cmd_obj *ph2c; + struct writeRF_parm *pwriterfparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC); + if (pwriterfparm == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); + pwriterfparm->offset = offset; + pwriterfparm->value = val; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval) +{ + struct cmd_obj *ph2c; + struct readRF_parm *prdrfparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC); + if (prdrfparm == NULL) { + kfree(ph2c); + return _FAIL; + } + INIT_LIST_HEAD(&ph2c->list); + ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg); + ph2c->parmbuf = (unsigned char *)prdrfparm; + ph2c->cmdsz = sizeof(struct readRF_parm); + ph2c->rsp = pval; + ph2c->rspsz = sizeof(struct readRF_rsp); + prdrfparm->offset = offset; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd) +{ + kfree(pcmd->parmbuf); + kfree(pcmd); + padapter->mppriv.workparam.bcompleted = true; +} + +void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd) +{ + kfree(pcmd->parmbuf); + kfree(pcmd); + + padapter->mppriv.workparam.bcompleted = true; +} + +u8 r8712_createbss_cmd(struct _adapter *padapter) +{ + struct cmd_obj *pcmd; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct wlan_bssid_ex *pdev_network = + &padapter->registrypriv.dev_network; + + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK); + pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); + if (pcmd == NULL) + return _FAIL; + INIT_LIST_HEAD(&pcmd->list); + pcmd->cmdcode = _CreateBss_CMD_; + pcmd->parmbuf = (unsigned char *)pdev_network; + pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(( + struct ndis_wlan_bssid_ex *) + pdev_network); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + /* notes: translate IELength & Length after assign to cmdsz; */ + pdev_network->Length = pcmd->cmdsz; + pdev_network->IELength = pdev_network->IELength; + pdev_network->Ssid.SsidLength = pdev_network->Ssid.SsidLength; + r8712_enqueue_cmd(pcmdpriv, pcmd); + return _SUCCESS; +} + +u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) +{ + uint t_len = 0; + struct ndis_wlan_bssid_ex *psecnetwork; + struct cmd_obj *pcmd; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork-> + network.InfrastructureMode; + + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK); + pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); + if (pcmd == NULL) + return _FAIL; + t_len = sizeof(u32) + 6 * sizeof(unsigned char) + 2 + + sizeof(struct ndis_802_11_ssid) + sizeof(u32) + + sizeof(s32) + + sizeof(enum NDIS_802_11_NETWORK_TYPE) + + sizeof(struct NDIS_802_11_CONFIGURATION) + + sizeof(enum NDIS_802_11_NETWORK_INFRASTRUCTURE) + + sizeof(NDIS_802_11_RATES_EX) + + sizeof(u32) + MAX_IE_SZ; + + /* for hidden ap to set fw_state here */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != + true) { + switch (ndis_network_mode) { + case Ndis802_11IBSS: + pmlmepriv->fw_state |= WIFI_ADHOC_STATE; + break; + case Ndis802_11Infrastructure: + pmlmepriv->fw_state |= WIFI_STATION_STATE; + break; + case Ndis802_11APMode: + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + break; + } + } + psecnetwork = (struct ndis_wlan_bssid_ex *)&psecuritypriv->sec_bss; + if (psecnetwork == NULL) { + kfree(pcmd); + return _FAIL; + } + memcpy(psecnetwork, &pnetwork->network, t_len); + psecuritypriv->authenticator_ie[0] = (unsigned char) + psecnetwork->IELength; + if ((psecnetwork->IELength-12) < (256 - 1)) + memcpy(&psecuritypriv->authenticator_ie[1], + &psecnetwork->IEs[12], psecnetwork->IELength-12); + else + memcpy(&psecuritypriv->authenticator_ie[1], + &psecnetwork->IEs[12], (256-1)); + psecnetwork->IELength = 0; + /* If the driver wants to use the bssid to create the connection. + * If not, we copy the connecting AP's MAC address to it so that + * the driver just has the bssid information for PMKIDList searching. + */ + if (pmlmepriv->assoc_by_bssid == false) + ether_addr_copy(&pmlmepriv->assoc_bssid[0], + &pnetwork->network.MacAddress[0]); + psecnetwork->IELength = r8712_restruct_sec_ie(padapter, + &pnetwork->network.IEs[0], + &psecnetwork->IEs[0], + pnetwork->network.IELength); + pqospriv->qos_option = 0; + if (pregistrypriv->wmm_enable) { + u32 tmp_len; + + tmp_len = r8712_restruct_wmm_ie(padapter, + &pnetwork->network.IEs[0], + &psecnetwork->IEs[0], + pnetwork->network.IELength, + psecnetwork->IELength); + if (psecnetwork->IELength != tmp_len) { + psecnetwork->IELength = tmp_len; + pqospriv->qos_option = 1; /* WMM IE in beacon */ + } else + pqospriv->qos_option = 0; /* no WMM IE in beacon */ + } + if (pregistrypriv->ht_enable) { + /* For WEP mode, we will use the bg mode to do the connection + * to avoid some IOT issues, especially for Realtek 8192u + * SoftAP. + */ + if ((padapter->securitypriv.PrivacyAlgrthm != _WEP40_) && + (padapter->securitypriv.PrivacyAlgrthm != _WEP104_)) { + /* restructure_ht_ie */ + r8712_restructure_ht_ie(padapter, + &pnetwork->network.IEs[0], + &psecnetwork->IEs[0], + pnetwork->network.IELength, + &psecnetwork->IELength); + } + } + psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength; + if (psecnetwork->IELength < 255) + memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], + psecnetwork->IELength); + else + memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], + 255); + /* get cmdsz before endian conversion */ + pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(psecnetwork); +#ifdef __BIG_ENDIAN + /* wlan_network endian conversion */ + psecnetwork->Length = cpu_to_le32(psecnetwork->Length); + psecnetwork->Ssid.SsidLength = cpu_to_le32( + psecnetwork->Ssid.SsidLength); + psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy); + psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi); + psecnetwork->NetworkTypeInUse = cpu_to_le32( + psecnetwork->NetworkTypeInUse); + psecnetwork->Configuration.ATIMWindow = cpu_to_le32( + psecnetwork->Configuration.ATIMWindow); + psecnetwork->Configuration.BeaconPeriod = cpu_to_le32( + psecnetwork->Configuration.BeaconPeriod); + psecnetwork->Configuration.DSConfig = cpu_to_le32( + psecnetwork->Configuration.DSConfig); + psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32( + psecnetwork->Configuration.FHConfig.DwellTime); + psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32( + psecnetwork->Configuration.FHConfig.HopPattern); + psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32( + psecnetwork->Configuration.FHConfig.HopSet); + psecnetwork->Configuration.FHConfig.Length = cpu_to_le32( + psecnetwork->Configuration.FHConfig.Length); + psecnetwork->Configuration.Length = cpu_to_le32( + psecnetwork->Configuration.Length); + psecnetwork->InfrastructureMode = cpu_to_le32( + psecnetwork->InfrastructureMode); + psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength); +#endif + INIT_LIST_HEAD(&pcmd->list); + pcmd->cmdcode = _JoinBss_CMD_; + pcmd->parmbuf = (unsigned char *)psecnetwork; + pcmd->rsp = NULL; + pcmd->rspsz = 0; + r8712_enqueue_cmd(pcmdpriv, pcmd); + return _SUCCESS; +} + +u8 r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */ +{ + struct cmd_obj *pdisconnect_cmd; + struct disconnect_parm *pdisconnect; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC); + if (pdisconnect_cmd == NULL) + return _FAIL; + pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC); + if (pdisconnect == NULL) { + kfree(pdisconnect_cmd); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect, + _DisConnect_CMD_); + r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd); + return _SUCCESS; +} + +u8 r8712_setopmode_cmd(struct _adapter *padapter, + enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) +{ + struct cmd_obj *ph2c; + struct setopmode_parm *psetop; + + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC); + if (psetop == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); + psetop->mode = (u8)networktype; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key) +{ + struct cmd_obj *ph2c; + struct set_stakey_parm *psetstakey_para; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct set_stakey_rsp *psetstakey_rsp = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sta_info *sta = (struct sta_info *)psta; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC); + if (psetstakey_para == NULL) { + kfree(ph2c); + return _FAIL; + } + psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC); + if (psetstakey_rsp == NULL) { + kfree(ph2c); + kfree(psetstakey_para); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); + ph2c->rsp = (u8 *) psetstakey_rsp; + ph2c->rspsz = sizeof(struct set_stakey_rsp); + ether_addr_copy(psetstakey_para->addr, sta->hwaddr); + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + psetstakey_para->algorithm = (unsigned char) + psecuritypriv->PrivacyAlgrthm; + else + GET_ENCRY_ALGO(psecuritypriv, sta, + psetstakey_para->algorithm, false); + if (unicast_key == true) + memcpy(&psetstakey_para->key, &sta->x_UncstKey, 16); + else + memcpy(&psetstakey_para->key, + &psecuritypriv->XGrpKey[ + psecuritypriv->XGrpKeyid - 1]. skey, 16); + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode) +{ + struct cmd_obj *ph2c; + struct setrfintfs_parm *psetrfintfsparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psetrfintfsparm = kmalloc(sizeof(*psetrfintfsparm), GFP_ATOMIC); + if (psetrfintfsparm == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psetrfintfsparm, + GEN_CMD_CODE(_SetRFIntFs)); + psetrfintfsparm->rfintfs = mode; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setrttbl_cmd(struct _adapter *padapter, + struct setratable_parm *prate_table) +{ + struct cmd_obj *ph2c; + struct setratable_parm *psetrttblparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psetrttblparm = kmalloc(sizeof(*psetrttblparm), GFP_ATOMIC); + if (psetrttblparm == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, + GEN_CMD_CODE(_SetRaTable)); + memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm)); + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_gettssi_cmd(struct _adapter *padapter, u8 offset, u8 *pval) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct readTSSI_parm *prdtssiparm; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + prdtssiparm = kmalloc(sizeof(*prdtssiparm), GFP_ATOMIC); + if (prdtssiparm == NULL) { + kfree(ph2c); + return _FAIL; + } + INIT_LIST_HEAD(&ph2c->list); + ph2c->cmdcode = GEN_CMD_CODE(_ReadTSSI); + ph2c->parmbuf = (unsigned char *)prdtssiparm; + ph2c->cmdsz = sizeof(struct readTSSI_parm); + ph2c->rsp = pval; + ph2c->rspsz = sizeof(struct readTSSI_rsp); + + prdtssiparm->offset = offset; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct SetMacAddr_param *psetMacAddr_para; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC); + if (psetMacAddr_para == NULL) { + kfree(ph2c); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para, + _SetMacAddress_CMD_); + ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr); + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct set_assocsta_parm *psetassocsta_para; + struct set_assocsta_rsp *psetassocsta_rsp = NULL; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + psetassocsta_para = kmalloc(sizeof(*psetassocsta_para), GFP_ATOMIC); + if (psetassocsta_para == NULL) { + kfree(ph2c); + return _FAIL; + } + psetassocsta_rsp = kmalloc(sizeof(*psetassocsta_rsp), GFP_ATOMIC); + if (psetassocsta_rsp == NULL) { + kfree(ph2c); + kfree(psetassocsta_para); + return _FAIL; + } + init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_); + ph2c->rsp = (u8 *) psetassocsta_rsp; + ph2c->rspsz = sizeof(struct set_assocsta_rsp); + ether_addr_copy(psetassocsta_para->addr, mac_addr); + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct addBaReq_parm *paddbareq_parm; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC); + if (paddbareq_parm == NULL) { + kfree(ph2c); + return _FAIL; + } + paddbareq_parm->tid = tid; + init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, + GEN_CMD_CODE(_AddBAReq)); + r8712_enqueue_cmd_ex(pcmdpriv, ph2c); + return _SUCCESS; +} + +u8 r8712_wdg_wk_cmd(struct _adapter *padapter) +{ + struct cmd_obj *ph2c; + struct drvint_cmd_parm *pdrvintcmd_param; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC); + if (pdrvintcmd_param == NULL) { + kfree(ph2c); + return _FAIL; + } + pdrvintcmd_param->i_cid = WDG_WK_CID; + pdrvintcmd_param->sz = 0; + pdrvintcmd_param->pbuf = NULL; + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_); + r8712_enqueue_cmd_ex(pcmdpriv, ph2c); + return _SUCCESS; +} + +void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (pcmd->res != H2C_SUCCESS) + clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY); + r8712_free_cmd_obj(pcmd); +} + +void r8712_disassoc_cmd_callback(struct _adapter *padapter, + struct cmd_obj *pcmd) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (pcmd->res != H2C_SUCCESS) { + spin_lock_irqsave(&pmlmepriv->lock, irqL); + set_fwstate(pmlmepriv, _FW_LINKED); + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return; + } + r8712_free_cmd_obj(pcmd); +} + +void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (pcmd->res != H2C_SUCCESS) + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + r8712_free_cmd_obj(pcmd); +} + +void r8712_createbss_cmd_callback(struct _adapter *padapter, + struct cmd_obj *pcmd) +{ + unsigned long irqL; + struct sta_info *psta = NULL; + struct wlan_network *pwlan = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ndis_wlan_bssid_ex *pnetwork = (struct ndis_wlan_bssid_ex *) + pcmd->parmbuf; + struct wlan_network *tgt_network = &(pmlmepriv->cur_network); + + if (pcmd->res != H2C_SUCCESS) + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + del_timer(&pmlmepriv->assoc_timer); +#ifdef __BIG_ENDIAN + /* endian_convert */ + pnetwork->Length = le32_to_cpu(pnetwork->Length); + pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); + pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy); + pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); + pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse); + pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork-> + Configuration.ATIMWindow); + pnetwork->Configuration.DSConfig = le32_to_cpu(pnetwork-> + Configuration.DSConfig); + pnetwork->Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork-> + Configuration.FHConfig.DwellTime); + pnetwork->Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork-> + Configuration.FHConfig.HopPattern); + pnetwork->Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork-> + Configuration.FHConfig.HopSet); + pnetwork->Configuration.FHConfig.Length = le32_to_cpu(pnetwork-> + Configuration.FHConfig.Length); + pnetwork->Configuration.Length = le32_to_cpu(pnetwork-> + Configuration.Length); + pnetwork->InfrastructureMode = le32_to_cpu(pnetwork-> + InfrastructureMode); + pnetwork->IELength = le32_to_cpu(pnetwork->IELength); +#endif + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((pmlmepriv->fw_state) & WIFI_AP_STATE) { + psta = r8712_get_stainfo(&padapter->stapriv, + pnetwork->MacAddress); + if (!psta) { + psta = r8712_alloc_stainfo(&padapter->stapriv, + pnetwork->MacAddress); + if (psta == NULL) + goto createbss_cmd_fail; + } + r8712_indicate_connect(padapter); + } else { + pwlan = _r8712_alloc_network(pmlmepriv); + if (pwlan == NULL) { + pwlan = r8712_get_oldest_wlan_network( + &pmlmepriv->scanned_queue); + if (pwlan == NULL) + goto createbss_cmd_fail; + pwlan->last_scanned = jiffies; + } else + list_add_tail(&(pwlan->list), + &pmlmepriv->scanned_queue.queue); + pnetwork->Length = r8712_get_ndis_wlan_bssid_ex_sz(pnetwork); + memcpy(&(pwlan->network), pnetwork, pnetwork->Length); + pwlan->fixed = true; + memcpy(&tgt_network->network, pnetwork, + (r8712_get_ndis_wlan_bssid_ex_sz(pnetwork))); + if (pmlmepriv->fw_state & _FW_UNDER_LINKING) + pmlmepriv->fw_state ^= _FW_UNDER_LINKING; + /* we will set _FW_LINKED when there is one more sat to + * join us (stassoc_event_callback) */ + } +createbss_cmd_fail: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + r8712_free_cmd_obj(pcmd); +} + +void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *) + (pcmd->rsp); + struct sta_info *psta = r8712_get_stainfo(pstapriv, + psetstakey_rsp->addr); + + if (psta == NULL) + goto exit; + psta->aid = psta->mac_id = psetstakey_rsp->keyid; /*CAM_ID(CAM_ENTRY)*/ +exit: + r8712_free_cmd_obj(pcmd); +} + +void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd) +{ + unsigned long irqL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct set_assocsta_parm *passocsta_parm = + (struct set_assocsta_parm *)(pcmd->parmbuf); + struct set_assocsta_rsp *passocsta_rsp = + (struct set_assocsta_rsp *) (pcmd->rsp); + struct sta_info *psta = r8712_get_stainfo(pstapriv, + passocsta_parm->addr); + + if (psta == NULL) + return; + psta->aid = psta->mac_id = passocsta_rsp->cam_id; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) && + (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) + pmlmepriv->fw_state ^= _FW_UNDER_LINKING; + set_fwstate(pmlmepriv, _FW_LINKED); + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + r8712_free_cmd_obj(pcmd); +} + +u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, + u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO) +{ + struct cmd_obj *ph2c; + struct DisconnectCtrlEx_param *param; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + + ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); + if (ph2c == NULL) + return _FAIL; + param = kzalloc(sizeof(*param), GFP_ATOMIC); + if (param == NULL) { + kfree(ph2c); + return _FAIL; + } + + param->EnableDrvCtrl = (unsigned char)enableDrvCtrl; + param->TryPktCnt = (unsigned char)tryPktCnt; + param->TryPktInterval = (unsigned char)tryPktInterval; + param->FirstStageTO = (unsigned int)firstStageTO; + + init_h2fwcmd_w_parm_no_rsp(ph2c, param, + GEN_CMD_CODE(_DisconnectCtrlEx)); + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_cmd.h b/kernel/drivers/staging/rtl8712/rtl871x_cmd.h new file mode 100644 index 000000000..cb8225b94 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_cmd.h @@ -0,0 +1,790 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL871X_CMD_H_ +#define __RTL871X_CMD_H_ + +#include "wlan_bssdef.h" +#include "rtl871x_rf.h" +#define C2H_MEM_SZ (16*1024) + +#include "osdep_service.h" +#include "ieee80211.h" + +#define FREE_CMDOBJ_SZ 128 +#define MAX_CMDSZ 512 +#define MAX_RSPSZ 512 +#define MAX_EVTSZ 1024 +#define CMDBUFF_ALIGN_SZ 512 + +struct cmd_obj { + u16 cmdcode; + u8 res; + u8 *parmbuf; + u32 cmdsz; + u8 *rsp; + u32 rspsz; + struct list_head list; +}; + +struct cmd_priv { + struct semaphore cmd_queue_sema; + struct semaphore terminate_cmdthread_sema; + struct __queue cmd_queue; + u8 cmd_seq; + u8 *cmd_buf; /*shall be non-paged, and 4 bytes aligned*/ + u8 *cmd_allocated_buf; + u8 *rsp_buf; /*shall be non-paged, and 4 bytes aligned*/ + u8 *rsp_allocated_buf; + u32 cmd_issued_cnt; + u32 cmd_done_cnt; + u32 rsp_cnt; + struct _adapter *padapter; +}; + +struct evt_obj { + u16 evtcode; + u8 res; + u8 *parmbuf; + u32 evtsz; + struct list_head list; +}; + +struct evt_priv { + struct __queue evt_queue; + u8 event_seq; + u8 *evt_buf; /*shall be non-paged, and 4 bytes aligned*/ + u8 *evt_allocated_buf; + u32 evt_done_cnt; + struct tasklet_struct event_tasklet; +}; + +#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \ +do {\ + INIT_LIST_HEAD(&pcmd->list);\ + pcmd->cmdcode = code;\ + pcmd->parmbuf = (u8 *)(pparm);\ + pcmd->cmdsz = sizeof(*pparm);\ + pcmd->rsp = NULL;\ + pcmd->rspsz = 0;\ +} while (0) + +u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); +u32 r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); +struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue); +void r8712_free_cmd_obj(struct cmd_obj *pcmd); +int r8712_cmd_thread(void *context); +u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv); +void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv); +u32 r8712_init_evt_priv(struct evt_priv *pevtpriv); +void r8712_free_evt_priv(struct evt_priv *pevtpriv); + +enum rtl871x_drvint_cid { + NONE_WK_CID, + WDG_WK_CID, + MAX_WK_CID +}; + +enum RFINTFS { + SWSI, + HWSI, + HWPI, +}; + +/* + * Caller Mode: Infra, Ad-HoC(C) + * Notes: To enter USB suspend mode + * Command Mode + */ +struct usb_suspend_parm { + u32 action; /* 1: sleep, 0:resume */ +}; + +/* + * Caller Mode: Infra, Ad-Hoc + * Notes: To join the specified bss + * Command Event Mode + */ +struct joinbss_parm { + struct ndis_wlan_bssid_ex network; +}; + +/* + * Caller Mode: Infra, Ad-HoC(C) + * Notes: To disconnect the current associated BSS + * Command Mode + */ +struct disconnect_parm { + u32 rsvd; +}; + +/* + * Caller Mode: AP, Ad-HoC(M) + * Notes: To create a BSS + * Command Mode + */ +struct createbss_parm { + struct ndis_wlan_bssid_ex network; +}; + +/* + * Caller Mode: AP, Ad-HoC, Infra + * Notes: To set the NIC mode of RTL8711 + * Command Mode + * The definition of mode: + * + * #define IW_MODE_AUTO 0 // Let the driver decides which AP to join + * #define IW_MODE_ADHOC 1 // Single cell network (Ad-Hoc Clients) + * #define IW_MODE_INFRA 2 // Multi cell network, roaming, .. + * #define IW_MODE_MASTER 3 // Synchronisation master or AP + * #define IW_MODE_REPEAT 4 // Wireless Repeater (forwarder) + * #define IW_MODE_SECOND 5 // Secondary master/repeater (backup) + * #define IW_MODE_MONITOR 6 // Passive monitor (listen only) +*/ +struct setopmode_parm { + u8 mode; + u8 rsvd[3]; +}; + +/* + * Caller Mode: AP, Ad-HoC, Infra + * Notes: To ask RTL8711 performing site-survey + * Command-Event Mode + */ +struct sitesurvey_parm { + sint passive_mode; /*active: 1, passive: 0 */ + sint bsslimit; /* 1 ~ 48 */ + sint ss_ssidlen; + u8 ss_ssid[IW_ESSID_MAX_SIZE + 1]; +}; + +/* + * Caller Mode: Any + * Notes: To set the auth type of RTL8711. open/shared/802.1x + * Command Mode + */ +struct setauth_parm { + u8 mode; /*0: legacy open, 1: legacy shared 2: 802.1x*/ + u8 _1x; /*0: PSK, 1: TLS*/ + u8 rsvd[2]; +}; + +/* + * Caller Mode: Infra + * a. algorithm: wep40, wep104, tkip & aes + * b. keytype: grp key/unicast key + * c. key contents + * + * when shared key ==> keyid is the camid + * when 802.1x ==> keyid [0:1] ==> grp key + * when 802.1x ==> keyid > 2 ==> unicast key + */ +struct setkey_parm { + u8 algorithm; /* encryption algorithm, could be none, wep40, + * TKIP, CCMP, wep104 */ + u8 keyid; + u8 grpkey; /* 1: this is the grpkey for 802.1x. + * 0: this is the unicast key for 802.1x */ + u8 key[16]; /* this could be 40 or 104 */ +}; + +/* + * When in AP or Ad-Hoc mode, this is used to + * allocate an sw/hw entry for a newly associated sta. + * Command + * when shared key ==> algorithm/keyid + */ +struct set_stakey_parm { + u8 addr[ETH_ALEN]; + u8 algorithm; + u8 key[16]; +}; + +struct set_stakey_rsp { + u8 addr[ETH_ALEN]; + u8 keyid; + u8 rsvd; +}; + +struct SetMacAddr_param { + u8 MacAddr[ETH_ALEN]; +}; + +/* +Caller Ad-Hoc/AP + +Command -Rsp(AID == CAMID) mode + +This is to force fw to add an sta_data entry per driver's request. + +FW will write an cam entry associated with it. + +*/ +struct set_assocsta_parm { + u8 addr[ETH_ALEN]; +}; + +struct set_assocsta_rsp { + u8 cam_id; + u8 rsvd[3]; +}; + +/* + Caller Ad-Hoc/AP + + Command mode + + This is to force fw to del an sta_data entry per driver's request + + FW will invalidate the cam entry associated with it. + +*/ +struct del_assocsta_parm { + u8 addr[ETH_ALEN]; +}; + +/* +Caller Mode: AP/Ad-HoC(M) + +Notes: To notify fw that given staid has changed its power state + +Command Mode + +*/ +struct setstapwrstate_parm { + u8 staid; + u8 status; + u8 hwaddr[6]; +}; + +/* +Caller Mode: Any + +Notes: To setup the basic rate of RTL8711 + +Command Mode + +*/ +struct setbasicrate_parm { + u8 basicrates[NumRates]; +}; + +/* +Caller Mode: Any + +Notes: To read the current basic rate + +Command-Rsp Mode + +*/ +struct getbasicrate_parm { + u32 rsvd; +}; + +struct getbasicrate_rsp { + u8 basicrates[NumRates]; +}; + +/* +Caller Mode: Any + +Notes: To setup the data rate of RTL8711 + +Command Mode + +*/ +struct setdatarate_parm { + u8 mac_id; + u8 datarates[NumRates]; +}; + +enum _RT_CHANNEL_DOMAIN { + RT_CHANNEL_DOMAIN_FCC = 0, + RT_CHANNEL_DOMAIN_IC = 1, + RT_CHANNEL_DOMAIN_ETSI = 2, + RT_CHANNEL_DOMAIN_SPAIN = 3, + RT_CHANNEL_DOMAIN_FRANCE = 4, + RT_CHANNEL_DOMAIN_MKK = 5, + RT_CHANNEL_DOMAIN_MKK1 = 6, + RT_CHANNEL_DOMAIN_ISRAEL = 7, + RT_CHANNEL_DOMAIN_TELEC = 8, + + /* Be compatible with old channel plan. No good! */ + RT_CHANNEL_DOMAIN_MIC = 9, + RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 10, + RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 11, + RT_CHANNEL_DOMAIN_TELEC_NETGEAR = 12, + + RT_CHANNEL_DOMAIN_NCC = 13, + RT_CHANNEL_DOMAIN_5G = 14, + RT_CHANNEL_DOMAIN_5G_40M = 15, + /*===== Add new channel plan above this line===============*/ + RT_CHANNEL_DOMAIN_MAX, +}; + + +struct SetChannelPlan_param { + enum _RT_CHANNEL_DOMAIN ChannelPlan; +}; + +/* +Caller Mode: Any + +Notes: To read the current data rate + +Command-Rsp Mode + +*/ +struct getdatarate_parm { + u32 rsvd; + +}; +struct getdatarate_rsp { + u8 datarates[NumRates]; +}; + + +/* +Caller Mode: Any +AP: AP can use the info for the contents of beacon frame +Infra: STA can use the info when sitesurveying +Ad-HoC(M): Like AP +Ad-HoC(C): Like STA + + +Notes: To set the phy capability of the NIC + +Command Mode + +*/ + +/* +Caller Mode: Any + +Notes: To set the channel/modem/band +This command will be used when channel/modem/band is changed. + +Command Mode + +*/ +/* +Caller Mode: Any + +Notes: To get the current setting of channel/modem/band + +Command-Rsp Mode + +*/ +struct getphy_rsp { + u8 rfchannel; + u8 modem; +}; + +struct readBB_parm { + u8 offset; +}; +struct readBB_rsp { + u8 value; +}; + +struct readTSSI_parm { + u8 offset; +}; +struct readTSSI_rsp { + u8 value; +}; + +struct writeBB_parm { + u8 offset; + u8 value; +}; + +struct writePTM_parm { + u8 type; +}; + +struct readRF_parm { + u8 offset; +}; +struct readRF_rsp { + u32 value; +}; + +struct writeRF_parm { + u32 offset; + u32 value; +}; + +struct setrfintfs_parm { + u8 rfintfs; +}; + +struct getrfintfs_parm { + u8 rfintfs; +}; + +/* + Notes: This command is used for H2C/C2H loopback testing + + mac[0] == 0 + ==> CMD mode, return H2C_SUCCESS. + The following condition must be ture under CMD mode + mac[1] == mac[4], mac[2] == mac[3], mac[0]=mac[5]= 0; + s0 == 0x1234, s1 == 0xabcd, w0 == 0x78563412, w1 == 0x5aa5def7; + s2 == (b1 << 8 | b0); + + mac[0] == 1 + ==> CMD_RSP mode, return H2C_SUCCESS_RSP + + The rsp layout shall be: + rsp: parm: + mac[0] = mac[5]; + mac[1] = mac[4]; + mac[2] = mac[3]; + mac[3] = mac[2]; + mac[4] = mac[1]; + mac[5] = mac[0]; + s0 = s1; + s1 = swap16(s0); + w0 = swap32(w1); + b0 = b1 + s2 = s0 + s1 + b1 = b0 + w1 = w0 + + mac[0] == 2 + ==> CMD_EVENT mode, return H2C_SUCCESS + The event layout shall be: + event: parm: + mac[0] = mac[5]; + mac[1] = mac[4]; + mac[2] = event's sequence number, starting from 1 to parm's marc[3] + mac[3] = mac[2]; + mac[4] = mac[1]; + mac[5] = mac[0]; + s0 = swap16(s0) - event.mac[2]; + s1 = s1 + event.mac[2]; + w0 = swap32(w0); + b0 = b1 + s2 = s0 + event.mac[2] + b1 = b0 + w1 = swap32(w1) - event.mac[2]; + + parm->mac[3] is the total event counts that host requested. + + + event will be the same with the cmd's param. + +*/ + +/* CMD param Formart for DRV INTERNAL CMD HDL*/ +struct drvint_cmd_parm { + int i_cid; /*internal cmd id*/ + int sz; /* buf sz*/ + unsigned char *pbuf; +}; + +/*------------------- Below are used for RF/BB tunning ---------------------*/ + +struct setantenna_parm { + u8 tx_antset; + u8 rx_antset; + u8 tx_antenna; + u8 rx_antenna; +}; + +struct enrateadaptive_parm { + u32 en; +}; + +struct settxagctbl_parm { + u32 txagc[MAX_RATES_LENGTH]; +}; + +struct gettxagctbl_parm { + u32 rsvd; +}; +struct gettxagctbl_rsp { + u32 txagc[MAX_RATES_LENGTH]; +}; + +struct setagcctrl_parm { + u32 agcctrl; /* 0: pure hw, 1: fw */ +}; + +struct setssup_parm { + u32 ss_ForceUp[MAX_RATES_LENGTH]; +}; + +struct getssup_parm { + u32 rsvd; +}; +struct getssup_rsp { + u8 ss_ForceUp[MAX_RATES_LENGTH]; +}; + +struct setssdlevel_parm { + u8 ss_DLevel[MAX_RATES_LENGTH]; +}; + +struct getssdlevel_parm { + u32 rsvd; +}; +struct getssdlevel_rsp { + u8 ss_DLevel[MAX_RATES_LENGTH]; +}; + +struct setssulevel_parm { + u8 ss_ULevel[MAX_RATES_LENGTH]; +}; + +struct getssulevel_parm { + u32 rsvd; +}; +struct getssulevel_rsp { + u8 ss_ULevel[MAX_RATES_LENGTH]; +}; + +struct setcountjudge_parm { + u8 count_judge[MAX_RATES_LENGTH]; +}; + +struct getcountjudge_parm { + u32 rsvd; +}; + +struct getcountjudge_rsp { + u8 count_judge[MAX_RATES_LENGTH]; +}; + +struct setpwrmode_parm { + u8 mode; + u8 flag_low_traffic_en; + u8 flag_lpnav_en; + u8 flag_rf_low_snr_en; + u8 flag_dps_en; /* 1: dps, 0: 32k */ + u8 bcn_rx_en; + u8 bcn_pass_cnt; /* fw report one beacon information to + * driver when it receives bcn_pass_cnt + * beacons. */ + u8 bcn_to; /* beacon TO (ms). ¡§=0¡¨ no limit.*/ + u16 bcn_itv; + u8 app_itv; /* only for VOIP mode. */ + u8 awake_bcn_itv; + u8 smart_ps; + u8 bcn_pass_time; /* unit: 100ms */ +}; + +struct setatim_parm { + u8 op; /*0: add, 1:del*/ + u8 txid; /* id of dest station.*/ +}; + +struct setratable_parm { + u8 ss_ForceUp[NumRates]; + u8 ss_ULevel[NumRates]; + u8 ss_DLevel[NumRates]; + u8 count_judge[NumRates]; +}; + +struct getratable_parm { + uint rsvd; +}; +struct getratable_rsp { + u8 ss_ForceUp[NumRates]; + u8 ss_ULevel[NumRates]; + u8 ss_DLevel[NumRates]; + u8 count_judge[NumRates]; +}; + +/*to get TX,RX retry count*/ +struct gettxretrycnt_parm { + unsigned int rsvd; +}; + +struct gettxretrycnt_rsp { + unsigned long tx_retrycnt; +}; + +struct getrxretrycnt_parm { + unsigned int rsvd; +}; + +struct getrxretrycnt_rsp { + unsigned long rx_retrycnt; +}; + +/*to get BCNOK,BCNERR count*/ +struct getbcnokcnt_parm { + unsigned int rsvd; +}; + +struct getbcnokcnt_rsp { + unsigned long bcnokcnt; +}; + +struct getbcnerrcnt_parm { + unsigned int rsvd; +}; +struct getbcnerrcnt_rsp { + unsigned long bcnerrcnt; +}; + +/* to get current TX power level*/ +struct getcurtxpwrlevel_parm { + unsigned int rsvd; +}; + +struct getcurtxpwrlevel_rsp { + unsigned short tx_power; +}; + +/*dynamic on/off DIG*/ +struct setdig_parm { + unsigned char dig_on; /* 1:on , 0:off */ +}; + +/*dynamic on/off RA*/ +struct setra_parm { + unsigned char ra_on; /* 1:on , 0:off */ +}; + +struct setprobereqextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct setassocreqextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct setproberspextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct setassocrspextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct addBaReq_parm { + unsigned int tid; +}; + +/*H2C Handler index: 46 */ +struct SetChannel_parm { + u32 curr_ch; +}; + +/*H2C Handler index: 61 */ +struct DisconnectCtrlEx_param { + /* MAXTIME = (2 * FirstStageTO) + (TryPktCnt * TryPktInterval) */ + unsigned char EnableDrvCtrl; + unsigned char TryPktCnt; + unsigned char TryPktInterval; /* Unit: ms */ + unsigned char rsvd; + unsigned int FirstStageTO; /* Unit: ms */ +}; + +#define GEN_CMD_CODE(cmd) cmd ## _CMD_ + +/* + * Result: + * 0x00: success + * 0x01: success, and check Response. + * 0x02: cmd ignored due to duplicated sequence number + * 0x03: cmd dropped due to invalid cmd code + * 0x04: reserved. + */ + +#define H2C_RSP_OFFSET 512 +#define H2C_SUCCESS 0x00 +#define H2C_SUCCESS_RSP 0x01 +#define H2C_DUPLICATED 0x02 +#define H2C_DROPPED 0x03 +#define H2C_PARAMETERS_ERROR 0x04 +#define H2C_REJECTED 0x05 +#define H2C_CMD_OVERFLOW 0x06 +#define H2C_RESERVED 0x07 + +u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr); +u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr); +u8 r8712_sitesurvey_cmd(struct _adapter *padapter, + struct ndis_802_11_ssid *pssid); +u8 r8712_createbss_cmd(struct _adapter *padapter); +u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key); +u8 r8712_joinbss_cmd(struct _adapter *padapter, + struct wlan_network *pnetwork); +u8 r8712_disassoc_cmd(struct _adapter *padapter); +u8 r8712_setopmode_cmd(struct _adapter *padapter, + enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype); +u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset); +u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan); +u8 r8712_setbasicrate_cmd(struct _adapter *padapter, u8 *rateset); +u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval); +u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode); +u8 r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val); +u8 r8712_setrttbl_cmd(struct _adapter *padapter, + struct setratable_parm *prate_table); +u8 r8712_gettssi_cmd(struct _adapter *padapter, u8 offset, u8 *pval); +u8 r8712_setptm_cmd(struct _adapter *padapter, u8 type); +u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type); +u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type); +u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid); +u8 r8712_wdg_wk_cmd(struct _adapter *padapter); +void r8712_survey_cmd_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +void r8712_disassoc_cmd_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +void r8712_joinbss_cmd_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +void r8712_createbss_cmd_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter, + struct cmd_obj *pcmd); +u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, + u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO); + +struct _cmd_callback { + u32 cmd_code; + void (*callback)(struct _adapter *padapter, struct cmd_obj *cmd); +}; + +#include "rtl8712_cmd.h" + +#endif /* _CMD_H_ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_debug.h b/kernel/drivers/staging/rtl8712/rtl871x_debug.h new file mode 100644 index 000000000..74468b058 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_debug.h @@ -0,0 +1,167 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL871X_DEBUG_H__ +#define __RTL871X_DEBUG_H__ + +#include "osdep_service.h" +#include "drv_types.h" + + +#define _drv_emerg_ 1 +#define _drv_alert_ 2 +#define _drv_crit_ 3 +#define _drv_err_ 4 +#define _drv_warning_ 5 +#define _drv_notice_ 6 +#define _drv_info_ 7 +#define _drv_dump_ 8 +#define _drv_debug_ 9 + + +#define _module_rtl871x_xmit_c_ BIT(0) +#define _module_xmit_osdep_c_ BIT(1) +#define _module_rtl871x_recv_c_ BIT(2) +#define _module_recv_osdep_c_ BIT(3) +#define _module_rtl871x_mlme_c_ BIT(4) +#define _module_mlme_osdep_c_ BIT(5) +#define _module_rtl871x_sta_mgt_c_ BIT(6) +#define _module_rtl871x_cmd_c_ BIT(7) +#define _module_cmd_osdep_c_ BIT(8) +#define _module_rtl871x_io_c_ BIT(9) +#define _module_io_osdep_c_ BIT(10) +#define _module_os_intfs_c_ BIT(11) +#define _module_rtl871x_security_c_ BIT(12) +#define _module_rtl871x_eeprom_c_ BIT(13) +#define _module_hal_init_c_ BIT(14) +#define _module_hci_hal_init_c_ BIT(15) +#define _module_rtl871x_ioctl_c_ BIT(16) +#define _module_rtl871x_ioctl_set_c_ BIT(17) +#define _module_rtl871x_pwrctrl_c_ BIT(19) +#define _module_hci_intfs_c_ BIT(20) +#define _module_hci_ops_c_ BIT(21) +#define _module_osdep_service_c_ BIT(22) +#define _module_rtl871x_mp_ioctl_c_ BIT(23) +#define _module_hci_ops_os_c_ BIT(24) +#define _module_rtl871x_ioctl_os_c BIT(25) +#define _module_rtl8712_cmd_c_ BIT(26) +#define _module_rtl871x_mp_c_ BIT(27) +#define _module_rtl8712_xmit_c_ BIT(28) +#define _module_rtl8712_efuse_c_ BIT(29) +#define _module_rtl8712_recv_c_ BIT(30) +#define _module_rtl8712_led_c_ BIT(31) + +#undef _MODULE_DEFINE_ + +#if defined _RTL871X_XMIT_C_ + #define _MODULE_DEFINE_ _module_rtl871x_xmit_c_ +#elif defined _XMIT_OSDEP_C_ + #define _MODULE_DEFINE_ _module_xmit_osdep_c_ +#elif defined _RTL871X_RECV_C_ + #define _MODULE_DEFINE_ _module_rtl871x_recv_c_ +#elif defined _RECV_OSDEP_C_ + #define _MODULE_DEFINE_ _module_recv_osdep_c_ +#elif defined _RTL871X_MLME_C_ + #define _MODULE_DEFINE_ _module_rtl871x_mlme_c_ +#elif defined _MLME_OSDEP_C_ + #define _MODULE_DEFINE_ _module_mlme_osdep_c_ +#elif defined _RTL871X_STA_MGT_C_ + #define _MODULE_DEFINE_ _module_rtl871x_sta_mgt_c_ +#elif defined _RTL871X_CMD_C_ + #define _MODULE_DEFINE_ _module_rtl871x_cmd_c_ +#elif defined _CMD_OSDEP_C_ + #define _MODULE_DEFINE_ _module_cmd_osdep_c_ +#elif defined _RTL871X_IO_C_ + #define _MODULE_DEFINE_ _module_rtl871x_io_c_ +#elif defined _IO_OSDEP_C_ + #define _MODULE_DEFINE_ _module_io_osdep_c_ +#elif defined _OS_INTFS_C_ + #define _MODULE_DEFINE_ _module_os_intfs_c_ +#elif defined _RTL871X_SECURITY_C_ + #define _MODULE_DEFINE_ _module_rtl871x_security_c_ +#elif defined _RTL871X_EEPROM_C_ + #define _MODULE_DEFINE_ _module_rtl871x_eeprom_c_ +#elif defined _HAL_INIT_C_ + #define _MODULE_DEFINE_ _module_hal_init_c_ +#elif defined _HCI_HAL_INIT_C_ + #define _MODULE_DEFINE_ _module_hci_hal_init_c_ +#elif defined _RTL871X_IOCTL_C_ + #define _MODULE_DEFINE_ _module_rtl871x_ioctl_c_ +#elif defined _RTL871X_IOCTL_SET_C_ + #define _MODULE_DEFINE_ _module_rtl871x_ioctl_set_c_ +#elif defined _RTL871X_PWRCTRL_C_ + #define _MODULE_DEFINE_ _module_rtl871x_pwrctrl_c_ +#elif defined _HCI_INTF_C_ + #define _MODULE_DEFINE_ _module_hci_intfs_c_ +#elif defined _HCI_OPS_C_ + #define _MODULE_DEFINE_ _module_hci_ops_c_ +#elif defined _OSDEP_HCI_INTF_C_ + #define _MODULE_DEFINE_ _module_hci_intfs_c_ +#elif defined _OSDEP_SERVICE_C_ + #define _MODULE_DEFINE_ _module_osdep_service_c_ +#elif defined _RTL871X_MP_IOCTL_C_ + #define _MODULE_DEFINE_ _module_rtl871x_mp_ioctl_c_ +#elif defined _HCI_OPS_OS_C_ + #define _MODULE_DEFINE_ _module_hci_ops_os_c_ +#elif defined _RTL871X_IOCTL_LINUX_C_ + #define _MODULE_DEFINE_ _module_rtl871x_ioctl_os_c +#elif defined _RTL871X_MP_C_ + #define _MODULE_DEFINE_ _module_rtl871x_mp_c_ +#elif defined _RTL8712_CMD_C_ + #define _MODULE_DEFINE_ _module_rtl8712_cmd_c_ +#elif defined _RTL8712_XMIT_C_ + #define _MODULE_DEFINE_ _module_rtl8712_xmit_c_ +#elif defined _RTL8712_EFUSE_C_ + #define _MODULE_DEFINE_ _module_rtl8712_efuse_c_ +#elif defined _RTL8712_RECV_C_ + #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ +#else + #undef _MODULE_DEFINE_ +#endif + +#define _dbgdump printk + +#define MSG_8712(x, ...) {} + +#define DBG_8712(x, ...) {} + +#define WRN_8712(x, ...) {} + +#define ERR_8712(x, ...) {} + +#undef MSG_8712 +#define MSG_8712 _dbgdump + +#undef DBG_8712 +#define DBG_8712 _dbgdump + +#undef WRN_8712 +#define WRN_8712 _dbgdump + +#undef ERR_8712 +#define ERR_8712 _dbgdump + +#endif /*__RTL871X_DEBUG_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_eeprom.c b/kernel/drivers/staging/rtl8712/rtl871x_eeprom.c new file mode 100644 index 000000000..50339e67d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_eeprom.c @@ -0,0 +1,233 @@ +/****************************************************************************** + * rtl871x_eeprom.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_EEPROM_C_ + +#include "osdep_service.h" +#include "drv_types.h" + +static void up_clk(struct _adapter *padapter, u16 *x) +{ + *x = *x | _EESK; + r8712_write8(padapter, EE_9346CR, (u8)*x); + udelay(CLOCK_RATE); +} + +static void down_clk(struct _adapter *padapter, u16 *x) +{ + *x = *x & ~_EESK; + r8712_write8(padapter, EE_9346CR, (u8)*x); + udelay(CLOCK_RATE); +} + +static void shift_out_bits(struct _adapter *padapter, u16 data, u16 count) +{ + u16 x, mask; + + if (padapter->bSurpriseRemoved == true) + goto out; + mask = 0x01 << (count - 1); + x = r8712_read8(padapter, EE_9346CR); + x &= ~(_EEDO | _EEDI); + do { + x &= ~_EEDI; + if (data & mask) + x |= _EEDI; + if (padapter->bSurpriseRemoved == true) + goto out; + r8712_write8(padapter, EE_9346CR, (u8)x); + udelay(CLOCK_RATE); + up_clk(padapter, &x); + down_clk(padapter, &x); + mask >>= 1; + } while (mask); + if (padapter->bSurpriseRemoved == true) + goto out; + x &= ~_EEDI; + r8712_write8(padapter, EE_9346CR, (u8)x); +out:; +} + +static u16 shift_in_bits(struct _adapter *padapter) +{ + u16 x, d = 0, i; + + if (padapter->bSurpriseRemoved == true) + goto out; + x = r8712_read8(padapter, EE_9346CR); + x &= ~(_EEDO | _EEDI); + d = 0; + for (i = 0; i < 16; i++) { + d <<= 1; + up_clk(padapter, &x); + if (padapter->bSurpriseRemoved == true) + goto out; + x = r8712_read8(padapter, EE_9346CR); + x &= ~(_EEDI); + if (x & _EEDO) + d |= 1; + down_clk(padapter, &x); + } +out: + return d; +} + +static void standby(struct _adapter *padapter) +{ + u8 x; + + x = r8712_read8(padapter, EE_9346CR); + x &= ~(_EECS | _EESK); + r8712_write8(padapter, EE_9346CR, x); + udelay(CLOCK_RATE); + x |= _EECS; + r8712_write8(padapter, EE_9346CR, x); + udelay(CLOCK_RATE); +} + +static u16 wait_eeprom_cmd_done(struct _adapter *padapter) +{ + u8 x; + u16 i; + + standby(padapter); + for (i = 0; i < 200; i++) { + x = r8712_read8(padapter, EE_9346CR); + if (x & _EEDO) + return true; + udelay(CLOCK_RATE); + } + return false; +} + +static void eeprom_clean(struct _adapter *padapter) +{ + u16 x; + + if (padapter->bSurpriseRemoved == true) + return; + x = r8712_read8(padapter, EE_9346CR); + if (padapter->bSurpriseRemoved == true) + return; + x &= ~(_EECS | _EEDI); + r8712_write8(padapter, EE_9346CR, (u8)x); + if (padapter->bSurpriseRemoved == true) + return; + up_clk(padapter, &x); + if (padapter->bSurpriseRemoved == true) + return; + down_clk(padapter, &x); +} + +void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data) +{ + u8 x; + u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; + + tmp8_ori = r8712_read8(padapter, 0x102502f1); + tmp8_new = tmp8_ori & 0xf7; + if (tmp8_ori != tmp8_new) + r8712_write8(padapter, 0x102502f1, tmp8_new); + tmp8_clk_ori = r8712_read8(padapter, 0x10250003); + tmp8_clk_new = tmp8_clk_ori | 0x20; + if (tmp8_clk_new != tmp8_clk_ori) + r8712_write8(padapter, 0x10250003, tmp8_clk_new); + x = r8712_read8(padapter, EE_9346CR); + x &= ~(_EEDI | _EEDO | _EESK | _EEM0); + x |= _EEM1 | _EECS; + r8712_write8(padapter, EE_9346CR, x); + shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5); + if (padapter->EepromAddressSize == 8) /*CF+ and SDIO*/ + shift_out_bits(padapter, 0, 6); + else /* USB */ + shift_out_bits(padapter, 0, 4); + standby(padapter); + /* Erase this particular word. Write the erase opcode and register + * number in that order. The opcode is 3bits in length; reg is 6 + * bits long. + */ + standby(padapter); + /* write the new word to the EEPROM + * send the write opcode the EEPORM + */ + shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3); + /* select which word in the EEPROM that we are writing to. */ + shift_out_bits(padapter, reg, padapter->EepromAddressSize); + /* write the data to the selected EEPROM word. */ + shift_out_bits(padapter, data, 16); + if (wait_eeprom_cmd_done(padapter)) { + standby(padapter); + shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5); + shift_out_bits(padapter, reg, 4); + eeprom_clean(padapter); + } + if (tmp8_clk_new != tmp8_clk_ori) + r8712_write8(padapter, 0x10250003, tmp8_clk_ori); + if (tmp8_new != tmp8_ori) + r8712_write8(padapter, 0x102502f1, tmp8_ori); +} + +u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg) /*ReadEEprom*/ +{ + u16 x; + u16 data = 0; + u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; + + tmp8_ori = r8712_read8(padapter, 0x102502f1); + tmp8_new = tmp8_ori & 0xf7; + if (tmp8_ori != tmp8_new) + r8712_write8(padapter, 0x102502f1, tmp8_new); + tmp8_clk_ori = r8712_read8(padapter, 0x10250003); + tmp8_clk_new = tmp8_clk_ori | 0x20; + if (tmp8_clk_new != tmp8_clk_ori) + r8712_write8(padapter, 0x10250003, tmp8_clk_new); + if (padapter->bSurpriseRemoved == true) + goto out; + /* select EEPROM, reset bits, set _EECS */ + x = r8712_read8(padapter, EE_9346CR); + if (padapter->bSurpriseRemoved == true) + goto out; + x &= ~(_EEDI | _EEDO | _EESK | _EEM0); + x |= _EEM1 | _EECS; + r8712_write8(padapter, EE_9346CR, (unsigned char)x); + /* write the read opcode and register number in that order + * The opcode is 3bits in length, reg is 6 bits long + */ + shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); + shift_out_bits(padapter, reg, padapter->EepromAddressSize); + /* Now read the data (16 bits) in from the selected EEPROM word */ + data = shift_in_bits(padapter); + eeprom_clean(padapter); +out: + if (tmp8_clk_new != tmp8_clk_ori) + r8712_write8(padapter, 0x10250003, tmp8_clk_ori); + if (tmp8_new != tmp8_ori) + r8712_write8(padapter, 0x102502f1, tmp8_ori); + return data; +} + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_eeprom.h b/kernel/drivers/staging/rtl8712/rtl871x_eeprom.h new file mode 100644 index 000000000..497276e53 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_eeprom.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __RTL871X_EEPROM_H__ +#define __RTL871X_EEPROM_H__ + +#include "osdep_service.h" + +#define RTL8712_EEPROM_ID 0x8712 +#define EEPROM_MAX_SIZE 256 +#define CLOCK_RATE 50 /*100us*/ + +/*- EEPROM opcodes*/ +#define EEPROM_READ_OPCODE 06 +#define EEPROM_WRITE_OPCODE 05 +#define EEPROM_ERASE_OPCODE 07 +#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable*/ +#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable*/ + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_ALPHA 0x1 +#define EEPROM_CID_Senao 0x3 +#define EEPROM_CID_NetCore 0x5 +#define EEPROM_CID_CAMEO 0X8 +#define EEPROM_CID_SITECOM 0x9 +#define EEPROM_CID_COREGA 0xB +#define EEPROM_CID_EDIMAX_BELKIN 0xC +#define EEPROM_CID_SERCOMM_BELKIN 0xE +#define EEPROM_CID_CAMEO1 0xF +#define EEPROM_CID_WNC_COREGA 0x12 +#define EEPROM_CID_CLEVO 0x13 +#define EEPROM_CID_WHQL 0xFE + +enum RT_CUSTOMER_ID { + RT_CID_DEFAULT = 0, + RT_CID_8187_ALPHA0 = 1, + RT_CID_8187_SERCOMM_PS = 2, + RT_CID_8187_HW_LED = 3, + RT_CID_8187_NETGEAR = 4, + RT_CID_WHQL = 5, + RT_CID_819x_CAMEO = 6, + RT_CID_819x_RUNTOP = 7, + RT_CID_819x_Senao = 8, + RT_CID_TOSHIBA = 9, + RT_CID_819x_Netcore = 10, + RT_CID_Nettronix = 11, + RT_CID_DLINK = 12, + RT_CID_PRONET = 13, + RT_CID_COREGA = 14, + RT_CID_819x_ALPHA = 15, + RT_CID_819x_Sitecom = 16, + RT_CID_CCX = 17, + RT_CID_819x_Lenovo = 18, + RT_CID_819x_QMI = 19, + RT_CID_819x_Edimax_Belkin = 20, + RT_CID_819x_Sercomm_Belkin = 21, + RT_CID_819x_CAMEO1 = 22, + RT_CID_819x_MSI = 23, + RT_CID_819x_Acer = 24, + RT_CID_819x_AzWave_ASUS = 25, + RT_CID_819x_AzWave = 26, + RT_CID_819x_WNC_COREGA = 27, + RT_CID_819x_CLEVO = 28, +}; + +struct eeprom_priv { + u8 bautoload_fail_flag; + u8 bempty; + u8 sys_config; + u8 mac_addr[6]; + u8 config0; + u16 channel_plan; + u8 country_string[3]; + u8 tx_power_b[15]; + u8 tx_power_g[15]; + u8 tx_power_a[201]; + u8 efuse_eeprom_data[EEPROM_MAX_SIZE]; + enum RT_CUSTOMER_ID CustomerID; +}; + +void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data); +u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg); + +#endif /*__RTL871X_EEPROM_H__*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_event.h b/kernel/drivers/staging/rtl8712/rtl871x_event.h new file mode 100644 index 000000000..e03ee90d2 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_event.h @@ -0,0 +1,120 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL871x_EVENT_H_ +#define _RTL871x_EVENT_H_ + +#include "osdep_service.h" + +#include "wlan_bssdef.h" +#include <linux/semaphore.h> +#include <linux/sem.h> + +/* + * Used to report a bss has been scanned +*/ +struct survey_event { + struct ndis_wlan_bssid_ex bss; +}; + +/* + * Used to report that the requested site survey has been done. + * bss_cnt indicates the number of bss that has been reported. +*/ +struct surveydone_event { + unsigned int bss_cnt; + +}; + +/* + * Used to report the link result of joinning the given bss + * join_res: + * -1: authentication fail + * -2: association fail + * > 0: TID +*/ +struct joinbss_event { + struct wlan_network network; +}; + +/* + * Used to report a given STA has joinned the created BSS. + * It is used in AP/Ad-HoC(M) mode. +*/ +struct stassoc_event { + unsigned char macaddr[6]; + unsigned char rsvd[2]; + int cam_id; +}; + +struct stadel_event { + unsigned char macaddr[6]; + unsigned char rsvd[2]; +}; + +struct addba_event { + unsigned int tid; +}; + +#define GEN_EVT_CODE(event) event ## _EVT_ + +struct fwevent { + u32 parmsize; + void (*event_callback)(struct _adapter *dev, u8 *pbuf); +}; + +#define C2HEVENT_SZ 32 +struct event_node { + unsigned char *node; + unsigned char evt_code; + unsigned short evt_sz; + /*volatile*/ int *caller_ff_tail; + int caller_ff_sz; +}; + +struct c2hevent_queue { + /*volatile*/ int head; + /*volatile*/ int tail; + struct event_node nodes[C2HEVENT_SZ]; + unsigned char seq; +}; + +#define NETWORK_QUEUE_SZ 4 + +struct network_queue { + /*volatile*/ int head; + /*volatile*/ int tail; + struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ]; +}; + +struct ADDBA_Req_Report_parm { + unsigned char MacAddress[ETH_ALEN]; + unsigned short StartSeqNum; + unsigned char tid; +}; +#include "rtl8712_event.h" + +#endif /* _WLANEVENT_H_ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_ht.h b/kernel/drivers/staging/rtl8712/rtl871x_ht.h new file mode 100644 index 000000000..41872d937 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_ht.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL871X_HT_H_ +#define _RTL871X_HT_H_ + +#include "osdep_service.h" +#include "wifi.h" + +struct ht_priv { + unsigned int ht_option; + unsigned int ampdu_enable;/*for enable Tx A-MPDU*/ + unsigned char baddbareq_issued[16]; + unsigned int tx_amsdu_enable;/*for enable Tx A-MSDU */ + unsigned int tx_amdsu_maxlen; /* 1: 8k, 0:4k ; default:8k, for tx */ + unsigned int rx_ampdu_maxlen; /* for rx reordering ctrl win_sz, + * updated when join_callback. */ + struct ieee80211_ht_cap ht_cap; +}; + +#endif /*_RTL871X_HT_H_ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_io.c b/kernel/drivers/staging/rtl8712/rtl871x_io.c new file mode 100644 index 000000000..e4e5b13cb --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_io.c @@ -0,0 +1,161 @@ +/****************************************************************************** + * rtl871x_io.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +/* + * + * The purpose of rtl871x_io.c + * + * a. provides the API + * b. provides the protocol engine + * c. provides the software interface between caller and the hardware interface + * + * For r8712u, both sync/async operations are provided. + * + * Only sync read/write_mem operations are provided. + * + */ + +#define _RTL871X_IO_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "rtl871x_io.h" +#include "osdep_intf.h" +#include "usb_ops.h" + +static uint _init_intf_hdl(struct _adapter *padapter, + struct intf_hdl *pintf_hdl) +{ + struct intf_priv *pintf_priv; + void (*set_intf_option)(u32 *poption) = NULL; + void (*set_intf_funs)(struct intf_hdl *pintf_hdl); + void (*set_intf_ops)(struct _io_ops *pops); + uint (*init_intf_priv)(struct intf_priv *pintfpriv); + + set_intf_option = &(r8712_usb_set_intf_option); + set_intf_funs = &(r8712_usb_set_intf_funs); + set_intf_ops = &r8712_usb_set_intf_ops; + init_intf_priv = &r8712_usb_init_intf_priv; + pintf_priv = pintf_hdl->pintfpriv = kmalloc(sizeof(struct intf_priv), + GFP_ATOMIC); + if (pintf_priv == NULL) + goto _init_intf_hdl_fail; + pintf_hdl->adapter = (u8 *)padapter; + set_intf_option(&pintf_hdl->intf_option); + set_intf_funs(pintf_hdl); + set_intf_ops(&pintf_hdl->io_ops); + pintf_priv->intf_dev = (u8 *)&(padapter->dvobjpriv); + if (init_intf_priv(pintf_priv) == _FAIL) + goto _init_intf_hdl_fail; + return _SUCCESS; +_init_intf_hdl_fail: + kfree(pintf_priv); + return _FAIL; +} + +static void _unload_intf_hdl(struct intf_priv *pintfpriv) +{ + void (*unload_intf_priv)(struct intf_priv *pintfpriv); + + unload_intf_priv = &r8712_usb_unload_intf_priv; + unload_intf_priv(pintfpriv); + kfree(pintfpriv); +} + +static uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl) +{ + struct _adapter *adapter = (struct _adapter *)dev; + + pintfhdl->intf_option = 0; + pintfhdl->adapter = dev; + pintfhdl->intf_dev = (u8 *)&(adapter->dvobjpriv); + if (!_init_intf_hdl(adapter, pintfhdl)) + goto register_intf_hdl_fail; + return _SUCCESS; +register_intf_hdl_fail: + return false; +} + +static void unregister_intf_hdl(struct intf_hdl *pintfhdl) +{ + _unload_intf_hdl(pintfhdl->pintfpriv); + memset((u8 *)pintfhdl, 0, sizeof(struct intf_hdl)); +} + +uint r8712_alloc_io_queue(struct _adapter *adapter) +{ + u32 i; + struct io_queue *pio_queue; + struct io_req *pio_req; + + pio_queue = kmalloc(sizeof(*pio_queue), GFP_ATOMIC); + if (pio_queue == NULL) + goto alloc_io_queue_fail; + INIT_LIST_HEAD(&pio_queue->free_ioreqs); + INIT_LIST_HEAD(&pio_queue->processing); + INIT_LIST_HEAD(&pio_queue->pending); + spin_lock_init(&pio_queue->lock); + pio_queue->pallocated_free_ioreqs_buf = kmalloc(NUM_IOREQ * + (sizeof(struct io_req)) + 4, + GFP_ATOMIC); + if ((pio_queue->pallocated_free_ioreqs_buf) == NULL) + goto alloc_io_queue_fail; + memset(pio_queue->pallocated_free_ioreqs_buf, 0, + (NUM_IOREQ * (sizeof(struct io_req)) + 4)); + pio_queue->free_ioreqs_buf = pio_queue->pallocated_free_ioreqs_buf + 4 + - ((addr_t)(pio_queue->pallocated_free_ioreqs_buf) + & 3); + pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf); + for (i = 0; i < NUM_IOREQ; i++) { + INIT_LIST_HEAD(&pio_req->list); + list_add_tail(&pio_req->list, &pio_queue->free_ioreqs); + pio_req++; + } + if ((register_intf_hdl((u8 *)adapter, &(pio_queue->intf))) == _FAIL) + goto alloc_io_queue_fail; + adapter->pio_queue = pio_queue; + return _SUCCESS; +alloc_io_queue_fail: + if (pio_queue) { + kfree(pio_queue->pallocated_free_ioreqs_buf); + kfree(pio_queue); + } + adapter->pio_queue = NULL; + return _FAIL; +} + +void r8712_free_io_queue(struct _adapter *adapter) +{ + struct io_queue *pio_queue = (struct io_queue *)(adapter->pio_queue); + + if (pio_queue) { + kfree(pio_queue->pallocated_free_ioreqs_buf); + adapter->pio_queue = NULL; + unregister_intf_hdl(&pio_queue->intf); + kfree(pio_queue); + } +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_io.h b/kernel/drivers/staging/rtl8712/rtl871x_io.h new file mode 100644 index 000000000..070cc03ce --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_io.h @@ -0,0 +1,258 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _IO_H_ +#define _IO_H_ + +#include "osdep_service.h" +#include "osdep_intf.h" + +#define NUM_IOREQ 8 + +#define MAX_PROT_SZ (64-16) + +#define _IOREADY 0 +#define _IO_WAIT_COMPLETE 1 +#define _IO_WAIT_RSP 2 + +/* IO COMMAND TYPE */ +#define _IOSZ_MASK_ (0x7F) +#define _IO_WRITE_ BIT(7) +#define _IO_FIXED_ BIT(8) +#define _IO_BURST_ BIT(9) +#define _IO_BYTE_ BIT(10) +#define _IO_HW_ BIT(11) +#define _IO_WORD_ BIT(12) +#define _IO_SYNC_ BIT(13) +#define _IO_CMDMASK_ (0x1F80) + +/* + For prompt mode accessing, caller shall free io_req + Otherwise, io_handler will free io_req +*/ +/* IO STATUS TYPE */ +#define _IO_ERR_ BIT(2) +#define _IO_SUCCESS_ BIT(1) +#define _IO_DONE_ BIT(0) +#define IO_RD32 (_IO_SYNC_ | _IO_WORD_) +#define IO_RD16 (_IO_SYNC_ | _IO_HW_) +#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_) +#define IO_RD32_ASYNC (_IO_WORD_) +#define IO_RD16_ASYNC (_IO_HW_) +#define IO_RD8_ASYNC (_IO_BYTE_) +#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_) +#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_) +#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_) +#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_) +#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_) +#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_) +/* + Only Sync. burst accessing is provided. +*/ +#define IO_WR_BURST(x) (IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | \ + ((x) & _IOSZ_MASK_)) +#define IO_RD_BURST(x) (_IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_)) +/*below is for the intf_option bit defition...*/ +#define _INTF_ASYNC_ BIT(0) /*support async io*/ +struct intf_priv; +struct intf_hdl; +struct io_queue; +struct _io_ops { + uint (*_sdbus_read_bytes_to_membuf)(struct intf_priv *pintfpriv, + u32 addr, u32 cnt, u8 *pbuf); + uint (*_sdbus_read_blocks_to_membuf)(struct intf_priv *pintfpriv, + u32 addr, u32 cnt, u8 *pbuf); + u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); + u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); + u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); + uint (*_sdbus_write_blocks_from_membuf)(struct intf_priv *pintfpriv, + u32 addr, u32 cnt, u8 *pbuf, + u8 async); + uint (*_sdbus_write_bytes_from_membuf)(struct intf_priv *pintfpriv, + u32 addr, u32 cnt, u8 *pbuf); + u8 (*_cmd52r)(struct intf_priv *pintfpriv, u32 addr); + void (*_cmd52w)(struct intf_priv *pintfpriv, u32 addr, u8 val8); + u8 (*_cmdfunc152r)(struct intf_priv *pintfpriv, u32 addr); + void (*_cmdfunc152w)(struct intf_priv *pintfpriv, u32 addr, u8 val8); + void (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); + void (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); + void (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); + void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); + void (*_sync_irp_protocol_rw)(struct io_queue *pio_q); + u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); + u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + u8 *pmem); +}; + +struct io_req { + struct list_head list; + u32 addr; + /*volatile*/ u32 val; + u32 command; + u32 status; + u8 *pbuf; + void (*_async_io_callback)(struct _adapter *padapter, + struct io_req *pio_req, u8 *cnxt); + u8 *cnxt; +}; + +struct intf_hdl { + u32 intf_option; + u8 *adapter; + u8 *intf_dev; + struct intf_priv *pintfpriv; + void (*intf_hdl_init)(u8 *priv); + void (*intf_hdl_unload)(u8 *priv); + void (*intf_hdl_open)(u8 *priv); + void (*intf_hdl_close)(u8 *priv); + struct _io_ops io_ops; +}; + +struct reg_protocol_rd { + +#ifdef __LITTLE_ENDIAN + /* DW1 */ + u32 NumOfTrans:4; + u32 Reserved1:4; + u32 Reserved2:24; + /* DW2 */ + u32 ByteCount:7; + u32 WriteEnable:1; /*0:read, 1:write*/ + u32 FixOrContinuous:1; /*0:continuous, 1: Fix*/ + u32 BurstMode:1; + u32 Byte1Access:1; + u32 Byte2Access:1; + u32 Byte4Access:1; + u32 Reserved3:3; + u32 Reserved4:16; + /*DW3*/ + u32 BusAddress; + /*DW4*/ +#else +/*DW1*/ + u32 Reserved1:4; + u32 NumOfTrans:4; + u32 Reserved2:24; + /*DW2*/ + u32 WriteEnable:1; + u32 ByteCount:7; + u32 Reserved3:3; + u32 Byte4Access:1; + u32 Byte2Access:1; + u32 Byte1Access:1; + u32 BurstMode:1; + u32 FixOrContinuous:1; + u32 Reserved4:16; + /*DW3*/ + u32 BusAddress; + /*DW4*/ +#endif +}; + +struct reg_protocol_wt { +#ifdef __LITTLE_ENDIAN + /*DW1*/ + u32 NumOfTrans:4; + u32 Reserved1:4; + u32 Reserved2:24; + /*DW2*/ + u32 ByteCount:7; + u32 WriteEnable:1; /*0:read, 1:write*/ + u32 FixOrContinuous:1; /*0:continuous, 1: Fix*/ + u32 BurstMode:1; + u32 Byte1Access:1; + u32 Byte2Access:1; + u32 Byte4Access:1; + u32 Reserved3:3; + u32 Reserved4:16; + /*DW3*/ + u32 BusAddress; + /*DW4*/ + u32 Value; +#else + /*DW1*/ + u32 Reserved1:4; + u32 NumOfTrans:4; + u32 Reserved2:24; + /*DW2*/ + u32 WriteEnable:1; + u32 ByteCount:7; + u32 Reserved3:3; + u32 Byte4Access:1; + u32 Byte2Access:1; + u32 Byte1Access:1; + u32 BurstMode:1; + u32 FixOrContinuous:1; + u32 Reserved4:16; + /*DW3*/ + u32 BusAddress; + /*DW4*/ + u32 Value; +#endif +}; + +/* +Below is the data structure used by _io_handler +*/ + +struct io_queue { + spinlock_t lock; + struct list_head free_ioreqs; + /*The io_req list that will be served in the single protocol r/w.*/ + struct list_head pending; + struct list_head processing; + u8 *free_ioreqs_buf; /* 4-byte aligned */ + u8 *pallocated_free_ioreqs_buf; + struct intf_hdl intf; +}; + +static inline u32 _RND4(u32 sz) +{ + u32 val; + + val = ((sz >> 2) + ((sz & 3) ? 1 : 0)) << 2; + return val; +} + +u8 r8712_read8(struct _adapter *adapter, u32 addr); +u16 r8712_read16(struct _adapter *adapter, u32 addr); +u32 r8712_read32(struct _adapter *adapter, u32 addr); +void r8712_read_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); +void r8712_read_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); +void r8712_write8(struct _adapter *adapter, u32 addr, u8 val); +void r8712_write16(struct _adapter *adapter, u32 addr, u16 val); +void r8712_write32(struct _adapter *adapter, u32 addr, u32 val); +void r8712_write_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); +void r8712_write_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); +/*ioreq */ +uint r8712_alloc_io_queue(struct _adapter *adapter); +void r8712_free_io_queue(struct _adapter *adapter); + +#endif /*_RTL8711_IO_H_*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_ioctl.h b/kernel/drivers/staging/rtl8712/rtl871x_ioctl.h new file mode 100644 index 000000000..8e6ef5d49 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_ioctl.h @@ -0,0 +1,97 @@ +#ifndef __IOCTL_H +#define __IOCTL_H + +#include "osdep_service.h" +#include "drv_types.h" + +#ifndef OID_802_11_CAPABILITY + #define OID_802_11_CAPABILITY 0x0d010122 +#endif + +#ifndef OID_802_11_PMKID + #define OID_802_11_PMKID 0x0d010123 +#endif + + +/* For DDK-defined OIDs*/ +#define OID_NDIS_SEG1 0x00010100 +#define OID_NDIS_SEG2 0x00010200 +#define OID_NDIS_SEG3 0x00020100 +#define OID_NDIS_SEG4 0x01010100 +#define OID_NDIS_SEG5 0x01020100 +#define OID_NDIS_SEG6 0x01020200 +#define OID_NDIS_SEG7 0xFD010100 +#define OID_NDIS_SEG8 0x0D010100 +#define OID_NDIS_SEG9 0x0D010200 +#define OID_NDIS_SEG10 0x0D020200 +#define SZ_OID_NDIS_SEG1 23 +#define SZ_OID_NDIS_SEG2 3 +#define SZ_OID_NDIS_SEG3 6 +#define SZ_OID_NDIS_SEG4 6 +#define SZ_OID_NDIS_SEG5 4 +#define SZ_OID_NDIS_SEG6 8 +#define SZ_OID_NDIS_SEG7 7 +#define SZ_OID_NDIS_SEG8 36 +#define SZ_OID_NDIS_SEG9 24 +#define SZ_OID_NDIS_SEG10 19 + +/* For Realtek-defined OIDs*/ +#define OID_MP_SEG1 0xFF871100 +#define OID_MP_SEG2 0xFF818000 +#define OID_MP_SEG3 0xFF818700 +#define OID_MP_SEG4 0xFF011100 + +enum oid_type { + QUERY_OID, + SET_OID +}; + +struct oid_funs_node { + unsigned int oid_start; /*the starting number for OID*/ + unsigned int oid_end; /*the ending number for OID*/ + struct oid_obj_priv *node_array; + unsigned int array_sz; /*the size of node_array*/ + int query_counter; /*count the number of query hits for this segment*/ + int set_counter; /*count the number of set hits for this segment*/ +}; + +struct oid_par_priv { + void *adapter_context; + uint oid; + void *information_buf; + unsigned long information_buf_len; + unsigned long *bytes_rw; + unsigned long *bytes_needed; + enum oid_type type_of_oid; + unsigned int dbg; +}; + +struct oid_obj_priv { + unsigned char dbg; /* 0: without OID debug message + * 1: with OID debug message */ + uint (*oidfuns)(struct oid_par_priv *poid_par_priv); +}; + +uint oid_null_function(struct oid_par_priv *poid_par_priv); + +extern struct iw_handler_def r871x_handlers_def; + +extern uint drv_query_info( + struct net_device *MiniportAdapterContext, + uint Oid, + void *InformationBuffer, + u32 InformationBufferLength, + u32 *BytesWritten, + u32 *BytesNeeded +); + +extern uint drv_set_info( + struct net_device *MiniportAdapterContext, + uint Oid, + void *InformationBuffer, + u32 InformationBufferLength, + u32 *BytesRead, + u32 *BytesNeeded +); + +#endif diff --git a/kernel/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_linux.c new file mode 100644 index 000000000..cb0b63877 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -0,0 +1,2361 @@ +/****************************************************************************** + * rtl871x_ioctl_linux.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_IOCTL_LINUX_C_ +#define _RTL871X_MP_IOCTL_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "wlan_bssdef.h" +#include "rtl871x_debug.h" +#include "wifi.h" +#include "rtl871x_mlme.h" +#include "rtl871x_ioctl.h" +#include "rtl871x_ioctl_set.h" +#include "rtl871x_mp_ioctl.h" +#include "mlme_osdep.h" +#include <linux/wireless.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/semaphore.h> +#include <net/iw_handler.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> + + +#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 0x1E) + +#define SCAN_ITEM_SIZE 768 +#define MAX_CUSTOM_LEN 64 +#define RATE_COUNT 4 + + +static const u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000, + 6000000, 9000000, 12000000, 18000000, + 24000000, 36000000, 48000000, 54000000}; + +static const long ieee80211_wlan_frequencies[] = { + 2412, 2417, 2422, 2427, + 2432, 2437, 2442, 2447, + 2452, 2457, 2462, 2467, + 2472, 2484 +}; + +static const char * const iw_operation_mode[] = { + "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", + "Monitor" +}; + +/** + * hwaddr_aton - Convert ASCII string to MAC address + * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") + * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) + * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) + */ +static int hwaddr_aton_i(const char *txt, u8 *addr) +{ + int i; + + for (i = 0; i < 6; i++) { + int a, b; + + a = hex_to_bin(*txt++); + if (a < 0) + return -1; + b = hex_to_bin(*txt++); + if (b < 0) + return -1; + *addr++ = (a << 4) | b; + if (i < 5 && *txt++ != ':') + return -1; + } + return 0; +} + +void r8712_indicate_wx_assoc_event(struct _adapter *padapter) +{ + union iwreq_data wrqu; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, + ETH_ALEN); + wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); +} + +void r8712_indicate_wx_disassoc_event(struct _adapter *padapter) +{ + union iwreq_data wrqu; + + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + eth_zero_addr(wrqu.ap_addr.sa_data); + wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); +} + +static inline void handle_pairwise_key(struct sta_info *psta, + struct ieee_param *param, + struct _adapter *padapter) +{ + /* pairwise key */ + memcpy(psta->x_UncstKey.skey, param->u.crypt.key, + (param->u.crypt. key_len > 16 ? 16 : param->u.crypt.key_len)); + if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */ + memcpy(psta->tkiptxmickey. skey, &(param->u.crypt. + key[16]), 8); + memcpy(psta->tkiprxmickey. skey, &(param->u.crypt. + key[24]), 8); + padapter->securitypriv. busetkipkey = false; + mod_timer(&padapter->securitypriv.tkip_timer, + jiffies + msecs_to_jiffies(50)); + } + r8712_setstakey_cmd(padapter, (unsigned char *)psta, true); +} + +static inline void handle_group_key(struct ieee_param *param, + struct _adapter *padapter) +{ + if (0 < param->u.crypt.idx && + param->u.crypt.idx < 3) { + /* group key idx is 1 or 2 */ + memcpy(padapter->securitypriv.XGrpKey[param->u.crypt. + idx-1].skey, param->u.crypt.key, (param->u.crypt.key_len + > 16 ? 16 : param->u.crypt.key_len)); + memcpy(padapter->securitypriv.XGrptxmickey[param-> + u.crypt.idx-1].skey, &(param->u.crypt.key[16]), 8); + memcpy(padapter->securitypriv. XGrprxmickey[param-> + u.crypt.idx-1].skey, &(param->u.crypt.key[24]), 8); + padapter->securitypriv.binstallGrpkey = true; + r8712_set_key(padapter, &padapter->securitypriv, + param->u.crypt.idx); + if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) { + if (padapter->registrypriv.power_mgnt != padapter-> + pwrctrlpriv.pwr_mode) + mod_timer(&padapter->mlmepriv.dhcp_timer, + jiffies + msecs_to_jiffies(60000)); + } + } +} + +static inline char *translate_scan(struct _adapter *padapter, + struct iw_request_info *info, + struct wlan_network *pnetwork, + char *start, char *stop) +{ + struct iw_event iwe; + struct ieee80211_ht_cap *pht_capie; + char *current_val; + s8 *p; + u32 i = 0, ht_ielen = 0; + u16 cap, ht_cap = false, mcs_rate; + u8 rssi; + + if ((pnetwork->network.Configuration.DSConfig < 1) || + (pnetwork->network.Configuration.DSConfig > 14)) { + if (pnetwork->network.Configuration.DSConfig < 1) + pnetwork->network.Configuration.DSConfig = 1; + else + pnetwork->network.Configuration.DSConfig = 14; + } + /* AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + ether_addr_copy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); + /* Add the ESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = min_t(u32, pnetwork->network.Ssid.SsidLength, 32); + start = iwe_stream_add_point(info, start, stop, &iwe, + pnetwork->network.Ssid.Ssid); + /* parsing HT_CAP_IE */ + p = r8712_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, + &ht_ielen, pnetwork->network.IELength - 12); + if (p && ht_ielen > 0) { + ht_cap = true; + pht_capie = (struct ieee80211_ht_cap *)(p + 2); + memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2); + } + /* Add the protocol name */ + iwe.cmd = SIOCGIWNAME; + if ((r8712_is_cckratesonly_included((u8 *)&pnetwork->network. + SupportedRates)) == true) { + if (ht_cap == true) + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); + else + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); + } else if ((r8712_is_cckrates_included((u8 *)&pnetwork->network. + SupportedRates)) == true) { + if (ht_cap == true) + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); + else + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg"); + } else { + if (ht_cap == true) + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); + else + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); + } + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs), + 2); + cap = le16_to_cpu(cap); + if (cap & (WLAN_CAPABILITY_IBSS|WLAN_CAPABILITY_BSS)) { + if (cap & WLAN_CAPABILITY_BSS) + iwe.u.mode = (u32)IW_MODE_MASTER; + else + iwe.u.mode = (u32)IW_MODE_ADHOC; + start = iwe_stream_add_event(info, start, stop, &iwe, + IW_EV_UINT_LEN); + } + /* Add frequency/channel */ + iwe.cmd = SIOCGIWFREQ; + { + /* check legal index */ + u8 dsconfig = pnetwork->network.Configuration.DSConfig; + + if (dsconfig >= 1 && dsconfig <= sizeof( + ieee80211_wlan_frequencies) / sizeof(long)) + iwe.u.freq.m = (s32)(ieee80211_wlan_frequencies[ + pnetwork->network.Configuration. + DSConfig - 1] * 100000); + else + iwe.u.freq.m = 0; + } + iwe.u.freq.e = (s16)1; + iwe.u.freq.i = (u8)pnetwork->network.Configuration.DSConfig; + start = iwe_stream_add_event(info, start, stop, &iwe, + IW_EV_FREQ_LEN); + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (cap & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = (u16)(IW_ENCODE_ENABLED | + IW_ENCODE_NOKEY); + else + iwe.u.data.flags = (u16)(IW_ENCODE_DISABLED); + iwe.u.data.length = (u16)0; + start = iwe_stream_add_point(info, start, stop, &iwe, + pnetwork->network.Ssid.Ssid); + /*Add basic and extended rates */ + current_val = start + iwe_stream_lcp_len(info); + iwe.cmd = SIOCGIWRATE; + iwe.u.bitrate.fixed = 0; + iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.value = 0; + i = 0; + while (pnetwork->network.SupportedRates[i] != 0) { + /* Bit rate given in 500 kb/s units */ + iwe.u.bitrate.value = (pnetwork->network.SupportedRates[i++] & + 0x7F) * 500000; + current_val = iwe_stream_add_value(info, start, current_val, + stop, &iwe, IW_EV_PARAM_LEN); + } + /* Check if we added any event */ + if ((current_val - start) > iwe_stream_lcp_len(info)) + start = current_val; + /* parsing WPA/WPA2 IE */ + { + u8 buf[MAX_WPA_IE_LEN]; + u8 wpa_ie[255], rsn_ie[255]; + u16 wpa_len = 0, rsn_len = 0; + int n; + + r8712_get_sec_ie(pnetwork->network.IEs, + pnetwork->network.IELength, rsn_ie, &rsn_len, + wpa_ie, &wpa_len); + if (wpa_len > 0) { + memset(buf, 0, MAX_WPA_IE_LEN); + n = sprintf(buf, "wpa_ie="); + for (i = 0; i < wpa_len; i++) { + n += snprintf(buf + n, MAX_WPA_IE_LEN - n, + "%02x", wpa_ie[i]); + if (n >= MAX_WPA_IE_LEN) + break; + } + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = (u16)strlen(buf); + start = iwe_stream_add_point(info, start, stop, + &iwe, buf); + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = (u16)wpa_len; + start = iwe_stream_add_point(info, start, stop, + &iwe, wpa_ie); + } + if (rsn_len > 0) { + memset(buf, 0, MAX_WPA_IE_LEN); + n = sprintf(buf, "rsn_ie="); + for (i = 0; i < rsn_len; i++) { + n += snprintf(buf + n, MAX_WPA_IE_LEN - n, + "%02x", rsn_ie[i]); + if (n >= MAX_WPA_IE_LEN) + break; + } + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); + start = iwe_stream_add_point(info, start, stop, + &iwe, buf); + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = rsn_len; + start = iwe_stream_add_point(info, start, stop, &iwe, + rsn_ie); + } + } + + { /* parsing WPS IE */ + u8 wps_ie[512]; + uint wps_ielen; + + if (r8712_get_wps_ie(pnetwork->network.IEs, + pnetwork->network.IELength, + wps_ie, &wps_ielen) == true) { + if (wps_ielen > 2) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = (u16)wps_ielen; + start = iwe_stream_add_point(info, start, stop, + &iwe, wps_ie); + } + } + } + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi); + /* we only update signal_level (signal strength) that is rssi. */ + iwe.u.qual.updated = (u8)(IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_INVALID); + iwe.u.qual.level = rssi; /* signal strength */ + iwe.u.qual.qual = 0; /* signal quality */ + iwe.u.qual.noise = 0; /* noise level */ + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); + /* how to translate rssi to ?% */ + return start; +} + +static int wpa_set_auth_algs(struct net_device *dev, u32 value) +{ + struct _adapter *padapter = netdev_priv(dev); + int ret = 0; + + if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) { + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeAutoSwitch; + padapter->securitypriv.AuthAlgrthm = 3; + } else if (value & AUTH_ALG_SHARED_KEY) { + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; + padapter->securitypriv.AuthAlgrthm = 1; + } else if (value & AUTH_ALG_OPEN_SYSTEM) { + if (padapter->securitypriv.ndisauthtype < + Ndis802_11AuthModeWPAPSK) { + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeOpen; + padapter->securitypriv.AuthAlgrthm = 0; + } + } else + ret = -EINVAL; + return ret; +} + +static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, + u32 param_len) +{ + int ret = 0; + u32 wep_key_idx, wep_key_len = 0; + struct NDIS_802_11_WEP *pwep = NULL; + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + param->u.crypt.err = 0; + param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; + if (param_len != (u32)((u8 *) param->u.crypt.key - (u8 *)param) + + param->u.crypt.key_len) + return -EINVAL; + if (is_broadcast_ether_addr(param->sta_addr)) { + if (param->u.crypt.idx >= WEP_KEYS) { + /* for large key indices, set the default (0) */ + param->u.crypt.idx = 0; + } + } else + return -EINVAL; + if (strcmp(param->u.crypt.alg, "WEP") == 0) { + netdev_info(dev, "r8712u: %s: crypt.alg = WEP\n", __func__); + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + padapter->securitypriv.PrivacyAlgrthm = _WEP40_; + padapter->securitypriv.XGrpPrivacy = _WEP40_; + wep_key_idx = param->u.crypt.idx; + wep_key_len = param->u.crypt.key_len; + if (wep_key_idx >= WEP_KEYS) + wep_key_idx = 0; + if (wep_key_len > 0) { + wep_key_len = wep_key_len <= 5 ? 5 : 13; + pwep = kmalloc((u32)(wep_key_len + + FIELD_OFFSET(struct NDIS_802_11_WEP, + KeyMaterial)), GFP_ATOMIC); + if (pwep == NULL) + return -ENOMEM; + memset(pwep, 0, sizeof(struct NDIS_802_11_WEP)); + pwep->KeyLength = wep_key_len; + pwep->Length = wep_key_len + + FIELD_OFFSET(struct NDIS_802_11_WEP, + KeyMaterial); + if (wep_key_len == 13) { + padapter->securitypriv.PrivacyAlgrthm = + _WEP104_; + padapter->securitypriv.XGrpPrivacy = + _WEP104_; + } + } else + return -EINVAL; + pwep->KeyIndex = wep_key_idx; + pwep->KeyIndex |= 0x80000000; + memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); + if (param->u.crypt.set_tx) { + if (r8712_set_802_11_add_wep(padapter, pwep) == + (u8)_FAIL) + ret = -EOPNOTSUPP; + } else { + /* don't update "psecuritypriv->PrivacyAlgrthm" and + * "psecuritypriv->PrivacyKeyIndex=keyid", but can + * r8712_set_key to fw/cam + */ + if (wep_key_idx >= WEP_KEYS) { + ret = -EOPNOTSUPP; + goto exit; + } + memcpy(&(psecuritypriv->DefKey[wep_key_idx]. + skey[0]), pwep->KeyMaterial, + pwep->KeyLength); + psecuritypriv->DefKeylen[wep_key_idx] = + pwep->KeyLength; + r8712_set_key(padapter, psecuritypriv, wep_key_idx); + } + goto exit; + } + if (padapter->securitypriv.AuthAlgrthm == 2) { /* 802_1x */ + struct sta_info *psta, *pbcmc_sta; + struct sta_priv *pstapriv = &padapter->stapriv; + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | + WIFI_MP_STATE) == true) { /* sta mode */ + psta = r8712_get_stainfo(pstapriv, + get_bssid(pmlmepriv)); + if (psta) { + psta->ieee8021x_blocked = false; + if ((padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption2Enabled) || + (padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption3Enabled)) + psta->XPrivacy = padapter-> + securitypriv.PrivacyAlgrthm; + if (param->u.crypt.set_tx == 1) + handle_pairwise_key(psta, param, + padapter); + else /* group key */ + handle_group_key(param, padapter); + } + pbcmc_sta = r8712_get_bcmc_stainfo(padapter); + if (pbcmc_sta) { + pbcmc_sta->ieee8021x_blocked = false; + if ((padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption2Enabled) || + (padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption3Enabled)) + pbcmc_sta->XPrivacy = + padapter->securitypriv. + PrivacyAlgrthm; + } + } + } +exit: + kfree(pwep); + return ret; +} + +static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie, + unsigned short ielen) +{ + u8 *buf = NULL; + int group_cipher = 0, pairwise_cipher = 0; + int ret = 0; + + if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL)) + return -EINVAL; + if (ielen) { + buf = kmemdup(pie, ielen, GFP_ATOMIC); + if (buf == NULL) + return -ENOMEM; + if (ielen < RSN_HEADER_LEN) { + ret = -EINVAL; + goto exit; + } + if (r8712_parse_wpa_ie(buf, ielen, &group_cipher, + &pairwise_cipher) == _SUCCESS) { + padapter->securitypriv.AuthAlgrthm = 2; + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeWPAPSK; + } + if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher, + &pairwise_cipher) == _SUCCESS) { + padapter->securitypriv.AuthAlgrthm = 2; + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeWPA2PSK; + } + switch (group_cipher) { + case WPA_CIPHER_NONE: + padapter->securitypriv.XGrpPrivacy = + _NO_PRIVACY_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11EncryptionDisabled; + break; + case WPA_CIPHER_WEP40: + padapter->securitypriv.XGrpPrivacy = _WEP40_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + case WPA_CIPHER_TKIP: + padapter->securitypriv.XGrpPrivacy = _TKIP_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption2Enabled; + break; + case WPA_CIPHER_CCMP: + padapter->securitypriv.XGrpPrivacy = _AES_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption3Enabled; + break; + case WPA_CIPHER_WEP104: + padapter->securitypriv.XGrpPrivacy = _WEP104_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + } + switch (pairwise_cipher) { + case WPA_CIPHER_NONE: + padapter->securitypriv.PrivacyAlgrthm = + _NO_PRIVACY_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11EncryptionDisabled; + break; + case WPA_CIPHER_WEP40: + padapter->securitypriv.PrivacyAlgrthm = _WEP40_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + case WPA_CIPHER_TKIP: + padapter->securitypriv.PrivacyAlgrthm = _TKIP_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption2Enabled; + break; + case WPA_CIPHER_CCMP: + padapter->securitypriv.PrivacyAlgrthm = _AES_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption3Enabled; + break; + case WPA_CIPHER_WEP104: + padapter->securitypriv.PrivacyAlgrthm = _WEP104_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + } + padapter->securitypriv.wps_phase = false; + {/* set wps_ie */ + u16 cnt = 0; + u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; + + while (cnt < ielen) { + eid = buf[cnt]; + + if ((eid == _VENDOR_SPECIFIC_IE_) && + (!memcmp(&buf[cnt+2], wps_oui, 4))) { + netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE\n"); + padapter->securitypriv.wps_ie_len = + ((buf[cnt+1] + 2) < + (MAX_WPA_IE_LEN << 2)) ? + (buf[cnt + 1] + 2) : + (MAX_WPA_IE_LEN << 2); + memcpy(padapter->securitypriv.wps_ie, + &buf[cnt], + padapter->securitypriv.wps_ie_len); + padapter->securitypriv.wps_phase = + true; + netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE, wps_phase==true\n"); + cnt += buf[cnt+1]+2; + break; + } else + cnt += buf[cnt + 1] + 2; + } + } + } +exit: + kfree(buf); + return ret; +} + +static int r8711_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + u32 ht_ielen = 0; + char *p; + u8 ht_cap = false; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + NDIS_802_11_RATES_EX *prates = NULL; + + if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == + true) { + /* parsing HT_CAP_IE */ + p = r8712_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, + &ht_ielen, pcur_bss->IELength - 12); + if (p && ht_ielen > 0) + ht_cap = true; + prates = &pcur_bss->SupportedRates; + if (r8712_is_cckratesonly_included((u8 *)prates) == true) { + if (ht_cap == true) + snprintf(wrqu->name, IFNAMSIZ, + "IEEE 802.11bn"); + else + snprintf(wrqu->name, IFNAMSIZ, + "IEEE 802.11b"); + } else if ((r8712_is_cckrates_included((u8 *)prates)) == true) { + if (ht_cap == true) + snprintf(wrqu->name, IFNAMSIZ, + "IEEE 802.11bgn"); + else + snprintf(wrqu->name, IFNAMSIZ, + "IEEE 802.11bg"); + } else { + if (ht_cap == true) + snprintf(wrqu->name, IFNAMSIZ, + "IEEE 802.11gn"); + else + snprintf(wrqu->name, IFNAMSIZ, + "IEEE 802.11g"); + } + } else + snprintf(wrqu->name, IFNAMSIZ, "unassociated"); + return 0; +} + +static const long frequency_list[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, + 2467, 2472, 2484, 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980, + 5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, + 5220, 5230, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, + 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745, 5765, 5785, 5805, + 5825 +}; + +static int r8711_wx_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct iw_freq *fwrq = &wrqu->freq; + int rc = 0; + +/* If setting by frequency, convert to a channel */ + if ((fwrq->e == 1) && + (fwrq->m >= (int) 2.412e8) && + (fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + + while ((c < 14) && (f != frequency_list[c])) + c++; + fwrq->e = 0; + fwrq->m = c + 1; + } + /* Setting by channel number */ + if ((fwrq->m > 14) || (fwrq->e > 0)) + rc = -EOPNOTSUPP; + else { + int channel = fwrq->m; + + if ((channel < 1) || (channel > 14)) + rc = -EINVAL; + else { + /* Yes ! We can set it !!! */ + padapter->registrypriv.channel = channel; + } + } + return rc; +} + +static int r8711_wx_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + wrqu->freq.m = ieee80211_wlan_frequencies[ + pcur_bss->Configuration.DSConfig-1] * 100000; + wrqu->freq.e = 1; + wrqu->freq.i = pcur_bss->Configuration.DSConfig; + } else { + return -ENOLINK; + } + return 0; +} + +static int r8711_wx_set_mode(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct _adapter *padapter = netdev_priv(dev); + enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType; + + switch (wrqu->mode) { + case IW_MODE_AUTO: + networkType = Ndis802_11AutoUnknown; + break; + case IW_MODE_ADHOC: + networkType = Ndis802_11IBSS; + break; + case IW_MODE_MASTER: + networkType = Ndis802_11APMode; + break; + case IW_MODE_INFRA: + networkType = Ndis802_11Infrastructure; + break; + default: + return -EINVAL; + } + if (Ndis802_11APMode == networkType) + r8712_setopmode_cmd(padapter, networkType); + else + r8712_setopmode_cmd(padapter, Ndis802_11AutoUnknown); + + r8712_set_802_11_infrastructure_mode(padapter, networkType); + return 0; +} + +static int r8711_wx_get_mode(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) + wrqu->mode = IW_MODE_INFRA; + else if (check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) == true) + wrqu->mode = IW_MODE_ADHOC; + else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) + wrqu->mode = IW_MODE_MASTER; + else + wrqu->mode = IW_MODE_AUTO; + return 0; +} + +static int r871x_wx_set_pmkid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct iw_pmksa *pPMK = (struct iw_pmksa *) extra; + u8 strZeroMacAddress[ETH_ALEN] = {0x00}; + u8 strIssueBssid[ETH_ALEN] = {0x00}; + u8 j, blInserted = false; + int intReturn = false; + +/* + There are the BSSID information in the bssid.sa_data array. + If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear + all the PMKID information. If cmd is IW_PMKSA_ADD, it means the + wpa_supplicant wants to add a PMKID/BSSID to driver. + If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to + remove a PMKID/BSSID from driver. +*/ + if (pPMK == NULL) + return -EINVAL; + memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); + switch (pPMK->cmd) { + case IW_PMKSA_ADD: + if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN)) + return intReturn; + else + intReturn = true; + blInserted = false; + /* overwrite PMKID */ + for (j = 0; j < NUM_PMKID_CACHE; j++) { + if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, + strIssueBssid, ETH_ALEN)) { + /* BSSID is matched, the same AP => rewrite + * with new PMKID. */ + netdev_info(dev, "r8712u: %s: BSSID exists in the PMKList.\n", + __func__); + memcpy(psecuritypriv->PMKIDList[j].PMKID, + pPMK->pmkid, IW_PMKID_LEN); + psecuritypriv->PMKIDList[j].bUsed = true; + psecuritypriv->PMKIDIndex = j + 1; + blInserted = true; + break; + } + } + if (!blInserted) { + /* Find a new entry */ + netdev_info(dev, "r8712u: %s: Use the new entry index = %d for this PMKID.\n", + __func__, psecuritypriv->PMKIDIndex); + memcpy(psecuritypriv->PMKIDList[psecuritypriv-> + PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN); + memcpy(psecuritypriv->PMKIDList[psecuritypriv-> + PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN); + psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex]. + bUsed = true; + psecuritypriv->PMKIDIndex++; + if (psecuritypriv->PMKIDIndex == NUM_PMKID_CACHE) + psecuritypriv->PMKIDIndex = 0; + } + break; + case IW_PMKSA_REMOVE: + intReturn = true; + for (j = 0; j < NUM_PMKID_CACHE; j++) { + if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, + strIssueBssid, ETH_ALEN)) { + /* BSSID is matched, the same AP => Remove + * this PMKID information and reset it. */ + eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid); + psecuritypriv->PMKIDList[j].bUsed = false; + break; + } + } + break; + case IW_PMKSA_FLUSH: + memset(psecuritypriv->PMKIDList, 0, + sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); + psecuritypriv->PMKIDIndex = 0; + intReturn = true; + break; + default: + netdev_info(dev, "r8712u: %s: unknown Command\n", __func__); + intReturn = false; + break; + } + return intReturn; +} + +static int r8711_wx_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wrqu->sens.value = 0; + wrqu->sens.fixed = 0; /* no auto select */ + wrqu->sens.disabled = 1; + return 0; +} + +static int r8711_wx_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_range *range = (struct iw_range *)extra; + u16 val; + int i; + + wrqu->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + /* Let's try to keep this struct in the same order as in + * linux/include/wireless.h + */ + + /* TODO: See what values we can set, and remove the ones we can't + * set, or fill them with some default data. + */ + /* ~5 Mb/s real (802.11b) */ + range->throughput = 5 * 1000 * 1000; + /* TODO: 8711 sensitivity ? */ + /* signal level threshold range */ + /* percent values between 0 and 100. */ + range->max_qual.qual = 100; + range->max_qual.level = 100; + range->max_qual.noise = 100; + range->max_qual.updated = 7; /* Updated all three */ + range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ + /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ + range->avg_qual.level = 20 + -98; + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; /* Updated all three */ + range->num_bitrates = RATE_COUNT; + for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) + range->bitrate[i] = rtl8180_rates[i]; + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + range->pm_capa = 0; + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 16; + range->num_channels = 14; + for (i = 0, val = 0; i < 14; i++) { + /* Include only legal frequencies for some countries */ + range->freq[val].i = i + 1; + range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; + range->freq[val].e = 1; + val++; + if (val == IW_MAX_FREQUENCIES) + break; + } + range->num_frequency = val; + range->enc_capa = IW_ENC_CAPA_WPA | + IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_CIPHER_CCMP; + return 0; +} + +static int r8711_wx_get_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +static int r871x_wx_set_priv(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + int ret = 0, len = 0; + char *ext; + struct _adapter *padapter = netdev_priv(dev); + struct iw_point *dwrq = (struct iw_point *)awrq; + + len = dwrq->length; + ext = memdup_user(dwrq->pointer, len); + if (IS_ERR(ext)) + return PTR_ERR(ext); + + if (0 == strcasecmp(ext, "RSSI")) { + /*Return received signal strength indicator in -db for */ + /* current AP */ + /*<ssid> Rssi xx */ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct wlan_network *pcur_network = &pmlmepriv->cur_network; + /*static u8 xxxx; */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + sprintf(ext, "%s rssi %d", + pcur_network->network.Ssid.Ssid, + /*(xxxx=xxxx+10) */ + ((padapter->recvpriv.fw_rssi)>>1)-95 + /*pcur_network->network.Rssi */ + ); + } else { + sprintf(ext, "OK"); + } + } else if (0 == strcasecmp(ext, "LINKSPEED")) { + /*Return link speed in MBPS */ + /*LinkSpeed xx */ + union iwreq_data wrqd; + int ret_inner; + int mbps; + + ret_inner = r8711_wx_get_rate(dev, info, &wrqd, extra); + if (0 != ret_inner) + mbps = 0; + else + mbps = wrqd.bitrate.value / 1000000; + sprintf(ext, "LINKSPEED %d", mbps); + } else if (0 == strcasecmp(ext, "MACADDR")) { + /*Return mac address of the station */ + /* Macaddr = xx:xx:xx:xx:xx:xx */ + sprintf(ext, "MACADDR = %pM", dev->dev_addr); + } else if (0 == strcasecmp(ext, "SCAN-ACTIVE")) { + /*Set scan type to active */ + /*OK if successful */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + pmlmepriv->passive_mode = 1; + sprintf(ext, "OK"); + } else if (0 == strcasecmp(ext, "SCAN-PASSIVE")) { + /*Set scan type to passive */ + /*OK if successful */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + pmlmepriv->passive_mode = 0; + sprintf(ext, "OK"); + } else if (0 == strncmp(ext, "DCE-E", 5)) { + /*Set scan type to passive */ + /*OK if successful */ + r8712_disconnectCtrlEx_cmd(padapter + , 1 /*u32 enableDrvCtrl */ + , 5 /*u32 tryPktCnt */ + , 100 /*u32 tryPktInterval */ + , 5000 /*u32 firstStageTO */ + ); + sprintf(ext, "OK"); + } else if (0 == strncmp(ext, "DCE-D", 5)) { + /*Set scan type to passive */ + /*OK if successfu */ + r8712_disconnectCtrlEx_cmd(padapter + , 0 /*u32 enableDrvCtrl */ + , 5 /*u32 tryPktCnt */ + , 100 /*u32 tryPktInterval */ + , 5000 /*u32 firstStageTO */ + ); + sprintf(ext, "OK"); + } else { + netdev_info(dev, "r8712u: %s: unknown Command %s.\n", + __func__, ext); + goto FREE_EXT; + } + if (copy_to_user(dwrq->pointer, ext, + min(dwrq->length, (__u16)(strlen(ext)+1)))) + ret = -EFAULT; + +FREE_EXT: + kfree(ext); + return ret; +} + +/* set bssid flow + * s1. set_802_11_infrastructure_mode() + * s2. set_802_11_authentication_mode() + * s3. set_802_11_encryption_mode() + * s4. set_802_11_bssid() + * + * This function intends to handle the Set AP command, which specifies the + * MAC# of a preferred Access Point. + * Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl. + * + * For this operation to succeed, there is no need for the interface to be up. + * + */ +static int r8711_wx_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + int ret = -EINPROGRESS; + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct __queue *queue = &pmlmepriv->scanned_queue; + struct sockaddr *temp = (struct sockaddr *)awrq; + unsigned long irqL; + struct list_head *phead; + u8 *dst_bssid; + struct wlan_network *pnetwork = NULL; + enum NDIS_802_11_AUTHENTICATION_MODE authmode; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) + return -EBUSY; + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) + return ret; + if (temp->sa_family != ARPHRD_ETHER) + return -EINVAL; + authmode = padapter->securitypriv.ndisauthtype; + spin_lock_irqsave(&queue->lock, irqL); + phead = &queue->queue; + pmlmepriv->pscanned = phead->next; + while (1) { + if (end_of_queue_search(phead, pmlmepriv->pscanned) == true) + break; + pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, + struct wlan_network, list); + pmlmepriv->pscanned = pmlmepriv->pscanned->next; + dst_bssid = pnetwork->network.MacAddress; + if (!memcmp(dst_bssid, temp->sa_data, ETH_ALEN)) { + r8712_set_802_11_infrastructure_mode(padapter, + pnetwork->network.InfrastructureMode); + break; + } + } + spin_unlock_irqrestore(&queue->lock, irqL); + if (!ret) { + if (!r8712_set_802_11_authentication_mode(padapter, authmode)) + ret = -ENOMEM; + else { + if (!r8712_set_802_11_bssid(padapter, temp->sa_data)) + ret = -1; + } + } + return ret; +} + +static int r8711_wx_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE | + WIFI_AP_STATE)) + ether_addr_copy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress); + else + eth_zero_addr(wrqu->ap_addr.sa_data); + return 0; +} + +static int r871x_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; + struct _adapter *padapter = netdev_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *) extra; + + if (mlme == NULL) + return -1; + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + if (!r8712_set_802_11_disassociate(padapter)) + ret = -1; + break; + case IW_MLME_DISASSOC: + if (!r8712_set_802_11_disassociate(padapter)) + ret = -1; + break; + default: + return -EOPNOTSUPP; + } + return ret; +} + +/** + * + * This function intends to handle the Set Scan command. + * Currently, the request comes via Wireless Extensions' SIOCSIWSCAN ioctl. + * + * For this operation to succeed, the interface is brought Up beforehand. + * + */ +static int r8711_wx_set_scan(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 status = true; + + if (padapter->bDriverStopped == true) { + netdev_info(dev, "In %s: bDriverStopped=%d\n", + __func__, padapter->bDriverStopped); + return -1; + } + if (padapter->bup == false) + return -ENETDOWN; + if (padapter->hw_init_completed == false) + return -1; + if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) || + (pmlmepriv->sitesurveyctrl.traffic_busy == true)) + return 0; + if (wrqu->data.length == sizeof(struct iw_scan_req)) { + struct iw_scan_req *req = (struct iw_scan_req *)extra; + + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + struct ndis_802_11_ssid ssid; + unsigned long irqL; + u32 len = min_t(u8, req->essid_len, IW_ESSID_MAX_SIZE); + + memset((unsigned char *)&ssid, 0, + sizeof(struct ndis_802_11_ssid)); + memcpy(ssid.Ssid, req->essid, len); + ssid.SsidLength = len; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | + _FW_UNDER_LINKING)) || + (pmlmepriv->sitesurveyctrl.traffic_busy == true)) { + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) + status = false; + } else + status = r8712_sitesurvey_cmd(padapter, &ssid); + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + } + } else + status = r8712_set_802_11_bssid_list_scan(padapter); + if (status == false) + return -1; + return 0; +} + +static int r8711_wx_get_scan(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct __queue *queue = &pmlmepriv->scanned_queue; + struct wlan_network *pnetwork = NULL; + unsigned long irqL; + struct list_head *plist, *phead; + char *ev = extra; + char *stop = ev + wrqu->data.length; + u32 ret = 0, cnt = 0; + + if (padapter->bDriverStopped) + return -EINVAL; + while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) { + msleep(30); + cnt++; + if (cnt > 100) + break; + } + spin_lock_irqsave(&queue->lock, irqL); + phead = &queue->queue; + plist = phead->next; + while (1) { + if (end_of_queue_search(phead, plist) == true) + break; + if ((stop - ev) < SCAN_ITEM_SIZE) { + ret = -E2BIG; + break; + } + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + ev = translate_scan(padapter, a, pnetwork, ev, stop); + plist = plist->next; + } + spin_unlock_irqrestore(&queue->lock, irqL); + wrqu->data.length = ev - extra; + wrqu->data.flags = 0; + return ret; +} + +/* set ssid flow + * s1. set_802_11_infrastructure_mode() + * s2. set_802_11_authenticaion_mode() + * s3. set_802_11_encryption_mode() + * s4. set_802_11_ssid() + * + * This function intends to handle the Set ESSID command. + * Currently, the request comes via the Wireless Extensions' SIOCSIWESSID ioctl. + * + * For this operation to succeed, there is no need for the interface to be Up. + * + */ +static int r8711_wx_set_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct __queue *queue = &pmlmepriv->scanned_queue; + struct wlan_network *pnetwork = NULL; + enum NDIS_802_11_AUTHENTICATION_MODE authmode; + struct ndis_802_11_ssid ndis_ssid; + u8 *dst_ssid, *src_ssid; + struct list_head *phead; + u32 len; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) + return -EBUSY; + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) + return 0; + if (wrqu->essid.length > IW_ESSID_MAX_SIZE) + return -E2BIG; + authmode = padapter->securitypriv.ndisauthtype; + if (wrqu->essid.flags && wrqu->essid.length) { + len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? + wrqu->essid.length : IW_ESSID_MAX_SIZE; + memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid)); + ndis_ssid.SsidLength = len; + memcpy(ndis_ssid.Ssid, extra, len); + src_ssid = ndis_ssid.Ssid; + phead = &queue->queue; + pmlmepriv->pscanned = phead->next; + while (1) { + if (end_of_queue_search(phead, pmlmepriv->pscanned)) + break; + pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, + struct wlan_network, list); + pmlmepriv->pscanned = pmlmepriv->pscanned->next; + dst_ssid = pnetwork->network.Ssid.Ssid; + if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) + && (pnetwork->network.Ssid.SsidLength == + ndis_ssid.SsidLength)) { + if (check_fwstate(pmlmepriv, + WIFI_ADHOC_STATE)) { + if (pnetwork->network. + InfrastructureMode + != + padapter->mlmepriv. + cur_network.network. + InfrastructureMode) + continue; + } + + r8712_set_802_11_infrastructure_mode( + padapter, + pnetwork->network.InfrastructureMode); + break; + } + } + r8712_set_802_11_authentication_mode(padapter, authmode); + r8712_set_802_11_ssid(padapter, &ndis_ssid); + } + return -EINPROGRESS; +} + +static int r8711_wx_get_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + u32 len, ret = 0; + + if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) { + len = pcur_bss->Ssid.SsidLength; + wrqu->essid.length = len; + memcpy(extra, pcur_bss->Ssid.Ssid, len); + wrqu->essid.flags = 1; + } else { + ret = -ENOLINK; + } + return ret; +} + +static int r8711_wx_set_rate(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + u32 target_rate = wrqu->bitrate.value; + u32 fixed = wrqu->bitrate.fixed; + u32 ratevalue = 0; + u8 datarates[NumRates]; + u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff}; + int i, ret = 0; + + if (target_rate == -1) { + ratevalue = 11; + goto set_rate; + } + target_rate = target_rate / 100000; + switch (target_rate) { + case 10: + ratevalue = 0; + break; + case 20: + ratevalue = 1; + break; + case 55: + ratevalue = 2; + break; + case 60: + ratevalue = 3; + break; + case 90: + ratevalue = 4; + break; + case 110: + ratevalue = 5; + break; + case 120: + ratevalue = 6; + break; + case 180: + ratevalue = 7; + break; + case 240: + ratevalue = 8; + break; + case 360: + ratevalue = 9; + break; + case 480: + ratevalue = 10; + break; + case 540: + ratevalue = 11; + break; + default: + ratevalue = 11; + break; + } +set_rate: + for (i = 0; i < NumRates; i++) { + if (ratevalue == mpdatarate[i]) { + datarates[i] = mpdatarate[i]; + if (fixed == 0) + break; + } else + datarates[i] = 0xff; + } + if (r8712_setdatarate_cmd(padapter, datarates) != _SUCCESS) + ret = -ENOMEM; + return ret; +} + +static int r8711_wx_get_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + struct ieee80211_ht_cap *pht_capie; + unsigned char rf_type = padapter->registrypriv.rf_config; + int i; + u8 *p; + u16 rate, max_rate = 0, ht_cap = false; + u32 ht_ielen = 0; + u8 bw_40MHz = 0, short_GI = 0; + u16 mcs_rate = 0; + + i = 0; + if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) { + p = r8712_get_ie(&pcur_bss->IEs[12], + _HT_CAPABILITY_IE_, &ht_ielen, + pcur_bss->IELength - 12); + if (p && ht_ielen > 0) { + ht_cap = true; + pht_capie = (struct ieee80211_ht_cap *)(p + 2); + memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2); + bw_40MHz = (pht_capie->cap_info & + IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0; + short_GI = (pht_capie->cap_info & + (IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; + } + while ((pcur_bss->SupportedRates[i] != 0) && + (pcur_bss->SupportedRates[i] != 0xFF)) { + rate = pcur_bss->SupportedRates[i] & 0x7F; + if (rate > max_rate) + max_rate = rate; + wrqu->bitrate.fixed = 0; /* no auto select */ + wrqu->bitrate.value = rate*500000; + i++; + } + if (ht_cap == true) { + if (mcs_rate & 0x8000 /* MCS15 */ + && + RTL8712_RF_2T2R == rf_type) + max_rate = (bw_40MHz) ? ((short_GI) ? 300 : + 270) : ((short_GI) ? 144 : 130); + else /* default MCS7 */ + max_rate = (bw_40MHz) ? ((short_GI) ? 150 : + 135) : ((short_GI) ? 72 : 65); + max_rate *= 2; /* Mbps/2 */ + } + wrqu->bitrate.value = max_rate * 500000; + } else + return -ENOLINK; + return 0; +} + +static int r8711_wx_get_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + + wrqu->rts.value = padapter->registrypriv.rts_thresh; + wrqu->rts.fixed = 0; /* no auto select */ + return 0; +} + +static int r8711_wx_set_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + + if (wrqu->frag.disabled) + padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD; + else { + if (wrqu->frag.value < MIN_FRAG_THRESHOLD || + wrqu->frag.value > MAX_FRAG_THRESHOLD) + return -EINVAL; + padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1; + } + return 0; +} + +static int r8711_wx_get_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + + wrqu->frag.value = padapter->xmitpriv.frag_len; + wrqu->frag.fixed = 0; /* no auto select */ + return 0; +} + +static int r8711_wx_get_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wrqu->retry.value = 7; + wrqu->retry.fixed = 0; /* no auto select */ + wrqu->retry.disabled = 1; + return 0; +} + +static int r8711_wx_set_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + u32 key; + u32 keyindex_provided; + struct NDIS_802_11_WEP wep; + enum NDIS_802_11_AUTHENTICATION_MODE authmode; + struct iw_point *erq = &(wrqu->encoding); + struct _adapter *padapter = netdev_priv(dev); + + key = erq->flags & IW_ENCODE_INDEX; + memset(&wep, 0, sizeof(struct NDIS_802_11_WEP)); + if (erq->flags & IW_ENCODE_DISABLED) { + netdev_info(dev, "r8712u: %s: EncryptionDisabled\n", __func__); + padapter->securitypriv.ndisencryptstatus = + Ndis802_11EncryptionDisabled; + padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_; + padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_; + padapter->securitypriv.AuthAlgrthm = 0; /* open system */ + authmode = Ndis802_11AuthModeOpen; + padapter->securitypriv.ndisauthtype = authmode; + return 0; + } + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + keyindex_provided = 1; + } else { + keyindex_provided = 0; + key = padapter->securitypriv.PrivacyKeyIndex; + } + /* set authentication mode */ + if (erq->flags & IW_ENCODE_OPEN) { + netdev_info(dev, "r8712u: %s: IW_ENCODE_OPEN\n", __func__); + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + padapter->securitypriv.AuthAlgrthm = 0; /* open system */ + padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_; + padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_; + authmode = Ndis802_11AuthModeOpen; + padapter->securitypriv.ndisauthtype = authmode; + } else if (erq->flags & IW_ENCODE_RESTRICTED) { + netdev_info(dev, + "r8712u: %s: IW_ENCODE_RESTRICTED\n", __func__); + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + padapter->securitypriv.AuthAlgrthm = 1; /* shared system */ + padapter->securitypriv.PrivacyAlgrthm = _WEP40_; + padapter->securitypriv.XGrpPrivacy = _WEP40_; + authmode = Ndis802_11AuthModeShared; + padapter->securitypriv.ndisauthtype = authmode; + } else { + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + padapter->securitypriv.AuthAlgrthm = 0; /* open system */ + padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_; + padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_; + authmode = Ndis802_11AuthModeOpen; + padapter->securitypriv.ndisauthtype = authmode; + } + wep.KeyIndex = key; + if (erq->length > 0) { + wep.KeyLength = erq->length <= 5 ? 5 : 13; + wep.Length = wep.KeyLength + + FIELD_OFFSET(struct NDIS_802_11_WEP, KeyMaterial); + } else { + wep.KeyLength = 0; + if (keyindex_provided == 1) { /* set key_id only, no given + * KeyMaterial(erq->length==0).*/ + padapter->securitypriv.PrivacyKeyIndex = key; + switch (padapter->securitypriv.DefKeylen[key]) { + case 5: + padapter->securitypriv.PrivacyAlgrthm = + _WEP40_; + break; + case 13: + padapter->securitypriv.PrivacyAlgrthm = + _WEP104_; + break; + default: + padapter->securitypriv.PrivacyAlgrthm = + _NO_PRIVACY_; + break; + } + return 0; + } + } + wep.KeyIndex |= 0x80000000; /* transmit key */ + memcpy(wep.KeyMaterial, keybuf, wep.KeyLength); + if (r8712_set_802_11_add_wep(padapter, &wep) == _FAIL) + return -EOPNOTSUPP; + return 0; +} + +static int r8711_wx_get_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + uint key, ret = 0; + struct _adapter *padapter = netdev_priv(dev); + struct iw_point *erq = &(wrqu->encoding); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + if (check_fwstate(pmlmepriv, _FW_LINKED) == false) { + if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + } + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + } else { + key = padapter->securitypriv.PrivacyKeyIndex; + } + erq->flags = key + 1; + switch (padapter->securitypriv.ndisencryptstatus) { + case Ndis802_11EncryptionNotSupported: + case Ndis802_11EncryptionDisabled: + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + break; + case Ndis802_11Encryption1Enabled: + erq->length = padapter->securitypriv.DefKeylen[key]; + if (erq->length) { + memcpy(keybuf, padapter->securitypriv.DefKey[ + key].skey, padapter->securitypriv. + DefKeylen[key]); + erq->flags |= IW_ENCODE_ENABLED; + if (padapter->securitypriv.ndisauthtype == + Ndis802_11AuthModeOpen) + erq->flags |= IW_ENCODE_OPEN; + else if (padapter->securitypriv.ndisauthtype == + Ndis802_11AuthModeShared) + erq->flags |= IW_ENCODE_RESTRICTED; + } else { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + } + break; + case Ndis802_11Encryption2Enabled: + case Ndis802_11Encryption3Enabled: + erq->length = 16; + erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | + IW_ENCODE_NOKEY); + break; + default: + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + break; + } + return ret; +} + +static int r8711_wx_get_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wrqu->power.value = 0; + wrqu->power.fixed = 0; /* no auto select */ + wrqu->power.disabled = 1; + return 0; +} + +static int r871x_wx_set_gen_ie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + + return r871x_set_wpa_ie(padapter, extra, wrqu->data.length); +} + +static int r871x_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct iw_param *param = (struct iw_param *)&(wrqu->param); + int paramid; + int paramval; + int ret = 0; + + paramid = param->flags & IW_AUTH_INDEX; + paramval = param->value; + switch (paramid) { + case IW_AUTH_WPA_VERSION: + break; + case IW_AUTH_CIPHER_PAIRWISE: + break; + case IW_AUTH_CIPHER_GROUP: + break; + case IW_AUTH_KEY_MGMT: + /* + * ??? does not use these parameters + */ + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + if (paramval) { + /* wpa_supplicant is enabling tkip countermeasure. */ + padapter->securitypriv.btkip_countermeasure = true; + } else { + /* wpa_supplicant is disabling tkip countermeasure. */ + padapter->securitypriv.btkip_countermeasure = false; + } + break; + case IW_AUTH_DROP_UNENCRYPTED: + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + if (padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption1Enabled) { + /* it means init value, or using wep, + * ndisencryptstatus = + * Ndis802_11Encryption1Enabled, + * then it needn't reset it; + */ + break; + } + + if (paramval) { + padapter->securitypriv.ndisencryptstatus = + Ndis802_11EncryptionDisabled; + padapter->securitypriv.PrivacyAlgrthm = + _NO_PRIVACY_; + padapter->securitypriv.XGrpPrivacy = + _NO_PRIVACY_; + padapter->securitypriv.AuthAlgrthm = 0; + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeOpen; + } + break; + case IW_AUTH_80211_AUTH_ALG: + ret = wpa_set_auth_algs(dev, (u32)paramval); + break; + case IW_AUTH_WPA_ENABLED: + break; + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + break; + case IW_AUTH_PRIVACY_INVOKED: + break; + default: + return -EOPNOTSUPP; + } + + return ret; +} + +static int r871x_wx_set_enc_ext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_point *pencoding = &wrqu->encoding; + struct iw_encode_ext *pext = (struct iw_encode_ext *)extra; + struct ieee_param *param = NULL; + char *alg_name; + u32 param_len; + int ret = 0; + + switch (pext->alg) { + case IW_ENCODE_ALG_NONE: + alg_name = "none"; + break; + case IW_ENCODE_ALG_WEP: + alg_name = "WEP"; + break; + case IW_ENCODE_ALG_TKIP: + alg_name = "TKIP"; + break; + case IW_ENCODE_ALG_CCMP: + alg_name = "CCMP"; + break; + default: + return -EINVAL; + } + + param_len = sizeof(struct ieee_param) + pext->key_len; + param = kzalloc(param_len, GFP_ATOMIC); + if (param == NULL) + return -ENOMEM; + param->cmd = IEEE_CMD_SET_ENCRYPTION; + memset(param->sta_addr, 0xff, ETH_ALEN); + + strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); + if (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + param->u.crypt.set_tx = 0; + if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + param->u.crypt.set_tx = 1; + param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1; + if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) + memcpy(param->u.crypt.seq, pext->rx_seq, 8); + if (pext->key_len) { + param->u.crypt.key_len = pext->key_len; + memcpy(param + 1, pext + 1, pext->key_len); + } + ret = wpa_set_encryption(dev, param, param_len); + kfree(param); + return ret; +} + +static int r871x_wx_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + if (extra) { + wrqu->data.length = 8; + wrqu->data.flags = 1; + memcpy(extra, "rtl_wifi", 8); + } + return 0; +} + +static int r8711_wx_read32(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct _adapter *padapter = netdev_priv(dev); + u32 addr; + u32 data32; + + get_user(addr, (u32 __user *)wrqu->data.pointer); + data32 = r8712_read32(padapter, addr); + put_user(data32, (u32 __user *)wrqu->data.pointer); + wrqu->data.length = (data32 & 0xffff0000) >> 16; + wrqu->data.flags = data32 & 0xffff; + get_user(addr, (u32 __user *)wrqu->data.pointer); + return 0; +} + +static int r8711_wx_write32(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct _adapter *padapter = netdev_priv(dev); + u32 addr; + u32 data32; + + get_user(addr, (u32 __user *)wrqu->data.pointer); + data32 = ((u32)wrqu->data.length<<16) | (u32)wrqu->data.flags; + r8712_write32(padapter, addr, data32); + return 0; +} + +static int dummy(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + return -ENOSYS; +} + +static int r8711_drvext_hdl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return 0; +} + +static int r871x_mp_ioctl_hdl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct iw_point *p = &wrqu->data; + struct oid_par_priv oid_par; + struct mp_ioctl_handler *phandler; + struct mp_ioctl_param *poidparam; + unsigned long BytesRead, BytesWritten, BytesNeeded; + u8 *pparmbuf, bset; + u16 len; + uint status; + int ret = 0; + + if ((!p->length) || (!p->pointer)) + return -EINVAL; + + bset = (u8)(p->flags & 0xFFFF); + len = p->length; + pparmbuf = memdup_user(p->pointer, len); + if (IS_ERR(pparmbuf)) + return PTR_ERR(pparmbuf); + + poidparam = (struct mp_ioctl_param *)pparmbuf; + if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) { + ret = -EINVAL; + goto _r871x_mp_ioctl_hdl_exit; + } + phandler = mp_ioctl_hdl + poidparam->subcode; + if ((phandler->paramsize != 0) && + (poidparam->len < phandler->paramsize)) { + ret = -EINVAL; + goto _r871x_mp_ioctl_hdl_exit; + } + if (phandler->oid == 0 && phandler->handler) + status = phandler->handler(&oid_par); + else if (phandler->handler) { + oid_par.adapter_context = padapter; + oid_par.oid = phandler->oid; + oid_par.information_buf = poidparam->data; + oid_par.information_buf_len = poidparam->len; + oid_par.dbg = 0; + BytesWritten = 0; + BytesNeeded = 0; + if (bset) { + oid_par.bytes_rw = &BytesRead; + oid_par.bytes_needed = &BytesNeeded; + oid_par.type_of_oid = SET_OID; + } else { + oid_par.bytes_rw = &BytesWritten; + oid_par.bytes_needed = &BytesNeeded; + oid_par.type_of_oid = QUERY_OID; + } + status = phandler->handler(&oid_par); + /* todo:check status, BytesNeeded, etc. */ + } else { + netdev_info(dev, "r8712u: %s: err!, subcode=%d, oid=%d, handler=%p\n", + __func__, poidparam->subcode, phandler->oid, + phandler->handler); + ret = -EFAULT; + goto _r871x_mp_ioctl_hdl_exit; + } + if (bset == 0x00) { /* query info */ + if (copy_to_user(p->pointer, pparmbuf, len)) + ret = -EFAULT; + } + if (status) { + ret = -EFAULT; + goto _r871x_mp_ioctl_hdl_exit; + } +_r871x_mp_ioctl_hdl_exit: + kfree(pparmbuf); + return ret; +} + +static int r871x_get_ap_info(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct __queue *queue = &pmlmepriv->scanned_queue; + struct iw_point *pdata = &wrqu->data; + struct wlan_network *pnetwork = NULL; + u32 cnt = 0, wpa_ielen; + unsigned long irqL; + struct list_head *plist, *phead; + unsigned char *pbuf; + u8 bssid[ETH_ALEN]; + char data[32]; + + if (padapter->bDriverStopped || (pdata == NULL)) + return -EINVAL; + while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) { + msleep(30); + cnt++; + if (cnt > 100) + break; + } + pdata->flags = 0; + if (pdata->length >= 32) { + if (copy_from_user(data, pdata->pointer, 32)) + return -EINVAL; + } else + return -EINVAL; + spin_lock_irqsave(&(pmlmepriv->scanned_queue.lock), irqL); + phead = &queue->queue; + plist = phead->next; + while (1) { + if (end_of_queue_search(phead, plist) == true) + break; + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + if (hwaddr_aton_i(data, bssid)) { + netdev_info(dev, "r8712u: Invalid BSSID '%s'.\n", + (u8 *)data); + spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock), + irqL); + return -EINVAL; + } + netdev_info(dev, "r8712u: BSSID:%pM\n", bssid); + if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN)) { + /* BSSID match, then check if supporting wpa/wpa2 */ + pbuf = r8712_get_wpa_ie(&pnetwork->network.IEs[12], + &wpa_ielen, pnetwork->network.IELength-12); + if (pbuf && (wpa_ielen > 0)) { + pdata->flags = 1; + break; + } + pbuf = r8712_get_wpa2_ie(&pnetwork->network.IEs[12], + &wpa_ielen, pnetwork->network.IELength-12); + if (pbuf && (wpa_ielen > 0)) { + pdata->flags = 2; + break; + } + } + plist = plist->next; + } + spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock), irqL); + if (pdata->length >= 34) { + if (copy_to_user((u8 __user *)pdata->pointer + 32, + (u8 *)&pdata->flags, 1)) + return -EINVAL; + } + return 0; +} + +static int r871x_set_pid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct iw_point *pdata = &wrqu->data; + + if ((padapter->bDriverStopped) || (pdata == NULL)) + return -EINVAL; + if (copy_from_user(&padapter->pid, pdata->pointer, sizeof(int))) + return -EINVAL; + return 0; +} + +static int r871x_set_chplan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; + struct _adapter *padapter = netdev_priv(dev); + struct iw_point *pdata = &wrqu->data; + int ch_plan = -1; + + if ((padapter->bDriverStopped) || (pdata == NULL)) { + ret = -EINVAL; + goto exit; + } + ch_plan = (int)*extra; + r8712_set_chplan_cmd(padapter, ch_plan); + +exit: + + return ret; +} + +static int r871x_wps_start(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct _adapter *padapter = netdev_priv(dev); + struct iw_point *pdata = &wrqu->data; + u32 u32wps_start = 0; + + if ((padapter->bDriverStopped) || (pdata == NULL)) + return -EINVAL; + if (copy_from_user((void *)&u32wps_start, pdata->pointer, 4)) + return -EFAULT; + if (u32wps_start == 0) + u32wps_start = *extra; + if (u32wps_start == 1) /* WPS Start */ + padapter->ledpriv.LedControlHandler(padapter, + LED_CTL_START_WPS); + else if (u32wps_start == 2) /* WPS Stop because of wps success */ + padapter->ledpriv.LedControlHandler(padapter, + LED_CTL_STOP_WPS); + else if (u32wps_start == 3) /* WPS Stop because of wps fail */ + padapter->ledpriv.LedControlHandler(padapter, + LED_CTL_STOP_WPS_FAIL); + return 0; +} + +static int wpa_set_param(struct net_device *dev, u8 name, u32 value) +{ + struct _adapter *padapter = netdev_priv(dev); + + switch (name) { + case IEEE_PARAM_WPA_ENABLED: + padapter->securitypriv.AuthAlgrthm = 2; /* 802.1x */ + switch ((value)&0xff) { + case 1: /* WPA */ + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeWPAPSK; /* WPA_PSK */ + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption2Enabled; + break; + case 2: /* WPA2 */ + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */ + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption3Enabled; + break; + } + break; + case IEEE_PARAM_TKIP_COUNTERMEASURES: + break; + case IEEE_PARAM_DROP_UNENCRYPTED: + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + break; + case IEEE_PARAM_PRIVACY_INVOKED: + break; + case IEEE_PARAM_AUTH_ALGS: + return wpa_set_auth_algs(dev, value); + case IEEE_PARAM_IEEE_802_1X: + break; + case IEEE_PARAM_WPAX_SELECT: + /* added for WPA2 mixed mode */ + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int wpa_mlme(struct net_device *dev, u32 command, u32 reason) +{ + struct _adapter *padapter = netdev_priv(dev); + + switch (command) { + case IEEE_MLME_STA_DEAUTH: + if (!r8712_set_802_11_disassociate(padapter)) + return -1; + break; + case IEEE_MLME_STA_DISASSOC: + if (!r8712_set_802_11_disassociate(padapter)) + return -1; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) +{ + struct ieee_param *param; + int ret = 0; + struct _adapter *padapter = netdev_priv(dev); + + if (p->length < sizeof(struct ieee_param) || !p->pointer) + return -EINVAL; + param = memdup_user(p->pointer, p->length); + if (IS_ERR(param)) + return PTR_ERR(param); + switch (param->cmd) { + case IEEE_CMD_SET_WPA_PARAM: + ret = wpa_set_param(dev, param->u.wpa_param.name, + param->u.wpa_param.value); + break; + case IEEE_CMD_SET_WPA_IE: + ret = r871x_set_wpa_ie(padapter, (char *)param->u.wpa_ie.data, + (u16)param->u.wpa_ie.len); + break; + case IEEE_CMD_SET_ENCRYPTION: + ret = wpa_set_encryption(dev, param, p->length); + break; + case IEEE_CMD_MLME: + ret = wpa_mlme(dev, param->u.mlme.command, + param->u.mlme.reason_code); + break; + default: + ret = -EOPNOTSUPP; + break; + } + if (ret == 0 && copy_to_user(p->pointer, param, p->length)) + ret = -EFAULT; + kfree(param); + return ret; +} + +/* based on "driver_ipw" and for hostapd */ +int r871x_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct iwreq *wrq = (struct iwreq *)rq; + + switch (cmd) { + case RTL_IOCTL_WPA_SUPPLICANT: + return wpa_supplicant_ioctl(dev, &wrq->u.data); + default: + return -EOPNOTSUPP; + } + return 0; +} + +static iw_handler r8711_handlers[] = { + NULL, /* SIOCSIWCOMMIT */ + r8711_wx_get_name, /* SIOCGIWNAME */ + dummy, /* SIOCSIWNWID */ + dummy, /* SIOCGIWNWID */ + r8711_wx_set_freq, /* SIOCSIWFREQ */ + r8711_wx_get_freq, /* SIOCGIWFREQ */ + r8711_wx_set_mode, /* SIOCSIWMODE */ + r8711_wx_get_mode, /* SIOCGIWMODE */ + dummy, /* SIOCSIWSENS */ + r8711_wx_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + r8711_wx_get_range, /* SIOCGIWRANGE */ + r871x_wx_set_priv, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + dummy, /* SIOCSIWSPY */ + dummy, /* SIOCGIWSPY */ + NULL, /* SIOCGIWTHRSPY */ + NULL, /* SIOCWIWTHRSPY */ + r8711_wx_set_wap, /* SIOCSIWAP */ + r8711_wx_get_wap, /* SIOCGIWAP */ + r871x_wx_set_mlme, /* request MLME operation; + * uses struct iw_mlme */ + dummy, /* SIOCGIWAPLIST -- deprecated */ + r8711_wx_set_scan, /* SIOCSIWSCAN */ + r8711_wx_get_scan, /* SIOCGIWSCAN */ + r8711_wx_set_essid, /* SIOCSIWESSID */ + r8711_wx_get_essid, /* SIOCGIWESSID */ + dummy, /* SIOCSIWNICKN */ + r871x_wx_get_nick, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + r8711_wx_set_rate, /* SIOCSIWRATE */ + r8711_wx_get_rate, /* SIOCGIWRATE */ + dummy, /* SIOCSIWRTS */ + r8711_wx_get_rts, /* SIOCGIWRTS */ + r8711_wx_set_frag, /* SIOCSIWFRAG */ + r8711_wx_get_frag, /* SIOCGIWFRAG */ + dummy, /* SIOCSIWTXPOW */ + dummy, /* SIOCGIWTXPOW */ + dummy, /* SIOCSIWRETRY */ + r8711_wx_get_retry, /* SIOCGIWRETRY */ + r8711_wx_set_enc, /* SIOCSIWENCODE */ + r8711_wx_get_enc, /* SIOCGIWENCODE */ + dummy, /* SIOCSIWPOWER */ + r8711_wx_get_power, /* SIOCGIWPOWER */ + NULL, /*---hole---*/ + NULL, /*---hole---*/ + r871x_wx_set_gen_ie, /* SIOCSIWGENIE */ + NULL, /* SIOCGIWGENIE */ + r871x_wx_set_auth, /* SIOCSIWAUTH */ + NULL, /* SIOCGIWAUTH */ + r871x_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ + NULL, /* SIOCGIWENCODEEXT */ + r871x_wx_set_pmkid, /* SIOCSIWPMKSA */ + NULL, /*---hole---*/ +}; + +static const struct iw_priv_args r8711_private_args[] = { + { + SIOCIWFIRSTPRIV + 0x0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "read32" + }, + { + SIOCIWFIRSTPRIV + 0x1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "write32" + }, + { + SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext" + }, + { + SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl" + }, + { + SIOCIWFIRSTPRIV + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" + }, + { + SIOCIWFIRSTPRIV + 0x5, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpid" + }, + { + SIOCIWFIRSTPRIV + 0x6, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start" + }, + { + SIOCIWFIRSTPRIV + 0x7, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "chplan" + } +}; + +static iw_handler r8711_private_handler[] = { + r8711_wx_read32, + r8711_wx_write32, + r8711_drvext_hdl, + r871x_mp_ioctl_hdl, + r871x_get_ap_info, /*for MM DTV platform*/ + r871x_set_pid, + r871x_wps_start, + r871x_set_chplan +}; + +static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev) +{ + struct _adapter *padapter = netdev_priv(dev); + struct iw_statistics *piwstats = &padapter->iwstats; + int tmp_level = 0; + int tmp_qual = 0; + int tmp_noise = 0; + + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) { + piwstats->qual.qual = 0; + piwstats->qual.level = 0; + piwstats->qual.noise = 0; + } else { + /* show percentage, we need transfer dbm to orignal value. */ + tmp_level = padapter->recvpriv.fw_rssi; + tmp_qual = padapter->recvpriv.signal; + tmp_noise = padapter->recvpriv.noise; + piwstats->qual.level = tmp_level; + piwstats->qual.qual = tmp_qual; + piwstats->qual.noise = tmp_noise; + } + piwstats->qual.updated = IW_QUAL_ALL_UPDATED; + return &padapter->iwstats; +} + +struct iw_handler_def r871x_handlers_def = { + .standard = r8711_handlers, + .num_standard = ARRAY_SIZE(r8711_handlers), + .private = r8711_private_handler, + .private_args = (struct iw_priv_args *)r8711_private_args, + .num_private = ARRAY_SIZE(r8711_private_handler), + .num_private_args = sizeof(r8711_private_args) / + sizeof(struct iw_priv_args), + .get_wireless_stats = r871x_get_wireless_stats +}; diff --git a/kernel/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c new file mode 100644 index 000000000..ac0baff7f --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c @@ -0,0 +1,536 @@ +/****************************************************************************** + * rtl871x_ioctl_rtl.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_IOCTL_RTL_C_ + +#include <linux/rndis.h> +#include "osdep_service.h" +#include "drv_types.h" +#include "wlan_bssdef.h" +#include "wifi.h" +#include "rtl871x_ioctl.h" +#include "rtl871x_ioctl_set.h" +#include "rtl871x_ioctl_rtl.h" +#include "mp_custom_oid.h" +#include "rtl871x_mp.h" +#include "rtl871x_mp_ioctl.h" + +uint oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + padapter->recvpriv.rx_smallpacket_crcerr; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + padapter->recvpriv.rx_middlepacket_crcerr; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + padapter->recvpriv.rx_largepacket_crcerr; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + padapter->recvpriv.rx_pkts + + padapter->recvpriv.rx_drop; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + *(uint *)poid_par_priv->information_buf = + padapter->recvpriv.rx_icv_err; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv + *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 preamblemode = 0; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + if (padapter->registrypriv.preamble == PREAMBLE_LONG) + preamblemode = 0; + else if (padapter->registrypriv.preamble == PREAMBLE_AUTO) + preamblemode = 1; + else if (padapter->registrypriv.preamble == PREAMBLE_SHORT) + preamblemode = 2; + *(u32 *)poid_par_priv->information_buf = preamblemode; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct eeprom_priv *peeprompriv = &padapter->eeprompriv; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + *(u16 *)poid_par_priv->information_buf = peeprompriv->channel_plan; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_set_channelplan_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct eeprom_priv *peeprompriv = &padapter->eeprompriv; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + peeprompriv->channel_plan = *(u16 *)poid_par_priv->information_buf; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_set_preamble_mode_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 preamblemode = 0; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + preamblemode = *(u32 *)poid_par_priv->information_buf; + if (preamblemode == 0) + padapter->registrypriv.preamble = PREAMBLE_LONG; + else if (preamblemode == 1) + padapter->registrypriv.preamble = PREAMBLE_AUTO; + else if (preamblemode == 2) + padapter->registrypriv.preamble = PREAMBLE_SHORT; + *(u32 *)poid_par_priv->information_buf = preamblemode; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_dedicate_probe_hdl(struct oid_par_priv + *poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + padapter->xmitpriv.tx_bytes; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + padapter->recvpriv.rx_bytes; + *poid_par_priv->bytes_rw = poid_par_priv-> + information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_current_tx_power_level_hdl(struct oid_par_priv + *poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv + *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv + *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct NDIS_802_11_CONFIGURATION *pnic_Config; + u32 channelnum; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) + pnic_Config = &pmlmepriv->cur_network.network.Configuration; + else + pnic_Config = &padapter->registrypriv.dev_network. + Configuration; + channelnum = pnic_Config->DSConfig; + *(u32 *)poid_par_priv->information_buf = channelnum; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv + *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_supported_wireless_mode_hdl(struct oid_par_priv + *poid_par_priv) +{ + u32 ulInfo = 0; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + ulInfo |= 0x0100; /* WIRELESS_MODE_B */ + ulInfo |= 0x0200; /* WIRELESS_MODE_G */ + ulInfo |= 0x0400; /* WIRELESS_MODE_A */ + *(u32 *) poid_par_priv->information_buf = ulInfo; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + return RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + + +uint oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv + *poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv + *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv + *poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv + *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv* + poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv* + poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */ + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len == + (sizeof(unsigned long) * 3)) { + if (!r8712_setrfreg_cmd(Adapter, + *(unsigned char *)poid_par_priv->information_buf, + (unsigned long)(*((unsigned long *) + poid_par_priv->information_buf + 2)))) + status = RNDIS_STATUS_NOT_ACCEPTED; + } else + status = RNDIS_STATUS_INVALID_LENGTH; + return status; +} + +uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */ + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len == (sizeof(unsigned long)*3)) { + if (Adapter->mppriv.act_in_progress == true) + status = RNDIS_STATUS_NOT_ACCEPTED; + else { + /* init workparam */ + Adapter->mppriv.act_in_progress = true; + Adapter->mppriv.workparam.bcompleted = false; + Adapter->mppriv.workparam.act_type = MPT_READ_RF; + Adapter->mppriv.workparam.io_offset = *(unsigned long *) + poid_par_priv->information_buf; + Adapter->mppriv.workparam.io_value = 0xcccccccc; + + /* RegOffsetValue - The offset of RF register to read. + * RegDataWidth - The data width of RF register to read. + * RegDataValue - The value to read. + * RegOffsetValue = *((unsigned long *)InformationBuffer); + * RegDataWidth = *((unsigned long *)InformationBuffer+1); + * RegDataValue = *((unsigned long *)InformationBuffer+2); + */ + if (!r8712_getrfreg_cmd(Adapter, + *(unsigned char *)poid_par_priv->information_buf, + (unsigned char *)&Adapter->mppriv.workparam. + io_value)) + status = RNDIS_STATUS_NOT_ACCEPTED; + } + } else + status = RNDIS_STATUS_INVALID_LENGTH; + return status; +} + +enum _CONNECT_STATE_ { + CHECKINGSTATUS, + ASSOCIATED, + ADHOCMODE, + NOTASSOCIATED +}; + +uint oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *padapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u32 ulInfo; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + /* nStatus==0 CheckingStatus + * nStatus==1 Associated + * nStatus==2 AdHocMode + * nStatus==3 NotAssociated + */ + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) + ulInfo = CHECKINGSTATUS; + else if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + ulInfo = ASSOCIATED; + else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) + ulInfo = ADHOCMODE; + else + ulInfo = NOTASSOCIATED; + *(u32 *)poid_par_priv->information_buf = ulInfo; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h new file mode 100644 index 000000000..3bcceae3c --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h @@ -0,0 +1,121 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL871X_IOCTL_RTL_H +#define _RTL871X_IOCTL_RTL_H + +#include "osdep_service.h" +#include "drv_types.h" + +/*************** oid_rtl_seg_01_01 **************/ +uint oid_rt_get_signal_quality_hdl( + struct oid_par_priv *poid_par_priv);/*84*/ +uint oid_rt_get_small_packet_crc_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_middle_packet_crc_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_large_packet_crc_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_tx_retry_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_rx_retry_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_rx_total_packet_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_tx_beacon_ok_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_tx_beacon_err_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_rx_icv_err_hdl( + struct oid_par_priv *poid_par_priv);/*93*/ +uint oid_rt_set_encryption_algorithm_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_preamble_mode_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_ap_ip_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_channelplan_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_set_channelplan_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_set_preamble_mode_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_set_bcn_intvl_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_dedicate_probe_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_total_tx_bytes_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_total_rx_bytes_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_current_tx_power_level_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_enc_key_mismatch_count_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_enc_key_match_count_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_channel_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_hardware_radio_off_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_key_mismatch_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_supported_wireless_mode_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_channel_list_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_scan_in_progress_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_forced_data_rate_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_wireless_mode_for_scan_list_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_bss_wireless_mode_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_scan_with_magic_packet_hdl( + struct oid_par_priv *poid_par_priv); + +/************** oid_rtl_seg_01_03 section start **************/ +uint oid_rt_ap_get_associated_station_list_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_ap_switch_into_ap_mode_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_ap_supported_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_ap_set_passphrase_hdl( + struct oid_par_priv *poid_par_priv); +/* oid_rtl_seg_01_11 */ +uint oid_rt_pro_rf_write_registry_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_rf_read_registry_hdl( + struct oid_par_priv *poid_par_priv); +/*************** oid_rtl_seg_03_00 section start **************/ +uint oid_rt_get_connect_state_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_set_default_key_id_hdl( + struct oid_par_priv *poid_par_priv); + +#endif + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_set.c new file mode 100644 index 000000000..22262b355 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_set.c @@ -0,0 +1,370 @@ +/****************************************************************************** + * rtl871x_ioctl_set.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_IOCTL_SET_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "rtl871x_ioctl_set.h" +#include "usb_osintf.h" +#include "usb_ops.h" + +#define IS_MAC_ADDRESS_BROADCAST(addr) \ +( \ + ((addr[0] == 0xff) && (addr[1] == 0xff) && \ + (addr[2] == 0xff) && (addr[3] == 0xff) && \ + (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \ +) + +static u8 validate_ssid(struct ndis_802_11_ssid *ssid) +{ + u8 i; + + if (ssid->SsidLength > 32) + return false; + for (i = 0; i < ssid->SsidLength; i++) { + /* wifi, printable ascii code must be supported */ + if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) + return false; + } + return true; +} + +static u8 do_join(struct _adapter *padapter) +{ + struct list_head *plist, *phead; + u8 *pibss = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct __queue *queue = &(pmlmepriv->scanned_queue); + + phead = &queue->queue; + plist = phead->next; + pmlmepriv->cur_network.join_res = -2; + pmlmepriv->fw_state |= _FW_UNDER_LINKING; + pmlmepriv->pscanned = plist; + pmlmepriv->to_join = true; + + /* adhoc mode will start with an empty queue, but skip checking */ + if (!check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) && + list_empty(&queue->queue)) { + if (pmlmepriv->fw_state & _FW_UNDER_LINKING) + pmlmepriv->fw_state ^= _FW_UNDER_LINKING; + /* when set_ssid/set_bssid for do_join(), but scanning queue + * is empty we try to issue sitesurvey firstly + */ + if (!pmlmepriv->sitesurveyctrl.traffic_busy) + r8712_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid); + return true; + } else { + int ret; + + ret = r8712_select_and_join_from_scan(pmlmepriv); + if (ret == _SUCCESS) + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); + else { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + /* submit r8712_createbss_cmd to change to an + * ADHOC_MASTER pmlmepriv->lock has been + * acquired by caller... + */ + struct wlan_bssid_ex *pdev_network = + &(padapter->registrypriv.dev_network); + pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; + pibss = padapter->registrypriv.dev_network. + MacAddress; + memcpy(&pdev_network->Ssid, + &pmlmepriv->assoc_ssid, + sizeof(struct ndis_802_11_ssid)); + r8712_update_registrypriv_dev_network(padapter); + r8712_generate_random_ibss(pibss); + if (r8712_createbss_cmd(padapter) != _SUCCESS) + return false; + pmlmepriv->to_join = false; + } else { + /* can't associate ; reset under-linking */ + if (pmlmepriv->fw_state & _FW_UNDER_LINKING) + pmlmepriv->fw_state ^= + _FW_UNDER_LINKING; + /* when set_ssid/set_bssid for do_join(), but + * there are no desired bss in scanning queue + * we try to issue sitesurvey first + */ + if (!pmlmepriv->sitesurveyctrl.traffic_busy) + r8712_sitesurvey_cmd(padapter, + &pmlmepriv->assoc_ssid); + } + } + } + return true; +} + +u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid) +{ + unsigned long irqL; + u8 status = true; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) { + status = false; + return status; + } + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | + _FW_UNDER_LINKING) == true) { + status = check_fwstate(pmlmepriv, _FW_UNDER_LINKING); + goto _Abort_Set_BSSID; + } + if (check_fwstate(pmlmepriv, + _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) { + if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, + ETH_ALEN)) { + if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + goto _Abort_Set_BSSID; /* driver is in + * WIFI_ADHOC_MASTER_STATE */ + } else { + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + if ((check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE))) { + _clr_fwstate_(pmlmepriv, + WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } + } + memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); + pmlmepriv->assoc_by_bssid = true; + status = do_join(padapter); + goto done; +_Abort_Set_BSSID: +done: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return status; +} + +void r8712_set_802_11_ssid(struct _adapter *padapter, + struct ndis_802_11_ssid *ssid) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *pnetwork = &pmlmepriv->cur_network; + + if (!padapter->hw_init_completed) + return; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) { + check_fwstate(pmlmepriv, _FW_UNDER_LINKING); + goto _Abort_Set_SSID; + } + if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) { + if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && + (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, + ssid->SsidLength))) { + if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + if (!r8712_is_same_ibss(padapter, + pnetwork)) { + /* if in WIFI_ADHOC_MASTER_STATE or + * WIFI_ADHOC_STATE, create bss or + * rejoin again + */ + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, + _FW_LINKED) == true) + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + if (check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE)) { + _clr_fwstate_(pmlmepriv, + WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, + WIFI_ADHOC_STATE); + } + } else + goto _Abort_Set_SSID; /* driver is in + * WIFI_ADHOC_MASTER_STATE */ + } + } else { + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + if (check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE) == true) { + _clr_fwstate_(pmlmepriv, + WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } + } + if (padapter->securitypriv.btkip_countermeasure == true) + goto _Abort_Set_SSID; + if (!validate_ssid(ssid)) + goto _Abort_Set_SSID; + memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); + pmlmepriv->assoc_by_bssid = false; + do_join(padapter); + goto done; +_Abort_Set_SSID: +done: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter, + enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + enum NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = + &(cur_network->network.InfrastructureMode); + + if (*pold_state != networktype) { + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || + (*pold_state == Ndis802_11IBSS)) + r8712_disassoc_cmd(padapter); + if (check_fwstate(pmlmepriv, + _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) + r8712_free_assoc_resources(padapter); + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || + (*pold_state == Ndis802_11Infrastructure) || + (*pold_state == Ndis802_11IBSS)) { + /* will clr Linked_state before this function, + * we must have checked whether issue dis-assoc_cmd or + * not */ + r8712_ind_disconnect(padapter); + } + *pold_state = networktype; + /* clear WIFI_STATION_STATE; WIFI_AP_STATE; WIFI_ADHOC_STATE; + * WIFI_ADHOC_MASTER_STATE */ + _clr_fwstate_(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE | + WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE); + switch (networktype) { + case Ndis802_11IBSS: + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; + case Ndis802_11Infrastructure: + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + break; + case Ndis802_11APMode: + set_fwstate(pmlmepriv, WIFI_AP_STATE); + break; + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + break; + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + } +} + +u8 r8712_set_802_11_disassociate(struct _adapter *padapter) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + r8712_disassoc_cmd(padapter); + r8712_ind_disconnect(padapter); + r8712_free_assoc_resources(padapter); + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return true; +} + +u8 r8712_set_802_11_bssid_list_scan(struct _adapter *padapter) +{ + struct mlme_priv *pmlmepriv = NULL; + unsigned long irqL; + u8 ret = true; + + if (!padapter) + return false; + pmlmepriv = &padapter->mlmepriv; + if (!padapter->hw_init_completed) + return false; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) || + (pmlmepriv->sitesurveyctrl.traffic_busy == true)) { + /* Scan or linking is in progress, do nothing. */ + ret = (u8)check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); + } else { + r8712_free_network_queue(padapter); + ret = r8712_sitesurvey_cmd(padapter, NULL); + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return ret; +} + +u8 r8712_set_802_11_authentication_mode(struct _adapter *padapter, + enum NDIS_802_11_AUTHENTICATION_MODE authmode) +{ + struct security_priv *psecuritypriv = &padapter->securitypriv; + u8 ret; + + psecuritypriv->ndisauthtype = authmode; + if (psecuritypriv->ndisauthtype > 3) + psecuritypriv->AuthAlgrthm = 2; /* 802.1x */ + if (r8712_set_auth(padapter, psecuritypriv) == _SUCCESS) + ret = true; + else + ret = false; + return ret; +} + +u8 r8712_set_802_11_add_wep(struct _adapter *padapter, + struct NDIS_802_11_WEP *wep) +{ + sint keyid; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + keyid = wep->KeyIndex & 0x3fffffff; + if (keyid >= WEP_KEYS) + return false; + switch (wep->KeyLength) { + case 5: + psecuritypriv->PrivacyAlgrthm = _WEP40_; + break; + case 13: + psecuritypriv->PrivacyAlgrthm = _WEP104_; + break; + default: + psecuritypriv->PrivacyAlgrthm = _NO_PRIVACY_; + break; + } + memcpy(psecuritypriv->DefKey[keyid].skey, &wep->KeyMaterial, + wep->KeyLength); + psecuritypriv->DefKeylen[keyid] = wep->KeyLength; + psecuritypriv->PrivacyKeyIndex = keyid; + if (r8712_set_key(padapter, psecuritypriv, keyid) == _FAIL) + return false; + return _SUCCESS; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_ioctl_set.h b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_set.h new file mode 100644 index 000000000..2c94cd151 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_ioctl_set.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __IOCTL_SET_H +#define __IOCTL_SET_H + +#include "drv_types.h" + +typedef u8 NDIS_802_11_PMKID_VALUE[16]; + +struct BSSIDInfo { + unsigned char BSSID[6]; + NDIS_802_11_PMKID_VALUE PMKID; +}; + +u8 r8712_set_802_11_authentication_mode(struct _adapter *pdapter, + enum NDIS_802_11_AUTHENTICATION_MODE authmode); + +u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid); + +u8 r8712_set_802_11_add_wep(struct _adapter *padapter, + struct NDIS_802_11_WEP *wep); + +u8 r8712_set_802_11_disassociate(struct _adapter *padapter); + +u8 r8712_set_802_11_bssid_list_scan(struct _adapter *padapter); + +void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter, + enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype); + +void r8712_set_802_11_ssid(struct _adapter *padapter, + struct ndis_802_11_ssid *ssid); + +#endif + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_led.h b/kernel/drivers/staging/rtl8712/rtl871x_led.h new file mode 100644 index 000000000..eb612053a --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_led.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL8712_LED_H +#define __RTL8712_LED_H + +#include "osdep_service.h" +#include "drv_types.h" + +/*=========================================================================== + * LED customization. + *=========================================================================== + */ +enum LED_CTL_MODE { + LED_CTL_POWER_ON = 1, + LED_CTL_LINK = 2, + LED_CTL_NO_LINK = 3, + LED_CTL_TX = 4, + LED_CTL_RX = 5, + LED_CTL_SITE_SURVEY = 6, + LED_CTL_POWER_OFF = 7, + LED_CTL_START_TO_LINK = 8, + LED_CTL_START_WPS = 9, + LED_CTL_STOP_WPS = 10, + LED_CTL_START_WPS_BOTTON = 11, + LED_CTL_STOP_WPS_FAIL = 12, + LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, +}; + +#define IS_LED_WPS_BLINKING(_LED_871x) \ + (((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS \ + || ((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS_STOP \ + || ((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress) + +#define IS_LED_BLINKING(_LED_871x) \ + (((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress \ + || ((struct LED_871x *)_LED_871x)->bLedScanBlinkInProgress) + +enum LED_PIN_871x { + LED_PIN_GPIO0, + LED_PIN_LED0, + LED_PIN_LED1 +}; + +/*=========================================================================== + * LED customization. + *=========================================================================== + */ +enum LED_STRATEGY_871x { + SW_LED_MODE0, /* SW control 1 LED via GPIO0. It is default option. */ + SW_LED_MODE1, /* 2 LEDs, through LED0 and LED1. For ALPHA. */ + SW_LED_MODE2, /* SW control 1 LED via GPIO0, + * custom for AzWave 8187 minicard. */ + SW_LED_MODE3, /* SW control 1 LED via GPIO0, + * customized for Sercomm Printer Server case.*/ + SW_LED_MODE4, /*for Edimax / Belkin*/ + SW_LED_MODE5, /*for Sercomm / Belkin*/ + SW_LED_MODE6, /*for WNC / Corega*/ + HW_LED, /* HW control 2 LEDs, LED0 and LED1 (there are 4 different + * control modes, see MAC.CONFIG1 for details.)*/ +}; + +struct LED_871x { + struct _adapter *padapter; + enum LED_PIN_871x LedPin; /* Implementation for this SW led. */ + u32 CurrLedState; /* Current LED state. */ + u8 bLedOn; /* true if LED is ON */ + u8 bSWLedCtrl; + u8 bLedBlinkInProgress; /*true if blinking */ + u8 bLedNoLinkBlinkInProgress; + u8 bLedLinkBlinkInProgress; + u8 bLedStartToLinkBlinkInProgress; + u8 bLedScanBlinkInProgress; + u8 bLedWPSBlinkInProgress; + u32 BlinkTimes; /* No. times to toggle for blink.*/ + u32 BlinkingLedState; /* Next state for blinking, + * either LED_ON or OFF.*/ + + struct timer_list BlinkTimer; /* Timer object for led blinking.*/ + struct work_struct BlinkWorkItem; /* Workitem used by BlinkTimer */ +}; + +struct led_priv { + /* add for led control */ + struct LED_871x SwLed0; + struct LED_871x SwLed1; + enum LED_STRATEGY_871x LedStrategy; + u8 bRegUseLed; + void (*LedControlHandler)(struct _adapter *padapter, + enum LED_CTL_MODE LedAction); + /* add for led control */ +}; + +/*=========================================================================== + * Interface to manipulate LED objects. + *===========================================================================*/ +void r8712_InitSwLeds(struct _adapter *padapter); +void r8712_DeInitSwLeds(struct _adapter *padapter); +void LedControl871x(struct _adapter *padapter, enum LED_CTL_MODE LedAction); + +#endif + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_mlme.c b/kernel/drivers/staging/rtl8712/rtl871x_mlme.c new file mode 100644 index 000000000..c044b0e55 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_mlme.c @@ -0,0 +1,1808 @@ +/****************************************************************************** + * rtl871x_mlme.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_MLME_C_ + +#include <linux/etherdevice.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "recv_osdep.h" +#include "xmit_osdep.h" +#include "mlme_osdep.h" +#include "sta_info.h" +#include "wifi.h" +#include "wlan_bssdef.h" + +static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len); + +static sint _init_mlme_priv(struct _adapter *padapter) +{ + sint i; + u8 *pbuf; + struct wlan_network *pnetwork; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + memset((u8 *)pmlmepriv, 0, sizeof(struct mlme_priv)); + pmlmepriv->nic_hdl = (u8 *)padapter; + pmlmepriv->pscanned = NULL; + pmlmepriv->fw_state = 0; + pmlmepriv->cur_network.network.InfrastructureMode = + Ndis802_11AutoUnknown; + /* Maybe someday we should rename this variable to "active_mode"(Jeff)*/ + pmlmepriv->passive_mode = 1; /* 1: active, 0: passive. */ + spin_lock_init(&(pmlmepriv->lock)); + spin_lock_init(&(pmlmepriv->lock2)); + _init_queue(&(pmlmepriv->free_bss_pool)); + _init_queue(&(pmlmepriv->scanned_queue)); + set_scanned_network_val(pmlmepriv, 0); + memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); + pbuf = kmalloc(MAX_BSS_CNT * (sizeof(struct wlan_network)), + GFP_ATOMIC); + if (pbuf == NULL) + return _FAIL; + pmlmepriv->free_bss_buf = pbuf; + pnetwork = (struct wlan_network *)pbuf; + for (i = 0; i < MAX_BSS_CNT; i++) { + INIT_LIST_HEAD(&(pnetwork->list)); + list_add_tail(&(pnetwork->list), + &(pmlmepriv->free_bss_pool.queue)); + pnetwork++; + } + pmlmepriv->sitesurveyctrl.last_rx_pkts = 0; + pmlmepriv->sitesurveyctrl.last_tx_pkts = 0; + pmlmepriv->sitesurveyctrl.traffic_busy = false; + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + r8712_init_mlme_timer(padapter); + return _SUCCESS; +} + +struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv) +{ + unsigned long irqL; + struct wlan_network *pnetwork; + struct __queue *free_queue = &pmlmepriv->free_bss_pool; + struct list_head *plist = NULL; + + if (list_empty(&free_queue->queue)) + return NULL; + spin_lock_irqsave(&free_queue->lock, irqL); + plist = free_queue->queue.next; + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + list_del_init(&pnetwork->list); + pnetwork->last_scanned = jiffies; + pmlmepriv->num_of_scanned++; + spin_unlock_irqrestore(&free_queue->lock, irqL); + return pnetwork; +} + +static void _free_network(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork) +{ + u32 curr_time, delta_time; + unsigned long irqL; + struct __queue *free_queue = &(pmlmepriv->free_bss_pool); + + if (pnetwork == NULL) + return; + if (pnetwork->fixed == true) + return; + curr_time = jiffies; + delta_time = (curr_time - (u32)pnetwork->last_scanned) / HZ; + if (delta_time < SCANQUEUE_LIFETIME) + return; + spin_lock_irqsave(&free_queue->lock, irqL); + list_del_init(&pnetwork->list); + list_add_tail(&pnetwork->list, &free_queue->queue); + pmlmepriv->num_of_scanned--; + spin_unlock_irqrestore(&free_queue->lock, irqL); +} + +static void _free_network_nolock(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork) +{ + struct __queue *free_queue = &pmlmepriv->free_bss_pool; + + if (pnetwork == NULL) + return; + if (pnetwork->fixed == true) + return; + list_del_init(&pnetwork->list); + list_add_tail(&pnetwork->list, &free_queue->queue); + pmlmepriv->num_of_scanned--; +} + + +/* + return the wlan_network with the matching addr + Shall be called under atomic context... + to avoid possible racing condition... +*/ +static struct wlan_network *_r8712_find_network(struct __queue *scanned_queue, + u8 *addr) +{ + unsigned long irqL; + struct list_head *phead, *plist; + struct wlan_network *pnetwork = NULL; + + if (is_zero_ether_addr(addr)) + return NULL; + spin_lock_irqsave(&scanned_queue->lock, irqL); + phead = &scanned_queue->queue; + plist = phead->next; + while (plist != phead) { + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + plist = plist->next; + if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN)) + break; + } + spin_unlock_irqrestore(&scanned_queue->lock, irqL); + return pnetwork; +} + +static void _free_network_queue(struct _adapter *padapter) +{ + unsigned long irqL; + struct list_head *phead, *plist; + struct wlan_network *pnetwork; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct __queue *scanned_queue = &pmlmepriv->scanned_queue; + + spin_lock_irqsave(&scanned_queue->lock, irqL); + phead = &scanned_queue->queue; + plist = phead->next; + while (end_of_queue_search(phead, plist) == false) { + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + plist = plist->next; + _free_network(pmlmepriv, pnetwork); + } + spin_unlock_irqrestore(&scanned_queue->lock, irqL); +} + +sint r8712_if_up(struct _adapter *padapter) +{ + sint res; + + if (padapter->bDriverStopped || padapter->bSurpriseRemoved || + (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) { + res = false; + } else + res = true; + return res; +} + +void r8712_generate_random_ibss(u8 *pibss) +{ + u32 curtime = jiffies; + + pibss[0] = 0x02; /*in ad-hoc mode bit1 must set to 1 */ + pibss[1] = 0x11; + pibss[2] = 0x87; + pibss[3] = (u8)(curtime & 0xff); + pibss[4] = (u8)((curtime>>8) & 0xff); + pibss[5] = (u8)((curtime>>16) & 0xff); +} + +uint r8712_get_ndis_wlan_bssid_ex_sz(struct ndis_wlan_bssid_ex *bss) +{ + uint t_len; + + t_len = sizeof(u32) + 6 * sizeof(unsigned long) + 2 + + sizeof(struct ndis_802_11_ssid) + sizeof(u32) + + sizeof(s32) + + sizeof(enum NDIS_802_11_NETWORK_TYPE) + + sizeof(struct NDIS_802_11_CONFIGURATION) + + sizeof(enum NDIS_802_11_NETWORK_INFRASTRUCTURE) + + sizeof(NDIS_802_11_RATES_EX) + + sizeof(u32) + bss->IELength; + return t_len; +} + +u8 *r8712_get_capability_from_ie(u8 *ie) +{ + return ie + 8 + 2; +} + +int r8712_init_mlme_priv(struct _adapter *padapter) +{ + return _init_mlme_priv(padapter); +} + +void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv) +{ + kfree(pmlmepriv->free_bss_buf); +} + +static struct wlan_network *alloc_network(struct mlme_priv *pmlmepriv) +{ + return _r8712_alloc_network(pmlmepriv); +} + +static void free_network_nolock(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork) +{ + _free_network_nolock(pmlmepriv, pnetwork); +} + +void r8712_free_network_queue(struct _adapter *dev) +{ + _free_network_queue(dev); +} + +/* + return the wlan_network with the matching addr + + Shall be called under atomic context... + to avoid possible racing condition... +*/ +static struct wlan_network *r8712_find_network(struct __queue *scanned_queue, + u8 *addr) +{ + struct wlan_network *pnetwork = _r8712_find_network(scanned_queue, + addr); + + return pnetwork; +} + +int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork) +{ + int ret = true; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + if ((psecuritypriv->PrivacyAlgrthm != _NO_PRIVACY_) && + (pnetwork->network.Privacy == 0)) + ret = false; + else if ((psecuritypriv->PrivacyAlgrthm == _NO_PRIVACY_) && + (pnetwork->network.Privacy == 1)) + ret = false; + else + ret = true; + return ret; + +} + +static int is_same_network(struct ndis_wlan_bssid_ex *src, + struct ndis_wlan_bssid_ex *dst) +{ + u16 s_cap, d_cap; + + memcpy((u8 *)&s_cap, r8712_get_capability_from_ie(src->IEs), 2); + memcpy((u8 *)&d_cap, r8712_get_capability_from_ie(dst->IEs), 2); + return (src->Ssid.SsidLength == dst->Ssid.SsidLength) && + (src->Configuration.DSConfig == + dst->Configuration.DSConfig) && + ((!memcmp(src->MacAddress, dst->MacAddress, + ETH_ALEN))) && + ((!memcmp(src->Ssid.Ssid, + dst->Ssid.Ssid, + src->Ssid.SsidLength))) && + ((s_cap & WLAN_CAPABILITY_IBSS) == + (d_cap & WLAN_CAPABILITY_IBSS)) && + ((s_cap & WLAN_CAPABILITY_BSS) == + (d_cap & WLAN_CAPABILITY_BSS)); + +} + +struct wlan_network *r8712_get_oldest_wlan_network( + struct __queue *scanned_queue) +{ + struct list_head *plist, *phead; + struct wlan_network *pwlan = NULL; + struct wlan_network *oldest = NULL; + + phead = &scanned_queue->queue; + plist = phead->next; + while (1) { + if (end_of_queue_search(phead, plist) == true) + break; + pwlan = LIST_CONTAINOR(plist, struct wlan_network, list); + if (pwlan->fixed != true) { + if (oldest == NULL || + time_after((unsigned long)oldest->last_scanned, + (unsigned long)pwlan->last_scanned)) + oldest = pwlan; + } + plist = plist->next; + } + return oldest; +} + +static void update_network(struct ndis_wlan_bssid_ex *dst, + struct ndis_wlan_bssid_ex *src, + struct _adapter *padapter) +{ + u32 last_evm = 0, tmpVal; + + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && + is_same_network(&(padapter->mlmepriv.cur_network.network), src)) { + if (padapter->recvpriv.signal_qual_data.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + padapter->recvpriv.signal_qual_data.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = padapter->recvpriv.signal_qual_data. + elements[padapter->recvpriv. + signal_qual_data.index]; + padapter->recvpriv.signal_qual_data.total_val -= + last_evm; + } + padapter->recvpriv.signal_qual_data.total_val += src->Rssi; + + padapter->recvpriv.signal_qual_data. + elements[padapter->recvpriv.signal_qual_data. + index++] = src->Rssi; + if (padapter->recvpriv.signal_qual_data.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + padapter->recvpriv.signal_qual_data.index = 0; + /* <1> Showed on UI for user, in percentage. */ + tmpVal = padapter->recvpriv.signal_qual_data.total_val / + padapter->recvpriv.signal_qual_data.total_num; + padapter->recvpriv.signal = (u8)tmpVal; + + src->Rssi = padapter->recvpriv.signal; + } else + src->Rssi = (src->Rssi + dst->Rssi) / 2; + memcpy((u8 *)dst, (u8 *)src, r8712_get_ndis_wlan_bssid_ex_sz(src)); +} + +static void update_current_network(struct _adapter *adapter, + struct ndis_wlan_bssid_ex *pnetwork) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + if (is_same_network(&(pmlmepriv->cur_network.network), pnetwork)) { + update_network(&(pmlmepriv->cur_network.network), + pnetwork, adapter); + r8712_update_protection(adapter, + (pmlmepriv->cur_network.network.IEs) + + sizeof(struct NDIS_802_11_FIXED_IEs), + pmlmepriv->cur_network.network.IELength); + } +} + +/* +Caller must hold pmlmepriv->lock first. +*/ +static void update_scanned_network(struct _adapter *adapter, + struct ndis_wlan_bssid_ex *target) +{ + struct list_head *plist, *phead; + + u32 bssid_ex_sz; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct __queue *queue = &pmlmepriv->scanned_queue; + struct wlan_network *pnetwork = NULL; + struct wlan_network *oldest = NULL; + + phead = &queue->queue; + plist = phead->next; + + while (1) { + if (end_of_queue_search(phead, plist) == true) + break; + + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + if (is_same_network(&pnetwork->network, target)) + break; + if ((oldest == ((struct wlan_network *)0)) || + time_after((unsigned long)oldest->last_scanned, + (unsigned long)pnetwork->last_scanned)) + oldest = pnetwork; + + plist = plist->next; + } + + + /* If we didn't find a match, then get a new network slot to initialize + * with this beacon's information */ + if (end_of_queue_search(phead, plist) == true) { + if (list_empty(&pmlmepriv->free_bss_pool.queue)) { + /* If there are no more slots, expire the oldest */ + pnetwork = oldest; + target->Rssi = (pnetwork->network.Rssi + + target->Rssi) / 2; + memcpy(&pnetwork->network, target, + r8712_get_ndis_wlan_bssid_ex_sz(target)); + pnetwork->last_scanned = jiffies; + } else { + /* Otherwise just pull from the free list */ + /* update scan_time */ + pnetwork = alloc_network(pmlmepriv); + if (pnetwork == NULL) + return; + bssid_ex_sz = r8712_get_ndis_wlan_bssid_ex_sz(target); + target->Length = bssid_ex_sz; + memcpy(&pnetwork->network, target, bssid_ex_sz); + list_add_tail(&pnetwork->list, &queue->queue); + } + } else { + /* we have an entry and we are going to update it. But + * this entry may be already expired. In this case we + * do the same as we found a new net and call the new_net + * handler + */ + update_network(&pnetwork->network, target, adapter); + pnetwork->last_scanned = jiffies; + } +} + +static void rtl8711_add_network(struct _adapter *adapter, + struct ndis_wlan_bssid_ex *pnetwork) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &(((struct _adapter *)adapter)->mlmepriv); + struct __queue *queue = &pmlmepriv->scanned_queue; + + spin_lock_irqsave(&queue->lock, irqL); + update_current_network(adapter, pnetwork); + update_scanned_network(adapter, pnetwork); + spin_unlock_irqrestore(&queue->lock, irqL); +} + +/*select the desired network based on the capability of the (i)bss. + * check items: (1) security + * (2) network_type + * (3) WMM + * (4) HT + * (5) others + */ +static int is_desired_network(struct _adapter *adapter, + struct wlan_network *pnetwork) +{ + u8 wps_ie[512]; + uint wps_ielen; + int bselected = true; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + if (psecuritypriv->wps_phase == true) { + if (r8712_get_wps_ie(pnetwork->network.IEs, + pnetwork->network.IELength, wps_ie, + &wps_ielen) == true) + return true; + else + return false; + } + if ((psecuritypriv->PrivacyAlgrthm != _NO_PRIVACY_) && + (pnetwork->network.Privacy == 0)) + bselected = false; + if (check_fwstate(&adapter->mlmepriv, WIFI_ADHOC_STATE) == true) { + if (pnetwork->network.InfrastructureMode != + adapter->mlmepriv.cur_network.network. + InfrastructureMode) + bselected = false; + } + return bselected; +} + +/* TODO: Perry : For Power Management */ +void r8712_atimdone_event_callback(struct _adapter *adapter, u8 *pbuf) +{ +} + +void r8712_survey_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + unsigned long flags; + u32 len; + struct ndis_wlan_bssid_ex *pnetwork; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + pnetwork = (struct ndis_wlan_bssid_ex *)pbuf; +#ifdef __BIG_ENDIAN + /* endian_convert */ + pnetwork->Length = le32_to_cpu(pnetwork->Length); + pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); + pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy); + pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); + pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse); + pnetwork->Configuration.ATIMWindow = + le32_to_cpu(pnetwork->Configuration.ATIMWindow); + pnetwork->Configuration.BeaconPeriod = + le32_to_cpu(pnetwork->Configuration.BeaconPeriod); + pnetwork->Configuration.DSConfig = + le32_to_cpu(pnetwork->Configuration.DSConfig); + pnetwork->Configuration.FHConfig.DwellTime = + le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime); + pnetwork->Configuration.FHConfig.HopPattern = + le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern); + pnetwork->Configuration.FHConfig.HopSet = + le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet); + pnetwork->Configuration.FHConfig.Length = + le32_to_cpu(pnetwork->Configuration.FHConfig.Length); + pnetwork->Configuration.Length = + le32_to_cpu(pnetwork->Configuration.Length); + pnetwork->InfrastructureMode = + le32_to_cpu(pnetwork->InfrastructureMode); + pnetwork->IELength = le32_to_cpu(pnetwork->IELength); +#endif + len = r8712_get_ndis_wlan_bssid_ex_sz(pnetwork); + if (len > sizeof(struct wlan_bssid_ex)) + return; + spin_lock_irqsave(&pmlmepriv->lock2, flags); + /* update IBSS_network 's timestamp */ + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { + if (!memcmp(&(pmlmepriv->cur_network.network.MacAddress), + pnetwork->MacAddress, ETH_ALEN)) { + struct wlan_network *ibss_wlan = NULL; + + memcpy(pmlmepriv->cur_network.network.IEs, + pnetwork->IEs, 8); + ibss_wlan = r8712_find_network( + &pmlmepriv->scanned_queue, + pnetwork->MacAddress); + if (ibss_wlan) { + memcpy(ibss_wlan->network.IEs, + pnetwork->IEs, 8); + goto exit; + } + } + } + /* lock pmlmepriv->lock when you accessing network_q */ + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == false) { + if (pnetwork->Ssid.Ssid[0] != 0) + rtl8711_add_network(adapter, pnetwork); + else { + pnetwork->Ssid.SsidLength = 8; + memcpy(pnetwork->Ssid.Ssid, "<hidden>", 8); + rtl8711_add_network(adapter, pnetwork); + } + } +exit: + spin_unlock_irqrestore(&pmlmepriv->lock2, flags); +} + +void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { + del_timer(&pmlmepriv->scan_to_timer); + + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + } + + if (pmlmepriv->to_join == true) { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == false) { + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + + if (r8712_select_and_join_from_scan(pmlmepriv) + == _SUCCESS) + mod_timer(&pmlmepriv->assoc_timer, jiffies + + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); + else { + struct wlan_bssid_ex *pdev_network = + &(adapter->registrypriv.dev_network); + u8 *pibss = + adapter->registrypriv. + dev_network.MacAddress; + pmlmepriv->fw_state ^= _FW_UNDER_SURVEY; + memcpy(&pdev_network->Ssid, + &pmlmepriv->assoc_ssid, + sizeof(struct + ndis_802_11_ssid)); + r8712_update_registrypriv_dev_network + (adapter); + r8712_generate_random_ibss(pibss); + pmlmepriv->fw_state = + WIFI_ADHOC_MASTER_STATE; + pmlmepriv->to_join = false; + } + } + } else { + pmlmepriv->to_join = false; + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + if (r8712_select_and_join_from_scan(pmlmepriv) == + _SUCCESS) + mod_timer(&pmlmepriv->assoc_timer, jiffies + + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); + else + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + } + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +/* + *r8712_free_assoc_resources: the caller has to lock pmlmepriv->lock + */ +void r8712_free_assoc_resources(struct _adapter *adapter) +{ + unsigned long irqL; + struct wlan_network *pwlan = NULL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + + pwlan = r8712_find_network(&pmlmepriv->scanned_queue, + tgt_network->network.MacAddress); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) { + struct sta_info *psta; + + psta = r8712_get_stainfo(&adapter->stapriv, + tgt_network->network.MacAddress); + + spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); + r8712_free_stainfo(adapter, psta); + spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); + } + + if (check_fwstate(pmlmepriv, + WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) + r8712_free_all_stainfo(adapter); + if (pwlan) + pwlan->fixed = false; + + if (((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) && + (adapter->stapriv.asoc_sta_count == 1))) + free_network_nolock(pmlmepriv, pwlan); +} + +/* +*r8712_indicate_connect: the caller has to lock pmlmepriv->lock +*/ +void r8712_indicate_connect(struct _adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + pmlmepriv->to_join = false; + set_fwstate(pmlmepriv, _FW_LINKED); + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_LINK); + r8712_os_indicate_connect(padapter); + if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) + mod_timer(&pmlmepriv->dhcp_timer, + jiffies + msecs_to_jiffies(60000)); +} + + +/* +*r8712_ind_disconnect: the caller has to lock pmlmepriv->lock +*/ +void r8712_ind_disconnect(struct _adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + _clr_fwstate_(pmlmepriv, _FW_LINKED); + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); + r8712_os_indicate_disconnect(padapter); + } + if (padapter->pwrctrlpriv.pwr_mode != + padapter->registrypriv.power_mgnt) { + del_timer(&pmlmepriv->dhcp_timer); + r8712_set_ps_mode(padapter, padapter->registrypriv.power_mgnt, + padapter->registrypriv.smart_ps); + } +} + +/*Notes: + *pnetwork : returns from r8712_joinbss_event_callback + *ptarget_wlan: found from scanned_queue + *if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if + * "ptarget_sta" & "ptarget_wlan" exist. + *if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check + * if "ptarget_wlan" exist. + *if join_res > 0, update "cur_network->network" from + * "pnetwork->network" if (ptarget_wlan !=NULL). + */ +void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + unsigned long irqL = 0, irqL2; + struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; + unsigned int the_same_macaddr = false; + struct wlan_network *pnetwork; + + if (sizeof(struct list_head) == 4 * sizeof(u32)) { + pnetwork = kmalloc(sizeof(struct wlan_network), GFP_ATOMIC); + if (!pnetwork) + return; + memcpy((u8 *)pnetwork+16, (u8 *)pbuf + 8, + sizeof(struct wlan_network) - 16); + } else + pnetwork = (struct wlan_network *)pbuf; + +#ifdef __BIG_ENDIAN + /* endian_convert */ + pnetwork->join_res = le32_to_cpu(pnetwork->join_res); + pnetwork->network_type = le32_to_cpu(pnetwork->network_type); + pnetwork->network.Length = le32_to_cpu(pnetwork->network.Length); + pnetwork->network.Ssid.SsidLength = + le32_to_cpu(pnetwork->network.Ssid.SsidLength); + pnetwork->network.Privacy = le32_to_cpu(pnetwork->network.Privacy); + pnetwork->network.Rssi = le32_to_cpu(pnetwork->network.Rssi); + pnetwork->network.NetworkTypeInUse = + le32_to_cpu(pnetwork->network.NetworkTypeInUse); + pnetwork->network.Configuration.ATIMWindow = + le32_to_cpu(pnetwork->network.Configuration.ATIMWindow); + pnetwork->network.Configuration.BeaconPeriod = + le32_to_cpu(pnetwork->network.Configuration.BeaconPeriod); + pnetwork->network.Configuration.DSConfig = + le32_to_cpu(pnetwork->network.Configuration.DSConfig); + pnetwork->network.Configuration.FHConfig.DwellTime = + le32_to_cpu(pnetwork->network.Configuration.FHConfig. + DwellTime); + pnetwork->network.Configuration.FHConfig.HopPattern = + le32_to_cpu(pnetwork->network.Configuration. + FHConfig.HopPattern); + pnetwork->network.Configuration.FHConfig.HopSet = + le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopSet); + pnetwork->network.Configuration.FHConfig.Length = + le32_to_cpu(pnetwork->network.Configuration.FHConfig.Length); + pnetwork->network.Configuration.Length = + le32_to_cpu(pnetwork->network.Configuration.Length); + pnetwork->network.InfrastructureMode = + le32_to_cpu(pnetwork->network.InfrastructureMode); + pnetwork->network.IELength = le32_to_cpu(pnetwork->network.IELength); +#endif + + the_same_macaddr = !memcmp(pnetwork->network.MacAddress, + cur_network->network.MacAddress, ETH_ALEN); + pnetwork->network.Length = + r8712_get_ndis_wlan_bssid_ex_sz(&pnetwork->network); + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) + goto ignore_joinbss_callback; + if (pnetwork->join_res > 0) { + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { + /*s1. find ptarget_wlan*/ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + if (the_same_macaddr == true) + ptarget_wlan = + r8712_find_network(&pmlmepriv-> + scanned_queue, + cur_network->network.MacAddress); + else { + pcur_wlan = + r8712_find_network(&pmlmepriv-> + scanned_queue, + cur_network->network.MacAddress); + pcur_wlan->fixed = false; + + pcur_sta = r8712_get_stainfo(pstapriv, + cur_network->network.MacAddress); + spin_lock_irqsave(&pstapriv-> + sta_hash_lock, irqL2); + r8712_free_stainfo(adapter, pcur_sta); + spin_unlock_irqrestore(&(pstapriv-> + sta_hash_lock), irqL2); + + ptarget_wlan = + r8712_find_network(&pmlmepriv-> + scanned_queue, + pnetwork->network. + MacAddress); + if (ptarget_wlan) + ptarget_wlan->fixed = true; + } + } else { + ptarget_wlan = r8712_find_network(&pmlmepriv-> + scanned_queue, + pnetwork->network.MacAddress); + if (ptarget_wlan) + ptarget_wlan->fixed = true; + } + + if (ptarget_wlan == NULL) { + if (check_fwstate(pmlmepriv, + _FW_UNDER_LINKING)) + pmlmepriv->fw_state ^= + _FW_UNDER_LINKING; + goto ignore_joinbss_callback; + } + + /*s2. find ptarget_sta & update ptarget_sta*/ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + if (the_same_macaddr == true) { + ptarget_sta = + r8712_get_stainfo(pstapriv, + pnetwork->network.MacAddress); + if (ptarget_sta == NULL) + ptarget_sta = + r8712_alloc_stainfo(pstapriv, + pnetwork->network.MacAddress); + } else + ptarget_sta = + r8712_alloc_stainfo(pstapriv, + pnetwork->network.MacAddress); + if (ptarget_sta) /*update ptarget_sta*/ { + ptarget_sta->aid = pnetwork->join_res; + ptarget_sta->qos_option = 1; + ptarget_sta->mac_id = 5; + if (adapter->securitypriv. + AuthAlgrthm == 2) { + adapter->securitypriv. + binstallGrpkey = + false; + adapter->securitypriv. + busetkipkey = + false; + adapter->securitypriv. + bgrpkey_handshake = + false; + ptarget_sta->ieee8021x_blocked + = true; + ptarget_sta->XPrivacy = + adapter->securitypriv. + PrivacyAlgrthm; + memset((u8 *)&ptarget_sta-> + x_UncstKey, + 0, + sizeof(union Keytype)); + memset((u8 *)&ptarget_sta-> + tkiprxmickey, + 0, + sizeof(union Keytype)); + memset((u8 *)&ptarget_sta-> + tkiptxmickey, + 0, + sizeof(union Keytype)); + memset((u8 *)&ptarget_sta-> + txpn, 0, + sizeof(union pn48)); + memset((u8 *)&ptarget_sta-> + rxpn, 0, + sizeof(union pn48)); + } + } else { + if (check_fwstate(pmlmepriv, + _FW_UNDER_LINKING)) + pmlmepriv->fw_state ^= + _FW_UNDER_LINKING; + goto ignore_joinbss_callback; + } + } + + /*s3. update cur_network & indicate connect*/ + memcpy(&cur_network->network, &pnetwork->network, + pnetwork->network.Length); + cur_network->aid = pnetwork->join_res; + /*update fw_state will clr _FW_UNDER_LINKING*/ + switch (pnetwork->network.InfrastructureMode) { + case Ndis802_11Infrastructure: + pmlmepriv->fw_state = WIFI_STATION_STATE; + break; + case Ndis802_11IBSS: + pmlmepriv->fw_state = WIFI_ADHOC_STATE; + break; + default: + pmlmepriv->fw_state = WIFI_NULL_STATE; + break; + } + r8712_update_protection(adapter, + (cur_network->network.IEs) + + sizeof(struct NDIS_802_11_FIXED_IEs), + (cur_network->network.IELength)); + /*TODO: update HT_Capability*/ + update_ht_cap(adapter, cur_network->network.IEs, + cur_network->network.IELength); + /*indicate connect*/ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) + == true) + r8712_indicate_connect(adapter); + del_timer(&pmlmepriv->assoc_timer); + } else + goto ignore_joinbss_callback; + } else { + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + } + } +ignore_joinbss_callback: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + if (sizeof(struct list_head) == 4 * sizeof(u32)) + kfree(pnetwork); +} + +void r8712_stassoc_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + unsigned long irqL; + struct sta_info *psta; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf; + + /* to do: */ + if (r8712_access_ctrl(&adapter->acl_list, pstassoc->macaddr) == false) + return; + psta = r8712_get_stainfo(&adapter->stapriv, pstassoc->macaddr); + if (psta != NULL) { + /*the sta have been in sta_info_queue => do nothing + *(between drv has received this event before and + * fw have not yet to set key to CAM_ENTRY) */ + return; + } + + psta = r8712_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); + if (psta == NULL) + return; + /* to do : init sta_info variable */ + psta->qos_option = 0; + psta->mac_id = le32_to_cpu((uint)pstassoc->cam_id); + /* psta->aid = (uint)pstassoc->cam_id; */ + + if (adapter->securitypriv.AuthAlgrthm == 2) + psta->XPrivacy = adapter->securitypriv.PrivacyAlgrthm; + psta->ieee8021x_blocked = false; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { + if (adapter->stapriv.asoc_sta_count == 2) { + /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ + r8712_indicate_connect(adapter); + } + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +void r8712_stadel_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + unsigned long irqL, irqL2; + struct sta_info *psta; + struct wlan_network *pwlan = NULL; + struct wlan_bssid_ex *pdev_network = NULL; + u8 *pibss = NULL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct stadel_event *pstadel = (struct stadel_event *)pbuf; + struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + + spin_lock_irqsave(&pmlmepriv->lock, irqL2); + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { + r8712_ind_disconnect(adapter); + r8712_free_assoc_resources(adapter); + } + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | + WIFI_ADHOC_STATE)) { + psta = r8712_get_stainfo(&adapter->stapriv, pstadel->macaddr); + spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); + r8712_free_stainfo(adapter, psta); + spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); + if (adapter->stapriv.asoc_sta_count == 1) { + /*a sta + bc/mc_stainfo (not Ibss_stainfo) */ + pwlan = r8712_find_network(&pmlmepriv->scanned_queue, + tgt_network->network.MacAddress); + if (pwlan) { + pwlan->fixed = false; + free_network_nolock(pmlmepriv, pwlan); + } + /*re-create ibss*/ + pdev_network = &(adapter->registrypriv.dev_network); + pibss = adapter->registrypriv.dev_network.MacAddress; + memcpy(pdev_network, &tgt_network->network, + r8712_get_ndis_wlan_bssid_ex_sz(&tgt_network-> + network)); + memcpy(&pdev_network->Ssid, + &pmlmepriv->assoc_ssid, + sizeof(struct ndis_802_11_ssid)); + r8712_update_registrypriv_dev_network(adapter); + r8712_generate_random_ibss(pibss); + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + } + } + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL2); +} + +void r8712_cpwm_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + struct reportpwrstate_parm *preportpwrstate = + (struct reportpwrstate_parm *)pbuf; + + preportpwrstate->state |= (u8)(adapter->pwrctrlpriv.cpwm_tog + 0x80); + r8712_cpwm_int_hdl(adapter, preportpwrstate); +} + +/* When the Netgear 3500 AP is with WPA2PSK-AES mode, it will send + * the ADDBA req frame with start seq control = 0 to wifi client after + * the WPA handshake and the seqence number of following data packet + * will be 0. In this case, the Rx reorder sequence is not longer than 0 + * and the WiFi client will drop the data with seq number 0. + * So, the 8712 firmware has to inform driver with receiving the + * ADDBA-Req frame so that the driver can reset the + * sequence value of Rx reorder control. + */ +void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + struct ADDBA_Req_Report_parm *pAddbareq_pram = + (struct ADDBA_Req_Report_parm *)pbuf; + struct sta_info *psta; + struct sta_priv *pstapriv = &adapter->stapriv; + struct recv_reorder_ctrl *precvreorder_ctrl = NULL; + + psta = r8712_get_stainfo(pstapriv, pAddbareq_pram->MacAddress); + if (psta) { + precvreorder_ctrl = + &psta->recvreorder_ctrl[pAddbareq_pram->tid]; + /* set the indicate_seq to 0xffff so that the rx reorder + * can store any following data packet. + */ + precvreorder_ctrl->indicate_seq = 0xffff; + } +} + +void r8712_wpspbc_event_callback(struct _adapter *adapter, u8 *pbuf) +{ + if (adapter->securitypriv.wps_hw_pbc_pressed == false) + adapter->securitypriv.wps_hw_pbc_pressed = true; +} + +void _r8712_sitesurvey_ctrl_handler(struct _adapter *adapter) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sitesurvey_ctrl *psitesurveyctrl = &pmlmepriv->sitesurveyctrl; + struct registry_priv *pregistrypriv = &adapter->registrypriv; + u64 current_tx_pkts; + uint current_rx_pkts; + + current_tx_pkts = (adapter->xmitpriv.tx_pkts) - + (psitesurveyctrl->last_tx_pkts); + current_rx_pkts = (adapter->recvpriv.rx_pkts) - + (psitesurveyctrl->last_rx_pkts); + psitesurveyctrl->last_tx_pkts = adapter->xmitpriv.tx_pkts; + psitesurveyctrl->last_rx_pkts = adapter->recvpriv.rx_pkts; + if ((current_tx_pkts > pregistrypriv->busy_thresh) || + (current_rx_pkts > pregistrypriv->busy_thresh)) + psitesurveyctrl->traffic_busy = true; + else + psitesurveyctrl->traffic_busy = false; +} + +void _r8712_join_timeout_handler(struct _adapter *adapter) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + if (adapter->bDriverStopped || adapter->bSurpriseRemoved) + return; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + pmlmepriv->to_join = false; + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + r8712_os_indicate_disconnect(adapter); + _clr_fwstate_(pmlmepriv, _FW_LINKED); + } + if (adapter->pwrctrlpriv.pwr_mode != adapter->registrypriv.power_mgnt) { + r8712_set_ps_mode(adapter, adapter->registrypriv.power_mgnt, + adapter->registrypriv.smart_ps); + } + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +void r8712_scan_timeout_handler (struct _adapter *adapter) +{ + unsigned long irqL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + pmlmepriv->to_join = false; /* scan fail, so clear to_join flag */ + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +void _r8712_dhcp_timeout_handler (struct _adapter *adapter) +{ + if (adapter->bDriverStopped || adapter->bSurpriseRemoved) + return; + if (adapter->pwrctrlpriv.pwr_mode != adapter->registrypriv.power_mgnt) + r8712_set_ps_mode(adapter, adapter->registrypriv.power_mgnt, + adapter->registrypriv.smart_ps); +} + +void _r8712_wdg_timeout_handler(struct _adapter *adapter) +{ + r8712_wdg_wk_cmd(adapter); +} + +int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv) +{ + struct list_head *phead; + unsigned char *dst_ssid, *src_ssid; + struct _adapter *adapter; + struct __queue *queue = NULL; + struct wlan_network *pnetwork = NULL; + struct wlan_network *pnetwork_max_rssi = NULL; + + adapter = (struct _adapter *)pmlmepriv->nic_hdl; + queue = &pmlmepriv->scanned_queue; + phead = &queue->queue; + pmlmepriv->pscanned = phead->next; + while (1) { + if (end_of_queue_search(phead, pmlmepriv->pscanned) == true) { + if ((pmlmepriv->assoc_by_rssi == true) && + (pnetwork_max_rssi != NULL)) { + pnetwork = pnetwork_max_rssi; + goto ask_for_joinbss; + } + return _FAIL; + } + pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, + struct wlan_network, list); + if (pnetwork == NULL) + return _FAIL; + pmlmepriv->pscanned = pmlmepriv->pscanned->next; + if (pmlmepriv->assoc_by_bssid == true) { + dst_ssid = pnetwork->network.MacAddress; + src_ssid = pmlmepriv->assoc_bssid; + if (!memcmp(dst_ssid, src_ssid, ETH_ALEN)) { + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + if (is_same_network(&pmlmepriv-> + cur_network.network, + &pnetwork->network)) { + _clr_fwstate_(pmlmepriv, + _FW_UNDER_LINKING); + /*r8712_indicate_connect again*/ + r8712_indicate_connect(adapter); + return 2; + } + r8712_disassoc_cmd(adapter); + r8712_ind_disconnect(adapter); + r8712_free_assoc_resources(adapter); + } + goto ask_for_joinbss; + } + } else if (pmlmepriv->assoc_ssid.SsidLength == 0) + goto ask_for_joinbss; + dst_ssid = pnetwork->network.Ssid.Ssid; + src_ssid = pmlmepriv->assoc_ssid.Ssid; + if ((pnetwork->network.Ssid.SsidLength == + pmlmepriv->assoc_ssid.SsidLength) && + (!memcmp(dst_ssid, src_ssid, + pmlmepriv->assoc_ssid.SsidLength))) { + if (pmlmepriv->assoc_by_rssi == true) { + /* if the ssid is the same, select the bss + * which has the max rssi*/ + if (pnetwork_max_rssi) { + if (pnetwork->network.Rssi > + pnetwork_max_rssi->network.Rssi) + pnetwork_max_rssi = pnetwork; + } else + pnetwork_max_rssi = pnetwork; + } else if (is_desired_network(adapter, pnetwork)) { + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + r8712_disassoc_cmd(adapter); + r8712_free_assoc_resources(adapter); + } + goto ask_for_joinbss; + } + } + } + return _FAIL; +ask_for_joinbss: + return r8712_joinbss_cmd(adapter, pnetwork); +} + +sint r8712_set_auth(struct _adapter *adapter, + struct security_priv *psecuritypriv) +{ + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct cmd_obj *pcmd; + struct setauth_parm *psetauthparm; + + pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); + if (pcmd == NULL) + return _FAIL; + + psetauthparm = kzalloc(sizeof(*psetauthparm), GFP_ATOMIC); + if (psetauthparm == NULL) { + kfree(pcmd); + return _FAIL; + } + psetauthparm->mode = (u8)psecuritypriv->AuthAlgrthm; + pcmd->cmdcode = _SetAuth_CMD_; + pcmd->parmbuf = (unsigned char *)psetauthparm; + pcmd->cmdsz = sizeof(struct setauth_parm); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + INIT_LIST_HEAD(&pcmd->list); + r8712_enqueue_cmd(pcmdpriv, pcmd); + return _SUCCESS; +} + +sint r8712_set_key(struct _adapter *adapter, + struct security_priv *psecuritypriv, + sint keyid) +{ + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct cmd_obj *pcmd; + struct setkey_parm *psetkeyparm; + u8 keylen; + sint ret = _SUCCESS; + + pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); + if (pcmd == NULL) + return _FAIL; + psetkeyparm = kzalloc(sizeof(*psetkeyparm), GFP_ATOMIC); + if (psetkeyparm == NULL) { + ret = _FAIL; + goto err_free_cmd; + } + if (psecuritypriv->AuthAlgrthm == 2) { /* 802.1X */ + psetkeyparm->algorithm = + (u8)psecuritypriv->XGrpPrivacy; + } else { /* WEP */ + psetkeyparm->algorithm = + (u8)psecuritypriv->PrivacyAlgrthm; + } + psetkeyparm->keyid = (u8)keyid; + + switch (psetkeyparm->algorithm) { + case _WEP40_: + keylen = 5; + memcpy(psetkeyparm->key, + psecuritypriv->DefKey[keyid].skey, keylen); + break; + case _WEP104_: + keylen = 13; + memcpy(psetkeyparm->key, + psecuritypriv->DefKey[keyid].skey, keylen); + break; + case _TKIP_: + if (keyid < 1 || keyid > 2) { + ret = _FAIL; + goto err_free_parm; + } + keylen = 16; + memcpy(psetkeyparm->key, + &psecuritypriv->XGrpKey[keyid - 1], keylen); + psetkeyparm->grpkey = 1; + break; + case _AES_: + if (keyid < 1 || keyid > 2) { + ret = _FAIL; + goto err_free_parm; + } + keylen = 16; + memcpy(psetkeyparm->key, + &psecuritypriv->XGrpKey[keyid - 1], keylen); + psetkeyparm->grpkey = 1; + break; + default: + ret = _FAIL; + goto err_free_parm; + } + pcmd->cmdcode = _SetKey_CMD_; + pcmd->parmbuf = (u8 *)psetkeyparm; + pcmd->cmdsz = (sizeof(struct setkey_parm)); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + INIT_LIST_HEAD(&pcmd->list); + r8712_enqueue_cmd(pcmdpriv, pcmd); + return ret; + +err_free_parm: + kfree(psetkeyparm); +err_free_cmd: + kfree(pcmd); + return ret; +} + +/* adjust IEs for r8712_joinbss_cmd in WMM */ +int r8712_restruct_wmm_ie(struct _adapter *adapter, u8 *in_ie, u8 *out_ie, + uint in_len, uint initial_out_len) +{ + unsigned int ielength = 0; + unsigned int i, j; + + i = 12; /* after the fixed IE */ + while (i < in_len) { + ielength = initial_out_len; + if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && + in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 && + in_ie[i + 5] == 0x02 && i + 5 < in_len) { + /*WMM element ID and OUI*/ + for (j = i; j < i + 9; j++) { + out_ie[ielength] = in_ie[j]; + ielength++; + } + out_ie[initial_out_len + 1] = 0x07; + out_ie[initial_out_len + 6] = 0x00; + out_ie[initial_out_len + 8] = 0x00; + break; + } + i += (in_ie[i + 1] + 2); /* to the next IE element */ + } + return ielength; +} + +/* + * Ported from 8185: IsInPreAuthKeyList(). + * + * Search by BSSID, + * Return Value: + * -1 :if there is no pre-auth key in the table + * >=0 :if there is pre-auth key, and return the entry id + */ +static int SecIsInPMKIDList(struct _adapter *Adapter, u8 *bssid) +{ + struct security_priv *psecuritypriv = &Adapter->securitypriv; + int i = 0; + + do { + if (psecuritypriv->PMKIDList[i].bUsed && + (!memcmp(psecuritypriv->PMKIDList[i].Bssid, + bssid, ETH_ALEN))) + break; + else + i++; + } while (i < NUM_PMKID_CACHE); + + if (i == NUM_PMKID_CACHE) { + i = -1; /* Could not find. */ + } else { + ; /* There is one Pre-Authentication Key for the + * specific BSSID. */ + } + return i; +} + +sint r8712_restruct_sec_ie(struct _adapter *adapter, u8 *in_ie, + u8 *out_ie, uint in_len) +{ + u8 authmode = 0, match; + u8 sec_ie[255], uncst_oui[4], bkup_ie[255]; + u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; + uint ielength, cnt, remove_cnt; + int iEntry; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct security_priv *psecuritypriv = &adapter->securitypriv; + uint ndisauthmode = psecuritypriv->ndisauthtype; + uint ndissecuritytype = psecuritypriv->ndisencryptstatus; + + if ((ndisauthmode == Ndis802_11AuthModeWPA) || + (ndisauthmode == Ndis802_11AuthModeWPAPSK)) { + authmode = _WPA_IE_ID_; + uncst_oui[0] = 0x0; + uncst_oui[1] = 0x50; + uncst_oui[2] = 0xf2; + } + if ((ndisauthmode == Ndis802_11AuthModeWPA2) || + (ndisauthmode == Ndis802_11AuthModeWPA2PSK)) { + authmode = _WPA2_IE_ID_; + uncst_oui[0] = 0x0; + uncst_oui[1] = 0x0f; + uncst_oui[2] = 0xac; + } + switch (ndissecuritytype) { + case Ndis802_11Encryption1Enabled: + case Ndis802_11Encryption1KeyAbsent: + uncst_oui[3] = 0x1; + break; + case Ndis802_11Encryption2Enabled: + case Ndis802_11Encryption2KeyAbsent: + uncst_oui[3] = 0x2; + break; + case Ndis802_11Encryption3Enabled: + case Ndis802_11Encryption3KeyAbsent: + uncst_oui[3] = 0x4; + break; + default: + break; + } + /*Search required WPA or WPA2 IE and copy to sec_ie[] */ + cnt = 12; + match = false; + while (cnt < in_len) { + if (in_ie[cnt] == authmode) { + if ((authmode == _WPA_IE_ID_) && + (!memcmp(&in_ie[cnt+2], &wpa_oui[0], 4))) { + memcpy(&sec_ie[0], &in_ie[cnt], + in_ie[cnt + 1] + 2); + match = true; + break; + } + if (authmode == _WPA2_IE_ID_) { + memcpy(&sec_ie[0], &in_ie[cnt], + in_ie[cnt + 1] + 2); + match = true; + break; + } + if (((authmode == _WPA_IE_ID_) && + (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) || + (authmode == _WPA2_IE_ID_)) + memcpy(&bkup_ie[0], &in_ie[cnt], + in_ie[cnt + 1] + 2); + } + cnt += in_ie[cnt+1] + 2; /*get next*/ + } + /*restruct WPA IE or WPA2 IE in sec_ie[] */ + if (match == true) { + if (sec_ie[0] == _WPA_IE_ID_) { + /* parsing SSN IE to select required encryption + * algorithm, and set the bc/mc encryption algorithm */ + while (true) { + /*check wpa_oui tag*/ + if (memcmp(&sec_ie[2], &wpa_oui[0], 4)) { + match = false; + break; + } + if ((sec_ie[6] != 0x01) || (sec_ie[7] != 0x0)) { + /*IE Ver error*/ + match = false; + break; + } + if (!memcmp(&sec_ie[8], &wpa_oui[0], 3)) { + /* get bc/mc encryption type (group + * key type)*/ + switch (sec_ie[11]) { + case 0x0: /*none*/ + psecuritypriv->XGrpPrivacy = + _NO_PRIVACY_; + break; + case 0x1: /*WEP_40*/ + psecuritypriv->XGrpPrivacy = + _WEP40_; + break; + case 0x2: /*TKIP*/ + psecuritypriv->XGrpPrivacy = + _TKIP_; + break; + case 0x3: /*AESCCMP*/ + case 0x4: + psecuritypriv->XGrpPrivacy = + _AES_; + break; + case 0x5: /*WEP_104*/ + psecuritypriv->XGrpPrivacy = + _WEP104_; + break; + } + } else { + match = false; + break; + } + if (sec_ie[12] == 0x01) { + /*check the unicast encryption type*/ + if (memcmp(&sec_ie[14], + &uncst_oui[0], 4)) { + match = false; + break; + + } /*else the uncst_oui is match*/ + } else { /*mixed mode, unicast_enc_type > 1*/ + /*select the uncst_oui and remove + * the other uncst_oui*/ + cnt = sec_ie[12]; + remove_cnt = (cnt-1) * 4; + sec_ie[12] = 0x01; + memcpy(&sec_ie[14], &uncst_oui[0], 4); + /*remove the other unicast suit*/ + memcpy(&sec_ie[18], + &sec_ie[18 + remove_cnt], + sec_ie[1] - 18 + 2 - + remove_cnt); + sec_ie[1] = sec_ie[1] - remove_cnt; + } + break; + } + } + if (authmode == _WPA2_IE_ID_) { + /* parsing RSN IE to select required encryption + * algorithm, and set the bc/mc encryption algorithm */ + while (true) { + if ((sec_ie[2] != 0x01) || (sec_ie[3] != 0x0)) { + /*IE Ver error*/ + match = false; + break; + } + if (!memcmp(&sec_ie[4], &uncst_oui[0], 3)) { + /*get bc/mc encryption type*/ + switch (sec_ie[7]) { + case 0x1: /*WEP_40*/ + psecuritypriv->XGrpPrivacy = + _WEP40_; + break; + case 0x2: /*TKIP*/ + psecuritypriv->XGrpPrivacy = + _TKIP_; + break; + case 0x4: /*AESWRAP*/ + psecuritypriv->XGrpPrivacy = + _AES_; + break; + case 0x5: /*WEP_104*/ + psecuritypriv->XGrpPrivacy = + _WEP104_; + break; + default: /*one*/ + psecuritypriv->XGrpPrivacy = + _NO_PRIVACY_; + break; + } + } else { + match = false; + break; + } + if (sec_ie[8] == 0x01) { + /*check the unicast encryption type*/ + if (memcmp(&sec_ie[10], + &uncst_oui[0], 4)) { + match = false; + break; + } /*else the uncst_oui is match*/ + } else { /*mixed mode, unicast_enc_type > 1*/ + /*select the uncst_oui and remove the + * other uncst_oui*/ + cnt = sec_ie[8]; + remove_cnt = (cnt-1)*4; + sec_ie[8] = 0x01; + memcpy(&sec_ie[10], &uncst_oui[0], 4); + /*remove the other unicast suit*/ + memcpy(&sec_ie[14], + &sec_ie[14 + remove_cnt], + (sec_ie[1] - 14 + 2 - + remove_cnt)); + sec_ie[1] = sec_ie[1]-remove_cnt; + } + break; + } + } + } + if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) { + /*copy fixed ie*/ + memcpy(out_ie, in_ie, 12); + ielength = 12; + /*copy RSN or SSN*/ + if (match == true) { + memcpy(&out_ie[ielength], &sec_ie[0], sec_ie[1]+2); + ielength += sec_ie[1] + 2; + if (authmode == _WPA2_IE_ID_) { + /*the Pre-Authentication bit should be zero*/ + out_ie[ielength - 1] = 0; + out_ie[ielength - 2] = 0; + } + r8712_report_sec_ie(adapter, authmode, sec_ie); + } + } else { + /*copy fixed ie only*/ + memcpy(out_ie, in_ie, 12); + ielength = 12; + if (psecuritypriv->wps_phase == true) { + memcpy(out_ie+ielength, psecuritypriv->wps_ie, + psecuritypriv->wps_ie_len); + ielength += psecuritypriv->wps_ie_len; + } + } + iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); + if (iEntry < 0) + return ielength; + if (authmode == _WPA2_IE_ID_) { + out_ie[ielength] = 1; + ielength++; + out_ie[ielength] = 0; /*PMKID count = 0x0100*/ + ielength++; + memcpy(&out_ie[ielength], + &psecuritypriv->PMKIDList[iEntry].PMKID, 16); + ielength += 16; + out_ie[13] += 18;/*PMKID length = 2+16*/ + } + return ielength; +} + +void r8712_init_registrypriv_dev_network(struct _adapter *adapter) +{ + struct registry_priv *pregistrypriv = &adapter->registrypriv; + struct eeprom_priv *peepriv = &adapter->eeprompriv; + struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; + u8 *myhwaddr = myid(peepriv); + + memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); + memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, + sizeof(struct ndis_802_11_ssid)); + pdev_network->Configuration.Length = + sizeof(struct NDIS_802_11_CONFIGURATION); + pdev_network->Configuration.BeaconPeriod = 100; + pdev_network->Configuration.FHConfig.Length = 0; + pdev_network->Configuration.FHConfig.HopPattern = 0; + pdev_network->Configuration.FHConfig.HopSet = 0; + pdev_network->Configuration.FHConfig.DwellTime = 0; +} + +void r8712_update_registrypriv_dev_network(struct _adapter *adapter) +{ + int sz = 0; + struct registry_priv *pregistrypriv = &adapter->registrypriv; + struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; + + pdev_network->Privacy = cpu_to_le32(psecuritypriv->PrivacyAlgrthm + > 0 ? 1 : 0); /* adhoc no 802.1x */ + pdev_network->Rssi = 0; + switch (pregistrypriv->wireless_mode) { + case WIRELESS_11B: + pdev_network->NetworkTypeInUse = cpu_to_le32(Ndis802_11DS); + break; + case WIRELESS_11G: + case WIRELESS_11BG: + pdev_network->NetworkTypeInUse = cpu_to_le32(Ndis802_11OFDM24); + break; + case WIRELESS_11A: + pdev_network->NetworkTypeInUse = cpu_to_le32(Ndis802_11OFDM5); + break; + default: + /* TODO */ + break; + } + pdev_network->Configuration.DSConfig = cpu_to_le32( + pregistrypriv->channel); + if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) + pdev_network->Configuration.ATIMWindow = cpu_to_le32(3); + pdev_network->InfrastructureMode = cpu_to_le32( + cur_network->network.InfrastructureMode); + /* 1. Supported rates + * 2. IE + */ + sz = r8712_generate_ie(pregistrypriv); + pdev_network->IELength = sz; + pdev_network->Length = r8712_get_ndis_wlan_bssid_ex_sz( + (struct ndis_wlan_bssid_ex *)pdev_network); +} + +/*the function is at passive_level*/ +void r8712_joinbss_reset(struct _adapter *padapter) +{ + int i; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + /* todo: if you want to do something io/reg/hw setting before join_bss, + * please add code here */ + phtpriv->ampdu_enable = false;/*reset to disabled*/ + for (i = 0; i < 16; i++) + phtpriv->baddbareq_issued[i] = false;/*reset it*/ + if (phtpriv->ht_option) { + /* validate usb rx aggregation */ + r8712_write8(padapter, 0x102500D9, 48);/*TH = 48 pages, 6k*/ + } else { + /* invalidate usb rx aggregation */ + /* TH=1 => means that invalidate usb rx aggregation */ + r8712_write8(padapter, 0x102500D9, 1); + } +} + +/*the function is >= passive_level*/ +unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, + u8 *out_ie, uint in_len, uint *pout_len) +{ + u32 ielen, out_len; + unsigned char *p; + struct ieee80211_ht_cap ht_capie; + unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + phtpriv->ht_option = 0; + p = r8712_get_ie(in_ie+12, _HT_CAPABILITY_IE_, &ielen, in_len-12); + if (p && (ielen > 0)) { + if (pqospriv->qos_option == 0) { + out_len = *pout_len; + r8712_set_ie(out_ie+out_len, _VENDOR_SPECIFIC_IE_, + _WMM_IE_Length_, WMM_IE, pout_len); + pqospriv->qos_option = 1; + } + out_len = *pout_len; + memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap)); + ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | + IEEE80211_HT_CAP_MAX_AMSDU | + IEEE80211_HT_CAP_DSSSCCK40; + ht_capie.ampdu_params_info = (IEEE80211_HT_CAP_AMPDU_FACTOR & + 0x03) | (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00); + r8712_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_, + sizeof(struct ieee80211_ht_cap), + (unsigned char *)&ht_capie, pout_len); + phtpriv->ht_option = 1; + } + return phtpriv->ht_option; +} + +/* the function is > passive_level (in critical_section) */ +static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) +{ + u8 *p, max_ampdu_sz; + int i, len; + struct sta_info *bmc_sta, *psta; + struct ieee80211_ht_cap *pht_capie; + struct recv_reorder_ctrl *preorder_ctrl; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct wlan_network *pcur_network = &(pmlmepriv->cur_network); + + if (!phtpriv->ht_option) + return; + /* maybe needs check if ap supports rx ampdu. */ + if ((phtpriv->ampdu_enable == false) && + (pregistrypriv->ampdu_enable == 1)) + phtpriv->ampdu_enable = true; + /*check Max Rx A-MPDU Size*/ + len = 0; + p = r8712_get_ie(pie + sizeof(struct NDIS_802_11_FIXED_IEs), + _HT_CAPABILITY_IE_, + &len, ie_len - + sizeof(struct NDIS_802_11_FIXED_IEs)); + if (p && len > 0) { + pht_capie = (struct ieee80211_ht_cap *)(p+2); + max_ampdu_sz = (pht_capie->ampdu_params_info & + IEEE80211_HT_CAP_AMPDU_FACTOR); + /* max_ampdu_sz (kbytes); */ + max_ampdu_sz = 1 << (max_ampdu_sz+3); + phtpriv->rx_ampdu_maxlen = max_ampdu_sz; + } + /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info + * if A-MPDU Rx is enabled, resetting rx_ordering_ctrl + * wstart_b(indicate_seq) to default value=0xffff + * todo: check if AP can send A-MPDU packets + */ + bmc_sta = r8712_get_bcmc_stainfo(padapter); + if (bmc_sta) { + for (i = 0; i < 16; i++) { + preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; + preorder_ctrl->indicate_seq = 0xffff; + preorder_ctrl->wend_b = 0xffff; + } + } + psta = r8712_get_stainfo(&padapter->stapriv, + pcur_network->network.MacAddress); + if (psta) { + for (i = 0; i < 16; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + preorder_ctrl->indicate_seq = 0xffff; + preorder_ctrl->wend_b = 0xffff; + } + } + len = 0; + p = r8712_get_ie(pie + sizeof(struct NDIS_802_11_FIXED_IEs), + _HT_ADD_INFO_IE_, &len, + ie_len-sizeof(struct NDIS_802_11_FIXED_IEs)); +} + +void r8712_issue_addbareq_cmd(struct _adapter *padapter, int priority) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + if ((phtpriv->ht_option == 1) && (phtpriv->ampdu_enable == true)) { + if (phtpriv->baddbareq_issued[priority] == false) { + r8712_addbareq_cmd(padapter, (u8)priority); + phtpriv->baddbareq_issued[priority] = true; + } + } +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_mlme.h b/kernel/drivers/staging/rtl8712/rtl871x_mlme.h new file mode 100644 index 000000000..42bd0bf8a --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_mlme.h @@ -0,0 +1,232 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL871X_MLME_H_ +#define __RTL871X_MLME_H_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "wlan_bssdef.h" + +#define MAX_BSS_CNT 64 +#define MAX_JOIN_TIMEOUT 6000 + +#define SCANNING_TIMEOUT 4500 + +#define SCANQUEUE_LIFETIME 20 /* unit:sec */ + +#define WIFI_NULL_STATE 0x00000000 +#define WIFI_ASOC_STATE 0x00000001 /* Under Linked state...*/ +#define WIFI_REASOC_STATE 0x00000002 +#define WIFI_SLEEP_STATE 0x00000004 +#define WIFI_STATION_STATE 0x00000008 +#define WIFI_AP_STATE 0x00000010 +#define WIFI_ADHOC_STATE 0x00000020 +#define WIFI_ADHOC_MASTER_STATE 0x00000040 +#define WIFI_UNDER_LINKING 0x00000080 +#define WIFI_SITE_MONITOR 0x00000800 /* to indicate the station + * is under site surveying*/ +#define WIFI_MP_STATE 0x00010000 +#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in cont. tx background*/ +#define WIFI_MP_CTX_ST 0x00040000 /* in cont. tx with + * single-tone*/ +#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in cont, tx + * background due to out of skb*/ +#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continuous tx*/ +#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in cont, tx with carrier + * suppression*/ +#define WIFI_MP_LPBK_STATE 0x00400000 + +#define _FW_UNDER_LINKING WIFI_UNDER_LINKING +#define _FW_LINKED WIFI_ASOC_STATE +#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR + +/* +there are several "locks" in mlme_priv, +since mlme_priv is a shared resource between many threads, +like ISR/Call-Back functions, the OID handlers, and even timer functions. +Each _queue has its own locks, already. +Other items are protected by mlme_priv.lock. +To avoid possible dead lock, any thread trying to modify mlme_priv +SHALL not lock up more than one lock at a time! +*/ + +#define traffic_threshold 10 +#define traffic_scan_period 500 + +struct sitesurvey_ctrl { + u64 last_tx_pkts; + uint last_rx_pkts; + sint traffic_busy; + struct timer_list sitesurvey_ctrl_timer; +}; + +struct mlme_priv { + + spinlock_t lock; + spinlock_t lock2; + sint fw_state; /*shall we protect this variable? */ + u8 to_join; /*flag*/ + u8 *nic_hdl; + struct list_head *pscanned; + struct __queue free_bss_pool; + struct __queue scanned_queue; + u8 *free_bss_buf; + unsigned long num_of_scanned; + u8 passive_mode; /*add for Android's SCAN-ACTIVE/SCAN-PASSIVE */ + struct ndis_802_11_ssid assoc_ssid; + u8 assoc_bssid[6]; + struct wlan_network cur_network; + struct sitesurvey_ctrl sitesurveyctrl; + struct timer_list assoc_timer; + uint assoc_by_bssid; + uint assoc_by_rssi; + struct timer_list scan_to_timer; /* driver handles scan_timeout.*/ + struct timer_list dhcp_timer; /* set dhcp to if driver in ps mode.*/ + struct qos_priv qospriv; + struct ht_priv htpriv; + struct timer_list wdg_timer; /*watchdog periodic timer*/ +}; + +static inline u8 *get_bssid(struct mlme_priv *pmlmepriv) +{ + return pmlmepriv->cur_network.network.MacAddress; +} + +static inline u8 check_fwstate(struct mlme_priv *pmlmepriv, sint state) +{ + if (pmlmepriv->fw_state & state) + return true; + return false; +} + +static inline sint get_fwstate(struct mlme_priv *pmlmepriv) +{ + return pmlmepriv->fw_state; +} + +/* + * No Limit on the calling context, + * therefore set it to be the critical section... + * + * ### NOTE:#### (!!!!) + * TAKE CARE BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock + */ +static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state) +{ + pmlmepriv->fw_state |= state; +} + +static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state) +{ + pmlmepriv->fw_state &= ~state; +} + +/* + * No Limit on the calling context, + * therefore set it to be the critical section... + */ +static inline void clr_fwstate(struct mlme_priv *pmlmepriv, sint state) +{ + unsigned long irqL; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, state) == true) + pmlmepriv->fw_state ^= state; + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +static inline void up_scanned_network(struct mlme_priv *pmlmepriv) +{ + unsigned long irqL; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + pmlmepriv->num_of_scanned++; + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +static inline void down_scanned_network(struct mlme_priv *pmlmepriv) +{ + unsigned long irqL; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + pmlmepriv->num_of_scanned--; + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, + sint val) +{ + unsigned long irqL; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + pmlmepriv->num_of_scanned = val; + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); +} + +void r8712_survey_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_stassoc_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_stadel_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_atimdone_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_cpwm_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_wpspbc_event_callback(struct _adapter *adapter, u8 *pbuf); +void r8712_free_network_queue(struct _adapter *adapter); +int r8712_init_mlme_priv(struct _adapter *adapter); +void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv); +sint r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv); +sint r8712_set_key(struct _adapter *adapter, + struct security_priv *psecuritypriv, sint keyid); +sint r8712_set_auth(struct _adapter *adapter, + struct security_priv *psecuritypriv); +uint r8712_get_ndis_wlan_bssid_ex_sz(struct ndis_wlan_bssid_ex *bss); +void r8712_generate_random_ibss(u8 *pibss); +u8 *r8712_get_capability_from_ie(u8 *ie); +struct wlan_network *r8712_get_oldest_wlan_network( + struct __queue *scanned_queue); +void r8712_free_assoc_resources(struct _adapter *adapter); +void r8712_ind_disconnect(struct _adapter *adapter); +void r8712_indicate_connect(struct _adapter *adapter); +int r8712_restruct_sec_ie(struct _adapter *adapter, u8 *in_ie, + u8 *out_ie, uint in_len); +int r8712_restruct_wmm_ie(struct _adapter *adapter, u8 *in_ie, + u8 *out_ie, uint in_len, uint initial_out_len); +void r8712_init_registrypriv_dev_network(struct _adapter *adapter); +void r8712_update_registrypriv_dev_network(struct _adapter *adapter); +void _r8712_sitesurvey_ctrl_handler(struct _adapter *adapter); +void _r8712_join_timeout_handler(struct _adapter *adapter); +void r8712_scan_timeout_handler(struct _adapter *adapter); +void _r8712_dhcp_timeout_handler(struct _adapter *adapter); +void _r8712_wdg_timeout_handler(struct _adapter *adapter); +struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv); +sint r8712_if_up(struct _adapter *padapter); +void r8712_joinbss_reset(struct _adapter *padapter); +unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, + u8 *out_ie, uint in_len, uint *pout_len); +void r8712_issue_addbareq_cmd(struct _adapter *padapter, int priority); +int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork); + +#endif /*__RTL871X_MLME_H_*/ diff --git a/kernel/drivers/staging/rtl8712/rtl871x_mp.c b/kernel/drivers/staging/rtl8712/rtl871x_mp.c new file mode 100644 index 000000000..26201ea3c --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_mp.c @@ -0,0 +1,745 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#define _RTL871X_MP_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "rtl871x_mp_phy_regdef.h" +#include "rtl8712_cmd.h" + +static void _init_mp_priv_(struct mp_priv *pmp_priv) +{ + pmp_priv->mode = _LOOPBOOK_MODE_; + pmp_priv->curr_ch = 1; + pmp_priv->curr_modem = MIXED_PHY; + pmp_priv->curr_rateidx = 0; + pmp_priv->curr_txpoweridx = 0x14; + pmp_priv->antenna_tx = ANTENNA_A; + pmp_priv->antenna_rx = ANTENNA_AB; + pmp_priv->check_mp_pkt = 0; + pmp_priv->tx_pktcount = 0; + pmp_priv->rx_pktcount = 0; + pmp_priv->rx_crcerrpktcount = 0; +} + +static int init_mp_priv(struct mp_priv *pmp_priv) +{ + int i, res; + struct mp_xmit_frame *pmp_xmitframe; + + _init_mp_priv_(pmp_priv); + _init_queue(&pmp_priv->free_mp_xmitqueue); + pmp_priv->pallocated_mp_xmitframe_buf = NULL; + pmp_priv->pallocated_mp_xmitframe_buf = kmalloc(NR_MP_XMITFRAME * + sizeof(struct mp_xmit_frame) + 4, + GFP_ATOMIC); + if (!pmp_priv->pallocated_mp_xmitframe_buf) { + res = _FAIL; + goto _exit_init_mp_priv; + } + pmp_priv->pmp_xmtframe_buf = pmp_priv->pallocated_mp_xmitframe_buf + + 4 - + ((addr_t)(pmp_priv->pallocated_mp_xmitframe_buf) & 3); + pmp_xmitframe = (struct mp_xmit_frame *)pmp_priv->pmp_xmtframe_buf; + for (i = 0; i < NR_MP_XMITFRAME; i++) { + INIT_LIST_HEAD(&(pmp_xmitframe->list)); + list_add_tail(&(pmp_xmitframe->list), + &(pmp_priv->free_mp_xmitqueue.queue)); + pmp_xmitframe->pkt = NULL; + pmp_xmitframe->frame_tag = MP_FRAMETAG; + pmp_xmitframe->padapter = pmp_priv->papdater; + pmp_xmitframe++; + } + pmp_priv->free_mp_xmitframe_cnt = NR_MP_XMITFRAME; + res = _SUCCESS; +_exit_init_mp_priv: + return res; +} + +static int free_mp_priv(struct mp_priv *pmp_priv) +{ + kfree(pmp_priv->pallocated_mp_xmitframe_buf); + return 0; +} + +void mp871xinit(struct _adapter *padapter) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + + pmppriv->papdater = padapter; + init_mp_priv(pmppriv); +} + +void mp871xdeinit(struct _adapter *padapter) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + + free_mp_priv(pmppriv); +} + +/* + * Special for bb and rf reg read/write + */ +static u32 fw_iocmd_read(struct _adapter *pAdapter, struct IOCMD_STRUCT iocmd) +{ + u32 cmd32 = 0, val32 = 0; + u8 iocmd_class = iocmd.cmdclass; + u16 iocmd_value = iocmd.value; + u8 iocmd_idx = iocmd.index; + + cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx; + if (r8712_fw_cmd(pAdapter, cmd32)) + r8712_fw_cmd_data(pAdapter, &val32, 1); + else + val32 = 0; + return val32; +} + +static u8 fw_iocmd_write(struct _adapter *pAdapter, + struct IOCMD_STRUCT iocmd, u32 value) +{ + u32 cmd32 = 0; + u8 iocmd_class = iocmd.cmdclass; + u32 iocmd_value = iocmd.value; + u8 iocmd_idx = iocmd.index; + + r8712_fw_cmd_data(pAdapter, &value, 0); + msleep(100); + cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx; + return r8712_fw_cmd(pAdapter, cmd32); +} + +/* offset : 0X800~0XFFF */ +u32 r8712_bb_reg_read(struct _adapter *pAdapter, u16 offset) +{ + u8 shift = offset & 0x0003; /* 4 byte access */ + u16 bb_addr = offset & 0x0FFC; /* 4 byte access */ + u32 bb_val = 0; + struct IOCMD_STRUCT iocmd; + + iocmd.cmdclass = IOCMD_CLASS_BB_RF; + iocmd.value = bb_addr; + iocmd.index = IOCMD_BB_READ_IDX; + bb_val = fw_iocmd_read(pAdapter, iocmd); + if (shift != 0) { + u32 bb_val2 = 0; + + bb_val >>= (shift * 8); + iocmd.value += 4; + bb_val2 = fw_iocmd_read(pAdapter, iocmd); + bb_val2 <<= ((4 - shift) * 8); + bb_val |= bb_val2; + } + return bb_val; +} + +/* offset : 0X800~0XFFF */ +u8 r8712_bb_reg_write(struct _adapter *pAdapter, u16 offset, u32 value) +{ + u8 shift = offset & 0x0003; /* 4 byte access */ + u16 bb_addr = offset & 0x0FFC; /* 4 byte access */ + struct IOCMD_STRUCT iocmd; + + iocmd.cmdclass = IOCMD_CLASS_BB_RF; + iocmd.value = bb_addr; + iocmd.index = IOCMD_BB_WRITE_IDX; + if (shift != 0) { + u32 oldValue = 0; + u32 newValue = value; + + oldValue = r8712_bb_reg_read(pAdapter, iocmd.value); + oldValue &= (0xFFFFFFFF >> ((4 - shift) * 8)); + value = oldValue | (newValue << (shift * 8)); + if (!fw_iocmd_write(pAdapter, iocmd, value)) + return false; + iocmd.value += 4; + oldValue = r8712_bb_reg_read(pAdapter, iocmd.value); + oldValue &= (0xFFFFFFFF << (shift * 8)); + value = oldValue | (newValue >> ((4 - shift) * 8)); + } + return fw_iocmd_write(pAdapter, iocmd, value); +} + +/* offset : 0x00 ~ 0xFF */ +u32 r8712_rf_reg_read(struct _adapter *pAdapter, u8 path, u8 offset) +{ + u16 rf_addr = (path << 8) | offset; + struct IOCMD_STRUCT iocmd; + + iocmd.cmdclass = IOCMD_CLASS_BB_RF; + iocmd.value = rf_addr; + iocmd.index = IOCMD_RF_READ_IDX; + return fw_iocmd_read(pAdapter, iocmd); +} + +u8 r8712_rf_reg_write(struct _adapter *pAdapter, u8 path, u8 offset, u32 value) +{ + u16 rf_addr = (path << 8) | offset; + struct IOCMD_STRUCT iocmd; + + iocmd.cmdclass = IOCMD_CLASS_BB_RF; + iocmd.value = rf_addr; + iocmd.index = IOCMD_RF_WRIT_IDX; + return fw_iocmd_write(pAdapter, iocmd, value); +} + +static u32 bitshift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) + if (((bitmask>>i) & 0x1) == 1) + break; + return i; +} + +static u32 get_bb_reg(struct _adapter *pAdapter, u16 offset, u32 bitmask) +{ + u32 org_value, bit_shift, new_value; + + org_value = r8712_bb_reg_read(pAdapter, offset); + bit_shift = bitshift(bitmask); + new_value = (org_value & bitmask) >> bit_shift; + return new_value; +} + +static u8 set_bb_reg(struct _adapter *pAdapter, + u16 offset, + u32 bitmask, + u32 value) +{ + u32 org_value, bit_shift, new_value; + + if (bitmask != bMaskDWord) { + org_value = r8712_bb_reg_read(pAdapter, offset); + bit_shift = bitshift(bitmask); + new_value = ((org_value & (~bitmask)) | (value << bit_shift)); + } else + new_value = value; + return r8712_bb_reg_write(pAdapter, offset, new_value); +} + +static u32 get_rf_reg(struct _adapter *pAdapter, u8 path, u8 offset, + u32 bitmask) +{ + u32 org_value, bit_shift, new_value; + + org_value = r8712_rf_reg_read(pAdapter, path, offset); + bit_shift = bitshift(bitmask); + new_value = (org_value & bitmask) >> bit_shift; + return new_value; +} + +static u8 set_rf_reg(struct _adapter *pAdapter, u8 path, u8 offset, u32 bitmask, + u32 value) +{ + u32 org_value, bit_shift, new_value; + + if (bitmask != bMaskDWord) { + org_value = r8712_rf_reg_read(pAdapter, path, offset); + bit_shift = bitshift(bitmask); + new_value = ((org_value & (~bitmask)) | (value << bit_shift)); + } else + new_value = value; + return r8712_rf_reg_write(pAdapter, path, offset, new_value); +} + +/* + * SetChannel + * Description + * Use H2C command to change channel, + * not only modify rf register, but also other setting need to be done. + */ +void r8712_SetChannel(struct _adapter *pAdapter) +{ + struct cmd_priv *pcmdpriv = &pAdapter->cmdpriv; + struct cmd_obj *pcmd = NULL; + struct SetChannel_parm *pparm = NULL; + u16 code = GEN_CMD_CODE(_SetChannel); + + pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); + if (pcmd == NULL) + return; + pparm = kmalloc(sizeof(*pparm), GFP_ATOMIC); + if (pparm == NULL) { + kfree(pcmd); + return; + } + pparm->curr_ch = pAdapter->mppriv.curr_ch; + init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code); + r8712_enqueue_cmd(pcmdpriv, pcmd); +} + +static void SetCCKTxPower(struct _adapter *pAdapter, u8 TxPower) +{ + u16 TxAGC = 0; + + TxAGC = TxPower; + set_bb_reg(pAdapter, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); +} + +static void SetOFDMTxPower(struct _adapter *pAdapter, u8 TxPower) +{ + u32 TxAGC = 0; + + TxAGC |= ((TxPower<<24)|(TxPower<<16)|(TxPower<<8)|TxPower); + set_bb_reg(pAdapter, rTxAGC_Rate18_06, bTxAGCRate18_06, TxAGC); + set_bb_reg(pAdapter, rTxAGC_Rate54_24, bTxAGCRate54_24, TxAGC); + set_bb_reg(pAdapter, rTxAGC_Mcs03_Mcs00, bTxAGCRateMCS3_MCS0, TxAGC); + set_bb_reg(pAdapter, rTxAGC_Mcs07_Mcs04, bTxAGCRateMCS7_MCS4, TxAGC); + set_bb_reg(pAdapter, rTxAGC_Mcs11_Mcs08, bTxAGCRateMCS11_MCS8, TxAGC); + set_bb_reg(pAdapter, rTxAGC_Mcs15_Mcs12, bTxAGCRateMCS15_MCS12, TxAGC); +} + +void r8712_SetTxPower(struct _adapter *pAdapter) +{ + u8 TxPower = pAdapter->mppriv.curr_txpoweridx; + + SetCCKTxPower(pAdapter, TxPower); + SetOFDMTxPower(pAdapter, TxPower); +} + +void r8712_SetTxAGCOffset(struct _adapter *pAdapter, u32 ulTxAGCOffset) +{ + u32 TxAGCOffset_B, TxAGCOffset_C, TxAGCOffset_D, tmpAGC; + + TxAGCOffset_B = (ulTxAGCOffset&0x000000ff); + TxAGCOffset_C = (ulTxAGCOffset & 0x0000ff00)>>8; + TxAGCOffset_D = (ulTxAGCOffset & 0x00ff0000)>>16; + tmpAGC = (TxAGCOffset_D<<8 | TxAGCOffset_C<<4 | TxAGCOffset_B); + set_bb_reg(pAdapter, rFPGA0_TxGainStage, + (bXBTxAGC|bXCTxAGC|bXDTxAGC), tmpAGC); +} + +void r8712_SetDataRate(struct _adapter *pAdapter) +{ + u8 path = RF_PATH_A; + u8 offset = RF_SYN_G2; + u32 value; + + value = (pAdapter->mppriv.curr_rateidx < 4) ? 0x4440 : 0xF200; + r8712_rf_reg_write(pAdapter, path, offset, value); +} + +void r8712_SwitchBandwidth(struct _adapter *pAdapter) +{ + /* 3 1.Set MAC register : BWOPMODE bit2:1 20MhzBW */ + u8 regBwOpMode = 0; + u8 Bandwidth = pAdapter->mppriv.curr_bandwidth; + + regBwOpMode = r8712_read8(pAdapter, 0x10250203); + if (Bandwidth == HT_CHANNEL_WIDTH_20) + regBwOpMode |= BIT(2); + else + regBwOpMode &= ~(BIT(2)); + r8712_write8(pAdapter, 0x10250203, regBwOpMode); + /* 3 2.Set PHY related register */ + switch (Bandwidth) { + /* 20 MHz channel*/ + case HT_CHANNEL_WIDTH_20: + set_bb_reg(pAdapter, rFPGA0_RFMOD, bRFMOD, 0x0); + set_bb_reg(pAdapter, rFPGA1_RFMOD, bRFMOD, 0x0); + /* Use PHY_REG.txt default value. Do not need to change. + * Correct the tx power for CCK rate in 40M. + * It is set in Tx descriptor for 8192x series + */ + set_bb_reg(pAdapter, rFPGA0_AnalogParameter2, bMaskDWord, 0x58); + break; + /* 40 MHz channel*/ + case HT_CHANNEL_WIDTH_40: + set_bb_reg(pAdapter, rFPGA0_RFMOD, bRFMOD, 0x1); + set_bb_reg(pAdapter, rFPGA1_RFMOD, bRFMOD, 0x1); + /* Use PHY_REG.txt default value. Do not need to change. + * Correct the tx power for CCK rate in 40M. + * Set Control channel to upper or lower. These settings are + * required only for 40MHz */ + set_bb_reg(pAdapter, rCCK0_System, bCCKSideBand, + (HAL_PRIME_CHNL_OFFSET_DONT_CARE>>1)); + set_bb_reg(pAdapter, rOFDM1_LSTF, 0xC00, + HAL_PRIME_CHNL_OFFSET_DONT_CARE); + set_bb_reg(pAdapter, rFPGA0_AnalogParameter2, bMaskDWord, 0x18); + break; + default: + break; + } + + /* 3 3.Set RF related register */ + switch (Bandwidth) { + case HT_CHANNEL_WIDTH_20: + set_rf_reg(pAdapter, RF_PATH_A, RF_CHNLBW, + BIT(10) | BIT(11), 0x01); + break; + case HT_CHANNEL_WIDTH_40: + set_rf_reg(pAdapter, RF_PATH_A, RF_CHNLBW, + BIT(10) | BIT(11), 0x00); + break; + default: + break; + } +} +/*------------------------------Define structure----------------------------*/ +struct R_ANTENNA_SELECT_OFDM { + u32 r_tx_antenna:4; + u32 r_ant_l:4; + u32 r_ant_non_ht:4; + u32 r_ant_ht1:4; + u32 r_ant_ht2:4; + u32 r_ant_ht_s1:4; + u32 r_ant_non_ht_s1:4; + u32 OFDM_TXSC:2; + u32 Reserved:2; +}; + +struct R_ANTENNA_SELECT_CCK { + u8 r_cckrx_enable_2:2; + u8 r_cckrx_enable:2; + u8 r_ccktx_enable:4; +}; + +void r8712_SwitchAntenna(struct _adapter *pAdapter) +{ + u32 ofdm_tx_en_val = 0, ofdm_tx_ant_sel_val = 0; + u8 ofdm_rx_ant_sel_val = 0; + u8 cck_ant_select_val = 0; + u32 cck_ant_sel_val = 0; + struct R_ANTENNA_SELECT_CCK *p_cck_txrx; + + p_cck_txrx = (struct R_ANTENNA_SELECT_CCK *)&cck_ant_select_val; + + switch (pAdapter->mppriv.antenna_tx) { + case ANTENNA_A: + /* From SD3 Willis suggestion !!! Set RF A=TX and B as standby*/ + set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); + set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1); + ofdm_tx_en_val = 0x3; + ofdm_tx_ant_sel_val = 0x11111111;/* Power save */ + p_cck_txrx->r_ccktx_enable = 0x8; + break; + case ANTENNA_B: + set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1); + set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); + ofdm_tx_en_val = 0x3; + ofdm_tx_ant_sel_val = 0x22222222;/* Power save */ + p_cck_txrx->r_ccktx_enable = 0x4; + break; + case ANTENNA_AB: /* For 8192S */ + set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); + set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); + ofdm_tx_en_val = 0x3; + ofdm_tx_ant_sel_val = 0x3321333; /* Disable Power save */ + p_cck_txrx->r_ccktx_enable = 0xC; + break; + default: + break; + } + /*OFDM Tx*/ + set_bb_reg(pAdapter, rFPGA1_TxInfo, 0xffffffff, ofdm_tx_ant_sel_val); + /*OFDM Tx*/ + set_bb_reg(pAdapter, rFPGA0_TxInfo, 0x0000000f, ofdm_tx_en_val); + switch (pAdapter->mppriv.antenna_rx) { + case ANTENNA_A: + ofdm_rx_ant_sel_val = 0x1; /* A */ + p_cck_txrx->r_cckrx_enable = 0x0; /* default: A */ + p_cck_txrx->r_cckrx_enable_2 = 0x0; /* option: A */ + break; + case ANTENNA_B: + ofdm_rx_ant_sel_val = 0x2; /* B */ + p_cck_txrx->r_cckrx_enable = 0x1; /* default: B */ + p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option: B */ + break; + case ANTENNA_AB: + ofdm_rx_ant_sel_val = 0x3; /* AB */ + p_cck_txrx->r_cckrx_enable = 0x0; /* default:A */ + p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option:B */ + break; + default: + break; + } + /*OFDM Rx*/ + set_bb_reg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, + ofdm_rx_ant_sel_val); + /*OFDM Rx*/ + set_bb_reg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, + ofdm_rx_ant_sel_val); + + cck_ant_sel_val = cck_ant_select_val; + /*CCK TxRx*/ + set_bb_reg(pAdapter, rCCK0_AFESetting, bMaskByte3, cck_ant_sel_val); +} + +void r8712_SetCrystalCap(struct _adapter *pAdapter) +{ + set_bb_reg(pAdapter, rFPGA0_AnalogParameter1, bXtalCap, + pAdapter->mppriv.curr_crystalcap); +} + +static void TriggerRFThermalMeter(struct _adapter *pAdapter) +{ + /* 0x24: RF Reg[6:5] */ + set_rf_reg(pAdapter, RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60); +} + +static u32 ReadRFThermalMeter(struct _adapter *pAdapter) +{ + /* 0x24: RF Reg[4:0] */ + return get_rf_reg(pAdapter, RF_PATH_A, RF_T_METER, 0x1F); +} + +void r8712_GetThermalMeter(struct _adapter *pAdapter, u32 *value) +{ + TriggerRFThermalMeter(pAdapter); + msleep(1000); + *value = ReadRFThermalMeter(pAdapter); +} + +void r8712_SetSingleCarrierTx(struct _adapter *pAdapter, u8 bStart) +{ + if (bStart) { /* Start Single Carrier. */ + /* 1. if OFDM block on? */ + if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) + /*set OFDM block on*/ + set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable); + /* 2. set CCK test mode off, set to CCK normal mode */ + set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); + /* 3. turn on scramble setting */ + set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); + /* 4. Turn On Single Carrier Tx and off the other test modes. */ + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); + } else { /* Stop Single Carrier.*/ + /* Turn off all test modes.*/ + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, + bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); + msleep(20); + /*BB Reset*/ + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + } +} + +void r8712_SetSingleToneTx(struct _adapter *pAdapter, u8 bStart) +{ + u8 rfPath = pAdapter->mppriv.curr_rfpath; + + switch (pAdapter->mppriv.antenna_tx) { + case ANTENNA_B: + rfPath = RF_PATH_B; + break; + case ANTENNA_A: + default: + rfPath = RF_PATH_A; + break; + } + if (bStart) { /* Start Single Tone.*/ + set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, bDisable); + set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bDisable); + set_rf_reg(pAdapter, rfPath, RF_TX_G2, bRFRegOffsetMask, + 0xd4000); + msleep(100); + /* PAD all on.*/ + set_rf_reg(pAdapter, rfPath, RF_AC, bRFRegOffsetMask, 0x2001f); + msleep(100); + } else { /* Stop Single Tone.*/ + set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable); + set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable); + set_rf_reg(pAdapter, rfPath, RF_TX_G2, bRFRegOffsetMask, + 0x54000); + msleep(100); + /* PAD all on.*/ + set_rf_reg(pAdapter, rfPath, RF_AC, bRFRegOffsetMask, 0x30000); + msleep(100); + } +} + +void r8712_SetCarrierSuppressionTx(struct _adapter *pAdapter, u8 bStart) +{ + if (bStart) { /* Start Carrier Suppression.*/ + if (pAdapter->mppriv.curr_rateidx <= MPT_RATE_11M) { + /* 1. if CCK block on? */ + if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn)) { + /*set CCK block on*/ + set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, + bEnable); + } + /* Turn Off All Test Mode */ + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, + bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, + bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, + bDisable); + /*transmit mode*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); + /*turn off scramble setting*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, + bDisable); + /*Set CCK Tx Test Rate*/ + /*Set FTxRate to 1Mbps*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); + } + } else { /* Stop Carrier Suppression. */ + if (pAdapter->mppriv.curr_rateidx <= MPT_RATE_11M) { + /*normal mode*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); + /*turn on scramble setting*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, + bEnable); + /*BB Reset*/ + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + } + } +} + +static void SetCCKContinuousTx(struct _adapter *pAdapter, u8 bStart) +{ + u32 cckrate; + + if (bStart) { + /* 1. if CCK block on? */ + if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn)) { + /*set CCK block on*/ + set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable); + } + /* Turn Off All Test Mode */ + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); + /*Set CCK Tx Test Rate*/ + cckrate = pAdapter->mppriv.curr_rateidx; + set_bb_reg(pAdapter, rCCK0_System, bCCKTxRate, cckrate); + /*transmit mode*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); + /*turn on scramble setting*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); + } else { + /*normal mode*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); + /*turn on scramble setting*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); + /*BB Reset*/ + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + } +} /* mpt_StartCckContTx */ + +static void SetOFDMContinuousTx(struct _adapter *pAdapter, u8 bStart) +{ + if (bStart) { + /* 1. if OFDM block on? */ + if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) { + /*set OFDM block on*/ + set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable); + } + /* 2. set CCK test mode off, set to CCK normal mode*/ + set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); + /* 3. turn on scramble setting */ + set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); + /* 4. Turn On Continue Tx and turn off the other test modes.*/ + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); + } else { + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, + bDisable); + set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); + msleep(20); + /*BB Reset*/ + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + } +} /* mpt_StartOfdmContTx */ + +void r8712_SetContinuousTx(struct _adapter *pAdapter, u8 bStart) +{ + /* ADC turn off [bit24-21] adc port0 ~ port1 */ + if (bStart) { + r8712_bb_reg_write(pAdapter, rRx_Wait_CCCA, + r8712_bb_reg_read(pAdapter, + rRx_Wait_CCCA) & 0xFE1FFFFF); + msleep(100); + } + if (pAdapter->mppriv.curr_rateidx <= MPT_RATE_11M) + SetCCKContinuousTx(pAdapter, bStart); + else if ((pAdapter->mppriv.curr_rateidx >= MPT_RATE_6M) && + (pAdapter->mppriv.curr_rateidx <= MPT_RATE_MCS15)) + SetOFDMContinuousTx(pAdapter, bStart); + /* ADC turn on [bit24-21] adc port0 ~ port1 */ + if (!bStart) + r8712_bb_reg_write(pAdapter, rRx_Wait_CCCA, + r8712_bb_reg_read(pAdapter, + rRx_Wait_CCCA) | 0x01E00000); +} + +void r8712_ResetPhyRxPktCount(struct _adapter *pAdapter) +{ + u32 i, phyrx_set = 0; + + for (i = OFDM_PPDU_BIT; i <= HT_MPDU_FAIL_BIT; i++) { + phyrx_set = 0; + phyrx_set |= (i << 28); /*select*/ + phyrx_set |= 0x08000000; /* set counter to zero*/ + r8712_write32(pAdapter, RXERR_RPT, phyrx_set); + } +} + +static u32 GetPhyRxPktCounts(struct _adapter *pAdapter, u32 selbit) +{ + /*selection*/ + u32 phyrx_set = 0, count = 0; + u32 SelectBit; + + SelectBit = selbit << 28; + phyrx_set |= (SelectBit & 0xF0000000); + r8712_write32(pAdapter, RXERR_RPT, phyrx_set); + /*Read packet count*/ + count = r8712_read32(pAdapter, RXERR_RPT) & RPTMaxCount; + return count; +} + +u32 r8712_GetPhyRxPktReceived(struct _adapter *pAdapter) +{ + u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; + + OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_OK_BIT); + CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_OK_BIT); + HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_OK_BIT); + return OFDM_cnt + CCK_cnt + HT_cnt; +} + +u32 r8712_GetPhyRxPktCRC32Error(struct _adapter *pAdapter) +{ + u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; + + OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_FAIL_BIT); + CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_FAIL_BIT); + HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_FAIL_BIT); + return OFDM_cnt + CCK_cnt + HT_cnt; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_mp.h b/kernel/drivers/staging/rtl8712/rtl871x_mp.h new file mode 100644 index 000000000..75893f225 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_mp.h @@ -0,0 +1,286 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL871X_MP_H_ +#define __RTL871X_MP_H_ + +#define MPT_NOOP 0 +#define MPT_READ_MAC_1BYTE 1 +#define MPT_READ_MAC_2BYTE 2 +#define MPT_READ_MAC_4BYTE 3 +#define MPT_WRITE_MAC_1BYTE 4 +#define MPT_WRITE_MAC_2BYTE 5 +#define MPT_WRITE_MAC_4BYTE 6 +#define MPT_READ_BB_CCK 7 +#define MPT_WRITE_BB_CCK 8 +#define MPT_READ_BB_OFDM 9 +#define MPT_WRITE_BB_OFDM 10 +#define MPT_READ_RF 11 +#define MPT_WRITE_RF 12 +#define MPT_READ_EEPROM_1BYTE 13 +#define MPT_WRITE_EEPROM_1BYTE 14 +#define MPT_READ_EEPROM_2BYTE 15 +#define MPT_WRITE_EEPROM_2BYTE 16 +#define MPT_SET_CSTHRESHOLD 21 +#define MPT_SET_INITGAIN 22 +#define MPT_SWITCH_BAND 23 +#define MPT_SWITCH_CHANNEL 24 +#define MPT_SET_DATARATE 25 +#define MPT_SWITCH_ANTENNA 26 +#define MPT_SET_TX_POWER 27 +#define MPT_SET_CONT_TX 28 +#define MPT_SET_SINGLE_CARRIER 29 +#define MPT_SET_CARRIER_SUPPRESSION 30 +#define MPT_GET_RATE_TABLE 31 +#define MPT_READ_TSSI 32 +#define MPT_GET_THERMAL_METER 33 +#define MAX_MP_XMITBUF_SZ 2048 +#define NR_MP_XMITFRAME 8 + +struct mp_xmit_frame { + struct list_head list; + struct pkt_attrib attrib; + _pkt *pkt; + int frame_tag; + struct _adapter *padapter; + u8 *mem_addr; + u16 sz[8]; + struct urb *pxmit_urb[8]; + u8 bpending[8]; + u8 last[8]; +}; + +struct mp_wiparam { + u32 bcompleted; + u32 act_type; + u32 io_offset; + u32 io_value; +}; + +struct mp_priv { + struct _adapter *papdater; + /*OID cmd handler*/ + struct mp_wiparam workparam; + u8 act_in_progress; + /*Tx Section*/ + u8 TID; + u32 tx_pktcount; + /*Rx Section*/ + u32 rx_pktcount; + u32 rx_crcerrpktcount; + u32 rx_pktloss; + struct recv_stat rxstat; + /*RF/BB relative*/ + u32 curr_ch; + u32 curr_rateidx; + u8 curr_bandwidth; + u8 curr_modem; + u8 curr_txpoweridx; + u32 curr_crystalcap; + u16 antenna_tx; + u16 antenna_rx; + u8 curr_rfpath; + u8 check_mp_pkt; + uint ForcedDataRate; + struct wlan_network mp_network; + unsigned char network_macaddr[6]; + /*Testing Flag*/ + u32 mode;/*0 for normal type packet, + * 1 for loopback packet (16bytes TXCMD)*/ + sint prev_fw_state; + u8 *pallocated_mp_xmitframe_buf; + u8 *pmp_xmtframe_buf; + struct __queue free_mp_xmitqueue; + u32 free_mp_xmitframe_cnt; +}; + +struct IOCMD_STRUCT { + u8 cmdclass; + u16 value; + u8 index; +}; + +struct rf_reg_param { + u32 path; + u32 offset; + u32 value; +}; + +struct bb_reg_param { + u32 offset; + u32 value; +}; +/* ======================================================================= */ + +#define LOWER true +#define RAISE false +#define IOCMD_CTRL_REG 0x10250370 +#define IOCMD_DATA_REG 0x10250374 +#define IOCMD_GET_THERMAL_METER 0xFD000028 +#define IOCMD_CLASS_BB_RF 0xF0 +#define IOCMD_BB_READ_IDX 0x00 +#define IOCMD_BB_WRITE_IDX 0x01 +#define IOCMD_RF_READ_IDX 0x02 +#define IOCMD_RF_WRIT_IDX 0x03 +#define BB_REG_BASE_ADDR 0x800 +#define RF_PATH_A 0 +#define RF_PATH_B 1 +#define RF_PATH_C 2 +#define RF_PATH_D 3 +#define MAX_RF_PATH_NUMS 2 +#define _2MAC_MODE_ 0 +#define _LOOPBOOK_MODE_ 1 + +/* MP set force data rate base on the definition. */ +enum { + /* CCK rate. */ + MPT_RATE_1M, /* 0 */ + MPT_RATE_2M, + MPT_RATE_55M, + MPT_RATE_11M, /* 3 */ + + /* OFDM rate. */ + MPT_RATE_6M, /* 4 */ + MPT_RATE_9M, + MPT_RATE_12M, + MPT_RATE_18M, + MPT_RATE_24M, + MPT_RATE_36M, + MPT_RATE_48M, + MPT_RATE_54M, /* 11 */ + + /* HT rate. */ + MPT_RATE_MCS0, /* 12 */ + MPT_RATE_MCS1, + MPT_RATE_MCS2, + MPT_RATE_MCS3, + MPT_RATE_MCS4, + MPT_RATE_MCS5, + MPT_RATE_MCS6, + MPT_RATE_MCS7, /* 19 */ + MPT_RATE_MCS8, + MPT_RATE_MCS9, + MPT_RATE_MCS10, + MPT_RATE_MCS11, + MPT_RATE_MCS12, + MPT_RATE_MCS13, + MPT_RATE_MCS14, + MPT_RATE_MCS15, /* 27 */ + MPT_RATE_LAST +}; + +/* Represent Channel Width in HT Capabilities */ +enum HT_CHANNEL_WIDTH { + HT_CHANNEL_WIDTH_20 = 0, + HT_CHANNEL_WIDTH_40 = 1, +}; + +#define MAX_TX_PWR_INDEX_N_MODE 64 /* 0x3F */ + +enum POWER_MODE { + POWER_LOW = 0, + POWER_NORMAL +}; + +#define RX_PKT_BROADCAST 1 +#define RX_PKT_DEST_ADDR 2 +#define RX_PKT_PHY_MATCH 3 + +#define RPTMaxCount 0x000FFFFF + +/* parameter 1 : BitMask + * bit 0 : OFDM PPDU + * bit 1 : OFDM False Alarm + * bit 2 : OFDM MPDU OK + * bit 3 : OFDM MPDU Fail + * bit 4 : CCK PPDU + * bit 5 : CCK False Alarm + * bit 6 : CCK MPDU ok + * bit 7 : CCK MPDU fail + * bit 8 : HT PPDU counter + * bit 9 : HT false alarm + * bit 10 : HT MPDU total + * bit 11 : HT MPDU OK + * bit 12 : HT MPDU fail + * bit 15 : RX full drop + */ +enum RXPHY_BITMASK { + OFDM_PPDU_BIT = 0, + OFDM_MPDU_OK_BIT, + OFDM_MPDU_FAIL_BIT, + CCK_PPDU_BIT, + CCK_MPDU_OK_BIT, + CCK_MPDU_FAIL_BIT, + HT_PPDU_BIT, + HT_MPDU_BIT, + HT_MPDU_OK_BIT, + HT_MPDU_FAIL_BIT, +}; + +enum ENCRY_CTRL_STATE { + HW_CONTROL, /*hw encryption& decryption*/ + SW_CONTROL, /*sw encryption& decryption*/ + HW_ENCRY_SW_DECRY, /*hw encryption & sw decryption*/ + SW_ENCRY_HW_DECRY /*sw encryption & hw decryption*/ +}; + +/* Bandwidth Offset */ +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 +/*=======================================================================*/ +void mp871xinit(struct _adapter *padapter); +void mp871xdeinit(struct _adapter *padapter); +u32 r8712_bb_reg_read(struct _adapter *Adapter, u16 offset); +u8 r8712_bb_reg_write(struct _adapter *Adapter, u16 offset, u32 value); +u32 r8712_rf_reg_read(struct _adapter *Adapter, u8 path, u8 offset); +u8 r8712_rf_reg_write(struct _adapter *Adapter, u8 path, + u8 offset, u32 value); +u32 r8712_get_bb_reg(struct _adapter *Adapter, u16 offset, u32 bitmask); +u8 r8712_set_bb_reg(struct _adapter *Adapter, u16 offset, + u32 bitmask, u32 value); +u32 r8712_get_rf_reg(struct _adapter *Adapter, u8 path, u8 offset, + u32 bitmask); +u8 r8712_set_rf_reg(struct _adapter *Adapter, u8 path, u8 offset, + u32 bitmask, u32 value); + +void r8712_SetChannel(struct _adapter *pAdapter); +void r8712_SetTxPower(struct _adapter *pAdapte); +void r8712_SetTxAGCOffset(struct _adapter *pAdapter, u32 ulTxAGCOffset); +void r8712_SetDataRate(struct _adapter *pAdapter); +void r8712_SwitchBandwidth(struct _adapter *pAdapter); +void r8712_SwitchAntenna(struct _adapter *pAdapter); +void r8712_SetCrystalCap(struct _adapter *pAdapter); +void r8712_GetThermalMeter(struct _adapter *pAdapter, u32 *value); +void r8712_SetContinuousTx(struct _adapter *pAdapter, u8 bStart); +void r8712_SetSingleCarrierTx(struct _adapter *pAdapter, u8 bStart); +void r8712_SetSingleToneTx(struct _adapter *pAdapter, u8 bStart); +void r8712_SetCarrierSuppressionTx(struct _adapter *pAdapter, u8 bStart); +void r8712_ResetPhyRxPktCount(struct _adapter *pAdapter); +u32 r8712_GetPhyRxPktReceived(struct _adapter *pAdapter); +u32 r8712_GetPhyRxPktCRC32Error(struct _adapter *pAdapter); + +#endif /*__RTL871X_MP_H_*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/kernel/drivers/staging/rtl8712/rtl871x_mp_ioctl.c new file mode 100644 index 000000000..0b5461208 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_mp_ioctl.c @@ -0,0 +1,929 @@ +/****************************************************************************** + * rtl871x_mp_ioctl.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#include <linux/rndis.h> +#include "osdep_service.h" +#include "drv_types.h" +#include "mlme_osdep.h" +#include "rtl871x_mp.h" +#include "rtl871x_mp_ioctl.h" + +uint oid_null_function(struct oid_par_priv *poid_par_priv) +{ + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid == SET_OID) { + if (poid_par_priv->information_buf_len >= sizeof(u8)) + Adapter->registrypriv.wireless_mode = + *(u8 *)poid_par_priv->information_buf; + else + status = RNDIS_STATUS_INVALID_LENGTH; + } else if (poid_par_priv->type_of_oid == QUERY_OID) { + if (poid_par_priv->information_buf_len >= sizeof(u8)) { + *(u8 *)poid_par_priv->information_buf = + Adapter->registrypriv.wireless_mode; + *poid_par_priv->bytes_rw = + poid_par_priv->information_buf_len; + } else + status = RNDIS_STATUS_INVALID_LENGTH; + } else { + status = RNDIS_STATUS_NOT_ACCEPTED; + } + return status; +} + +uint oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct bb_reg_param *pbbreg; + u16 offset; + u32 value; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) + return RNDIS_STATUS_INVALID_LENGTH; + pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); + offset = (u16)(pbbreg->offset) & 0xFFF; /*0ffset :0x800~0xfff*/ + if (offset < BB_REG_BASE_ADDR) + offset |= BB_REG_BASE_ADDR; + value = pbbreg->value; + r8712_bb_reg_write(Adapter, offset, value); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct bb_reg_param *pbbreg; + u16 offset; + u32 value; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) + return RNDIS_STATUS_INVALID_LENGTH; + pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); + offset = (u16)(pbbreg->offset) & 0xFFF; /*0ffset :0x800~0xfff*/ + if (offset < BB_REG_BASE_ADDR) + offset |= BB_REG_BASE_ADDR; + value = r8712_bb_reg_read(Adapter, offset); + pbbreg->value = value; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct rf_reg_param *pbbreg; + u8 path; + u8 offset; + u32 value; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) + return RNDIS_STATUS_INVALID_LENGTH; + pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); + path = (u8)pbbreg->path; + if (path > RF_PATH_B) + return RNDIS_STATUS_NOT_ACCEPTED; + offset = (u8)pbbreg->offset; + value = pbbreg->value; + r8712_rf_reg_write(Adapter, path, offset, value); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + struct rf_reg_param *pbbreg; + u8 path; + u8 offset; + u32 value; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) + return RNDIS_STATUS_INVALID_LENGTH; + pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); + path = (u8)pbbreg->path; + if (path > RF_PATH_B) /* 1T2R path_a /path_b */ + return RNDIS_STATUS_NOT_ACCEPTED; + offset = (u8)pbbreg->offset; + value = r8712_rf_reg_read(Adapter, path, offset); + pbbreg->value = value; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +/*This function initializes the DUT to the MP test mode*/ +static int mp_start_test(struct _adapter *padapter) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + struct ndis_wlan_bssid_ex bssid; + struct sta_info *psta; + unsigned long length; + unsigned long irqL; + int res = _SUCCESS; + + /* 3 1. initialize a new struct ndis_wlan_bssid_ex */ + memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN); + bssid.Ssid.SsidLength = 16; + memcpy(bssid.Ssid.Ssid, (unsigned char *)"mp_pseudo_adhoc", + bssid.Ssid.SsidLength); + bssid.InfrastructureMode = Ndis802_11IBSS; + bssid.NetworkTypeInUse = Ndis802_11DS; + bssid.IELength = 0; + length = r8712_get_ndis_wlan_bssid_ex_sz(&bssid); + if (length % 4) { + /*round up to multiple of 4 bytes.*/ + bssid.Length = ((length >> 2) + 1) << 2; + } else + bssid.Length = length; + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) + goto end_of_mp_start_test; + /*init mp_start_test status*/ + pmppriv->prev_fw_state = get_fwstate(pmlmepriv); + pmlmepriv->fw_state = WIFI_MP_STATE; + if (pmppriv->mode == _LOOPBOOK_MODE_) + set_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE); /*append txdesc*/ + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + /* 3 2. create a new psta for mp driver */ + /* clear psta in the cur_network, if any */ + psta = r8712_get_stainfo(&padapter->stapriv, + tgt_network->network.MacAddress); + if (psta) + r8712_free_stainfo(padapter, psta); + psta = r8712_alloc_stainfo(&padapter->stapriv, bssid.MacAddress); + if (psta == NULL) { + res = _FAIL; + goto end_of_mp_start_test; + } + /* 3 3. join psudo AdHoc */ + tgt_network->join_res = 1; + tgt_network->aid = psta->aid = 1; + memcpy(&tgt_network->network, &bssid, length); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + r8712_os_indicate_connect(padapter); + /* Set to LINKED STATE for MP TRX Testing */ + set_fwstate(pmlmepriv, _FW_LINKED); +end_of_mp_start_test: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return res; +} + +/*This function change the DUT from the MP test mode into normal mode */ +static int mp_stop_test(struct _adapter *padapter) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + struct sta_info *psta; + unsigned long irqL; + + spin_lock_irqsave(&pmlmepriv->lock, irqL); + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false) + goto end_of_mp_stop_test; + /* 3 1. disconnect psudo AdHoc */ + r8712_os_indicate_disconnect(padapter); + /* 3 2. clear psta used in mp test mode. */ + psta = r8712_get_stainfo(&padapter->stapriv, + tgt_network->network.MacAddress); + if (psta) + r8712_free_stainfo(padapter, psta); + /* 3 3. return to normal state (default:station mode) */ + pmlmepriv->fw_state = pmppriv->prev_fw_state; /* WIFI_STATION_STATE;*/ + /*flush the cur_network*/ + memset(tgt_network, 0, sizeof(struct wlan_network)); +end_of_mp_stop_test: + spin_unlock_irqrestore(&pmlmepriv->lock, irqL); + return _SUCCESS; +} + +int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + unsigned char res = _SUCCESS; + + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false) + return _FAIL; + if (check_fwstate(pmlmepriv, _FW_LINKED) == false) + return _FAIL; + _clr_fwstate_(pmlmepriv, _FW_LINKED); + res = r8712_setassocsta_cmd(padapter, pmppriv->network_macaddr); + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + return res; +} + +uint oid_rt_pro_set_data_rate_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 ratevalue; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len != sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + ratevalue = *((u32 *)poid_par_priv->information_buf); + if (ratevalue >= MPT_RATE_LAST) + return RNDIS_STATUS_INVALID_DATA; + Adapter->mppriv.curr_rateidx = ratevalue; + r8712_SetDataRate(Adapter); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + uint status = RNDIS_STATUS_SUCCESS; + u32 mode; + u8 val8; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + mode = *((u32 *)poid_par_priv->information_buf); + Adapter->mppriv.mode = mode;/* 1 for loopback*/ + if (mp_start_test(Adapter) == _FAIL) + status = RNDIS_STATUS_NOT_ACCEPTED; + r8712_write8(Adapter, MSR, 1); /* Link in ad hoc network, 0x1025004C */ + r8712_write8(Adapter, RCR, 0); /* RCR : disable all pkt, 0x10250048 */ + /* RCR disable Check BSSID, 0x1025004a */ + r8712_write8(Adapter, RCR+2, 0x57); + /* disable RX filter map , mgt frames will put in RX FIFO 0 */ + r8712_write16(Adapter, RXFLTMAP0, 0x0); + val8 = r8712_read8(Adapter, EE_9346CR); + if (!(val8 & _9356SEL)) { /*boot from EFUSE*/ + r8712_efuse_reg_init(Adapter); + r8712_efuse_change_max_size(Adapter); + r8712_efuse_reg_uninit(Adapter); + } + return status; +} + +uint oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + uint status = RNDIS_STATUS_SUCCESS; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (mp_stop_test(Adapter) == _FAIL) + status = RNDIS_STATUS_NOT_ACCEPTED; + return status; +} + +uint oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 Channel; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len != sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + Channel = *((u32 *)poid_par_priv->information_buf); + if (Channel > 14) + return RNDIS_STATUS_NOT_ACCEPTED; + Adapter->mppriv.curr_ch = Channel; + r8712_SetChannel(Adapter); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 antenna; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len != sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + antenna = *((u32 *)poid_par_priv->information_buf); + Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16); + Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF); + r8712_SwitchAntenna(Adapter); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_set_tx_power_control_hdl( + struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 tx_pwr_idx; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len != sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + tx_pwr_idx = *((u32 *)poid_par_priv->information_buf); + if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE) + return RNDIS_STATUS_NOT_ACCEPTED; + Adapter->mppriv.curr_txpoweridx = (u8)tx_pwr_idx; + r8712_SetTxPower(Adapter); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_query_tx_packet_sent_hdl( + struct oid_par_priv *poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = RNDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len == sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + Adapter->mppriv.tx_pktcount; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = RNDIS_STATUS_INVALID_LENGTH; + return status; +} + +uint oid_rt_pro_query_rx_packet_received_hdl( + struct oid_par_priv *poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = RNDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len == sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + Adapter->mppriv.rx_pktcount; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = RNDIS_STATUS_INVALID_LENGTH; + return status; +} + +uint oid_rt_pro_query_rx_packet_crc32_error_hdl( + struct oid_par_priv *poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = RNDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len == sizeof(u32)) { + *(u32 *)poid_par_priv->information_buf = + Adapter->mppriv.rx_crcerrpktcount; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = RNDIS_STATUS_INVALID_LENGTH; + return status; +} + +uint oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + Adapter->mppriv.tx_pktcount = 0; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv + *poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len == sizeof(u32)) { + Adapter->mppriv.rx_pktcount = 0; + Adapter->mppriv.rx_crcerrpktcount = 0; + } else + status = RNDIS_STATUS_INVALID_LENGTH; + return status; +} + +uint oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + r8712_ResetPhyRxPktCount(Adapter); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len != sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + *(u32 *)poid_par_priv->information_buf = + r8712_GetPhyRxPktReceived(Adapter); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len != sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + *(u32 *)poid_par_priv->information_buf = + r8712_GetPhyRxPktCRC32Error(Adapter); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_set_modulation_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + + Adapter->mppriv.curr_modem = *((u8 *)poid_par_priv->information_buf); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 bStartTest; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + bStartTest = *((u32 *)poid_par_priv->information_buf); + r8712_SetContinuousTx(Adapter, (u8)bStartTest); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 bStartTest; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + bStartTest = *((u32 *)poid_par_priv->information_buf); + r8712_SetSingleCarrierTx(Adapter, (u8)bStartTest); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 bStartTest; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + bStartTest = *((u32 *)poid_par_priv->information_buf); + r8712_SetCarrierSuppressionTx(Adapter, (u8)bStartTest); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 bStartTest; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + bStartTest = *((u32 *)poid_par_priv->information_buf); + r8712_SetSingleToneTx(Adapter, (u8)bStartTest); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_read_register_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + uint status = RNDIS_STATUS_SUCCESS; + struct mp_rw_reg *RegRWStruct; + u16 offset; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; + if ((RegRWStruct->offset >= 0x10250800) && + (RegRWStruct->offset <= 0x10250FFF)) { + /*baseband register*/ + /*0ffset :0x800~0xfff*/ + offset = (u16)(RegRWStruct->offset) & 0xFFF; + RegRWStruct->value = r8712_bb_reg_read(Adapter, offset); + } else { + switch (RegRWStruct->width) { + case 1: + RegRWStruct->value = r8712_read8(Adapter, + RegRWStruct->offset); + break; + case 2: + RegRWStruct->value = r8712_read16(Adapter, + RegRWStruct->offset); + break; + case 4: + RegRWStruct->value = r8712_read32(Adapter, + RegRWStruct->offset); + break; + default: + status = RNDIS_STATUS_NOT_ACCEPTED; + break; + } + } + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return status; +} + +uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + uint status = RNDIS_STATUS_SUCCESS; + struct mp_rw_reg *RegRWStruct; + u16 offset; + u32 value; + u32 oldValue = 0; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; + if ((RegRWStruct->offset >= 0x10250800) && + (RegRWStruct->offset <= 0x10250FFF)) { + /*baseband register*/ + offset = (u16)(RegRWStruct->offset) & 0xFFF; + value = RegRWStruct->value; + switch (RegRWStruct->width) { + case 1: + oldValue = r8712_bb_reg_read(Adapter, offset); + oldValue &= 0xFFFFFF00; + value &= 0x000000FF; + value |= oldValue; + break; + case 2: + oldValue = r8712_bb_reg_read(Adapter, offset); + oldValue &= 0xFFFF0000; + value &= 0x0000FFFF; + value |= oldValue; + break; + } + r8712_bb_reg_write(Adapter, offset, value); + } else { + switch (RegRWStruct->width) { + case 1: + r8712_write8(Adapter, RegRWStruct->offset, + (unsigned char)RegRWStruct->value); + break; + case 2: + r8712_write16(Adapter, RegRWStruct->offset, + (unsigned short)RegRWStruct->value); + break; + case 4: + r8712_write32(Adapter, RegRWStruct->offset, + (unsigned int)RegRWStruct->value); + break; + default: + status = RNDIS_STATUS_NOT_ACCEPTED; + break; + } + + if ((status == RNDIS_STATUS_SUCCESS) && + (RegRWStruct->offset == HIMR) && + (RegRWStruct->width == 4)) + Adapter->ImrContent = RegRWStruct->value; + } + return status; +} + +uint oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + + if (Adapter->mppriv.act_in_progress == true) + return RNDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u8)) + return RNDIS_STATUS_INVALID_LENGTH; + /*init workparam*/ + Adapter->mppriv.act_in_progress = true; + Adapter->mppriv.workparam.bcompleted = false; + Adapter->mppriv.workparam.act_type = MPT_GET_THERMAL_METER; + Adapter->mppriv.workparam.io_offset = 0; + Adapter->mppriv.workparam.io_value = 0xFFFFFFFF; + r8712_GetThermalMeter(Adapter, &Adapter->mppriv.workparam.io_value); + Adapter->mppriv.workparam.bcompleted = true; + Adapter->mppriv.act_in_progress = false; + *(u32 *)poid_par_priv->information_buf = + Adapter->mppriv.workparam.io_value; + *poid_par_priv->bytes_rw = sizeof(u32); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + uint status = RNDIS_STATUS_SUCCESS; + + struct EFUSE_ACCESS_STRUCT *pefuse; + u8 *data; + u16 addr = 0, cnts = 0; + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < + sizeof(struct EFUSE_ACCESS_STRUCT)) + return RNDIS_STATUS_INVALID_LENGTH; + pefuse = (struct EFUSE_ACCESS_STRUCT *)poid_par_priv->information_buf; + addr = pefuse->start_addr; + cnts = pefuse->cnts; + data = pefuse->data; + memset(data, 0xFF, cnts); + if ((addr > 511) || (cnts < 1) || (cnts > 512) || (addr + cnts) > + EFUSE_MAX_SIZE) + return RNDIS_STATUS_NOT_ACCEPTED; + if (r8712_efuse_access(Adapter, true, addr, cnts, data) == false) + status = RNDIS_STATUS_FAILURE; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return status; +} +/*------------------------------------------------------------------------*/ +uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + uint status = RNDIS_STATUS_SUCCESS; + + struct EFUSE_ACCESS_STRUCT *pefuse; + u8 *data; + u16 addr = 0, cnts = 0; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + + pefuse = (struct EFUSE_ACCESS_STRUCT *)poid_par_priv->information_buf; + addr = pefuse->start_addr; + cnts = pefuse->cnts; + data = pefuse->data; + + if ((addr > 511) || (cnts < 1) || (cnts > 512) || + (addr + cnts) > r8712_efuse_get_max_size(Adapter)) + return RNDIS_STATUS_NOT_ACCEPTED; + if (r8712_efuse_access(Adapter, false, addr, cnts, data) == false) + status = RNDIS_STATUS_FAILURE; + return status; +} +/*----------------------------------------------------------------------*/ + +uint oid_rt_get_efuse_current_size_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(int)) + return RNDIS_STATUS_INVALID_LENGTH; + r8712_efuse_reg_init(Adapter); + *(int *)poid_par_priv->information_buf = + r8712_efuse_get_current_size(Adapter); + r8712_efuse_reg_uninit(Adapter); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + *(int *)poid_par_priv->information_buf = + r8712_efuse_get_max_size(Adapter); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ + uint status = RNDIS_STATUS_SUCCESS; + + if (poid_par_priv->type_of_oid == QUERY_OID) + status = oid_rt_pro_read_efuse_hdl(poid_par_priv); + else + status = oid_rt_pro_write_efuse_hdl(poid_par_priv); + return status; +} + +uint oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + uint status = RNDIS_STATUS_SUCCESS; + u8 *data; + + *poid_par_priv->bytes_rw = 0; + if (poid_par_priv->information_buf_len < EFUSE_MAP_MAX_SIZE) + return RNDIS_STATUS_INVALID_LENGTH; + data = (u8 *)poid_par_priv->information_buf; + if (poid_par_priv->type_of_oid == QUERY_OID) { + if (r8712_efuse_map_read(Adapter, 0, EFUSE_MAP_MAX_SIZE, data)) + *poid_par_priv->bytes_rw = EFUSE_MAP_MAX_SIZE; + else + status = RNDIS_STATUS_FAILURE; + } else { + /* SET_OID */ + if (r8712_efuse_reg_init(Adapter) == true) { + if (r8712_efuse_map_write(Adapter, 0, + EFUSE_MAP_MAX_SIZE, data)) + *poid_par_priv->bytes_rw = EFUSE_MAP_MAX_SIZE; + else + status = RNDIS_STATUS_FAILURE; + r8712_efuse_reg_uninit(Adapter); + } else { + status = RNDIS_STATUS_FAILURE; + } + } + return status; +} + +uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u32 bandwidth; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + bandwidth = *((u32 *)poid_par_priv->information_buf);/*4*/ + if (bandwidth != HT_CHANNEL_WIDTH_20) + bandwidth = HT_CHANNEL_WIDTH_40; + Adapter->mppriv.curr_bandwidth = (u8)bandwidth; + r8712_SwitchBandwidth(Adapter); + return RNDIS_STATUS_SUCCESS; +} + +uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv + *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + u8 rx_pkt_type; + u32 rcr_val32; + + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(u8)) + return RNDIS_STATUS_INVALID_LENGTH; + rx_pkt_type = *((u8 *)poid_par_priv->information_buf);/*4*/ + rcr_val32 = r8712_read32(Adapter, RCR);/*RCR = 0x10250048*/ + rcr_val32 &= ~(RCR_CBSSID | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); + switch (rx_pkt_type) { + case RX_PKT_BROADCAST: + rcr_val32 |= (RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_ACRC32); + break; + case RX_PKT_DEST_ADDR: + rcr_val32 |= (RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_ACRC32); + break; + case RX_PKT_PHY_MATCH: + rcr_val32 |= (RCR_APM|RCR_ACRC32); + break; + default: + rcr_val32 &= ~(RCR_AAP | + RCR_APM | + RCR_AM | + RCR_AB | + RCR_ACRC32); + break; + } + if (rx_pkt_type == RX_PKT_DEST_ADDR) + Adapter->mppriv.check_mp_pkt = 1; + else + Adapter->mppriv.check_mp_pkt = 0; + r8712_write32(Adapter, RCR, rcr_val32); + return RNDIS_STATUS_SUCCESS; +} + +/*--------------------------------------------------------------------------*/ +/*Linux*/ +unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) +{ + return _SUCCESS; +} +/*-------------------------------------------------------------------------*/ +uint oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv) +{ + if (poid_par_priv->type_of_oid != SET_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + /*CALL the power_down function*/ + return RNDIS_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- */ +uint oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + struct _adapter *Adapter = (struct _adapter *) + (poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len < sizeof(u32)) + return RNDIS_STATUS_INVALID_LENGTH; + *(int *)poid_par_priv->information_buf = + Adapter->registrypriv.low_power ? POWER_LOW : POWER_NORMAL; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return RNDIS_STATUS_SUCCESS; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_mp_ioctl.h b/kernel/drivers/staging/rtl8712/rtl871x_mp_ioctl.h new file mode 100644 index 000000000..8e7c7f8b6 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_mp_ioctl.h @@ -0,0 +1,434 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL871X_MP_IOCTL_H +#define _RTL871X_MP_IOCTL_H + +#include "osdep_service.h" +#include "drv_types.h" +#include "mp_custom_oid.h" +#include "rtl871x_ioctl.h" +#include "rtl871x_ioctl_rtl.h" +#include "rtl8712_efuse.h" + +#define TESTFWCMDNUMBER 1000000 +#define TEST_H2CINT_WAIT_TIME 500 +#define TEST_C2HINT_WAIT_TIME 500 +#define HCI_TEST_SYSCFG_HWMASK 1 +#define _BUSCLK_40M (4 << 2) + +struct CFG_DBG_MSG_STRUCT { + u32 DebugLevel; + u32 DebugComponent_H32; + u32 DebugComponent_L32; +}; + +struct mp_rw_reg { + uint offset; + uint width; + u32 value; +}; + +/* for OID_RT_PRO_READ16_EEPROM & OID_RT_PRO_WRITE16_EEPROM */ +struct eeprom_rw_param { + uint offset; + u16 value; +}; + +struct EFUSE_ACCESS_STRUCT { + u16 start_addr; + u16 cnts; + u8 data[0]; +}; + +struct burst_rw_reg { + uint offset; + uint len; + u8 Data[256]; +}; + +struct usb_vendor_req { + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; + u8 u8Dir;/*0:OUT, 1:IN */ + u8 u8InData; +}; + +struct DR_VARIABLE_STRUCT { + u8 offset; + u32 variable; +}; + +int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid); + +/* oid_rtl_seg_87_11_00 */ +uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv); +/* oid_rtl_seg_81_80_00 */ +uint oid_rt_pro_set_data_rate_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_channel_direct_call_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_antenna_bb_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_tx_power_control_hdl( + struct oid_par_priv *poid_par_priv); +/* oid_rtl_seg_81_80_20 */ +uint oid_rt_pro_query_tx_packet_sent_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_query_rx_packet_received_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_query_rx_packet_crc32_error_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_reset_tx_packet_sent_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_reset_rx_packet_received_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_continuous_tx_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_single_carrier_tx_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_carrier_suppression_tx_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_set_single_tone_tx_hdl( + struct oid_par_priv *poid_par_priv); +/* oid_rtl_seg_81_87 */ +uint oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv); +/* oid_rtl_seg_81_85 */ +uint oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_get_efuse_current_size_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv); +uint oid_rt_get_thermal_meter_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_reset_phy_rx_packet_count_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_phy_rx_packet_received_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_phy_rx_packet_crc32_error_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_set_power_down_hdl( + struct oid_par_priv *poid_par_priv); +uint oid_rt_get_power_mode_hdl( + struct oid_par_priv *poid_par_priv); +#ifdef _RTL871X_MP_IOCTL_C_ /* CAUTION!!! */ +/* This ifdef _MUST_ be left in!! */ +static const struct oid_obj_priv oid_rtl_seg_81_80_00[] = { + {1, &oid_null_function}, /*0x00 OID_RT_PRO_RESET_DUT */ + {1, &oid_rt_pro_set_data_rate_hdl}, /*0x01*/ + {1, &oid_rt_pro_start_test_hdl},/*0x02*/ + {1, &oid_rt_pro_stop_test_hdl}, /*0x03*/ + {1, &oid_null_function}, /*0x04 OID_RT_PRO_SET_PREAMBLE*/ + {1, &oid_null_function}, /*0x05 OID_RT_PRO_SET_SCRAMBLER*/ + {1, &oid_null_function}, /*0x06 OID_RT_PRO_SET_FILTER_BB*/ + {1, &oid_null_function}, /*0x07 + * OID_RT_PRO_SET_MANUAL_DIVERS_BB*/ + {1, &oid_rt_pro_set_channel_direct_call_hdl}, /*0x08*/ + {1, &oid_null_function}, /*0x09 + * OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL*/ + {1, &oid_null_function}, /*0x0A + * OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL*/ + {1, &oid_rt_pro_set_continuous_tx_hdl}, /*0x0B + * OID_RT_PRO_SET_TX_CONTINUOUS_DIRECT_CALL*/ + {1, &oid_rt_pro_set_single_carrier_tx_hdl}, /*0x0C + * OID_RT_PRO_SET_SINGLE_CARRIER_TX_CONTINUOUS*/ + {1, &oid_null_function}, /*0x0D + * OID_RT_PRO_SET_TX_ANTENNA_BB*/ + {1, &oid_rt_pro_set_antenna_bb_hdl}, /*0x0E*/ + {1, &oid_null_function}, /*0x0F OID_RT_PRO_SET_CR_SCRAMBLER*/ + {1, &oid_null_function}, /*0x10 OID_RT_PRO_SET_CR_NEW_FILTER*/ + {1, &oid_rt_pro_set_tx_power_control_hdl}, /*0x11 + * OID_RT_PRO_SET_TX_POWER_CONTROL*/ + {1, &oid_null_function}, /*0x12 OID_RT_PRO_SET_CR_TX_CONFIG*/ + {1, &oid_null_function}, /*0x13 + * OID_RT_PRO_GET_TX_POWER_CONTROL*/ + {1, &oid_null_function}, /*0x14 + * OID_RT_PRO_GET_CR_SIGNAL_QUALITY*/ + {1, &oid_null_function}, /*0x15 OID_RT_PRO_SET_CR_SETPOINT*/ + {1, &oid_null_function}, /*0x16 OID_RT_PRO_SET_INTEGRATOR*/ + {1, &oid_null_function}, /*0x17 OID_RT_PRO_SET_SIGNAL_QUALITY*/ + {1, &oid_null_function}, /*0x18 OID_RT_PRO_GET_INTEGRATOR*/ + {1, &oid_null_function}, /*0x19 OID_RT_PRO_GET_SIGNAL_QUALITY*/ + {1, &oid_null_function}, /*0x1A OID_RT_PRO_QUERY_EEPROM_TYPE*/ + {1, &oid_null_function}, /*0x1B OID_RT_PRO_WRITE_MAC_ADDRESS*/ + {1, &oid_null_function}, /*0x1C OID_RT_PRO_READ_MAC_ADDRESS*/ + {1, &oid_null_function}, /*0x1D OID_RT_PRO_WRITE_CIS_DATA*/ + {1, &oid_null_function}, /*0x1E OID_RT_PRO_READ_CIS_DATA*/ + {1, &oid_null_function} /*0x1F OID_RT_PRO_WRITE_POWER_CONTROL*/ +}; + +static const struct oid_obj_priv oid_rtl_seg_81_80_20[] = { + {1, &oid_null_function}, /*0x20 OID_RT_PRO_READ_POWER_CONTROL*/ + {1, &oid_null_function}, /*0x21 OID_RT_PRO_WRITE_EEPROM*/ + {1, &oid_null_function}, /*0x22 OID_RT_PRO_READ_EEPROM*/ + {1, &oid_rt_pro_reset_tx_packet_sent_hdl}, /*0x23*/ + {1, &oid_rt_pro_query_tx_packet_sent_hdl}, /*0x24*/ + {1, &oid_rt_pro_reset_rx_packet_received_hdl}, /*0x25*/ + {1, &oid_rt_pro_query_rx_packet_received_hdl}, /*0x26*/ + {1, &oid_rt_pro_query_rx_packet_crc32_error_hdl},/*0x27*/ + {1, &oid_null_function}, /*0x28 + *OID_RT_PRO_QUERY_CURRENT_ADDRESS*/ + {1, &oid_null_function}, /*0x29 + *OID_RT_PRO_QUERY_PERMANENT_ADDRESS*/ + {1, &oid_null_function}, /*0x2A + *OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS*/ + {1, &oid_rt_pro_set_carrier_suppression_tx_hdl},/*0x2B + *OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX*/ + {1, &oid_null_function}, /*0x2C OID_RT_PRO_RECEIVE_PACKET*/ + {1, &oid_null_function}, /*0x2D OID_RT_PRO_WRITE_EEPROM_BYTE*/ + {1, &oid_null_function}, /*0x2E OID_RT_PRO_READ_EEPROM_BYTE*/ + {1, &oid_rt_pro_set_modulation_hdl} /*0x2F*/ +}; + +static const struct oid_obj_priv oid_rtl_seg_81_80_40[] = { + {1, &oid_null_function}, /*0x40*/ + {1, &oid_null_function}, /*0x41*/ + {1, &oid_null_function}, /*0x42*/ + {1, &oid_rt_pro_set_single_tone_tx_hdl}, /*0x43*/ + {1, &oid_null_function}, /*0x44*/ + {1, &oid_null_function} /*0x45*/ +}; + +static const struct oid_obj_priv oid_rtl_seg_81_80_80[] = { + {1, &oid_null_function}, /*0x80 OID_RT_DRIVER_OPTION*/ + {1, &oid_null_function}, /*0x81 OID_RT_RF_OFF*/ + {1, &oid_null_function} /*0x82 OID_RT_AUTH_STATUS*/ + +}; + +static const struct oid_obj_priv oid_rtl_seg_81_85[] = { + {1, &oid_rt_wireless_mode_hdl} /*0x00 OID_RT_WIRELESS_MODE*/ +}; + +#else /* _RTL871X_MP_IOCTL_C_ */ +extern struct oid_obj_priv oid_rtl_seg_81_80_00[32]; +extern struct oid_obj_priv oid_rtl_seg_81_80_20[16]; +extern struct oid_obj_priv oid_rtl_seg_81_80_40[6]; +extern struct oid_obj_priv oid_rtl_seg_81_80_80[3]; +extern struct oid_obj_priv oid_rtl_seg_81_85[1]; +extern struct oid_obj_priv oid_rtl_seg_81_87[5]; +extern struct oid_obj_priv oid_rtl_seg_87_11_00[32]; +extern struct oid_obj_priv oid_rtl_seg_87_11_20[5]; +extern struct oid_obj_priv oid_rtl_seg_87_11_50[2]; +extern struct oid_obj_priv oid_rtl_seg_87_11_80[1]; +extern struct oid_obj_priv oid_rtl_seg_87_11_B0[1]; +extern struct oid_obj_priv oid_rtl_seg_87_11_F0[16]; +extern struct oid_obj_priv oid_rtl_seg_87_12_00[32]; + +#endif /* _RTL871X_MP_IOCTL_C_ */ + + +enum MP_MODE { + MP_START_MODE, + MP_STOP_MODE, + MP_ERR_MODE +}; + +struct rwreg_param { + unsigned int offset; + unsigned int width; + unsigned int value; +}; + +struct bbreg_param { + unsigned int offset; + unsigned int phymask; + unsigned int value; +}; + +struct txpower_param { + unsigned int pwr_index; +}; + +struct datarate_param { + unsigned int rate_index; +}; + +struct rfintfs_parm { + unsigned int rfintfs; +}; + +struct mp_xmit_packet { + unsigned int len; +}; + +struct psmode_param { + unsigned int ps_mode; + unsigned int smart_ps; +}; + +struct mp_ioctl_handler { + unsigned int paramsize; + unsigned int (*handler)(struct oid_par_priv *poid_par_priv); + unsigned int oid; +}; + +struct mp_ioctl_param { + unsigned int subcode; + unsigned int len; + unsigned char data[0]; +}; + +#define GEN_MP_IOCTL_SUBCODE(code) _MP_IOCTL_ ## code ## _CMD_ + +enum RTL871X_MP_IOCTL_SUBCODE { + GEN_MP_IOCTL_SUBCODE(MP_START), /*0*/ + GEN_MP_IOCTL_SUBCODE(MP_STOP), /*1*/ + GEN_MP_IOCTL_SUBCODE(READ_REG), /*2*/ + GEN_MP_IOCTL_SUBCODE(WRITE_REG), + GEN_MP_IOCTL_SUBCODE(SET_CHANNEL), /*4*/ + GEN_MP_IOCTL_SUBCODE(SET_TXPOWER), /*5*/ + GEN_MP_IOCTL_SUBCODE(SET_DATARATE), /*6*/ + GEN_MP_IOCTL_SUBCODE(READ_BB_REG), /*7*/ + GEN_MP_IOCTL_SUBCODE(WRITE_BB_REG), + GEN_MP_IOCTL_SUBCODE(READ_RF_REG), /*9*/ + GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG), + GEN_MP_IOCTL_SUBCODE(SET_RF_INTFS), + GEN_MP_IOCTL_SUBCODE(IOCTL_XMIT_PACKET), /*12*/ + GEN_MP_IOCTL_SUBCODE(PS_STATE), /*13*/ + GEN_MP_IOCTL_SUBCODE(READ16_EEPROM), /*14*/ + GEN_MP_IOCTL_SUBCODE(WRITE16_EEPROM), /*15*/ + GEN_MP_IOCTL_SUBCODE(SET_PTM), /*16*/ + GEN_MP_IOCTL_SUBCODE(READ_TSSI), /*17*/ + GEN_MP_IOCTL_SUBCODE(CNTU_TX), /*18*/ + GEN_MP_IOCTL_SUBCODE(SET_BANDWIDTH), /*19*/ + GEN_MP_IOCTL_SUBCODE(SET_RX_PKT_TYPE), /*20*/ + GEN_MP_IOCTL_SUBCODE(RESET_PHY_RX_PKT_CNT), /*21*/ + GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_RECV), /*22*/ + GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_ERROR), /*23*/ + GEN_MP_IOCTL_SUBCODE(SET_POWER_DOWN), /*24*/ + GEN_MP_IOCTL_SUBCODE(GET_THERMAL_METER), /*25*/ + GEN_MP_IOCTL_SUBCODE(GET_POWER_MODE), /*26*/ + GEN_MP_IOCTL_SUBCODE(EFUSE), /*27*/ + GEN_MP_IOCTL_SUBCODE(EFUSE_MAP), /*28*/ + GEN_MP_IOCTL_SUBCODE(GET_EFUSE_MAX_SIZE), /*29*/ + GEN_MP_IOCTL_SUBCODE(GET_EFUSE_CURRENT_SIZE), /*30*/ + GEN_MP_IOCTL_SUBCODE(SC_TX), /*31*/ + GEN_MP_IOCTL_SUBCODE(CS_TX), /*32*/ + GEN_MP_IOCTL_SUBCODE(ST_TX), /*33*/ + GEN_MP_IOCTL_SUBCODE(SET_ANTENNA), /*34*/ + MAX_MP_IOCTL_SUBCODE, +}; + +unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv); + +#ifdef _RTL871X_MP_IOCTL_C_ /* CAUTION!!! */ +/* This ifdef _MUST_ be left in!! */ + +static struct mp_ioctl_handler mp_ioctl_hdl[] = { + {sizeof(u32), oid_rt_pro_start_test_hdl, + OID_RT_PRO_START_TEST},/*0*/ + {sizeof(u32), oid_rt_pro_stop_test_hdl, + OID_RT_PRO_STOP_TEST},/*1*/ + {sizeof(struct rwreg_param), + oid_rt_pro_read_register_hdl, + OID_RT_PRO_READ_REGISTER},/*2*/ + {sizeof(struct rwreg_param), + oid_rt_pro_write_register_hdl, + OID_RT_PRO_WRITE_REGISTER}, + {sizeof(u32), + oid_rt_pro_set_channel_direct_call_hdl, + OID_RT_PRO_SET_CHANNEL_DIRECT_CALL}, + {sizeof(struct txpower_param), + oid_rt_pro_set_tx_power_control_hdl, + OID_RT_PRO_SET_TX_POWER_CONTROL}, + {sizeof(u32), + oid_rt_pro_set_data_rate_hdl, + OID_RT_PRO_SET_DATA_RATE}, + {sizeof(struct bb_reg_param), + oid_rt_pro_read_bb_reg_hdl, + OID_RT_PRO_READ_BB_REG},/*7*/ + {sizeof(struct bb_reg_param), + oid_rt_pro_write_bb_reg_hdl, + OID_RT_PRO_WRITE_BB_REG}, + {sizeof(struct rwreg_param), + oid_rt_pro_read_rf_reg_hdl, + OID_RT_PRO_RF_READ_REGISTRY},/*9*/ + {sizeof(struct rwreg_param), + oid_rt_pro_write_rf_reg_hdl, + OID_RT_PRO_RF_WRITE_REGISTRY}, + {sizeof(struct rfintfs_parm), NULL, 0}, + {0, &mp_ioctl_xmit_packet_hdl, 0},/*12*/ + {sizeof(struct psmode_param), NULL, 0},/*13*/ + {sizeof(struct eeprom_rw_param), NULL, 0},/*14*/ + {sizeof(struct eeprom_rw_param), NULL, 0},/*15*/ + {sizeof(unsigned char), NULL, 0},/*16*/ + {sizeof(u32), NULL, 0},/*17*/ + {sizeof(u32), oid_rt_pro_set_continuous_tx_hdl, + OID_RT_PRO_SET_CONTINUOUS_TX},/*18*/ + {sizeof(u32), oid_rt_set_bandwidth_hdl, + OID_RT_SET_BANDWIDTH},/*19*/ + {sizeof(u32), oid_rt_set_rx_packet_type_hdl, + OID_RT_SET_RX_PACKET_TYPE},/*20*/ + {0, oid_rt_reset_phy_rx_packet_count_hdl, + OID_RT_RESET_PHY_RX_PACKET_COUNT},/*21*/ + {sizeof(u32), oid_rt_get_phy_rx_packet_received_hdl, + OID_RT_GET_PHY_RX_PACKET_RECEIVED},/*22*/ + {sizeof(u32), oid_rt_get_phy_rx_packet_crc32_error_hdl, + OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR},/*23*/ + {sizeof(unsigned char), oid_rt_set_power_down_hdl, + OID_RT_SET_POWER_DOWN},/*24*/ + {sizeof(u32), oid_rt_get_thermal_meter_hdl, + OID_RT_PRO_GET_THERMAL_METER},/*25*/ + {sizeof(u32), oid_rt_get_power_mode_hdl, + OID_RT_GET_POWER_MODE},/*26*/ + {sizeof(struct EFUSE_ACCESS_STRUCT), + oid_rt_pro_efuse_hdl, OID_RT_PRO_EFUSE},/*27*/ + {EFUSE_MAP_MAX_SIZE, oid_rt_pro_efuse_map_hdl, + OID_RT_PRO_EFUSE_MAP},/*28*/ + {sizeof(u32), oid_rt_get_efuse_max_size_hdl, + OID_RT_GET_EFUSE_MAX_SIZE},/*29*/ + {sizeof(u32), oid_rt_get_efuse_current_size_hdl, + OID_RT_GET_EFUSE_CURRENT_SIZE},/*30*/ + {sizeof(u32), oid_rt_pro_set_single_carrier_tx_hdl, + OID_RT_PRO_SET_SINGLE_CARRIER_TX},/*31*/ + {sizeof(u32), oid_rt_pro_set_carrier_suppression_tx_hdl, + OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX},/*32*/ + {sizeof(u32), oid_rt_pro_set_single_tone_tx_hdl, + OID_RT_PRO_SET_SINGLE_TONE_TX},/*33*/ + {sizeof(u32), oid_rt_pro_set_antenna_bb_hdl, + OID_RT_PRO_SET_ANTENNA_BB},/*34*/ +}; + +#else /* _RTL871X_MP_IOCTL_C_ */ +extern struct mp_ioctl_handler mp_ioctl_hdl[]; +#endif /* _RTL871X_MP_IOCTL_C_ */ + +#endif + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/kernel/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h new file mode 100644 index 000000000..8e2586231 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h @@ -0,0 +1,1025 @@ +/***************************************************************************** + * Copyright(c) 2008, RealTEK Technology Inc. All Right Reserved. + * + * Module: __INC_HAL8192SPHYREG_H + * + * + * Note: 1. Define PMAC/BB register map + * 2. Define RF register map + * 3. PMAC/BB register bit mask. + * 4. RF reg bit mask. + * 5. Other BB/RF relative definition. + * + * + * Export: Constants, macro, functions(API), global variables(None). + * + * Abbrev: + * + * History: + * Data Who Remark + * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. + * 2. Reorganize code architecture. + * 09/25/2008 MH 1. Add RL6052 register definition + * + *****************************************************************************/ +#ifndef __RTL871X_MP_PHY_REGDEF_H +#define __RTL871X_MP_PHY_REGDEF_H + + +/*--------------------------Define Parameters-------------------------------*/ + +/*============================================================ + * 8192S Regsiter offset definition + *============================================================ + * + * + * BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF + * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF + * 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 + * 3. RF register 0x00-2E + * 4. Bit Mask for BB/RF register + * 5. Other definition for BB/RF R/W + * + * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF + * 1. Page1(0x100) + */ +#define rPMAC_Reset 0x100 +#define rPMAC_TxStart 0x104 +#define rPMAC_TxLegacySIG 0x108 +#define rPMAC_TxHTSIG1 0x10c +#define rPMAC_TxHTSIG2 0x110 +#define rPMAC_PHYDebug 0x114 +#define rPMAC_TxPacketNum 0x118 +#define rPMAC_TxIdle 0x11c +#define rPMAC_TxMACHeader0 0x120 +#define rPMAC_TxMACHeader1 0x124 +#define rPMAC_TxMACHeader2 0x128 +#define rPMAC_TxMACHeader3 0x12c +#define rPMAC_TxMACHeader4 0x130 +#define rPMAC_TxMACHeader5 0x134 +#define rPMAC_TxDataType 0x138 +#define rPMAC_TxRandomSeed 0x13c +#define rPMAC_CCKPLCPPreamble 0x140 +#define rPMAC_CCKPLCPHeader 0x144 +#define rPMAC_CCKCRC16 0x148 +#define rPMAC_OFDMRxCRC32OK 0x170 +#define rPMAC_OFDMRxCRC32Er 0x174 +#define rPMAC_OFDMRxParityEr 0x178 +#define rPMAC_OFDMRxCRC8Er 0x17c +#define rPMAC_CCKCRxRC16Er 0x180 +#define rPMAC_CCKCRxRC32Er 0x184 +#define rPMAC_CCKCRxRC32OK 0x188 +#define rPMAC_TxStatus 0x18c + +/* + * 2. Page2(0x200) + * + * The following two definition are only used for USB interface. + *#define RF_BB_CMD_ADDR 0x02c0 // RF/BB read/write command address. + *#define RF_BB_CMD_DATA 0x02c4 // RF/BB read/write command data. + * + * + * 3. Page8(0x800) + */ +#define rFPGA0_RFMOD 0x800 /*RF mode & CCK TxSC RF + * BW Setting?? */ +#define rFPGA0_TxInfo 0x804 /* Status report?? */ +#define rFPGA0_PSDFunction 0x808 +#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ +#define rFPGA0_RFTiming1 0x810 /* Useless now */ +#define rFPGA0_RFTiming2 0x814 +#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ +#define rFPGA0_XA_HSSIParameter2 0x824 +#define rFPGA0_XB_HSSIParameter1 0x828 +#define rFPGA0_XB_HSSIParameter2 0x82c +#define rFPGA0_XC_HSSIParameter1 0x830 +#define rFPGA0_XC_HSSIParameter2 0x834 +#define rFPGA0_XD_HSSIParameter1 0x838 +#define rFPGA0_XD_HSSIParameter2 0x83c +#define rFPGA0_XA_LSSIParameter 0x840 +#define rFPGA0_XB_LSSIParameter 0x844 +#define rFPGA0_XC_LSSIParameter 0x848 +#define rFPGA0_XD_LSSIParameter 0x84c + +#define rFPGA0_RFWakeUpParameter 0x850 /* Useless now */ +#define rFPGA0_RFSleepUpParameter 0x854 + +#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ +#define rFPGA0_XCD_SwitchControl 0x85c + +#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ +#define rFPGA0_XB_RFInterfaceOE 0x864 +#define rFPGA0_XC_RFInterfaceOE 0x868 +#define rFPGA0_XD_RFInterfaceOE 0x86c +#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Ctrl */ +#define rFPGA0_XCD_RFInterfaceSW 0x874 + +#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ +#define rFPGA0_XCD_RFParameter 0x87c + +#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting + * RF-R/W protection + * for parameter4?? */ +#define rFPGA0_AnalogParameter2 0x884 +#define rFPGA0_AnalogParameter3 0x888 /* Useless now */ +#define rFPGA0_AnalogParameter4 0x88c + +#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */ +#define rFPGA0_XB_LSSIReadBack 0x8a4 +#define rFPGA0_XC_LSSIReadBack 0x8a8 +#define rFPGA0_XD_LSSIReadBack 0x8ac + +#define rFPGA0_PSDReport 0x8b4 /* Useless now */ +#define rFPGA0_XAB_RFInterfaceRB 0x8e0 /* Useless now */ +#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */ + +/* + * 4. Page9(0x900) + */ +#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC */ + +#define rFPGA1_TxBlock 0x904 /* Useless now */ +#define rFPGA1_DebugSelect 0x908 /* Useless now */ +#define rFPGA1_TxInfo 0x90c /* Useless now */ + +/* + * 5. PageA(0xA00) + * + * Set Control channel to upper or lower. + * These settings are required only for 40MHz */ +#define rCCK0_System 0xa00 + +#define rCCK0_AFESetting 0xa04 /* Disable init gain now */ +#define rCCK0_CCA 0xa08 /* Disable init gain now */ + +#define rCCK0_RxAGC1 0xa0c +/* AGC default value, saturation level + * Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. + * Not the same as 90 series */ +#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */ + +#define rCCK0_RxHP 0xa14 + +#define rCCK0_DSPParameter1 0xa18 /* Timing recovery & Channel + * estimation threshold */ +#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ + +#define rCCK0_TxFilter1 0xa20 +#define rCCK0_TxFilter2 0xa24 +#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ +#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f + * channel report */ +#define rCCK0_TRSSIReport 0xa50 +#define rCCK0_RxReport 0xa54 /* 0xa57 */ +#define rCCK0_FACounterLower 0xa5c /* 0xa5b */ +#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */ + +/* + * 6. PageC(0xC00) + */ +#define rOFDM0_LSTF 0xc00 +#define rOFDM0_TRxPathEnable 0xc04 +#define rOFDM0_TRMuxPar 0xc08 +#define rOFDM0_TRSWIsolation 0xc0c + +/*RxIQ DC offset, Rx digital filter, DC notch filter */ +#define rOFDM0_XARxAFE 0xc10 +#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imbalance matrix */ +#define rOFDM0_XBRxAFE 0xc18 +#define rOFDM0_XBRxIQImbalance 0xc1c +#define rOFDM0_XCRxAFE 0xc20 +#define rOFDM0_XCRxIQImbalance 0xc24 +#define rOFDM0_XDRxAFE 0xc28 +#define rOFDM0_XDRxIQImbalance 0xc2c + +#define rOFDM0_RxDetector1 0xc30 /* PD,BW & SBD DM tune + * init gain */ +#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ +#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ +#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & + * Short-GI */ + +#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ +#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ +#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ +#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ + +#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ +#define rOFDM0_XAAGCCore2 0xc54 +#define rOFDM0_XBAGCCore1 0xc58 +#define rOFDM0_XBAGCCore2 0xc5c +#define rOFDM0_XCAGCCore1 0xc60 +#define rOFDM0_XCAGCCore2 0xc64 +#define rOFDM0_XDAGCCore1 0xc68 +#define rOFDM0_XDAGCCore2 0xc6c +#define rOFDM0_AGCParameter1 0xc70 +#define rOFDM0_AGCParameter2 0xc74 +#define rOFDM0_AGCRSSITable 0xc78 +#define rOFDM0_HTSTFAGC 0xc7c + +#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */ +#define rOFDM0_XATxAFE 0xc84 +#define rOFDM0_XBTxIQImbalance 0xc88 +#define rOFDM0_XBTxAFE 0xc8c +#define rOFDM0_XCTxIQImbalance 0xc90 +#define rOFDM0_XCTxAFE 0xc94 +#define rOFDM0_XDTxIQImbalance 0xc98 +#define rOFDM0_XDTxAFE 0xc9c + +#define rOFDM0_RxHPParameter 0xce0 +#define rOFDM0_TxPseudoNoiseWgt 0xce4 +#define rOFDM0_FrameSync 0xcf0 +#define rOFDM0_DFSReport 0xcf4 +#define rOFDM0_TxCoeff1 0xca4 +#define rOFDM0_TxCoeff2 0xca8 +#define rOFDM0_TxCoeff3 0xcac +#define rOFDM0_TxCoeff4 0xcb0 +#define rOFDM0_TxCoeff5 0xcb4 +#define rOFDM0_TxCoeff6 0xcb8 + +/* + * 7. PageD(0xD00) + */ +#define rOFDM1_LSTF 0xd00 +#define rOFDM1_TRxPathEnable 0xd04 + +#define rOFDM1_CFO 0xd08 /* No setting now */ +#define rOFDM1_CSI1 0xd10 +#define rOFDM1_SBD 0xd14 +#define rOFDM1_CSI2 0xd18 +#define rOFDM1_CFOTracking 0xd2c +#define rOFDM1_TRxMesaure1 0xd34 +#define rOFDM1_IntfDet 0xd3c +#define rOFDM1_PseudoNoiseStateAB 0xd50 +#define rOFDM1_PseudoNoiseStateCD 0xd54 +#define rOFDM1_RxPseudoNoiseWgt 0xd58 + +#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */ +#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */ +#define rOFDM_PHYCounter3 0xda8 /* MCS not support */ +#define rOFDM_ShortCFOAB 0xdac /* No setting now */ +#define rOFDM_ShortCFOCD 0xdb0 +#define rOFDM_LongCFOAB 0xdb4 +#define rOFDM_LongCFOCD 0xdb8 +#define rOFDM_TailCFOAB 0xdbc +#define rOFDM_TailCFOCD 0xdc0 +#define rOFDM_PWMeasure1 0xdc4 +#define rOFDM_PWMeasure2 0xdc8 +#define rOFDM_BWReport 0xdcc +#define rOFDM_AGCReport 0xdd0 +#define rOFDM_RxSNR 0xdd4 +#define rOFDM_RxEVMCSI 0xdd8 +#define rOFDM_SIGReport 0xddc + +/* + * 8. PageE(0xE00) + */ +#define rTxAGC_Rate18_06 0xe00 +#define rTxAGC_Rate54_24 0xe04 +#define rTxAGC_CCK_Mcs32 0xe08 +#define rTxAGC_Mcs03_Mcs00 0xe10 +#define rTxAGC_Mcs07_Mcs04 0xe14 +#define rTxAGC_Mcs11_Mcs08 0xe18 +#define rTxAGC_Mcs15_Mcs12 0xe1c + +/* Analog- control in RX_WAIT_CCA : REG: EE0 + * [Analog- Power & Control Register] */ +#define rRx_Wait_CCCA 0xe70 +#define rAnapar_Ctrl_BB 0xee0 + +/* + * 7. RF Register 0x00-0x2E (RF 8256) + * RF-0222D 0x00-3F + * + * Zebra1 + */ +#define rZebra1_HSSIEnable 0x0 /* Useless now */ +#define rZebra1_TRxEnable1 0x1 +#define rZebra1_TRxEnable2 0x2 +#define rZebra1_AGC 0x4 +#define rZebra1_ChargePump 0x5 +#define rZebra1_Channel 0x7 /* RF channel switch */ +#define rZebra1_TxGain 0x8 /* Useless now */ +#define rZebra1_TxLPF 0x9 +#define rZebra1_RxLPF 0xb +#define rZebra1_RxHPFCorner 0xc + +/* Zebra4 */ +#define rGlobalCtrl 0 /* Useless now */ +#define rRTL8256_TxLPF 19 +#define rRTL8256_RxLPF 11 + +/* RTL8258 */ +#define rRTL8258_TxLPF 0x11 /* Useless now */ +#define rRTL8258_RxLPF 0x13 +#define rRTL8258_RSSILPF 0xa + +/* RL6052 Register definition */ +#define RF_AC 0x00 +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_POW_TRSW 0x05 + +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 + +#define RF_TXM_IDAC 0x08 +#define RF_BS_IQGEN 0x0F + +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 + +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define rRfChannel 0x18 /* RF channel and BW switch */ +#define RF_CHNLBW 0x18 /* RF channel and BW switch */ +#define RF_TOP 0x19 +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D + +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F + +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 + +#define RF_TX_BB1 0x23 +#define RF_T_METER 0x24 + +#define RF_SYN_G1 0x25 /* RF TX Power control */ +#define RF_SYN_G2 0x26 /* RF TX Power control */ +#define RF_SYN_G3 0x27 /* RF TX Power control */ +#define RF_SYN_G4 0x28 /* RF TX Power control */ +#define RF_SYN_G5 0x29 /* RF TX Power control */ +#define RF_SYN_G6 0x2A /* RF TX Power control */ +#define RF_SYN_G7 0x2B /* RF TX Power control */ +#define RF_SYN_G8 0x2C /* RF TX Power control */ + +#define RF_RCK_OS 0x30 /* RF TX PA control */ + +#define RF_TXPA_G1 0x31 /* RF TX PA control */ +#define RF_TXPA_G2 0x32 /* RF TX PA control */ +#define RF_TXPA_G3 0x33 /* RF TX PA control */ + +/* + * Bit Mask + * + * 1. Page1(0x100) */ +#define bBBResetB 0x100 /* Useless now? */ +#define bGlobalResetB 0x200 +#define bOFDMTxStart 0x4 +#define bCCKTxStart 0x8 +#define bCRC32Debug 0x100 +#define bPMACLoopback 0x10 +#define bTxLSIG 0xffffff +#define bOFDMTxRate 0xf +#define bOFDMTxReserved 0x10 +#define bOFDMTxLength 0x1ffe0 +#define bOFDMTxParity 0x20000 +#define bTxHTSIG1 0xffffff +#define bTxHTMCSRate 0x7f +#define bTxHTBW 0x80 +#define bTxHTLength 0xffff00 +#define bTxHTSIG2 0xffffff +#define bTxHTSmoothing 0x1 +#define bTxHTSounding 0x2 +#define bTxHTReserved 0x4 +#define bTxHTAggreation 0x8 +#define bTxHTSTBC 0x30 +#define bTxHTAdvanceCoding 0x40 +#define bTxHTShortGI 0x80 +#define bTxHTNumberHT_LTF 0x300 +#define bTxHTCRC8 0x3fc00 +#define bCounterReset 0x10000 +#define bNumOfOFDMTx 0xffff +#define bNumOfCCKTx 0xffff0000 +#define bTxIdleInterval 0xffff +#define bOFDMService 0xffff0000 +#define bTxMACHeader 0xffffffff +#define bTxDataInit 0xff +#define bTxHTMode 0x100 +#define bTxDataType 0x30000 +#define bTxRandomSeed 0xffffffff +#define bCCKTxPreamble 0x1 +#define bCCKTxSFD 0xffff0000 +#define bCCKTxSIG 0xff +#define bCCKTxService 0xff00 +#define bCCKLengthExt 0x8000 +#define bCCKTxLength 0xffff0000 +#define bCCKTxCRC16 0xffff +#define bCCKTxStatus 0x1 +#define bOFDMTxStatus 0x2 +#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && \ + (_Offset <= 0xfff)) + +/* 2. Page8(0x800) */ +#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ +#define bJapanMode 0x2 +#define bCCKTxSC 0x30 +#define bCCKEn 0x1000000 +#define bOFDMEn 0x2000000 + +#define bOFDMRxADCPhase 0x10000 /* Useless now */ +#define bOFDMTxDACPhase 0x40000 +#define bXATxAGC 0x3f +#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ +#define bXCTxAGC 0xf000 +#define bXDTxAGC 0xf0000 + +#define bPAStart 0xf0000000 /* Useless now */ +#define bTRStart 0x00f00000 +#define bRFStart 0x0000f000 +#define bBBStart 0x000000f0 +#define bBBCCKStart 0x0000000f +#define bPAEnd 0xf /* Reg0x814 */ +#define bTREnd 0x0f000000 +#define bRFEnd 0x000f0000 +#define bCCAMask 0x000000f0 /* T2R */ +#define bR2RCCAMask 0x00000f00 +#define bHSSI_R2TDelay 0xf8000000 +#define bHSSI_T2RDelay 0xf80000 +#define bContTxHSSI 0x400 /* change gain at continue Tx */ +#define bIGFromCCK 0x200 +#define bAGCAddress 0x3f +#define bRxHPTx 0x7000 +#define bRxHPT2R 0x38000 +#define bRxHPCCKIni 0xc0000 +#define bAGCTxCode 0xc00000 +#define bAGCRxCode 0x300000 +#define b3WireDataLength 0x800 /* Reg 0x820~84f rFPGA0_XA_HSSIParm1 */ +#define b3WireAddressLength 0x400 +#define b3WireRFPowerDown 0x1 /* Useless now */ +#define b5GPAPEPolarity 0x40000000 +#define b2GPAPEPolarity 0x80000000 +#define bRFSW_TxDefaultAnt 0x3 +#define bRFSW_TxOptionAnt 0x30 +#define bRFSW_RxDefaultAnt 0x300 +#define bRFSW_RxOptionAnt 0x3000 +#define bRFSI_3WireData 0x1 +#define bRFSI_3WireClock 0x2 +#define bRFSI_3WireLoad 0x4 +#define bRFSI_3WireRW 0x8 +#define bRFSI_3Wire 0xf +#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */ +#define bRFSI_TRSW 0x20 /* Useless now */ +#define bRFSI_TRSWB 0x40 +#define bRFSI_ANTSW 0x100 +#define bRFSI_ANTSWB 0x200 +#define bRFSI_PAPE 0x400 +#define bRFSI_PAPE5G 0x800 +#define bBandSelect 0x1 +#define bHTSIG2_GI 0x80 +#define bHTSIG2_Smoothing 0x01 +#define bHTSIG2_Sounding 0x02 +#define bHTSIG2_Aggreaton 0x08 +#define bHTSIG2_STBC 0x30 +#define bHTSIG2_AdvCoding 0x40 +#define bHTSIG2_NumOfHTLTF 0x300 +#define bHTSIG2_CRC8 0x3fc +#define bHTSIG1_MCS 0x7f +#define bHTSIG1_BandWidth 0x80 +#define bHTSIG1_HTLength 0xffff +#define bLSIG_Rate 0xf +#define bLSIG_Reserved 0x10 +#define bLSIG_Length 0x1fffe +#define bLSIG_Parity 0x20 +#define bCCKRxPhase 0x4 +#define bLSSIReadAddress 0x7f800000 /* T65 RF */ +#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */ +#define bLSSIReadBackData 0xfffff /* T65 RF */ +#define bLSSIReadOKFlag 0x1000 /* Useless now */ +#define bCCKSampleRate 0x8 /*0: 44MHz, 1:88MHz*/ +#define bRegulator0Standby 0x1 +#define bRegulatorPLLStandby 0x2 +#define bRegulator1Standby 0x4 +#define bPLLPowerUp 0x8 +#define bDPLLPowerUp 0x10 +#define bDA10PowerUp 0x20 +#define bAD7PowerUp 0x200 +#define bDA6PowerUp 0x2000 +#define bXtalPowerUp 0x4000 +#define b40MDClkPowerUP 0x8000 +#define bDA6DebugMode 0x20000 +#define bDA6Swing 0x380000 + +/* Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */ +#define bADClkPhase 0x4000000 + +#define b80MClkDelay 0x18000000 /* Useless */ +#define bAFEWatchDogEnable 0x20000000 + +/* Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */ +#define bXtalCap01 0xc0000000 +#define bXtalCap23 0x3 +#define bXtalCap92x 0x0f000000 +#define bXtalCap 0x0f000000 +#define bIntDifClkEnable 0x400 /* Useless */ +#define bExtSigClkEnable 0x800 +#define bBandgapMbiasPowerUp 0x10000 +#define bAD11SHGain 0xc0000 +#define bAD11InputRange 0x700000 +#define bAD11OPCurrent 0x3800000 +#define bIPathLoopback 0x4000000 +#define bQPathLoopback 0x8000000 +#define bAFELoopback 0x10000000 +#define bDA10Swing 0x7e0 +#define bDA10Reverse 0x800 +#define bDAClkSource 0x1000 +#define bAD7InputRange 0x6000 +#define bAD7Gain 0x38000 +#define bAD7OutputCMMode 0x40000 +#define bAD7InputCMMode 0x380000 +#define bAD7Current 0xc00000 +#define bRegulatorAdjust 0x7000000 +#define bAD11PowerUpAtTx 0x1 +#define bDA10PSAtTx 0x10 +#define bAD11PowerUpAtRx 0x100 +#define bDA10PSAtRx 0x1000 +#define bCCKRxAGCFormat 0x200 +#define bPSDFFTSamplepPoint 0xc000 +#define bPSDAverageNum 0x3000 +#define bIQPathControl 0xc00 +#define bPSDFreq 0x3ff +#define bPSDAntennaPath 0x30 +#define bPSDIQSwitch 0x40 +#define bPSDRxTrigger 0x400000 +#define bPSDTxTrigger 0x80000000 +#define bPSDSineToneScale 0x7f000000 +#define bPSDReport 0xffff + +/* 3. Page9(0x900) */ +#define bOFDMTxSC 0x30000000 /* Useless */ +#define bCCKTxOn 0x1 +#define bOFDMTxOn 0x2 +#define bDebugPage 0xfff /* reset debug page and HWord, LWord */ +#define bDebugItem 0xff /* reset debug page and LWord */ +#define bAntL 0x10 +#define bAntNonHT 0x100 +#define bAntHT1 0x1000 +#define bAntHT2 0x10000 +#define bAntHT1S1 0x100000 +#define bAntNonHTS1 0x1000000 + +/* 4. PageA(0xA00) */ +#define bCCKBBMode 0x3 /* Useless */ +#define bCCKTxPowerSaving 0x80 +#define bCCKRxPowerSaving 0x40 + +#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch*/ +#define bCCKScramble 0x8 /* Useless */ +#define bCCKAntDiversity 0x8000 +#define bCCKCarrierRecovery 0x4000 +#define bCCKTxRate 0x3000 +#define bCCKDCCancel 0x0800 +#define bCCKISICancel 0x0400 +#define bCCKMatchFilter 0x0200 +#define bCCKEqualizer 0x0100 +#define bCCKPreambleDetect 0x800000 +#define bCCKFastFalseCCA 0x400000 +#define bCCKChEstStart 0x300000 +#define bCCKCCACount 0x080000 +#define bCCKcs_lim 0x070000 +#define bCCKBistMode 0x80000000 +#define bCCKCCAMask 0x40000000 +#define bCCKTxDACPhase 0x4 +#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ +#define bCCKr_cp_mode0 0x0100 +#define bCCKTxDCOffset 0xf0 +#define bCCKRxDCOffset 0xf +#define bCCKCCAMode 0xc000 +#define bCCKFalseCS_lim 0x3f00 +#define bCCKCS_ratio 0xc00000 +#define bCCKCorgBit_sel 0x300000 +#define bCCKPD_lim 0x0f0000 +#define bCCKNewCCA 0x80000000 +#define bCCKRxHPofIG 0x8000 +#define bCCKRxIG 0x7f00 +#define bCCKLNAPolarity 0x800000 +#define bCCKRx1stGain 0x7f0000 +#define bCCKRFExtend 0x20000000 /* CCK Rx inital gain polarity */ +#define bCCKRxAGCSatLevel 0x1f000000 +#define bCCKRxAGCSatCount 0xe0 +#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ +#define bCCKFixedRxAGC 0x8000 +#define bCCKAntennaPolarity 0x2000 +#define bCCKTxFilterType 0x0c00 +#define bCCKRxAGCReportType 0x0300 +#define bCCKRxDAGCEn 0x80000000 +#define bCCKRxDAGCPeriod 0x20000000 +#define bCCKRxDAGCSatLevel 0x1f000000 +#define bCCKTimingRecovery 0x800000 +#define bCCKTxC0 0x3f0000 +#define bCCKTxC1 0x3f000000 +#define bCCKTxC2 0x3f +#define bCCKTxC3 0x3f00 +#define bCCKTxC4 0x3f0000 +#define bCCKTxC5 0x3f000000 +#define bCCKTxC6 0x3f +#define bCCKTxC7 0x3f00 +#define bCCKDebugPort 0xff0000 +#define bCCKDACDebug 0x0f000000 +#define bCCKFalseAlarmEnable 0x8000 +#define bCCKFalseAlarmRead 0x4000 +#define bCCKTRSSI 0x7f +#define bCCKRxAGCReport 0xfe +#define bCCKRxReport_AntSel 0x80000000 +#define bCCKRxReport_MFOff 0x40000000 +#define bCCKRxRxReport_SQLoss 0x20000000 +#define bCCKRxReport_Pktloss 0x10000000 +#define bCCKRxReport_Lockedbit 0x08000000 +#define bCCKRxReport_RateError 0x04000000 +#define bCCKRxReport_RxRate 0x03000000 +#define bCCKRxFACounterLower 0xff +#define bCCKRxFACounterUpper 0xff000000 +#define bCCKRxHPAGCStart 0xe000 +#define bCCKRxHPAGCFinal 0x1c00 +#define bCCKRxFalseAlarmEnable 0x8000 +#define bCCKFACounterFreeze 0x4000 +#define bCCKTxPathSel 0x10000000 +#define bCCKDefaultRxPath 0xc000000 +#define bCCKOptionRxPath 0x3000000 + +/* 5. PageC(0xC00) */ +#define bNumOfSTF 0x3 /* Useless */ +#define bShift_L 0xc0 +#define bGI_TH 0xc +#define bRxPathA 0x1 +#define bRxPathB 0x2 +#define bRxPathC 0x4 +#define bRxPathD 0x8 +#define bTxPathA 0x1 +#define bTxPathB 0x2 +#define bTxPathC 0x4 +#define bTxPathD 0x8 +#define bTRSSIFreq 0x200 +#define bADCBackoff 0x3000 +#define bDFIRBackoff 0xc000 +#define bTRSSILatchPhase 0x10000 +#define bRxIDCOffset 0xff +#define bRxQDCOffset 0xff00 +#define bRxDFIRMode 0x1800000 +#define bRxDCNFType 0xe000000 +#define bRXIQImb_A 0x3ff +#define bRXIQImb_B 0xfc00 +#define bRXIQImb_C 0x3f0000 +#define bRXIQImb_D 0xffc00000 +#define bDC_dc_Notch 0x60000 +#define bRxNBINotch 0x1f000000 +#define bPD_TH 0xf +#define bPD_TH_Opt2 0xc000 +#define bPWED_TH 0x700 +#define bIfMF_Win_L 0x800 +#define bPD_Option 0x1000 +#define bMF_Win_L 0xe000 +#define bBW_Search_L 0x30000 +#define bwin_enh_L 0xc0000 +#define bBW_TH 0x700000 +#define bED_TH2 0x3800000 +#define bBW_option 0x4000000 +#define bRatio_TH 0x18000000 +#define bWindow_L 0xe0000000 +#define bSBD_Option 0x1 +#define bFrame_TH 0x1c +#define bFS_Option 0x60 +#define bDC_Slope_check 0x80 +#define bFGuard_Counter_DC_L 0xe00 +#define bFrame_Weight_Short 0x7000 +#define bSub_Tune 0xe00000 +#define bFrame_DC_Length 0xe000000 +#define bSBD_start_offset 0x30000000 +#define bFrame_TH_2 0x7 +#define bFrame_GI2_TH 0x38 +#define bGI2_Sync_en 0x40 +#define bSarch_Short_Early 0x300 +#define bSarch_Short_Late 0xc00 +#define bSarch_GI2_Late 0x70000 +#define bCFOAntSum 0x1 +#define bCFOAcc 0x2 +#define bCFOStartOffset 0xc +#define bCFOLookBack 0x70 +#define bCFOSumWeight 0x80 +#define bDAGCEnable 0x10000 +#define bTXIQImb_A 0x3ff +#define bTXIQImb_B 0xfc00 +#define bTXIQImb_C 0x3f0000 +#define bTXIQImb_D 0xffc00000 +#define bTxIDCOffset 0xff +#define bTxQDCOffset 0xff00 +#define bTxDFIRMode 0x10000 +#define bTxPesudoNoiseOn 0x4000000 +#define bTxPesudoNoise_A 0xff +#define bTxPesudoNoise_B 0xff00 +#define bTxPesudoNoise_C 0xff0000 +#define bTxPesudoNoise_D 0xff000000 +#define bCCADropOption 0x20000 +#define bCCADropThres 0xfff00000 +#define bEDCCA_H 0xf +#define bEDCCA_L 0xf0 +#define bLambda_ED 0x300 +#define bRxInitialGain 0x7f +#define bRxAntDivEn 0x80 +#define bRxAGCAddressForLNA 0x7f00 +#define bRxHighPowerFlow 0x8000 +#define bRxAGCFreezeThres 0xc0000 +#define bRxFreezeStep_AGC1 0x300000 +#define bRxFreezeStep_AGC2 0xc00000 +#define bRxFreezeStep_AGC3 0x3000000 +#define bRxFreezeStep_AGC0 0xc000000 +#define bRxRssi_Cmp_En 0x10000000 +#define bRxQuickAGCEn 0x20000000 +#define bRxAGCFreezeThresMode 0x40000000 +#define bRxOverFlowCheckType 0x80000000 +#define bRxAGCShift 0x7f +#define bTRSW_Tri_Only 0x80 +#define bPowerThres 0x300 +#define bRxAGCEn 0x1 +#define bRxAGCTogetherEn 0x2 +#define bRxAGCMin 0x4 +#define bRxHP_Ini 0x7 +#define bRxHP_TRLNA 0x70 +#define bRxHP_RSSI 0x700 +#define bRxHP_BBP1 0x7000 +#define bRxHP_BBP2 0x70000 +#define bRxHP_BBP3 0x700000 +#define bRSSI_H 0x7f0000 /* the threshold for high power */ +#define bRSSI_Gen 0x7f000000 /* the threshold for ant divers */ +#define bRxSettle_TRSW 0x7 +#define bRxSettle_LNA 0x38 +#define bRxSettle_RSSI 0x1c0 +#define bRxSettle_BBP 0xe00 +#define bRxSettle_RxHP 0x7000 +#define bRxSettle_AntSW_RSSI 0x38000 +#define bRxSettle_AntSW 0xc0000 +#define bRxProcessTime_DAGC 0x300000 +#define bRxSettle_HSSI 0x400000 +#define bRxProcessTime_BBPPW 0x800000 +#define bRxAntennaPowerShift 0x3000000 +#define bRSSITableSelect 0xc000000 +#define bRxHP_Final 0x7000000 +#define bRxHTSettle_BBP 0x7 +#define bRxHTSettle_HSSI 0x8 +#define bRxHTSettle_RxHP 0x70 +#define bRxHTSettle_BBPPW 0x80 +#define bRxHTSettle_Idle 0x300 +#define bRxHTSettle_Reserved 0x1c00 +#define bRxHTRxHPEn 0x8000 +#define bRxHTAGCFreezeThres 0x30000 +#define bRxHTAGCTogetherEn 0x40000 +#define bRxHTAGCMin 0x80000 +#define bRxHTAGCEn 0x100000 +#define bRxHTDAGCEn 0x200000 +#define bRxHTRxHP_BBP 0x1c00000 +#define bRxHTRxHP_Final 0xe0000000 +#define bRxPWRatioTH 0x3 +#define bRxPWRatioEn 0x4 +#define bRxMFHold 0x3800 +#define bRxPD_Delay_TH1 0x38 +#define bRxPD_Delay_TH2 0x1c0 +#define bRxPD_DC_COUNT_MAX 0x600 +#define bRxPD_Delay_TH 0x8000 +#define bRxProcess_Delay 0xf0000 +#define bRxSearchrange_GI2_Early 0x700000 +#define bRxFrame_Guard_Counter_L 0x3800000 +#define bRxSGI_Guard_L 0xc000000 +#define bRxSGI_Search_L 0x30000000 +#define bRxSGI_TH 0xc0000000 +#define bDFSCnt0 0xff +#define bDFSCnt1 0xff00 +#define bDFSFlag 0xf0000 +#define bMFWeightSum 0x300000 +#define bMinIdxTH 0x7f000000 +#define bDAFormat 0x40000 +#define bTxChEmuEnable 0x01000000 +#define bTRSWIsolation_A 0x7f +#define bTRSWIsolation_B 0x7f00 +#define bTRSWIsolation_C 0x7f0000 +#define bTRSWIsolation_D 0x7f000000 +#define bExtLNAGain 0x7c00 + +/* 6. PageE(0xE00) */ +#define bSTBCEn 0x4 /* Useless */ +#define bAntennaMapping 0x10 +#define bNss 0x20 +#define bCFOAntSumD 0x200 +#define bPHYCounterReset 0x8000000 +#define bCFOReportGet 0x4000000 +#define bOFDMContinueTx 0x10000000 +#define bOFDMSingleCarrier 0x20000000 +#define bOFDMSingleTone 0x40000000 +#define bHTDetect 0x100 +#define bCFOEn 0x10000 +#define bCFOValue 0xfff00000 +#define bSigTone_Re 0x3f +#define bSigTone_Im 0x7f00 +#define bCounter_CCA 0xffff +#define bCounter_ParityFail 0xffff0000 +#define bCounter_RateIllegal 0xffff +#define bCounter_CRC8Fail 0xffff0000 +#define bCounter_MCSNoSupport 0xffff +#define bCounter_FastSync 0xffff +#define bShortCFO 0xfff +#define bShortCFOTLength 12 /* total */ +#define bShortCFOFLength 11 /* fraction */ +#define bLongCFO 0x7ff +#define bLongCFOTLength 11 +#define bLongCFOFLength 11 +#define bTailCFO 0x1fff +#define bTailCFOTLength 13 +#define bTailCFOFLength 12 +#define bmax_en_pwdB 0xffff +#define bCC_power_dB 0xffff0000 +#define bnoise_pwdB 0xffff +#define bPowerMeasTLength 10 +#define bPowerMeasFLength 3 +#define bRx_HT_BW 0x1 +#define bRxSC 0x6 +#define bRx_HT 0x8 +#define bNB_intf_det_on 0x1 +#define bIntf_win_len_cfg 0x30 +#define bNB_Intf_TH_cfg 0x1c0 +#define bRFGain 0x3f +#define bTableSel 0x40 +#define bTRSW 0x80 +#define bRxSNR_A 0xff +#define bRxSNR_B 0xff00 +#define bRxSNR_C 0xff0000 +#define bRxSNR_D 0xff000000 +#define bSNREVMTLength 8 +#define bSNREVMFLength 1 +#define bCSI1st 0xff +#define bCSI2nd 0xff00 +#define bRxEVM1st 0xff0000 +#define bRxEVM2nd 0xff000000 +#define bSIGEVM 0xff +#define bPWDB 0xff00 +#define bSGIEN 0x10000 + +#define bSFactorQAM1 0xf /* Useless */ +#define bSFactorQAM2 0xf0 +#define bSFactorQAM3 0xf00 +#define bSFactorQAM4 0xf000 +#define bSFactorQAM5 0xf0000 +#define bSFactorQAM6 0xf0000 +#define bSFactorQAM7 0xf00000 +#define bSFactorQAM8 0xf000000 +#define bSFactorQAM9 0xf0000000 +#define bCSIScheme 0x100000 + +#define bNoiseLvlTopSet 0x3 /* Useless */ +#define bChSmooth 0x4 +#define bChSmoothCfg1 0x38 +#define bChSmoothCfg2 0x1c0 +#define bChSmoothCfg3 0xe00 +#define bChSmoothCfg4 0x7000 +#define bMRCMode 0x800000 +#define bTHEVMCfg 0x7000000 + +#define bLoopFitType 0x1 /* Useless */ +#define bUpdCFO 0x40 +#define bUpdCFOOffData 0x80 +#define bAdvUpdCFO 0x100 +#define bAdvTimeCtrl 0x800 +#define bUpdClko 0x1000 +#define bFC 0x6000 +#define bTrackingMode 0x8000 +#define bPhCmpEnable 0x10000 +#define bUpdClkoLTF 0x20000 +#define bComChCFO 0x40000 +#define bCSIEstiMode 0x80000 +#define bAdvUpdEqz 0x100000 +#define bUChCfg 0x7000000 +#define bUpdEqz 0x8000000 + +#define bTxAGCRate18_06 0x7f7f7f7f /* Useless */ +#define bTxAGCRate54_24 0x7f7f7f7f +#define bTxAGCRateMCS32 0x7f +#define bTxAGCRateCCK 0x7f00 +#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f +#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f +#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f +#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f + +/* Rx Pseduo noise */ +#define bRxPesudoNoiseOn 0x20000000 /* Useless */ +#define bRxPesudoNoise_A 0xff +#define bRxPesudoNoise_B 0xff00 +#define bRxPesudoNoise_C 0xff0000 +#define bRxPesudoNoise_D 0xff000000 +#define bPesudoNoiseState_A 0xffff +#define bPesudoNoiseState_B 0xffff0000 +#define bPesudoNoiseState_C 0xffff +#define bPesudoNoiseState_D 0xffff0000 + +/* 7. RF Register + * Zebra1 */ +#define bZebra1_HSSIEnable 0x8 /* Useless */ +#define bZebra1_TRxControl 0xc00 +#define bZebra1_TRxGainSetting 0x07f +#define bZebra1_RxCorner 0xc00 +#define bZebra1_TxChargePump 0x38 +#define bZebra1_RxChargePump 0x7 +#define bZebra1_ChannelNum 0xf80 +#define bZebra1_TxLPFBW 0x400 +#define bZebra1_RxLPFBW 0x600 + +/*Zebra4 */ +#define bRTL8256RegModeCtrl1 0x100 /* Useless */ +#define bRTL8256RegModeCtrl0 0x40 +#define bRTL8256_TxLPFBW 0x18 +#define bRTL8256_RxLPFBW 0x600 + +/* RTL8258 */ +#define bRTL8258_TxLPFBW 0xc /* Useless */ +#define bRTL8258_RxLPFBW 0xc00 +#define bRTL8258_RSSILPFBW 0xc0 + +/* + * Other Definition + */ + +/* byte endable for sb_write */ +#define bByte0 0x1 /* Useless */ +#define bByte1 0x2 +#define bByte2 0x4 +#define bByte3 0x8 +#define bWord0 0x3 +#define bWord1 0xc +#define bDWord 0xf + +/* for PutRegsetting & GetRegSetting BitMask */ +#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +/* for PutRFRegsetting & GetRFRegSetting BitMask */ +#define bRFRegOffsetMask 0xfffff +#define bEnable 0x1 /* Useless */ +#define bDisable 0x0 + +#define LeftAntenna 0x0 /* Useless */ +#define RightAntenna 0x1 + +#define tCheckTxStatus 500 /* 500ms Useless */ +#define tUpdateRxCounter 100 /* 100ms */ + +#define rateCCK 0 /* Useless */ +#define rateOFDM 1 +#define rateHT 2 + +/* define Register-End */ +#define bPMAC_End 0x1ff /* Useless */ +#define bFPGAPHY0_End 0x8ff +#define bFPGAPHY1_End 0x9ff +#define bCCKPHY0_End 0xaff +#define bOFDMPHY0_End 0xcff +#define bOFDMPHY1_End 0xdff + +#define bPMACControl 0x0 /* Useless */ +#define bWMACControl 0x1 +#define bWNICControl 0x2 + +#define ANTENNA_A 0x1 /* Useless */ +#define ANTENNA_B 0x2 +#define ANTENNA_AB 0x3 /* ANTENNA_A |ANTENNA_B */ + +#define ANTENNA_C 0x4 +#define ANTENNA_D 0x8 + + +/* accept all physical address */ +#define RCR_AAP BIT(0) +#define RCR_APM BIT(1) /* accept physical match */ +#define RCR_AM BIT(2) /* accept multicast */ +#define RCR_AB BIT(3) /* accept broadcast */ +#define RCR_ACRC32 BIT(5) /* accept error packet */ +#define RCR_9356SEL BIT(6) +#define RCR_AICV BIT(12) /* Accept ICV error packet */ +#define RCR_RXFTH0 (BIT(13)|BIT(14)|BIT(15)) /* Rx FIFO threshold */ +#define RCR_ADF BIT(18) /* Accept Data(frame type) frame */ +#define RCR_ACF BIT(19) /* Accept control frame */ +#define RCR_AMF BIT(20) /* Accept management frame */ +#define RCR_ADD3 BIT(21) +#define RCR_APWRMGT BIT(22) /* Accept power management packet */ +#define RCR_CBSSID BIT(23) /* Accept BSSID match packet */ +#define RCR_ENMARP BIT(28) /* enable mac auto reset phy */ +#define RCR_EnCS1 BIT(29) /* enable carrier sense method 1 */ +#define RCR_EnCS2 BIT(30) /* enable carrier sense method 2 */ +/* Rx Early mode is performed for packet size greater than 1536 */ +#define RCR_OnlyErlPkt BIT(31) + +/*--------------------------Define Parameters-------------------------------*/ + + +#endif /*__INC_HAL8192SPHYREG_H */ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_pwrctrl.c b/kernel/drivers/staging/rtl8712/rtl871x_pwrctrl.c new file mode 100644 index 000000000..9bc04f474 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_pwrctrl.c @@ -0,0 +1,245 @@ +/****************************************************************************** + * rtl871x_pwrctrl.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_PWRCTRL_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "osdep_intf.h" + +#define RTL8712_SDIO_LOCAL_BASE 0X10100000 +#define SDIO_HCPWM (RTL8712_SDIO_LOCAL_BASE + 0x0081) + +void r8712_set_rpwm(struct _adapter *padapter, u8 val8) +{ + u8 rpwm; + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + + if (pwrpriv->rpwm == val8) { + if (pwrpriv->rpwm_retry == 0) + return; + } + if ((padapter->bDriverStopped == true) || + (padapter->bSurpriseRemoved == true)) + return; + rpwm = val8 | pwrpriv->tog; + switch (val8) { + case PS_STATE_S1: + pwrpriv->cpwm = val8; + break; + case PS_STATE_S2:/* only for USB normal powersave mode use, + * temp mark some code. */ + case PS_STATE_S3: + case PS_STATE_S4: + pwrpriv->cpwm = val8; + break; + default: + break; + } + pwrpriv->rpwm_retry = 0; + pwrpriv->rpwm = val8; + r8712_write8(padapter, 0x1025FE58, rpwm); + pwrpriv->tog += 0x80; +} + +void r8712_set_ps_mode(struct _adapter *padapter, uint ps_mode, uint smart_ps) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + + if (ps_mode > PM_Card_Disable) + return; + /* if driver is in active state, we dont need set smart_ps.*/ + if (ps_mode == PS_MODE_ACTIVE) + smart_ps = 0; + if ((pwrpriv->pwr_mode != ps_mode) || (pwrpriv->smart_ps != smart_ps)) { + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) + pwrpriv->bSleep = true; + else + pwrpriv->bSleep = false; + pwrpriv->pwr_mode = ps_mode; + pwrpriv->smart_ps = smart_ps; + schedule_work(&pwrpriv->SetPSModeWorkItem); + } +} + +/* + * Caller:ISR handler... + * + * This will be called when CPWM interrupt is up. + * + * using to update cpwn of drv; and drv will make a decision to up or + * down pwr level + */ +void r8712_cpwm_int_hdl(struct _adapter *padapter, + struct reportpwrstate_parm *preportpwrstate) +{ + struct pwrctrl_priv *pwrpriv = &(padapter->pwrctrlpriv); + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + + if (pwrpriv->cpwm_tog == ((preportpwrstate->state) & 0x80)) + return; + del_timer(&padapter->pwrctrlpriv.rpwm_check_timer); + _enter_pwrlock(&pwrpriv->lock); + pwrpriv->cpwm = (preportpwrstate->state) & 0xf; + if (pwrpriv->cpwm >= PS_STATE_S2) { + if (pwrpriv->alives & CMD_ALIVE) + up(&(pcmdpriv->cmd_queue_sema)); + } + pwrpriv->cpwm_tog = (preportpwrstate->state) & 0x80; + up(&pwrpriv->lock); +} + +static inline void register_task_alive(struct pwrctrl_priv *pwrctrl, uint tag) +{ + pwrctrl->alives |= tag; +} + +static inline void unregister_task_alive(struct pwrctrl_priv *pwrctrl, uint tag) +{ + if (pwrctrl->alives & tag) + pwrctrl->alives ^= tag; +} + +static void _rpwm_check_handler (struct _adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + + if (padapter->bDriverStopped == true || + padapter->bSurpriseRemoved == true) + return; + if (pwrpriv->cpwm != pwrpriv->rpwm) + schedule_work(&pwrpriv->rpwm_workitem); +} + +static void SetPSModeWorkItemCallback(struct work_struct *work) +{ + struct pwrctrl_priv *pwrpriv = container_of(work, + struct pwrctrl_priv, SetPSModeWorkItem); + struct _adapter *padapter = container_of(pwrpriv, + struct _adapter, pwrctrlpriv); + if (!pwrpriv->bSleep) { + _enter_pwrlock(&pwrpriv->lock); + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) + r8712_set_rpwm(padapter, PS_STATE_S4); + up(&pwrpriv->lock); + } +} + +static void rpwm_workitem_callback(struct work_struct *work) +{ + struct pwrctrl_priv *pwrpriv = container_of(work, + struct pwrctrl_priv, rpwm_workitem); + struct _adapter *padapter = container_of(pwrpriv, + struct _adapter, pwrctrlpriv); + if (pwrpriv->cpwm != pwrpriv->rpwm) { + _enter_pwrlock(&pwrpriv->lock); + r8712_read8(padapter, SDIO_HCPWM); + pwrpriv->rpwm_retry = 1; + r8712_set_rpwm(padapter, pwrpriv->rpwm); + up(&pwrpriv->lock); + } +} + +static void rpwm_check_handler (unsigned long data) +{ + struct _adapter *adapter = (struct _adapter *)data; + + _rpwm_check_handler(adapter); +} + +void r8712_init_pwrctrl_priv(struct _adapter *padapter) +{ + struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; + + memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv)); + sema_init(&pwrctrlpriv->lock, 1); + pwrctrlpriv->cpwm = PS_STATE_S4; + pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; + pwrctrlpriv->smart_ps = 0; + pwrctrlpriv->tog = 0x80; +/* clear RPWM to ensure driver and fw back to initial state. */ + r8712_write8(padapter, 0x1025FE58, 0); + INIT_WORK(&pwrctrlpriv->SetPSModeWorkItem, SetPSModeWorkItemCallback); + INIT_WORK(&pwrctrlpriv->rpwm_workitem, rpwm_workitem_callback); + setup_timer(&pwrctrlpriv->rpwm_check_timer, rpwm_check_handler, + (unsigned long)padapter); +} + +/* +Caller: r8712_cmd_thread + +Check if the fw_pwrstate is okay for issuing cmd. +If not (cpwm should be is less than P2 state), then the sub-routine +will raise the cpwm to be greater than or equal to P2. + +Calling Context: Passive + +Return Value: + +_SUCCESS: r8712_cmd_thread can issue cmds to firmware afterwards. +_FAIL: r8712_cmd_thread can not do anything. +*/ +sint r8712_register_cmd_alive(struct _adapter *padapter) +{ + uint res = _SUCCESS; + struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv; + + _enter_pwrlock(&pwrctrl->lock); + register_task_alive(pwrctrl, CMD_ALIVE); + if (pwrctrl->cpwm < PS_STATE_S2) { + r8712_set_rpwm(padapter, PS_STATE_S3); + res = _FAIL; + } + up(&pwrctrl->lock); + return res; +} + +/* +Caller: ISR + +If ISR's txdone, +No more pkts for TX, +Then driver shall call this fun. to power down firmware again. +*/ + +void r8712_unregister_cmd_alive(struct _adapter *padapter) +{ + struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv; + + _enter_pwrlock(&pwrctrl->lock); + unregister_task_alive(pwrctrl, CMD_ALIVE); + if ((pwrctrl->cpwm > PS_STATE_S2) && + (pwrctrl->pwr_mode > PS_MODE_ACTIVE)) { + if ((pwrctrl->alives == 0) && + (check_fwstate(&padapter->mlmepriv, + _FW_UNDER_LINKING) != true)) { + r8712_set_rpwm(padapter, PS_STATE_S0); + } + } + up(&pwrctrl->lock); +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/kernel/drivers/staging/rtl8712/rtl871x_pwrctrl.h new file mode 100644 index 000000000..dbfb55523 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_pwrctrl.h @@ -0,0 +1,131 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL871X_PWRCTRL_H_ +#define __RTL871X_PWRCTRL_H_ + +#include "osdep_service.h" +#include "drv_types.h" + + +#define CMD_ALIVE BIT(2) + +enum Power_Mgnt { + PS_MODE_ACTIVE = 0, + PS_MODE_MIN, + PS_MODE_MAX, + PS_MODE_DTIM, + PS_MODE_VOIP, + PS_MODE_UAPSD_WMM, + PS_MODE_UAPSD, + PS_MODE_IBSS, + PS_MODE_WWLAN, + PM_Radio_Off, + PM_Card_Disable, + PS_MODE_NUM +}; + +/* + BIT[2:0] = HW state + BIT[3] = Protocol PS state, 0: register active state, + 1: register sleep state + BIT[4] = sub-state +*/ + +#define PS_DPS BIT(0) +#define PS_LCLK (PS_DPS) +#define PS_RF_OFF BIT(1) +#define PS_ALL_ON BIT(2) +#define PS_ST_ACTIVE BIT(3) +#define PS_LP BIT(4) /* low performance */ + +#define PS_STATE_MASK (0x0F) +#define PS_STATE_HW_MASK (0x07) +#define PS_SEQ_MASK (0xc0) + +#define PS_STATE(x) (PS_STATE_MASK & (x)) +#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x)) +#define PS_SEQ(x) (PS_SEQ_MASK & (x)) + +#define PS_STATE_S0 (PS_DPS) +#define PS_STATE_S1 (PS_LCLK) +#define PS_STATE_S2 (PS_RF_OFF) +#define PS_STATE_S3 (PS_ALL_ON) +#define PS_STATE_S4 ((PS_ST_ACTIVE) | (PS_ALL_ON)) + + +#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON)) +#define PS_IS_ACTIVE(x) ((x) & (PS_ST_ACTIVE)) +#define CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) + + +struct reportpwrstate_parm { + unsigned char mode; + unsigned char state; /* the CPWM value */ + unsigned short rsvd; +}; + +static inline void _enter_pwrlock(struct semaphore *plock) +{ + _down_sema(plock); +} + +struct pwrctrl_priv { + struct semaphore lock; + /*volatile*/ u8 rpwm; /* requested power state for fw */ + /* fw current power state. updated when 1. read from HCPWM or + * 2. driver lowers power level */ + /*volatile*/ u8 cpwm; + /*volatile*/ u8 tog; /* toggling */ + /*volatile*/ u8 cpwm_tog; /* toggling */ + /*volatile*/ u8 tgt_rpwm; /* wanted power state */ + uint pwr_mode; + uint smart_ps; + uint alives; + uint ImrContent; /* used to store original imr. */ + uint bSleep; /* sleep -> active is different from active -> sleep. */ + + struct work_struct SetPSModeWorkItem; + struct work_struct rpwm_workitem; + struct timer_list rpwm_check_timer; + u8 rpwm_retry; + uint bSetPSModeWorkItemInProgress; + + spinlock_t pnp_pwr_mgnt_lock; + s32 pnp_current_pwr_state; + u8 pnp_bstop_trx; + u8 pnp_wwirp_pending; +}; + +void r8712_init_pwrctrl_priv(struct _adapter *adapter); +sint r8712_register_cmd_alive(struct _adapter *padapter); +void r8712_unregister_cmd_alive(struct _adapter *padapter); +void r8712_cpwm_int_hdl(struct _adapter *padapter, + struct reportpwrstate_parm *preportpwrstate); +void r8712_set_ps_mode(struct _adapter *padapter, uint ps_mode, + uint smart_ps); +void r8712_set_rpwm(struct _adapter *padapter, u8 val8); + +#endif /* __RTL871X_PWRCTRL_H_ */ diff --git a/kernel/drivers/staging/rtl8712/rtl871x_recv.c b/kernel/drivers/staging/rtl8712/rtl871x_recv.c new file mode 100644 index 000000000..046a46c4c --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_recv.c @@ -0,0 +1,678 @@ +/****************************************************************************** + * rtl871x_recv.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_RECV_C_ + +#include <linux/ip.h> +#include <linux/slab.h> +#include <linux/if_ether.h> +#include <linux/kmemleak.h> +#include <linux/etherdevice.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "recv_osdep.h" +#include "mlme_osdep.h" +#include "ethernet.h" +#include "usb_ops.h" +#include "wifi.h" + +static const u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37}; + +/* Datagram Delivery Protocol */ +static const u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3}; + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static const u8 bridge_tunnel_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; + +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static const u8 rfc1042_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; + +void _r8712_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) +{ + memset((u8 *)psta_recvpriv, 0, sizeof(struct sta_recv_priv)); + spin_lock_init(&psta_recvpriv->lock); + _init_queue(&psta_recvpriv->defrag_q); +} + +sint _r8712_init_recv_priv(struct recv_priv *precvpriv, + struct _adapter *padapter) +{ + sint i; + union recv_frame *precvframe; + + memset((unsigned char *)precvpriv, 0, sizeof(struct recv_priv)); + spin_lock_init(&precvpriv->lock); + _init_queue(&precvpriv->free_recv_queue); + _init_queue(&precvpriv->recv_pending_queue); + precvpriv->adapter = padapter; + precvpriv->free_recvframe_cnt = NR_RECVFRAME; + precvpriv->pallocated_frame_buf = kmalloc(NR_RECVFRAME * + sizeof(union recv_frame) + RXFRAME_ALIGN_SZ, + GFP_ATOMIC); + if (precvpriv->pallocated_frame_buf == NULL) + return _FAIL; + kmemleak_not_leak(precvpriv->pallocated_frame_buf); + memset(precvpriv->pallocated_frame_buf, 0, NR_RECVFRAME * + sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); + precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf + + RXFRAME_ALIGN_SZ - + ((addr_t)(precvpriv->pallocated_frame_buf) & + (RXFRAME_ALIGN_SZ-1)); + precvframe = (union recv_frame *)precvpriv->precv_frame_buf; + for (i = 0; i < NR_RECVFRAME; i++) { + INIT_LIST_HEAD(&(precvframe->u.list)); + list_add_tail(&(precvframe->u.list), + &(precvpriv->free_recv_queue.queue)); + r8712_os_recv_resource_alloc(padapter, precvframe); + precvframe->u.hdr.adapter = padapter; + precvframe++; + } + precvpriv->rx_pending_cnt = 1; + return r8712_init_recv_priv(precvpriv, padapter); +} + +void _r8712_free_recv_priv(struct recv_priv *precvpriv) +{ + kfree(precvpriv->pallocated_frame_buf); + r8712_free_recv_priv(precvpriv); +} + +union recv_frame *r8712_alloc_recvframe(struct __queue *pfree_recv_queue) +{ + unsigned long irqL; + union recv_frame *precvframe; + struct list_head *plist, *phead; + struct _adapter *padapter; + struct recv_priv *precvpriv; + + spin_lock_irqsave(&pfree_recv_queue->lock, irqL); + if (list_empty(&pfree_recv_queue->queue)) + precvframe = NULL; + else { + phead = &pfree_recv_queue->queue; + plist = phead->next; + precvframe = LIST_CONTAINOR(plist, union recv_frame, u); + list_del_init(&precvframe->u.hdr.list); + padapter = precvframe->u.hdr.adapter; + if (padapter != NULL) { + precvpriv = &padapter->recvpriv; + if (pfree_recv_queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt--; + } + } + spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL); + return precvframe; +} + +/* +caller : defrag; recvframe_chk_defrag in recv_thread (passive) +pframequeue: defrag_queue : will be accessed in recv_thread (passive) + +using spin_lock to protect + +*/ + +void r8712_free_recvframe_queue(struct __queue *pframequeue, + struct __queue *pfree_recv_queue) +{ + union recv_frame *precvframe; + struct list_head *plist, *phead; + + spin_lock(&pframequeue->lock); + phead = &pframequeue->queue; + plist = phead->next; + while (end_of_queue_search(phead, plist) == false) { + precvframe = LIST_CONTAINOR(plist, union recv_frame, u); + plist = plist->next; + r8712_free_recvframe(precvframe, pfree_recv_queue); + } + spin_unlock(&pframequeue->lock); +} + +sint r8712_recvframe_chkmic(struct _adapter *adapter, + union recv_frame *precvframe) +{ + sint i, res = _SUCCESS; + u32 datalen; + u8 miccode[8]; + u8 bmic_err = false; + u8 *pframe, *payload, *pframemic; + u8 *mickey, idx, *iv; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + stainfo = r8712_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); + if (prxattrib->encrypt == _TKIP_) { + /* calculate mic code */ + if (stainfo != NULL) { + if (IS_MCAST(prxattrib->ra)) { + iv = precvframe->u.hdr.rx_data + + prxattrib->hdrlen; + idx = iv[3]; + mickey = &psecuritypriv->XGrprxmickey[(((idx >> + 6) & 0x3)) - 1].skey[0]; + if (psecuritypriv->binstallGrpkey == false) + return _FAIL; + } else + mickey = &stainfo->tkiprxmickey.skey[0]; + /*icv_len included the mic code*/ + datalen = precvframe->u.hdr.len - prxattrib->hdrlen - + prxattrib->iv_len - prxattrib->icv_len - 8; + pframe = precvframe->u.hdr.rx_data; + payload = pframe + prxattrib->hdrlen + + prxattrib->iv_len; + seccalctkipmic(mickey, pframe, payload, datalen, + &miccode[0], + (unsigned char)prxattrib->priority); + pframemic = payload + datalen; + bmic_err = false; + for (i = 0; i < 8; i++) { + if (miccode[i] != *(pframemic + i)) + bmic_err = true; + } + if (bmic_err == true) { + if (prxattrib->bdecrypted == true) + r8712_handle_tkip_mic_err(adapter, + (u8)IS_MCAST(prxattrib->ra)); + res = _FAIL; + } else { + /* mic checked ok */ + if ((psecuritypriv->bcheck_grpkey == + false) && (IS_MCAST(prxattrib->ra) == + true)) + psecuritypriv->bcheck_grpkey = true; + } + recvframe_pull_tail(precvframe, 8); + } + } + return res; +} + +/* decrypt and set the ivlen,icvlen of the recv_frame */ +union recv_frame *r8712_decryptor(struct _adapter *padapter, + union recv_frame *precv_frame) +{ + struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + union recv_frame *return_packet = precv_frame; + + if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || + (psecuritypriv->sw_decrypt == true))) { + psecuritypriv->hw_decrypted = false; + switch (prxattrib->encrypt) { + case _WEP40_: + case _WEP104_: + r8712_wep_decrypt(padapter, (u8 *)precv_frame); + break; + case _TKIP_: + r8712_tkip_decrypt(padapter, (u8 *)precv_frame); + break; + case _AES_: + r8712_aes_decrypt(padapter, (u8 *)precv_frame); + break; + default: + break; + } + } else if (prxattrib->bdecrypted == 1) + psecuritypriv->hw_decrypted = true; + return return_packet; +} +/*###set the security information in the recv_frame */ +union recv_frame *r8712_portctrl(struct _adapter *adapter, + union recv_frame *precv_frame) +{ + u8 *psta_addr, *ptr; + uint auth_alg; + struct recv_frame_hdr *pfhdr; + struct sta_info *psta; + struct sta_priv *pstapriv; + union recv_frame *prtnframe; + u16 ether_type; + + pstapriv = &adapter->stapriv; + ptr = get_recvframe_data(precv_frame); + pfhdr = &precv_frame->u.hdr; + psta_addr = pfhdr->attrib.ta; + psta = r8712_get_stainfo(pstapriv, psta_addr); + auth_alg = adapter->securitypriv.AuthAlgrthm; + if (auth_alg == 2) { + /* get ether_type */ + ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE; + memcpy(ðer_type, ptr, 2); + ether_type = ntohs((unsigned short)ether_type); + + if ((psta != NULL) && (psta->ieee8021x_blocked)) { + /* blocked + * only accept EAPOL frame */ + if (ether_type == 0x888e) + prtnframe = precv_frame; + else { + /*free this frame*/ + r8712_free_recvframe(precv_frame, + &adapter->recvpriv.free_recv_queue); + prtnframe = NULL; + } + } else { + /* allowed + * check decryption status, and decrypt the + * frame if needed */ + prtnframe = precv_frame; + /* check is the EAPOL frame or not (Rekey) */ + if (ether_type == 0x888e) { + /* check Rekey */ + prtnframe = precv_frame; + } + } + } else + prtnframe = precv_frame; + return prtnframe; +} + +static sint recv_decache(union recv_frame *precv_frame, u8 bretry, + struct stainfo_rxcache *prxcache) +{ + sint tid = precv_frame->u.hdr.attrib.priority; + u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) | + (precv_frame->u.hdr.attrib.frag_num & 0xf); + + if (tid > 15) + return _FAIL; + if (seq_ctrl == prxcache->tid_rxseq[tid]) + return _FAIL; + prxcache->tid_rxseq[tid] = seq_ctrl; + return _SUCCESS; +} + +static sint sta2sta_data_frame(struct _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta) +{ + u8 *ptr = precv_frame->u.hdr.rx_data; + sint ret = _SUCCESS; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u8 *mybssid = get_bssid(pmlmepriv); + u8 *myhwaddr = myid(&adapter->eeprompriv); + u8 *sta_addr = NULL; + sint bmcast = IS_MCAST(pattrib->dst); + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { + /* filter packets that SA is myself or multicast or broadcast */ + if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) + return _FAIL; + if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) + return _FAIL; + if (is_zero_ether_addr(pattrib->bssid) || + is_zero_ether_addr(mybssid) || + (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) + return _FAIL; + sta_addr = pattrib->src; + } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { + /* For Station mode, sa and bssid should always be BSSID, + * and DA is my mac-address */ + if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) + return _FAIL; + sta_addr = pattrib->bssid; + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + if (bmcast) { + /* For AP mode, if DA == MCAST, then BSSID should + * be also MCAST */ + if (!IS_MCAST(pattrib->bssid)) + return _FAIL; + } else { /* not mc-frame */ + /* For AP mode, if DA is non-MCAST, then it must be + * BSSID, and bssid == BSSID */ + if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) + return _FAIL; + sta_addr = pattrib->src; + } + } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); + memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); + memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); + memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + sta_addr = mybssid; + } else + ret = _FAIL; + if (bmcast) + *psta = r8712_get_bcmc_stainfo(adapter); + else + *psta = r8712_get_stainfo(pstapriv, sta_addr); /* get ap_info */ + if (*psta == NULL) { + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) + adapter->mppriv.rx_pktloss++; + return _FAIL; + } + return ret; +} + +static sint ap2sta_data_frame(struct _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta) +{ + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u8 *mybssid = get_bssid(pmlmepriv); + u8 *myhwaddr = myid(&adapter->eeprompriv); + sint bmcast = IS_MCAST(pattrib->dst); + + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) + && (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + /* if NULL-frame, drop packet */ + if ((GetFrameSubType(ptr)) == WIFI_DATA_NULL) + return _FAIL; + /* drop QoS-SubType Data, including QoS NULL, + * excluding QoS-Data */ + if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == + WIFI_QOS_DATA_TYPE) { + if (GetFrameSubType(ptr) & (BIT(4) | BIT(5) | BIT(6))) + return _FAIL; + } + + /* filter packets that SA is myself or multicast or broadcast */ + if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) + return _FAIL; + + /* da should be for me */ + if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) + return _FAIL; + /* check BSSID */ + if (is_zero_ether_addr(pattrib->bssid) || + is_zero_ether_addr(mybssid) || + (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) + return _FAIL; + if (bmcast) + *psta = r8712_get_bcmc_stainfo(adapter); + else + *psta = r8712_get_stainfo(pstapriv, pattrib->bssid); + if (*psta == NULL) + return _FAIL; + } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); + memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); + memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); + memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + memcpy(pattrib->bssid, mybssid, ETH_ALEN); + *psta = r8712_get_stainfo(pstapriv, pattrib->bssid); + if (*psta == NULL) + return _FAIL; + } else + return _FAIL; + return _SUCCESS; +} + +static sint sta2ap_data_frame(struct _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta) +{ + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + unsigned char *mybssid = get_bssid(pmlmepriv); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + /* For AP mode, if DA is non-MCAST, then it must be BSSID, + * and bssid == BSSID + * For AP mode, RA=BSSID, TX=STA(SRC_ADDR), A3=DST_ADDR */ + if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) + return _FAIL; + *psta = r8712_get_stainfo(pstapriv, pattrib->src); + if (*psta == NULL) + return _FAIL; + } + return _SUCCESS; +} + +static sint validate_recv_ctrl_frame(struct _adapter *adapter, + union recv_frame *precv_frame) +{ + return _FAIL; +} + +static sint validate_recv_mgnt_frame(struct _adapter *adapter, + union recv_frame *precv_frame) +{ + return _FAIL; +} + + +static sint validate_recv_data_frame(struct _adapter *adapter, + union recv_frame *precv_frame) +{ + int res; + u8 bretry; + u8 *psa, *pda, *pbssid; + struct sta_info *psta = NULL; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + bretry = GetRetry(ptr); + pda = get_da(ptr); + psa = get_sa(ptr); + pbssid = get_hdr_bssid(ptr); + if (pbssid == NULL) + return _FAIL; + memcpy(pattrib->dst, pda, ETH_ALEN); + memcpy(pattrib->src, psa, ETH_ALEN); + memcpy(pattrib->bssid, pbssid, ETH_ALEN); + switch (pattrib->to_fr_ds) { + case 0: + memcpy(pattrib->ra, pda, ETH_ALEN); + memcpy(pattrib->ta, psa, ETH_ALEN); + res = sta2sta_data_frame(adapter, precv_frame, &psta); + break; + case 1: + memcpy(pattrib->ra, pda, ETH_ALEN); + memcpy(pattrib->ta, pbssid, ETH_ALEN); + res = ap2sta_data_frame(adapter, precv_frame, &psta); + break; + case 2: + memcpy(pattrib->ra, pbssid, ETH_ALEN); + memcpy(pattrib->ta, psa, ETH_ALEN); + res = sta2ap_data_frame(adapter, precv_frame, &psta); + break; + case 3: + memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); + memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); + return _FAIL; + default: + return _FAIL; + } + if (res == _FAIL) + return _FAIL; + if (psta == NULL) + return _FAIL; + precv_frame->u.hdr.psta = psta; + pattrib->amsdu = 0; + /* parsing QC field */ + if (pattrib->qos == 1) { + pattrib->priority = GetPriority((ptr + 24)); + pattrib->ack_policy = GetAckpolicy((ptr + 24)); + pattrib->amsdu = GetAMsdu((ptr + 24)); + pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26; + } else { + pattrib->priority = 0; + pattrib->hdrlen = (pattrib->to_fr_ds == 3) ? 30 : 24; + } + + if (pattrib->order)/*HT-CTRL 11n*/ + pattrib->hdrlen += 4; + precv_frame->u.hdr.preorder_ctrl = + &psta->recvreorder_ctrl[pattrib->priority]; + + /* decache, drop duplicate recv packets */ + if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == + _FAIL) + return _FAIL; + + if (pattrib->privacy) { + GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, + IS_MCAST(pattrib->ra)); + SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, + pattrib->encrypt); + } else { + pattrib->encrypt = 0; + pattrib->iv_len = pattrib->icv_len = 0; + } + return _SUCCESS; +} + +sint r8712_validate_recv_frame(struct _adapter *adapter, + union recv_frame *precv_frame) +{ + /*shall check frame subtype, to / from ds, da, bssid */ + /*then call check if rx seq/frag. duplicated.*/ + + u8 type; + u8 subtype; + sint retval = _SUCCESS; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + + u8 *ptr = precv_frame->u.hdr.rx_data; + u8 ver = (unsigned char)(*ptr) & 0x3; + + /*add version chk*/ + if (ver != 0) + return _FAIL; + type = GetFrameType(ptr); + subtype = GetFrameSubType(ptr); /*bit(7)~bit(2)*/ + pattrib->to_fr_ds = get_tofr_ds(ptr); + pattrib->frag_num = GetFragNum(ptr); + pattrib->seq_num = GetSequence(ptr); + pattrib->pw_save = GetPwrMgt(ptr); + pattrib->mfrag = GetMFrag(ptr); + pattrib->mdata = GetMData(ptr); + pattrib->privacy = GetPrivacy(ptr); + pattrib->order = GetOrder(ptr); + switch (type) { + case WIFI_MGT_TYPE: /*mgnt*/ + retval = validate_recv_mgnt_frame(adapter, precv_frame); + break; + case WIFI_CTRL_TYPE:/*ctrl*/ + retval = validate_recv_ctrl_frame(adapter, precv_frame); + break; + case WIFI_DATA_TYPE: /*data*/ + pattrib->qos = (subtype & BIT(7)) ? 1 : 0; + retval = validate_recv_data_frame(adapter, precv_frame); + break; + default: + return _FAIL; + } + return retval; +} + +sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe) +{ + /*remove the wlanhdr and add the eth_hdr*/ + sint rmv_len; + u16 len; + u8 bsnaphdr; + u8 *psnap_type; + struct ieee80211_snap_hdr *psnap; + struct _adapter *adapter = precvframe->u.hdr.adapter; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + u8 *ptr = get_recvframe_data(precvframe); /*point to frame_ctrl field*/ + struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; + + if (pattrib->encrypt) + recvframe_pull_tail(precvframe, pattrib->icv_len); + psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + + pattrib->iv_len); + psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; + /* convert hdr + possible LLC headers into Ethernet header */ + if ((!memcmp(psnap, (void *)rfc1042_header, SNAP_SIZE) && + (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_IPX, 2)) && + (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_APPLETALK_AARP, 2))) || + !memcmp(psnap, (void *)bridge_tunnel_header, SNAP_SIZE)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + bsnaphdr = true; + } else { + /* Leave Ethernet header part of hdr and full payload */ + bsnaphdr = false; + } + rmv_len = pattrib->hdrlen + pattrib->iv_len + + (bsnaphdr ? SNAP_SIZE : 0); + len = precvframe->u.hdr.len - rmv_len; + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + ptr += rmv_len; + *ptr = 0x87; + *(ptr+1) = 0x12; + /* append rx status for mp test packets */ + ptr = recvframe_pull(precvframe, (rmv_len - + sizeof(struct ethhdr) + 2) - 24); + memcpy(ptr, get_rxmem(precvframe), 24); + ptr += 24; + } else + ptr = recvframe_pull(precvframe, (rmv_len - + sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); + + memcpy(ptr, pattrib->dst, ETH_ALEN); + memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); + if (!bsnaphdr) { + len = htons(len); + memcpy(ptr + 12, &len, 2); + } + return _SUCCESS; +} + +s32 r8712_recv_entry(union recv_frame *precvframe) +{ + struct _adapter *padapter; + struct recv_priv *precvpriv; + + s32 ret = _SUCCESS; + + padapter = precvframe->u.hdr.adapter; + precvpriv = &(padapter->recvpriv); + + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_RX); + + ret = recv_func(padapter, precvframe); + if (ret == _FAIL) + goto _recv_entry_drop; + precvpriv->rx_pkts++; + precvpriv->rx_bytes += (uint)(precvframe->u.hdr.rx_tail - + precvframe->u.hdr.rx_data); + return ret; +_recv_entry_drop: + precvpriv->rx_drop++; + padapter->mppriv.rx_pktloss = precvpriv->rx_drop; + return ret; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_recv.h b/kernel/drivers/staging/rtl8712/rtl871x_recv.h new file mode 100644 index 000000000..77487bb9d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_recv.h @@ -0,0 +1,216 @@ +#ifndef _RTL871X_RECV_H_ +#define _RTL871X_RECV_H_ + +#include "osdep_service.h" +#include "drv_types.h" + +#define NR_RECVFRAME 256 + +#define RXFRAME_ALIGN 8 +#define RXFRAME_ALIGN_SZ (1 << RXFRAME_ALIGN) + +#define MAX_SUBFRAME_COUNT 64 + +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +/* for Rx reordering buffer control */ +struct recv_reorder_ctrl { + struct _adapter *padapter; + u16 indicate_seq; /* =wstart_b, init_value=0xffff */ + u16 wend_b; + u8 wsize_b; + struct __queue pending_recvframe_queue; + struct timer_list reordering_ctrl_timer; +}; + +struct stainfo_rxcache { + u16 tid_rxseq[16]; +}; + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 + + +struct smooth_rssi_data { + u32 elements[100]; /* array to store values */ + u32 index; /* index to current array to store */ + u32 total_num; /* num of valid elements */ + u32 total_val; /* sum of valid elements */ +}; + +struct rx_pkt_attrib { + + u8 amsdu; + u8 order; + u8 qos; + u8 to_fr_ds; + u8 frag_num; + u16 seq_num; + u8 pw_save; + u8 mfrag; + u8 mdata; + u8 privacy; /* in frame_ctrl field */ + u8 bdecrypted; + int hdrlen; /* the WLAN Header Len */ + int encrypt; /* 0 no encrypt. != 0 encrypt algorith */ + int iv_len; + int icv_len; + int priority; + int ack_policy; + u8 crc_err; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 ta[ETH_ALEN]; + u8 ra[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 tcpchk_valid; /* 0: invalid, 1: valid */ + u8 ip_chkrpt; /* 0: incorrect, 1: correct */ + u8 tcp_chkrpt; /* 0: incorrect, 1: correct */ + u8 signal_qual; + s8 rx_mimo_signal_qual[2]; + u8 mcs_rate; + u8 htc; + u8 signal_strength; +}; + +/* +accesser of recv_priv: recv_entry(dispatch / passive level); +recv_thread(passive) ; returnpkt(dispatch) +; halt(passive) ; + +using enter_critical section to protect +*/ +struct recv_priv { + spinlock_t lock; + struct __queue free_recv_queue; + struct __queue recv_pending_queue; + u8 *pallocated_frame_buf; + u8 *precv_frame_buf; + uint free_recvframe_cnt; + struct _adapter *adapter; + uint rx_bytes; + uint rx_pkts; + uint rx_drop; + uint rx_icv_err; + uint rx_largepacket_crcerr; + uint rx_smallpacket_crcerr; + uint rx_middlepacket_crcerr; + u8 rx_pending_cnt; + uint ff_hwaddr; + struct tasklet_struct recv_tasklet; + struct sk_buff_head free_recv_skb_queue; + struct sk_buff_head rx_skb_queue; + u8 *pallocated_recv_buf; + u8 *precv_buf; /* 4 alignment */ + struct __queue free_recv_buf_queue; + u32 free_recv_buf_queue_cnt; + /* For the phy informatiom */ + s8 rssi; + u8 signal; + u8 noise; + u8 fw_rssi; + struct smooth_rssi_data signal_qual_data; + struct smooth_rssi_data signal_strength_data; +}; + +struct sta_recv_priv { + spinlock_t lock; + sint option; + struct __queue defrag_q; /* keeping the fragment frame until defrag */ + struct stainfo_rxcache rxcache; + uint sta_rx_bytes; + uint sta_rx_pkts; + uint sta_rx_fail; +}; + +#include "rtl8712_recv.h" + +/* get a free recv_frame from pfree_recv_queue */ +union recv_frame *r8712_alloc_recvframe(struct __queue *pfree_recv_queue); +int r8712_free_recvframe(union recv_frame *precvframe, + struct __queue *pfree_recv_queue); +void r8712_free_recvframe_queue(struct __queue *pframequeue, + struct __queue *pfree_recv_queue); +int r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe); +int recv_func(struct _adapter *padapter, void *pcontext); + +static inline u8 *get_rxmem(union recv_frame *precvframe) +{ + /* always return rx_head... */ + if (precvframe == NULL) + return NULL; + return precvframe->u.hdr.rx_head; +} + +static inline u8 *get_recvframe_data(union recv_frame *precvframe) +{ + /* always return rx_data */ + if (precvframe == NULL) + return NULL; + return precvframe->u.hdr.rx_data; +} + +static inline u8 *recvframe_pull(union recv_frame *precvframe, sint sz) +{ + /* used for extract sz bytes from rx_data, update rx_data and return + * the updated rx_data to the caller */ + if (precvframe == NULL) + return NULL; + precvframe->u.hdr.rx_data += sz; + if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) { + precvframe->u.hdr.rx_data -= sz; + return NULL; + } + precvframe->u.hdr.len -= sz; + return precvframe->u.hdr.rx_data; +} + +static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz) +{ + /* used for append sz bytes from ptr to rx_tail, update rx_tail and + * return the updated rx_tail to the caller + * after putting, rx_tail must be still larger than rx_end. */ + if (precvframe == NULL) + return NULL; + precvframe->u.hdr.rx_tail += sz; + if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) { + precvframe->u.hdr.rx_tail -= sz; + return NULL; + } + precvframe->u.hdr.len += sz; + return precvframe->u.hdr.rx_tail; +} + +static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz) +{ + /* rmv data from rx_tail (by yitsen) + * used for extract sz bytes from rx_end, update rx_end and return the + * updated rx_end to the caller + * after pulling, rx_end must be still larger than rx_data. */ + if (precvframe == NULL) + return NULL; + precvframe->u.hdr.rx_tail -= sz; + if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) { + precvframe->u.hdr.rx_tail += sz; + return NULL; + } + precvframe->u.hdr.len -= sz; + return precvframe->u.hdr.rx_tail; +} + +struct sta_info; + +void _r8712_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv); +sint r8712_recvframe_chkmic(struct _adapter *adapter, + union recv_frame *precvframe); +union recv_frame *r8712_decryptor(struct _adapter *adapter, + union recv_frame *precv_frame); +union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *adapter, + union recv_frame *precv_frame); +int r8712_validate_recv_frame(struct _adapter *adapter, + union recv_frame *precv_frame); +union recv_frame *r8712_portctrl(struct _adapter *adapter, + union recv_frame *precv_frame); + +#endif + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_rf.h b/kernel/drivers/staging/rtl8712/rtl871x_rf.h new file mode 100644 index 000000000..133ed6462 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_rf.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL871X_RF_H_ +#define __RTL871X_RF_H_ + +#include "rtl871x_cmd.h" +#include "rtl871x_mp_phy_regdef.h" + +#define OFDM_PHY 1 +#define MIXED_PHY 2 +#define CCK_PHY 3 +#define NumRates (13) +#define RTL8711_RF_MAX_SENS 6 +#define RTL8711_RF_DEF_SENS 4 +#define NUM_CHANNELS 15 + +struct regulatory_class { + u32 starting_freq; /*MHz, */ + u8 channel_set[NUM_CHANNELS]; + u8 channel_cck_power[NUM_CHANNELS]; /*dbm*/ + u8 channel_ofdm_power[NUM_CHANNELS];/*dbm*/ + u8 txpower_limit; /*dbm*/ + u8 channel_spacing; /*MHz*/ + u8 modem; +}; + +enum _REG_PREAMBLE_MODE { + PREAMBLE_LONG = 1, + PREAMBLE_AUTO = 2, + PREAMBLE_SHORT = 3, +}; + +enum { + RTL8712_RFC_1T = 0x10, + RTL8712_RFC_2T = 0x20, + RTL8712_RFC_1R = 0x01, + RTL8712_RFC_2R = 0x02, + RTL8712_RFC_1T1R = 0x11, + RTL8712_RFC_1T2R = 0x12, + RTL8712_RFC_TURBO = 0x92, + RTL8712_RFC_2T2R = 0x22 +}; + +#endif /*_RTL8711_RF_H_*/ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_security.c b/kernel/drivers/staging/rtl8712/rtl871x_security.c new file mode 100644 index 000000000..bcd1a5128 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_security.c @@ -0,0 +1,1400 @@ +/****************************************************************************** + * rtl871x_security.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_SECURITY_C_ + +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kref.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/circ_buf.h> +#include <linux/uaccess.h> +#include <asm/byteorder.h> +#include <linux/atomic.h> +#include <linux/semaphore.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "wifi.h" +#include "osdep_intf.h" + +/* =====WEP related===== */ + +#define CRC32_POLY 0x04c11db7 + +struct arc4context { + u32 x; + u32 y; + u8 state[256]; +}; + +static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len) +{ + u32 t, u; + u32 keyindex; + u32 stateindex; + u8 *state; + u32 counter; + + state = parc4ctx->state; + parc4ctx->x = 0; + parc4ctx->y = 0; + for (counter = 0; counter < 256; counter++) + state[counter] = (u8)counter; + keyindex = 0; + stateindex = 0; + for (counter = 0; counter < 256; counter++) { + t = state[counter]; + stateindex = (stateindex + key[keyindex] + t) & 0xff; + u = state[stateindex]; + state[stateindex] = (u8)t; + state[counter] = (u8)u; + if (++keyindex >= key_len) + keyindex = 0; + } +} + +static u32 arcfour_byte(struct arc4context *parc4ctx) +{ + u32 x; + u32 y; + u32 sx, sy; + u8 *state; + + state = parc4ctx->state; + x = (parc4ctx->x + 1) & 0xff; + sx = state[x]; + y = (sx + parc4ctx->y) & 0xff; + sy = state[y]; + parc4ctx->x = x; + parc4ctx->y = y; + state[y] = (u8)sx; + state[x] = (u8)sy; + return state[(sx + sy) & 0xff]; +} + +static void arcfour_encrypt(struct arc4context *parc4ctx, + u8 *dest, u8 *src, u32 len) +{ + u32 i; + + for (i = 0; i < len; i++) + dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); +} + +static sint bcrc32initialized; +static u32 crc32_table[256]; + +static u8 crc32_reverseBit(u8 data) +{ + return ((u8)(data << 7) & 0x80) | ((data << 5) & 0x40) | ((data << 3) + & 0x20) | ((data << 1) & 0x10) | ((data >> 1) & 0x08) | + ((data >> 3) & 0x04) | ((data >> 5) & 0x02) | ((data >> 7) & + 0x01); +} + +static void crc32_init(void) +{ + if (bcrc32initialized == 1) + return; + else { + sint i, j; + u32 c; + u8 *p = (u8 *)&c, *p1; + u8 k; + + c = 0x12340000; + for (i = 0; i < 256; ++i) { + k = crc32_reverseBit((u8)i); + for (c = ((u32)k) << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : + (c << 1); + p1 = (u8 *)&crc32_table[i]; + p1[0] = crc32_reverseBit(p[3]); + p1[1] = crc32_reverseBit(p[2]); + p1[2] = crc32_reverseBit(p[1]); + p1[3] = crc32_reverseBit(p[0]); + } + bcrc32initialized = 1; + } +} + +static u32 getcrc32(u8 *buf, u32 len) +{ + u8 *p; + u32 crc; + + if (!bcrc32initialized) + crc32_init(); + crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ + for (p = buf; len > 0; ++p, --len) + crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8); + return ~crc; /* transmit complement, per CRC-32 spec */ +} + +/* + Need to consider the fragment situation +*/ +void r8712_wep_encrypt(struct _adapter *padapter, u8 *pxmitframe) +{ /* exclude ICV */ + unsigned char crc[4]; + struct arc4context mycontext; + u32 curfragnum, length, keylength; + u8 *pframe, *payload, *iv; /*,*wepkey*/ + u8 wepkey[16]; + struct pkt_attrib *pattrib = &((struct xmit_frame *) + pxmitframe)->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) + return; + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr+TXDESC_OFFSET; + /*start to encrypt each fragment*/ + if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) { + keylength = psecuritypriv->DefKeylen[psecuritypriv-> + PrivacyKeyIndex]; + for (curfragnum = 0; curfragnum < pattrib->nr_frags; + curfragnum++) { + iv = pframe+pattrib->hdrlen; + memcpy(&wepkey[0], iv, 3); + memcpy(&wepkey[3], &psecuritypriv->DefKey[ + psecuritypriv->PrivacyKeyIndex].skey[0], + keylength); + payload = pframe+pattrib->iv_len+pattrib->hdrlen; + if ((curfragnum + 1) == pattrib->nr_frags) { + length = pattrib->last_txcmdsz-pattrib-> + hdrlen-pattrib->iv_len - + pattrib->icv_len; + *((u32 *)crc) = cpu_to_le32(getcrc32( + payload, length)); + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, + length); + arcfour_encrypt(&mycontext, payload + length, + crc, 4); + } else { + length = pxmitpriv->frag_len-pattrib->hdrlen - + pattrib->iv_len-pattrib->icv_len; + *((u32 *)crc) = cpu_to_le32(getcrc32( + payload, length)); + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, + length); + arcfour_encrypt(&mycontext, payload+length, + crc, 4); + pframe += pxmitpriv->frag_len; + pframe = (u8 *)RND4((addr_t)(pframe)); + } + } + } +} + +void r8712_wep_decrypt(struct _adapter *padapter, u8 *precvframe) +{ + /* exclude ICV */ + u8 crc[4]; + struct arc4context mycontext; + u32 length, keylength; + u8 *pframe, *payload, *iv, wepkey[16]; + u8 keyindex; + struct rx_pkt_attrib *prxattrib = &(((union recv_frame *) + precvframe)->u.hdr.attrib); + struct security_priv *psecuritypriv = &padapter->securitypriv; + + pframe = (unsigned char *)((union recv_frame *)precvframe)-> + u.hdr.rx_data; + /* start to decrypt recvframe */ + if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == + _WEP104_)) { + iv = pframe + prxattrib->hdrlen; + keyindex = (iv[3] & 0x3); + keylength = psecuritypriv->DefKeylen[keyindex]; + memcpy(&wepkey[0], iv, 3); + memcpy(&wepkey[3], &psecuritypriv->DefKey[ + psecuritypriv->PrivacyKeyIndex].skey[0], + keylength); + length = ((union recv_frame *)precvframe)-> + u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; + payload = pframe+prxattrib->iv_len+prxattrib->hdrlen; + /* decrypt payload include icv */ + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, length); + /* calculate icv and compare the icv */ + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length - 4)); + } +} + +/* 3 =====TKIP related===== */ + +static u32 secmicgetuint32(u8 *p) +/* Convert from Byte[] to Us4Byte32 in a portable way */ +{ + s32 i; + u32 res = 0; + + for (i = 0; i < 4; i++) + res |= ((u32)(*p++)) << (8 * i); + return res; +} + +static void secmicputuint32(u8 *p, u32 val) +/* Convert from Us4Byte32 to Byte[] in a portable way */ +{ + long i; + + for (i = 0; i < 4; i++) { + *p++ = (u8) (val & 0xff); + val >>= 8; + } +} + +static void secmicclear(struct mic_data *pmicdata) +{ +/* Reset the state to the empty message. */ + pmicdata->L = pmicdata->K0; + pmicdata->R = pmicdata->K1; + pmicdata->nBytesInM = 0; + pmicdata->M = 0; +} + +void r8712_secmicsetkey(struct mic_data *pmicdata, u8 *key) +{ + /* Set the key */ + pmicdata->K0 = secmicgetuint32(key); + pmicdata->K1 = secmicgetuint32(key + 4); + /* and reset the message */ + secmicclear(pmicdata); +} + +static void secmicappendbyte(struct mic_data *pmicdata, u8 b) +{ + /* Append the byte to our word-sized buffer */ + pmicdata->M |= ((u32)b) << (8 * pmicdata->nBytesInM); + pmicdata->nBytesInM++; + /* Process the word if it is full. */ + if (pmicdata->nBytesInM >= 4) { + pmicdata->L ^= pmicdata->M; + pmicdata->R ^= ROL32(pmicdata->L, 17); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | + ((pmicdata->L & 0x00ff00ff) << 8); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ROL32(pmicdata->L, 3); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ROR32(pmicdata->L, 2); + pmicdata->L += pmicdata->R; + /* Clear the buffer */ + pmicdata->M = 0; + pmicdata->nBytesInM = 0; + } +} + +void r8712_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes) +{ + /* This is simple */ + while (nbytes > 0) { + secmicappendbyte(pmicdata, *src++); + nbytes--; + } +} + +void r8712_secgetmic(struct mic_data *pmicdata, u8 *dst) +{ + /* Append the minimum padding */ + secmicappendbyte(pmicdata, 0x5a); + secmicappendbyte(pmicdata, 0); + secmicappendbyte(pmicdata, 0); + secmicappendbyte(pmicdata, 0); + secmicappendbyte(pmicdata, 0); + /* and then zeroes until the length is a multiple of 4 */ + while (pmicdata->nBytesInM != 0) + secmicappendbyte(pmicdata, 0); + /* The appendByte function has already computed the result. */ + secmicputuint32(dst, pmicdata->L); + secmicputuint32(dst + 4, pmicdata->R); + /* Reset to the empty message. */ + secmicclear(pmicdata); +} + +void seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, + u8 pri) +{ + + struct mic_data micdata; + u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; + + r8712_secmicsetkey(&micdata, key); + priority[0] = pri; + /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ + if (header[1] & 1) { /* ToDS==1 */ + r8712_secmicappend(&micdata, &header[16], 6); /* DA */ + if (header[1] & 2) /* From Ds==1 */ + r8712_secmicappend(&micdata, &header[24], 6); + else + r8712_secmicappend(&micdata, &header[10], 6); + } else { /* ToDS==0 */ + r8712_secmicappend(&micdata, &header[4], 6); /* DA */ + if (header[1] & 2) /* From Ds==1 */ + r8712_secmicappend(&micdata, &header[16], 6); + else + r8712_secmicappend(&micdata, &header[10], 6); + } + r8712_secmicappend(&micdata, &priority[0], 4); + r8712_secmicappend(&micdata, data, data_len); + r8712_secgetmic(&micdata, mic_code); +} + +/* macros for extraction/creation of unsigned char/unsigned short values */ +#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) +#define Lo8(v16) ((u8)((v16) & 0x00FF)) +#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) +#define Lo16(v32) ((u16)((v32) & 0xFFFF)) +#define Hi16(v32) ((u16)(((v32) >> 16) & 0xFFFF)) +#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8)) + +/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ +#define TK16(N) Mk16(tk[2 * (N) + 1], tk[2 * (N)]) + +/* S-box lookup: 16 bits --> 16 bits */ +#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)]) + +/* fixed algorithm "parameters" */ +#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ +#define TA_SIZE 6 /* 48-bit transmitter address */ +#define TK_SIZE 16 /* 128-bit temporal key */ +#define P1K_SIZE 10 /* 80-bit Phase1 key */ +#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ + + +/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */ +static const unsigned short Sbox1[2][256] = {/* Sbox for hash (can be in ROM) */ + { + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, + 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, + 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, + 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, + 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, + 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, + 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, + 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, + 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, + 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, + 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, + 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, + 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, + 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, + 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, + 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, + 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, + 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, + 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, + 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, + 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, + 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, + 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, + 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, + 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, + 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, + 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, + 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, + 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, + }, + { /* second half is unsigned char-reversed version of first! */ + 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, + 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, + 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, + 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, + 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, + 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, + 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, + 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, + 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, + 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, + 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, + 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, + 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, + 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, + 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, + 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, + 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, + 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, + 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, + 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, + 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, + 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, + 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, + 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, + 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, + 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, + 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, + 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, + 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, + 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, + 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, + 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C, + } +}; + +/* +********************************************************************** +* Routine: Phase 1 -- generate P1K, given TA, TK, IV32 +* +* Inputs: +* tk[] = temporal key [128 bits] +* ta[] = transmitter's MAC address [ 48 bits] +* iv32 = upper 32 bits of IV [ 32 bits] +* Output: +* p1k[] = Phase 1 key [ 80 bits] +* +* Note: +* This function only needs to be called every 2**16 packets, +* although in theory it could be called every packet. +* +********************************************************************** +*/ +static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) +{ + sint i; + + /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ + p1k[0] = Lo16(iv32); + p1k[1] = Hi16(iv32); + p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */ + p1k[3] = Mk16(ta[3], ta[2]); + p1k[4] = Mk16(ta[5], ta[4]); + /* Now compute an unbalanced Feistel cipher with 80-bit block */ + /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ + for (i = 0; i < PHASE1_LOOP_CNT; i++) { /* Each add is mod 2**16 */ + p1k[0] += _S_(p1k[4] ^ TK16((i&1) + 0)); + p1k[1] += _S_(p1k[0] ^ TK16((i&1) + 2)); + p1k[2] += _S_(p1k[1] ^ TK16((i&1) + 4)); + p1k[3] += _S_(p1k[2] ^ TK16((i&1) + 6)); + p1k[4] += _S_(p1k[3] ^ TK16((i&1) + 0)); + p1k[4] += (unsigned short)i; /* avoid "slide attacks" */ + } +} + +/* +********************************************************************** +* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 +* +* Inputs: +* tk[] = Temporal key [128 bits] +* p1k[] = Phase 1 output key [ 80 bits] +* iv16 = low 16 bits of IV counter [ 16 bits] +* Output: +* rc4key[] = the key used to encrypt the packet [128 bits] +* +* Note: +* The value {TA,IV32,IV16} for Phase1/Phase2 must be unique +* across all packets using the same key TK value. Then, for a +* given value of TK[], this TKIP48 construction guarantees that +* the final RC4KEY value is unique across all packets. +* +* Suggested implementation optimization: if PPK[] is "overlaid" +* appropriately on RC4KEY[], there is no need for the final +* for loop below that copies the PPK[] result into RC4KEY[]. +* +********************************************************************** +*/ +static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) +{ + sint i; + u16 PPK[6]; /* temporary key for mixing */ + + /* Note: all adds in the PPK[] equations below are mod 2**16 */ + for (i = 0; i < 5; i++) + PPK[i] = p1k[i]; /* first, copy P1K to PPK */ + PPK[5] = p1k[4] + iv16; /* next, add in IV16 */ + /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ + PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ + PPK[1] += _S_(PPK[0] ^ TK16(1)); + PPK[2] += _S_(PPK[1] ^ TK16(2)); + PPK[3] += _S_(PPK[2] ^ TK16(3)); + PPK[4] += _S_(PPK[3] ^ TK16(4)); + PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ + /* Final sweep: bijective, "linear". Rotates kill LSB correlations */ + PPK[0] += RotR1(PPK[5] ^ TK16(6)); + PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + /* Note: At this point, for a given key TK[0..15], the 96-bit output */ + /* value PPK[0..5] is guaranteed to be unique, as a function */ + /* of the 96-bit "input" value {TA,IV32,IV16}. That is, P1K */ + /* is now a keyed permutation of {TA,IV32,IV16}. */ + /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */ + rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */ + rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */ + rc4key[2] = Lo8(iv16); + rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); + /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ + for (i = 0; i < 6; i++) { + rc4key[4 + 2 * i] = Lo8(PPK[i]); + rc4key[5 + 2 * i] = Hi8(PPK[i]); + } +} + +/*The hlen isn't include the IV*/ +u32 r8712_tkip_encrypt(struct _adapter *padapter, u8 *pxmitframe) +{ /* exclude ICV */ + u16 pnl; + u32 pnh; + u8 rc4key[16]; + u8 ttkey[16]; + u8 crc[4]; + struct arc4context mycontext; + u32 curfragnum, length; + + u8 *pframe, *payload, *iv, *prwskey; + union pn48 txpn; + struct sta_info *stainfo; + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u32 res = _SUCCESS; + + if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) + return _FAIL; + + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr+TXDESC_OFFSET; + /* 4 start to encrypt each fragment */ + if (pattrib->encrypt == _TKIP_) { + if (pattrib->psta) + stainfo = pattrib->psta; + else + stainfo = r8712_get_stainfo(&padapter->stapriv, + &pattrib->ra[0]); + if (stainfo != NULL) { + prwskey = &stainfo->x_UncstKey.skey[0]; + for (curfragnum = 0; curfragnum < pattrib->nr_frags; + curfragnum++) { + iv = pframe + pattrib->hdrlen; + payload = pframe+pattrib->iv_len + + pattrib->hdrlen; + GET_TKIP_PN(iv, txpn); + pnl = (u16)(txpn.val); + pnh = (u32)(txpn.val >> 16); + phase1((u16 *)&ttkey[0], prwskey, &pattrib-> + ta[0], pnh); + phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], + pnl); + if ((curfragnum + 1) == pattrib->nr_frags) { + /* 4 the last fragment */ + length = pattrib->last_txcmdsz - + pattrib->hdrlen-pattrib->iv_len - + pattrib->icv_len; + *((u32 *)crc) = cpu_to_le32( + getcrc32(payload, length)); + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, + payload, length); + arcfour_encrypt(&mycontext, payload + + length, crc, 4); + } else { + length = pxmitpriv->frag_len-pattrib-> + hdrlen-pattrib-> + iv_len-pattrib->icv_len; + *((u32 *)crc) = cpu_to_le32(getcrc32( + payload, length)); + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, + payload, length); + arcfour_encrypt(&mycontext, + payload+length, crc, 4); + pframe += pxmitpriv->frag_len; + pframe = (u8 *)RND4((addr_t)(pframe)); + } + } + } else + res = _FAIL; + } + return res; +} + +/* The hlen doesn't include the IV */ +u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe) +{ /* exclude ICV */ + u16 pnl; + u32 pnh; + u8 rc4key[16]; + u8 ttkey[16]; + u8 crc[4]; + struct arc4context mycontext; + u32 length; + u8 *pframe, *payload, *iv, *prwskey, idx = 0; + union pn48 txpn; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &((union recv_frame *) + precvframe)->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + pframe = (unsigned char *)((union recv_frame *) + precvframe)->u.hdr.rx_data; + /* 4 start to decrypt recvframe */ + if (prxattrib->encrypt == _TKIP_) { + stainfo = r8712_get_stainfo(&padapter->stapriv, + &prxattrib->ta[0]); + if (stainfo != NULL) { + iv = pframe+prxattrib->hdrlen; + payload = pframe+prxattrib->iv_len + prxattrib->hdrlen; + length = ((union recv_frame *)precvframe)-> + u.hdr.len - prxattrib->hdrlen - + prxattrib->iv_len; + if (IS_MCAST(prxattrib->ra)) { + idx = iv[3]; + prwskey = &psecuritypriv->XGrpKey[ + ((idx >> 6) & 0x3) - 1].skey[0]; + if (psecuritypriv->binstallGrpkey == false) + return _FAIL; + } else + prwskey = &stainfo->x_UncstKey.skey[0]; + GET_TKIP_PN(iv, txpn); + pnl = (u16)(txpn.val); + pnh = (u32)(txpn.val >> 16); + phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], + pnh); + phase2(&rc4key[0], prwskey, (unsigned short *) + &ttkey[0], pnl); + /* 4 decrypt payload include icv */ + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, payload, length); + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, + length - 4)); + if (crc[3] != payload[length - 1] || + crc[2] != payload[length - 2] || + crc[1] != payload[length - 3] || + crc[0] != payload[length - 4]) + return _FAIL; + } else + return _FAIL; + } + return _SUCCESS; +} + +/* 3 =====AES related===== */ + +#define MAX_MSG_SIZE 2048 +/*****************************/ +/******** SBOX Table *********/ +/*****************************/ + +static const u8 sbox_table[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +/****************************************/ +/* aes128k128d() */ +/* Performs a 128 bit AES encrypt with */ +/* 128 bit data. */ +/****************************************/ +static void xor_128(u8 *a, u8 *b, u8 *out) +{ + sint i; + + for (i = 0; i < 16; i++) + out[i] = a[i] ^ b[i]; +} + +static void xor_32(u8 *a, u8 *b, u8 *out) +{ + sint i; + + for (i = 0; i < 4; i++) + out[i] = a[i] ^ b[i]; +} + +static u8 sbox(u8 a) +{ + return sbox_table[(sint)a]; +} + +static void next_key(u8 *key, sint round) +{ + u8 rcon; + u8 sbox_key[4]; + u8 rcon_table[12] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x1b, 0x36, 0x36, 0x36 + }; + + sbox_key[0] = sbox(key[13]); + sbox_key[1] = sbox(key[14]); + sbox_key[2] = sbox(key[15]); + sbox_key[3] = sbox(key[12]); + rcon = rcon_table[round]; + xor_32(&key[0], sbox_key, &key[0]); + key[0] = key[0] ^ rcon; + xor_32(&key[4], &key[0], &key[4]); + xor_32(&key[8], &key[4], &key[8]); + xor_32(&key[12], &key[8], &key[12]); +} + +static void byte_sub(u8 *in, u8 *out) +{ + sint i; + + for (i = 0; i < 16; i++) + out[i] = sbox(in[i]); +} + +static void shift_row(u8 *in, u8 *out) +{ + out[0] = in[0]; + out[1] = in[5]; + out[2] = in[10]; + out[3] = in[15]; + out[4] = in[4]; + out[5] = in[9]; + out[6] = in[14]; + out[7] = in[3]; + out[8] = in[8]; + out[9] = in[13]; + out[10] = in[2]; + out[11] = in[7]; + out[12] = in[12]; + out[13] = in[1]; + out[14] = in[6]; + out[15] = in[11]; +} + +static void mix_column(u8 *in, u8 *out) +{ + sint i; + u8 add1b[4]; + u8 add1bf7[4]; + u8 rotl[4]; + u8 swap_halfs[4]; + u8 andf7[4]; + u8 rotr[4]; + u8 temp[4]; + u8 tempb[4]; + + for (i = 0; i < 4; i++) { + if ((in[i] & 0x80) == 0x80) + add1b[i] = 0x1b; + else + add1b[i] = 0x00; + } + swap_halfs[0] = in[2]; /* Swap halves */ + swap_halfs[1] = in[3]; + swap_halfs[2] = in[0]; + swap_halfs[3] = in[1]; + rotl[0] = in[3]; /* Rotate left 8 bits */ + rotl[1] = in[0]; + rotl[2] = in[1]; + rotl[3] = in[2]; + andf7[0] = in[0] & 0x7f; + andf7[1] = in[1] & 0x7f; + andf7[2] = in[2] & 0x7f; + andf7[3] = in[3] & 0x7f; + for (i = 3; i > 0; i--) { /* logical shift left 1 bit */ + andf7[i] = andf7[i] << 1; + if ((andf7[i-1] & 0x80) == 0x80) + andf7[i] = (andf7[i] | 0x01); + } + andf7[0] = andf7[0] << 1; + andf7[0] = andf7[0] & 0xfe; + xor_32(add1b, andf7, add1bf7); + xor_32(in, add1bf7, rotr); + temp[0] = rotr[0]; /* Rotate right 8 bits */ + rotr[0] = rotr[1]; + rotr[1] = rotr[2]; + rotr[2] = rotr[3]; + rotr[3] = temp[0]; + xor_32(add1bf7, rotr, temp); + xor_32(swap_halfs, rotl, tempb); + xor_32(temp, tempb, out); +} + +static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) +{ + sint round; + sint i; + u8 intermediatea[16]; + u8 intermediateb[16]; + u8 round_key[16]; + + for (i = 0; i < 16; i++) + round_key[i] = key[i]; + for (round = 0; round < 11; round++) { + if (round == 0) { + xor_128(round_key, data, ciphertext); + next_key(round_key, round); + } else if (round == 10) { + byte_sub(ciphertext, intermediatea); + shift_row(intermediatea, intermediateb); + xor_128(intermediateb, round_key, ciphertext); + } else { /* 1 - 9 */ + byte_sub(ciphertext, intermediatea); + shift_row(intermediatea, intermediateb); + mix_column(&intermediateb[0], &intermediatea[0]); + mix_column(&intermediateb[4], &intermediatea[4]); + mix_column(&intermediateb[8], &intermediatea[8]); + mix_column(&intermediateb[12], &intermediatea[12]); + xor_128(intermediatea, round_key, ciphertext); + next_key(round_key, round); + } + } +} + +/************************************************/ +/* construct_mic_iv() */ +/* Builds the MIC IV from header fields and PN */ +/************************************************/ +static void construct_mic_iv(u8 *mic_iv, sint qc_exists, sint a4_exists, + u8 *mpdu, uint payload_length, u8 *pn_vector) +{ + sint i; + + mic_iv[0] = 0x59; + if (qc_exists && a4_exists) + mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ + if (qc_exists && !a4_exists) + mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ + if (!qc_exists) + mic_iv[1] = 0x00; + for (i = 2; i < 8; i++) + mic_iv[i] = mpdu[i + 8]; + for (i = 8; i < 14; i++) + mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ + mic_iv[14] = (unsigned char) (payload_length / 256); + mic_iv[15] = (unsigned char) (payload_length % 256); +} + +/************************************************/ +/* construct_mic_header1() */ +/* Builds the first MIC header block from */ +/* header fields. */ +/************************************************/ +static void construct_mic_header1(u8 *mic_header1, sint header_length, u8 *mpdu) +{ + mic_header1[0] = (u8)((header_length - 2) / 256); + mic_header1[1] = (u8)((header_length - 2) % 256); + mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ + /* Mute retry, more data and pwr mgt bits */ + mic_header1[3] = mpdu[1] & 0xc7; + mic_header1[4] = mpdu[4]; /* A1 */ + mic_header1[5] = mpdu[5]; + mic_header1[6] = mpdu[6]; + mic_header1[7] = mpdu[7]; + mic_header1[8] = mpdu[8]; + mic_header1[9] = mpdu[9]; + mic_header1[10] = mpdu[10]; /* A2 */ + mic_header1[11] = mpdu[11]; + mic_header1[12] = mpdu[12]; + mic_header1[13] = mpdu[13]; + mic_header1[14] = mpdu[14]; + mic_header1[15] = mpdu[15]; +} + +/************************************************/ +/* construct_mic_header2() */ +/* Builds the last MIC header block from */ +/* header fields. */ +/************************************************/ +static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, sint a4_exists, + sint qc_exists) +{ + sint i; + + for (i = 0; i < 16; i++) + mic_header2[i] = 0x00; + mic_header2[0] = mpdu[16]; /* A3 */ + mic_header2[1] = mpdu[17]; + mic_header2[2] = mpdu[18]; + mic_header2[3] = mpdu[19]; + mic_header2[4] = mpdu[20]; + mic_header2[5] = mpdu[21]; + mic_header2[6] = 0x00; + mic_header2[7] = 0x00; /* mpdu[23]; */ + if (!qc_exists && a4_exists) + for (i = 0; i < 6; i++) + mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ + if (qc_exists && !a4_exists) { + mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ + mic_header2[9] = mpdu[25] & 0x00; + } + if (qc_exists && a4_exists) { + for (i = 0; i < 6; i++) + mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ + mic_header2[14] = mpdu[30] & 0x0f; + mic_header2[15] = mpdu[31] & 0x00; + } +} + +/************************************************/ +/* construct_mic_header2() */ +/* Builds the last MIC header block from */ +/* header fields. */ +/************************************************/ +static void construct_ctr_preload(u8 *ctr_preload, sint a4_exists, sint qc_exists, + u8 *mpdu, u8 *pn_vector, sint c) +{ + sint i; + + for (i = 0; i < 16; i++) + ctr_preload[i] = 0x00; + i = 0; + ctr_preload[0] = 0x01; /* flag */ + if (qc_exists && a4_exists) + ctr_preload[1] = mpdu[30] & 0x0f; + if (qc_exists && !a4_exists) + ctr_preload[1] = mpdu[24] & 0x0f; + for (i = 2; i < 8; i++) + ctr_preload[i] = mpdu[i + 8]; + for (i = 8; i < 14; i++) + ctr_preload[i] = pn_vector[13 - i]; + ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */ + ctr_preload[15] = (unsigned char) (c % 256); +} + +/************************************/ +/* bitwise_xor() */ +/* A 128 bit, bitwise exclusive or */ +/************************************/ +static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) +{ + sint i; + + for (i = 0; i < 16; i++) + out[i] = ina[i] ^ inb[i]; +} + +static sint aes_cipher(u8 *key, uint hdrlen, + u8 *pframe, uint plen) +{ + uint qc_exists, a4_exists, i, j, payload_remainder; + uint num_blocks, payload_index; + + u8 pn_vector[6]; + u8 mic_iv[16]; + u8 mic_header1[16]; + u8 mic_header2[16]; + u8 ctr_preload[16]; + + /* Intermediate Buffers */ + u8 chain_buffer[16]; + u8 aes_out[16]; + u8 padded_buffer[16]; + u8 mic[8]; + uint frtype = GetFrameType(pframe); + uint frsubtype = GetFrameSubType(pframe); + + frsubtype >>= 4; + memset((void *)mic_iv, 0, 16); + memset((void *)mic_header1, 0, 16); + memset((void *)mic_header2, 0, 16); + memset((void *)ctr_preload, 0, 16); + memset((void *)chain_buffer, 0, 16); + memset((void *)aes_out, 0, 16); + memset((void *)padded_buffer, 0, 16); + + if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) + a4_exists = 0; + else + a4_exists = 1; + + if ((frtype == WIFI_DATA_CFACK) || + (frtype == WIFI_DATA_CFPOLL) || + (frtype == WIFI_DATA_CFACKPOLL)) { + qc_exists = 1; + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + hdrlen += 2; + } else if ((frsubtype == 0x08) || + (frsubtype == 0x09) || + (frsubtype == 0x0a) || + (frsubtype == 0x0b)) { + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + hdrlen += 2; + qc_exists = 1; + } else + qc_exists = 0; + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen+1]; + pn_vector[2] = pframe[hdrlen+4]; + pn_vector[3] = pframe[hdrlen+5]; + pn_vector[4] = pframe[hdrlen+6]; + pn_vector[5] = pframe[hdrlen+7]; + construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector); + construct_mic_header1(mic_header1, hdrlen, pframe); + construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists); + payload_remainder = plen % 16; + num_blocks = plen / 16; + /* Find start of payload */ + payload_index = hdrlen + 8; + /* Calculate MIC */ + aes128k128d(key, mic_iv, aes_out); + bitwise_xor(aes_out, mic_header1, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + bitwise_xor(aes_out, mic_header2, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + for (i = 0; i < num_blocks; i++) { + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + payload_index += 16; + aes128k128d(key, chain_buffer, aes_out); + } + /* Add on the final payload block if it needs padding */ + if (payload_remainder > 0) { + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = pframe[payload_index++]; + bitwise_xor(aes_out, padded_buffer, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + } + for (j = 0; j < 8; j++) + mic[j] = aes_out[j]; + /* Insert MIC into payload */ + for (j = 0; j < 8; j++) + pframe[payload_index+j] = mic[j]; + payload_index = hdrlen + 8; + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + pframe, pn_vector, i + 1); + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + for (j = 0; j < 16; j++) + pframe[payload_index++] = chain_buffer[j]; + } + if (payload_remainder > 0) { /* If short final block, then pad it,*/ + /* encrypt and copy unpadded part back */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + pframe, pn_vector, num_blocks+1); + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = pframe[payload_index+j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + pframe[payload_index++] = chain_buffer[j]; + } + /* Encrypt the MIC */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + pframe, pn_vector, 0); + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < 8; j++) + padded_buffer[j] = pframe[j+hdrlen+8+plen]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < 8; j++) + pframe[payload_index++] = chain_buffer[j]; + return _SUCCESS; +} + +u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe) +{ /* exclude ICV */ + /* Intermediate Buffers */ + sint curfragnum, length; + u8 *pframe, *prwskey; + struct sta_info *stainfo; + struct pkt_attrib *pattrib = &((struct xmit_frame *) + pxmitframe)->attrib; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u32 res = _SUCCESS; + + if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) + return _FAIL; + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_OFFSET; + /* 4 start to encrypt each fragment */ + if (pattrib->encrypt == _AES_) { + if (pattrib->psta) + stainfo = pattrib->psta; + else + stainfo = r8712_get_stainfo(&padapter->stapriv, + &pattrib->ra[0]); + if (stainfo != NULL) { + prwskey = &stainfo->x_UncstKey.skey[0]; + for (curfragnum = 0; curfragnum < pattrib->nr_frags; + curfragnum++) { + if ((curfragnum + 1) == pattrib->nr_frags) { + length = pattrib->last_txcmdsz - + pattrib->hdrlen - + pattrib->iv_len - + pattrib->icv_len; + aes_cipher(prwskey, pattrib-> + hdrlen, pframe, length); + } else { + length = pxmitpriv->frag_len - + pattrib->hdrlen - + pattrib->iv_len - + pattrib->icv_len; + aes_cipher(prwskey, pattrib-> + hdrlen, pframe, length); + pframe += pxmitpriv->frag_len; + pframe = (u8 *)RND4((addr_t)(pframe)); + } + } + } else + res = _FAIL; + } + return res; +} + +static sint aes_decipher(u8 *key, uint hdrlen, + u8 *pframe, uint plen) +{ + static u8 message[MAX_MSG_SIZE]; + uint qc_exists, a4_exists, i, j, payload_remainder; + uint num_blocks, payload_index; + u8 pn_vector[6]; + u8 mic_iv[16]; + u8 mic_header1[16]; + u8 mic_header2[16]; + u8 ctr_preload[16]; + /* Intermediate Buffers */ + u8 chain_buffer[16]; + u8 aes_out[16]; + u8 padded_buffer[16]; + u8 mic[8]; + uint frtype = GetFrameType(pframe); + uint frsubtype = GetFrameSubType(pframe); + + frsubtype >>= 4; + memset((void *)mic_iv, 0, 16); + memset((void *)mic_header1, 0, 16); + memset((void *)mic_header2, 0, 16); + memset((void *)ctr_preload, 0, 16); + memset((void *)chain_buffer, 0, 16); + memset((void *)aes_out, 0, 16); + memset((void *)padded_buffer, 0, 16); + /* start to decrypt the payload */ + /*(plen including llc, payload and mic) */ + num_blocks = (plen - 8) / 16; + payload_remainder = (plen-8) % 16; + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen+1]; + pn_vector[2] = pframe[hdrlen+4]; + pn_vector[3] = pframe[hdrlen+5]; + pn_vector[4] = pframe[hdrlen+6]; + pn_vector[5] = pframe[hdrlen+7]; + if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) + a4_exists = 0; + else + a4_exists = 1; + if ((frtype == WIFI_DATA_CFACK) || + (frtype == WIFI_DATA_CFPOLL) || + (frtype == WIFI_DATA_CFACKPOLL)) { + qc_exists = 1; + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + hdrlen += 2; + } else if ((frsubtype == 0x08) || + (frsubtype == 0x09) || + (frsubtype == 0x0a) || + (frsubtype == 0x0b)) { + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + hdrlen += 2; + qc_exists = 1; + } else { + qc_exists = 0; + } + /* now, decrypt pframe with hdrlen offset and plen long */ + payload_index = hdrlen + 8; /* 8 is for extiv */ + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + pframe, pn_vector, i + 1); + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + for (j = 0; j < 16; j++) + pframe[payload_index++] = chain_buffer[j]; + } + if (payload_remainder > 0) { /* If short final block, pad it,*/ + /* encrypt it and copy the unpadded part back */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + pframe, pn_vector, num_blocks+1); + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = pframe[payload_index + j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + pframe[payload_index++] = chain_buffer[j]; + } + /* start to calculate the mic */ + memcpy((void *)message, pframe, (hdrlen + plen + 8)); + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen+1]; + pn_vector[2] = pframe[hdrlen+4]; + pn_vector[3] = pframe[hdrlen+5]; + pn_vector[4] = pframe[hdrlen+6]; + pn_vector[5] = pframe[hdrlen+7]; + construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, + pn_vector); + construct_mic_header1(mic_header1, hdrlen, message); + construct_mic_header2(mic_header2, message, a4_exists, qc_exists); + payload_remainder = (plen - 8) % 16; + num_blocks = (plen - 8) / 16; + /* Find start of payload */ + payload_index = hdrlen + 8; + /* Calculate MIC */ + aes128k128d(key, mic_iv, aes_out); + bitwise_xor(aes_out, mic_header1, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + bitwise_xor(aes_out, mic_header2, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + for (i = 0; i < num_blocks; i++) { + bitwise_xor(aes_out, &message[payload_index], chain_buffer); + payload_index += 16; + aes128k128d(key, chain_buffer, aes_out); + } + /* Add on the final payload block if it needs padding */ + if (payload_remainder > 0) { + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = message[payload_index++]; + bitwise_xor(aes_out, padded_buffer, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + } + for (j = 0; j < 8; j++) + mic[j] = aes_out[j]; + /* Insert MIC into payload */ + for (j = 0; j < 8; j++) + message[payload_index+j] = mic[j]; + payload_index = hdrlen + 8; + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + message, pn_vector, i + 1); + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &message[payload_index], chain_buffer); + for (j = 0; j < 16; j++) + message[payload_index++] = chain_buffer[j]; + } + if (payload_remainder > 0) { /* If short final block, pad it,*/ + /* encrypt and copy unpadded part back */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + message, pn_vector, num_blocks+1); + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = message[payload_index + j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + message[payload_index++] = chain_buffer[j]; + } + /* Encrypt the MIC */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, + pn_vector, 0); + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < 8; j++) + padded_buffer[j] = message[j + hdrlen + plen]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < 8; j++) + message[payload_index++] = chain_buffer[j]; + /* compare the mic */ + return _SUCCESS; +} + +u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe) +{ /* exclude ICV */ + /* Intermediate Buffers */ + sint length; + u8 *pframe, *prwskey, *iv, idx; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &((union recv_frame *) + precvframe)->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + pframe = (unsigned char *)((union recv_frame *)precvframe)-> + u.hdr.rx_data; + /* 4 start to encrypt each fragment */ + if (prxattrib->encrypt == _AES_) { + stainfo = r8712_get_stainfo(&padapter->stapriv, + &prxattrib->ta[0]); + if (stainfo != NULL) { + if (IS_MCAST(prxattrib->ra)) { + iv = pframe+prxattrib->hdrlen; + idx = iv[3]; + prwskey = &psecuritypriv->XGrpKey[ + ((idx >> 6) & 0x3) - 1].skey[0]; + if (psecuritypriv->binstallGrpkey == false) + return _FAIL; + + } else + prwskey = &stainfo->x_UncstKey.skey[0]; + length = ((union recv_frame *)precvframe)-> + u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; + aes_decipher(prwskey, prxattrib->hdrlen, pframe, + length); + } else + return _FAIL; + } + return _SUCCESS; +} + +void r8712_use_tkipkey_handler(unsigned long data) +{ + struct _adapter *padapter = (struct _adapter *)data; + + padapter->securitypriv.busetkipkey = true; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_security.h b/kernel/drivers/staging/rtl8712/rtl871x_security.h new file mode 100644 index 000000000..2295f0e64 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_security.h @@ -0,0 +1,222 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __RTL871X_SECURITY_H_ +#define __RTL871X_SECURITY_H_ + +#include "osdep_service.h" +#include "drv_types.h" + +#define _NO_PRIVACY_ 0x0 +#define _WEP40_ 0x1 +#define _TKIP_ 0x2 +#define _TKIP_WTMIC_ 0x3 +#define _AES_ 0x4 +#define _WEP104_ 0x5 + +#define _WPA_IE_ID_ 0xdd +#define _WPA2_IE_ID_ 0x30 + +#ifndef Ndis802_11AuthModeWPA2 +#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1) +#endif + +#ifndef Ndis802_11AuthModeWPA2PSK +#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2) +#endif + +union pn48 { + u64 val; +#if defined(__BIG_ENDIAN) + struct { + u8 TSC7; + u8 TSC6; + u8 TSC5; + u8 TSC4; + u8 TSC3; + u8 TSC2; + u8 TSC1; + u8 TSC0; + } _byte_; +#else + struct { + u8 TSC0; + u8 TSC1; + u8 TSC2; + u8 TSC3; + u8 TSC4; + u8 TSC5; + u8 TSC6; + u8 TSC7; + } _byte_; +#endif +}; + +union Keytype { + u8 skey[16]; + u32 lkey[4]; +}; + +struct RT_PMKID_LIST { + u8 bUsed; + u8 Bssid[6]; + u8 PMKID[16]; + u8 SsidBuf[33]; + u8 *ssid_octet; + u16 ssid_length; +}; + +struct security_priv { + u32 AuthAlgrthm; /* 802.11 auth, could be open, shared, + * 8021x and authswitch */ + u32 PrivacyAlgrthm; /* This specify the privacy for shared + * auth. algorithm. */ + u32 PrivacyKeyIndex; /* this is only valid for legendary + * wep, 0~3 for key id. */ + union Keytype DefKey[4]; /* this is only valid for def. key */ + u32 DefKeylen[4]; + u32 XGrpPrivacy; /* This specify the privacy algthm. + * used for Grp key */ + u32 XGrpKeyid; /* key id used for Grp Key */ + union Keytype XGrpKey[2]; /* 802.1x Group Key, for + * inx0 and inx1 */ + union Keytype XGrptxmickey[2]; + union Keytype XGrprxmickey[2]; + union pn48 Grptxpn; /* PN48 used for Grp Key xmit. */ + union pn48 Grprxpn; /* PN48 used for Grp Key recv. */ + u8 wps_hw_pbc_pressed;/*for hw pbc pressed*/ + u8 wps_phase;/*for wps*/ + u8 wps_ie[MAX_WPA_IE_LEN<<2]; + int wps_ie_len; + u8 binstallGrpkey; + u8 busetkipkey; + struct timer_list tkip_timer; + u8 bcheck_grpkey; + u8 bgrpkey_handshake; + s32 sw_encrypt; /* from registry_priv */ + s32 sw_decrypt; /* from registry_priv */ + s32 hw_decrypted; /* if the rx packets is hw_decrypted==false, + * it means the hw has not been ready. */ + u32 ndisauthtype; /* keeps the auth_type & enc_status from upper + * layer ioctl(wpa_supplicant or wzc) */ + u32 ndisencryptstatus; + struct wlan_bssid_ex sec_bss; /* for joinbss (h2c buffer) usage */ + struct NDIS_802_11_WEP ndiswep; + u8 assoc_info[600]; + u8 szofcapability[256]; /* for wpa2 usage */ + u8 oidassociation[512]; /* for wpa/wpa2 usage */ + u8 authenticator_ie[256]; /* store ap security information element */ + u8 supplicant_ie[256]; /* store sta security information element */ + /* for tkip countermeasure */ + u32 last_mic_err_time; + u8 btkip_countermeasure; + u8 btkip_wait_report; + u32 btkip_countermeasure_time; + /*------------------------------------------------------------------- + * For WPA2 Pre-Authentication. + *------------------------------------------------------------------ */ + struct RT_PMKID_LIST PMKIDList[NUM_PMKID_CACHE]; + u8 PMKIDIndex; +}; + +#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst) \ +do { \ + switch (psecuritypriv->AuthAlgrthm) { \ + case 0: \ + case 1: \ + case 3: \ + encry_algo = (u8)psecuritypriv->PrivacyAlgrthm; \ + break; \ + case 2: \ + if (bmcst) \ + encry_algo = (u8)psecuritypriv->XGrpPrivacy; \ + else \ + encry_algo = (u8)psta->XPrivacy; \ + break; \ + } \ +} while (0) +#define SET_ICE_IV_LEN(iv_len, icv_len, encrypt)\ +do {\ + switch (encrypt) { \ + case _WEP40_: \ + case _WEP104_: \ + iv_len = 4; \ + icv_len = 4; \ + break; \ + case _TKIP_: \ + iv_len = 8; \ + icv_len = 4; \ + break; \ + case _AES_: \ + iv_len = 8; \ + icv_len = 8; \ + break; \ + default: \ + iv_len = 0; \ + icv_len = 0; \ + break; \ + } \ +} while (0) +#define GET_TKIP_PN(iv, txpn) \ +do {\ + txpn._byte_.TSC0 = iv[2];\ + txpn._byte_.TSC1 = iv[0];\ + txpn._byte_.TSC2 = iv[4];\ + txpn._byte_.TSC3 = iv[5];\ + txpn._byte_.TSC4 = iv[6];\ + txpn._byte_.TSC5 = iv[7];\ +} while (0) + +#define ROL32(A, n) (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1))) +#define ROR32(A, n) ROL32((A), 32 - (n)) + +struct mic_data { + u32 K0, K1; /* Key */ + u32 L, R; /* Current state */ + u32 M; /* Message accumulator (single word) */ + u32 nBytesInM; /* # bytes in M */ +}; + +void seccalctkipmic( + u8 *key, + u8 *header, + u8 *data, + u32 data_len, + u8 *Miccode, + u8 priority); + +void r8712_secmicsetkey(struct mic_data *pmicdata, u8 *key); +void r8712_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nBytes); +void r8712_secgetmic(struct mic_data *pmicdata, u8 *dst); +u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe); +u32 r8712_tkip_encrypt(struct _adapter *padapter, u8 *pxmitframe); +void r8712_wep_encrypt(struct _adapter *padapter, u8 *pxmitframe); +u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe); +u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe); +void r8712_wep_decrypt(struct _adapter *padapter, u8 *precvframe); +void r8712_use_tkipkey_handler(unsigned long data); + +#endif /*__RTL871X_SECURITY_H_ */ + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/kernel/drivers/staging/rtl8712/rtl871x_sta_mgt.c new file mode 100644 index 000000000..a9b93d0f6 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_sta_mgt.c @@ -0,0 +1,285 @@ +/****************************************************************************** + * rtl871x_sta_mgt.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_STA_MGT_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "recv_osdep.h" +#include "xmit_osdep.h" +#include "sta_info.h" + +static void _init_stainfo(struct sta_info *psta) +{ + memset((u8 *)psta, 0, sizeof(struct sta_info)); + spin_lock_init(&psta->lock); + INIT_LIST_HEAD(&psta->list); + INIT_LIST_HEAD(&psta->hash_list); + _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); + _r8712_init_sta_recv_priv(&psta->sta_recvpriv); + INIT_LIST_HEAD(&psta->asoc_list); + INIT_LIST_HEAD(&psta->auth_list); +} + +u32 _r8712_init_sta_priv(struct sta_priv *pstapriv) +{ + struct sta_info *psta; + s32 i; + + pstapriv->pallocated_stainfo_buf = kmalloc(sizeof(struct sta_info) * + NUM_STA + 4, GFP_ATOMIC); + if (pstapriv->pallocated_stainfo_buf == NULL) + return _FAIL; + pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - + ((addr_t)(pstapriv->pallocated_stainfo_buf) & 3); + _init_queue(&pstapriv->free_sta_queue); + spin_lock_init(&pstapriv->sta_hash_lock); + pstapriv->asoc_sta_count = 0; + _init_queue(&pstapriv->sleep_q); + _init_queue(&pstapriv->wakeup_q); + psta = (struct sta_info *)(pstapriv->pstainfo_buf); + for (i = 0; i < NUM_STA; i++) { + _init_stainfo(psta); + INIT_LIST_HEAD(&(pstapriv->sta_hash[i])); + list_add_tail(&psta->list, &pstapriv->free_sta_queue.queue); + psta++; + } + INIT_LIST_HEAD(&pstapriv->asoc_list); + INIT_LIST_HEAD(&pstapriv->auth_list); + return _SUCCESS; +} + +/* this function is used to free the memory of lock || sema for all stainfos */ +static void mfree_all_stainfo(struct sta_priv *pstapriv) +{ + unsigned long irqL; + struct list_head *plist, *phead; + + spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); + phead = &pstapriv->free_sta_queue.queue; + plist = phead->next; + while ((end_of_queue_search(phead, plist)) == false) + plist = plist->next; + + spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); +} + + +static void mfree_sta_priv_lock(struct sta_priv *pstapriv) +{ + mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ +} + +u32 _r8712_free_sta_priv(struct sta_priv *pstapriv) +{ + if (pstapriv) { + mfree_sta_priv_lock(pstapriv); + kfree(pstapriv->pallocated_stainfo_buf); + } + return _SUCCESS; +} + +struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) +{ + s32 index; + struct list_head *phash_list; + struct sta_info *psta; + struct __queue *pfree_sta_queue; + struct recv_reorder_ctrl *preorder_ctrl; + int i = 0; + u16 wRxSeqInitialValue = 0xffff; + unsigned long flags; + + pfree_sta_queue = &pstapriv->free_sta_queue; + spin_lock_irqsave(&(pfree_sta_queue->lock), flags); + if (list_empty(&pfree_sta_queue->queue)) + psta = NULL; + else { + psta = LIST_CONTAINOR(pfree_sta_queue->queue.next, + struct sta_info, list); + list_del_init(&(psta->list)); + _init_stainfo(psta); + memcpy(psta->hwaddr, hwaddr, ETH_ALEN); + index = wifi_mac_hash(hwaddr); + if (index >= NUM_STA) { + psta = NULL; + goto exit; + } + phash_list = &(pstapriv->sta_hash[index]); + list_add_tail(&psta->hash_list, phash_list); + pstapriv->asoc_sta_count++; + +/* For the SMC router, the sequence number of first packet of WPS handshake + * will be 0. In this case, this packet will be dropped by recv_decache function + * if we use the 0x00 as the default value for tid_rxseq variable. So, we + * initialize the tid_rxseq variable as the 0xffff. + */ + for (i = 0; i < 16; i++) + memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], + &wRxSeqInitialValue, 2); + /* for A-MPDU Rx reordering buffer control */ + for (i = 0; i < 16; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + preorder_ctrl->padapter = pstapriv->padapter; + preorder_ctrl->indicate_seq = 0xffff; + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64; + _init_queue(&preorder_ctrl->pending_recvframe_queue); + r8712_init_recv_timer(preorder_ctrl); + } + } +exit: + spin_unlock_irqrestore(&(pfree_sta_queue->lock), flags); + return psta; +} + +/* using pstapriv->sta_hash_lock to protect */ +void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta) +{ + int i; + unsigned long irqL0; + struct __queue *pfree_sta_queue; + struct recv_reorder_ctrl *preorder_ctrl; + struct sta_xmit_priv *pstaxmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + + if (psta == NULL) + return; + pfree_sta_queue = &pstapriv->free_sta_queue; + pstaxmitpriv = &psta->sta_xmitpriv; + spin_lock_irqsave(&(pxmitpriv->vo_pending.lock), irqL0); + r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); + list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); + spin_unlock_irqrestore(&(pxmitpriv->vo_pending.lock), irqL0); + spin_lock_irqsave(&(pxmitpriv->vi_pending.lock), irqL0); + r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); + list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); + spin_unlock_irqrestore(&(pxmitpriv->vi_pending.lock), irqL0); + spin_lock_irqsave(&(pxmitpriv->bk_pending.lock), irqL0); + r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); + list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); + spin_unlock_irqrestore(&(pxmitpriv->bk_pending.lock), irqL0); + spin_lock_irqsave(&(pxmitpriv->be_pending.lock), irqL0); + r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); + list_del_init(&(pstaxmitpriv->be_q.tx_pending)); + spin_unlock_irqrestore(&(pxmitpriv->be_pending.lock), irqL0); + list_del_init(&psta->hash_list); + pstapriv->asoc_sta_count--; + /* re-init sta_info; 20061114 */ + _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); + _r8712_init_sta_recv_priv(&psta->sta_recvpriv); + /* for A-MPDU Rx reordering buffer control, + * cancel reordering_ctrl_timer */ + for (i = 0; i < 16; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + del_timer(&preorder_ctrl->reordering_ctrl_timer); + } + spin_lock(&(pfree_sta_queue->lock)); + /* insert into free_sta_queue; 20061114 */ + list_add_tail(&psta->list, &pfree_sta_queue->queue); + spin_unlock(&(pfree_sta_queue->lock)); +} + +/* free all stainfo which in sta_hash[all] */ +void r8712_free_all_stainfo(struct _adapter *padapter) +{ + unsigned long irqL; + struct list_head *plist, *phead; + s32 index; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *pbcmc_stainfo = r8712_get_bcmc_stainfo(padapter); + + if (pstapriv->asoc_sta_count == 1) + return; + spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); + for (index = 0; index < NUM_STA; index++) { + phead = &(pstapriv->sta_hash[index]); + plist = phead->next; + while ((end_of_queue_search(phead, plist)) == false) { + psta = LIST_CONTAINOR(plist, + struct sta_info, hash_list); + plist = plist->next; + if (pbcmc_stainfo != psta) + r8712_free_stainfo(padapter, psta); + } + } + spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); +} + +/* any station allocated can be searched by hash list */ +struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) +{ + unsigned long irqL; + struct list_head *plist, *phead; + struct sta_info *psta = NULL; + u32 index; + + if (hwaddr == NULL) + return NULL; + index = wifi_mac_hash(hwaddr); + spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); + phead = &(pstapriv->sta_hash[index]); + plist = phead->next; + while ((end_of_queue_search(phead, plist)) == false) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + if ((!memcmp(psta->hwaddr, hwaddr, ETH_ALEN))) { + /* if found the matched address */ + break; + } + psta = NULL; + plist = plist->next; + } + spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); + return psta; +} + +void r8712_init_bcmc_stainfo(struct _adapter *padapter) +{ + unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct sta_priv *pstapriv = &padapter->stapriv; + + r8712_alloc_stainfo(pstapriv, bcast_addr); +} + +struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter) +{ + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + psta = r8712_get_stainfo(pstapriv, bc_addr); + return psta; +} + + +u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr) +{ + return true; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_wlan_sme.h b/kernel/drivers/staging/rtl8712/rtl871x_wlan_sme.h new file mode 100644 index 000000000..44924d5de --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_wlan_sme.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL871X_WLAN_SME_H_ +#define _RTL871X_WLAN_SME_H_ + +#define MSR_APMODE 0x0C +#define MSR_STAMODE 0x08 +#define MSR_ADHOCMODE 0x04 +#define MSR_NOLINKMODE 0x00 +#define _1M_RATE_ 0 +#define _2M_RATE_ 1 +#define _5M_RATE_ 2 +#define _11M_RATE_ 3 +#define _6M_RATE_ 4 +#define _9M_RATE_ 5 +#define _12M_RATE_ 6 +#define _18M_RATE_ 7 +#define _24M_RATE_ 8 +#define _36M_RATE_ 9 +#define _48M_RATE_ 10 +#define _54M_RATE_ 11 + +#endif + diff --git a/kernel/drivers/staging/rtl8712/rtl871x_xmit.c b/kernel/drivers/staging/rtl8712/rtl871x_xmit.c new file mode 100644 index 000000000..2e4fa8895 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_xmit.c @@ -0,0 +1,1056 @@ +/****************************************************************************** + * rtl871x_xmit.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _RTL871X_XMIT_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "wifi.h" +#include "osdep_intf.h" +#include "usb_ops.h" + + +static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8}; +static const u8 RFC1042_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0x00}; +static void init_hwxmits(struct hw_xmit *phwxmit, sint entry); +static void alloc_hwxmits(struct _adapter *padapter); +static void free_hwxmits(struct _adapter *padapter); + +static void _init_txservq(struct tx_servq *ptxservq) +{ + INIT_LIST_HEAD(&ptxservq->tx_pending); + _init_queue(&ptxservq->sta_pending); + ptxservq->qcnt = 0; +} + +void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) +{ + memset((unsigned char *)psta_xmitpriv, 0, + sizeof(struct sta_xmit_priv)); + spin_lock_init(&psta_xmitpriv->lock); + _init_txservq(&psta_xmitpriv->be_q); + _init_txservq(&psta_xmitpriv->bk_q); + _init_txservq(&psta_xmitpriv->vi_q); + _init_txservq(&psta_xmitpriv->vo_q); + INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); + INIT_LIST_HEAD(&psta_xmitpriv->apsd); +} + +sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv, + struct _adapter *padapter) +{ + sint i; + struct xmit_buf *pxmitbuf; + struct xmit_frame *pxframe; + + memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); + spin_lock_init(&pxmitpriv->lock); + /* + Please insert all the queue initialization using _init_queue below + */ + pxmitpriv->adapter = padapter; + _init_queue(&pxmitpriv->be_pending); + _init_queue(&pxmitpriv->bk_pending); + _init_queue(&pxmitpriv->vi_pending); + _init_queue(&pxmitpriv->vo_pending); + _init_queue(&pxmitpriv->bm_pending); + _init_queue(&pxmitpriv->legacy_dz_queue); + _init_queue(&pxmitpriv->apsd_queue); + _init_queue(&pxmitpriv->free_xmit_queue); + /* + Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, + and initialize free_xmit_frame below. + Please also apply free_txobj to link_up all the xmit_frames... + */ + pxmitpriv->pallocated_frame_buf = kmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4, + GFP_ATOMIC); + if (pxmitpriv->pallocated_frame_buf == NULL) { + pxmitpriv->pxmit_frame_buf = NULL; + return _FAIL; + } + pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - + ((addr_t) (pxmitpriv->pallocated_frame_buf) & 3); + pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; + for (i = 0; i < NR_XMITFRAME; i++) { + INIT_LIST_HEAD(&(pxframe->list)); + pxframe->padapter = padapter; + pxframe->frame_tag = DATA_FRAMETAG; + pxframe->pkt = NULL; + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + list_add_tail(&(pxframe->list), + &(pxmitpriv->free_xmit_queue.queue)); + pxframe++; + } + pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; + /* + init xmit hw_txqueue + */ + _r8712_init_hw_txqueue(&pxmitpriv->be_txqueue, BE_QUEUE_INX); + _r8712_init_hw_txqueue(&pxmitpriv->bk_txqueue, BK_QUEUE_INX); + _r8712_init_hw_txqueue(&pxmitpriv->vi_txqueue, VI_QUEUE_INX); + _r8712_init_hw_txqueue(&pxmitpriv->vo_txqueue, VO_QUEUE_INX); + _r8712_init_hw_txqueue(&pxmitpriv->bmc_txqueue, BMC_QUEUE_INX); + pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; + pxmitpriv->txirp_cnt = 1; + /*per AC pending irp*/ + pxmitpriv->beq_cnt = 0; + pxmitpriv->bkq_cnt = 0; + pxmitpriv->viq_cnt = 0; + pxmitpriv->voq_cnt = 0; + /*init xmit_buf*/ + _init_queue(&pxmitpriv->free_xmitbuf_queue); + _init_queue(&pxmitpriv->pending_xmitbuf_queue); + pxmitpriv->pallocated_xmitbuf = kmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4, + GFP_ATOMIC); + if (pxmitpriv->pallocated_xmitbuf == NULL) + return _FAIL; + pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - + ((addr_t)(pxmitpriv->pallocated_xmitbuf) & 3); + pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; + for (i = 0; i < NR_XMITBUFF; i++) { + INIT_LIST_HEAD(&pxmitbuf->list); + pxmitbuf->pallocated_buf = kmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ, + GFP_ATOMIC); + if (pxmitbuf->pallocated_buf == NULL) + return _FAIL; + pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ - + ((addr_t) (pxmitbuf->pallocated_buf) & + (XMITBUF_ALIGN_SZ - 1)); + r8712_xmit_resource_alloc(padapter, pxmitbuf); + list_add_tail(&pxmitbuf->list, + &(pxmitpriv->free_xmitbuf_queue.queue)); + pxmitbuf++; + } + pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; + INIT_WORK(&padapter->wkFilterRxFF0, r8712_SetFilter); + alloc_hwxmits(padapter); + init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); + tasklet_init(&pxmitpriv->xmit_tasklet, + (void(*)(unsigned long))r8712_xmit_bh, + (unsigned long)padapter); + return _SUCCESS; +} + +void _free_xmit_priv(struct xmit_priv *pxmitpriv) +{ + int i; + struct _adapter *padapter = pxmitpriv->adapter; + struct xmit_frame *pxmitframe = (struct xmit_frame *) + pxmitpriv->pxmit_frame_buf; + struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; + + if (pxmitpriv->pxmit_frame_buf == NULL) + return; + for (i = 0; i < NR_XMITFRAME; i++) { + r8712_xmit_complete(padapter, pxmitframe); + pxmitframe++; + } + for (i = 0; i < NR_XMITBUFF; i++) { + r8712_xmit_resource_free(padapter, pxmitbuf); + kfree(pxmitbuf->pallocated_buf); + pxmitbuf++; + } + kfree(pxmitpriv->pallocated_frame_buf); + kfree(pxmitpriv->pallocated_xmitbuf); + free_hwxmits(padapter); +} + +sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, + struct pkt_attrib *pattrib) +{ + struct pkt_file pktfile; + struct sta_info *psta = NULL; + struct ethhdr etherhdr; + + struct tx_cmd txdesc; + + sint bmcast; + struct sta_priv *pstapriv = &padapter->stapriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + + _r8712_open_pktfile(pkt, &pktfile); + + _r8712_pktfile_read(&pktfile, (unsigned char *)ðerhdr, ETH_HLEN); + + pattrib->ether_type = ntohs(etherhdr.h_proto); + +{ + /*If driver xmit ARP packet, driver can set ps mode to initial + * setting. It stands for getting DHCP or fix IP.*/ + if (pattrib->ether_type == 0x0806) { + if (padapter->pwrctrlpriv.pwr_mode != + padapter->registrypriv.power_mgnt) { + del_timer_sync(&pmlmepriv->dhcp_timer); + r8712_set_ps_mode(padapter, padapter->registrypriv. + power_mgnt, padapter->registrypriv.smart_ps); + } + } +} + memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); + memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); + pattrib->pctrl = 0; + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { + memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); + } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + /*firstly, filter packet not belongs to mp*/ + if (pattrib->ether_type != 0x8712) + return _FAIL; + /* for mp storing the txcmd per packet, + * according to the info of txcmd to update pattrib */ + /*get MP_TXDESC_SIZE bytes txcmd per packet*/ + _r8712_pktfile_read(&pktfile, (u8 *)&txdesc, TXDESC_SIZE); + memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + pattrib->pctrl = 1; + } + /* r8712_xmitframe_coalesce() overwrite this!*/ + pattrib->pktlen = pktfile.pkt_len; + if (ETH_P_IP == pattrib->ether_type) { + /* The following is for DHCP and ARP packet, we use cck1M to + * tx these packets and let LPS awake some time + * to prevent DHCP protocol fail */ + u8 tmp[24]; + + _r8712_pktfile_read(&pktfile, &tmp[0], 24); + pattrib->dhcp_pkt = 0; + if (pktfile.pkt_len > 282) {/*MINIMUM_DHCP_PACKET_SIZE)*/ + if (ETH_P_IP == pattrib->ether_type) {/* IP header*/ + if (((tmp[21] == 68) && (tmp[23] == 67)) || + ((tmp[21] == 67) && (tmp[23] == 68))) { + /* 68 : UDP BOOTP client + * 67 : UDP BOOTP server + * Use low rate to send DHCP packet.*/ + pattrib->dhcp_pkt = 1; + } + } + } + } + bmcast = IS_MCAST(pattrib->ra); + /* get sta_info*/ + if (bmcast) { + psta = r8712_get_bcmc_stainfo(padapter); + pattrib->mac_id = 4; + } else { + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + psta = r8712_get_stainfo(pstapriv, + get_bssid(pmlmepriv)); + pattrib->mac_id = 5; + } else { + psta = r8712_get_stainfo(pstapriv, pattrib->ra); + if (psta == NULL) /* drop the pkt */ + return _FAIL; + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + pattrib->mac_id = 5; + else + pattrib->mac_id = psta->mac_id; + } + } + + if (psta) { + pattrib->psta = psta; + } else { + /* if we cannot get psta => drrp the pkt */ + return _FAIL; + } + + pattrib->ack_policy = 0; + /* get ether_hdr_len */ + pattrib->pkt_hdrlen = ETH_HLEN; + + if (pqospriv->qos_option) + r8712_set_qos(&pktfile, pattrib); + else { + pattrib->hdrlen = WLAN_HDR_A3_LEN; + pattrib->subtype = WIFI_DATA_TYPE; + pattrib->priority = 0; + } + if (psta->ieee8021x_blocked == true) { + pattrib->encrypt = 0; + if ((pattrib->ether_type != 0x888e) && + (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) + return _FAIL; + } else + GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + pattrib->iv_len = 4; + pattrib->icv_len = 4; + break; + case _TKIP_: + pattrib->iv_len = 8; + pattrib->icv_len = 4; + if (padapter->securitypriv.busetkipkey == _FAIL) + return _FAIL; + break; + case _AES_: + pattrib->iv_len = 8; + pattrib->icv_len = 8; + break; + default: + pattrib->iv_len = 0; + pattrib->icv_len = 0; + break; + } + + if (pattrib->encrypt && + ((padapter->securitypriv.sw_encrypt == true) || + (psecuritypriv->hw_decrypted == false))) + pattrib->bswenc = true; + else + pattrib->bswenc = false; + /* if in MP_STATE, update pkt_attrib from mp_txcmd, and overwrite + * some settings above.*/ + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) + pattrib->priority = (txdesc.txdw1 >> QSEL_SHT) & 0x1f; + return _SUCCESS; +} + +static sint xmitframe_addmic(struct _adapter *padapter, + struct xmit_frame *pxmitframe) +{ + u32 curfragnum, length; + u8 *pframe, *payload, mic[8]; + struct mic_data micdata; + struct sta_info *stainfo; + struct qos_priv *pqospriv = &(padapter->mlmepriv.qospriv); + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; + sint bmcst = IS_MCAST(pattrib->ra); + + if (pattrib->psta) + stainfo = pattrib->psta; + else + stainfo = r8712_get_stainfo(&padapter->stapriv, + &pattrib->ra[0]); + if (pattrib->encrypt == _TKIP_) { + /*encode mic code*/ + if (stainfo != NULL) { + u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0}; + pframe = pxmitframe->buf_addr + TXDESC_OFFSET; + if (bmcst) { + if (!memcmp(psecuritypriv->XGrptxmickey + [psecuritypriv->XGrpKeyid].skey, + null_key, 16)) + return _FAIL; + /*start to calculate the mic code*/ + r8712_secmicsetkey(&micdata, + psecuritypriv-> + XGrptxmickey[psecuritypriv-> + XGrpKeyid].skey); + } else { + if (!memcmp(&stainfo->tkiptxmickey.skey[0], + null_key, 16)) + return _FAIL; + /* start to calculate the mic code */ + r8712_secmicsetkey(&micdata, + &stainfo->tkiptxmickey.skey[0]); + } + if (pframe[1] & 1) { /* ToDS==1 */ + r8712_secmicappend(&micdata, + &pframe[16], 6); /*DA*/ + if (pframe[1]&2) /* From Ds==1 */ + r8712_secmicappend(&micdata, + &pframe[24], 6); + else + r8712_secmicappend(&micdata, + &pframe[10], 6); + } else { /* ToDS==0 */ + r8712_secmicappend(&micdata, + &pframe[4], 6); /* DA */ + if (pframe[1]&2) /* From Ds==1 */ + r8712_secmicappend(&micdata, + &pframe[16], 6); + else + r8712_secmicappend(&micdata, + &pframe[10], 6); + } + if (pqospriv->qos_option == 1) + priority[0] = (u8)pxmitframe-> + attrib.priority; + r8712_secmicappend(&micdata, &priority[0], 4); + payload = pframe; + for (curfragnum = 0; curfragnum < pattrib->nr_frags; + curfragnum++) { + payload = (u8 *)RND4((addr_t)(payload)); + payload = payload+pattrib-> + hdrlen+pattrib->iv_len; + if ((curfragnum + 1) == pattrib->nr_frags) { + length = pattrib->last_txcmdsz - + pattrib->hdrlen - + pattrib->iv_len - + ((psecuritypriv->sw_encrypt) + ? pattrib->icv_len : 0); + r8712_secmicappend(&micdata, payload, + length); + payload = payload+length; + } else{ + length = pxmitpriv->frag_len - + pattrib->hdrlen-pattrib->iv_len - + ((psecuritypriv->sw_encrypt) ? + pattrib->icv_len : 0); + r8712_secmicappend(&micdata, payload, + length); + payload = payload + length + + pattrib->icv_len; + } + } + r8712_secgetmic(&micdata, &(mic[0])); + /* add mic code and add the mic code length in + * last_txcmdsz */ + memcpy(payload, &(mic[0]), 8); + pattrib->last_txcmdsz += 8; + payload = payload-pattrib->last_txcmdsz + 8; + } + } + return _SUCCESS; +} + +static sint xmitframe_swencrypt(struct _adapter *padapter, + struct xmit_frame *pxmitframe) +{ + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + if (pattrib->bswenc) { + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + r8712_wep_encrypt(padapter, (u8 *)pxmitframe); + break; + case _TKIP_: + r8712_tkip_encrypt(padapter, (u8 *)pxmitframe); + break; + case _AES_: + r8712_aes_encrypt(padapter, (u8 *)pxmitframe); + break; + default: + break; + } + } + return _SUCCESS; +} + +static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr, + struct pkt_attrib *pattrib) +{ + u16 *qc; + + struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + u16 *fctrl = &pwlanhdr->frame_ctl; + + memset(hdr, 0, WLANHDR_OFFSET); + SetFrameSubType(fctrl, pattrib->subtype); + if (pattrib->subtype & WIFI_DATA_TYPE) { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { + /* to_ds = 1, fr_ds = 0; */ + SetToDs(fctrl); + memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), + ETH_ALEN); + memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + /* to_ds = 0, fr_ds = 1; */ + SetFrDs(fctrl); + memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), + ETH_ALEN); + memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); + } else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) + || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) + == true)) { + memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), + ETH_ALEN); + } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), + ETH_ALEN); + } else + return _FAIL; + + if (pattrib->encrypt) + SetPrivacy(fctrl); + if (pqospriv->qos_option) { + qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); + if (pattrib->priority) + SetPriority(qc, pattrib->priority); + SetAckpolicy(qc, pattrib->ack_policy); + } + /* TODO: fill HT Control Field */ + /* Update Seq Num will be handled by f/w */ + { + struct sta_info *psta; + sint bmcst = IS_MCAST(pattrib->ra); + + if (pattrib->psta) + psta = pattrib->psta; + else { + if (bmcst) + psta = r8712_get_bcmc_stainfo(padapter); + else + psta = + r8712_get_stainfo(&padapter->stapriv, + pattrib->ra); + } + if (psta) { + psta->sta_xmitpriv.txseq_tid + [pattrib->priority]++; + psta->sta_xmitpriv.txseq_tid[pattrib->priority] + &= 0xFFF; + pattrib->seqnum = psta->sta_xmitpriv. + txseq_tid[pattrib->priority]; + SetSeqNum(hdr, pattrib->seqnum); + } + } + } + return _SUCCESS; +} + +static sint r8712_put_snap(u8 *data, u16 h_proto) +{ + struct ieee80211_snap_hdr *snap; + const u8 *oui; + + snap = (struct ieee80211_snap_hdr *)data; + snap->dsap = 0xaa; + snap->ssap = 0xaa; + snap->ctrl = 0x03; + if (h_proto == 0x8137 || h_proto == 0x80f3) + oui = P802_1H_OUI; + else + oui = RFC1042_OUI; + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; + *(u16 *)(data + SNAP_SIZE) = htons(h_proto); + return SNAP_SIZE + sizeof(u16); +} + +/* + * This sub-routine will perform all the following: + * 1. remove 802.3 header. + * 2. create wlan_header, based on the info in pxmitframe + * 3. append sta's iv/ext-iv + * 4. append LLC + * 5. move frag chunk from pframe to pxmitframe->mem + * 6. apply sw-encrypt, if necessary. + */ +sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt, + struct xmit_frame *pxmitframe) +{ + struct pkt_file pktfile; + + sint frg_len, mpdu_len, llc_sz; + u32 mem_sz; + u8 frg_inx; + addr_t addr; + u8 *pframe, *mem_start, *ptxdesc; + struct sta_info *psta; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + u8 *pbuf_start; + sint bmcst = IS_MCAST(pattrib->ra); + + if (pattrib->psta == NULL) + return _FAIL; + psta = pattrib->psta; + if (pxmitframe->buf_addr == NULL) + return _FAIL; + pbuf_start = pxmitframe->buf_addr; + ptxdesc = pbuf_start; + mem_start = pbuf_start + TXDESC_OFFSET; + if (make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) + return _FAIL; + _r8712_open_pktfile(pkt, &pktfile); + _r8712_pktfile_read(&pktfile, NULL, (uint) pattrib->pkt_hdrlen); + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + /* truncate TXDESC_SIZE bytes txcmd if at mp mode for 871x */ + if (pattrib->ether_type == 0x8712) { + /* take care - update_txdesc overwrite this */ + _r8712_pktfile_read(&pktfile, ptxdesc, TXDESC_SIZE); + } + } + pattrib->pktlen = pktfile.pkt_len; + frg_inx = 0; + frg_len = pxmitpriv->frag_len - 4; + while (1) { + llc_sz = 0; + mpdu_len = frg_len; + pframe = mem_start; + SetMFrag(mem_start); + pframe += pattrib->hdrlen; + mpdu_len -= pattrib->hdrlen; + /* adding icv, if necessary...*/ + if (pattrib->iv_len) { + if (psta != NULL) { + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + WEP_IV(pattrib->iv, psta->txpn, + (u8)psecuritypriv-> + PrivacyKeyIndex); + break; + case _TKIP_: + if (bmcst) + TKIP_IV(pattrib->iv, + psta->txpn, + (u8)psecuritypriv-> + XGrpKeyid); + else + TKIP_IV(pattrib->iv, psta->txpn, + 0); + break; + case _AES_: + if (bmcst) + AES_IV(pattrib->iv, psta->txpn, + (u8)psecuritypriv-> + XGrpKeyid); + else + AES_IV(pattrib->iv, psta->txpn, + 0); + break; + } + } + memcpy(pframe, pattrib->iv, pattrib->iv_len); + pframe += pattrib->iv_len; + mpdu_len -= pattrib->iv_len; + } + if (frg_inx == 0) { + llc_sz = r8712_put_snap(pframe, pattrib->ether_type); + pframe += llc_sz; + mpdu_len -= llc_sz; + } + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) + mpdu_len -= pattrib->icv_len; + if (bmcst) + mem_sz = _r8712_pktfile_read(&pktfile, pframe, + pattrib->pktlen); + else + mem_sz = _r8712_pktfile_read(&pktfile, pframe, + mpdu_len); + pframe += mem_sz; + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { + memcpy(pframe, pattrib->icv, pattrib->icv_len); + pframe += pattrib->icv_len; + } + frg_inx++; + if (bmcst || (r8712_endofpktfile(&pktfile) == true)) { + pattrib->nr_frags = frg_inx; + pattrib->last_txcmdsz = pattrib->hdrlen + + pattrib->iv_len + + ((pattrib->nr_frags == 1) ? + llc_sz : 0) + + ((pattrib->bswenc) ? + pattrib->icv_len : 0) + mem_sz; + ClearMFrag(mem_start); + break; + } + addr = (addr_t)(pframe); + mem_start = (unsigned char *)RND4(addr) + TXDESC_OFFSET; + memcpy(mem_start, pbuf_start + TXDESC_OFFSET, pattrib->hdrlen); + } + + if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) + return _FAIL; + xmitframe_swencrypt(padapter, pxmitframe); + return _SUCCESS; +} + +void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len) +{ + uint protection; + u8 *perp; + sint erp_len; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + + switch (pxmitpriv->vcs_setting) { + case DISABLE_VCS: + pxmitpriv->vcs = NONE_VCS; + break; + case ENABLE_VCS: + break; + case AUTO_VCS: + default: + perp = r8712_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); + if (perp == NULL) + pxmitpriv->vcs = NONE_VCS; + else { + protection = (*(perp + 2)) & BIT(1); + if (protection) { + if (pregistrypriv->vcs_type == RTS_CTS) + pxmitpriv->vcs = RTS_CTS; + else + pxmitpriv->vcs = CTS_TO_SELF; + } else + pxmitpriv->vcs = NONE_VCS; + } + break; + } +} + +struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv) +{ + unsigned long irqL; + struct xmit_buf *pxmitbuf = NULL; + struct list_head *plist, *phead; + struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; + + spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); + if (list_empty(&pfree_xmitbuf_queue->queue)) + pxmitbuf = NULL; + else { + phead = &pfree_xmitbuf_queue->queue; + plist = phead->next; + pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); + list_del_init(&(pxmitbuf->list)); + } + if (pxmitbuf != NULL) + pxmitpriv->free_xmitbuf_cnt--; + spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); + return pxmitbuf; +} + +int r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) +{ + unsigned long irqL; + struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; + + if (pxmitbuf == NULL) + return _FAIL; + spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); + list_del_init(&pxmitbuf->list); + list_add_tail(&(pxmitbuf->list), &pfree_xmitbuf_queue->queue); + pxmitpriv->free_xmitbuf_cnt++; + spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); + return _SUCCESS; +} + +/* +Calling context: +1. OS_TXENTRY +2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) + +If we turn on USE_RXTHREAD, then, no need for critical section. +Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... + +Must be very very cautious... + +*/ + +struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv) +{ + /* + Please remember to use all the osdep_service api, + and lock/unlock or _enter/_exit critical to protect + pfree_xmit_queue + */ + unsigned long irqL; + struct xmit_frame *pxframe = NULL; + struct list_head *plist, *phead; + struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; + + spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); + if (list_empty(&pfree_xmit_queue->queue)) + pxframe = NULL; + else { + phead = &pfree_xmit_queue->queue; + plist = phead->next; + pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); + list_del_init(&(pxframe->list)); + } + if (pxframe != NULL) { + pxmitpriv->free_xmitframe_cnt--; + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + pxframe->attrib.psta = NULL; + pxframe->pkt = NULL; + } + spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL); + return pxframe; +} + +void r8712_free_xmitframe(struct xmit_priv *pxmitpriv, + struct xmit_frame *pxmitframe) +{ + unsigned long irqL; + struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; + struct _adapter *padapter = pxmitpriv->adapter; + + if (pxmitframe == NULL) + return; + spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); + list_del_init(&pxmitframe->list); + if (pxmitframe->pkt) + pxmitframe->pkt = NULL; + list_add_tail(&pxmitframe->list, &pfree_xmit_queue->queue); + pxmitpriv->free_xmitframe_cnt++; + spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL); + if (netif_queue_stopped(padapter->pnetdev)) + netif_wake_queue(padapter->pnetdev); +} + +void r8712_free_xmitframe_ex(struct xmit_priv *pxmitpriv, + struct xmit_frame *pxmitframe) +{ + if (pxmitframe == NULL) + return; + if (pxmitframe->frame_tag == DATA_FRAMETAG) + r8712_free_xmitframe(pxmitpriv, pxmitframe); +} + +void r8712_free_xmitframe_queue(struct xmit_priv *pxmitpriv, + struct __queue *pframequeue) +{ + unsigned long irqL; + struct list_head *plist, *phead; + struct xmit_frame *pxmitframe; + + spin_lock_irqsave(&(pframequeue->lock), irqL); + phead = &pframequeue->queue; + plist = phead->next; + while (end_of_queue_search(phead, plist) == false) { + pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); + plist = plist->next; + r8712_free_xmitframe(pxmitpriv, pxmitframe); + } + spin_unlock_irqrestore(&(pframequeue->lock), irqL); +} + +static inline struct tx_servq *get_sta_pending(struct _adapter *padapter, + struct __queue **ppstapending, + struct sta_info *psta, sint up) +{ + + struct tx_servq *ptxservq; + struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; + + switch (up) { + case 1: + case 2: + ptxservq = &(psta->sta_xmitpriv.bk_q); + *ppstapending = &padapter->xmitpriv.bk_pending; + (phwxmits+3)->accnt++; + break; + case 4: + case 5: + ptxservq = &(psta->sta_xmitpriv.vi_q); + *ppstapending = &padapter->xmitpriv.vi_pending; + (phwxmits+1)->accnt++; + break; + case 6: + case 7: + ptxservq = &(psta->sta_xmitpriv.vo_q); + *ppstapending = &padapter->xmitpriv.vo_pending; + (phwxmits+0)->accnt++; + break; + case 0: + case 3: + default: + ptxservq = &(psta->sta_xmitpriv.be_q); + *ppstapending = &padapter->xmitpriv.be_pending; + (phwxmits + 2)->accnt++; + break; + } + return ptxservq; +} + +/* + * Will enqueue pxmitframe to the proper queue, and indicate it + * to xx_pending list..... + */ +sint r8712_xmit_classifier(struct _adapter *padapter, + struct xmit_frame *pxmitframe) +{ + unsigned long irqL0; + struct __queue *pstapending; + struct sta_info *psta; + struct tx_servq *ptxservq; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + sint bmcst = IS_MCAST(pattrib->ra); + + if (pattrib->psta) + psta = pattrib->psta; + else { + if (bmcst) + psta = r8712_get_bcmc_stainfo(padapter); + else { + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) + psta = r8712_get_stainfo(pstapriv, + get_bssid(pmlmepriv)); + else + psta = r8712_get_stainfo(pstapriv, pattrib->ra); + } + } + if (psta == NULL) + return _FAIL; + ptxservq = get_sta_pending(padapter, &pstapending, + psta, pattrib->priority); + spin_lock_irqsave(&pstapending->lock, irqL0); + if (list_empty(&ptxservq->tx_pending)) + list_add_tail(&ptxservq->tx_pending, &pstapending->queue); + list_add_tail(&pxmitframe->list, &ptxservq->sta_pending.queue); + ptxservq->qcnt++; + spin_unlock_irqrestore(&pstapending->lock, irqL0); + return _SUCCESS; +} + +static void alloc_hwxmits(struct _adapter *padapter) +{ + struct hw_xmit *hwxmits; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; + pxmitpriv->hwxmits = kmalloc_array(pxmitpriv->hwxmit_entry, + sizeof(struct hw_xmit), GFP_ATOMIC); + if (pxmitpriv->hwxmits == NULL) + return; + hwxmits = pxmitpriv->hwxmits; + if (pxmitpriv->hwxmit_entry == 5) { + pxmitpriv->bmc_txqueue.head = 0; + hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; + hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; + pxmitpriv->vo_txqueue.head = 0; + hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; + hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; + pxmitpriv->vi_txqueue.head = 0; + hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; + hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; + pxmitpriv->bk_txqueue.head = 0; + hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; + hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; + pxmitpriv->be_txqueue.head = 0; + hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; + hwxmits[4] .sta_queue = &pxmitpriv->be_pending; + } else if (pxmitpriv->hwxmit_entry == 4) { + pxmitpriv->vo_txqueue.head = 0; + hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; + hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; + pxmitpriv->vi_txqueue.head = 0; + hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; + hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; + pxmitpriv->be_txqueue.head = 0; + hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; + hwxmits[2] .sta_queue = &pxmitpriv->be_pending; + pxmitpriv->bk_txqueue.head = 0; + hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; + hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; + } +} + +static void free_hwxmits(struct _adapter *padapter) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + kfree(pxmitpriv->hwxmits); +} + +static void init_hwxmits(struct hw_xmit *phwxmit, sint entry) +{ + sint i; + + for (i = 0; i < entry; i++, phwxmit++) { + spin_lock_init(&phwxmit->xmit_lock); + INIT_LIST_HEAD(&phwxmit->pending); + phwxmit->txcmdcnt = 0; + phwxmit->accnt = 0; + } +} + +void xmitframe_xmitbuf_attach(struct xmit_frame *pxmitframe, + struct xmit_buf *pxmitbuf) +{ + /* pxmitbuf attach to pxmitframe */ + pxmitframe->pxmitbuf = pxmitbuf; + /* urb and irp connection */ + pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; + /* buffer addr assoc */ + pxmitframe->buf_addr = pxmitbuf->pbuf; + /* pxmitframe attach to pxmitbuf */ + pxmitbuf->priv_data = pxmitframe; +} + +/* + * tx_action == 0 == no frames to transmit + * tx_action > 0 ==> we have frames to transmit + * tx_action < 0 ==> we have frames to transmit, but TXFF is not even enough + * to transmit 1 frame. + */ + +int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe) +{ + unsigned long irqL; + int ret; + struct xmit_buf *pxmitbuf = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + r8712_do_queue_select(padapter, pattrib); + spin_lock_irqsave(&pxmitpriv->lock, irqL); + if (r8712_txframes_sta_ac_pending(padapter, pattrib) > 0) { + ret = false; + r8712_xmit_enqueue(padapter, pxmitframe); + spin_unlock_irqrestore(&pxmitpriv->lock, irqL); + return ret; + } + pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); + if (pxmitbuf == NULL) { /*enqueue packet*/ + ret = false; + r8712_xmit_enqueue(padapter, pxmitframe); + spin_unlock_irqrestore(&pxmitpriv->lock, irqL); + } else { /*dump packet directly*/ + spin_unlock_irqrestore(&pxmitpriv->lock, irqL); + ret = true; + xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); + r8712_xmit_direct(padapter, pxmitframe); + } + return ret; +} diff --git a/kernel/drivers/staging/rtl8712/rtl871x_xmit.h b/kernel/drivers/staging/rtl8712/rtl871x_xmit.h new file mode 100644 index 000000000..a9633c3f7 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/rtl871x_xmit.h @@ -0,0 +1,302 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _RTL871X_XMIT_H_ +#define _RTL871X_XMIT_H_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "xmit_osdep.h" + +#ifdef CONFIG_R8712_TX_AGGR +#define MAX_XMITBUF_SZ (16384) +#else +#define MAX_XMITBUF_SZ (2048) +#endif + +#define NR_XMITBUFF (4) + +#ifdef CONFIG_R8712_TX_AGGR +#define AGGR_NR_HIGH_BOUND (4) /*(8) */ +#define AGGR_NR_LOW_BOUND (2) +#endif + +#define XMITBUF_ALIGN_SZ 512 +#define TX_GUARD_BAND 5 +#define MAX_NUMBLKS (1) + +/* Fixed the Big Endian bug when using the software driver encryption.*/ +#define WEP_IV(pattrib_iv, txpn, keyidx)\ +do { \ + pattrib_iv[0] = txpn._byte_.TSC0;\ + pattrib_iv[1] = txpn._byte_.TSC1;\ + pattrib_iv[2] = txpn._byte_.TSC2;\ + pattrib_iv[3] = ((keyidx & 0x3)<<6);\ + txpn.val = (txpn.val == 0xffffff) ? 0 : (txpn.val+1);\ +} while (0) + +/* Fixed the Big Endian bug when doing the Tx. + * The Linksys WRH54G will check this.*/ +#define TKIP_IV(pattrib_iv, txpn, keyidx)\ +do { \ + pattrib_iv[0] = txpn._byte_.TSC1;\ + pattrib_iv[1] = (txpn._byte_.TSC1 | 0x20) & 0x7f;\ + pattrib_iv[2] = txpn._byte_.TSC0;\ + pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\ + pattrib_iv[4] = txpn._byte_.TSC2;\ + pattrib_iv[5] = txpn._byte_.TSC3;\ + pattrib_iv[6] = txpn._byte_.TSC4;\ + pattrib_iv[7] = txpn._byte_.TSC5;\ + txpn.val = txpn.val == 0xffffffffffffULL ? 0 : \ + (txpn.val+1);\ +} while (0) + +#define AES_IV(pattrib_iv, txpn, keyidx)\ +do { \ + pattrib_iv[0] = txpn._byte_.TSC0;\ + pattrib_iv[1] = txpn._byte_.TSC1;\ + pattrib_iv[2] = 0;\ + pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\ + pattrib_iv[4] = txpn._byte_.TSC2;\ + pattrib_iv[5] = txpn._byte_.TSC3;\ + pattrib_iv[6] = txpn._byte_.TSC4;\ + pattrib_iv[7] = txpn._byte_.TSC5;\ + txpn.val = txpn.val == 0xffffffffffffULL ? 0 : \ + (txpn.val+1);\ +} while (0) + +struct hw_xmit { + spinlock_t xmit_lock; + struct list_head pending; + struct __queue *sta_queue; + struct hw_txqueue *phwtxqueue; + sint txcmdcnt; + int accnt; +}; + +struct pkt_attrib { + u8 type; + u8 subtype; + u8 bswenc; + u8 dhcp_pkt; + + u16 seqnum; + u16 ether_type; + u16 pktlen; /* the original 802.3 pkt raw_data len + * (not include ether_hdr data) */ + u16 last_txcmdsz; + + u8 pkt_hdrlen; /*the original 802.3 pkt header len*/ + u8 hdrlen; /*the WLAN Header Len*/ + u8 nr_frags; + u8 ack_policy; + u8 mac_id; + u8 vcs_mode; /*virtual carrier sense method*/ + u8 pctrl;/*per packet txdesc control enable*/ + u8 qsel; + + u8 priority; + u8 encrypt; /* when 0 indicate no encrypt. when non-zero, + * indicate the encrypt algorithm*/ + u8 iv_len; + u8 icv_len; + unsigned char iv[8]; + unsigned char icv[8]; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 ta[ETH_ALEN]; + u8 ra[ETH_ALEN]; + struct sta_info *psta; +}; + +#define WLANHDR_OFFSET 64 +#define DATA_FRAMETAG 0x01 +#define L2_FRAMETAG 0x02 +#define MGNT_FRAMETAG 0x03 +#define AMSDU_FRAMETAG 0x04 +#define EII_FRAMETAG 0x05 +#define IEEE8023_FRAMETAG 0x06 +#define MP_FRAMETAG 0x07 +#define TXAGG_FRAMETAG 0x08 + +struct xmit_buf { + struct list_head list; + + u8 *pallocated_buf; + u8 *pbuf; + void *priv_data; + struct urb *pxmit_urb[8]; + u32 aggr_nr; +}; + +struct xmit_frame { + struct list_head list; + struct pkt_attrib attrib; + _pkt *pkt; + int frame_tag; + struct _adapter *padapter; + u8 *buf_addr; + struct xmit_buf *pxmitbuf; + u8 *mem_addr; + u16 sz[8]; + struct urb *pxmit_urb[8]; + u8 bpending[8]; + u8 last[8]; +}; + +struct tx_servq { + struct list_head tx_pending; + struct __queue sta_pending; + int qcnt; +}; + +struct sta_xmit_priv { + spinlock_t lock; + sint option; + sint apsd_setting; /* When bit mask is on, the associated edca + * queue supports APSD.*/ + struct tx_servq be_q; /* priority == 0,3 */ + struct tx_servq bk_q; /* priority == 1,2*/ + struct tx_servq vi_q; /*priority == 4,5*/ + struct tx_servq vo_q; /*priority == 6,7*/ + struct list_head legacy_dz; + struct list_head apsd; + u16 txseq_tid[16]; + uint sta_tx_bytes; + u64 sta_tx_pkts; + uint sta_tx_fail; +}; + +struct hw_txqueue { + /*volatile*/ sint head; + /*volatile*/ sint tail; + /*volatile*/ sint free_sz; /*in units of 64 bytes*/ + /*volatile*/ sint free_cmdsz; + /*volatile*/ sint txsz[8]; + uint ff_hwaddr; + uint cmd_hwaddr; + sint ac_tag; +}; + +struct xmit_priv { + spinlock_t lock; + struct __queue be_pending; + struct __queue bk_pending; + struct __queue vi_pending; + struct __queue vo_pending; + struct __queue bm_pending; + struct __queue legacy_dz_queue; + struct __queue apsd_queue; + u8 *pallocated_frame_buf; + u8 *pxmit_frame_buf; + uint free_xmitframe_cnt; + uint mapping_addr; + uint pkt_sz; + struct __queue free_xmit_queue; + struct hw_txqueue be_txqueue; + struct hw_txqueue bk_txqueue; + struct hw_txqueue vi_txqueue; + struct hw_txqueue vo_txqueue; + struct hw_txqueue bmc_txqueue; + uint frag_len; + struct _adapter *adapter; + u8 vcs_setting; + u8 vcs; + u8 vcs_type; + u16 rts_thresh; + uint tx_bytes; + u64 tx_pkts; + uint tx_drop; + struct hw_xmit *hwxmits; + u8 hwxmit_entry; + u8 txirp_cnt; + struct tasklet_struct xmit_tasklet; + struct work_struct xmit_pipe4_reset_wi; + struct work_struct xmit_pipe6_reset_wi; + struct work_struct xmit_piped_reset_wi; + /*per AC pending irp*/ + int beq_cnt; + int bkq_cnt; + int viq_cnt; + int voq_cnt; + struct __queue free_amsdu_xmit_queue; + u8 *pallocated_amsdu_frame_buf; + u8 *pxmit_amsdu_frame_buf; + uint free_amsdu_xmitframe_cnt; + struct __queue free_txagg_xmit_queue; + u8 *pallocated_txagg_frame_buf; + u8 *pxmit_txagg_frame_buf; + uint free_txagg_xmitframe_cnt; + int cmdseq; + struct __queue free_xmitbuf_queue; + struct __queue pending_xmitbuf_queue; + u8 *pallocated_xmitbuf; + u8 *pxmitbuf; + uint free_xmitbuf_cnt; +}; + +static inline struct __queue *get_free_xmit_queue( + struct xmit_priv *pxmitpriv) +{ + return &(pxmitpriv->free_xmit_queue); +} + +int r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, + struct xmit_buf *pxmitbuf); +struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv); +void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len); +struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv); +void r8712_free_xmitframe(struct xmit_priv *pxmitpriv, + struct xmit_frame *pxmitframe); +void r8712_free_xmitframe_queue(struct xmit_priv *pxmitpriv, + struct __queue *pframequeue); +sint r8712_xmit_classifier(struct _adapter *padapter, + struct xmit_frame *pxmitframe); +sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt, + struct xmit_frame *pxmitframe); +sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag); +void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv); +sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, + struct pkt_attrib *pattrib); +int r8712_txframes_sta_ac_pending(struct _adapter *padapter, + struct pkt_attrib *pattrib); +sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv, + struct _adapter *padapter); +void _free_xmit_priv(struct xmit_priv *pxmitpriv); +void r8712_free_xmitframe_ex(struct xmit_priv *pxmitpriv, + struct xmit_frame *pxmitframe); +int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe); +int r8712_xmit_enqueue(struct _adapter *padapter, + struct xmit_frame *pxmitframe); +int r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe); +void r8712_xmit_bh(void *priv); + +void xmitframe_xmitbuf_attach(struct xmit_frame *pxmitframe, + struct xmit_buf *pxmitbuf); + +#include "rtl8712_xmit.h" + +#endif /*_RTL871X_XMIT_H_*/ + diff --git a/kernel/drivers/staging/rtl8712/sta_info.h b/kernel/drivers/staging/rtl8712/sta_info.h new file mode 100644 index 000000000..742dfa0ca --- /dev/null +++ b/kernel/drivers/staging/rtl8712/sta_info.h @@ -0,0 +1,146 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __STA_INFO_H_ +#define __STA_INFO_H_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "wifi.h" + +#define NUM_STA 32 +#define NUM_ACL 64 + + +/* if mode ==0, then the sta is allowed once the addr is hit. + * if mode ==1, then the sta is rejected once the addr is non-hit. + */ +struct wlan_acl_node { + struct list_head list; + u8 addr[ETH_ALEN]; + u8 mode; +}; + +struct wlan_acl_pool { + struct wlan_acl_node aclnode[NUM_ACL]; +}; + +struct stainfo_stats { + + uint rx_pkts; + uint rx_bytes; + u64 tx_pkts; + uint tx_bytes; +}; + +struct sta_info { + spinlock_t lock; + struct list_head list; /*free_sta_queue*/ + struct list_head hash_list; /*sta_hash*/ + struct sta_xmit_priv sta_xmitpriv; + struct sta_recv_priv sta_recvpriv; + uint state; + uint aid; + uint mac_id; + uint qos_option; + u8 hwaddr[ETH_ALEN]; + uint ieee8021x_blocked; /*0: allowed, 1:blocked */ + uint XPrivacy; /*aes, tkip...*/ + union Keytype tkiptxmickey; + union Keytype tkiprxmickey; + union Keytype x_UncstKey; + union pn48 txpn; /* PN48 used for Unicast xmit.*/ + union pn48 rxpn; /* PN48 used for Unicast recv.*/ + u8 bssrateset[16]; + uint bssratelen; + s32 rssi; + s32 signal_quality; + struct stainfo_stats sta_stats; + /*for A-MPDU Rx reordering buffer control */ + struct recv_reorder_ctrl recvreorder_ctrl[16]; + struct ht_priv htpriv; + /* Notes: + * STA_Mode: + * curr_network(mlme_priv/security_priv/qos/ht) + * + sta_info: (STA & AP) CAP/INFO + * scan_q: AP CAP/INFO + * AP_Mode: + * curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO + * sta_info: (AP & STA) CAP/INFO + */ + struct list_head asoc_list; + struct list_head auth_list; + unsigned int expire_to; + unsigned int auth_seq; + unsigned int authalg; + unsigned char chg_txt[128]; + unsigned int tx_ra_bitmap; +}; + +struct sta_priv { + u8 *pallocated_stainfo_buf; + u8 *pstainfo_buf; + struct __queue free_sta_queue; + spinlock_t sta_hash_lock; + struct list_head sta_hash[NUM_STA]; + int asoc_sta_count; + struct __queue sleep_q; + struct __queue wakeup_q; + struct _adapter *padapter; + struct list_head asoc_list; + struct list_head auth_list; + unsigned int auth_to; /* sec, time to expire in authenticating. */ + unsigned int assoc_to; /* sec, time to expire before associating. */ + unsigned int expire_to; /* sec , time to expire after associated. */ +}; + +static inline u32 wifi_mac_hash(u8 *mac) +{ + u32 x; + + x = mac[0]; + x = (x << 2) ^ mac[1]; + x = (x << 2) ^ mac[2]; + x = (x << 2) ^ mac[3]; + x = (x << 2) ^ mac[4]; + x = (x << 2) ^ mac[5]; + x ^= x >> 8; + x = x & (NUM_STA - 1); + return x; +} + +u32 _r8712_init_sta_priv(struct sta_priv *pstapriv); +u32 _r8712_free_sta_priv(struct sta_priv *pstapriv); +struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, + u8 *hwaddr); +void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta); +void r8712_free_all_stainfo(struct _adapter *padapter); +struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr); +void r8712_init_bcmc_stainfo(struct _adapter *padapter); +struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter); +u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr); + +#endif /* _STA_INFO_H_ */ + diff --git a/kernel/drivers/staging/rtl8712/usb_halinit.c b/kernel/drivers/staging/rtl8712/usb_halinit.c new file mode 100644 index 000000000..b4ae11a78 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/usb_halinit.c @@ -0,0 +1,317 @@ +/****************************************************************************** + * usb_halinit.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _HCI_HAL_INIT_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "usb_ops.h" +#include "usb_osintf.h" + +u8 r8712_usb_hal_bus_init(struct _adapter *padapter) +{ + u8 val8 = 0; + u8 ret = _SUCCESS; + int PollingCnt = 20; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + + if (pregistrypriv->chip_version == RTL8712_FPGA) { + val8 = 0x01; + /* switch to 80M clock */ + r8712_write8(padapter, SYS_CLKR, val8); + val8 = r8712_read8(padapter, SPS1_CTRL); + val8 = val8 | 0x01; + /* enable VSPS12 LDO Macro block */ + r8712_write8(padapter, SPS1_CTRL, val8); + val8 = r8712_read8(padapter, AFE_MISC); + val8 = val8 | 0x01; + /* Enable AFE Macro Block's Bandgap */ + r8712_write8(padapter, AFE_MISC, val8); + val8 = r8712_read8(padapter, LDOA15_CTRL); + val8 = val8 | 0x01; + /* enable LDOA15 block */ + r8712_write8(padapter, LDOA15_CTRL, val8); + val8 = r8712_read8(padapter, SPS1_CTRL); + val8 = val8 | 0x02; + /* Enable VSPS12_SW Macro Block */ + r8712_write8(padapter, SPS1_CTRL, val8); + val8 = r8712_read8(padapter, AFE_MISC); + val8 = val8 | 0x02; + /* Enable AFE Macro Block's Mbias */ + r8712_write8(padapter, AFE_MISC, val8); + val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1); + val8 = val8 | 0x08; + /* isolate PCIe Analog 1.2V to PCIe 3.3V and PCIE Digital */ + r8712_write8(padapter, SYS_ISO_CTRL + 1, val8); + val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1); + val8 = val8 & 0xEF; + /* attatch AFE PLL to MACTOP/BB/PCIe Digital */ + r8712_write8(padapter, SYS_ISO_CTRL + 1, val8); + val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1); + val8 = val8 & 0xFB; + /* enable AFE clock */ + r8712_write8(padapter, AFE_XTAL_CTRL + 1, val8); + val8 = r8712_read8(padapter, AFE_PLL_CTRL); + val8 = val8 | 0x01; + /* Enable AFE PLL Macro Block */ + r8712_write8(padapter, AFE_PLL_CTRL, val8); + val8 = 0xEE; + /* release isolation AFE PLL & MD */ + r8712_write8(padapter, SYS_ISO_CTRL, val8); + val8 = r8712_read8(padapter, SYS_CLKR + 1); + val8 = val8 | 0x08; + /* enable MAC clock */ + r8712_write8(padapter, SYS_CLKR + 1, val8); + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + val8 = val8 | 0x08; + /* enable Core digital and enable IOREG R/W */ + r8712_write8(padapter, SYS_FUNC_EN + 1, val8); + val8 = val8 | 0x80; + /* enable REG_EN */ + r8712_write8(padapter, SYS_FUNC_EN + 1, val8); + val8 = r8712_read8(padapter, SYS_CLKR + 1); + val8 = (val8 | 0x80) & 0xBF; + /* switch the control path */ + r8712_write8(padapter, SYS_CLKR + 1, val8); + val8 = 0xFC; + r8712_write8(padapter, CR, val8); + val8 = 0x37; + r8712_write8(padapter, CR + 1, val8); + /* reduce EndPoint & init it */ + r8712_write8(padapter, 0x102500ab, r8712_read8(padapter, + 0x102500ab) | BIT(6) | BIT(7)); + /* consideration of power consumption - init */ + r8712_write8(padapter, 0x10250008, r8712_read8(padapter, + 0x10250008) & 0xfffffffb); + } else if (pregistrypriv->chip_version == RTL8712_1stCUT) { + /* Initialization for power on sequence, */ + r8712_write8(padapter, SPS0_CTRL + 1, 0x53); + r8712_write8(padapter, SPS0_CTRL, 0x57); + /* Enable AFE Macro Block's Bandgap and Enable AFE Macro + * Block's Mbias + */ + val8 = r8712_read8(padapter, AFE_MISC); + r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN | + AFE_MISC_MBEN)); + /* Enable LDOA15 block */ + val8 = r8712_read8(padapter, LDOA15_CTRL); + r8712_write8(padapter, LDOA15_CTRL, (val8 | LDA15_EN)); + val8 = r8712_read8(padapter, SPS1_CTRL); + r8712_write8(padapter, SPS1_CTRL, (val8 | SPS1_LDEN)); + msleep(20); + /* Enable Switch Regulator Block */ + val8 = r8712_read8(padapter, SPS1_CTRL); + r8712_write8(padapter, SPS1_CTRL, (val8 | SPS1_SWEN)); + r8712_write32(padapter, SPS1_CTRL, 0x00a7b267); + val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1); + r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 | 0x08)); + /* Engineer Packet CP test Enable */ + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x20)); + val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1); + r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 & 0x6F)); + /* Enable AFE clock */ + val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1); + r8712_write8(padapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb)); + /* Enable AFE PLL Macro Block */ + val8 = r8712_read8(padapter, AFE_PLL_CTRL); + r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11)); + /* Attach AFE PLL to MACTOP/BB/PCIe Digital */ + val8 = r8712_read8(padapter, SYS_ISO_CTRL); + r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE)); + /* Switch to 40M clock */ + val8 = r8712_read8(padapter, SYS_CLKR); + r8712_write8(padapter, SYS_CLKR, val8 & (~SYS_CLKSEL)); + /* SSC Disable */ + val8 = r8712_read8(padapter, SYS_CLKR); + /* Enable MAC clock */ + val8 = r8712_read8(padapter, SYS_CLKR + 1); + r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x18)); + /* Revised POS, */ + r8712_write8(padapter, PMC_FSM, 0x02); + /* Enable Core digital and enable IOREG R/W */ + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x08)); + /* Enable REG_EN */ + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x80)); + /* Switch the control path to FW */ + val8 = r8712_read8(padapter, SYS_CLKR + 1); + r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF); + r8712_write8(padapter, CR, 0xFC); + r8712_write8(padapter, CR + 1, 0x37); + /* Fix the RX FIFO issue(usb error), */ + val8 = r8712_read8(padapter, 0x1025FE5c); + r8712_write8(padapter, 0x1025FE5c, (val8|BIT(7))); + val8 = r8712_read8(padapter, 0x102500ab); + r8712_write8(padapter, 0x102500ab, (val8|BIT(6)|BIT(7))); + /* For power save, used this in the bit file after 970621 */ + val8 = r8712_read8(padapter, SYS_CLKR); + r8712_write8(padapter, SYS_CLKR, val8&(~CPU_CLKSEL)); + } else if (pregistrypriv->chip_version == RTL8712_2ndCUT || + pregistrypriv->chip_version == RTL8712_3rdCUT) { + /* Initialization for power on sequence, + * E-Fuse leakage prevention sequence + */ + r8712_write8(padapter, 0x37, 0xb0); + msleep(20); + r8712_write8(padapter, 0x37, 0x30); + /* Set control path switch to HW control and reset Digital Core, + * CPU Core and MAC I/O to solve FW download fail when system + * from resume sate. + */ + val8 = r8712_read8(padapter, SYS_CLKR + 1); + if (val8 & 0x80) { + val8 &= 0x3f; + r8712_write8(padapter, SYS_CLKR + 1, val8); + } + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + val8 &= 0x73; + r8712_write8(padapter, SYS_FUNC_EN + 1, val8); + msleep(20); + /* Revised POS, */ + /* Enable AFE Macro Block's Bandgap and Enable AFE Macro + * Block's Mbias */ + r8712_write8(padapter, SPS0_CTRL + 1, 0x53); + r8712_write8(padapter, SPS0_CTRL, 0x57); + val8 = r8712_read8(padapter, AFE_MISC); + /*Bandgap*/ + r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN)); + r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN | + AFE_MISC_MBEN | AFE_MISC_I32_EN)); + /* Enable PLL Power (LDOA15V) */ + val8 = r8712_read8(padapter, LDOA15_CTRL); + r8712_write8(padapter, LDOA15_CTRL, (val8 | LDA15_EN)); + /* Enable LDOV12D block */ + val8 = r8712_read8(padapter, LDOV12D_CTRL); + r8712_write8(padapter, LDOV12D_CTRL, (val8 | LDV12_EN)); + val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1); + r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 | 0x08)); + /* Engineer Packet CP test Enable */ + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x20)); + /* Support 64k IMEM */ + val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1); + r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 & 0x68)); + /* Enable AFE clock */ + val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1); + r8712_write8(padapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb)); + /* Enable AFE PLL Macro Block */ + val8 = r8712_read8(padapter, AFE_PLL_CTRL); + r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11)); + /* Some sample will download fw failure. The clock will be + * stable with 500 us delay after reset the PLL + * TODO: When usleep is added to kernel, change next 3 + * udelay(500) to usleep(500) + */ + udelay(500); + r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x51)); + udelay(500); + r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11)); + udelay(500); + /* Attach AFE PLL to MACTOP/BB/PCIe Digital */ + val8 = r8712_read8(padapter, SYS_ISO_CTRL); + r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE)); + /* Switch to 40M clock */ + r8712_write8(padapter, SYS_CLKR, 0x00); + /* CPU Clock and 80M Clock SSC Disable to overcome FW download + * fail timing issue. + */ + val8 = r8712_read8(padapter, SYS_CLKR); + r8712_write8(padapter, SYS_CLKR, (val8 | 0xa0)); + /* Enable MAC clock */ + val8 = r8712_read8(padapter, SYS_CLKR + 1); + r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x18)); + /* Revised POS, */ + r8712_write8(padapter, PMC_FSM, 0x02); + /* Enable Core digital and enable IOREG R/W */ + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x08)); + /* Enable REG_EN */ + val8 = r8712_read8(padapter, SYS_FUNC_EN + 1); + r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x80)); + /* Switch the control path to FW */ + val8 = r8712_read8(padapter, SYS_CLKR + 1); + r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF); + r8712_write8(padapter, CR, 0xFC); + r8712_write8(padapter, CR + 1, 0x37); + /* Fix the RX FIFO issue(usb error), 970410 */ + val8 = r8712_read8(padapter, 0x1025FE5c); + r8712_write8(padapter, 0x1025FE5c, (val8 | BIT(7))); + /* For power save, used this in the bit file after 970621 */ + val8 = r8712_read8(padapter, SYS_CLKR); + r8712_write8(padapter, SYS_CLKR, val8 & (~CPU_CLKSEL)); + /* Revised for 8051 ROM code wrong operation. */ + r8712_write8(padapter, 0x1025fe1c, 0x80); + /* To make sure that TxDMA can ready to download FW. + * We should reset TxDMA if IMEM RPT was not ready. + */ + do { + val8 = r8712_read8(padapter, TCR); + if ((val8 & _TXDMA_INIT_VALUE) == _TXDMA_INIT_VALUE) + break; + udelay(5); /* PlatformStallExecution(5); */ + } while (PollingCnt--); /* Delay 1ms */ + + if (PollingCnt <= 0) { + val8 = r8712_read8(padapter, CR); + r8712_write8(padapter, CR, val8&(~_TXDMA_EN)); + udelay(2); /* PlatformStallExecution(2); */ + /* Reset TxDMA */ + r8712_write8(padapter, CR, val8|_TXDMA_EN); + } + } else + ret = _FAIL; + return ret; +} + +unsigned int r8712_usb_inirp_init(struct _adapter *padapter) +{ + u8 i; + struct recv_buf *precvbuf; + struct intf_hdl *pintfhdl = &padapter->pio_queue->intf; + struct recv_priv *precvpriv = &(padapter->recvpriv); + + precvpriv->ff_hwaddr = RTL8712_DMA_RX0FF; /* mapping rx fifo address */ + /* issue Rx irp to receive data */ + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + for (i = 0; i < NR_RECVBUFF; i++) { + if (r8712_usb_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, + (unsigned char *)precvbuf) == false) + return _FAIL; + precvbuf++; + precvpriv->free_recv_buf_queue_cnt--; + } + return _SUCCESS; +} + +unsigned int r8712_usb_inirp_deinit(struct _adapter *padapter) +{ + r8712_usb_read_port_cancel(padapter); + return _SUCCESS; +} diff --git a/kernel/drivers/staging/rtl8712/usb_intf.c b/kernel/drivers/staging/rtl8712/usb_intf.c new file mode 100644 index 000000000..f8b5b332e --- /dev/null +++ b/kernel/drivers/staging/rtl8712/usb_intf.c @@ -0,0 +1,648 @@ +/****************************************************************************** + * usb_intf.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _HCI_INTF_C_ + +#include <linux/usb.h> +#include <linux/module.h> +#include <linux/firmware.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "recv_osdep.h" +#include "xmit_osdep.h" +#include "rtl8712_efuse.h" +#include "usb_ops.h" +#include "usb_osintf.h" + +static struct usb_interface *pintf; + +static int r871xu_drv_init(struct usb_interface *pusb_intf, + const struct usb_device_id *pdid); + +static void r871xu_dev_remove(struct usb_interface *pusb_intf); + +static struct usb_device_id rtl871x_usb_id_tbl[] = { + +/* RTL8188SU */ + /* Realtek */ + {USB_DEVICE(0x0BDA, 0x8171)}, + {USB_DEVICE(0x0bda, 0x8173)}, + {USB_DEVICE(0x0bda, 0x8712)}, + {USB_DEVICE(0x0bda, 0x8713)}, + {USB_DEVICE(0x0bda, 0xC512)}, + /* Abocom */ + {USB_DEVICE(0x07B8, 0x8188)}, + /* ASUS */ + {USB_DEVICE(0x0B05, 0x1786)}, + {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ + /* Belkin */ + {USB_DEVICE(0x050D, 0x945A)}, + /* ISY IWL - Belkin clone */ + {USB_DEVICE(0x050D, 0x11F1)}, + /* Corega */ + {USB_DEVICE(0x07AA, 0x0047)}, + /* D-Link */ + {USB_DEVICE(0x2001, 0x3306)}, + {USB_DEVICE(0x07D1, 0x3306)}, /* 11n mode disable */ + /* Edimax */ + {USB_DEVICE(0x7392, 0x7611)}, + /* EnGenius */ + {USB_DEVICE(0x1740, 0x9603)}, + /* Hawking */ + {USB_DEVICE(0x0E66, 0x0016)}, + /* Hercules */ + {USB_DEVICE(0x06F8, 0xE034)}, + {USB_DEVICE(0x06F8, 0xE032)}, + /* Logitec */ + {USB_DEVICE(0x0789, 0x0167)}, + /* PCI */ + {USB_DEVICE(0x2019, 0xAB28)}, + {USB_DEVICE(0x2019, 0xED16)}, + /* Sitecom */ + {USB_DEVICE(0x0DF6, 0x0057)}, + {USB_DEVICE(0x0DF6, 0x0045)}, + {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ + {USB_DEVICE(0x0DF6, 0x004B)}, + {USB_DEVICE(0x0DF6, 0x005B)}, + {USB_DEVICE(0x0DF6, 0x005D)}, + {USB_DEVICE(0x0DF6, 0x0063)}, + /* Sweex */ + {USB_DEVICE(0x177F, 0x0154)}, + /* Thinkware */ + {USB_DEVICE(0x0BDA, 0x5077)}, + /* Toshiba */ + {USB_DEVICE(0x1690, 0x0752)}, + /* - */ + {USB_DEVICE(0x20F4, 0x646B)}, + {USB_DEVICE(0x083A, 0xC512)}, + {USB_DEVICE(0x25D4, 0x4CA1)}, + {USB_DEVICE(0x25D4, 0x4CAB)}, + +/* RTL8191SU */ + /* Realtek */ + {USB_DEVICE(0x0BDA, 0x8172)}, + {USB_DEVICE(0x0BDA, 0x8192)}, + /* Amigo */ + {USB_DEVICE(0x0EB0, 0x9061)}, + /* ASUS/EKB */ + {USB_DEVICE(0x13D3, 0x3323)}, + {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */ + {USB_DEVICE(0x13D3, 0x3342)}, + /* ASUS/EKBLenovo */ + {USB_DEVICE(0x13D3, 0x3333)}, + {USB_DEVICE(0x13D3, 0x3334)}, + {USB_DEVICE(0x13D3, 0x3335)}, /* 11n mode disable */ + {USB_DEVICE(0x13D3, 0x3336)}, /* 11n mode disable */ + /* ASUS/Media BOX */ + {USB_DEVICE(0x13D3, 0x3309)}, + /* Belkin */ + {USB_DEVICE(0x050D, 0x815F)}, + /* D-Link */ + {USB_DEVICE(0x07D1, 0x3302)}, + {USB_DEVICE(0x07D1, 0x3300)}, + {USB_DEVICE(0x07D1, 0x3303)}, + /* Edimax */ + {USB_DEVICE(0x7392, 0x7612)}, + /* EnGenius */ + {USB_DEVICE(0x1740, 0x9605)}, + /* Guillemot */ + {USB_DEVICE(0x06F8, 0xE031)}, + /* Hawking */ + {USB_DEVICE(0x0E66, 0x0015)}, + /* Mediao */ + {USB_DEVICE(0x13D3, 0x3306)}, + /* PCI */ + {USB_DEVICE(0x2019, 0xED18)}, + {USB_DEVICE(0x2019, 0x4901)}, + /* Sitecom */ + {USB_DEVICE(0x0DF6, 0x0058)}, + {USB_DEVICE(0x0DF6, 0x0049)}, + {USB_DEVICE(0x0DF6, 0x004C)}, + {USB_DEVICE(0x0DF6, 0x0064)}, + /* Skyworth */ + {USB_DEVICE(0x14b2, 0x3300)}, + {USB_DEVICE(0x14b2, 0x3301)}, + {USB_DEVICE(0x14B2, 0x3302)}, + /* - */ + {USB_DEVICE(0x04F2, 0xAFF2)}, + {USB_DEVICE(0x04F2, 0xAFF5)}, + {USB_DEVICE(0x04F2, 0xAFF6)}, + {USB_DEVICE(0x13D3, 0x3339)}, + {USB_DEVICE(0x13D3, 0x3340)}, /* 11n mode disable */ + {USB_DEVICE(0x13D3, 0x3341)}, /* 11n mode disable */ + {USB_DEVICE(0x13D3, 0x3310)}, + {USB_DEVICE(0x13D3, 0x3325)}, + +/* RTL8192SU */ + /* Realtek */ + {USB_DEVICE(0x0BDA, 0x8174)}, + /* Belkin */ + {USB_DEVICE(0x050D, 0x845A)}, + /* Corega */ + {USB_DEVICE(0x07AA, 0x0051)}, + /* Edimax */ + {USB_DEVICE(0x7392, 0x7622)}, + /* NEC */ + {USB_DEVICE(0x0409, 0x02B6)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, rtl871x_usb_id_tbl); + +static struct specific_device_id specific_device_id_tbl[] = { + {.idVendor = 0x0b05, .idProduct = 0x1791, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x0df6, .idProduct = 0x0059, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3306, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13D3, .idProduct = 0x3311, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3335, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3336, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3340, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3341, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {} +}; + +struct drv_priv { + struct usb_driver r871xu_drv; + int drv_registered; +}; + +#ifdef CONFIG_PM +static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state) +{ + struct net_device *pnetdev = usb_get_intfdata(pusb_intf); + + netdev_info(pnetdev, "Suspending...\n"); + if (!pnetdev || !netif_running(pnetdev)) { + netdev_info(pnetdev, "Unable to suspend\n"); + return 0; + } + if (pnetdev->netdev_ops->ndo_stop) + pnetdev->netdev_ops->ndo_stop(pnetdev); + mdelay(10); + netif_device_detach(pnetdev); + return 0; +} + +static int r871x_resume(struct usb_interface *pusb_intf) +{ + struct net_device *pnetdev = usb_get_intfdata(pusb_intf); + + netdev_info(pnetdev, "Resuming...\n"); + if (!pnetdev || !netif_running(pnetdev)) { + netdev_info(pnetdev, "Unable to resume\n"); + return 0; + } + netif_device_attach(pnetdev); + if (pnetdev->netdev_ops->ndo_open) + pnetdev->netdev_ops->ndo_open(pnetdev); + return 0; +} + +static int r871x_reset_resume(struct usb_interface *pusb_intf) +{ + /* dummy routine */ + return 0; +} + +#endif + +static struct drv_priv drvpriv = { + .r871xu_drv.name = "r8712u", + .r871xu_drv.id_table = rtl871x_usb_id_tbl, + .r871xu_drv.probe = r871xu_drv_init, + .r871xu_drv.disconnect = r871xu_dev_remove, +#ifdef CONFIG_PM + .r871xu_drv.suspend = r871x_suspend, + .r871xu_drv.resume = r871x_resume, + .r871xu_drv.reset_resume = r871x_reset_resume, +#endif +}; + +static uint r8712_usb_dvobj_init(struct _adapter *padapter) +{ + uint status = _SUCCESS; + struct usb_host_interface *phost_iface; + struct usb_interface_descriptor *piface_desc; + struct dvobj_priv *pdvobjpriv = &padapter->dvobjpriv; + struct usb_device *pusbd = pdvobjpriv->pusbdev; + + pdvobjpriv->padapter = padapter; + padapter->EepromAddressSize = 6; + phost_iface = &pintf->altsetting[0]; + piface_desc = &phost_iface->desc; + pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; + if (pusbd->speed == USB_SPEED_HIGH) { + pdvobjpriv->ishighspeed = true; + dev_info(&pusbd->dev, "r8712u: USB_SPEED_HIGH with %d endpoints\n", + pdvobjpriv->nr_endpoint); + } else { + pdvobjpriv->ishighspeed = false; + dev_info(&pusbd->dev, "r8712u: USB_SPEED_LOW with %d endpoints\n", + pdvobjpriv->nr_endpoint); + } + if ((r8712_alloc_io_queue(padapter)) == _FAIL) + status = _FAIL; + return status; +} + +static void r8712_usb_dvobj_deinit(struct _adapter *padapter) +{ +} + +void rtl871x_intf_stop(struct _adapter *padapter) +{ + /*disable_hw_interrupt*/ + if (!padapter->bSurpriseRemoved) { + /*device still exists, so driver can do i/o operation + * TODO: */ + } + + /* cancel in irp */ + if (padapter->dvobjpriv.inirp_deinit) + padapter->dvobjpriv.inirp_deinit(padapter); + /* cancel out irp */ + r8712_usb_write_port_cancel(padapter); + /* TODO:cancel other irps */ +} + +void r871x_dev_unload(struct _adapter *padapter) +{ + if (padapter->bup == true) { + /*s1.*/ + padapter->bDriverStopped = true; + + /*s3.*/ + rtl871x_intf_stop(padapter); + + /*s4.*/ + r8712_stop_drv_threads(padapter); + + /*s5.*/ + if (!padapter->bSurpriseRemoved) { + padapter->hw_init_completed = false; + rtl8712_hal_deinit(padapter); + } + + /*s6.*/ + if (padapter->dvobj_deinit) + padapter->dvobj_deinit(padapter); + padapter->bup = false; + } +} + +static void disable_ht_for_spec_devid(const struct usb_device_id *pdid, + struct _adapter *padapter) +{ + u16 vid, pid; + u32 flags; + int i; + int num = sizeof(specific_device_id_tbl) / + sizeof(struct specific_device_id); + + for (i = 0; i < num; i++) { + vid = specific_device_id_tbl[i].idVendor; + pid = specific_device_id_tbl[i].idProduct; + flags = specific_device_id_tbl[i].flags; + + if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && + (flags&SPEC_DEV_ID_DISABLE_HT)) { + padapter->registrypriv.ht_enable = 0; + padapter->registrypriv.cbw40_enable = 0; + padapter->registrypriv.ampdu_enable = 0; + } + } +} + +static const struct device_type wlan_type = { + .name = "wlan", +}; + +/* + * drv_init() - a device potentially for us + * + * notes: drv_init() is called when the bus driver has located a card for us + * to support. We accept the new device by returning 0. +*/ +static int r871xu_drv_init(struct usb_interface *pusb_intf, + const struct usb_device_id *pdid) +{ + uint status; + struct _adapter *padapter = NULL; + struct dvobj_priv *pdvobjpriv; + struct net_device *pnetdev; + struct usb_device *udev; + + /* In this probe function, O.S. will provide the usb interface pointer + * to driver. We have to increase the reference count of the usb device + * structure by using the usb_get_dev function. + */ + udev = interface_to_usbdev(pusb_intf); + usb_get_dev(udev); + pintf = pusb_intf; + /* step 1. */ + pnetdev = r8712_init_netdev(); + if (!pnetdev) + goto error; + padapter = netdev_priv(pnetdev); + disable_ht_for_spec_devid(pdid, padapter); + pdvobjpriv = &padapter->dvobjpriv; + pdvobjpriv->padapter = padapter; + padapter->dvobjpriv.pusbdev = udev; + padapter->pusb_intf = pusb_intf; + usb_set_intfdata(pusb_intf, pnetdev); + SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); + pnetdev->dev.type = &wlan_type; + /* step 2. */ + padapter->dvobj_init = &r8712_usb_dvobj_init; + padapter->dvobj_deinit = &r8712_usb_dvobj_deinit; + padapter->halpriv.hal_bus_init = &r8712_usb_hal_bus_init; + padapter->dvobjpriv.inirp_init = &r8712_usb_inirp_init; + padapter->dvobjpriv.inirp_deinit = &r8712_usb_inirp_deinit; + /* step 3. + * initialize the dvobj_priv + */ + if (!padapter->dvobj_init) + goto error; + else { + status = padapter->dvobj_init(padapter); + if (status != _SUCCESS) + goto error; + } + /* step 4. */ + status = r8712_init_drv_sw(padapter); + if (status == _FAIL) + goto error; + /* step 5. read efuse/eeprom data and get mac_addr */ + { + int i, offset; + u8 mac[6]; + u8 tmpU1b, AutoloadFail, eeprom_CustomerID; + u8 *pdata = padapter->eeprompriv.efuse_eeprom_data; + + tmpU1b = r8712_read8(padapter, EE_9346CR);/*CR9346*/ + + /* To check system boot selection.*/ + dev_info(&udev->dev, "r8712u: Boot from %s: Autoload %s\n", + (tmpU1b & _9356SEL) ? "EEPROM" : "EFUSE", + (tmpU1b & _EEPROM_EN) ? "OK" : "Failed"); + + /* To check autoload success or not.*/ + if (tmpU1b & _EEPROM_EN) { + AutoloadFail = true; + /* The following operations prevent Efuse leakage by + * turning on 2.5V. + */ + tmpU1b = r8712_read8(padapter, EFUSE_TEST+3); + r8712_write8(padapter, EFUSE_TEST + 3, tmpU1b | 0x80); + msleep(20); + r8712_write8(padapter, EFUSE_TEST + 3, + (tmpU1b & (~BIT(7)))); + + /* Retrieve Chip version. + * Recognize IC version by Reg0x4 BIT15. + */ + tmpU1b = (u8)((r8712_read32(padapter, PMC_FSM) >> 15) & + 0x1F); + if (tmpU1b == 0x3) + padapter->registrypriv.chip_version = + RTL8712_3rdCUT; + else + padapter->registrypriv.chip_version = + (tmpU1b >> 1) + 1; + switch (padapter->registrypriv.chip_version) { + case RTL8712_1stCUT: + case RTL8712_2ndCUT: + case RTL8712_3rdCUT: + break; + default: + padapter->registrypriv.chip_version = + RTL8712_2ndCUT; + break; + } + + for (i = 0, offset = 0; i < 128; i += 8, offset++) + r8712_efuse_pg_packet_read(padapter, offset, + &pdata[i]); + + if (!r8712_initmac || !mac_pton(r8712_initmac, mac)) { + /* Use the mac address stored in the Efuse + * offset = 0x12 for usb in efuse + */ + ether_addr_copy(mac, &pdata[0x12]); + } + eeprom_CustomerID = pdata[0x52]; + switch (eeprom_CustomerID) { + case EEPROM_CID_ALPHA: + padapter->eeprompriv.CustomerID = + RT_CID_819x_ALPHA; + break; + case EEPROM_CID_CAMEO: + padapter->eeprompriv.CustomerID = + RT_CID_819x_CAMEO; + break; + case EEPROM_CID_SITECOM: + padapter->eeprompriv.CustomerID = + RT_CID_819x_Sitecom; + break; + case EEPROM_CID_COREGA: + padapter->eeprompriv.CustomerID = + RT_CID_COREGA; + break; + case EEPROM_CID_Senao: + padapter->eeprompriv.CustomerID = + RT_CID_819x_Senao; + break; + case EEPROM_CID_EDIMAX_BELKIN: + padapter->eeprompriv.CustomerID = + RT_CID_819x_Edimax_Belkin; + break; + case EEPROM_CID_SERCOMM_BELKIN: + padapter->eeprompriv.CustomerID = + RT_CID_819x_Sercomm_Belkin; + break; + case EEPROM_CID_WNC_COREGA: + padapter->eeprompriv.CustomerID = + RT_CID_819x_WNC_COREGA; + break; + case EEPROM_CID_WHQL: + break; + case EEPROM_CID_NetCore: + padapter->eeprompriv.CustomerID = + RT_CID_819x_Netcore; + break; + case EEPROM_CID_CAMEO1: + padapter->eeprompriv.CustomerID = + RT_CID_819x_CAMEO1; + break; + case EEPROM_CID_CLEVO: + padapter->eeprompriv.CustomerID = + RT_CID_819x_CLEVO; + break; + default: + padapter->eeprompriv.CustomerID = + RT_CID_DEFAULT; + break; + } + dev_info(&udev->dev, "r8712u: CustomerID = 0x%.4x\n", + padapter->eeprompriv.CustomerID); + /* Led mode */ + switch (padapter->eeprompriv.CustomerID) { + case RT_CID_DEFAULT: + case RT_CID_819x_ALPHA: + case RT_CID_819x_CAMEO: + padapter->ledpriv.LedStrategy = SW_LED_MODE1; + padapter->ledpriv.bRegUseLed = true; + break; + case RT_CID_819x_Sitecom: + padapter->ledpriv.LedStrategy = SW_LED_MODE2; + padapter->ledpriv.bRegUseLed = true; + break; + case RT_CID_COREGA: + case RT_CID_819x_Senao: + padapter->ledpriv.LedStrategy = SW_LED_MODE3; + padapter->ledpriv.bRegUseLed = true; + break; + case RT_CID_819x_Edimax_Belkin: + padapter->ledpriv.LedStrategy = SW_LED_MODE4; + padapter->ledpriv.bRegUseLed = true; + break; + case RT_CID_819x_Sercomm_Belkin: + padapter->ledpriv.LedStrategy = SW_LED_MODE5; + padapter->ledpriv.bRegUseLed = true; + break; + case RT_CID_819x_WNC_COREGA: + padapter->ledpriv.LedStrategy = SW_LED_MODE6; + padapter->ledpriv.bRegUseLed = true; + break; + default: + padapter->ledpriv.LedStrategy = SW_LED_MODE0; + padapter->ledpriv.bRegUseLed = false; + break; + } + } else + AutoloadFail = false; + if (((mac[0] == 0xff) && (mac[1] == 0xff) && + (mac[2] == 0xff) && (mac[3] == 0xff) && + (mac[4] == 0xff) && (mac[5] == 0xff)) || + ((mac[0] == 0x00) && (mac[1] == 0x00) && + (mac[2] == 0x00) && (mac[3] == 0x00) && + (mac[4] == 0x00) && (mac[5] == 0x00)) || + (!AutoloadFail)) { + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0x4c; + mac[3] = 0x87; + mac[4] = 0x00; + mac[5] = 0x00; + } + if (r8712_initmac) { + /* Make sure the user did not select a multicast + * address by setting bit 1 of first octet. + */ + mac[0] &= 0xFE; + dev_info(&udev->dev, + "r8712u: MAC Address from user = %pM\n", mac); + } else + dev_info(&udev->dev, + "r8712u: MAC Address from efuse = %pM\n", mac); + ether_addr_copy(pnetdev->dev_addr, mac); + } + /* step 6. Load the firmware asynchronously */ + if (rtl871x_load_fw(padapter)) + goto error; + spin_lock_init(&padapter->lockRxFF0Filter); + mutex_init(&padapter->mutex_start); + return 0; +error: + usb_put_dev(udev); + usb_set_intfdata(pusb_intf, NULL); + if (padapter && padapter->dvobj_deinit != NULL) + padapter->dvobj_deinit(padapter); + if (pnetdev) + free_netdev(pnetdev); + return -ENODEV; +} + +/* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() + * => how to recognize both */ +static void r871xu_dev_remove(struct usb_interface *pusb_intf) +{ + struct net_device *pnetdev = usb_get_intfdata(pusb_intf); + struct usb_device *udev = interface_to_usbdev(pusb_intf); + + if (pnetdev) { + struct _adapter *padapter = netdev_priv(pnetdev); + + usb_set_intfdata(pusb_intf, NULL); + release_firmware(padapter->fw); + /* never exit with a firmware callback pending */ + wait_for_completion(&padapter->rtl8712_fw_ready); + if (drvpriv.drv_registered == true) + padapter->bSurpriseRemoved = true; + unregister_netdev(pnetdev); /* will call netdev_close() */ + flush_scheduled_work(); + udelay(1); + /* Stop driver mlme relation timer */ + r8712_stop_drv_timers(padapter); + r871x_dev_unload(padapter); + r8712_free_drv_sw(padapter); + + /* decrease the reference count of the usb device structure + * when disconnect */ + usb_put_dev(udev); + } + /* If we didn't unplug usb dongle and remove/insert module, driver + * fails on sitesurvey for the first time when device is up. + * Reset usb port for sitesurvey fail issue. */ + if (udev->state != USB_STATE_NOTATTACHED) + usb_reset_device(udev); +} + +static int __init r8712u_drv_entry(void) +{ + drvpriv.drv_registered = true; + return usb_register(&drvpriv.r871xu_drv); +} + +static void __exit r8712u_drv_halt(void) +{ + drvpriv.drv_registered = false; + usb_deregister(&drvpriv.r871xu_drv); +} + +module_init(r8712u_drv_entry); +module_exit(r8712u_drv_halt); diff --git a/kernel/drivers/staging/rtl8712/usb_ops.c b/kernel/drivers/staging/rtl8712/usb_ops.c new file mode 100644 index 000000000..c03508d93 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/usb_ops.c @@ -0,0 +1,200 @@ +/****************************************************************************** + * usb_ops.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _HCI_OPS_C_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "osdep_intf.h" +#include "usb_ops.h" +#include "recv_osdep.h" + +static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + + request = 0x05; + requesttype = 0x01; /* read_in */ + index = 0; + wvalue = (u16)(addr&0x0000ffff); + len = 1; + r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len, + requesttype); + return (u8)(le32_to_cpu(data)&0x0ff); +} + +static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + + request = 0x05; + requesttype = 0x01; /* read_in */ + index = 0; + wvalue = (u16)(addr&0x0000ffff); + len = 2; + r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len, + requesttype); + return (u16)(le32_to_cpu(data)&0xffff); +} + +static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + + request = 0x05; + requesttype = 0x01; /* read_in */ + index = 0; + wvalue = (u16)(addr&0x0000ffff); + len = 4; + r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len, + requesttype); + return le32_to_cpu(data); +} + +static void usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + + request = 0x05; + requesttype = 0x00; /* write_out */ + index = 0; + wvalue = (u16)(addr&0x0000ffff); + len = 1; + data = val; + data = cpu_to_le32(data&0x000000ff); + r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len, + requesttype); +} + +static void usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + + request = 0x05; + requesttype = 0x00; /* write_out */ + index = 0; + wvalue = (u16)(addr&0x0000ffff); + len = 2; + data = val; + data = cpu_to_le32(data&0x0000ffff); + r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len, + requesttype); +} + +static void usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + + request = 0x05; + requesttype = 0x00; /* write_out */ + index = 0; + wvalue = (u16)(addr&0x0000ffff); + len = 4; + data = cpu_to_le32(val); + r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len, + requesttype); +} + +void r8712_usb_set_intf_option(u32 *poption) +{ + *poption = ((*poption) | _INTF_ASYNC_); +} + +static void usb_intf_hdl_init(u8 *priv) +{ +} + +static void usb_intf_hdl_unload(u8 *priv) +{ +} + +static void usb_intf_hdl_open(u8 *priv) +{ +} + +static void usb_intf_hdl_close(u8 *priv) +{ +} + +void r8712_usb_set_intf_funs(struct intf_hdl *pintf_hdl) +{ + pintf_hdl->intf_hdl_init = &usb_intf_hdl_init; + pintf_hdl->intf_hdl_unload = &usb_intf_hdl_unload; + pintf_hdl->intf_hdl_open = &usb_intf_hdl_open; + pintf_hdl->intf_hdl_close = &usb_intf_hdl_close; +} + +void r8712_usb_set_intf_ops(struct _io_ops *pops) +{ + memset((u8 *)pops, 0, sizeof(struct _io_ops)); + pops->_read8 = &usb_read8; + pops->_read16 = &usb_read16; + pops->_read32 = &usb_read32; + pops->_read_port = &r8712_usb_read_port; + pops->_write8 = &usb_write8; + pops->_write16 = &usb_write16; + pops->_write32 = &usb_write32; + pops->_write_mem = &r8712_usb_write_mem; + pops->_write_port = &r8712_usb_write_port; +} diff --git a/kernel/drivers/staging/rtl8712/usb_ops.h b/kernel/drivers/staging/rtl8712/usb_ops.h new file mode 100644 index 000000000..78e775a46 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/usb_ops.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __USB_OPS_H_ +#define __USB_OPS_H_ + +#include "osdep_service.h" +#include "drv_types.h" +#include "osdep_intf.h" + +void r8712_usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, + u32 cnt, u8 *wmem); +u32 r8712_usb_write_port(struct intf_hdl *pintfhdl, u32 addr, + u32 cnt, u8 *wmem); +u32 r8712_usb_read_port(struct intf_hdl *pintfhdl, u32 addr, + u32 cnt, u8 *rmem); +void r8712_usb_set_intf_option(u32 *poption); +void r8712_usb_set_intf_funs(struct intf_hdl *pintf_hdl); +uint r8712_usb_init_intf_priv(struct intf_priv *pintfpriv); +void r8712_usb_unload_intf_priv(struct intf_priv *pintfpriv); +void r8712_usb_set_intf_ops(struct _io_ops *pops); +void r8712_usb_read_port_cancel(struct _adapter *padapter); +void r8712_usb_write_port_cancel(struct _adapter *padapter); +int r8712_usbctrl_vendorreq(struct intf_priv *pintfpriv, u8 request, u16 value, + u16 index, void *pdata, u16 len, u8 requesttype); + +#endif + diff --git a/kernel/drivers/staging/rtl8712/usb_ops_linux.c b/kernel/drivers/staging/rtl8712/usb_ops_linux.c new file mode 100644 index 000000000..c3a4e3f26 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/usb_ops_linux.c @@ -0,0 +1,523 @@ +/****************************************************************************** + * usb_ops_linux.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _HCI_OPS_OS_C_ + +#include <linux/usb.h> + +#include "osdep_service.h" +#include "drv_types.h" +#include "osdep_intf.h" +#include "usb_ops.h" + +#define RTL871X_VENQT_READ 0xc0 +#define RTL871X_VENQT_WRITE 0x40 + +struct zero_bulkout_context { + void *pbuf; + void *purb; + void *pirp; + void *padapter; +}; + +uint r8712_usb_init_intf_priv(struct intf_priv *pintfpriv) +{ + pintfpriv->piorw_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!pintfpriv->piorw_urb) + return _FAIL; + sema_init(&(pintfpriv->io_retevt), 0); + return _SUCCESS; +} + +void r8712_usb_unload_intf_priv(struct intf_priv *pintfpriv) +{ + if (pintfpriv->piorw_urb) { + usb_kill_urb(pintfpriv->piorw_urb); + usb_free_urb(pintfpriv->piorw_urb); + } +} + +static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) +{ + unsigned int pipe = 0; + struct usb_device *pusbd = pdvobj->pusbdev; + + if (pdvobj->nr_endpoint == 11) { + switch (addr) { + case RTL8712_DMA_BKQ: + pipe = usb_sndbulkpipe(pusbd, 0x07); + break; + case RTL8712_DMA_BEQ: + pipe = usb_sndbulkpipe(pusbd, 0x06); + break; + case RTL8712_DMA_VIQ: + pipe = usb_sndbulkpipe(pusbd, 0x05); + break; + case RTL8712_DMA_VOQ: + pipe = usb_sndbulkpipe(pusbd, 0x04); + break; + case RTL8712_DMA_BCNQ: + pipe = usb_sndbulkpipe(pusbd, 0x0a); + break; + case RTL8712_DMA_BMCQ: /* HI Queue */ + pipe = usb_sndbulkpipe(pusbd, 0x0b); + break; + case RTL8712_DMA_MGTQ: + pipe = usb_sndbulkpipe(pusbd, 0x0c); + break; + case RTL8712_DMA_RX0FF: + pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ + break; + case RTL8712_DMA_C2HCMD: + pipe = usb_rcvbulkpipe(pusbd, 0x09); /* in */ + break; + case RTL8712_DMA_H2CCMD: + pipe = usb_sndbulkpipe(pusbd, 0x0d); + break; + } + } else if (pdvobj->nr_endpoint == 6) { + switch (addr) { + case RTL8712_DMA_BKQ: + pipe = usb_sndbulkpipe(pusbd, 0x07); + break; + case RTL8712_DMA_BEQ: + pipe = usb_sndbulkpipe(pusbd, 0x06); + break; + case RTL8712_DMA_VIQ: + pipe = usb_sndbulkpipe(pusbd, 0x05); + break; + case RTL8712_DMA_VOQ: + pipe = usb_sndbulkpipe(pusbd, 0x04); + break; + case RTL8712_DMA_RX0FF: + case RTL8712_DMA_C2HCMD: + pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ + break; + case RTL8712_DMA_H2CCMD: + case RTL8712_DMA_BCNQ: + case RTL8712_DMA_BMCQ: + case RTL8712_DMA_MGTQ: + pipe = usb_sndbulkpipe(pusbd, 0x0d); + break; + } + } else if (pdvobj->nr_endpoint == 4) { + switch (addr) { + case RTL8712_DMA_BEQ: + pipe = usb_sndbulkpipe(pusbd, 0x06); + break; + case RTL8712_DMA_VOQ: + pipe = usb_sndbulkpipe(pusbd, 0x04); + break; + case RTL8712_DMA_RX0FF: + case RTL8712_DMA_C2HCMD: + pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ + break; + case RTL8712_DMA_H2CCMD: + case RTL8712_DMA_BCNQ: + case RTL8712_DMA_BMCQ: + case RTL8712_DMA_MGTQ: + pipe = usb_sndbulkpipe(pusbd, 0x0d); + break; + } + } else + pipe = 0; + return pipe; +} + +static void usb_write_mem_complete(struct urb *purb) +{ + struct io_queue *pio_q = (struct io_queue *)purb->context; + struct intf_hdl *pintf = &(pio_q->intf); + struct intf_priv *pintfpriv = pintf->pintfpriv; + struct _adapter *padapter = (struct _adapter *)pintf->adapter; + + if (purb->status != 0) { + if (purb->status == (-ESHUTDOWN)) + padapter->bDriverStopped = true; + else + padapter->bSurpriseRemoved = true; + } + up(&pintfpriv->io_retevt); +} + +void r8712_usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) +{ + unsigned int pipe; + struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + struct io_queue *pio_queue = (struct io_queue *)padapter->pio_queue; + struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev; + struct usb_device *pusbd = pdvobj->pusbdev; + struct urb *piorw_urb = pintfpriv->piorw_urb; + + if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || + (padapter->pwrctrlpriv.pnp_bstop_trx)) + return; + /* translate DMA FIFO addr to pipehandle */ + pipe = ffaddr2pipehdl(pdvobj, addr); + if (pipe == 0) + return; + usb_fill_bulk_urb(piorw_urb, pusbd, pipe, + wmem, cnt, usb_write_mem_complete, + pio_queue); + usb_submit_urb(piorw_urb, GFP_ATOMIC); + _down_sema(&pintfpriv->io_retevt); +} + +static void r8712_usb_read_port_complete(struct urb *purb) +{ + uint isevt, *pbuf; + struct recv_buf *precvbuf = (struct recv_buf *)purb->context; + struct _adapter *padapter = (struct _adapter *)precvbuf->adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + + if (padapter->bSurpriseRemoved || padapter->bDriverStopped) + return; + if (purb->status == 0) { /* SUCCESS */ + if ((purb->actual_length > (MAX_RECVBUF_SZ)) || + (purb->actual_length < RXDESC_SIZE)) { + precvbuf->reuse = true; + r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, + (unsigned char *)precvbuf); + } else { + precvbuf->transfer_len = purb->actual_length; + pbuf = (uint *)precvbuf->pbuf; + isevt = le32_to_cpu(*(pbuf + 1)) & 0x1ff; + if ((isevt & 0x1ff) == 0x1ff) { + r8712_rxcmd_event_hdl(padapter, pbuf); + precvbuf->reuse = true; + r8712_read_port(padapter, precvpriv->ff_hwaddr, + 0, (unsigned char *)precvbuf); + } else { + _pkt *pskb = precvbuf->pskb; + + skb_put(pskb, purb->actual_length); + skb_queue_tail(&precvpriv->rx_skb_queue, pskb); + tasklet_hi_schedule(&precvpriv->recv_tasklet); + precvbuf->pskb = NULL; + precvbuf->reuse = false; + r8712_read_port(padapter, precvpriv->ff_hwaddr, + 0, (unsigned char *)precvbuf); + } + } + } else { + switch (purb->status) { + case -EINVAL: + case -EPIPE: + case -ENODEV: + case -ESHUTDOWN: + case -ENOENT: + padapter->bDriverStopped = true; + break; + case -EPROTO: + precvbuf->reuse = true; + r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, + (unsigned char *)precvbuf); + break; + case -EINPROGRESS: + netdev_err(padapter->pnetdev, "ERROR: URB IS IN PROGRESS!\n"); + break; + default: + break; + } + } +} + +u32 r8712_usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) +{ + unsigned int pipe; + int err; + u32 tmpaddr = 0; + int alignment = 0; + u32 ret = _SUCCESS; + struct urb *purb = NULL; + struct recv_buf *precvbuf = (struct recv_buf *)rmem; + struct intf_priv *pintfpriv = pintfhdl->pintfpriv; + struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev; + struct _adapter *adapter = (struct _adapter *)pdvobj->padapter; + struct recv_priv *precvpriv = &adapter->recvpriv; + struct usb_device *pusbd = pdvobj->pusbdev; + + if (adapter->bDriverStopped || adapter->bSurpriseRemoved || + adapter->pwrctrlpriv.pnp_bstop_trx) + return _FAIL; + if (!precvbuf->reuse == false || !precvbuf->pskb) { + precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); + if (NULL != precvbuf->pskb) + precvbuf->reuse = true; + } + if (precvbuf != NULL) { + r8712_init_recvbuf(adapter, precvbuf); + /* re-assign for linux based on skb */ + if (!precvbuf->reuse || !precvbuf->pskb) { + precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, + MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); + if (!precvbuf->pskb) + return _FAIL; + tmpaddr = (addr_t)precvbuf->pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); + skb_reserve(precvbuf->pskb, + (RECVBUFF_ALIGN_SZ - alignment)); + precvbuf->phead = precvbuf->pskb->head; + precvbuf->pdata = precvbuf->pskb->data; + precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); + precvbuf->pend = skb_end_pointer(precvbuf->pskb); + precvbuf->pbuf = precvbuf->pskb->data; + } else { /* reuse skb */ + precvbuf->phead = precvbuf->pskb->head; + precvbuf->pdata = precvbuf->pskb->data; + precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); + precvbuf->pend = skb_end_pointer(precvbuf->pskb); + precvbuf->pbuf = precvbuf->pskb->data; + precvbuf->reuse = false; + } + purb = precvbuf->purb; + /* translate DMA FIFO addr to pipehandle */ + pipe = ffaddr2pipehdl(pdvobj, addr); + usb_fill_bulk_urb(purb, pusbd, pipe, + precvbuf->pbuf, MAX_RECVBUF_SZ, + r8712_usb_read_port_complete, + precvbuf); + err = usb_submit_urb(purb, GFP_ATOMIC); + if ((err) && (err != (-EPERM))) + ret = _FAIL; + } else + ret = _FAIL; + return ret; +} + +void r8712_usb_read_port_cancel(struct _adapter *padapter) +{ + int i; + struct recv_buf *precvbuf; + + precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; + for (i = 0; i < NR_RECVBUFF; i++) { + if (precvbuf->purb) + usb_kill_urb(precvbuf->purb); + precvbuf++; + } +} + +void r8712_xmit_bh(void *priv) +{ + int ret = false; + struct _adapter *padapter = (struct _adapter *)priv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if ((padapter->bDriverStopped == true) || + (padapter->bSurpriseRemoved == true)) { + netdev_err(padapter->pnetdev, "xmit_bh => bDriverStopped or bSurpriseRemoved\n"); + return; + } + ret = r8712_xmitframe_complete(padapter, pxmitpriv, NULL); + if (ret == false) + return; + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); +} + +static void usb_write_port_complete(struct urb *purb) +{ + int i; + struct xmit_frame *pxmitframe = (struct xmit_frame *)purb->context; + struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; + struct _adapter *padapter = pxmitframe->padapter; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + switch (pattrib->priority) { + case 1: + case 2: + pxmitpriv->bkq_cnt--; + break; + case 4: + case 5: + pxmitpriv->viq_cnt--; + break; + case 6: + case 7: + pxmitpriv->voq_cnt--; + break; + case 0: + case 3: + default: + pxmitpriv->beq_cnt--; + break; + } + pxmitpriv->txirp_cnt--; + for (i = 0; i < 8; i++) { + if (purb == pxmitframe->pxmit_urb[i]) { + pxmitframe->bpending[i] = false; + break; + } + } + if (padapter->bSurpriseRemoved) + return; + switch (purb->status) { + case 0: + break; + default: + netdev_warn(padapter->pnetdev, + "r8712u: pipe error: (%d)\n", purb->status); + break; + } + /* not to consider tx fragment */ + r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); + r8712_free_xmitbuf(pxmitpriv, pxmitbuf); + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); +} + +u32 r8712_usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) +{ + unsigned long irqL; + int i, status; + unsigned int pipe; + u32 ret, bwritezero; + struct urb *purb = NULL; + struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter; + struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_frame *pxmitframe = (struct xmit_frame *)wmem; + struct usb_device *pusbd = pdvobj->pusbdev; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || + (padapter->pwrctrlpriv.pnp_bstop_trx)) + return _FAIL; + for (i = 0; i < 8; i++) { + if (pxmitframe->bpending[i] == false) { + spin_lock_irqsave(&pxmitpriv->lock, irqL); + pxmitpriv->txirp_cnt++; + pxmitframe->bpending[i] = true; + switch (pattrib->priority) { + case 1: + case 2: + pxmitpriv->bkq_cnt++; + break; + case 4: + case 5: + pxmitpriv->viq_cnt++; + break; + case 6: + case 7: + pxmitpriv->voq_cnt++; + break; + case 0: + case 3: + default: + pxmitpriv->beq_cnt++; + break; + } + spin_unlock_irqrestore(&pxmitpriv->lock, irqL); + pxmitframe->sz[i] = (u16)cnt; + purb = pxmitframe->pxmit_urb[i]; + break; + } + } + bwritezero = false; + if (pdvobj->ishighspeed) { + if (cnt > 0 && cnt % 512 == 0) + bwritezero = true; + } else { + if (cnt > 0 && cnt % 64 == 0) + bwritezero = true; + } + /* translate DMA FIFO addr to pipehandle */ + pipe = ffaddr2pipehdl(pdvobj, addr); + if (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0) + purb->transfer_flags &= (~URB_NO_INTERRUPT); + else + purb->transfer_flags |= URB_NO_INTERRUPT; + if (bwritezero) + cnt += 8; + usb_fill_bulk_urb(purb, pusbd, pipe, + pxmitframe->mem_addr, + cnt, usb_write_port_complete, + pxmitframe); /* context is xmit_frame */ + status = usb_submit_urb(purb, GFP_ATOMIC); + if (!status) + ret = _SUCCESS; + else + ret = _FAIL; + return ret; +} + +void r8712_usb_write_port_cancel(struct _adapter *padapter) +{ + int i, j; + struct xmit_buf *pxmitbuf = (struct xmit_buf *) + padapter->xmitpriv.pxmitbuf; + + for (i = 0; i < NR_XMITBUFF; i++) { + for (j = 0; j < 8; j++) { + if (pxmitbuf->pxmit_urb[j]) + usb_kill_urb(pxmitbuf->pxmit_urb[j]); + } + pxmitbuf++; + } +} + +int r8712_usbctrl_vendorreq(struct intf_priv *pintfpriv, u8 request, u16 value, + u16 index, void *pdata, u16 len, u8 requesttype) +{ + unsigned int pipe; + int status; + u8 reqtype; + struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *) + pintfpriv->intf_dev; + struct usb_device *udev = pdvobjpriv->pusbdev; + /* For mstar platform, mstar suggests the address for USB IO + * should be 16 bytes alignment. Trying to fix it here. + */ + u8 *palloc_buf, *pIo_buf; + + palloc_buf = kmalloc((u32)len + 16, GFP_ATOMIC); + if (palloc_buf == NULL) + return -ENOMEM; + pIo_buf = palloc_buf + 16 - ((addr_t)(palloc_buf) & 0x0f); + if (requesttype == 0x01) { + pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ + reqtype = RTL871X_VENQT_READ; + } else { + pipe = usb_sndctrlpipe(udev, 0); /* write_out */ + reqtype = RTL871X_VENQT_WRITE; + memcpy(pIo_buf, pdata, len); + } + status = usb_control_msg(udev, pipe, request, reqtype, value, index, + pIo_buf, len, HZ / 2); + if (status > 0) { /* Success this control transfer. */ + if (requesttype == 0x01) { + /* For Control read transfer, we have to copy the read + * data from pIo_buf to pdata. + */ + memcpy(pdata, pIo_buf, status); + } + } + kfree(palloc_buf); + return status; +} diff --git a/kernel/drivers/staging/rtl8712/usb_osintf.h b/kernel/drivers/staging/rtl8712/usb_osintf.h new file mode 100644 index 000000000..609f9210c --- /dev/null +++ b/kernel/drivers/staging/rtl8712/usb_osintf.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __USB_OSINTF_H +#define __USB_OSINTF_H + +#include "osdep_service.h" +#include "drv_types.h" + +extern char *r8712_initmac; + +unsigned int r8712_usb_inirp_init(struct _adapter *padapter); +unsigned int r8712_usb_inirp_deinit(struct _adapter *padapter); +uint rtl871x_hal_init(struct _adapter *padapter); +uint rtl8712_hal_deinit(struct _adapter *padapter); + +void rtl871x_intf_stop(struct _adapter *padapter); +void r871x_dev_unload(struct _adapter *padapter); +void r8712_stop_drv_threads(struct _adapter *padapter); +void r8712_stop_drv_timers(struct _adapter *padapter); +u8 r8712_init_drv_sw(struct _adapter *padapter); +u8 r8712_free_drv_sw(struct _adapter *padapter); +struct net_device *r8712_init_netdev(void); + +#endif diff --git a/kernel/drivers/staging/rtl8712/wifi.h b/kernel/drivers/staging/rtl8712/wifi.h new file mode 100644 index 000000000..17f513122 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/wifi.h @@ -0,0 +1,594 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef _WIFI_H_ +#define _WIFI_H_ + +#include <linux/compiler.h> + +#ifdef BIT +#undef BIT +#endif +#define BIT(x) (1 << (x)) + +#define WLAN_ETHHDR_LEN 14 +#define WLAN_ETHADDR_LEN 6 +#define WLAN_IEEE_OUI_LEN 3 +#define WLAN_ADDR_LEN 6 +#define WLAN_CRC_LEN 4 +#define WLAN_BSSID_LEN 6 +#define WLAN_BSS_TS_LEN 8 +#define WLAN_HDR_A3_LEN 24 +#define WLAN_HDR_A4_LEN 30 +#define WLAN_HDR_A3_QOS_LEN 26 +#define WLAN_HDR_A4_QOS_LEN 32 +#define WLAN_SSID_MAXLEN 32 +#define WLAN_DATA_MAXLEN 2312 + +#define WLAN_A3_PN_OFFSET 24 +#define WLAN_A4_PN_OFFSET 30 + +#define WLAN_MIN_ETHFRM_LEN 60 +#define WLAN_MAX_ETHFRM_LEN 1514 +#define WLAN_ETHHDR_LEN 14 + +#define P80211CAPTURE_VERSION 0x80211001 + +enum WIFI_FRAME_TYPE { + WIFI_MGT_TYPE = (0), + WIFI_CTRL_TYPE = (BIT(2)), + WIFI_DATA_TYPE = (BIT(3)), + WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), /*!< QoS Data */ +}; + +enum WIFI_FRAME_SUBTYPE { + /* below is for mgt frame */ + WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE), + WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE), + WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE), + WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE), + WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE), + WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE), + WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE), + WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE), + WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE), + WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE), + WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE), + WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE), + /* below is for control frame */ + WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE), + WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), + WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE), + WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE), + WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE), + WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), + /* below is for data frame */ + WIFI_DATA = (0 | WIFI_DATA_TYPE), + WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE), + WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE), + WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE), + WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE), + WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE), + WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE), + WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE), +}; + +enum WIFI_REASON_CODE { + _RSON_RESERVED_ = 0, + _RSON_UNSPECIFIED_ = 1, + _RSON_AUTH_NO_LONGER_VALID_ = 2, + _RSON_DEAUTH_STA_LEAVING_ = 3, + _RSON_INACTIVITY_ = 4, + _RSON_UNABLE_HANDLE_ = 5, + _RSON_CLS2_ = 6, + _RSON_CLS3_ = 7, + _RSON_DISAOC_STA_LEAVING_ = 8, + _RSON_ASOC_NOT_AUTH_ = 9, + /* WPA reason */ + _RSON_INVALID_IE_ = 13, + _RSON_MIC_FAILURE_ = 14, + _RSON_4WAY_HNDSHK_TIMEOUT_ = 15, + _RSON_GROUP_KEY_UPDATE_TIMEOUT_ = 16, + _RSON_DIFF_IE_ = 17, + _RSON_MLTCST_CIPHER_NOT_VALID_ = 18, + _RSON_UNICST_CIPHER_NOT_VALID_ = 19, + _RSON_AKMP_NOT_VALID_ = 20, + _RSON_UNSUPPORT_RSNE_VER_ = 21, + _RSON_INVALID_RSNE_CAP_ = 22, + _RSON_IEEE_802DOT1X_AUTH_FAIL_ = 23, + /* below are Realtek definitions */ + _RSON_PMK_NOT_AVAILABLE_ = 24, +}; + +enum WIFI_STATUS_CODE { + _STATS_SUCCESSFUL_ = 0, + _STATS_FAILURE_ = 1, + _STATS_CAP_FAIL_ = 10, + _STATS_NO_ASOC_ = 11, + _STATS_OTHER_ = 12, + _STATS_NO_SUPP_ALG_ = 13, + _STATS_OUT_OF_AUTH_SEQ_ = 14, + _STATS_CHALLENGE_FAIL_ = 15, + _STATS_AUTH_TIMEOUT_ = 16, + _STATS_UNABLE_HANDLE_STA_ = 17, + _STATS_RATE_FAIL_ = 18, +}; + +enum WIFI_REG_DOMAIN { + DOMAIN_FCC = 1, + DOMAIN_IC = 2, + DOMAIN_ETSI = 3, + DOMAIN_SPAIN = 4, + DOMAIN_FRANCE = 5, + DOMAIN_MKK = 6, + DOMAIN_ISRAEL = 7, + DOMAIN_MKK1 = 8, + DOMAIN_MKK2 = 9, + DOMAIN_MKK3 = 10, + DOMAIN_MAX +}; + +#define _TO_DS_ BIT(8) +#define _FROM_DS_ BIT(9) +#define _MORE_FRAG_ BIT(10) +#define _RETRY_ BIT(11) +#define _PWRMGT_ BIT(12) +#define _MORE_DATA_ BIT(13) +#define _PRIVACY_ BIT(14) +#define _ORDER_ BIT(15) + +#define SetToDs(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_TO_DS_); \ +}) + +#define GetToDs(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_TO_DS_)) != 0) + +#define ClearToDs(pbuf) ({ \ + *(unsigned short *)(pbuf) &= (~cpu_to_le16(_TO_DS_)); \ +}) + +#define SetFrDs(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_FROM_DS_); \ +}) + +#define GetFrDs(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_FROM_DS_)) != 0) + +#define ClearFrDs(pbuf) ({ \ + *(unsigned short *)(pbuf) &= (~cpu_to_le16(_FROM_DS_)); \ +}) + +#define get_tofr_ds(pframe) ((GetToDs(pframe) << 1) | GetFrDs(pframe)) + + +#define SetMFrag(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_MORE_FRAG_); \ +}) + +#define GetMFrag(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_MORE_FRAG_)) != 0) + +#define ClearMFrag(pbuf) ({ \ + *(unsigned short *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_)); \ +}) + +#define SetRetry(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_RETRY_); \ +}) + +#define GetRetry(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_RETRY_)) != 0) + +#define ClearRetry(pbuf) ({ \ + *(unsigned short *)(pbuf) &= (~cpu_to_le16(_RETRY_)); \ +}) + +#define SetPwrMgt(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_PWRMGT_); \ +}) + +#define GetPwrMgt(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_PWRMGT_)) != 0) + +#define ClearPwrMgt(pbuf) ({ \ + *(unsigned short *)(pbuf) &= (~cpu_to_le16(_PWRMGT_)); \ +}) + +#define SetMData(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_MORE_DATA_); \ +}) + +#define GetMData(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_MORE_DATA_)) != 0) + +#define ClearMData(pbuf) ({ \ + *(unsigned short *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_)); \ +}) + +#define SetPrivacy(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_PRIVACY_); \ +}) + +#define GetPrivacy(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_PRIVACY_)) != 0) + +#define GetOrder(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_ORDER_)) != 0) + +#define GetFrameType(pbuf) (le16_to_cpu(*(unsigned short *)(pbuf)) & \ + (BIT(3) | BIT(2))) + +#define SetFrameType(pbuf, type) \ + do { \ + *(unsigned short *)(pbuf) &= cpu_to_le16(~(BIT(3) | \ + BIT(2))); \ + *(unsigned short *)(pbuf) |= cpu_to_le16(type); \ + } while (0) + +#define GetFrameSubType(pbuf) (cpu_to_le16(*(unsigned short *)(pbuf)) & \ + (BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | \ + BIT(2))) + +#define SetFrameSubType(pbuf, type) \ + do { \ + *(unsigned short *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | \ + BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ + *(unsigned short *)(pbuf) |= cpu_to_le16(type); \ + } while (0) + +#define GetSequence(pbuf) (cpu_to_le16(*(unsigned short *)\ + ((addr_t)(pbuf) + 22)) >> 4) + +#define GetFragNum(pbuf) (cpu_to_le16(*(unsigned short *)((addr_t)\ + (pbuf) + 22)) & 0x0f) + +#define SetSeqNum(pbuf, num) ({ \ + *(unsigned short *)((addr_t)(pbuf) + 22) = \ + ((*(unsigned short *)((addr_t)(pbuf) + 22)) & \ + le16_to_cpu((unsigned short)0x000f)) | \ + le16_to_cpu((unsigned short)(0xfff0 & (num << 4))); \ +}) + +#define SetDuration(pbuf, dur) ({ \ + *(unsigned short *)((addr_t)(pbuf) + 2) |= \ + cpu_to_le16(0xffff & (dur)); \ +}) + +#define SetPriority(pbuf, tid) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(tid & 0xf); \ +}) + +#define GetPriority(pbuf) ((le16_to_cpu(*(unsigned short *)(pbuf))) & 0xf) + +#define SetAckpolicy(pbuf, ack) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16((ack & 3) << 5); \ +}) + +#define GetAckpolicy(pbuf) (((le16_to_cpu(*(unsigned short *)pbuf)) >> 5) & 0x3) + +#define GetAMsdu(pbuf) (((le16_to_cpu(*(unsigned short *)pbuf)) >> 7) & 0x1) + +#define GetAid(pbuf) (cpu_to_le16(*(unsigned short *)((addr_t)(pbuf) + 2)) \ + & 0x3fff) + +#define GetAddr1Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 4)) + +#define GetAddr2Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 10)) + +#define GetAddr3Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 16)) + +#define GetAddr4Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 24)) + + + +static inline int IS_MCAST(unsigned char *da) +{ + if ((*da) & 0x01) + return true; + else + return false; +} + + +static inline unsigned char *get_da(unsigned char *pframe) +{ + unsigned char *da; + unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); + + switch (to_fr_ds) { + case 0x00: /* ToDs=0, FromDs=0 */ + da = GetAddr1Ptr(pframe); + break; + case 0x01: /* ToDs=0, FromDs=1 */ + da = GetAddr1Ptr(pframe); + break; + case 0x02: /* ToDs=1, FromDs=0 */ + da = GetAddr3Ptr(pframe); + break; + default: /* ToDs=1, FromDs=1 */ + da = GetAddr3Ptr(pframe); + break; + } + return da; +} + + +static inline unsigned char *get_sa(unsigned char *pframe) +{ + unsigned char *sa; + unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); + + switch (to_fr_ds) { + case 0x00: /* ToDs=0, FromDs=0 */ + sa = GetAddr2Ptr(pframe); + break; + case 0x01: /* ToDs=0, FromDs=1 */ + sa = GetAddr3Ptr(pframe); + break; + case 0x02: /* ToDs=1, FromDs=0 */ + sa = GetAddr2Ptr(pframe); + break; + default: /* ToDs=1, FromDs=1 */ + sa = GetAddr4Ptr(pframe); + break; + } + + return sa; +} + +static inline unsigned char *get_hdr_bssid(unsigned char *pframe) +{ + unsigned char *sa; + unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); + + switch (to_fr_ds) { + case 0x00: /* ToDs=0, FromDs=0 */ + sa = GetAddr3Ptr(pframe); + break; + case 0x01: /* ToDs=0, FromDs=1 */ + sa = GetAddr2Ptr(pframe); + break; + case 0x02: /* ToDs=1, FromDs=0 */ + sa = GetAddr1Ptr(pframe); + break; + default: /* ToDs=1, FromDs=1 */ + sa = NULL; + break; + } + return sa; +} + + + +/*----------------------------------------------------------------------------- + Below is for the security related definition +------------------------------------------------------------------------------*/ +#define _RESERVED_FRAME_TYPE_ 0 +#define _SKB_FRAME_TYPE_ 2 +#define _PRE_ALLOCMEM_ 1 +#define _PRE_ALLOCHDR_ 3 +#define _PRE_ALLOCLLCHDR_ 4 +#define _PRE_ALLOCICVHDR_ 5 +#define _PRE_ALLOCMICHDR_ 6 + +#define _SIFSTIME_ ((priv->pmib->BssType.net_work_type & \ + WIRELESS_11A) ? 16 : 10) +#define _ACKCTSLNG_ 14 /*14 bytes long, including crclng */ +#define _CRCLNG_ 4 + +#define _ASOCREQ_IE_OFFSET_ 4 /* excluding wlan_hdr */ +#define _ASOCRSP_IE_OFFSET_ 6 +#define _REASOCREQ_IE_OFFSET_ 10 +#define _REASOCRSP_IE_OFFSET_ 6 +#define _PROBEREQ_IE_OFFSET_ 0 +#define _PROBERSP_IE_OFFSET_ 12 +#define _AUTH_IE_OFFSET_ 6 +#define _DEAUTH_IE_OFFSET_ 0 +#define _BEACON_IE_OFFSET_ 12 + +#define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_ + +#define _SSID_IE_ 0 +#define _SUPPORTEDRATES_IE_ 1 +#define _DSSET_IE_ 3 +#define _IBSS_PARA_IE_ 6 +#define _ERPINFO_IE_ 42 +#define _EXT_SUPPORTEDRATES_IE_ 50 + +#define _HT_CAPABILITY_IE_ 45 +#define _HT_EXTRA_INFO_IE_ 61 +#define _HT_ADD_INFO_IE_ 61 /* _HT_EXTRA_INFO_IE_ */ + +#define _VENDOR_SPECIFIC_IE_ 221 + +#define _RESERVED47_ 47 + + +/* --------------------------------------------------------------------------- + Below is the fixed elements... +-----------------------------------------------------------------------------*/ +#define _AUTH_ALGM_NUM_ 2 +#define _AUTH_SEQ_NUM_ 2 +#define _BEACON_ITERVAL_ 2 +#define _CAPABILITY_ 2 +#define _CURRENT_APADDR_ 6 +#define _LISTEN_INTERVAL_ 2 +#define _RSON_CODE_ 2 +#define _ASOC_ID_ 2 +#define _STATUS_CODE_ 2 +#define _TIMESTAMP_ 8 + +#define AUTH_ODD_TO 0 +#define AUTH_EVEN_TO 1 + +#define WLAN_ETHCONV_ENCAP 1 +#define WLAN_ETHCONV_RFC1042 2 +#define WLAN_ETHCONV_8021h 3 + +#define cap_ESS BIT(0) +#define cap_IBSS BIT(1) +#define cap_CFPollable BIT(2) +#define cap_CFRequest BIT(3) +#define cap_Privacy BIT(4) +#define cap_ShortPremble BIT(5) + +/*----------------------------------------------------------------------------- + Below is the definition for 802.11i / 802.1x +------------------------------------------------------------------------------*/ +#define _IEEE8021X_MGT_ 1 /*WPA */ +#define _IEEE8021X_PSK_ 2 /* WPA with pre-shared key */ + +/*----------------------------------------------------------------------------- + Below is the definition for WMM +------------------------------------------------------------------------------*/ +#define _WMM_IE_Length_ 7 /* for WMM STA */ +#define _WMM_Para_Element_Length_ 24 + + +/*----------------------------------------------------------------------------- + Below is the definition for 802.11n +------------------------------------------------------------------------------*/ + +/* block-ack parameters */ +#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 +#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C +#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 +#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 +#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 + +#define SetOrderBit(pbuf) ({ \ + *(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_); \ +}) + +#define GetOrderBit(pbuf) (((*(unsigned short *)(pbuf)) & \ + le16_to_cpu(_ORDER_)) != 0) + + +/** + * struct ieee80211_bar - HT Block Ack Request + * + * This structure refers to "HT BlockAckReq" as + * described in 802.11n draft section 7.2.1.7.1 + */ +struct ieee80211_bar { + unsigned short frame_control; + unsigned short duration; + unsigned char ra[6]; + unsigned char ta[6]; + unsigned short control; + unsigned short start_seq_num; +} __packed; + +/* 802.11 BAR control masks */ +#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 +#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 + + + /** + * struct ieee80211_ht_cap - HT capabilities + * + * This structure refers to "HT capabilities element" as + * described in 802.11n draft section 7.3.2.52 + */ + +struct ieee80211_ht_cap { + unsigned short cap_info; + unsigned char ampdu_params_info; + unsigned char supp_mcs_set[16]; + unsigned short extended_ht_cap_info; + unsigned int tx_BF_cap_info; + unsigned char antenna_selection_info; +} __packed; + +/** + * struct ieee80211_ht_cap - HT additional information + * + * This structure refers to "HT information element" as + * described in 802.11n draft section 7.3.2.53 + */ +struct ieee80211_ht_addt_info { + unsigned char control_chan; + unsigned char ht_param; + unsigned short operation_mode; + unsigned short stbc_param; + unsigned char basic_set[16]; +} __packed; + +/* 802.11n HT capabilities masks */ +#define IEEE80211_HT_CAP_SUP_WIDTH 0x0002 +#define IEEE80211_HT_CAP_SM_PS 0x000C +#define IEEE80211_HT_CAP_GRN_FLD 0x0010 +#define IEEE80211_HT_CAP_SGI_20 0x0020 +#define IEEE80211_HT_CAP_SGI_40 0x0040 +#define IEEE80211_HT_CAP_TX_STBC 0x0080 +#define IEEE80211_HT_CAP_DELAY_BA 0x0400 +#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 +/* 802.11n HT capability AMPDU settings */ +#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 +#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C +/* 802.11n HT capability MSC set */ +#define IEEE80211_SUPP_MCS_SET_UEQM 4 +#define IEEE80211_HT_CAP_MAX_STREAMS 4 +#define IEEE80211_SUPP_MCS_SET_LEN 10 +/* maximum streams the spec allows */ +#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01 +#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02 +#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C +#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 +/* 802.11n HT IE masks */ +#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 +#define IEEE80211_HT_IE_CHA_SEC_NONE 0x00 +#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01 +#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03 +#define IEEE80211_HT_IE_CHA_WIDTH 0x04 +#define IEEE80211_HT_IE_HT_PROTECTION 0x0003 +#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 +#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 + +/* block-ack parameters */ +#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 +#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C +#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 +#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 +#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 + +/* + * A-PMDU buffer sizes + * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) + */ +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_MAX_AMPDU_BUF 0x40 + + +/* Spatial Multiplexing Power Save Modes */ +#define WLAN_HT_CAP_SM_PS_STATIC 0 +#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 +#define WLAN_HT_CAP_SM_PS_INVALID 2 +#define WLAN_HT_CAP_SM_PS_DISABLED 3 + +#endif /* _WIFI_H_ */ + diff --git a/kernel/drivers/staging/rtl8712/wlan_bssdef.h b/kernel/drivers/staging/rtl8712/wlan_bssdef.h new file mode 100644 index 000000000..2ea8a3d6b --- /dev/null +++ b/kernel/drivers/staging/rtl8712/wlan_bssdef.h @@ -0,0 +1,267 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __WLAN_BSSDEF_H__ +#define __WLAN_BSSDEF_H__ + +#define MAX_IE_SZ 768 + +#define NDIS_802_11_LENGTH_SSID 32 +#define NDIS_802_11_LENGTH_RATES 8 +#define NDIS_802_11_LENGTH_RATES_EX 16 + +/* Set of 8 data rates*/ +typedef unsigned char NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; +/* Set of 16 data rates */ +typedef unsigned char NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; + +struct ndis_802_11_ssid { + u32 SsidLength; + u8 Ssid[32]; +}; + +enum NDIS_802_11_NETWORK_TYPE { + Ndis802_11FH, + Ndis802_11DS, + Ndis802_11OFDM5, + Ndis802_11OFDM24, + Ndis802_11NetworkTypeMax /* not a real type, defined as an upper bound*/ +}; + +struct NDIS_802_11_CONFIGURATION_FH { + u32 Length; /* Length of structure */ + u32 HopPattern; /* As defined by 802.11, MSB set */ + u32 HopSet; /* to one if non-802.11 */ + u32 DwellTime; /* units are Kusec */ +}; + +/* + FW will only save the channel number in DSConfig. + ODI Handler will convert the channel number to freq. number. +*/ +struct NDIS_802_11_CONFIGURATION { + u32 Length; /* Length of structure */ + u32 BeaconPeriod; /* units are Kusec */ + u32 ATIMWindow; /* units are Kusec */ + u32 DSConfig; /* Frequency, units are kHz */ + struct NDIS_802_11_CONFIGURATION_FH FHConfig; +}; + +enum NDIS_802_11_NETWORK_INFRASTRUCTURE { + Ndis802_11IBSS, + Ndis802_11Infrastructure, + Ndis802_11AutoUnknown, + Ndis802_11InfrastructureMax, /*Not a real value,defined as upper bound*/ + Ndis802_11APMode +}; + +struct NDIS_802_11_FIXED_IEs { + u8 Timestamp[8]; + u16 BeaconInterval; + u16 Capabilities; +}; + +/* + * Length is the 4 bytes multiples of the sume of + * 6 * sizeof (unsigned char) + 2 + sizeof (ndis_802_11_ssid) + sizeof (u32) + * + sizeof (s32) + sizeof (NDIS_802_11_NETWORK_TYPE) + * + sizeof (struct NDIS_802_11_CONFIGURATION) + * + sizeof (NDIS_802_11_RATES_EX) + IELength + + * Except the IELength, all other fields are fixed length. Therefore, we can + * define a macro to present the partial sum. + */ + +struct ndis_wlan_bssid_ex { + u32 Length; + unsigned char MacAddress[6]; + u8 Reserved[2]; + struct ndis_802_11_ssid Ssid; + u32 Privacy; + s32 Rssi; + enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; + struct NDIS_802_11_CONFIGURATION Configuration; + enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + NDIS_802_11_RATES_EX SupportedRates; + u32 IELength; + /*(timestamp, beacon interval, and capability information) */ + u8 IEs[MAX_IE_SZ]; +}; + +enum NDIS_802_11_AUTHENTICATION_MODE { + Ndis802_11AuthModeOpen, + Ndis802_11AuthModeShared, + Ndis802_11AuthModeAutoSwitch, + Ndis802_11AuthModeWPA, + Ndis802_11AuthModeWPAPSK, + Ndis802_11AuthModeWPANone, + Ndis802_11AuthModeMax /* Not a real mode, defined as upper bound */ +}; + +enum { + Ndis802_11WEPEnabled, + Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, + Ndis802_11WEPDisabled, + Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, + Ndis802_11WEPKeyAbsent, + Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, + Ndis802_11WEPNotSupported, + Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, + Ndis802_11Encryption2Enabled, + Ndis802_11Encryption2KeyAbsent, + Ndis802_11Encryption3Enabled, + Ndis802_11Encryption3KeyAbsent +}; + +#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 +#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 +#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 + +#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 +#define NDIS_802_11_AI_RESFI_STATUSCODE 2 +#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 + +struct NDIS_802_11_AI_REQFI { + u16 Capabilities; + u16 ListenInterval; + unsigned char CurrentAPAddress[6]; +}; + +struct NDIS_802_11_AI_RESFI { + u16 Capabilities; + u16 StatusCode; + u16 AssociationId; +}; + +struct NDIS_802_11_ASSOCIATION_INFORMATION { + u32 Length; + u16 AvailableRequestFixedIEs; + struct NDIS_802_11_AI_REQFI RequestFixedIEs; + u32 RequestIELength; + u32 OffsetRequestIEs; + u16 AvailableResponseFixedIEs; + struct NDIS_802_11_AI_RESFI ResponseFixedIEs; + u32 ResponseIELength; + u32 OffsetResponseIEs; +}; + +/* Key mapping keys require a BSSID*/ +struct NDIS_802_11_KEY { + u32 Length; /* Length of this structure */ + u32 KeyIndex; + u32 KeyLength; /* length of key in bytes */ + unsigned char BSSID[6]; + unsigned long long KeyRSC; + u8 KeyMaterial[32]; /* variable length */ +}; + +struct NDIS_802_11_REMOVE_KEY { + u32 Length; /* Length of this structure */ + u32 KeyIndex; + unsigned char BSSID[6]; +}; + +struct NDIS_802_11_WEP { + u32 Length; /* Length of this structure */ + u32 KeyIndex; /* 0 is the per-client key, + * 1-N are the global keys */ + u32 KeyLength; /* length of key in bytes */ + u8 KeyMaterial[16]; /* variable length depending on above field */ +}; + +/* mask for authentication/integrity fields */ +#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f +#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 +#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 +#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 +#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E + +/* MIC check time, 60 seconds. */ +#define MIC_CHECK_TIME 60000000 + +#ifndef Ndis802_11APMode +#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1) +#endif + +struct wlan_network { + struct list_head list; + int network_type; /*refer to ieee80211.h for WIRELESS_11A/B/G */ + int fixed; /* set to fixed when not to be removed asi + * site-surveying */ + unsigned int last_scanned; /*timestamp for the network */ + int aid; /*will only be valid when a BSS is joined. */ + int join_res; + struct ndis_wlan_bssid_ex network; /*must be the last item */ +}; + +enum VRTL_CARRIER_SENSE { + DISABLE_VCS, + ENABLE_VCS, + AUTO_VCS +}; + +enum VCS_TYPE { + NONE_VCS, + RTS_CTS, + CTS_TO_SELF +}; + +#define PWR_CAM 0 +#define PWR_MINPS 1 +#define PWR_MAXPS 2 +#define PWR_UAPSD 3 +#define PWR_VOIP 4 + +enum UAPSD_MAX_SP { + NO_LIMIT, + TWO_MSDU, + FOUR_MSDU, + SIX_MSDU +}; + +#define NUM_PRE_AUTH_KEY 16 +#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY + +/* + * WPA2 + */ +struct wlan_bssid_ex { + u32 Length; + unsigned char MacAddress[6]; + u8 Reserved[2]; + struct ndis_802_11_ssid Ssid; + u32 Privacy; + s32 Rssi; + enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; + struct NDIS_802_11_CONFIGURATION Configuration; + enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + NDIS_802_11_RATES_EX SupportedRates; + u32 IELength; + u8 IEs[MAX_IE_SZ]; /* (timestamp, beacon interval, and capability + * information) */ +}; + +#endif /* #ifndef WLAN_BSSDEF_H_ */ + diff --git a/kernel/drivers/staging/rtl8712/xmit_linux.c b/kernel/drivers/staging/rtl8712/xmit_linux.c new file mode 100644 index 000000000..d15fb1ad4 --- /dev/null +++ b/kernel/drivers/staging/rtl8712/xmit_linux.c @@ -0,0 +1,198 @@ +/****************************************************************************** + * xmit_linux.c + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192SU + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ + +#define _XMIT_OSDEP_C_ + +#include <linux/usb.h> +#include <linux/ip.h> +#include <linux/if_ether.h> + +#include "osdep_service.h" +#include "drv_types.h" + +#include "wifi.h" +#include "mlme_osdep.h" +#include "xmit_osdep.h" +#include "osdep_intf.h" + +static uint remainder_len(struct pkt_file *pfile) +{ + return (uint)(pfile->buf_len - ((addr_t)(pfile->cur_addr) - + (addr_t)(pfile->buf_start))); +} + +void _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) +{ + pfile->pkt = pktptr; + pfile->cur_addr = pfile->buf_start = pktptr->data; + pfile->pkt_len = pfile->buf_len = pktptr->len; + pfile->cur_buffer = pfile->buf_start; +} + +uint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) +{ + uint len; + + len = remainder_len(pfile); + len = (rlen > len) ? len : rlen; + if (rmem) + skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, + rmem, len); + pfile->cur_addr += len; + pfile->pkt_len -= len; + return len; +} + +sint r8712_endofpktfile(struct pkt_file *pfile) +{ + if (pfile->pkt_len == 0) + return true; + else + return false; +} + + +void r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) +{ + struct ethhdr etherhdr; + struct iphdr ip_hdr; + u16 UserPriority = 0; + + _r8712_open_pktfile(ppktfile->pkt, ppktfile); + _r8712_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); + + /* get UserPriority from IP hdr*/ + if (pattrib->ether_type == 0x0800) { + _r8712_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); + /*UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3 ;*/ + UserPriority = ip_hdr.tos >> 5; + } else { + /* "When priority processing of data frames is supported, + * a STA's SME should send EAPOL-Key frames at the highest + * priority." */ + + if (pattrib->ether_type == 0x888e) + UserPriority = 7; + } + pattrib->priority = UserPriority; + pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; + pattrib->subtype = WIFI_QOS_DATA_TYPE; +} + +void r8712_SetFilter(struct work_struct *work) +{ + struct _adapter *padapter = container_of(work, struct _adapter, + wkFilterRxFF0); + u8 oldvalue = 0x00, newvalue = 0x00; + unsigned long irqL; + + oldvalue = r8712_read8(padapter, 0x117); + newvalue = oldvalue & 0xfe; + r8712_write8(padapter, 0x117, newvalue); + + spin_lock_irqsave(&padapter->lockRxFF0Filter, irqL); + padapter->blnEnableRxFF0Filter = 1; + spin_unlock_irqrestore(&padapter->lockRxFF0Filter, irqL); + do { + msleep(100); + } while (padapter->blnEnableRxFF0Filter == 1); + r8712_write8(padapter, 0x117, oldvalue); +} + +int r8712_xmit_resource_alloc(struct _adapter *padapter, + struct xmit_buf *pxmitbuf) +{ + int i; + + for (i = 0; i < 8; i++) { + pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); + if (pxmitbuf->pxmit_urb[i] == NULL) { + netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n"); + return _FAIL; + } + } + return _SUCCESS; +} + +void r8712_xmit_resource_free(struct _adapter *padapter, + struct xmit_buf *pxmitbuf) +{ + int i; + + for (i = 0; i < 8; i++) { + if (pxmitbuf->pxmit_urb[i]) { + usb_kill_urb(pxmitbuf->pxmit_urb[i]); + usb_free_urb(pxmitbuf->pxmit_urb[i]); + } + } +} + +void r8712_xmit_complete(struct _adapter *padapter, struct xmit_frame *pxframe) +{ + if (pxframe->pkt) + dev_kfree_skb_any(pxframe->pkt); + pxframe->pkt = NULL; +} + +int r8712_xmit_entry(_pkt *pkt, struct net_device *pnetdev) +{ + struct xmit_frame *pxmitframe = NULL; + struct _adapter *padapter = netdev_priv(pnetdev); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + int ret = 0; + + if (r8712_if_up(padapter) == false) { + ret = 0; + goto _xmit_entry_drop; + } + pxmitframe = r8712_alloc_xmitframe(pxmitpriv); + if (pxmitframe == NULL) { + ret = 0; + goto _xmit_entry_drop; + } + if ((!r8712_update_attrib(padapter, pkt, &pxmitframe->attrib))) { + ret = 0; + goto _xmit_entry_drop; + } + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_TX); + pxmitframe->pkt = pkt; + if (r8712_pre_xmit(padapter, pxmitframe) == true) { + /*dump xmitframe directly or drop xframe*/ + dev_kfree_skb_any(pkt); + pxmitframe->pkt = NULL; + } + pxmitpriv->tx_pkts++; + pxmitpriv->tx_bytes += pxmitframe->attrib.last_txcmdsz; + return ret; +_xmit_entry_drop: + if (pxmitframe) + r8712_free_xmitframe(pxmitpriv, pxmitframe); + pxmitpriv->tx_drop++; + dev_kfree_skb_any(pkt); + return ret; +} diff --git a/kernel/drivers/staging/rtl8712/xmit_osdep.h b/kernel/drivers/staging/rtl8712/xmit_osdep.h new file mode 100644 index 000000000..8eba7ca0d --- /dev/null +++ b/kernel/drivers/staging/rtl8712/xmit_osdep.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Modifications for inclusion into the Linux staging tree are + * Copyright(c) 2010 Larry Finger. All rights reserved. + * + * Contact information: + * WLAN FAE <wlanfae@realtek.com> + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __XMIT_OSDEP_H_ +#define __XMIT_OSDEP_H_ + +#include "osdep_service.h" +#include "drv_types.h" + +struct pkt_file { + _pkt *pkt; + u32 pkt_len; /*the remainder length of the open_file*/ + _buffer *cur_buffer; + u8 *buf_start; + u8 *cur_addr; + u32 buf_len; +}; + +#define NR_XMITFRAME 256 + +struct xmit_priv; +struct pkt_attrib; +struct sta_xmit_priv; +struct xmit_frame; +struct xmit_buf; + +int r8712_xmit_entry(_pkt *pkt, struct net_device *pnetdev); +void r8712_SetFilter(struct work_struct *work); +int r8712_xmit_resource_alloc(struct _adapter *padapter, + struct xmit_buf *pxmitbuf); +void r8712_xmit_resource_free(struct _adapter *padapter, + struct xmit_buf *pxmitbuf); + +void r8712_set_qos(struct pkt_file *ppktfile, + struct pkt_attrib *pattrib); +void _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile); +uint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen); +sint r8712_endofpktfile(struct pkt_file *pfile); +void r8712_xmit_complete(struct _adapter *padapter, + struct xmit_frame *pxframe); + +#endif |