diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-12-05 04:01:41 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 21:52:31 (GMT) |
commit | c8d86be38785705aca77e33933298c320a1bf2a5 (patch) | |
tree | b188305415619e6901fb2f259861110d5762041a /drivers/staging/rtl8187se | |
parent | c8801d8c9f639153afb7c4926654f0769483348e (diff) | |
download | linux-fsl-qoriq-c8d86be38785705aca77e33933298c320a1bf2a5.tar.xz |
Staging: add rtl8187se driver
This is a driver for the Realtek 8187 "SE" wireless PCI devices in some
netbook computers (MSI Wind, and others). It includes its own copy of
the ieee80211 stack, but it is compiled into the driver to prevend
duplicate symbol issues.
This version comes from Ralink with no authorship, but it is based
on an old version of the rtl8180 driver from Andrea Merello. It was
hacked up a bit to get it to build properly within the kernel tree and
to properly handle the merged wireless stack within the driver.
Cc: Andrea Merello <andreamrl@tiscali.it>
Cc: linux-wireless <linux-wireless@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/rtl8187se')
57 files changed, 38284 insertions, 0 deletions
diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig new file mode 100644 index 0000000..79c225a --- /dev/null +++ b/drivers/staging/rtl8187se/Kconfig @@ -0,0 +1,5 @@ +config RTL8187SE + tristate "RealTek RTL8187SE Wireless LAN NIC driver" + depends on PCI + default N + ---help--- diff --git a/drivers/staging/rtl8187se/Makefile b/drivers/staging/rtl8187se/Makefile new file mode 100644 index 0000000..cc1c240 --- /dev/null +++ b/drivers/staging/rtl8187se/Makefile @@ -0,0 +1,54 @@ + +#EXTRA_CFLAGS += -DCONFIG_IEEE80211_NOWEP=y +#EXTRA_CFLAGS += -DCONFIG_RTL8180_IOMAP +#EXTRA_CFLAGS += -std=gnu89 +#EXTRA_CFLAGS += -O2 +#CC = gcc +EXTRA_CFLAGS += -DTHOMAS_TURBO +#CFLAGS += -DCONFIG_RTL8185B +#CFLAGS += -DCONFIG_RTL818x_S + +#added for EeePC testing +EXTRA_CFLAGS += -DENABLE_IPS +EXTRA_CFLAGS += -DSW_ANTE +EXTRA_CFLAGS += -DTX_TRACK +EXTRA_CFLAGS += -DHIGH_POWER +EXTRA_CFLAGS += -DSW_DIG +EXTRA_CFLAGS += -DRATE_ADAPT +EXTRA_CFLAGS += -DCONFIG_RTL8180_PM + +#+YJ,080626 +EXTRA_CFLAGS += -DENABLE_DOT11D + +#enable it for legacy power save, disable it for leisure power save +EXTRA_CFLAGS += -DENABLE_LPS + + +#EXTRA_CFLAGS += -mhard-float -DCONFIG_FORCE_HARD_FLOAT=y + +r8187se-objs := r8180_core.o \ + r8180_sa2400.o \ + r8180_93cx6.o \ + r8180_wx.o \ + r8180_max2820.o \ + r8180_gct.o \ + r8180_rtl8225.o \ + r8180_rtl8255.o \ + r8180_rtl8225z2.o \ + r8185b_init.o \ + r8180_dm.o \ + r8180_pm.o \ + ieee80211/dot11d.o \ + ieee80211/ieee80211_softmac.o \ + ieee80211/ieee80211_rx.o \ + ieee80211/ieee80211_tx.o \ + ieee80211/ieee80211_wx.o \ + ieee80211/ieee80211_module.o \ + ieee80211/ieee80211_softmac_wx.o \ + ieee80211/ieee80211_crypt.o \ + ieee80211/ieee80211_crypt_tkip.o \ + ieee80211/ieee80211_crypt_ccmp.o \ + ieee80211/ieee80211_crypt_wep.o + +obj-$(CONFIG_RTL8187SE) += r8187se.o + diff --git a/drivers/staging/rtl8187se/dot11d.h b/drivers/staging/rtl8187se/dot11d.h new file mode 100644 index 0000000..49f53fe --- /dev/null +++ b/drivers/staging/rtl8187se/dot11d.h @@ -0,0 +1,101 @@ +#ifndef __INC_DOT11D_H
+#define __INC_DOT11D_H
+
+#include "ieee80211.h"
+
+//#define ENABLE_DOT11D
+
+//#define DOT11D_MAX_CHNL_NUM 83
+
+typedef struct _CHNL_TXPOWER_TRIPLE {
+ u8 FirstChnl;
+ u8 NumChnls;
+ u8 MaxTxPowerInDbm;
+}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
+
+typedef enum _DOT11D_STATE {
+ DOT11D_STATE_NONE = 0,
+ DOT11D_STATE_LEARNED,
+ DOT11D_STATE_DONE,
+}DOT11D_STATE;
+
+typedef struct _RT_DOT11D_INFO {
+ //DECLARE_RT_OBJECT(RT_DOT11D_INFO);
+
+ bool bEnabled; // dot11MultiDomainCapabilityEnabled
+
+ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element.
+ u8 CountryIeBuf[MAX_IE_LEN];
+ u8 CountryIeSrcAddr[6]; // Source AP of the country IE.
+ u8 CountryIeWatchdog;
+
+ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
+ //u8 ChnlListLen; // #Bytes valid in ChnlList[].
+ //u8 ChnlList[DOT11D_MAX_CHNL_NUM];
+ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
+
+ DOT11D_STATE State;
+}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
+#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
+#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
+#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
+
+#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
+#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
+
+#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
+#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
+
+#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \
+ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \
+ FALSE : \
+ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length)))
+
+#define CIE_WATCHDOG_TH 1
+#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog
+#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0
+#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev)
+
+#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
+
+
+void
+Dot11d_Init(
+ struct ieee80211_device *dev
+ );
+
+void
+Dot11d_Reset(
+ struct ieee80211_device *dev
+ );
+
+void
+Dot11d_UpdateCountryIe(
+ struct ieee80211_device *dev,
+ u8 * pTaddr,
+ u16 CoutryIeLen,
+ u8 * pCoutryIe
+ );
+
+u8
+DOT11D_GetMaxTxPwrInDbm(
+ struct ieee80211_device *dev,
+ u8 Channel
+ );
+
+void
+DOT11D_ScanComplete(
+ struct ieee80211_device * dev
+ );
+
+int IsLegalChannel(
+ struct ieee80211_device * dev,
+ u8 channel
+);
+
+int ToLegalChannel(
+ struct ieee80211_device * dev,
+ u8 channel
+);
+
+#endif // #ifndef __INC_DOT11D_H
diff --git a/drivers/staging/rtl8187se/ieee80211.h b/drivers/staging/rtl8187se/ieee80211.h new file mode 100644 index 0000000..bf06abe --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211.h @@ -0,0 +1,1755 @@ +/* + * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * <jkmaline@cc.hut.fi> + * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * <jketreno@linux.intel.com> + * Copyright (c) 2004, Intel Corporation + * + * Modified for Realtek's wi-fi cards by Andrea Merello + * <andreamrl@tiscali.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ +#ifndef IEEE80211_H +#define IEEE80211_H +#include <linux/if_ether.h> /* ETH_ALEN */ +#include <linux/kernel.h> /* ARRAY_SIZE */ +#include <linux/version.h> +#include <linux/jiffies.h> +#include <linux/timer.h> +#include <linux/sched.h> + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) +#include <linux/wireless.h> +#endif + +/* +#ifndef bool +#define bool int +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif +*/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +#ifndef bool +typedef enum{false = 0, true} bool; +#endif +#endif +//#ifdef JOHN_HWSEC +#define KEY_TYPE_NA 0x0 +#define KEY_TYPE_WEP40 0x1 +#define KEY_TYPE_TKIP 0x2 +#define KEY_TYPE_CCMP 0x4 +#define KEY_TYPE_WEP104 0x5 +//#endif + + +#define aSifsTime 10 + +#define MGMT_QUEUE_NUM 5 + + +#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 +//It should consistent with the driver_XXX.c +// David, 2006.9.26 +#define IEEE_PARAM_WPAX_SELECT 7 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_PROTO_WPA 1 +#define IEEE_PROTO_RSN 2 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_WPAX_USEGROUP 0 +#define IEEE_WPAX_WEP40 1 +#define IEEE_WPAX_TKIP 2 +#define IEEE_WPAX_WRAP 3 +#define IEEE_WPAX_CCMP 4 +#define IEEE_WPAX_WEP104 5 + +#define IEEE_KEY_MGMT_IEEE8021X 1 +#define IEEE_KEY_MGMT_PSK 2 + + + +#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 + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) +#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rtl +#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rtl +#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rtl +//////////////////////////////// +// added for kernel conflict under FC5 +#define ieee80211_wx_get_name ieee80211_wx_get_name_rtl +#define free_ieee80211 free_ieee80211_rtl +#define alloc_ieee80211 alloc_ieee80211_rtl +/////////////////////////////// +#endif +//error in ubuntu2.6.22,so add these +#define ieee80211_wake_queue ieee80211_wake_queue_rtl +#define ieee80211_stop_queue ieee80211_stop_queue_rtl + +#define ieee80211_rx ieee80211_rx_rtl + +#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rtl +#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rtl +#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rtl +#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rtl +#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rtl +#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rtl + +#define ieee80211_txb_free ieee80211_txb_free_rtl +#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rtl +#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rtl +#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rtl +#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rtl +#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rtl +#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rtl +#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rtl +#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rtl +#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rtl +#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rtl +#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rtl +#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rtl +#define ieee80211_wx_set_power ieee80211_wx_set_power_rtl +#define ieee80211_wx_get_power ieee80211_wx_get_power_rtl +#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rtl +#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rtl +#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rtl +#define ieee80211_start_protocol ieee80211_start_protocol_rtl +#define ieee80211_stop_protocol ieee80211_stop_protocol_rtl +#define ieee80211_rx_mgt ieee80211_rx_mgt_rtl + +#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rtl +//by amy for ps +#define notify_wx_assoc_event notify_wx_assoc_event_rtl +#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rtl +#define ieee80211_disassociate ieee80211_disassociate_rtl +#define ieee80211_start_scan ieee80211_start_scan_rtl +//by amy for ps +typedef 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; +}ieee_param; + + +#if WIRELESS_EXT < 17 +#define IW_QUAL_QUAL_INVALID 0x10 +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_QUAL_UPDATED 0x1 +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#endif + +// linux under 2.6.9 release may not support it, so modify it for common use +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) +#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) +static inline unsigned long msleep_interruptible_rtl(unsigned int msecs) +{ + unsigned long timeout = MSECS(msecs) + 1; + + while (timeout) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } + return timeout; +} +#else +#define MSECS(t) msecs_to_jiffies(t) +#define msleep_interruptible_rtl msleep_interruptible +#endif + +#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 and modified from the madwifi driver*/ +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_DATA 0x08 +#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 + +#define IEEE80211_QOS_HAS_SEQ(fc) \ + (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +/* this is stolen from ipw2200 driver */ +#define IEEE_IBSS_MAC_HASH_SIZE 31 +struct ieee_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num[17]; + u16 frag_num[17]; + unsigned long packet_time[17]; + 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]; +} __attribute__ ((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 QOS_ctl; +} __attribute__ ((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; +} __attribute__ ((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 QOS_ctl; +} __attribute__ ((packed)); + +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, + EAPOL_LOGOFF, + EAPOL_KEY, + EAPOL_ENCAP_ASF_ALERT +}; + +static const char *eap_types[] = { + [EAP_PACKET] = "EAP-Packet", + [EAPOL_START] = "EAPOL-Start", + [EAPOL_LOGOFF] = "EAPOL-Logoff", + [EAPOL_KEY] = "EAPOL-Key", + [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" +}; + +static inline const char *eap_get_type(int type) +{ + return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; +} + +struct eapol { + u8 snap[6]; + u16 ethertype; + u8 version; + u8 type; + u16 length; +} __attribute__ ((packed)); + +#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_DSTODS 0x0300 //added by david +#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 +#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 + +/* 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_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 +#define IEEE80211_STYPE_QOS_NULL 0x00C0 + + +#define IEEE80211_SCTL_FRAG 0x000F +#define IEEE80211_SCTL_SEQ 0xFFF0 + + +/* debug macros */ + +#ifdef CONFIG_IEEE80211_DEBUG +extern u32 ieee80211_debug_level; +#define IEEE80211_DEBUG(level, fmt, args...) \ +do { if (ieee80211_debug_level & (level)) \ + printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) +#else +#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) +#endif /* CONFIG_IEEE80211_DEBUG */ + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IEEE80211_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your + * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw/debug_level + * + * you simply need to add your entry to the ipw_debug_levels array. + * + * If you do not see debug_level in /proc/net/ipw then you do not have + * CONFIG_IEEE80211_DEBUG defined in your kernel configuration + * + */ + +#define IEEE80211_DL_INFO (1<<0) +#define IEEE80211_DL_WX (1<<1) +#define IEEE80211_DL_SCAN (1<<2) +#define IEEE80211_DL_STATE (1<<3) +#define IEEE80211_DL_MGMT (1<<4) +#define IEEE80211_DL_FRAG (1<<5) +#define IEEE80211_DL_EAP (1<<6) +#define IEEE80211_DL_DROP (1<<7) + +#define IEEE80211_DL_TX (1<<8) +#define IEEE80211_DL_RX (1<<9) + +#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) +#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) +#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) + +#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) +#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) +//#define IEEE_DEBUG_SCAN IEEE80211_WARNING +#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) +#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) +#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) +#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) +#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) +#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) +#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <linux/if_arp.h> /* ARPHRD_ETHER */ + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY // enable iwspy support +#endif +#include <net/iw_handler.h> // new driver API + +#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 */ + +#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 */ + +} __attribute__ ((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_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_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 { + u32 mac_time[2]; + u8 signalstrength; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u8 nic_type; +}; + +/* 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 { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct ieee80211_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct ieee80211_softmac_stats{ + unsigned int rx_ass_ok; + unsigned int rx_ass_err; + unsigned int rx_probe_rq; + unsigned int tx_probe_rs; + unsigned int tx_beacons; + unsigned int rx_auth_rq; + unsigned int rx_auth_rs_ok; + unsigned int rx_auth_rs_err; + unsigned int tx_auth_rq; + unsigned int no_auth_rs; + unsigned int no_ass_rs; + unsigned int tx_ass_rq; + unsigned int rx_ass_rq; + unsigned int tx_probe_rq; + unsigned int reassoc; + unsigned int swtxstop; + unsigned int swtxawake; +}; + +struct ieee80211_device; + +#include "ieee80211_crypt.h" + +#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 + +#define WEP_KEY_LEN_MODIF 32 + +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_MODIF]; + u8 level; + u16 flags; +} __attribute__ ((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_COUNTRY 7 //+YJ,080625 +#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 + +#ifdef ENABLE_DOT11D +typedef enum +{ + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC = 8, + COUNTRY_CODE_GLOBAL_DOMAIN = 9, + COUNTRY_CODE_WORLD_WIDE_13_INDEX = 10 +}country_code_type_t; +#endif + +struct ieee80211_info_element_hdr { + u8 id; + u8 len; +} __attribute__ ((packed)); + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((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; + } __attribute__ ((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; + //struct ieee80211_info_element_hdr info_element; +} __attribute__ ((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; +} __attribute__ ((packed)); + +struct ieee80211_probe_request { + struct ieee80211_header_data header; + /*struct ieee80211_info_element info_element;*/ +} __attribute__ ((packed)); + +struct ieee80211_assoc_request_frame { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 listen_interval; + //u8 current_ap[ETH_ALEN]; + struct ieee80211_info_element_hdr info_element; +} __attribute__ ((packed)); + +struct ieee80211_assoc_response_frame { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 status; + u16 aid; + struct ieee80211_info_element info_element; /* supported rates */ +} __attribute__ ((packed)); + +struct ieee80211_disassoc_frame{ + struct ieee80211_hdr_3addr header; + u16 reasoncode; +}__attribute__ ((packed)); + +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; + u16 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + +struct ieee80211_wmm_ac_param { + u8 ac_aci_acm_aifsn; + u8 ac_ecwmin_ecwmax; + u16 ac_txop_limit; +}; + +struct ieee80211_wmm_ts_info { + u8 ac_dir_tid; + u8 ac_up_psb; + u8 reserved; +} __attribute__ ((packed)); + +struct ieee80211_wmm_tspec_elem { + struct ieee80211_wmm_ts_info ts_info; + u16 norm_msdu_size; + u16 max_msdu_size; + u32 min_serv_inter; + u32 max_serv_inter; + u32 inact_inter; + u32 suspen_inter; + u32 serv_start_time; + u32 min_data_rate; + u32 mean_data_rate; + u32 peak_data_rate; + u32 max_burst_size; + u32 delay_bound; + u32 min_phy_rate; + u16 surp_band_allow; + u16 medium_time; +}__attribute__((packed)); + +enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; +#define MAX_SP_Len (WMM_all_frame << 4) +#define IEEE80211_QOS_TID 0x0f +#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) + +/* 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 MAX_CHANNEL_NUMBER 165 //YJ,modified,080625 +#define MAX_IE_LEN 0xFF //+YJ,080625 + +typedef struct _CHANNEL_LIST{ + u8 Channel[MAX_CHANNEL_NUMBER + 1]; + u8 Len; +}CHANNEL_LIST, *PCHANNEL_LIST; + +#define IEEE80211_SOFTMAC_SCAN_TIME 100//400 +//(HZ / 2) +//by amy for ps +#define IEEE80211_WATCH_DOG_TIME 2000 +//by amy for ps +//by amy for antenna +#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000 // 1000 m +//by amy for antenna +#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 + +#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 IEEE80211_PS_ENABLE IEEE80211_DTIM_VALID +//added by David for QoS 2006/6/30 +//#define WMM_Hang_8187 +#ifdef WMM_Hang_8187 +#undef WMM_Hang_8187 +#endif + +#define WME_AC_BE 0x00 +#define WME_AC_BK 0x01 +#define WME_AC_VI 0x02 +#define WME_AC_VO 0x03 +#define WME_ACI_MASK 0x03 +#define WME_AIFSN_MASK 0x03 +#define WME_AC_PRAM_LEN 16 + +//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP +//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) +#define UP2AC(up) ( \ + ((up) < 1) ? WME_AC_BE : \ + ((up) < 3) ? WME_AC_BK : \ + ((up) < 4) ? WME_AC_BE : \ + ((up) < 6) ? WME_AC_VI : \ + WME_AC_VO) +//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue +#define AC2UP(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +struct ether_header { + u8 ether_dhost[ETHER_ADDR_LEN]; + u8 ether_shost[ETHER_ADDR_LEN]; + u16 ether_type; +} __attribute__((packed)); + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif + +struct ieee80211_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + + /* These are network statistics */ + struct ieee80211_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u8 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + u8 dtim_period; + u8 dtim_data; + u32 last_dtim_sta_time[2]; + struct list_head list; + //appeded for QoS + u8 wmm_info; + struct ieee80211_wmm_ac_param wmm_param[4]; + u8 QoS_Enable; + u8 SignalStrength; +//by amy 080312 + u8 HighestOperaRate; +//by amy 080312 +#ifdef THOMAS_TURBO + u8 Turbo_Enable;//enable turbo mode, added by thomas +#endif +#ifdef ENABLE_DOT11D + u16 CountryIeLen; + u8 CountryIeBuf[MAX_IE_LEN]; +#endif +}; + +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 authentcated + * 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 MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] + + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) +extern inline int is_multicast_ether_addr(const u8 *addr) +{ + return ((addr[0] != 0xff) && (0x01 & addr[0])); +} +#endif + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) +extern inline int is_broadcast_ether_addr(const u8 *addr) +{ + return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ + (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); +} +#endif + +#define CFG_IEEE80211_RESERVE_FCS (1<<0) +#define CFG_IEEE80211_COMPUTE_FCS (1<<1) + +typedef struct tx_pending_t{ + int frag; + struct ieee80211_txb *txb; +}tx_pending_t; + + +struct ieee80211_device { + struct net_device *dev; + + /* Bookkeeping structures */ + struct net_device_stats stats; + struct ieee80211_stats ieee_stats; + struct ieee80211_softmac_stats softmac_stats; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct ieee80211_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + + spinlock_t lock; + spinlock_t wpax_suitlist_lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_decrypt; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + int wpa_enabled; + int drop_unencrypted; + int tkip_countermeasures; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + + u8 ap_mac_addr[6]; + u16 pairwise_key_type; + u16 broadcast_key_type; + + struct list_head crypt_deinit_list; + struct ieee80211_crypt_data *crypt[WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct timer_list crypt_deinit_timer; + + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + /* Fragmentation structures */ + // each streaming contain a entry + struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; + unsigned int frag_next_idx[17]; + u16 fts; /* Fragmentation Threshold */ + + /* This stores infos for the current network. + * Either the network we are associated in INFRASTRUCTURE + * or the network that we are creating in MASTER mode. + * ad-hoc is a mixture ;-). + * Note that in infrastructure mode, even when not associated, + * fields bssid and essid may be valid (if wpa_set and essid_set + * are true) as thy carry the value set by the user via iwconfig + */ + struct ieee80211_network current_network; + + + enum ieee80211_state state; + + int short_slot; + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_true; /* ABG flag */ + + /* used for forcing the ibss workqueue to terminate + * without wait for the syncro scan to terminate + */ + short sync_scan_hurryup; + +#ifdef ENABLE_DOT11D + void * pDot11dInfo; + bool bGlobalDomain; + + // For Liteon Ch12~13 passive scan + u8 MinPassiveChnlNum; + u8 IbssStartChnl; +#else + /* map of allowed channels. 0 is dummy */ + // FIXME: remeber to default to a basic channel plan depending of the PHY type + int channel_map[MAX_CHANNEL_NUMBER+1]; +#endif + + int rate; /* current rate */ + int basic_rate; + //FIXME: pleace callback, see if redundant with softmac_features + short active_scan; + + /* this contains flags for selectively enable softmac support */ + u16 softmac_features; + + /* if the sequence control field is not filled by HW */ + u16 seq_ctrl[5]; + + /* association procedure transaction sequence number */ + u16 associate_seq; + + /* AID for RTXed association responses */ + u16 assoc_id; + + /* power save mode related*/ + short ps; + short sta_sleep; + int ps_timeout; + struct tasklet_struct ps_task; + u32 ps_th; + u32 ps_tl; + + short raw_tx; + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + short queue_stop; + short scanning; + short proto_started; + + struct semaphore wx_sem; + struct semaphore scan_sem; + + spinlock_t mgmt_tx_lock; + spinlock_t beacon_lock; + + short beacon_txing; + + short wap_set; + short ssid_set; + + u8 wpax_type_set; //{added by David, 2006.9.28} + u32 wpax_type_notify; //{added by David, 2006.9.26} + + /* QoS related flag */ + char init_wmmparam_flag; + + /* for discarding duplicated packets in IBSS */ + struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; + + /* for discarding duplicated packets in BSS */ + u16 last_rxseq_num[17]; /* rx seq previous per-tid */ + u16 last_rxfrag_num[17];/* tx frag previous per-tid */ + unsigned long last_packet_time[17]; + + /* for PS mode */ + unsigned long last_rx_ps_time; + + /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ + struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; + int mgmt_queue_head; + int mgmt_queue_tail; + + + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + struct tx_pending_t tx_pending; + + /* used if IEEE_SOFTMAC_ASSOCIATE is set */ + struct timer_list associate_timer; + + /* used if IEEE_SOFTMAC_BEACONS is set */ + struct timer_list beacon_timer; + + struct work_struct associate_complete_wq; +// struct work_struct associate_retry_wq; + struct work_struct associate_procedure_wq; +// struct work_struct softmac_scan_wq; + struct work_struct wx_sync_scan_wq; + struct work_struct wmm_param_update_wq; + struct work_struct ps_request_tx_ack_wq;//for ps +// struct work_struct hw_wakeup_wq; +// struct work_struct hw_sleep_wq; +// struct work_struct watch_dog_wq; + bool bInactivePs; + bool actscanning; + bool beinretry; + u16 ListenInterval; + unsigned long NumRxDataInPeriod; //YJ,add,080828 + unsigned long NumRxBcnInPeriod; //YJ,add,080828 + unsigned long NumRxOkTotal; + unsigned long NumRxUnicast;//YJ,add,080828,for keep alive + bool bHwRadioOff; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct delayed_work softmac_scan_wq; + struct delayed_work associate_retry_wq; + struct delayed_work hw_wakeup_wq; + struct delayed_work hw_sleep_wq;//+by amy 080324 + struct delayed_work watch_dog_wq; + struct delayed_work sw_antenna_wq; + struct delayed_work start_ibss_wq; +//by amy for rate adaptive 080312 + struct delayed_work rate_adapter_wq; +//by amy for rate adaptive + struct delayed_work hw_dig_wq; + struct delayed_work tx_pw_wq; + +//Added for RF power on power off by lizhaoming 080512 + struct delayed_work GPIOChangeRFWorkItem; +#else + + struct work_struct start_ibss_wq; + struct work_struct softmac_scan_wq; + struct work_struct associate_retry_wq; + struct work_struct hw_wakeup_wq; + struct work_struct hw_sleep_wq; + struct work_struct watch_dog_wq; + struct work_struct sw_antenna_wq; +//by amy for rate adaptive 080312 + struct work_struct rate_adapter_wq; +//by amy for rate adaptive + struct work_struct hw_dig_wq; + struct work_struct tx_pw_wq; + +//Added for RF power on power off by lizhaoming 080512 + struct work_struct GPIOChangeRFWorkItem; +#endif + struct workqueue_struct *wq; + + /* Callback functions */ + void (*set_security)(struct net_device *dev, + struct ieee80211_security *sec); + + /* Used to TX data frame by using txb structs. + * this is not used if in the softmac_features + * is set the flag IEEE_SOFTMAC_TX_QUEUE + */ + int (*hard_start_xmit)(struct ieee80211_txb *txb, + struct net_device *dev); + + int (*reset_port)(struct net_device *dev); + + /* Softmac-generated frames (mamagement) are TXed via this + * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is + * not set. As some cards may have different HW queues that + * one might want to use for data and management frames + * the option to have two callbacks might be useful. + * This fucntion can't sleep. + */ + int (*softmac_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev); + + /* used instead of hard_start_xmit (not softmac_hard_start_xmit) + * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data + * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * then also management frames are sent via this callback. + * This function can't sleep. + */ + void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev,int rate); + + /* stops the HW queue for DATA frames. Useful to avoid + * waste time to TX data frame when we are reassociating + * This function can sleep. + */ + void (*data_hard_stop)(struct net_device *dev); + + /* OK this is complementar to data_poll_hard_stop */ + void (*data_hard_resume)(struct net_device *dev); + + /* ask to the driver to retune the radio . + * This function can sleep. the driver should ensure + * the radio has been swithced before return. + */ + void (*set_chan)(struct net_device *dev,short ch); + + /* These are not used if the ieee stack takes care of + * scanning (IEEE_SOFTMAC_SCAN feature set). + * In this case only the set_chan is used. + * + * The syncro version is similar to the start_scan but + * does not return until all channels has been scanned. + * this is called in user context and should sleep, + * it is called in a work_queue when swithcing to ad-hoc mode + * or in behalf of iwlist scan when the card is associated + * and root user ask for a scan. + * the fucntion stop_scan should stop both the syncro and + * background scanning and can sleep. + * The fucntion start_scan should initiate the background + * scanning and can't sleep. + */ + void (*scan_syncro)(struct net_device *dev); + void (*start_scan)(struct net_device *dev); + void (*stop_scan)(struct net_device *dev); + + /* indicate the driver that the link state is changed + * for example it may indicate the card is associated now. + * Driver might be interested in this to apply RX filter + * rules or simply light the LINK led + */ + void (*link_change)(struct net_device *dev); + + /* these two function indicates to the HW when to start + * and stop to send beacons. This is used when the + * IEEE_SOFTMAC_BEACONS is not set. For now the + * stop_send_bacons is NOT guaranteed to be called only + * after start_send_beacons. + */ + void (*start_send_beacons) (struct net_device *dev); + void (*stop_send_beacons) (struct net_device *dev); + + /* power save mode related */ + void (*sta_wake_up) (struct net_device *dev); + void (*ps_request_tx_ack) (struct net_device *dev); + void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); + short (*ps_is_queue_empty) (struct net_device *dev); + + /* QoS related */ + //void (*wmm_param_update) (struct net_device *dev, u8 *ac_param); + //void (*wmm_param_update) (struct ieee80211_device *ieee); + + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_ieee80211 */ + u8 priv[0]; +}; + +#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) + +/* Generate a 802.11 header */ + +/* Uses the channel change callback directly + * instead of [start/stop] scan callbacks + */ +#define IEEE_SOFTMAC_SCAN (1<<2) + +/* Perform authentication and association handshake */ +#define IEEE_SOFTMAC_ASSOCIATE (1<<3) + +/* Generate probe requests */ +#define IEEE_SOFTMAC_PROBERQ (1<<4) + +/* Generate respones to probe requests */ +#define IEEE_SOFTMAC_PROBERS (1<<5) + +/* The ieee802.11 stack will manages the netif queue + * wake/stop for the driver, taking care of 802.11 + * fragmentation. See softmac.c for details. */ +#define IEEE_SOFTMAC_TX_QUEUE (1<<7) + +/* Uses only the softmac_data_hard_start_xmit + * even for TX management frames. + */ +#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) + +/* Generate beacons. The stack will enqueue beacons + * to the card + */ +#define IEEE_SOFTMAC_BEACONS (1<<6) + + + +static inline void *ieee80211_priv(struct net_device *dev) +{ + return ((struct ieee80211_device *)netdev_priv(dev))->priv; +} + +extern 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; +} + +extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) +{ + /* + * It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + * + */ + if ((mode & IEEE_A) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & IEEE80211_CCK_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + return 0; +} + +extern inline int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = 30; /* Addr4 */ + if(IEEE80211_QOS_HAS_SEQ(fc)) + hdrlen += 2; /* QOS ctrl*/ + 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; +} + + + +/* ieee80211.c */ +extern void free_ieee80211(struct net_device *dev); +extern struct net_device *alloc_ieee80211(int sizeof_priv); + +extern int ieee80211_set_encryption(struct ieee80211_device *ieee); + +/* ieee80211_tx.c */ + +extern int ieee80211_encrypt_fragment( + struct ieee80211_device *ieee, + struct sk_buff *frag, + int hdr_len); + +extern int ieee80211_xmit(struct sk_buff *skb, + struct net_device *dev); +extern void ieee80211_txb_free(struct ieee80211_txb *); + + +/* ieee80211_rx.c */ +extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats); +extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr *header, + struct ieee80211_rx_stats *stats); + +/* ieee80211_wx.c */ +extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data* wrqu, char *extra); +int ieee80211_wx_set_auth(struct ieee80211_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra); +int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); +/* ieee80211_softmac.c */ +extern short ieee80211_is_54g(struct ieee80211_network net); +extern short ieee80211_is_shortslot(struct ieee80211_network net); +extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype); +extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); + +extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); +extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_ibss(struct ieee80211_device *ieee); +extern void ieee80211_softmac_init(struct ieee80211_device *ieee); +extern void ieee80211_softmac_free(struct ieee80211_device *ieee); +extern void ieee80211_associate_abort(struct ieee80211_device *ieee); +extern void ieee80211_disassociate(struct ieee80211_device *ieee); +extern void ieee80211_stop_scan(struct ieee80211_device *ieee); +extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); +extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_reset_queue(struct ieee80211_device *ieee); +extern void ieee80211_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); +extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); +extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); +extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); +extern void notify_wx_assoc_event(struct ieee80211_device *ieee); +extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); +extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn); +extern void ieee80211_start_scan(struct ieee80211_device *ieee); + +//Add for RF power on power off by lizhaoming 080512 +extern void SendDisassociation(struct ieee80211_device *ieee, + u8* asSta, + u8 asRsn); + +/* ieee80211_crypt_ccmp&tkip&wep.c */ +extern void ieee80211_tkip_null(void); +extern void ieee80211_wep_null(void); +extern void ieee80211_ccmp_null(void); +/* ieee80211_softmac_wx.c */ + +extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *ext); + +extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra); + +extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); + +extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); +#else + extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); +#endif +//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); + +extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee); + +extern void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr); + +extern const long ieee80211_wlan_frequencies[]; + +extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +{ + ieee->scans++; +} + +extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +{ + return ieee->scans; +} + +static inline const char *escape_essid(const char *essid, u8 essid_len) { + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (ieee80211_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "<hidden>", sizeof("<hidden>")); + return escaped; + } + + essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else { + *d++ = *s++; + } + } + *d = '\0'; + return escaped; +} +#endif /* IEEE80211_H */ diff --git a/drivers/staging/rtl8187se/ieee80211/Makefile b/drivers/staging/rtl8187se/ieee80211/Makefile new file mode 100644 index 0000000..b5b78dc --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/Makefile @@ -0,0 +1,35 @@ + +#EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/wireless +#EXTRA_CFLAGS += -O2 + +EXTRA_CFLAGS += -DTHOMAS_TURBO +EXTRA_CFLAGS += -DENABLE_IPS + +ifeq ($(shell uname -r|cut -d. -f1,2,3,4), 2.6.16.60-0) +EXTRA_CFLAGS += -DOPENSUSE_SLED +endif + +ifeq ($(shell uname -r|cut -d. -f1,2,3,4), 2.6.26.3-29) +EXTRA_CFLAGS += -DFEDORACORE_9 +endif + + +#+YJ,080626 +EXTRA_CFLAGS += -DENABLE_DOT11D + +#enable it for legacy power save, disable it for leisure power save +#CFLAGS += -DENABLE_LPS + +ieee80211-rtl-objs := dot11d.o ieee80211_softmac.o ieee80211_rx.o ieee80211_tx.o ieee80211_wx.o ieee80211_module.o ieee80211_softmac_wx.o + +ieee80211_crypt-rtl-objs := ieee80211_crypt.o +ieee80211_crypt_tkip-rtl-objs := ieee80211_crypt_tkip.o +ieee80211_crypt_ccmp-rtl-objs := ieee80211_crypt_ccmp.o +ieee80211_crypt_wep-rtl-objs := ieee80211_crypt_wep.o + +obj-m +=ieee80211-rtl.o +obj-m +=ieee80211_crypt-rtl.o +obj-m +=ieee80211_crypt_wep-rtl.o +obj-m +=ieee80211_crypt_tkip-rtl.o +obj-m +=ieee80211_crypt_ccmp-rtl.o + diff --git a/drivers/staging/rtl8187se/ieee80211/aes.c b/drivers/staging/rtl8187se/ieee80211/aes.c new file mode 100644 index 0000000..0c176e2 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/aes.c @@ -0,0 +1,469 @@ +/* + * Cryptographic API. + * + * AES Cipher Algorithm. + * + * Based on Brian Gladman's code. + * + * Linux developers: + * Alexander Kjeldaas <astor@fast.no> + * Herbert Valerio Riedel <hvr@hvrlab.org> + * Kyle McMartin <kyle@debian.org> + * Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * --------------------------------------------------------------------------- + * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. + * All rights reserved. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +/* Some changes from the Gladman version: + s/RIJNDAEL(e_key)/E_KEY/g + s/RIJNDAEL(d_key)/D_KEY/g +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <asm/byteorder.h> + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define AES_BLOCK_SIZE 16 + +static inline +u32 generic_rotr32 (const u32 x, const unsigned bits) +{ + const unsigned n = bits % 32; + return (x >> n) | (x << (32 - n)); +} + +static inline +u32 generic_rotl32 (const u32 x, const unsigned bits) +{ + const unsigned n = bits % 32; + return (x << n) | (x >> (32 - n)); +} + +#define rotl generic_rotl32 +#define rotr generic_rotr32 + +/* + * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) + */ +inline static u8 +byte(const u32 x, const unsigned n) +{ + return x >> (n << 3); +} + +#define u32_in(x) le32_to_cpu(*(const u32 *)(x)) +#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from)) + +struct aes_ctx { + int key_length; + u32 E[60]; + u32 D[60]; +}; + +#define E_KEY ctx->E +#define D_KEY ctx->D + +static u8 pow_tab[256] __initdata; +static u8 log_tab[256] __initdata; +static u8 sbx_tab[256] __initdata; +static u8 isb_tab[256] __initdata; +static u32 rco_tab[10]; +static u32 ft_tab[4][256]; +static u32 it_tab[4][256]; + +static u32 fl_tab[4][256]; +static u32 il_tab[4][256]; + +static inline u8 __init +f_mult (u8 a, u8 b) +{ + u8 aa = log_tab[a], cc = aa + log_tab[b]; + + return pow_tab[cc + (cc < aa ? 1 : 0)]; +} + +#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) + +#define f_rn(bo, bi, n, k) \ + bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rn(bo, bi, n, k) \ + bo[n] = it_tab[0][byte(bi[n],0)] ^ \ + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#define ls_box(x) \ + ( fl_tab[0][byte(x, 0)] ^ \ + fl_tab[1][byte(x, 1)] ^ \ + fl_tab[2][byte(x, 2)] ^ \ + fl_tab[3][byte(x, 3)] ) + +#define f_rl(bo, bi, n, k) \ + bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] = il_tab[0][byte(bi[n],0)] ^ \ + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +static void __init +gen_tabs (void) +{ + u32 i, t; + u8 p, q; + + /* log and power tables for GF(2**8) finite field with + 0x011b as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables */ + + for (i = 0, p = 1; i < 256; ++i) { + pow_tab[i] = (u8) p; + log_tab[p] = (u8) i; + + p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + log_tab[1] = 0; + + for (i = 0, p = 1; i < 10; ++i) { + rco_tab[i] = p; + + p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + for (i = 0; i < 256; ++i) { + p = (i ? pow_tab[255 - log_tab[i]] : 0); + q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); + p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); + sbx_tab[i] = p; + isb_tab[p] = (u8) i; + } + + for (i = 0; i < 256; ++i) { + p = sbx_tab[i]; + + t = p; + fl_tab[0][i] = t; + fl_tab[1][i] = rotl (t, 8); + fl_tab[2][i] = rotl (t, 16); + fl_tab[3][i] = rotl (t, 24); + + t = ((u32) ff_mult (2, p)) | + ((u32) p << 8) | + ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); + + ft_tab[0][i] = t; + ft_tab[1][i] = rotl (t, 8); + ft_tab[2][i] = rotl (t, 16); + ft_tab[3][i] = rotl (t, 24); + + p = isb_tab[i]; + + t = p; + il_tab[0][i] = t; + il_tab[1][i] = rotl (t, 8); + il_tab[2][i] = rotl (t, 16); + il_tab[3][i] = rotl (t, 24); + + t = ((u32) ff_mult (14, p)) | + ((u32) ff_mult (9, p) << 8) | + ((u32) ff_mult (13, p) << 16) | + ((u32) ff_mult (11, p) << 24); + + it_tab[0][i] = t; + it_tab[1][i] = rotl (t, 8); + it_tab[2][i] = rotl (t, 16); + it_tab[3][i] = rotl (t, 24); + } +} + +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) + +#define imix_col(y,x) \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= rotr(u ^ t, 8) ^ \ + rotr(v ^ t, 16) ^ \ + rotr(t,24) + +/* initialise the key schedule from the user supplied key */ + +#define loop4(i) \ +{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ + t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ + t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ + t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ +} + +#define loop6(i) \ +{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ + t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ + t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ + t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ + t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ + t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ +} + +#define loop8(i) \ +{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ + t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ + t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ + t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ + t = E_KEY[8 * i + 4] ^ ls_box(t); \ + E_KEY[8 * i + 12] = t; \ + t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ + t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ + t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ +} + +static int +aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) +{ + struct aes_ctx *ctx = ctx_arg; + u32 i, t, u, v, w; + + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->key_length = key_len; + + E_KEY[0] = u32_in (in_key); + E_KEY[1] = u32_in (in_key + 4); + E_KEY[2] = u32_in (in_key + 8); + E_KEY[3] = u32_in (in_key + 12); + + switch (key_len) { + case 16: + t = E_KEY[3]; + for (i = 0; i < 10; ++i) + loop4 (i); + break; + + case 24: + E_KEY[4] = u32_in (in_key + 16); + t = E_KEY[5] = u32_in (in_key + 20); + for (i = 0; i < 8; ++i) + loop6 (i); + break; + + case 32: + E_KEY[4] = u32_in (in_key + 16); + E_KEY[5] = u32_in (in_key + 20); + E_KEY[6] = u32_in (in_key + 24); + t = E_KEY[7] = u32_in (in_key + 28); + for (i = 0; i < 7; ++i) + loop8 (i); + break; + } + + D_KEY[0] = E_KEY[0]; + D_KEY[1] = E_KEY[1]; + D_KEY[2] = E_KEY[2]; + D_KEY[3] = E_KEY[3]; + + for (i = 4; i < key_len + 24; ++i) { + imix_col (D_KEY[i], E_KEY[i]); + } + + return 0; +} + +/* encrypt a block of text */ + +#define f_nround(bo, bi, k) \ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k += 4 + +#define f_lround(bo, bi, k) \ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k) + +static void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx = ctx_arg; + u32 b0[4], b1[4]; + const u32 *kp = E_KEY + 4; + + b0[0] = u32_in (in) ^ E_KEY[0]; + b0[1] = u32_in (in + 4) ^ E_KEY[1]; + b0[2] = u32_in (in + 8) ^ E_KEY[2]; + b0[3] = u32_in (in + 12) ^ E_KEY[3]; + + if (ctx->key_length > 24) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + if (ctx->key_length > 16) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_lround (b0, b1, kp); + + u32_out (out, b0[0]); + u32_out (out + 4, b0[1]); + u32_out (out + 8, b0[2]); + u32_out (out + 12, b0[3]); +} + +/* decrypt a block of text */ + +#define i_nround(bo, bi, k) \ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k -= 4 + +#define i_lround(bo, bi, k) \ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k) + +static void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx = ctx_arg; + u32 b0[4], b1[4]; + const int key_len = ctx->key_length; + const u32 *kp = D_KEY + key_len + 20; + + b0[0] = u32_in (in) ^ E_KEY[key_len + 24]; + b0[1] = u32_in (in + 4) ^ E_KEY[key_len + 25]; + b0[2] = u32_in (in + 8) ^ E_KEY[key_len + 26]; + b0[3] = u32_in (in + 12) ^ E_KEY[key_len + 27]; + + if (key_len > 24) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + if (key_len > 16) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_lround (b0, b1, kp); + + u32_out (out, b0[0]); + u32_out (out + 4, b0[1]); + u32_out (out + 8, b0[2]); + u32_out (out + 12, b0[3]); +} + + +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt + } + } +}; + +static int __init aes_init(void) +{ + gen_tabs(); + return crypto_register_alg(&aes_alg); +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/drivers/staging/rtl8187se/ieee80211/api.c b/drivers/staging/rtl8187se/ieee80211/api.c new file mode 100644 index 0000000..c627d02 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/api.c @@ -0,0 +1,246 @@ +/* + * Scatterlist Cryptographic API. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * + * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> + * and Nettle, by Niels Mé°ˆler. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include "kmap_types.h" + +#include <linux/init.h> +#include <linux/module.h> +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <linux/errno.h> +#include <linux/rwsem.h> +#include <linux/slab.h> +#include "internal.h" + +LIST_HEAD(crypto_alg_list); +DECLARE_RWSEM(crypto_alg_sem); + +static inline int crypto_alg_get(struct crypto_alg *alg) +{ + return try_inc_mod_count(alg->cra_module); +} + +static inline void crypto_alg_put(struct crypto_alg *alg) +{ + if (alg->cra_module) + __MOD_DEC_USE_COUNT(alg->cra_module); +} + +struct crypto_alg *crypto_alg_lookup(const char *name) +{ + struct crypto_alg *q, *alg = NULL; + + if (!name) + return NULL; + + down_read(&crypto_alg_sem); + + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (!(strcmp(q->cra_name, name))) { + if (crypto_alg_get(q)) + alg = q; + break; + } + } + + up_read(&crypto_alg_sem); + return alg; +} + +static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) +{ + tfm->crt_flags = 0; + + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + return crypto_init_cipher_flags(tfm, flags); + + case CRYPTO_ALG_TYPE_DIGEST: + return crypto_init_digest_flags(tfm, flags); + + case CRYPTO_ALG_TYPE_COMPRESS: + return crypto_init_compress_flags(tfm, flags); + + default: + break; + } + + BUG(); + return -EINVAL; +} + +static int crypto_init_ops(struct crypto_tfm *tfm) +{ + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + return crypto_init_cipher_ops(tfm); + + case CRYPTO_ALG_TYPE_DIGEST: + return crypto_init_digest_ops(tfm); + + case CRYPTO_ALG_TYPE_COMPRESS: + return crypto_init_compress_ops(tfm); + + default: + break; + } + + BUG(); + return -EINVAL; +} + +static void crypto_exit_ops(struct crypto_tfm *tfm) +{ + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + crypto_exit_cipher_ops(tfm); + break; + + case CRYPTO_ALG_TYPE_DIGEST: + crypto_exit_digest_ops(tfm); + break; + + case CRYPTO_ALG_TYPE_COMPRESS: + crypto_exit_compress_ops(tfm); + break; + + default: + BUG(); + + } +} + +struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) +{ + struct crypto_tfm *tfm = NULL; + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name); + if (alg == NULL) + goto out; + + tfm = kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL); + if (tfm == NULL) + goto out_put; + + memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize); + + tfm->__crt_alg = alg; + + if (crypto_init_flags(tfm, flags)) + goto out_free_tfm; + + if (crypto_init_ops(tfm)) { + crypto_exit_ops(tfm); + goto out_free_tfm; + } + + goto out; + +out_free_tfm: + kfree(tfm); + tfm = NULL; +out_put: + crypto_alg_put(alg); +out: + return tfm; +} + +void crypto_free_tfm(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + int size = sizeof(*tfm) + alg->cra_ctxsize; + + crypto_exit_ops(tfm); + crypto_alg_put(alg); + memset(tfm, 0, size); + kfree(tfm); +} + +int crypto_register_alg(struct crypto_alg *alg) +{ + int ret = 0; + struct crypto_alg *q; + + down_write(&crypto_alg_sem); + + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (!(strcmp(q->cra_name, alg->cra_name))) { + ret = -EEXIST; + goto out; + } + } + + list_add_tail(&alg->cra_list, &crypto_alg_list); +out: + up_write(&crypto_alg_sem); + return ret; +} + +int crypto_unregister_alg(struct crypto_alg *alg) +{ + int ret = -ENOENT; + struct crypto_alg *q; + + BUG_ON(!alg->cra_module); + + down_write(&crypto_alg_sem); + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (alg == q) { + list_del(&alg->cra_list); + ret = 0; + goto out; + } + } +out: + up_write(&crypto_alg_sem); + return ret; +} + +int crypto_alg_available(const char *name, u32 flags) +{ + int ret = 0; + struct crypto_alg *alg = crypto_alg_mod_lookup(name); + + if (alg) { + crypto_alg_put(alg); + ret = 1; + } + + return ret; +} + +static int __init init_crypto(void) +{ + printk(KERN_INFO "Initializing Cryptographic API\n"); + crypto_init_proc(); + return 0; +} + +__initcall(init_crypto); + +/* +EXPORT_SYMBOL_GPL(crypto_register_alg); +EXPORT_SYMBOL_GPL(crypto_unregister_alg); +EXPORT_SYMBOL_GPL(crypto_alloc_tfm); +EXPORT_SYMBOL_GPL(crypto_free_tfm); +EXPORT_SYMBOL_GPL(crypto_alg_available); +*/ + +EXPORT_SYMBOL_NOVERS(crypto_register_alg); +EXPORT_SYMBOL_NOVERS(crypto_unregister_alg); +EXPORT_SYMBOL_NOVERS(crypto_alloc_tfm); +EXPORT_SYMBOL_NOVERS(crypto_free_tfm); +EXPORT_SYMBOL_NOVERS(crypto_alg_available); diff --git a/drivers/staging/rtl8187se/ieee80211/arc4.c b/drivers/staging/rtl8187se/ieee80211/arc4.c new file mode 100644 index 0000000..654f0e9 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/arc4.c @@ -0,0 +1,103 @@ +/* + * Cryptographic API + * + * ARC4 Cipher Algorithm + * + * Jon Oberheide <jon@oberheide.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include <linux/module.h> +#include <linux/init.h> +#include "rtl_crypto.h" + +#define ARC4_MIN_KEY_SIZE 1 +#define ARC4_MAX_KEY_SIZE 256 +#define ARC4_BLOCK_SIZE 1 + +struct arc4_ctx { + u8 S[256]; + u8 x, y; +}; + +static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) +{ + struct arc4_ctx *ctx = ctx_arg; + int i, j = 0, k = 0; + + ctx->x = 1; + ctx->y = 0; + + for(i = 0; i < 256; i++) + ctx->S[i] = i; + + for(i = 0; i < 256; i++) + { + u8 a = ctx->S[i]; + j = (j + in_key[k] + a) & 0xff; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = a; + if(++k >= key_len) + k = 0; + } + + return 0; +} + +static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in) +{ + struct arc4_ctx *ctx = ctx_arg; + + u8 *const S = ctx->S; + u8 x = ctx->x; + u8 y = ctx->y; + u8 a, b; + + a = S[x]; + y = (y + a) & 0xff; + b = S[y]; + S[x] = b; + S[y] = a; + x = (x + 1) & 0xff; + *out++ = *in ^ S[(a + b) & 0xff]; + + ctx->x = x; + ctx->y = y; +} + +static struct crypto_alg arc4_alg = { + .cra_name = "arc4", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = ARC4_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct arc4_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = ARC4_MIN_KEY_SIZE, + .cia_max_keysize = ARC4_MAX_KEY_SIZE, + .cia_setkey = arc4_set_key, + .cia_encrypt = arc4_crypt, + .cia_decrypt = arc4_crypt } } +}; + +static int __init arc4_init(void) +{ + return crypto_register_alg(&arc4_alg); +} + + +static void __exit arc4_exit(void) +{ + crypto_unregister_alg(&arc4_alg); +} + +module_init(arc4_init); +module_exit(arc4_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); +MODULE_AUTHOR("Jon Oberheide <jon@oberheide.org>"); diff --git a/drivers/staging/rtl8187se/ieee80211/autoload.c b/drivers/staging/rtl8187se/ieee80211/autoload.c new file mode 100644 index 0000000..c97756f --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/autoload.c @@ -0,0 +1,40 @@ +/* + * Cryptographic API. + * + * Algorithm autoloader. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include "kmap_types.h" + +#include <linux/kernel.h> +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <linux/string.h> +#include <linux/kmod.h> +#include "internal.h" + +/* + * A far more intelligent version of this is planned. For now, just + * try an exact match on the name of the algorithm. + */ +void crypto_alg_autoload(const char *name) +{ + request_module(name); +} + +struct crypto_alg *crypto_alg_mod_lookup(const char *name) +{ + struct crypto_alg *alg = crypto_alg_lookup(name); + if (alg == NULL) { + crypto_alg_autoload(name); + alg = crypto_alg_lookup(name); + } + return alg; +} diff --git a/drivers/staging/rtl8187se/ieee80211/cipher.c b/drivers/staging/rtl8187se/ieee80211/cipher.c new file mode 100644 index 0000000..1968acf --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/cipher.c @@ -0,0 +1,299 @@ +/* + * Cryptographic API. + * + * Cipher operations. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include <linux/kernel.h> +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/scatterlist.h> +#include "internal.h" +#include "scatterwalk.h" + +typedef void (cryptfn_t)(void *, u8 *, const u8 *); +typedef void (procfn_t)(struct crypto_tfm *, u8 *, + u8*, cryptfn_t, int enc, void *, int); + +static inline void xor_64(u8 *a, const u8 *b) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; +} + +static inline void xor_128(u8 *a, const u8 *b) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; + ((u32 *)a)[2] ^= ((u32 *)b)[2]; + ((u32 *)a)[3] ^= ((u32 *)b)[3]; +} + + +/* + * Generic encrypt/decrypt wrapper for ciphers, handles operations across + * multiple page boundaries by using temporary blocks. In user context, + * the kernel is given a chance to schedule us once per block. + */ +static int crypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, cryptfn_t crfn, + procfn_t prfn, int enc, void *info) +{ + struct scatter_walk walk_in, walk_out; + const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); + u8 tmp_src[bsize]; + u8 tmp_dst[bsize]; + + if (!nbytes) + return 0; + + if (nbytes % bsize) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; + return -EINVAL; + } + + scatterwalk_start(&walk_in, src); + scatterwalk_start(&walk_out, dst); + + for(;;) { + u8 *src_p, *dst_p; + int in_place; + + scatterwalk_map(&walk_in, 0); + scatterwalk_map(&walk_out, 1); + src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src); + dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst); + in_place = scatterwalk_samebuf(&walk_in, &walk_out, + src_p, dst_p); + + nbytes -= bsize; + + scatterwalk_copychunks(src_p, &walk_in, bsize, 0); + + prfn(tfm, dst_p, src_p, crfn, enc, info, in_place); + + scatterwalk_done(&walk_in, 0, nbytes); + + scatterwalk_copychunks(dst_p, &walk_out, bsize, 1); + scatterwalk_done(&walk_out, 1, nbytes); + + if (!nbytes) + return 0; + + crypto_yield(tfm); + } +} + +static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, + cryptfn_t fn, int enc, void *info, int in_place) +{ + u8 *iv = info; + + /* Null encryption */ + if (!iv) + return; + + if (enc) { + tfm->crt_u.cipher.cit_xor_block(iv, src); + fn(crypto_tfm_ctx(tfm), dst, iv); + memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm)); + } else { + u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0]; + u8 *buf = in_place ? stack : dst; + + fn(crypto_tfm_ctx(tfm), buf, src); + tfm->crt_u.cipher.cit_xor_block(buf, iv); + memcpy(iv, src, crypto_tfm_alg_blocksize(tfm)); + if (buf != dst) + memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm)); + } +} + +static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, + cryptfn_t fn, int enc, void *info, int in_place) +{ + fn(crypto_tfm_ctx(tfm), dst, src); +} + +static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; + + if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } else + return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen, + &tfm->crt_flags); +} + +static int ecb_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + ecb_process, 1, NULL); +} + +static int ecb_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + ecb_process, 1, NULL); +} + +static int cbc_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + cbc_process, 1, tfm->crt_cipher.cit_iv); +} + +static int cbc_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + cbc_process, 1, iv); +} + +static int cbc_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + cbc_process, 0, tfm->crt_cipher.cit_iv); +} + +static int cbc_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + cbc_process, 0, iv); +} + +static int nocrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return -ENOSYS; +} + +static int nocrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return -ENOSYS; +} + +int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) +{ + u32 mode = flags & CRYPTO_TFM_MODE_MASK; + + tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; + if (flags & CRYPTO_TFM_REQ_WEAK_KEY) + tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY; + + return 0; +} + +int crypto_init_cipher_ops(struct crypto_tfm *tfm) +{ + int ret = 0; + struct cipher_tfm *ops = &tfm->crt_cipher; + + ops->cit_setkey = setkey; + + switch (tfm->crt_cipher.cit_mode) { + case CRYPTO_TFM_MODE_ECB: + ops->cit_encrypt = ecb_encrypt; + ops->cit_decrypt = ecb_decrypt; + break; + + case CRYPTO_TFM_MODE_CBC: + ops->cit_encrypt = cbc_encrypt; + ops->cit_decrypt = cbc_decrypt; + ops->cit_encrypt_iv = cbc_encrypt_iv; + ops->cit_decrypt_iv = cbc_decrypt_iv; + break; + + case CRYPTO_TFM_MODE_CFB: + ops->cit_encrypt = nocrypt; + ops->cit_decrypt = nocrypt; + ops->cit_encrypt_iv = nocrypt_iv; + ops->cit_decrypt_iv = nocrypt_iv; + break; + + case CRYPTO_TFM_MODE_CTR: + ops->cit_encrypt = nocrypt; + ops->cit_decrypt = nocrypt; + ops->cit_encrypt_iv = nocrypt_iv; + ops->cit_decrypt_iv = nocrypt_iv; + break; + + default: + BUG(); + } + + if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) { + + switch (crypto_tfm_alg_blocksize(tfm)) { + case 8: + ops->cit_xor_block = xor_64; + break; + + case 16: + ops->cit_xor_block = xor_128; + break; + + default: + printk(KERN_WARNING "%s: block size %u not supported\n", + crypto_tfm_alg_name(tfm), + crypto_tfm_alg_blocksize(tfm)); + ret = -EINVAL; + goto out; + } + + ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm); + ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL); + if (ops->cit_iv == NULL) + ret = -ENOMEM; + } + +out: + return ret; +} + +void crypto_exit_cipher_ops(struct crypto_tfm *tfm) +{ + if (tfm->crt_cipher.cit_iv) + kfree(tfm->crt_cipher.cit_iv); +} diff --git a/drivers/staging/rtl8187se/ieee80211/compress.c b/drivers/staging/rtl8187se/ieee80211/compress.c new file mode 100644 index 0000000..c2df80e --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/compress.c @@ -0,0 +1,64 @@ +/* + * Cryptographic API. + * + * Compression operations. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include <linux/types.h> +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <linux/errno.h> +#include <asm/scatterlist.h> +#include <linux/string.h> +#include "internal.h" + +static int crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); +} + +static int crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); +} + +int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) +{ + return flags ? -EINVAL : 0; +} + +int crypto_init_compress_ops(struct crypto_tfm *tfm) +{ + int ret = 0; + struct compress_tfm *ops = &tfm->crt_compress; + + ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm)); + if (ret) + goto out; + + ops->cot_compress = crypto_compress; + ops->cot_decompress = crypto_decompress; + +out: + return ret; +} + +void crypto_exit_compress_ops(struct crypto_tfm *tfm) +{ + tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm)); +} diff --git a/drivers/staging/rtl8187se/ieee80211/digest.c b/drivers/staging/rtl8187se/ieee80211/digest.c new file mode 100644 index 0000000..1a95f2d --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/digest.c @@ -0,0 +1,108 @@ +/* + * Cryptographic API. + * + * Digest operations. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/highmem.h> +#include <asm/scatterlist.h> +#include "internal.h" + +static void init(struct crypto_tfm *tfm) +{ + tfm->__crt_alg->cra_digest.dia_init(crypto_tfm_ctx(tfm)); +} + +static void update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg) +{ + unsigned int i; + + for (i = 0; i < nsg; i++) { + + struct page *pg = sg[i].page; + unsigned int offset = sg[i].offset; + unsigned int l = sg[i].length; + + do { + unsigned int bytes_from_page = min(l, ((unsigned int) + (PAGE_SIZE)) - + offset); + char *p = crypto_kmap(pg, 0) + offset; + + tfm->__crt_alg->cra_digest.dia_update + (crypto_tfm_ctx(tfm), p, + bytes_from_page); + crypto_kunmap(p, 0); + crypto_yield(tfm); + offset = 0; + pg++; + l -= bytes_from_page; + } while (l > 0); + } +} + +static void final(struct crypto_tfm *tfm, u8 *out) +{ + tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out); +} + +static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + u32 flags; + if (tfm->__crt_alg->cra_digest.dia_setkey == NULL) + return -ENOSYS; + return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm), + key, keylen, &flags); +} + +static void digest(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg, u8 *out) +{ + unsigned int i; + + tfm->crt_digest.dit_init(tfm); + + for (i = 0; i < nsg; i++) { + char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset; + tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), + p, sg[i].length); + crypto_kunmap(p, 0); + crypto_yield(tfm); + } + crypto_digest_final(tfm, out); +} + +int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) +{ + return flags ? -EINVAL : 0; +} + +int crypto_init_digest_ops(struct crypto_tfm *tfm) +{ + struct digest_tfm *ops = &tfm->crt_digest; + + ops->dit_init = init; + ops->dit_update = update; + ops->dit_final = final; + ops->dit_digest = digest; + ops->dit_setkey = setkey; + + return crypto_alloc_hmac_block(tfm); +} + +void crypto_exit_digest_ops(struct crypto_tfm *tfm) +{ + crypto_free_hmac_block(tfm); +} diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.c b/drivers/staging/rtl8187se/ieee80211/dot11d.c new file mode 100644 index 0000000..5d8b752f --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/dot11d.c @@ -0,0 +1,246 @@ +#ifdef ENABLE_DOT11D
+//-----------------------------------------------------------------------------
+// File:
+// Dot11d.c
+//
+// Description:
+// Implement 802.11d.
+//
+//-----------------------------------------------------------------------------
+
+#include "dot11d.h"
+
+void
+Dot11d_Init(struct ieee80211_device *ieee)
+{
+ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
+
+ pDot11dInfo->bEnabled = 0;
+
+ pDot11dInfo->State = DOT11D_STATE_NONE;
+ pDot11dInfo->CountryIeLen = 0;
+ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
+ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
+ RESET_CIE_WATCHDOG(ieee);
+
+ printk("Dot11d_Init()\n");
+}
+
+//
+// Description:
+// Reset to the state as we are just entering a regulatory domain.
+//
+void
+Dot11d_Reset(struct ieee80211_device *ieee)
+{
+ u32 i;
+ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
+
+ // Clear old channel map
+ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
+ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
+ // Set new channel map
+ for (i=1; i<=11; i++) {
+ (pDot11dInfo->channel_map)[i] = 1;
+ }
+ for (i=12; i<=14; i++) {
+ (pDot11dInfo->channel_map)[i] = 2;
+ }
+
+ pDot11dInfo->State = DOT11D_STATE_NONE;
+ pDot11dInfo->CountryIeLen = 0;
+ RESET_CIE_WATCHDOG(ieee);
+
+ //printk("Dot11d_Reset()\n");
+}
+
+//
+// Description:
+// Update country IE from Beacon or Probe Resopnse
+// and configure PHY for operation in the regulatory domain.
+//
+// TODO:
+// Configure Tx power.
+//
+// Assumption:
+// 1. IS_DOT11D_ENABLE() is TRUE.
+// 2. Input IE is an valid one.
+//
+void
+Dot11d_UpdateCountryIe(
+ struct ieee80211_device *dev,
+ u8 * pTaddr,
+ u16 CoutryIeLen,
+ u8 * pCoutryIe
+ )
+{
+ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
+ u8 i, j, NumTriples, MaxChnlNum;
+ PCHNL_TXPOWER_TRIPLE pTriple;
+
+ if((CoutryIeLen - 3)%3 != 0)
+ {
+ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
+ Dot11d_Reset(dev);
+ return;
+ }
+
+ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
+ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
+ MaxChnlNum = 0;
+ NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string.
+ pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3);
+ for(i = 0; i < NumTriples; i++)
+ {
+ if(MaxChnlNum >= pTriple->FirstChnl)
+ { // It is not in a monotonically increasing order, so stop processing.
+ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
+ Dot11d_Reset(dev);
+ return;
+ }
+ if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls))
+ { // It is not a valid set of channel id, so stop processing.
+ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
+ Dot11d_Reset(dev);
+ return;
+ }
+
+ for(j = 0 ; j < pTriple->NumChnls; j++)
+ {
+ pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1;
+ pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm;
+ MaxChnlNum = pTriple->FirstChnl + j;
+ }
+
+ pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3);
+ }
+#if 1
+ //printk("Dot11d_UpdateCountryIe(): Channel List:\n");
+ printk("Channel List:");
+ for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
+ if(pDot11dInfo->channel_map[i] > 0)
+ printk(" %d", i);
+ printk("\n");
+#endif
+
+ UPDATE_CIE_SRC(dev, pTaddr);
+
+ pDot11dInfo->CountryIeLen = CoutryIeLen;
+ memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen);
+ pDot11dInfo->State = DOT11D_STATE_LEARNED;
+}
+
+void dump_chnl_map(u8 * channel_map)
+{
+ int i;
+ printk("Channel List:");
+ for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
+ if(channel_map[i] > 0)
+ printk(" %d(%d)", i, channel_map[i]);
+ printk("\n");
+}
+
+u8
+DOT11D_GetMaxTxPwrInDbm(
+ struct ieee80211_device *dev,
+ u8 Channel
+ )
+{
+ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
+ u8 MaxTxPwrInDbm = 255;
+
+ if(MAX_CHANNEL_NUMBER < Channel)
+ {
+ printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
+ return MaxTxPwrInDbm;
+ }
+ if(pDot11dInfo->channel_map[Channel])
+ {
+ MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel];
+ }
+
+ return MaxTxPwrInDbm;
+}
+
+
+void
+DOT11D_ScanComplete(
+ struct ieee80211_device * dev
+ )
+{
+ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
+
+ switch(pDot11dInfo->State)
+ {
+ case DOT11D_STATE_LEARNED:
+ pDot11dInfo->State = DOT11D_STATE_DONE;
+ break;
+
+ case DOT11D_STATE_DONE:
+ if( GET_CIE_WATCHDOG(dev) == 0 )
+ { // Reset country IE if previous one is gone.
+ Dot11d_Reset(dev);
+ }
+ break;
+ case DOT11D_STATE_NONE:
+ break;
+ }
+}
+
+int IsLegalChannel(
+ struct ieee80211_device * dev,
+ u8 channel
+)
+{
+ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
+
+ if(MAX_CHANNEL_NUMBER < channel)
+ {
+ printk("IsLegalChannel(): Invalid Channel\n");
+ return 0;
+ }
+ if(pDot11dInfo->channel_map[channel] > 0)
+ return 1;
+ return 0;
+}
+
+int ToLegalChannel(
+ struct ieee80211_device * dev,
+ u8 channel
+)
+{
+ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
+ u8 default_chn = 0;
+ u32 i = 0;
+
+ for (i=1; i<= MAX_CHANNEL_NUMBER; i++)
+ {
+ if(pDot11dInfo->channel_map[i] > 0)
+ {
+ default_chn = i;
+ break;
+ }
+ }
+
+ if(MAX_CHANNEL_NUMBER < channel)
+ {
+ printk("IsLegalChannel(): Invalid Channel\n");
+ return default_chn;
+ }
+
+ if(pDot11dInfo->channel_map[channel] > 0)
+ return channel;
+
+ return default_chn;
+}
+
+#if 0
+EXPORT_SYMBOL(Dot11d_Init);
+EXPORT_SYMBOL(Dot11d_Reset);
+EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
+EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
+EXPORT_SYMBOL(DOT11D_ScanComplete);
+EXPORT_SYMBOL(IsLegalChannel);
+EXPORT_SYMBOL(ToLegalChannel);
+#endif
+#endif
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.h b/drivers/staging/rtl8187se/ieee80211/dot11d.h new file mode 100644 index 0000000..64bcf15 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/dot11d.h @@ -0,0 +1,102 @@ +#ifndef __INC_DOT11D_H
+#define __INC_DOT11D_H
+
+#include "ieee80211.h"
+
+//#define ENABLE_DOT11D
+
+//#define DOT11D_MAX_CHNL_NUM 83
+
+typedef struct _CHNL_TXPOWER_TRIPLE {
+ u8 FirstChnl;
+ u8 NumChnls;
+ u8 MaxTxPowerInDbm;
+}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
+
+typedef enum _DOT11D_STATE {
+ DOT11D_STATE_NONE = 0,
+ DOT11D_STATE_LEARNED,
+ DOT11D_STATE_DONE,
+}DOT11D_STATE;
+
+typedef struct _RT_DOT11D_INFO {
+ //DECLARE_RT_OBJECT(RT_DOT11D_INFO);
+
+ bool bEnabled; // dot11MultiDomainCapabilityEnabled
+
+ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element.
+ u8 CountryIeBuf[MAX_IE_LEN];
+ u8 CountryIeSrcAddr[6]; // Source AP of the country IE.
+ u8 CountryIeWatchdog;
+
+ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
+ //u8 ChnlListLen; // #Bytes valid in ChnlList[].
+ //u8 ChnlList[DOT11D_MAX_CHNL_NUM];
+ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
+
+ DOT11D_STATE State;
+}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
+#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
+#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
+#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
+
+#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
+#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
+
+#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
+#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
+
+#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \
+ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \
+ FALSE : \
+ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length)))
+
+#define CIE_WATCHDOG_TH 1
+#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog
+#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0
+#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev)
+
+#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
+
+
+void
+Dot11d_Init(
+ struct ieee80211_device *dev
+ );
+
+void
+Dot11d_Reset(
+ struct ieee80211_device *dev
+ );
+
+void
+Dot11d_UpdateCountryIe(
+ struct ieee80211_device *dev,
+ u8 * pTaddr,
+ u16 CoutryIeLen,
+ u8 * pCoutryIe
+ );
+
+u8
+DOT11D_GetMaxTxPwrInDbm(
+ struct ieee80211_device *dev,
+ u8 Channel
+ );
+
+void
+DOT11D_ScanComplete(
+ struct ieee80211_device * dev
+ );
+
+int IsLegalChannel(
+ struct ieee80211_device * dev,
+ u8 channel
+);
+
+int ToLegalChannel(
+ struct ieee80211_device * dev,
+ u8 channel
+);
+
+void dump_chnl_map(u8 * channel_map);
+#endif // #ifndef __INC_DOT11D_H
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h new file mode 100644 index 0000000..bf06abe --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -0,0 +1,1755 @@ +/* + * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * <jkmaline@cc.hut.fi> + * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * <jketreno@linux.intel.com> + * Copyright (c) 2004, Intel Corporation + * + * Modified for Realtek's wi-fi cards by Andrea Merello + * <andreamrl@tiscali.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ +#ifndef IEEE80211_H +#define IEEE80211_H +#include <linux/if_ether.h> /* ETH_ALEN */ +#include <linux/kernel.h> /* ARRAY_SIZE */ +#include <linux/version.h> +#include <linux/jiffies.h> +#include <linux/timer.h> +#include <linux/sched.h> + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) +#include <linux/wireless.h> +#endif + +/* +#ifndef bool +#define bool int +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif +*/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +#ifndef bool +typedef enum{false = 0, true} bool; +#endif +#endif +//#ifdef JOHN_HWSEC +#define KEY_TYPE_NA 0x0 +#define KEY_TYPE_WEP40 0x1 +#define KEY_TYPE_TKIP 0x2 +#define KEY_TYPE_CCMP 0x4 +#define KEY_TYPE_WEP104 0x5 +//#endif + + +#define aSifsTime 10 + +#define MGMT_QUEUE_NUM 5 + + +#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 +//It should consistent with the driver_XXX.c +// David, 2006.9.26 +#define IEEE_PARAM_WPAX_SELECT 7 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_PROTO_WPA 1 +#define IEEE_PROTO_RSN 2 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_WPAX_USEGROUP 0 +#define IEEE_WPAX_WEP40 1 +#define IEEE_WPAX_TKIP 2 +#define IEEE_WPAX_WRAP 3 +#define IEEE_WPAX_CCMP 4 +#define IEEE_WPAX_WEP104 5 + +#define IEEE_KEY_MGMT_IEEE8021X 1 +#define IEEE_KEY_MGMT_PSK 2 + + + +#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 + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) +#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rtl +#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rtl +#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rtl +//////////////////////////////// +// added for kernel conflict under FC5 +#define ieee80211_wx_get_name ieee80211_wx_get_name_rtl +#define free_ieee80211 free_ieee80211_rtl +#define alloc_ieee80211 alloc_ieee80211_rtl +/////////////////////////////// +#endif +//error in ubuntu2.6.22,so add these +#define ieee80211_wake_queue ieee80211_wake_queue_rtl +#define ieee80211_stop_queue ieee80211_stop_queue_rtl + +#define ieee80211_rx ieee80211_rx_rtl + +#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rtl +#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rtl +#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rtl +#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rtl +#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rtl +#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rtl + +#define ieee80211_txb_free ieee80211_txb_free_rtl +#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rtl +#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rtl +#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rtl +#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rtl +#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rtl +#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rtl +#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rtl +#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rtl +#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rtl +#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rtl +#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rtl +#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rtl +#define ieee80211_wx_set_power ieee80211_wx_set_power_rtl +#define ieee80211_wx_get_power ieee80211_wx_get_power_rtl +#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rtl +#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rtl +#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rtl +#define ieee80211_start_protocol ieee80211_start_protocol_rtl +#define ieee80211_stop_protocol ieee80211_stop_protocol_rtl +#define ieee80211_rx_mgt ieee80211_rx_mgt_rtl + +#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rtl +//by amy for ps +#define notify_wx_assoc_event notify_wx_assoc_event_rtl +#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rtl +#define ieee80211_disassociate ieee80211_disassociate_rtl +#define ieee80211_start_scan ieee80211_start_scan_rtl +//by amy for ps +typedef 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; +}ieee_param; + + +#if WIRELESS_EXT < 17 +#define IW_QUAL_QUAL_INVALID 0x10 +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_QUAL_UPDATED 0x1 +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#endif + +// linux under 2.6.9 release may not support it, so modify it for common use +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) +#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) +static inline unsigned long msleep_interruptible_rtl(unsigned int msecs) +{ + unsigned long timeout = MSECS(msecs) + 1; + + while (timeout) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } + return timeout; +} +#else +#define MSECS(t) msecs_to_jiffies(t) +#define msleep_interruptible_rtl msleep_interruptible +#endif + +#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 and modified from the madwifi driver*/ +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_DATA 0x08 +#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 + +#define IEEE80211_QOS_HAS_SEQ(fc) \ + (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +/* this is stolen from ipw2200 driver */ +#define IEEE_IBSS_MAC_HASH_SIZE 31 +struct ieee_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num[17]; + u16 frag_num[17]; + unsigned long packet_time[17]; + 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]; +} __attribute__ ((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 QOS_ctl; +} __attribute__ ((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; +} __attribute__ ((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 QOS_ctl; +} __attribute__ ((packed)); + +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, + EAPOL_LOGOFF, + EAPOL_KEY, + EAPOL_ENCAP_ASF_ALERT +}; + +static const char *eap_types[] = { + [EAP_PACKET] = "EAP-Packet", + [EAPOL_START] = "EAPOL-Start", + [EAPOL_LOGOFF] = "EAPOL-Logoff", + [EAPOL_KEY] = "EAPOL-Key", + [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" +}; + +static inline const char *eap_get_type(int type) +{ + return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; +} + +struct eapol { + u8 snap[6]; + u16 ethertype; + u8 version; + u8 type; + u16 length; +} __attribute__ ((packed)); + +#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_DSTODS 0x0300 //added by david +#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 +#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 + +/* 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_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 +#define IEEE80211_STYPE_QOS_NULL 0x00C0 + + +#define IEEE80211_SCTL_FRAG 0x000F +#define IEEE80211_SCTL_SEQ 0xFFF0 + + +/* debug macros */ + +#ifdef CONFIG_IEEE80211_DEBUG +extern u32 ieee80211_debug_level; +#define IEEE80211_DEBUG(level, fmt, args...) \ +do { if (ieee80211_debug_level & (level)) \ + printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) +#else +#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) +#endif /* CONFIG_IEEE80211_DEBUG */ + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IEEE80211_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your + * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw/debug_level + * + * you simply need to add your entry to the ipw_debug_levels array. + * + * If you do not see debug_level in /proc/net/ipw then you do not have + * CONFIG_IEEE80211_DEBUG defined in your kernel configuration + * + */ + +#define IEEE80211_DL_INFO (1<<0) +#define IEEE80211_DL_WX (1<<1) +#define IEEE80211_DL_SCAN (1<<2) +#define IEEE80211_DL_STATE (1<<3) +#define IEEE80211_DL_MGMT (1<<4) +#define IEEE80211_DL_FRAG (1<<5) +#define IEEE80211_DL_EAP (1<<6) +#define IEEE80211_DL_DROP (1<<7) + +#define IEEE80211_DL_TX (1<<8) +#define IEEE80211_DL_RX (1<<9) + +#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) +#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) +#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) + +#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) +#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) +//#define IEEE_DEBUG_SCAN IEEE80211_WARNING +#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) +#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) +#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) +#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) +#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) +#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) +#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <linux/if_arp.h> /* ARPHRD_ETHER */ + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY // enable iwspy support +#endif +#include <net/iw_handler.h> // new driver API + +#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 */ + +#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 */ + +} __attribute__ ((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_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_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 { + u32 mac_time[2]; + u8 signalstrength; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u8 nic_type; +}; + +/* 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 { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct ieee80211_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct ieee80211_softmac_stats{ + unsigned int rx_ass_ok; + unsigned int rx_ass_err; + unsigned int rx_probe_rq; + unsigned int tx_probe_rs; + unsigned int tx_beacons; + unsigned int rx_auth_rq; + unsigned int rx_auth_rs_ok; + unsigned int rx_auth_rs_err; + unsigned int tx_auth_rq; + unsigned int no_auth_rs; + unsigned int no_ass_rs; + unsigned int tx_ass_rq; + unsigned int rx_ass_rq; + unsigned int tx_probe_rq; + unsigned int reassoc; + unsigned int swtxstop; + unsigned int swtxawake; +}; + +struct ieee80211_device; + +#include "ieee80211_crypt.h" + +#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 + +#define WEP_KEY_LEN_MODIF 32 + +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_MODIF]; + u8 level; + u16 flags; +} __attribute__ ((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_COUNTRY 7 //+YJ,080625 +#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 + +#ifdef ENABLE_DOT11D +typedef enum +{ + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC = 8, + COUNTRY_CODE_GLOBAL_DOMAIN = 9, + COUNTRY_CODE_WORLD_WIDE_13_INDEX = 10 +}country_code_type_t; +#endif + +struct ieee80211_info_element_hdr { + u8 id; + u8 len; +} __attribute__ ((packed)); + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((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; + } __attribute__ ((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; + //struct ieee80211_info_element_hdr info_element; +} __attribute__ ((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; +} __attribute__ ((packed)); + +struct ieee80211_probe_request { + struct ieee80211_header_data header; + /*struct ieee80211_info_element info_element;*/ +} __attribute__ ((packed)); + +struct ieee80211_assoc_request_frame { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 listen_interval; + //u8 current_ap[ETH_ALEN]; + struct ieee80211_info_element_hdr info_element; +} __attribute__ ((packed)); + +struct ieee80211_assoc_response_frame { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 status; + u16 aid; + struct ieee80211_info_element info_element; /* supported rates */ +} __attribute__ ((packed)); + +struct ieee80211_disassoc_frame{ + struct ieee80211_hdr_3addr header; + u16 reasoncode; +}__attribute__ ((packed)); + +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; + u16 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + +struct ieee80211_wmm_ac_param { + u8 ac_aci_acm_aifsn; + u8 ac_ecwmin_ecwmax; + u16 ac_txop_limit; +}; + +struct ieee80211_wmm_ts_info { + u8 ac_dir_tid; + u8 ac_up_psb; + u8 reserved; +} __attribute__ ((packed)); + +struct ieee80211_wmm_tspec_elem { + struct ieee80211_wmm_ts_info ts_info; + u16 norm_msdu_size; + u16 max_msdu_size; + u32 min_serv_inter; + u32 max_serv_inter; + u32 inact_inter; + u32 suspen_inter; + u32 serv_start_time; + u32 min_data_rate; + u32 mean_data_rate; + u32 peak_data_rate; + u32 max_burst_size; + u32 delay_bound; + u32 min_phy_rate; + u16 surp_band_allow; + u16 medium_time; +}__attribute__((packed)); + +enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; +#define MAX_SP_Len (WMM_all_frame << 4) +#define IEEE80211_QOS_TID 0x0f +#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) + +/* 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 MAX_CHANNEL_NUMBER 165 //YJ,modified,080625 +#define MAX_IE_LEN 0xFF //+YJ,080625 + +typedef struct _CHANNEL_LIST{ + u8 Channel[MAX_CHANNEL_NUMBER + 1]; + u8 Len; +}CHANNEL_LIST, *PCHANNEL_LIST; + +#define IEEE80211_SOFTMAC_SCAN_TIME 100//400 +//(HZ / 2) +//by amy for ps +#define IEEE80211_WATCH_DOG_TIME 2000 +//by amy for ps +//by amy for antenna +#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000 // 1000 m +//by amy for antenna +#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 + +#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 IEEE80211_PS_ENABLE IEEE80211_DTIM_VALID +//added by David for QoS 2006/6/30 +//#define WMM_Hang_8187 +#ifdef WMM_Hang_8187 +#undef WMM_Hang_8187 +#endif + +#define WME_AC_BE 0x00 +#define WME_AC_BK 0x01 +#define WME_AC_VI 0x02 +#define WME_AC_VO 0x03 +#define WME_ACI_MASK 0x03 +#define WME_AIFSN_MASK 0x03 +#define WME_AC_PRAM_LEN 16 + +//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP +//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) +#define UP2AC(up) ( \ + ((up) < 1) ? WME_AC_BE : \ + ((up) < 3) ? WME_AC_BK : \ + ((up) < 4) ? WME_AC_BE : \ + ((up) < 6) ? WME_AC_VI : \ + WME_AC_VO) +//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue +#define AC2UP(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +struct ether_header { + u8 ether_dhost[ETHER_ADDR_LEN]; + u8 ether_shost[ETHER_ADDR_LEN]; + u16 ether_type; +} __attribute__((packed)); + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif + +struct ieee80211_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + + /* These are network statistics */ + struct ieee80211_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u8 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + u8 dtim_period; + u8 dtim_data; + u32 last_dtim_sta_time[2]; + struct list_head list; + //appeded for QoS + u8 wmm_info; + struct ieee80211_wmm_ac_param wmm_param[4]; + u8 QoS_Enable; + u8 SignalStrength; +//by amy 080312 + u8 HighestOperaRate; +//by amy 080312 +#ifdef THOMAS_TURBO + u8 Turbo_Enable;//enable turbo mode, added by thomas +#endif +#ifdef ENABLE_DOT11D + u16 CountryIeLen; + u8 CountryIeBuf[MAX_IE_LEN]; +#endif +}; + +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 authentcated + * 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 MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] + + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) +extern inline int is_multicast_ether_addr(const u8 *addr) +{ + return ((addr[0] != 0xff) && (0x01 & addr[0])); +} +#endif + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) +extern inline int is_broadcast_ether_addr(const u8 *addr) +{ + return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ + (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); +} +#endif + +#define CFG_IEEE80211_RESERVE_FCS (1<<0) +#define CFG_IEEE80211_COMPUTE_FCS (1<<1) + +typedef struct tx_pending_t{ + int frag; + struct ieee80211_txb *txb; +}tx_pending_t; + + +struct ieee80211_device { + struct net_device *dev; + + /* Bookkeeping structures */ + struct net_device_stats stats; + struct ieee80211_stats ieee_stats; + struct ieee80211_softmac_stats softmac_stats; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct ieee80211_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + + spinlock_t lock; + spinlock_t wpax_suitlist_lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_decrypt; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + int wpa_enabled; + int drop_unencrypted; + int tkip_countermeasures; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + + u8 ap_mac_addr[6]; + u16 pairwise_key_type; + u16 broadcast_key_type; + + struct list_head crypt_deinit_list; + struct ieee80211_crypt_data *crypt[WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct timer_list crypt_deinit_timer; + + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + /* Fragmentation structures */ + // each streaming contain a entry + struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; + unsigned int frag_next_idx[17]; + u16 fts; /* Fragmentation Threshold */ + + /* This stores infos for the current network. + * Either the network we are associated in INFRASTRUCTURE + * or the network that we are creating in MASTER mode. + * ad-hoc is a mixture ;-). + * Note that in infrastructure mode, even when not associated, + * fields bssid and essid may be valid (if wpa_set and essid_set + * are true) as thy carry the value set by the user via iwconfig + */ + struct ieee80211_network current_network; + + + enum ieee80211_state state; + + int short_slot; + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_true; /* ABG flag */ + + /* used for forcing the ibss workqueue to terminate + * without wait for the syncro scan to terminate + */ + short sync_scan_hurryup; + +#ifdef ENABLE_DOT11D + void * pDot11dInfo; + bool bGlobalDomain; + + // For Liteon Ch12~13 passive scan + u8 MinPassiveChnlNum; + u8 IbssStartChnl; +#else + /* map of allowed channels. 0 is dummy */ + // FIXME: remeber to default to a basic channel plan depending of the PHY type + int channel_map[MAX_CHANNEL_NUMBER+1]; +#endif + + int rate; /* current rate */ + int basic_rate; + //FIXME: pleace callback, see if redundant with softmac_features + short active_scan; + + /* this contains flags for selectively enable softmac support */ + u16 softmac_features; + + /* if the sequence control field is not filled by HW */ + u16 seq_ctrl[5]; + + /* association procedure transaction sequence number */ + u16 associate_seq; + + /* AID for RTXed association responses */ + u16 assoc_id; + + /* power save mode related*/ + short ps; + short sta_sleep; + int ps_timeout; + struct tasklet_struct ps_task; + u32 ps_th; + u32 ps_tl; + + short raw_tx; + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + short queue_stop; + short scanning; + short proto_started; + + struct semaphore wx_sem; + struct semaphore scan_sem; + + spinlock_t mgmt_tx_lock; + spinlock_t beacon_lock; + + short beacon_txing; + + short wap_set; + short ssid_set; + + u8 wpax_type_set; //{added by David, 2006.9.28} + u32 wpax_type_notify; //{added by David, 2006.9.26} + + /* QoS related flag */ + char init_wmmparam_flag; + + /* for discarding duplicated packets in IBSS */ + struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; + + /* for discarding duplicated packets in BSS */ + u16 last_rxseq_num[17]; /* rx seq previous per-tid */ + u16 last_rxfrag_num[17];/* tx frag previous per-tid */ + unsigned long last_packet_time[17]; + + /* for PS mode */ + unsigned long last_rx_ps_time; + + /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ + struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; + int mgmt_queue_head; + int mgmt_queue_tail; + + + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + struct tx_pending_t tx_pending; + + /* used if IEEE_SOFTMAC_ASSOCIATE is set */ + struct timer_list associate_timer; + + /* used if IEEE_SOFTMAC_BEACONS is set */ + struct timer_list beacon_timer; + + struct work_struct associate_complete_wq; +// struct work_struct associate_retry_wq; + struct work_struct associate_procedure_wq; +// struct work_struct softmac_scan_wq; + struct work_struct wx_sync_scan_wq; + struct work_struct wmm_param_update_wq; + struct work_struct ps_request_tx_ack_wq;//for ps +// struct work_struct hw_wakeup_wq; +// struct work_struct hw_sleep_wq; +// struct work_struct watch_dog_wq; + bool bInactivePs; + bool actscanning; + bool beinretry; + u16 ListenInterval; + unsigned long NumRxDataInPeriod; //YJ,add,080828 + unsigned long NumRxBcnInPeriod; //YJ,add,080828 + unsigned long NumRxOkTotal; + unsigned long NumRxUnicast;//YJ,add,080828,for keep alive + bool bHwRadioOff; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct delayed_work softmac_scan_wq; + struct delayed_work associate_retry_wq; + struct delayed_work hw_wakeup_wq; + struct delayed_work hw_sleep_wq;//+by amy 080324 + struct delayed_work watch_dog_wq; + struct delayed_work sw_antenna_wq; + struct delayed_work start_ibss_wq; +//by amy for rate adaptive 080312 + struct delayed_work rate_adapter_wq; +//by amy for rate adaptive + struct delayed_work hw_dig_wq; + struct delayed_work tx_pw_wq; + +//Added for RF power on power off by lizhaoming 080512 + struct delayed_work GPIOChangeRFWorkItem; +#else + + struct work_struct start_ibss_wq; + struct work_struct softmac_scan_wq; + struct work_struct associate_retry_wq; + struct work_struct hw_wakeup_wq; + struct work_struct hw_sleep_wq; + struct work_struct watch_dog_wq; + struct work_struct sw_antenna_wq; +//by amy for rate adaptive 080312 + struct work_struct rate_adapter_wq; +//by amy for rate adaptive + struct work_struct hw_dig_wq; + struct work_struct tx_pw_wq; + +//Added for RF power on power off by lizhaoming 080512 + struct work_struct GPIOChangeRFWorkItem; +#endif + struct workqueue_struct *wq; + + /* Callback functions */ + void (*set_security)(struct net_device *dev, + struct ieee80211_security *sec); + + /* Used to TX data frame by using txb structs. + * this is not used if in the softmac_features + * is set the flag IEEE_SOFTMAC_TX_QUEUE + */ + int (*hard_start_xmit)(struct ieee80211_txb *txb, + struct net_device *dev); + + int (*reset_port)(struct net_device *dev); + + /* Softmac-generated frames (mamagement) are TXed via this + * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is + * not set. As some cards may have different HW queues that + * one might want to use for data and management frames + * the option to have two callbacks might be useful. + * This fucntion can't sleep. + */ + int (*softmac_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev); + + /* used instead of hard_start_xmit (not softmac_hard_start_xmit) + * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data + * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * then also management frames are sent via this callback. + * This function can't sleep. + */ + void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev,int rate); + + /* stops the HW queue for DATA frames. Useful to avoid + * waste time to TX data frame when we are reassociating + * This function can sleep. + */ + void (*data_hard_stop)(struct net_device *dev); + + /* OK this is complementar to data_poll_hard_stop */ + void (*data_hard_resume)(struct net_device *dev); + + /* ask to the driver to retune the radio . + * This function can sleep. the driver should ensure + * the radio has been swithced before return. + */ + void (*set_chan)(struct net_device *dev,short ch); + + /* These are not used if the ieee stack takes care of + * scanning (IEEE_SOFTMAC_SCAN feature set). + * In this case only the set_chan is used. + * + * The syncro version is similar to the start_scan but + * does not return until all channels has been scanned. + * this is called in user context and should sleep, + * it is called in a work_queue when swithcing to ad-hoc mode + * or in behalf of iwlist scan when the card is associated + * and root user ask for a scan. + * the fucntion stop_scan should stop both the syncro and + * background scanning and can sleep. + * The fucntion start_scan should initiate the background + * scanning and can't sleep. + */ + void (*scan_syncro)(struct net_device *dev); + void (*start_scan)(struct net_device *dev); + void (*stop_scan)(struct net_device *dev); + + /* indicate the driver that the link state is changed + * for example it may indicate the card is associated now. + * Driver might be interested in this to apply RX filter + * rules or simply light the LINK led + */ + void (*link_change)(struct net_device *dev); + + /* these two function indicates to the HW when to start + * and stop to send beacons. This is used when the + * IEEE_SOFTMAC_BEACONS is not set. For now the + * stop_send_bacons is NOT guaranteed to be called only + * after start_send_beacons. + */ + void (*start_send_beacons) (struct net_device *dev); + void (*stop_send_beacons) (struct net_device *dev); + + /* power save mode related */ + void (*sta_wake_up) (struct net_device *dev); + void (*ps_request_tx_ack) (struct net_device *dev); + void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); + short (*ps_is_queue_empty) (struct net_device *dev); + + /* QoS related */ + //void (*wmm_param_update) (struct net_device *dev, u8 *ac_param); + //void (*wmm_param_update) (struct ieee80211_device *ieee); + + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_ieee80211 */ + u8 priv[0]; +}; + +#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) + +/* Generate a 802.11 header */ + +/* Uses the channel change callback directly + * instead of [start/stop] scan callbacks + */ +#define IEEE_SOFTMAC_SCAN (1<<2) + +/* Perform authentication and association handshake */ +#define IEEE_SOFTMAC_ASSOCIATE (1<<3) + +/* Generate probe requests */ +#define IEEE_SOFTMAC_PROBERQ (1<<4) + +/* Generate respones to probe requests */ +#define IEEE_SOFTMAC_PROBERS (1<<5) + +/* The ieee802.11 stack will manages the netif queue + * wake/stop for the driver, taking care of 802.11 + * fragmentation. See softmac.c for details. */ +#define IEEE_SOFTMAC_TX_QUEUE (1<<7) + +/* Uses only the softmac_data_hard_start_xmit + * even for TX management frames. + */ +#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) + +/* Generate beacons. The stack will enqueue beacons + * to the card + */ +#define IEEE_SOFTMAC_BEACONS (1<<6) + + + +static inline void *ieee80211_priv(struct net_device *dev) +{ + return ((struct ieee80211_device *)netdev_priv(dev))->priv; +} + +extern 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; +} + +extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) +{ + /* + * It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + * + */ + if ((mode & IEEE_A) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & IEEE80211_CCK_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + return 0; +} + +extern inline int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = 30; /* Addr4 */ + if(IEEE80211_QOS_HAS_SEQ(fc)) + hdrlen += 2; /* QOS ctrl*/ + 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; +} + + + +/* ieee80211.c */ +extern void free_ieee80211(struct net_device *dev); +extern struct net_device *alloc_ieee80211(int sizeof_priv); + +extern int ieee80211_set_encryption(struct ieee80211_device *ieee); + +/* ieee80211_tx.c */ + +extern int ieee80211_encrypt_fragment( + struct ieee80211_device *ieee, + struct sk_buff *frag, + int hdr_len); + +extern int ieee80211_xmit(struct sk_buff *skb, + struct net_device *dev); +extern void ieee80211_txb_free(struct ieee80211_txb *); + + +/* ieee80211_rx.c */ +extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats); +extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr *header, + struct ieee80211_rx_stats *stats); + +/* ieee80211_wx.c */ +extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data* wrqu, char *extra); +int ieee80211_wx_set_auth(struct ieee80211_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra); +int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); +/* ieee80211_softmac.c */ +extern short ieee80211_is_54g(struct ieee80211_network net); +extern short ieee80211_is_shortslot(struct ieee80211_network net); +extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype); +extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); + +extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); +extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_ibss(struct ieee80211_device *ieee); +extern void ieee80211_softmac_init(struct ieee80211_device *ieee); +extern void ieee80211_softmac_free(struct ieee80211_device *ieee); +extern void ieee80211_associate_abort(struct ieee80211_device *ieee); +extern void ieee80211_disassociate(struct ieee80211_device *ieee); +extern void ieee80211_stop_scan(struct ieee80211_device *ieee); +extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); +extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_reset_queue(struct ieee80211_device *ieee); +extern void ieee80211_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); +extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); +extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); +extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); +extern void notify_wx_assoc_event(struct ieee80211_device *ieee); +extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); +extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn); +extern void ieee80211_start_scan(struct ieee80211_device *ieee); + +//Add for RF power on power off by lizhaoming 080512 +extern void SendDisassociation(struct ieee80211_device *ieee, + u8* asSta, + u8 asRsn); + +/* ieee80211_crypt_ccmp&tkip&wep.c */ +extern void ieee80211_tkip_null(void); +extern void ieee80211_wep_null(void); +extern void ieee80211_ccmp_null(void); +/* ieee80211_softmac_wx.c */ + +extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *ext); + +extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra); + +extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); + +extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); +#else + extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); +#endif +//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); + +extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee); + +extern void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr); + +extern const long ieee80211_wlan_frequencies[]; + +extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +{ + ieee->scans++; +} + +extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +{ + return ieee->scans; +} + +static inline const char *escape_essid(const char *essid, u8 essid_len) { + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (ieee80211_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "<hidden>", sizeof("<hidden>")); + return escaped; + } + + essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else { + *d++ = *s++; + } + } + *d = '\0'; + return escaped; +} +#endif /* IEEE80211_H */ diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c new file mode 100644 index 0000000..af64cfb --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c @@ -0,0 +1,265 @@ +/* + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + * + */ + +//#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <asm/string.h> +#include <asm/errno.h> + +#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,6,18)) +#include<linux/config.h> +#endif + +#include "ieee80211.h" + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("HostAP crypto"); +MODULE_LICENSE("GPL"); + +struct ieee80211_crypto_alg { + struct list_head list; + struct ieee80211_crypto_ops *ops; +}; + + +struct ieee80211_crypto { + struct list_head algs; + spinlock_t lock; +}; + +static struct ieee80211_crypto *hcrypt; + +void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, + int force) +{ + struct list_head *ptr, *n; + struct ieee80211_crypt_data *entry; + + for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; + ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct ieee80211_crypt_data, list); + + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(ptr); + + if (entry->ops) { + entry->ops->deinit(entry->priv); + module_put(entry->ops->owner); + } + kfree(entry); + } +} + +void ieee80211_crypt_deinit_handler(unsigned long data) +{ + struct ieee80211_device *ieee = (struct ieee80211_device *)data; + unsigned long flags; + + spin_lock_irqsave(&ieee->lock, flags); + ieee80211_crypt_deinit_entries(ieee, 0); + if (!list_empty(&ieee->crypt_deinit_list)) { + printk(KERN_DEBUG "%s: entries remaining in delayed crypt " + "deletion list\n", ieee->dev->name); + ieee->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&ieee->crypt_deinit_timer); + } + spin_unlock_irqrestore(&ieee->lock, flags); + +} + +void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, + struct ieee80211_crypt_data **crypt) +{ + struct ieee80211_crypt_data *tmp; + unsigned long flags; + + if (*crypt == NULL) + return; + + tmp = *crypt; + *crypt = NULL; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. */ + + spin_lock_irqsave(&ieee->lock, flags); + list_add(&tmp->list, &ieee->crypt_deinit_list); + if (!timer_pending(&ieee->crypt_deinit_timer)) { + ieee->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&ieee->crypt_deinit_timer); + } + spin_unlock_irqrestore(&ieee->lock, flags); +} + +int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) +{ + unsigned long flags; + struct ieee80211_crypto_alg *alg; + + if (hcrypt == NULL) + return -1; + + alg = kmalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + memset(alg, 0, sizeof(*alg)); + alg->ops = ops; + + spin_lock_irqsave(&hcrypt->lock, flags); + list_add(&alg->list, &hcrypt->algs); + spin_unlock_irqrestore(&hcrypt->lock, flags); + + printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} + +int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) +{ + unsigned long flags; + struct list_head *ptr; + struct ieee80211_crypto_alg *del_alg = NULL; + + if (hcrypt == NULL) + return -1; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct ieee80211_crypto_alg *alg = + (struct ieee80211_crypto_alg *) ptr; + if (alg->ops == ops) { + list_del(&alg->list); + del_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (del_alg) { + printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " + "'%s'\n", ops->name); + kfree(del_alg); + } + + return del_alg ? 0 : -1; +} + + +struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name) +{ + unsigned long flags; + struct list_head *ptr; + struct ieee80211_crypto_alg *found_alg = NULL; + + if (hcrypt == NULL) + return NULL; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct ieee80211_crypto_alg *alg = + (struct ieee80211_crypto_alg *) ptr; + if (strcmp(alg->ops->name, name) == 0) { + found_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (found_alg) + return found_alg->ops; + else + return NULL; +} + + +static void * ieee80211_crypt_null_init(int keyidx) { return (void *) 1; } +static void ieee80211_crypt_null_deinit(void *priv) {} + +static struct ieee80211_crypto_ops ieee80211_crypt_null = { + .name = "NULL", + .init = ieee80211_crypt_null_init, + .deinit = ieee80211_crypt_null_deinit, + .encrypt_mpdu = NULL, + .decrypt_mpdu = NULL, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = NULL, + .get_key = NULL, + .extra_prefix_len = 0, + .extra_postfix_len = 0, + .owner = THIS_MODULE, +}; + + +int ieee80211_crypto_init(void) +{ + int ret = -ENOMEM; + + hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL); + if (!hcrypt) + goto out; + + memset(hcrypt, 0, sizeof(*hcrypt)); + INIT_LIST_HEAD(&hcrypt->algs); + spin_lock_init(&hcrypt->lock); + + ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); + if (ret < 0) { + kfree(hcrypt); + hcrypt = NULL; + } +out: + return ret; +} + + +void ieee80211_crypto_deinit(void) +{ + struct list_head *ptr, *n; + + if (hcrypt == NULL) + return; + + for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; + ptr = n, n = ptr->next) { + struct ieee80211_crypto_alg *alg = + (struct ieee80211_crypto_alg *) ptr; + list_del(ptr); + printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " + "'%s' (deinit)\n", alg->ops->name); + kfree(alg); + } + + kfree(hcrypt); +} + +#if 0 +EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); +EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); +EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); + +EXPORT_SYMBOL(ieee80211_register_crypto_ops); +EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); +EXPORT_SYMBOL(ieee80211_get_crypto_ops); +#endif + +//module_init(ieee80211_crypto_init); +//module_exit(ieee80211_crypto_deinit); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h new file mode 100644 index 0000000..b58a3bc --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h @@ -0,0 +1,86 @@ +/* + * Original code based on Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * <jkmaline@cc.hut.fi> + * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * <jketreno@linux.intel.com> + * + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +/* + * This file defines the interface to the ieee80211 crypto module. + */ +#ifndef IEEE80211_CRYPT_H +#define IEEE80211_CRYPT_H + +#include <linux/skbuff.h> + +struct ieee80211_crypto_ops { + const char *name; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void * (*init)(int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit)(void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key)(void *key, int len, u8 *seq, void *priv); + int (*get_key)(void *key, int len, u8 *seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + char * (*print_stats)(char *p, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_prefix_len, extra_postfix_len; + + struct module *owner; +}; + +struct ieee80211_crypt_data { + struct list_head list; /* delayed deletion list */ + struct ieee80211_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); +int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); +struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); +void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); +void ieee80211_crypt_deinit_handler(unsigned long); +void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, + struct ieee80211_crypt_data **crypt); + +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c new file mode 100644 index 0000000..7d890c3 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c @@ -0,0 +1,533 @@ +/* + * Host AP crypt: host-based CCMP encryption implementation for Host AP driver + * + * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +//#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> +#include <asm/string.h> +#include <linux/wireless.h> + +#include "ieee80211.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "rtl_crypto.h" +#else +#include <linux/crypto.h> +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + #include <asm/scatterlist.h> +#else + #include <linux/scatterlist.h> +#endif + +//#include <asm/scatterlist.h> + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: CCMP"); +MODULE_LICENSE("GPL"); + +#ifdef OPENSUSE_SLED +#ifndef IN_OPENSUSE_SLED +#define IN_OPENSUSE_SLED 1 +#endif +#endif + +#define AES_BLOCK_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 + +struct ieee80211_ccmp_data { + u8 key[CCMP_TK_LEN]; + int key_set; + + u8 tx_pn[CCMP_PN_LEN]; + u8 rx_pn[CCMP_PN_LEN]; + + u32 dot11RSNAStatsCCMPFormatErrors; + u32 dot11RSNAStatsCCMPReplays; + u32 dot11RSNAStatsCCMPDecryptErrors; + + int key_idx; + + struct crypto_tfm *tfm; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], + tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; + u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; +}; + +void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, + const u8 pt[16], u8 ct[16]) +{ + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) + crypto_cipher_encrypt_one((void *)tfm, ct, pt); + #else + struct scatterlist src, dst; + + src.page = virt_to_page(pt); + src.offset = offset_in_page(pt); + src.length = AES_BLOCK_LEN; + + dst.page = virt_to_page(ct); + dst.offset = offset_in_page(ct); + dst.length = AES_BLOCK_LEN; + + crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); + #endif +} + +static void * ieee80211_ccmp_init(int key_idx) +{ + struct ieee80211_ccmp_data *priv; + + priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + memset(priv, 0, sizeof(*priv)); + priv->key_idx = key_idx; + + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) + priv->tfm = crypto_alloc_tfm("aes", 0); + if (priv->tfm == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " + "crypto API aes\n"); + goto fail; + } + #else + priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tfm)) { + printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " + "crypto API aes\n"); + priv->tfm = NULL; + goto fail; + } + #endif + return priv; + +fail: + if (priv) { + if (priv->tfm) + //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) + crypto_free_tfm(priv->tfm); + #else + crypto_free_cipher((void *)priv->tfm); + #endif + kfree(priv); + } + + return NULL; +} + + +static void ieee80211_ccmp_deinit(void *priv) +{ + struct ieee80211_ccmp_data *_priv = priv; + if (_priv && _priv->tfm) + //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) + crypto_free_tfm(_priv->tfm); + #else + crypto_free_cipher((void *)_priv->tfm); + #endif + kfree(priv); +} + + +static inline void xor_block(u8 *b, u8 *a, size_t len) +{ + int i; + for (i = 0; i < len; i++) + b[i] ^= a[i]; +} + +#ifndef JOHN_CCMP +static void ccmp_init_blocks(struct crypto_tfm *tfm, + struct ieee80211_hdr *hdr, + u8 *pn, size_t dlen, u8 *b0, u8 *auth, + u8 *s0) +{ + u8 *pos, qc = 0; + size_t aad_len; + u16 fc; + int a4_included, qc_included; + u8 aad[2 * AES_BLOCK_LEN]; + + fc = le16_to_cpu(hdr->frame_ctl); + a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); + /* + qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && + (WLAN_FC_GET_STYPE(fc) & 0x08)); + */ + // fixed by David :2006.9.6 + qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && + (WLAN_FC_GET_STYPE(fc) & 0x80)); + aad_len = 22; + if (a4_included) + aad_len += 6; + if (qc_included) { + pos = (u8 *) &hdr->addr4; + if (a4_included) + pos += 6; + qc = *pos & 0x0f; + aad_len += 2; + } + /* CCM Initial Block: + * Flag (Include authentication header, M=3 (8-octet MIC), + * L=1 (2-octet Dlen)) + * Nonce: 0x00 | A2 | PN + * Dlen */ + b0[0] = 0x59; + b0[1] = qc; + memcpy(b0 + 2, hdr->addr2, ETH_ALEN); + memcpy(b0 + 8, pn, CCMP_PN_LEN); + b0[14] = (dlen >> 8) & 0xff; + b0[15] = dlen & 0xff; + + /* AAD: + * FC with bits 4..6 and 11..13 masked to zero; 14 is always one + * A1 | A2 | A3 + * SC with bits 4..15 (seq#) masked to zero + * A4 (if present) + * QC (if present) + */ + pos = (u8 *) hdr; + aad[0] = 0; /* aad_len >> 8 */ + aad[1] = aad_len & 0xff; + aad[2] = pos[0] & 0x8f; + aad[3] = pos[1] & 0xc7; + memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); + pos = (u8 *) &hdr->seq_ctl; + aad[22] = pos[0] & 0x0f; + aad[23] = 0; /* all bits masked */ + memset(aad + 24, 0, 8); + if (a4_included) + memcpy(aad + 24, hdr->addr4, ETH_ALEN); + if (qc_included) { + aad[a4_included ? 30 : 24] = qc; + /* rest of QC masked */ + } + + /* Start with the first block and AAD */ + ieee80211_ccmp_aes_encrypt(tfm, b0, auth); + xor_block(auth, aad, AES_BLOCK_LEN); + ieee80211_ccmp_aes_encrypt(tfm, auth, auth); + xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); + ieee80211_ccmp_aes_encrypt(tfm, auth, auth); + b0[0] &= 0x07; + b0[14] = b0[15] = 0; + ieee80211_ccmp_aes_encrypt(tfm, b0, s0); +} +#endif + +static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_ccmp_data *key = priv; + int data_len, i; + u8 *pos; + struct ieee80211_hdr *hdr; +#ifndef JOHN_CCMP + int blocks, last, len; + u8 *mic; + u8 *b0 = key->tx_b0; + u8 *b = key->tx_b; + u8 *e = key->tx_e; + u8 *s0 = key->tx_s0; +#endif + if (skb_headroom(skb) < CCMP_HDR_LEN || + skb_tailroom(skb) < CCMP_MIC_LEN || + skb->len < hdr_len) + return -1; + + data_len = skb->len - hdr_len; + pos = skb_push(skb, CCMP_HDR_LEN); + memmove(pos, pos + CCMP_HDR_LEN, hdr_len); + pos += hdr_len; +// mic = skb_put(skb, CCMP_MIC_LEN); + + i = CCMP_PN_LEN - 1; + while (i >= 0) { + key->tx_pn[i]++; + if (key->tx_pn[i] != 0) + break; + i--; + } + + *pos++ = key->tx_pn[5]; + *pos++ = key->tx_pn[4]; + *pos++ = 0; + *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; + *pos++ = key->tx_pn[3]; + *pos++ = key->tx_pn[2]; + *pos++ = key->tx_pn[1]; + *pos++ = key->tx_pn[0]; + + hdr = (struct ieee80211_hdr *) skb->data; +#ifndef JOHN_CCMP + //mic is moved to here by john + mic = skb_put(skb, CCMP_MIC_LEN); + + ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); + + blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Authentication */ + xor_block(b, pos, len); + ieee80211_ccmp_aes_encrypt(key->tfm, b, b); + /* Encryption, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); + xor_block(pos, e, len); + pos += len; + } + + for (i = 0; i < CCMP_MIC_LEN; i++) + mic[i] = b[i] ^ s0[i]; +#endif + return 0; +} + + +static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_ccmp_data *key = priv; + u8 keyidx, *pos; + struct ieee80211_hdr *hdr; + u8 pn[6]; +#ifndef JOHN_CCMP + size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; + u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; + u8 *b0 = key->rx_b0; + u8 *b = key->rx_b; + u8 *a = key->rx_a; + int i, blocks, last, len; +#endif + if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { + key->dot11RSNAStatsCCMPFormatErrors++; + return -1; + } + + hdr = (struct ieee80211_hdr *) skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: received packet without ExtIV" + " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + key->dot11RSNAStatsCCMPFormatErrors++; + return -2; + } + keyidx >>= 6; + if (key->key_idx != keyidx) { + printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " + "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); + return -6; + } + if (!key->key_set) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT + " with keyid=%d that does not have a configured" + " key\n", MAC_ARG(hdr->addr2), keyidx); + } + return -3; + } + + pn[0] = pos[7]; + pn[1] = pos[6]; + pn[2] = pos[5]; + pn[3] = pos[4]; + pn[4] = pos[1]; + pn[5] = pos[0]; + pos += 8; + + if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT + " previous PN %02x%02x%02x%02x%02x%02x " + "received PN %02x%02x%02x%02x%02x%02x\n", + MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), + MAC_ARG(pn)); + } + key->dot11RSNAStatsCCMPReplays++; + return -4; + } + +#ifndef JOHN_CCMP + ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); + xor_block(mic, b, CCMP_MIC_LEN); + + blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Decrypt, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); + xor_block(pos, b, len); + /* Authentication */ + xor_block(a, pos, len); + ieee80211_ccmp_aes_encrypt(key->tfm, a, a); + pos += len; + } + + if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: decrypt failed: STA=" + MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + key->dot11RSNAStatsCCMPDecryptErrors++; + return -5; + } + + memcpy(key->rx_pn, pn, CCMP_PN_LEN); + +#endif + /* Remove hdr and MIC */ + memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, CCMP_HDR_LEN); + skb_trim(skb, skb->len - CCMP_MIC_LEN); + + return keyidx; +} + + +static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_ccmp_data *data = priv; + int keyidx; + struct crypto_tfm *tfm = data->tfm; + + keyidx = data->key_idx; + memset(data, 0, sizeof(*data)); + data->key_idx = keyidx; + data->tfm = tfm; + if (len == CCMP_TK_LEN) { + memcpy(data->key, key, CCMP_TK_LEN); + data->key_set = 1; + if (seq) { + data->rx_pn[0] = seq[5]; + data->rx_pn[1] = seq[4]; + data->rx_pn[2] = seq[3]; + data->rx_pn[3] = seq[2]; + data->rx_pn[4] = seq[1]; + data->rx_pn[5] = seq[0]; + } + crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN); + } else if (len == 0) + data->key_set = 0; + else + return -1; + + return 0; +} + + +static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_ccmp_data *data = priv; + + if (len < CCMP_TK_LEN) + return -1; + + if (!data->key_set) + return 0; + memcpy(key, data->key, CCMP_TK_LEN); + + if (seq) { + seq[0] = data->tx_pn[5]; + seq[1] = data->tx_pn[4]; + seq[2] = data->tx_pn[3]; + seq[3] = data->tx_pn[2]; + seq[4] = data->tx_pn[1]; + seq[5] = data->tx_pn[0]; + } + + return CCMP_TK_LEN; +} + + +static char * ieee80211_ccmp_print_stats(char *p, void *priv) +{ + struct ieee80211_ccmp_data *ccmp = priv; + p += sprintf(p, "key[%d] alg=CCMP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "format_errors=%d replays=%d decrypt_errors=%d\n", + ccmp->key_idx, ccmp->key_set, + MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), + ccmp->dot11RSNAStatsCCMPFormatErrors, + ccmp->dot11RSNAStatsCCMPReplays, + ccmp->dot11RSNAStatsCCMPDecryptErrors); + + return p; +} + +void ieee80211_ccmp_null(void) +{ +// printk("============>%s()\n", __FUNCTION__); + return; +} +static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { + .name = "CCMP", + .init = ieee80211_ccmp_init, + .deinit = ieee80211_ccmp_deinit, + .encrypt_mpdu = ieee80211_ccmp_encrypt, + .decrypt_mpdu = ieee80211_ccmp_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = ieee80211_ccmp_set_key, + .get_key = ieee80211_ccmp_get_key, + .print_stats = ieee80211_ccmp_print_stats, + .extra_prefix_len = CCMP_HDR_LEN, + .extra_postfix_len = CCMP_MIC_LEN, + .owner = THIS_MODULE, +}; + + +int ieee80211_crypto_ccmp_init(void) +{ + return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); +} + + +void ieee80211_crypto_ccmp_exit(void) +{ + ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); +} + +#if 0 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_ccmp_null); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_ccmp_null); +#endif +#endif + +//module_init(ieee80211_crypto_ccmp_init); +//module_exit(ieee80211_crypto_ccmp_exit); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c new file mode 100644 index 0000000..e560b1e --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c @@ -0,0 +1,1001 @@ +/* + * Host AP crypt: host-based TKIP encryption implementation for Host AP driver + * + * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +//#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> +#include <asm/string.h> + +#include "ieee80211.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "rtl_crypto.h" +#else +#include <linux/crypto.h> +#endif +//#include <asm/scatterlist.h> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) + #include <asm/scatterlist.h> +#else + #include <linux/scatterlist.h> +#endif + +#include <linux/crc32.h> + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: TKIP"); +MODULE_LICENSE("GPL"); + +#ifdef OPENSUSE_SLED +#ifndef IN_OPENSUSE_SLED +#define IN_OPENSUSE_SLED 1 +#endif +#endif + +struct ieee80211_tkip_data { +#define TKIP_KEY_LEN 32 + u8 key[TKIP_KEY_LEN]; + int key_set; + + u32 tx_iv32; + u16 tx_iv16; + u16 tx_ttak[5]; + int tx_phase1_done; + + u32 rx_iv32; + u16 rx_iv16; + u16 rx_ttak[5]; + int rx_phase1_done; + u32 rx_iv32_new; + u16 rx_iv16_new; + + u32 dot11RSNAStatsTKIPReplays; + u32 dot11RSNAStatsTKIPICVErrors; + u32 dot11RSNAStatsTKIPLocalMICFailures; + + int key_idx; + + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) + struct crypto_blkcipher *rx_tfm_arc4; + struct crypto_hash *rx_tfm_michael; + struct crypto_blkcipher *tx_tfm_arc4; + struct crypto_hash *tx_tfm_michael; + #endif + + struct crypto_tfm *tfm_arc4; + struct crypto_tfm *tfm_michael; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 rx_hdr[16], tx_hdr[16]; +}; + +static void * ieee80211_tkip_init(int key_idx) +{ + struct ieee80211_tkip_data *priv; + + priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + memset(priv, 0, sizeof(*priv)); + priv->key_idx = key_idx; + + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); + if (priv->tfm_arc4 == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + goto fail; + } + + priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0); + if (priv->tfm_michael == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + goto fail; + } + + #else + priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_arc4)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + priv->tx_tfm_arc4 = NULL; + goto fail; + } + + priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_michael)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + priv->tx_tfm_michael = NULL; + goto fail; + } + + priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_arc4)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + priv->rx_tfm_arc4 = NULL; + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_michael)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + priv->rx_tfm_michael = NULL; + goto fail; + } + #endif + return priv; + +fail: + if (priv) { + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + if (priv->tfm_michael) + crypto_free_tfm(priv->tfm_michael); + if (priv->tfm_arc4) + crypto_free_tfm(priv->tfm_arc4); + #else + if (priv->tx_tfm_michael) + crypto_free_hash(priv->tx_tfm_michael); + if (priv->tx_tfm_arc4) + crypto_free_blkcipher(priv->tx_tfm_arc4); + if (priv->rx_tfm_michael) + crypto_free_hash(priv->rx_tfm_michael); + if (priv->rx_tfm_arc4) + crypto_free_blkcipher(priv->rx_tfm_arc4); + #endif + kfree(priv); + } + + return NULL; +} + + +static void ieee80211_tkip_deinit(void *priv) +{ + struct ieee80211_tkip_data *_priv = priv; + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + if (_priv && _priv->tfm_michael) + crypto_free_tfm(_priv->tfm_michael); + if (_priv && _priv->tfm_arc4) + crypto_free_tfm(_priv->tfm_arc4); + #else + if (_priv) { + if (_priv->tx_tfm_michael) + crypto_free_hash(_priv->tx_tfm_michael); + if (_priv->tx_tfm_arc4) + crypto_free_blkcipher(_priv->tx_tfm_arc4); + if (_priv->rx_tfm_michael) + crypto_free_hash(_priv->rx_tfm_michael); + if (_priv->rx_tfm_arc4) + crypto_free_blkcipher(_priv->rx_tfm_arc4); + } + #endif + kfree(priv); +} + + +static inline u16 RotR1(u16 val) +{ + return (val >> 1) | (val << 15); +} + + +static inline u8 Lo8(u16 val) +{ + return val & 0xff; +} + + +static inline u8 Hi8(u16 val) +{ + return val >> 8; +} + + +static inline u16 Lo16(u32 val) +{ + return val & 0xffff; +} + + +static inline u16 Hi16(u32 val) +{ + return val >> 16; +} + + +static inline u16 Mk16(u8 hi, u8 lo) +{ + return lo | (((u16) hi) << 8); +} + + +static inline u16 Mk16_le(u16 *v) +{ + return le16_to_cpu(*v); +} + + +static const u16 Sbox[256] = +{ + 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, +}; + + +static inline u16 _S_(u16 v) +{ + u16 t = Sbox[Hi8(v)]; + return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); +} + +#ifndef JOHN_TKIP +#define PHASE1_LOOP_COUNT 8 + +static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) +{ + int i, j; + + /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ + TTAK[0] = Lo16(IV32); + TTAK[1] = Hi16(IV32); + TTAK[2] = Mk16(TA[1], TA[0]); + TTAK[3] = Mk16(TA[3], TA[2]); + TTAK[4] = Mk16(TA[5], TA[4]); + + for (i = 0; i < PHASE1_LOOP_COUNT; i++) { + j = 2 * (i & 1); + TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); + TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); + TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); + TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); + TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; + } +} + + +static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, + u16 IV16) +{ + /* Make temporary area overlap WEP seed so that the final copy can be + * avoided on little endian hosts. */ + u16 *PPK = (u16 *) &WEPSeed[4]; + + /* Step 1 - make copy of TTAK and bring in TSC */ + PPK[0] = TTAK[0]; + PPK[1] = TTAK[1]; + PPK[2] = TTAK[2]; + PPK[3] = TTAK[3]; + PPK[4] = TTAK[4]; + PPK[5] = TTAK[4] + IV16; + + /* Step 2 - 96-bit bijective mixing using S-box */ + PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); + PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); + PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); + PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); + PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); + PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); + + PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); + PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + + /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value + * WEPSeed[0..2] is transmitted as WEP IV */ + WEPSeed[0] = Hi8(IV16); + WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; + WEPSeed[2] = Lo8(IV16); + WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); + +#ifdef __BIG_ENDIAN + { + int i; + for (i = 0; i < 6; i++) + PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); + } +#endif +} +#endif +static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4}; + #endif + int len; + u8 *pos; + struct ieee80211_hdr *hdr; +#ifndef JOHN_TKIP + u8 rc4key[16],*icv; + u32 crc; + struct scatterlist sg; +#endif + int ret; + + ret = 0; + if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || + skb->len < hdr_len) + return -1; + + hdr = (struct ieee80211_hdr *) skb->data; +#if 0 +printk("@@ tkey\n"); +printk("%x|", ((u32*)tkey->key)[0]); +printk("%x|", ((u32*)tkey->key)[1]); +printk("%x|", ((u32*)tkey->key)[2]); +printk("%x|", ((u32*)tkey->key)[3]); +printk("%x|", ((u32*)tkey->key)[4]); +printk("%x|", ((u32*)tkey->key)[5]); +printk("%x|", ((u32*)tkey->key)[6]); +printk("%x\n", ((u32*)tkey->key)[7]); +#endif + +#ifndef JOHN_TKIP + if (!tkey->tx_phase1_done) { + tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, + tkey->tx_iv32); + tkey->tx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); + +#else + tkey->tx_phase1_done = 1; +#endif /*JOHN_TKIP*/ + + len = skb->len - hdr_len; + pos = skb_push(skb, 8); + memmove(pos, pos + 8, hdr_len); + pos += hdr_len; + +#ifdef JOHN_TKIP + *pos++ = Hi8(tkey->tx_iv16); + *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F; + *pos++ = Lo8(tkey->tx_iv16); +#else + *pos++ = rc4key[0]; + *pos++ = rc4key[1]; + *pos++ = rc4key[2]; +#endif + *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; + *pos++ = tkey->tx_iv32 & 0xff; + *pos++ = (tkey->tx_iv32 >> 8) & 0xff; + *pos++ = (tkey->tx_iv32 >> 16) & 0xff; + *pos++ = (tkey->tx_iv32 >> 24) & 0xff; +#ifndef JOHN_TKIP + icv = skb_put(skb, 4); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, len); +#else + crc = ~ether_crc_le(len, pos); +#endif + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; + crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); + #else + crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; + #else + sg_init_one(&sg, pos, len+4); + #endif + ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); + #endif +#endif + tkey->tx_iv16++; + if (tkey->tx_iv16 == 0) { + tkey->tx_phase1_done = 0; + tkey->tx_iv32++; + } +#ifndef JOHN_TKIP + #if((LINUX_VERSION_CODE <KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + return 0; + #else + return ret; + #endif +#else + return 0; +#endif +} + +static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ||(IN_OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4}; + #endif + u8 keyidx, *pos; + u32 iv32; + u16 iv16; + struct ieee80211_hdr *hdr; +#ifndef JOHN_TKIP + u8 icv[4]; + u32 crc; + struct scatterlist sg; + u8 rc4key[16]; + int plen; +#endif + if (skb->len < hdr_len + 8 + 4) + return -1; + + hdr = (struct ieee80211_hdr *) skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: received packet without ExtIV" + " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + return -2; + } + keyidx >>= 6; + if (tkey->key_idx != keyidx) { + printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " + "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); + return -6; + } + if (!tkey->key_set) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT + " with keyid=%d that does not have a configured" + " key\n", MAC_ARG(hdr->addr2), keyidx); + } + return -3; + } + iv16 = (pos[0] << 8) | pos[2]; + iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); + pos += 8; +#ifndef JOHN_TKIP + + if (iv32 < tkey->rx_iv32 || + (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT + " previous TSC %08x%04x received TSC " + "%08x%04x\n", MAC_ARG(hdr->addr2), + tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); + } + tkey->dot11RSNAStatsTKIPReplays++; + return -4; + } + + if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { + tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); + tkey->rx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); + + plen = skb->len - hdr_len - 12; + #if((LINUX_VERSION_CODE <KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; + crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); + #else + crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + #if(LINUX_VERSION_CODE <KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; + #else + sg_init_one(&sg, pos, plen+4); + #endif + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { + if (net_ratelimit()) { + printk(KERN_DEBUG ": TKIP: failed to decrypt " + "received packet from " MAC_FMT "\n", + MAC_ARG(hdr->addr2)); + } + return -7; + } + #endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, plen); +#else + crc = ~ether_crc_le(plen, pos); +#endif + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + if (iv32 != tkey->rx_iv32) { + /* Previously cached Phase1 result was already lost, so + * it needs to be recalculated for the next packet. */ + tkey->rx_phase1_done = 0; + } + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: ICV error detected: STA=" + MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + tkey->dot11RSNAStatsTKIPICVErrors++; + return -5; + } + +#endif /* JOHN_TKIP */ + + /* Update real counters only after Michael MIC verification has + * completed */ + tkey->rx_iv32_new = iv32; + tkey->rx_iv16_new = iv16; + + /* Remove IV and ICV */ + memmove(skb->data + 8, skb->data, hdr_len); + skb_pull(skb, 8); + skb_trim(skb, skb->len - 4); + +//john's test +#ifdef JOHN_DUMP +if( ((u16*)skb->data)[0] & 0x4000){ + printk("@@ rx decrypted skb->data"); + int i; + for(i=0;i<skb->len;i++){ + if( (i%24)==0 ) printk("\n"); + printk("%2x ", ((u8*)skb->data)[i]); + } + printk("\n"); +} +#endif /*JOHN_DUMP*/ + return keyidx; +} + +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) +static int michael_mic(struct ieee80211_tkip_data *tkey, u8 *key, u8 *hdr, + u8 *data, size_t data_len, u8 *mic) +{ + struct scatterlist sg[2]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct hash_desc desc; + int ret=0; +#endif + if (tkey->tfm_michael == NULL) { + printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + return -1; + } + sg[0].page = virt_to_page(hdr); + sg[0].offset = offset_in_page(hdr); + sg[0].length = 16; + + sg[1].page = virt_to_page(data); + sg[1].offset = offset_in_page(data); + sg[1].length = data_len; + + //crypto_digest_init(tkey->tfm_michael); + //crypto_digest_setkey(tkey->tfm_michael, key, 8); + //crypto_digest_update(tkey->tfm_michael, sg, 2); + //crypto_digest_final(tkey->tfm_michael, mic); + + //return 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + crypto_digest_init(tkey->tfm_michael); + crypto_digest_setkey(tkey->tfm_michael, key, 8); + crypto_digest_update(tkey->tfm_michael, sg, 2); + crypto_digest_final(tkey->tfm_michael, mic); + + return 0; +#else +if (crypto_hash_setkey(tkey->tfm_michael, key, 8)) + return -1; + +// return 0; + desc.tfm = tkey->tfm_michael; + desc.flags = 0; + ret = crypto_hash_digest(&desc, sg, data_len + 16, mic); + return ret; +#endif +} +#else +static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, + u8 * data, size_t data_len, u8 * mic) +{ + struct hash_desc desc; + struct scatterlist sg[2]; + + if (tfm_michael == NULL) { + printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + return -1; + } + #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg[0].page = virt_to_page(hdr); + sg[0].offset = offset_in_page(hdr); + sg[0].length = 16; + sg[1].page = virt_to_page(data); + sg[1].offset = offset_in_page(data); + sg[1].length = data_len; + #else + sg_init_table(sg, 2); + sg_set_buf(&sg[0], hdr, 16); + sg_set_buf(&sg[1], data, data_len); + #endif + + if (crypto_hash_setkey(tfm_michael, key, 8)) + return -1; + + desc.tfm = tfm_michael; + desc.flags = 0; + return crypto_hash_digest(&desc, sg, data_len + 16, mic); +} +#endif + + + +static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) +{ + struct ieee80211_hdr *hdr11; + + hdr11 = (struct ieee80211_hdr *) skb->data; + switch (le16_to_cpu(hdr11->frame_ctl) & + (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ + break; + case 0: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + } + + hdr[12] = 0; /* priority */ + + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + + +static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + u8 *pos; + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *) skb->data; + + if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { + printk(KERN_DEBUG "Invalid packet for Michael MIC add " + "(tailroom=%d hdr_len=%d skb->len=%d)\n", + skb_tailroom(skb), hdr_len, skb->len); + return -1; + } + + michael_mic_hdr(skb, tkey->tx_hdr); + + // { david, 2006.9.1 + // fix the wpa process with wmm enabled. + if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { + tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; + } + // } + pos = skb_put(skb, 8); + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) + #else + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) + #endif + return -1; + + return 0; +} + + +#if WIRELESS_EXT >= 18 +static void ieee80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + memset(&ev, 0, sizeof(ev)); + ev.flags = keyidx & IW_MICFAILURE_KEY_ID; + if (hdr->addr1[0] & 0x01) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev); +} +#elif WIRELESS_EXT >= 15 +static void ieee80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + char buf[128]; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" + MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", + MAC_ARG(hdr->addr2)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); +} +#else /* WIRELESS_EXT >= 15 */ +static inline void ieee80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr *hdr, + int keyidx) +{ +} +#endif /* WIRELESS_EXT >= 15 */ + + +static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, + int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + u8 mic[8]; + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *) skb->data; + + if (!tkey->key_set) + return -1; + + michael_mic_hdr(skb, tkey->rx_hdr); + // { david, 2006.9.1 + // fix the wpa process with wmm enabled. + if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { + tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; + } + // } + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) + #else + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) + #endif + return -1; + if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *) skb->data; + printk(KERN_DEBUG "%s: Michael MIC verification failed for " + "MSDU from " MAC_FMT " keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), + keyidx); + if (skb->dev) + ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); + tkey->dot11RSNAStatsTKIPLocalMICFailures++; + return -1; + } + + /* Update TSC counters for RX now that the packet verification has + * completed. */ + tkey->rx_iv32 = tkey->rx_iv32_new; + tkey->rx_iv16 = tkey->rx_iv16_new; + + skb_trim(skb, skb->len - 8); + + return 0; +} + + +static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + int keyidx; + #if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + struct crypto_tfm *tfm = tkey->tfm_michael; + struct crypto_tfm *tfm2 = tkey->tfm_arc4; + #else + struct crypto_hash *tfm = tkey->tx_tfm_michael; + struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_hash *tfm3 = tkey->rx_tfm_michael; + struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; + #endif + + keyidx = tkey->key_idx; + memset(tkey, 0, sizeof(*tkey)); + tkey->key_idx = keyidx; + + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + tkey->tfm_michael = tfm; + tkey->tfm_arc4 = tfm2; + #else + tkey->tx_tfm_michael = tfm; + tkey->tx_tfm_arc4 = tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_tfm_arc4 = tfm4; + #endif + + if (len == TKIP_KEY_LEN) { + memcpy(tkey->key, key, TKIP_KEY_LEN); + tkey->key_set = 1; + tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ + if (seq) { + tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | + (seq[3] << 8) | seq[2]; + tkey->rx_iv16 = (seq[1] << 8) | seq[0]; + } + } else if (len == 0) + tkey->key_set = 0; + else + return -1; + + return 0; +} + + +static int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + + if (len < TKIP_KEY_LEN) + return -1; + + if (!tkey->key_set) + return 0; + memcpy(key, tkey->key, TKIP_KEY_LEN); + + if (seq) { + /* Return the sequence number of the last transmitted frame. */ + u16 iv16 = tkey->tx_iv16; + u32 iv32 = tkey->tx_iv32; + if (iv16 == 0) + iv32--; + iv16--; + seq[0] = tkey->tx_iv16; + seq[1] = tkey->tx_iv16 >> 8; + seq[2] = tkey->tx_iv32; + seq[3] = tkey->tx_iv32 >> 8; + seq[4] = tkey->tx_iv32 >> 16; + seq[5] = tkey->tx_iv32 >> 24; + } + + return TKIP_KEY_LEN; +} + + +static char * ieee80211_tkip_print_stats(char *p, void *priv) +{ + struct ieee80211_tkip_data *tkip = priv; + p += sprintf(p, "key[%d] alg=TKIP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "replays=%d icv_errors=%d local_mic_failures=%d\n", + tkip->key_idx, tkip->key_set, + (tkip->tx_iv32 >> 24) & 0xff, + (tkip->tx_iv32 >> 16) & 0xff, + (tkip->tx_iv32 >> 8) & 0xff, + tkip->tx_iv32 & 0xff, + (tkip->tx_iv16 >> 8) & 0xff, + tkip->tx_iv16 & 0xff, + (tkip->rx_iv32 >> 24) & 0xff, + (tkip->rx_iv32 >> 16) & 0xff, + (tkip->rx_iv32 >> 8) & 0xff, + tkip->rx_iv32 & 0xff, + (tkip->rx_iv16 >> 8) & 0xff, + tkip->rx_iv16 & 0xff, + tkip->dot11RSNAStatsTKIPReplays, + tkip->dot11RSNAStatsTKIPICVErrors, + tkip->dot11RSNAStatsTKIPLocalMICFailures); + return p; +} + + +static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { + .name = "TKIP", + .init = ieee80211_tkip_init, + .deinit = ieee80211_tkip_deinit, + .encrypt_mpdu = ieee80211_tkip_encrypt, + .decrypt_mpdu = ieee80211_tkip_decrypt, + .encrypt_msdu = ieee80211_michael_mic_add, + .decrypt_msdu = ieee80211_michael_mic_verify, + .set_key = ieee80211_tkip_set_key, + .get_key = ieee80211_tkip_get_key, + .print_stats = ieee80211_tkip_print_stats, + .extra_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_postfix_len = 8 + 4, /* MIC + ICV */ + .owner = THIS_MODULE, +}; + + +int ieee80211_crypto_tkip_init(void) +{ + return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); +} + + +void ieee80211_crypto_tkip_exit(void) +{ + ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); +} + + +void ieee80211_tkip_null(void) +{ +// printk("============>%s()\n", __FUNCTION__); + return; +} + +#if 0 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_tkip_null); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_tkip_null); +#endif +#endif + + +//module_init(ieee80211_crypto_tkip_init); +//module_exit(ieee80211_crypto_tkip_exit); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c new file mode 100644 index 0000000..f973dae --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c @@ -0,0 +1,394 @@ +/* + * Host AP crypt: host-based WEP encryption implementation for Host AP driver + * + * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +//#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/skbuff.h> +#include <asm/string.h> + +#include "ieee80211.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "rtl_crypto.h" +#else +#include <linux/crypto.h> +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + #include <asm/scatterlist.h> +#else + #include <linux/scatterlist.h> +#endif +//#include <asm/scatterlist.h> +#include <linux/crc32.h> + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: WEP"); +MODULE_LICENSE("GPL"); + +#ifdef OPENSUSE_SLED +#ifndef IN_OPENSUSE_SLED +#define IN_OPENSUSE_SLED 1 +#endif +#endif + + +struct prism2_wep_data { + u32 iv; +#define WEP_KEY_LEN 13 + u8 key[WEP_KEY_LEN + 1]; + u8 key_len; + u8 key_idx; + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + struct crypto_tfm *tfm; + #else + struct crypto_blkcipher *tx_tfm; + struct crypto_blkcipher *rx_tfm; + #endif +}; + + +static void * prism2_wep_init(int keyidx) +{ + struct prism2_wep_data *priv; + + priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + memset(priv, 0, sizeof(*priv)); + priv->key_idx = keyidx; + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + priv->tfm = crypto_alloc_tfm("arc4", 0); + if (priv->tfm == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + "crypto API arc4\n"); + goto fail; + } + #else + priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm)) { + printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + "crypto API arc4\n"); + priv->tx_tfm = NULL; + goto fail; + } + priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm)) { + printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + "crypto API arc4\n"); + priv->rx_tfm = NULL; + goto fail; + } + #endif + + /* start WEP IV from a random value */ + get_random_bytes(&priv->iv, 4); + + return priv; + +fail: + //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + if (priv) { + if (priv->tfm) + crypto_free_tfm(priv->tfm); + kfree(priv); + } + #else + if (priv) { + if (priv->tx_tfm) + crypto_free_blkcipher(priv->tx_tfm); + if (priv->rx_tfm) + crypto_free_blkcipher(priv->rx_tfm); + kfree(priv); + } + #endif + return NULL; +} + + +static void prism2_wep_deinit(void *priv) +{ + struct prism2_wep_data *_priv = priv; + //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + if (_priv && _priv->tfm) + crypto_free_tfm(_priv->tfm); + #else + if (_priv) { + if (_priv->tx_tfm) + crypto_free_blkcipher(_priv->tx_tfm); + if (_priv->rx_tfm) + crypto_free_blkcipher(_priv->rx_tfm); + } + #endif + kfree(priv); +} + + +/* Perform WEP encryption on given skb that has at least 4 bytes of headroom + * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, + * so the payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct prism2_wep_data *wep = priv; +//#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; +#endif + u32 klen, len; + u8 key[WEP_KEY_LEN + 3]; + u8 *pos; +#ifndef JOHN_HWSEC + u32 crc; + u8 *icv; + struct scatterlist sg; +#endif + if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || + skb->len < hdr_len) + return -1; + + len = skb->len - hdr_len; + pos = skb_push(skb, 4); + memmove(pos, pos + 4, hdr_len); + pos += hdr_len; + + klen = 3 + wep->key_len; + + wep->iv++; + + /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key + * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) + * can be used to speedup attacks, so avoid using them. */ + if ((wep->iv & 0xff00) == 0xff00) { + u8 B = (wep->iv >> 16) & 0xff; + if (B >= 3 && B < klen) + wep->iv += 0x0100; + } + + /* Prepend 24-bit IV to RC4 key and TX frame */ + *pos++ = key[0] = (wep->iv >> 16) & 0xff; + *pos++ = key[1] = (wep->iv >> 8) & 0xff; + *pos++ = key[2] = wep->iv & 0xff; + *pos++ = wep->key_idx << 6; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + +#ifndef JOHN_HWSEC + /* Append little-endian CRC32 and encrypt it to produce ICV */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, len); +#else + crc = ~ether_crc_le(len, pos); +#endif + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + crypto_cipher_setkey(wep->tfm, key, klen); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; + crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); + + return 0; + #else + crypto_blkcipher_setkey(wep->tx_tfm, key, klen); + #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; + #else + sg_init_one(&sg, pos, len+4); + #endif + return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); + #endif +#endif /* JOHN_HWSEC */ + return 0; +} + + +/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of + * the frame: IV (4 bytes), encrypted payload (including SNAP header), + * ICV (4 bytes). len includes both IV and ICV. + * + * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on + * failure. If frame is OK, IV and ICV will be removed. + */ +static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct prism2_wep_data *wep = priv; + //#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = wep->rx_tfm}; + #endif + u32 klen, plen; + u8 key[WEP_KEY_LEN + 3]; + u8 keyidx, *pos; +#ifndef JOHN_HWSEC + u32 crc; + u8 icv[4]; + struct scatterlist sg; +#endif + if (skb->len < hdr_len + 8) + return -1; + + pos = skb->data + hdr_len; + key[0] = *pos++; + key[1] = *pos++; + key[2] = *pos++; + keyidx = *pos++ >> 6; + if (keyidx != wep->key_idx) + return -1; + + klen = 3 + wep->key_len; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + /* Apply RC4 to data and compute CRC32 over decrypted data */ + plen = skb->len - hdr_len - 8; +#ifndef JOHN_HWSEC +//#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) + crypto_cipher_setkey(wep->tfm, key, klen); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; + crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); +#else + crypto_blkcipher_setkey(wep->rx_tfm, key, klen); + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; + #else + sg_init_one(&sg, pos, plen+4); + #endif + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) + return -7; +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, plen); +#else + crc = ~ether_crc_le(plen, pos); +#endif + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + if (memcmp(icv, pos + plen, 4) != 0) { + /* ICV mismatch - drop frame */ + return -2; + } +#endif /* JOHN_HWSEC */ + + /* Remove IV and ICV */ + memmove(skb->data + 4, skb->data, hdr_len); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + return 0; +} + + +static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (len < 0 || len > WEP_KEY_LEN) + return -1; + + memcpy(wep->key, key, len); + wep->key_len = len; + + return 0; +} + + +static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (len < wep->key_len) + return -1; + + memcpy(key, wep->key, wep->key_len); + + return wep->key_len; +} + + +static char * prism2_wep_print_stats(char *p, void *priv) +{ + struct prism2_wep_data *wep = priv; + p += sprintf(p, "key[%d] alg=WEP len=%d\n", + wep->key_idx, wep->key_len); + return p; +} + + +static struct ieee80211_crypto_ops ieee80211_crypt_wep = { + .name = "WEP", + .init = prism2_wep_init, + .deinit = prism2_wep_deinit, + .encrypt_mpdu = prism2_wep_encrypt, + .decrypt_mpdu = prism2_wep_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = prism2_wep_set_key, + .get_key = prism2_wep_get_key, + .print_stats = prism2_wep_print_stats, + .extra_prefix_len = 4, /* IV */ + .extra_postfix_len = 4, /* ICV */ + .owner = THIS_MODULE, +}; + + +int ieee80211_crypto_wep_init(void) +{ + return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); +} + + +void ieee80211_crypto_wep_exit(void) +{ + ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); +} + + +void ieee80211_wep_null(void) +{ +// printk("============>%s()\n", __FUNCTION__); + return; +} +#if 0 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_wep_null); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_wep_null); +#endif +#endif +//module_init(ieee80211_crypto_wep_init); +//module_exit(ieee80211_crypto_wep_exit); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c new file mode 100644 index 0000000..0c9fef0 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c @@ -0,0 +1,301 @@ +/******************************************************************************* + + Copyright(c) 2004 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + <jkmaline@cc.hut.fi> + Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + + 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., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos <ipw2100-admin@linux.intel.com> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include <linux/compiler.h> +//#include <linux/config.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/in6.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/wireless.h> +#include <linux/etherdevice.h> +#include <asm/uaccess.h> +#include <net/arp.h> +#include <net/net_namespace.h> + +#include "ieee80211.h" + +MODULE_DESCRIPTION("802.11 data/management/control stack"); +MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation <jketreno@linux.intel.com>"); +MODULE_LICENSE("GPL"); + +#define DRV_NAME "ieee80211" + +static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) +{ + if (ieee->networks) + return 0; + + ieee->networks = kmalloc( + MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), + GFP_KERNEL); + if (!ieee->networks) { + printk(KERN_WARNING "%s: Out of memory allocating beacons\n", + ieee->dev->name); + return -ENOMEM; + } + + memset(ieee->networks, 0, + MAX_NETWORK_COUNT * sizeof(struct ieee80211_network)); + + return 0; +} + +static inline void ieee80211_networks_free(struct ieee80211_device *ieee) +{ + if (!ieee->networks) + return; + kfree(ieee->networks); + ieee->networks = NULL; +} + +static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) +{ + int i; + + INIT_LIST_HEAD(&ieee->network_free_list); + INIT_LIST_HEAD(&ieee->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) + list_add_tail(&ieee->networks[i].list, &ieee->network_free_list); +} + + +struct net_device *alloc_ieee80211(int sizeof_priv) +{ + struct ieee80211_device *ieee; + struct net_device *dev; + int i,err; + + IEEE80211_DEBUG_INFO("Initializing...\n"); + + dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); + if (!dev) { + IEEE80211_ERROR("Unable to network device.\n"); + goto failed; + } + ieee = netdev_priv(dev); + dev->hard_start_xmit = ieee80211_xmit; + + ieee->dev = dev; + + err = ieee80211_networks_allocate(ieee); + if (err) { + IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", + err); + goto failed; + } + ieee80211_networks_initialize(ieee); + + /* Default fragmentation threshold is maximum payload size */ + ieee->fts = DEFAULT_FTS; + ieee->scan_age = DEFAULT_MAX_SCAN_AGE; + ieee->open_wep = 1; + + /* Default to enabling full open WEP with host based encrypt/decrypt */ + ieee->host_encrypt = 1; + ieee->host_decrypt = 1; + ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ + + INIT_LIST_HEAD(&ieee->crypt_deinit_list); + init_timer(&ieee->crypt_deinit_timer); + ieee->crypt_deinit_timer.data = (unsigned long)ieee; + ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; + + spin_lock_init(&ieee->lock); + spin_lock_init(&ieee->wpax_suitlist_lock); + + ieee->wpax_type_set = 0; + ieee->wpa_enabled = 0; + ieee->tkip_countermeasures = 0; + ieee->drop_unencrypted = 0; + ieee->privacy_invoked = 0; + ieee->ieee802_1x = 1; + ieee->raw_tx = 0; + + ieee80211_softmac_init(ieee); + + for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); + + for (i = 0; i < 17; i++) { + ieee->last_rxseq_num[i] = -1; + ieee->last_rxfrag_num[i] = -1; + ieee->last_packet_time[i] = 0; + } +//These function were added to load crypte module autoly + ieee80211_tkip_null(); + ieee80211_wep_null(); + ieee80211_ccmp_null(); + return dev; + + failed: + if (dev) + free_netdev(dev); + return NULL; +} + + +void free_ieee80211(struct net_device *dev) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + + int i; + struct list_head *p, *q; + + + ieee80211_softmac_free(ieee); + del_timer_sync(&ieee->crypt_deinit_timer); + ieee80211_crypt_deinit_entries(ieee, 1); + + for (i = 0; i < WEP_KEYS; i++) { + struct ieee80211_crypt_data *crypt = ieee->crypt[i]; + if (crypt) { + if (crypt->ops) { + crypt->ops->deinit(crypt->priv); + module_put(crypt->ops->owner); + } + kfree(crypt); + ieee->crypt[i] = NULL; + } + } + + ieee80211_networks_free(ieee); + + for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) { + kfree(list_entry(p, struct ieee_ibss_seq, list)); + list_del(p); + } + } + + + free_netdev(dev); +} + +//#ifdef CONFIG_IEEE80211_DEBUG +#if 0 + +static int debug = 0; +u32 ieee80211_debug_level = 0; +struct proc_dir_entry *ieee80211_proc = NULL; + +static int show_debug_level(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); +} + +static int store_debug_level(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char buf[] = "0x00000000"; + unsigned long len = min(sizeof(buf) - 1, (u32)count); + char *p = (char *)buf; + unsigned long val; + + if (copy_from_user(buf, buffer, len)) + return count; + buf[len] = 0; + if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { + p++; + if (p[0] == 'x' || p[0] == 'X') + p++; + val = simple_strtoul(p, &p, 16); + } else + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + ieee80211_debug_level = val; + + return strnlen(buf, count); +} + +static int __init ieee80211_init(void) +{ + struct proc_dir_entry *e; + + ieee80211_debug_level = debug; + ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net); + if (ieee80211_proc == NULL) { + IEEE80211_ERROR("Unable to create " DRV_NAME + " proc directory\n"); + return -EIO; + } + e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, + ieee80211_proc); + if (!e) { + remove_proc_entry(DRV_NAME, proc_net); + ieee80211_proc = NULL; + return -EIO; + } + e->read_proc = show_debug_level; + e->write_proc = store_debug_level; + e->data = NULL; + + return 0; +} + +static void __exit ieee80211_exit(void) +{ + if (ieee80211_proc) { + remove_proc_entry("debug_level", ieee80211_proc); + remove_proc_entry(DRV_NAME, proc_net); + ieee80211_proc = NULL; + } +} + +#include <linux/moduleparam.h> +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); + + +module_exit(ieee80211_exit); +module_init(ieee80211_init); +#endif + +#if 0 +EXPORT_SYMBOL(alloc_ieee80211); +EXPORT_SYMBOL(free_ieee80211); +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c new file mode 100644 index 0000000..79ec649 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c @@ -0,0 +1,1971 @@ +/* + * Original code based Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3 - hostap.o module, common routines + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * <jkmaline@cc.hut.fi> + * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + ****************************************************************************** + + Few modifications for Realtek's Wi-Fi drivers by + Andrea Merello <andreamrl@tiscali.it> + + A special thanks goes to Realtek for their support ! + +******************************************************************************/ + + +#include <linux/compiler.h> +//#include <linux/config.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/in6.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/wireless.h> +#include <linux/etherdevice.h> +#include <asm/uaccess.h> +#include <linux/ctype.h> + +#include "ieee80211.h" +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif +static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, + struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_ctl); + + skb->dev = ieee->dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + skb_reset_mac_header(skb); +#else + skb->mac.raw = skb->data; +#endif + skb_pull(skb, ieee80211_get_hdrlen(fc)); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_80211_RAW); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + + +/* Called only as a tasklet (software IRQ) */ +static struct ieee80211_frag_entry * +ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq, + unsigned int frag, u8 tid,u8 *src, u8 *dst) +{ + struct ieee80211_frag_entry *entry; + int i; + + for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { + entry = &ieee->frag_cache[tid][i]; + if (entry->skb != NULL && + time_after(jiffies, entry->first_frag_time + 2 * HZ)) { + IEEE80211_DEBUG_FRAG( + "expiring fragment cache entry " + "seq=%u last_frag=%u\n", + entry->seq, entry->last_frag); + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; + } + + if (entry->skb != NULL && entry->seq == seq && + (entry->last_frag + 1 == frag || frag == -1) && + memcmp(entry->src_addr, src, ETH_ALEN) == 0 && + memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) + return entry; + } + + return NULL; +} + +/* Called only as a tasklet (software IRQ) */ +static struct sk_buff * +ieee80211_frag_cache_get(struct ieee80211_device *ieee, + struct ieee80211_hdr *hdr) +{ + struct sk_buff *skb = NULL; + u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 sc = le16_to_cpu(hdr->seq_ctl); + unsigned int frag = WLAN_GET_SEQ_FRAG(sc); + unsigned int seq = WLAN_GET_SEQ_SEQ(sc); + struct ieee80211_frag_entry *entry; + struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; + struct ieee80211_hdr_QOS *hdr_4addr_QoS; + u8 tid; + +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode) + { + tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; + } + else +#endif + if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr; + tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; + tid = UP2AC(tid); + tid ++; + } else if (IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr; + tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; + tid = UP2AC(tid); + tid ++; + } else { + tid = 0; + } + + if (frag == 0) { + /* Reserve enough space to fit maximum frame length */ + skb = dev_alloc_skb(ieee->dev->mtu + + sizeof(struct ieee80211_hdr) + + 8 /* LLC */ + + 2 /* alignment */ + + 8 /* WEP */ + + ETH_ALEN /* WDS */ + + (IEEE80211_QOS_HAS_SEQ(fc)?2:0) /* QOS Control */); + if (skb == NULL) + return NULL; + + entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; + ieee->frag_next_idx[tid]++; + if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN) + ieee->frag_next_idx[tid] = 0; + + if (entry->skb != NULL) + dev_kfree_skb_any(entry->skb); + + entry->first_frag_time = jiffies; + entry->seq = seq; + entry->last_frag = frag; + entry->skb = skb; + memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); + memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); + } else { + /* received a fragment of a frame for which the head fragment + * should have already been received */ + entry = ieee80211_frag_cache_find(ieee, seq, frag, tid,hdr->addr2, + hdr->addr1); + if (entry != NULL) { + entry->last_frag = frag; + skb = entry->skb; + } + } + + return skb; +} + + +/* Called only as a tasklet (software IRQ) */ +static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, + struct ieee80211_hdr *hdr) +{ + u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 sc = le16_to_cpu(hdr->seq_ctl); + unsigned int seq = WLAN_GET_SEQ_SEQ(sc); + struct ieee80211_frag_entry *entry; + struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; + struct ieee80211_hdr_QOS *hdr_4addr_QoS; + u8 tid; + +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode) + { + tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; + } + else +#endif + if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr; + tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; + tid = UP2AC(tid); + tid ++; + } else if (IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr; + tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; + tid = UP2AC(tid); + tid ++; + } else { + tid = 0; + } + + entry = ieee80211_frag_cache_find(ieee, seq, -1, tid,hdr->addr2, + hdr->addr1); + + if (entry == NULL) { + IEEE80211_DEBUG_FRAG( + "could not invalidate fragment cache " + "entry (seq=%u)\n", seq); + return -1; + } + + entry->skb = NULL; + return 0; +} + + + +/* ieee80211_rx_frame_mgtmt + * + * Responsible for handling management control frames + * + * Called by ieee80211_rx */ +static inline int +ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype) +{ + struct ieee80211_hdr *hdr; + + // cheat the the hdr type + hdr = (struct ieee80211_hdr *)skb->data; + + /* On the struct stats definition there is written that + * this is not mandatory.... but seems that the probe + * response parser uses it + */ + rx_stats->len = skb->len; + ieee80211_rx_mgt(ieee,(struct ieee80211_hdr *)skb->data,rx_stats); + + if((ieee->state == IEEE80211_LINKED)&&(memcmp(hdr->addr3,ieee->current_network.bssid,ETH_ALEN))) { + dev_kfree_skb_any(skb); + return 0; + } + + ieee80211_rx_frame_softmac(ieee, skb, rx_stats, type, stype); + + dev_kfree_skb_any(skb); + + return 0; + + #ifdef NOT_YET + if (ieee->iw_mode == IW_MODE_MASTER) { + printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", + ieee->dev->name); + return 0; +/* + hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) + skb->data);*/ + } + + if (ieee->hostapd && type == IEEE80211_TYPE_MGMT) { + if (stype == WLAN_FC_STYPE_BEACON && + ieee->iw_mode == IW_MODE_MASTER) { + struct sk_buff *skb2; + /* Process beacon frames also in kernel driver to + * update STA(AP) table statistics */ + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) + hostap_rx(skb2->dev, skb2, rx_stats); + } + + /* send management frames to the user space daemon for + * processing */ + ieee->apdevstats.rx_packets++; + ieee->apdevstats.rx_bytes += skb->len; + prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); + return 0; + } + + if (ieee->iw_mode == IW_MODE_MASTER) { + if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { + printk(KERN_DEBUG "%s: unknown management frame " + "(type=0x%02x, stype=0x%02x) dropped\n", + skb->dev->name, type, stype); + return -1; + } + + hostap_rx(skb->dev, skb, rx_stats); + return 0; + } + + printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " + "received in non-Host AP mode\n", skb->dev->name); + return -1; + #endif +} + + + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char rfc1042_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +/* No encapsulation header if EtherType < 0x600 (=length) */ + +/* Called by ieee80211_rx_frame_decrypt */ +static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, + struct sk_buff *skb, size_t hdrlen) +{ + struct net_device *dev = ieee->dev; + u16 fc, ethertype; + struct ieee80211_hdr *hdr; + u8 *pos; + + if (skb->len < 24) + return 0; + + hdr = (struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + + /* check that the frame is unicast frame to us */ + if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_TODS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && + memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { + /* ToDS frame with own addr BSSID and DA */ + } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_FROMDS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + /* FromDS frame with own addr as DA */ + } else + return 0; + + if (skb->len < 24 + 8) + return 0; + + /* check for port access entity Ethernet type */ +// pos = skb->data + 24; + pos = skb->data + hdrlen; + ethertype = (pos[6] << 8) | pos[7]; + if (ethertype == ETH_P_PAE) + return 1; + + return 0; +} + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static inline int +ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb, + struct ieee80211_crypt_data *crypt) +{ + struct ieee80211_hdr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) + return 0; + + hdr = (struct ieee80211_hdr *) skb->data; +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) + { + hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); + } + else +#endif + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + +#ifdef CONFIG_IEEE80211_CRYPT_TKIP + if (ieee->tkip_countermeasures && + strcmp(crypt->ops->name, "TKIP") == 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "received packet from " MAC_FMT "\n", + ieee->dev->name, MAC_ARG(hdr->addr2)); + } + return -1; + } +#endif + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + IEEE80211_DEBUG_DROP( + "decryption failed (SA=" MAC_FMT + ") res=%d\n", MAC_ARG(hdr->addr2), res); + if (res == -2) + IEEE80211_DEBUG_DROP("Decryption failed ICV " + "mismatch (key %d)\n", + skb->data[hdrlen + 3] >> 6); + ieee->ieee_stats.rx_discards_undecryptable++; + return -1; + } + + return res; +} + + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static inline int +ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *skb, + int keyidx, struct ieee80211_crypt_data *crypt) +{ + struct ieee80211_hdr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) + return 0; + + hdr = (struct ieee80211_hdr *) skb->data; +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) + { + hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); + } + else +#endif + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" + " (SA=" MAC_FMT " keyidx=%d)\n", + ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); + return -1; + } + + return 0; +} + + +/* this function is stolen from ipw2200 driver*/ +#define IEEE_PACKET_RETRY_TIME (5*HZ) +static int is_duplicate_packet(struct ieee80211_device *ieee, + struct ieee80211_hdr *header) +{ + u16 fc = le16_to_cpu(header->frame_ctl); + u16 sc = le16_to_cpu(header->seq_ctl); + u16 seq = WLAN_GET_SEQ_SEQ(sc); + u16 frag = WLAN_GET_SEQ_FRAG(sc); + u16 *last_seq, *last_frag; + unsigned long *last_time; + struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; + struct ieee80211_hdr_QOS *hdr_4addr_QoS; + u8 tid; + +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode) + { + tid = (header->addr2[ETH_ALEN-2] ^ header->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; + } + else +#endif + //TO2DS and QoS + if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)header; + tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; + tid = UP2AC(tid); + tid ++; + } else if(IEEE80211_QOS_HAS_SEQ(fc)) { //QoS + hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS*)header; + tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; + tid = UP2AC(tid); + tid ++; + } else { // no QoS + tid = 0; + } + switch (ieee->iw_mode) { + case IW_MODE_ADHOC: + { + struct list_head *p; + struct ieee_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; + //for (pos = (head)->next; pos != (head); pos = pos->next) + __list_for_each(p, &ieee->ibss_mac_hash[index]) { + entry = list_entry(p, struct ieee_ibss_seq, list); + if (!memcmp(entry->mac, mac, ETH_ALEN)) + break; + } + // if (memcmp(entry->mac, mac, ETH_ALEN)){ + if (p == &ieee->ibss_mac_hash[index]) { + entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC); + if (!entry) { + printk(KERN_WARNING "Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num[tid] = seq; + entry->frag_num[tid] = frag; + entry->packet_time[tid] = jiffies; + list_add(&entry->list, &ieee->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num[tid]; + last_frag = &entry->frag_num[tid]; + last_time = &entry->packet_time[tid]; + break; + } + + case IW_MODE_INFRA: + last_seq = &ieee->last_rxseq_num[tid]; + last_frag = &ieee->last_rxfrag_num[tid]; + last_time = &ieee->last_packet_time[tid]; + + break; + default: +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode) + { + last_seq = &ieee->last_rxseq_num[tid]; + last_frag = &ieee->last_rxfrag_num[tid]; + last_time = &ieee->last_packet_time[tid]; + break; + } + else +#endif + return 0; + } + +// if(tid != 0) { +// printk(KERN_WARNING ":)))))))))))%x %x %x, fc(%x)\n", tid, *last_seq, seq, header->frame_ctl); +// } + if ((*last_seq == seq) && + time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag){ + //printk(KERN_WARNING "[1] go drop!\n"); + goto drop; + + } + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + //printk(KERN_WARNING "[2] go drop!\n"); + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + +drop: +// BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); +// printk("DUP\n"); + + return 1; +} + + +/* All received frames are sent to this function. @skb contains the frame in + * IEEE 802.11 format, i.e., in the format it was sent over air. + * This function is called only as a tasklet (software IRQ). */ +int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats) +{ + struct net_device *dev = ieee->dev; + //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct ieee80211_hdr *hdr; + //struct ieee80211_hdr_3addr_QOS *hdr; + + size_t hdrlen; + u16 fc, type, stype, sc; + struct net_device_stats *stats; + unsigned int frag; + u8 *payload; + u16 ethertype; +#ifdef NOT_YET + struct net_device *wds = NULL; + struct sk_buff *skb2 = NULL; + struct net_device *wds = NULL; + int frame_authorized = 0; + int from_assoc_ap = 0; + void *sta = NULL; +#endif +// u16 QOS_ctl = 0; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + struct ieee80211_crypt_data *crypt = NULL; + int keyidx = 0; + + //Added for mesh by Lawrence. +#ifdef _RTL8187_EXT_PATCH_ + u8 status; + u32 flags; +#endif + // cheat the the hdr type + hdr = (struct ieee80211_hdr *)skb->data; + stats = &ieee->stats; + + if (skb->len < 10) { + printk(KERN_INFO "%s: SKB length < 10\n", + dev->name); + goto rx_dropped; + } + + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + sc = le16_to_cpu(hdr->seq_ctl); + + frag = WLAN_GET_SEQ_FRAG(sc); + +//YJ,add,080828,for keep alive + if((fc & IEEE80211_FCTL_TODS) != IEEE80211_FCTL_TODS) + { + if(!memcmp(hdr->addr1,dev->dev_addr, ETH_ALEN)) + { + ieee->NumRxUnicast++; + } + } + else + { + if(!memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) + { + ieee->NumRxUnicast++; + } + } +//YJ,add,080828,for keep alive,end + +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) + { + hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); + if(skb->len < hdrlen) + goto rx_dropped; + } + else +#endif + hdrlen = ieee80211_get_hdrlen(fc); + +#ifdef NOT_YET +#if WIRELESS_EXT > 15 + /* Put this code here so that we avoid duplicating it in all + * Rx paths. - Jean II */ +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + /* If spy monitoring on */ + if (iface->spy_data.spy_number > 0) { + struct iw_quality wstats; + wstats.level = rx_stats->signal; + wstats.noise = rx_stats->noise; + wstats.updated = 6; /* No qual value */ + /* Update spy records */ + wireless_spy_update(dev, hdr->addr2, &wstats); + } +#endif /* IW_WIRELESS_SPY */ +#endif /* WIRELESS_EXT > 15 */ + hostap_update_rx_stats(local->ap, hdr, rx_stats); +#endif + +#if WIRELESS_EXT > 15 + if (ieee->iw_mode == IW_MODE_MONITOR) { + ieee80211_monitor_rx(ieee, skb, rx_stats); + stats->rx_packets++; + stats->rx_bytes += skb->len; + return 1; + } +#endif + if (ieee->host_decrypt) { + int idx = 0; + if (skb->len >= hdrlen + 3) + idx = skb->data[hdrlen + 3] >> 6; + crypt = ieee->crypt[idx]; +#ifdef NOT_YET + sta = NULL; + + /* Use station specific key to override default keys if the + * receiver address is a unicast address ("individual RA"). If + * bcrx_sta_key parameter is set, station specific key is used + * even with broad/multicast targets (this is against IEEE + * 802.11, but makes it easier to use different keys with + * stations that do not support WEP key mapping). */ + + if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) + (void) hostap_handle_sta_crypto(local, hdr, &crypt, + &sta); +#endif + + /* allow NULL decrypt to indicate an station specific override + * for default encryption */ + if (crypt && (crypt->ops == NULL || + crypt->ops->decrypt_mpdu == NULL)) + crypt = NULL; + + if (!crypt && (fc & IEEE80211_FCTL_WEP)) { + /* This seems to be triggered by some (multicast?) + * frames from other than current BSS, so just drop the + * frames silently instead of filling system log with + * these reports. */ + IEEE80211_DEBUG_DROP("Decryption failed (not set)" + " (SA=" MAC_FMT ")\n", + MAC_ARG(hdr->addr2)); + ieee->ieee_stats.rx_discards_undecryptable++; + goto rx_dropped; + } + } + + if (skb->len < IEEE80211_DATA_HDR3_LEN) + goto rx_dropped; + +#ifdef _RTL8187_EXT_PATCH_ + if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_update_expire ) + ieee->ext_patch_ieee80211_rx_mgt_update_expire( ieee, skb ); +#endif + + // if QoS enabled, should check the sequence for each of the AC + if (is_duplicate_packet(ieee, hdr)) + goto rx_dropped; + + + if (type == IEEE80211_FTYPE_MGMT) { + + #if 0 + if ( stype == IEEE80211_STYPE_AUTH && + fc & IEEE80211_FCTL_WEP && ieee->host_decrypt && + (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) + { + printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " + "from " MAC_FMT "\n", dev->name, + MAC_ARG(hdr->addr2)); + /* TODO: could inform hostapd about this so that it + * could send auth failure report */ + goto rx_dropped; + } + #endif + + + if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) + goto rx_dropped; + else + goto rx_exit; + } +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_on_rx) + { + if(ieee->ext_patch_ieee80211_rx_on_rx(ieee, skb, rx_stats, type, stype)==0) + { + goto rx_exit; + } + } +#endif + + /* Data frame - extract src/dst addresses */ + switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_FROMDS: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr3, ETH_ALEN); + memcpy(bssid,hdr->addr2,ETH_ALEN); + break; + case IEEE80211_FCTL_TODS: + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(bssid,hdr->addr1,ETH_ALEN); + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + if (skb->len < IEEE80211_DATA_HDR4_LEN) + goto rx_dropped; + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr4, ETH_ALEN); + memcpy(bssid, ieee->current_network.bssid, ETH_ALEN); + break; + case 0: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(bssid,hdr->addr3,ETH_ALEN); + break; + } + +#ifdef NOT_YET + if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) + goto rx_dropped; + if (wds) { + skb->dev = dev = wds; + stats = hostap_get_stats(dev); + } + + if (ieee->iw_mode == IW_MODE_MASTER && !wds && + (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && + ieee->stadev && + memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) { + /* Frame from BSSID of the AP for which we are a client */ + skb->dev = dev = ieee->stadev; + stats = hostap_get_stats(dev); + from_assoc_ap = 1; + } +#endif + + dev->last_rx = jiffies; + +#ifdef NOT_YET + if ((ieee->iw_mode == IW_MODE_MASTER || + ieee->iw_mode == IW_MODE_REPEAT) && + !from_assoc_ap) { + switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats, + wds != NULL)) { + case AP_RX_CONTINUE_NOT_AUTHORIZED: + frame_authorized = 0; + break; + case AP_RX_CONTINUE: + frame_authorized = 1; + break; + case AP_RX_DROP: + goto rx_dropped; + case AP_RX_EXIT: + goto rx_exit; + } + } +#endif + +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_is_valid_framectl) + { + if(ieee->ext_patch_ieee80211_rx_is_valid_framectl(ieee, fc, type, stype)==0) + goto rx_dropped; + } + else +#endif + /* Nullfunc frames may have PS-bit set, so they must be passed to + * hostap_handle_sta_rx() before being dropped here. */ + if (stype != IEEE80211_STYPE_DATA && + stype != IEEE80211_STYPE_DATA_CFACK && + stype != IEEE80211_STYPE_DATA_CFPOLL && + stype != IEEE80211_STYPE_DATA_CFACKPOLL&& + stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4 + ) { + if (stype != IEEE80211_STYPE_NULLFUNC) + IEEE80211_DEBUG_DROP( + "RX: dropped data frame " + "with no data (type=0x%02x, " + "subtype=0x%02x, len=%d)\n", + type, stype, skb->len); + goto rx_dropped; + } + if(memcmp(bssid,ieee->current_network.bssid,ETH_ALEN)) { + goto rx_dropped; + } + + ieee->NumRxDataInPeriod++; + ieee->NumRxOkTotal++; + /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ + + if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && + (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) + goto rx_dropped; + + hdr = (struct ieee80211_hdr *) skb->data; + + /* skb: hdr + (possibly fragmented) plaintext payload */ + // PR: FIXME: hostap has additional conditions in the "if" below: + // ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && + if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { + int flen; + struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); + IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); + + if (!frag_skb) { + IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, + "Rx cannot get skb from fragment " + "cache (morefrag=%d seq=%u frag=%u)\n", + (fc & IEEE80211_FCTL_MOREFRAGS) != 0, + WLAN_GET_SEQ_SEQ(sc), frag); + goto rx_dropped; + } + flen = skb->len; + if (frag != 0) + flen -= hdrlen; + + if (frag_skb->tail + flen > frag_skb->end) { + printk(KERN_WARNING "%s: host decrypted and " + "reassembled frame did not fit skb\n", + dev->name); + ieee80211_frag_cache_invalidate(ieee, hdr); + goto rx_dropped; + } + + if (frag == 0) { + /* copy first fragment (including full headers) into + * beginning of the fragment cache skb */ + memcpy(skb_put(frag_skb, flen), skb->data, flen); + } else { + /* append frame payload to the end of the fragment + * cache skb */ + memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, + flen); + } + dev_kfree_skb_any(skb); + skb = NULL; + + if (fc & IEEE80211_FCTL_MOREFRAGS) { + /* more fragments expected - leave the skb in fragment + * cache for now; it will be delivered to upper layers + * after all fragments have been received */ + goto rx_exit; + } + + /* this was the last fragment and the frame will be + * delivered, so remove skb from fragment cache */ + skb = frag_skb; + hdr = (struct ieee80211_hdr *) skb->data; + ieee80211_frag_cache_invalidate(ieee, hdr); + } + + /* skb: hdr + (possible reassembled) full MSDU payload; possibly still + * encrypted/authenticated */ + if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && + ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) + goto rx_dropped; + + hdr = (struct ieee80211_hdr *) skb->data; + if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) { + if (/*ieee->ieee802_1x &&*/ + ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + +#ifdef CONFIG_IEEE80211_DEBUG + /* pass unencrypted EAPOL frames even if encryption is + * configured */ + struct eapol *eap = (struct eapol *)(skb->data + + 24); + IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", + eap_get_type(eap->type)); +#endif + } else { + IEEE80211_DEBUG_DROP( + "encryption configured, but RX " + "frame not encrypted (SA=" MAC_FMT ")\n", + MAC_ARG(hdr->addr2)); + goto rx_dropped; + } + } + +#ifdef CONFIG_IEEE80211_DEBUG + if (crypt && !(fc & IEEE80211_FCTL_WEP) && + ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + struct eapol *eap = (struct eapol *)(skb->data + + 24); + IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", + eap_get_type(eap->type)); + } +#endif + + if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep && + !ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + IEEE80211_DEBUG_DROP( + "dropped unencrypted RX data " + "frame from " MAC_FMT + " (drop_unencrypted=1)\n", + MAC_ARG(hdr->addr2)); + goto rx_dropped; + } +/* + if(ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + printk(KERN_WARNING "RX: IEEE802.1X EPAOL frame!\n"); + } +*/ + /* skb: hdr + (possible reassembled) full plaintext payload */ + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + +#ifdef NOT_YET + /* If IEEE 802.1X is used, check whether the port is authorized to send + * the received frame. */ + if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) { + if (ethertype == ETH_P_PAE) { + printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n", + dev->name); + if (ieee->hostapd && ieee->apdev) { + /* Send IEEE 802.1X frames to the user + * space daemon for processing */ + prism2_rx_80211(ieee->apdev, skb, rx_stats, + PRISM2_RX_MGMT); + ieee->apdevstats.rx_packets++; + ieee->apdevstats.rx_bytes += skb->len; + goto rx_exit; + } + } else if (!frame_authorized) { + printk(KERN_DEBUG "%s: dropped frame from " + "unauthorized port (IEEE 802.1X): " + "ethertype=0x%04x\n", + dev->name, ethertype); + goto rx_dropped; + } + } +#endif + +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_process_dataframe) + { + //Added for mesh rx interrupt. + //spin_lock_irqsave(&ieee->lock,flags); + status = ieee->ext_patch_ieee80211_rx_process_dataframe(ieee, skb, rx_stats); + //spin_unlock_irqrestore(&ieee->lock,flags); + + if(status) +// if(ieee->ext_patch_ieee80211_rx_process_dataframe(ieee, skb, rx_stats)) + goto rx_exit; + else + goto rx_dropped; + } +#endif + + /* convert hdr + possible LLC headers into Ethernet header */ + if (skb->len - hdrlen >= 8 && + ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + SNAP_SIZE); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + skb_pull(skb, hdrlen); + len = htons(skb->len); + memcpy(skb_push(skb, 2), &len, 2); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } + +#ifdef NOT_YET + if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_TODS) && + skb->len >= ETH_HLEN + ETH_ALEN) { + /* Non-standard frame: get addr4 from its bogus location after + * the payload */ + memcpy(skb->data + ETH_ALEN, + skb->data + skb->len - ETH_ALEN, ETH_ALEN); + skb_trim(skb, skb->len - ETH_ALEN); + } +#endif + + stats->rx_packets++; + stats->rx_bytes += skb->len; + +#ifdef NOT_YET + if (ieee->iw_mode == IW_MODE_MASTER && !wds && + ieee->ap->bridge_packets) { + if (dst[0] & 0x01) { + /* copy multicast frame both to the higher layers and + * to the wireless media */ + ieee->ap->bridged_multicast++; + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2 == NULL) + printk(KERN_DEBUG "%s: skb_clone failed for " + "multicast frame\n", dev->name); + } else if (hostap_is_sta_assoc(ieee->ap, dst)) { + /* send frame directly to the associated STA using + * wireless media and not passing to higher layers */ + ieee->ap->bridged_unicast++; + skb2 = skb; + skb = NULL; + } + } + + if (skb2 != NULL) { + /* send to wireless media */ + skb2->protocol = __constant_htons(ETH_P_802_3); + skb2->mac.raw = skb2->nh.raw = skb2->data; + /* skb2->nh.raw = skb2->data + ETH_HLEN; */ + skb2->dev = dev; + dev_queue_xmit(skb2); + } + +#endif + if (skb) { + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + skb->dev = dev; + skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ + ieee->last_rx_ps_time = jiffies; + netif_rx(skb); + } + + rx_exit: +#ifdef NOT_YET + if (sta) + hostap_handle_sta_release(sta); +#endif + return 1; + + rx_dropped: + stats->rx_dropped++; + + /* Returning 0 indicates to caller that we have not handled the SKB-- + * so it is still allocated and can be used again by underlying + * hardware as a DMA target */ + return 0; +} + +#ifdef _RTL8187_EXT_PATCH_ +int ieee_ext_skb_p80211_to_ether(struct sk_buff *skb, int hdrlen, u8 *dst, u8 *src) +{ + u8 *payload; + u16 ethertype; + + /* skb: hdr + (possible reassembled) full plaintext payload */ + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + + /* convert hdr + possible LLC headers into Ethernet header */ + if (skb->len - hdrlen >= 8 && + ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + SNAP_SIZE); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + skb_pull(skb, hdrlen); + len = htons(skb->len); + memcpy(skb_push(skb, 2), &len, 2); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } + + return 1; +} +#endif // _RTL8187_EXT_PATCH_ + + +#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 + +static inline int ieee80211_is_ofdm_rate(u8 rate) +{ + switch (rate & ~IEEE80211_BASIC_RATE_MASK) { + case IEEE80211_OFDM_RATE_6MB: + case IEEE80211_OFDM_RATE_9MB: + case IEEE80211_OFDM_RATE_12MB: + case IEEE80211_OFDM_RATE_18MB: + case IEEE80211_OFDM_RATE_24MB: + case IEEE80211_OFDM_RATE_36MB: + case IEEE80211_OFDM_RATE_48MB: + case IEEE80211_OFDM_RATE_54MB: + return 1; + } + return 0; +} + +static inline int ieee80211_SignalStrengthTranslate( + int CurrSS + ) +{ + int RetSS; + + // Step 1. Scale mapping. + if(CurrSS >= 71 && CurrSS <= 100) + { + RetSS = 90 + ((CurrSS - 70) / 3); + } + else if(CurrSS >= 41 && CurrSS <= 70) + { + RetSS = 78 + ((CurrSS - 40) / 3); + } + else if(CurrSS >= 31 && CurrSS <= 40) + { + RetSS = 66 + (CurrSS - 30); + } + else if(CurrSS >= 21 && CurrSS <= 30) + { + RetSS = 54 + (CurrSS - 20); + } + else if(CurrSS >= 5 && CurrSS <= 20) + { + RetSS = 42 + (((CurrSS - 5) * 2) / 3); + } + else if(CurrSS == 4) + { + RetSS = 36; + } + else if(CurrSS == 3) + { + RetSS = 27; + } + else if(CurrSS == 2) + { + RetSS = 18; + } + else if(CurrSS == 1) + { + RetSS = 9; + } + else + { + RetSS = CurrSS; + } + //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); + + // Step 2. Smoothing. + + //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); + + return RetSS; +} + +#ifdef ENABLE_DOT11D +static inline void ieee80211_extract_country_ie( + struct ieee80211_device *ieee, + struct ieee80211_info_element *info_element, + struct ieee80211_network *network, + u8 * addr2 +) +{ +#if 0 + u32 i = 0; + u8 * p = (u8*)info_element->data; + printk("-----------------------\n"); + printk("%s Country IE:", network->ssid); + for(i=0; i<info_element->len; i++) + printk("\t%2.2x", *(p+i)); + printk("\n-----------------------\n"); +#endif + if(IS_DOT11D_ENABLE(ieee)) + { + if(info_element->len!= 0) + { + memcpy(network->CountryIeBuf, info_element->data, info_element->len); + network->CountryIeLen = info_element->len; + + if(!IS_COUNTRY_IE_VALID(ieee)) + { + Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data); + } + } + + // + // 070305, rcnjko: I update country IE watch dog here because + // some AP (e.g. Cisco 1242) don't include country IE in their + // probe response frame. + // + if(IS_EQUAL_CIE_SRC(ieee, addr2) ) + { + UPDATE_CIE_WATCHDOG(ieee); + } + } + +} +#endif + +int +ieee80211_TranslateToDbm( + unsigned char SignalStrengthIndex // 0-100 index. + ) +{ + unsigned char SignalPower; // in dBm. + + // Translate to dBm (x=0.5y-95). + SignalPower = (int)SignalStrengthIndex * 7 / 10; + SignalPower -= 95; + + return SignalPower; +} +inline int ieee80211_network_init( + struct ieee80211_device *ieee, + struct ieee80211_probe_response *beacon, + struct ieee80211_network *network, + struct ieee80211_rx_stats *stats) +{ +#ifdef CONFIG_IEEE80211_DEBUG + char rates_str[64]; + char *p; +#endif + struct ieee80211_info_element *info_element; + u16 left; + u8 i; + short offset; + u8 curRate = 0,hOpRate = 0,curRate_ex = 0; + + /* Pull out fixed field data */ + memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); + network->capability = beacon->capability; + network->last_scanned = jiffies; + network->time_stamp[0] = beacon->time_stamp[0]; + network->time_stamp[1] = beacon->time_stamp[1]; + network->beacon_interval = beacon->beacon_interval; + /* Where to pull this? beacon->listen_interval;*/ + network->listen_interval = 0x0A; + network->rates_len = network->rates_ex_len = 0; + network->last_associate = 0; + network->ssid_len = 0; + network->flags = 0; + network->atim_window = 0; + network->QoS_Enable = 0; +//by amy 080312 + network->HighestOperaRate = 0; +//by amy 080312 +#ifdef THOMAS_TURBO + network->Turbo_Enable = 0; +#endif +#ifdef ENABLE_DOT11D + network->CountryIeLen = 0; + memset(network->CountryIeBuf, 0, MAX_IE_LEN); +#endif + + if (stats->freq == IEEE80211_52GHZ_BAND) { + /* for A band (No DS info) */ + network->channel = stats->received_channel; + } else + network->flags |= NETWORK_HAS_CCK; + + network->wpa_ie_len = 0; + network->rsn_ie_len = 0; + + info_element = &beacon->info_element; + left = stats->len - ((void *)info_element - (void *)beacon); + while (left >= sizeof(struct ieee80211_info_element_hdr)) { + if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { + IEEE80211_DEBUG_SCAN("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%d left=%d.\n", + info_element->len + sizeof(struct ieee80211_info_element), + left); + return 1; + } + + switch (info_element->id) { + case MFIE_TYPE_SSID: + if (ieee80211_is_empty_essid(info_element->data, + info_element->len)) { + network->flags |= NETWORK_EMPTY_ESSID; + break; + } + + network->ssid_len = min(info_element->len, + (u8)IW_ESSID_MAX_SIZE); + memcpy(network->ssid, info_element->data, network->ssid_len); + if (network->ssid_len < IW_ESSID_MAX_SIZE) + memset(network->ssid + network->ssid_len, 0, + IW_ESSID_MAX_SIZE - network->ssid_len); + + IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n", + network->ssid, network->ssid_len); + break; + + case MFIE_TYPE_RATES: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_len = min(info_element->len, MAX_RATES_LENGTH); + for (i = 0; i < network->rates_len; i++) { + network->rates[i] = info_element->data[i]; + curRate = network->rates[i] & 0x7f; + if( hOpRate < curRate ) + hOpRate = curRate; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate(info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n", + rates_str, network->rates_len); + break; + + case MFIE_TYPE_RATES_EX: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_ex_len = min(info_element->len, MAX_RATES_EX_LENGTH); + for (i = 0; i < network->rates_ex_len; i++) { + network->rates_ex[i] = info_element->data[i]; + curRate_ex = network->rates_ex[i] & 0x7f; + if( hOpRate < curRate_ex ) + hOpRate = curRate_ex; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate(info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n", + rates_str, network->rates_ex_len); + break; + + case MFIE_TYPE_DS_SET: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n", + info_element->data[0]); + if (stats->freq == IEEE80211_24GHZ_BAND) + network->channel = info_element->data[0]; + break; + + case MFIE_TYPE_FH_SET: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n"); + break; + + case MFIE_TYPE_CF_SET: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n"); + break; + + case MFIE_TYPE_TIM: + + if(info_element->len < 4) + break; + + network->dtim_period = info_element->data[1]; + + if(ieee->state != IEEE80211_LINKED) + break; +#if 0 + network->last_dtim_sta_time[0] = stats->mac_time[0]; +#else + network->last_dtim_sta_time[0] = jiffies; +#endif + network->last_dtim_sta_time[1] = stats->mac_time[1]; + + network->dtim_data = IEEE80211_DTIM_VALID; + + if(info_element->data[0] != 0) + break; + + if(info_element->data[2] & 1) + network->dtim_data |= IEEE80211_DTIM_MBCAST; + + offset = (info_element->data[2] >> 1)*2; + + //printk("offset1:%x aid:%x\n",offset, ieee->assoc_id); + + /* add and modified for ps 2008.1.22 */ + if(ieee->assoc_id < 8*offset || + ieee->assoc_id > 8*(offset + info_element->len -3)) { + break; + } + + offset = (ieee->assoc_id/8) - offset;// + ((aid % 8)? 0 : 1) ; + + // printk("offset:%x data:%x, ucast:%d\n", offset, + // info_element->data[3+offset] , + // info_element->data[3+offset] & (1<<(ieee->assoc_id%8))); + + if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8))) { + network->dtim_data |= IEEE80211_DTIM_UCAST; + } + break; + + case MFIE_TYPE_IBSS_SET: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n"); + break; + + case MFIE_TYPE_CHALLENGE: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n"); + break; + + case MFIE_TYPE_GENERIC: + //nic is 87B + IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", + info_element->len); + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x01) { + network->wpa_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->wpa_ie, info_element, + network->wpa_ie_len); + } + +#ifdef THOMAS_TURBO + if (info_element->len == 7 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0xe0 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x01 && + info_element->data[4] == 0x02) { + network->Turbo_Enable = 1; + } +#endif + if (1 == stats->nic_type) {//nic 87 + break; + } + + if (info_element->len >= 5 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x02 && + info_element->data[4] == 0x00) { + //printk(KERN_WARNING "wmm info updated: %x\n", info_element->data[6]); + //WMM Information Element + network->wmm_info = info_element->data[6]; + network->QoS_Enable = 1; + } + + if (info_element->len >= 8 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x02 && + info_element->data[4] == 0x01) { + // Not care about version at present. + //WMM Information Element + //printk(KERN_WARNING "wmm info¶m updated: %x\n", info_element->data[6]); + network->wmm_info = info_element->data[6]; + //WMM Parameter Element + memcpy(network->wmm_param, (u8 *)(info_element->data + 8),(info_element->len - 8)); + network->QoS_Enable = 1; + } + break; + + case MFIE_TYPE_RSN: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n", + info_element->len); + network->rsn_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->rsn_ie, info_element, + network->rsn_ie_len); + break; +#ifdef ENABLE_DOT11D + case MFIE_TYPE_COUNTRY: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", + info_element->len); +// printk("=====>Receive <%s> Country IE\n",network->ssid); + ieee80211_extract_country_ie(ieee, info_element, network, beacon->header.addr2); + break; +#endif + default: + IEEE80211_DEBUG_SCAN("unsupported IE %d\n", + info_element->id); + break; + } + + left -= sizeof(struct ieee80211_info_element_hdr) + + info_element->len; + info_element = (struct ieee80211_info_element *) + &info_element->data[info_element->len]; + } +//by amy 080312 + network->HighestOperaRate = hOpRate; +//by amy 080312 + network->mode = 0; + if (stats->freq == IEEE80211_52GHZ_BAND) + network->mode = IEEE_A; + else { + if (network->flags & NETWORK_HAS_OFDM) + network->mode |= IEEE_G; + if (network->flags & NETWORK_HAS_CCK) + network->mode |= IEEE_B; + } + + if (network->mode == 0) { + IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " + "network.\n", + escape_essid(network->ssid, + network->ssid_len), + MAC_ARG(network->bssid)); + return 1; + } + + if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) + network->flags |= NETWORK_EMPTY_ESSID; +#if 0 + stats->signal = ieee80211_SignalStrengthTranslate(stats->signal); +#endif + stats->signal = ieee80211_TranslateToDbm(stats->signalstrength); + //stats->noise = stats->signal - stats->noise; + stats->noise = ieee80211_TranslateToDbm(100 - stats->signalstrength) - 25; + memcpy(&network->stats, stats, sizeof(network->stats)); + + return 0; +} + +static inline int is_same_network(struct ieee80211_network *src, + struct ieee80211_network *dst, + struct ieee80211_device * ieee) +{ + /* A network is only a duplicate if the channel, BSSID, ESSID + * and the capability field (in particular IBSS and BSS) all match. + * We treat all <hidden> with the same BSSID and channel + * as one network */ + return (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap + //((src->ssid_len == dst->ssid_len) && + (src->channel == dst->channel) && + !memcmp(src->bssid, dst->bssid, ETH_ALEN) && + (!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap + //!memcmp(src->ssid, dst->ssid, src->ssid_len) && + ((src->capability & WLAN_CAPABILITY_IBSS) == + (dst->capability & WLAN_CAPABILITY_IBSS)) && + ((src->capability & WLAN_CAPABILITY_BSS) == + (dst->capability & WLAN_CAPABILITY_BSS))); +} + +inline void update_network(struct ieee80211_network *dst, + struct ieee80211_network *src) +{ + unsigned char quality = src->stats.signalstrength; + unsigned char signal = 0; + unsigned char noise = 0; + if(dst->stats.signalstrength > 0) { + quality = (dst->stats.signalstrength * 5 + src->stats.signalstrength + 5)/6; + } + signal = ieee80211_TranslateToDbm(quality); + //noise = signal - src->stats.noise; + if(dst->stats.noise > 0) + noise = (dst->stats.noise * 5 + src->stats.noise)/6; + //if(strcmp(dst->ssid, "linksys_lzm000") == 0) +// printk("ssid:%s, quality:%d, signal:%d\n", dst->ssid, quality, signal); + memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); + dst->stats.signalstrength = quality; + dst->stats.signal = signal; +// printk("==================>stats.signal is %d\n",dst->stats.signal); + dst->stats.noise = noise; + + + dst->capability = src->capability; + memcpy(dst->rates, src->rates, src->rates_len); + dst->rates_len = src->rates_len; + memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); + dst->rates_ex_len = src->rates_ex_len; + dst->HighestOperaRate= src->HighestOperaRate; + //printk("==========>in %s: src->ssid is %s,chan is %d\n",__FUNCTION__,src->ssid,src->channel); + + //YJ,add,080819,for hidden ap + if(src->ssid_len > 0) + { + //if(src->ssid_len == 13) + // printk("=====================>>>>>>>> Dst ssid: %s Src ssid: %s\n", dst->ssid, src->ssid); + memset(dst->ssid, 0, dst->ssid_len); + dst->ssid_len = src->ssid_len; + memcpy(dst->ssid, src->ssid, src->ssid_len); + } + //YJ,add,080819,for hidden ap,end + + dst->channel = src->channel; + dst->mode = src->mode; + dst->flags = src->flags; + dst->time_stamp[0] = src->time_stamp[0]; + dst->time_stamp[1] = src->time_stamp[1]; + + dst->beacon_interval = src->beacon_interval; + dst->listen_interval = src->listen_interval; + dst->atim_window = src->atim_window; + dst->dtim_period = src->dtim_period; + dst->dtim_data = src->dtim_data; + dst->last_dtim_sta_time[0] = src->last_dtim_sta_time[0]; + dst->last_dtim_sta_time[1] = src->last_dtim_sta_time[1]; +// printk("update:%s, dtim_period:%x, dtim_data:%x\n", src->ssid, src->dtim_period, src->dtim_data); + memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); + dst->wpa_ie_len = src->wpa_ie_len; + memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); + dst->rsn_ie_len = src->rsn_ie_len; + + dst->last_scanned = jiffies; + /* dst->last_associate is not overwritten */ +// disable QoS process now, added by David 2006/7/25 +#if 1 + dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame. +/* + if((dst->wmm_info^src->wmm_info)&0x0f) {//Param Set Count change, update Parameter + memcpy(dst->wmm_param, src->wmm_param, IEEE80211_AC_PRAM_LEN); + } +*/ + if(src->wmm_param[0].ac_aci_acm_aifsn|| \ + src->wmm_param[1].ac_aci_acm_aifsn|| \ + src->wmm_param[2].ac_aci_acm_aifsn|| \ + src->wmm_param[1].ac_aci_acm_aifsn) { + memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); + } + dst->QoS_Enable = src->QoS_Enable; +#else + dst->QoS_Enable = 1;//for Rtl8187 simulation +#endif + dst->SignalStrength = src->SignalStrength; +#ifdef THOMAS_TURBO + dst->Turbo_Enable = src->Turbo_Enable; +#endif +#ifdef ENABLE_DOT11D + dst->CountryIeLen = src->CountryIeLen; + memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); +#endif +} + + +inline void ieee80211_process_probe_response( + struct ieee80211_device *ieee, + struct ieee80211_probe_response *beacon, + struct ieee80211_rx_stats *stats) +{ + struct ieee80211_network network; + struct ieee80211_network *target; + struct ieee80211_network *oldest = NULL; +#ifdef CONFIG_IEEE80211_DEBUG + struct ieee80211_info_element *info_element = &beacon->info_element; +#endif + unsigned long flags; + short renew; + u8 wmm_info; + u8 is_beacon = (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON)? 1:0; //YJ,add,080819,for hidden ap + + memset(&network, 0, sizeof(struct ieee80211_network)); +//rz +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_process_probe_response_1) { + ieee->ext_patch_ieee80211_process_probe_response_1(ieee, beacon, stats); + return; + } +#endif + + IEEE80211_DEBUG_SCAN( + "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", + escape_essid(info_element->data, info_element->len), + MAC_ARG(beacon->header.addr3), + (beacon->capability & (1<<0xf)) ? '1' : '0', + (beacon->capability & (1<<0xe)) ? '1' : '0', + (beacon->capability & (1<<0xd)) ? '1' : '0', + (beacon->capability & (1<<0xc)) ? '1' : '0', + (beacon->capability & (1<<0xb)) ? '1' : '0', + (beacon->capability & (1<<0xa)) ? '1' : '0', + (beacon->capability & (1<<0x9)) ? '1' : '0', + (beacon->capability & (1<<0x8)) ? '1' : '0', + (beacon->capability & (1<<0x7)) ? '1' : '0', + (beacon->capability & (1<<0x6)) ? '1' : '0', + (beacon->capability & (1<<0x5)) ? '1' : '0', + (beacon->capability & (1<<0x4)) ? '1' : '0', + (beacon->capability & (1<<0x3)) ? '1' : '0', + (beacon->capability & (1<<0x2)) ? '1' : '0', + (beacon->capability & (1<<0x1)) ? '1' : '0', + (beacon->capability & (1<<0x0)) ? '1' : '0'); +#if 0 + if(strcmp(escape_essid(beacon->info_element.data, beacon->info_element.len), "rtl_softap") == 0) + { + if(WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON) + { + u32 i = 0, len = stats->len; + u8 * p = (u8*)beacon; + printk("-----------------------\n"); + printk("rtl_softap Beacon:"); + for(i=0; i<len; i++) + printk("\t%2.2x", *(p+i)); + printk("\n-----------------------\n"); + } + } +#endif + if (ieee80211_network_init(ieee, beacon, &network, stats)) { + IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", + escape_essid(info_element->data, + info_element->len), + MAC_ARG(beacon->header.addr3), + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == + IEEE80211_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); + return; + } + +#ifdef ENABLE_DOT11D + // For Asus EeePc request, + // (1) if wireless adapter receive get any 802.11d country code in AP beacon, + // wireless adapter should follow the country code. + // (2) If there is no any country code in beacon, + // then wireless adapter should do active scan from ch1~11 and + // passive scan from ch12~14 + if(ieee->bGlobalDomain) + { + if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) + { + // Case 1: Country code + if(IS_COUNTRY_IE_VALID(ieee) ) + { + if( !IsLegalChannel(ieee, network.channel) ) + { + printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel); + return; + } + } + // Case 2: No any country code. + else + { + // Filter over channel ch12~14 + if(network.channel > 11) + { + printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel); + return; + } + } + } + else + { + // Case 1: Country code + if(IS_COUNTRY_IE_VALID(ieee) ) + { + if( !IsLegalChannel(ieee, network.channel) ) + { + printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network.channel); + return; + } + } + // Case 2: No any country code. + else + { + // Filter over channel ch12~14 + if(network.channel > 14) + { + printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network.channel); + return; + } + } + } + } +#endif + /* The network parsed correctly -- so now we scan our known networks + * to see if we can find it in our list. + * + * NOTE: This search is definitely not optimized. Once its doing + * the "right thing" we'll optimize it for efficiency if + * necessary */ + + /* Search for this entry in the list and update it if it is + * already there. */ + + spin_lock_irqsave(&ieee->lock, flags); + + if(is_same_network(&ieee->current_network, &network, ieee)) { + wmm_info = ieee->current_network.wmm_info; + //YJ,add,080819,for hidden ap + if(is_beacon == 0) + network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); + else if(ieee->state == IEEE80211_LINKED) + ieee->NumRxBcnInPeriod++; + //YJ,add,080819,for hidden ap,end + //printk("====>network.ssid=%s cur_ssid=%s\n", network.ssid, ieee->current_network.ssid); + update_network(&ieee->current_network, &network); + } + + list_for_each_entry(target, &ieee->network_list, list) { + if (is_same_network(target, &network, ieee)) + break; + if ((oldest == NULL) || + (target->last_scanned < oldest->last_scanned)) + oldest = target; + } + + /* If we didn't find a match, then get a new network slot to initialize + * with this beacon's information */ + if (&target->list == &ieee->network_list) { + if (list_empty(&ieee->network_free_list)) { + /* If there are no more slots, expire the oldest */ + list_del(&oldest->list); + target = oldest; + IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " + "network list.\n", + escape_essid(target->ssid, + target->ssid_len), + MAC_ARG(target->bssid)); + } else { + /* Otherwise just pull from the free list */ + target = list_entry(ieee->network_free_list.next, + struct ieee80211_network, list); + list_del(ieee->network_free_list.next); + } + + +#ifdef CONFIG_IEEE80211_DEBUG + IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", + escape_essid(network.ssid, + network.ssid_len), + MAC_ARG(network.bssid), + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == + IEEE80211_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); +#endif + +#ifdef _RTL8187_EXT_PATCH_ + network.ext_entry = target->ext_entry; +#endif + memcpy(target, &network, sizeof(*target)); + list_add_tail(&target->list, &ieee->network_list); + if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) + ieee80211_softmac_new_net(ieee,&network); + } else { + IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", + escape_essid(target->ssid, + target->ssid_len), + MAC_ARG(target->bssid), + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == + IEEE80211_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); + + /* 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 + */ + renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); + //YJ,add,080819,for hidden ap + if(is_beacon == 0) + network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); + //if(strncmp(network.ssid, "linksys-c",9) == 0) + // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); + if(((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ + && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\ + ||((ieee->current_network.ssid_len == network.ssid_len)&&(strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK)))) + renew = 1; + //YJ,add,080819,for hidden ap,end + update_network(target, &network); + if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) + ieee80211_softmac_new_net(ieee,&network); + } + + spin_unlock_irqrestore(&ieee->lock, flags); +} + +void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr *header, + struct ieee80211_rx_stats *stats) +{ + switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { + + case IEEE80211_STYPE_BEACON: + IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + IEEE80211_DEBUG_SCAN("Beacon\n"); + ieee80211_process_probe_response( + ieee, (struct ieee80211_probe_response *)header, stats); + break; + + case IEEE80211_STYPE_PROBE_RESP: + IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + IEEE80211_DEBUG_SCAN("Probe response\n"); + ieee80211_process_probe_response( + ieee, (struct ieee80211_probe_response *)header, stats); + break; +//rz +#ifdef _RTL8187_EXT_PATCH_ + case IEEE80211_STYPE_PROBE_REQ: + IEEE80211_DEBUG_MGMT("received PROBE REQUEST (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + IEEE80211_DEBUG_SCAN("Probe request\n"); + /// + if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_on_probe_req ) + ieee->ext_patch_ieee80211_rx_mgt_on_probe_req( ieee, (struct ieee80211_probe_request *)header, stats); + break; +#endif // _RTL8187_EXT_PATCH_ + + } +} + +#if 0 +EXPORT_SYMBOL(ieee80211_rx_mgt); +EXPORT_SYMBOL(ieee80211_rx); +EXPORT_SYMBOL(ieee80211_network_init); +#ifdef _RTL8187_EXT_PATCH_ +EXPORT_SYMBOL(ieee_ext_skb_p80211_to_ether); +#endif +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c new file mode 100644 index 0000000..fcffee5 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -0,0 +1,4029 @@ +/* IEEE 802.11 SoftMAC layer + * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> + * + * Mostly extracted from the rtl8180-sa2400 driver for the + * in-kernel generic ieee802.11 stack. + * + * Few lines might be stolen from other part of the ieee80211 + * stack. Copyright who own it's copyright + * + * WPA code stolen from the ipw2200 driver. + * Copyright who own it's copyright. + * + * released under the GPL + */ + + +#include "ieee80211.h" + +#include <linux/random.h> +#include <linux/delay.h> +#include <linux/version.h> +#include <asm/uaccess.h> + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif +u8 rsn_authen_cipher_suite[16][4] = { + {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved + {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default + {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default} + {0x00,0x0F,0xAC,0x03}, //WRAP-historical + {0x00,0x0F,0xAC,0x04}, //CCMP + {0x00,0x0F,0xAC,0x05}, //WEP-104 +}; + +short ieee80211_is_54g(struct ieee80211_network net) +{ + return ((net.rates_ex_len > 0) || (net.rates_len > 4)); +} + +short ieee80211_is_shortslot(struct ieee80211_network net) +{ + return (net.capability & WLAN_CAPABILITY_SHORT_SLOT); +} + +/* returns the total length needed for pleacing the RATE MFIE + * tag and the EXTENDED RATE MFIE tag if needed. + * It encludes two bytes per tag for the tag itself and its len + */ +unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee) +{ + unsigned int rate_len = 0; + + if (ieee->modulation & IEEE80211_CCK_MODULATION) + rate_len = IEEE80211_CCK_RATE_LEN + 2; + + if (ieee->modulation & IEEE80211_OFDM_MODULATION) + + rate_len += IEEE80211_OFDM_RATE_LEN + 2; + + return rate_len; +} + +/* pleace the MFIE rate, tag to the memory (double) poined. + * Then it updates the pointer so that + * it points after the new MFIE tag added. + */ +void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + if (ieee->modulation & IEEE80211_CCK_MODULATION){ + *tag++ = MFIE_TYPE_RATES; + *tag++ = 4; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + } + + /* We may add an option for custom rates that specific HW might support */ + *tag_p = tag; +} + +void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + if (ieee->modulation & IEEE80211_OFDM_MODULATION){ + + *tag++ = MFIE_TYPE_RATES_EX; + *tag++ = 8; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; + + } + + /* We may add an option for custom rates that specific HW might support */ + *tag_p = tag; +} + + +void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) { + u8 *tag = *tag_p; + + *tag++ = MFIE_TYPE_GENERIC; //0 + *tag++ = 7; + *tag++ = 0x00; + *tag++ = 0x50; + *tag++ = 0xf2; + *tag++ = 0x02;//5 + *tag++ = 0x00; + *tag++ = 0x01; +#ifdef SUPPORT_USPD + if(ieee->current_network.wmm_info & 0x80) { + *tag++ = 0x0f|MAX_SP_Len; + } else { + *tag++ = MAX_SP_Len; + } +#else + *tag++ = MAX_SP_Len; +#endif + *tag_p = tag; +} + +#ifdef THOMAS_TURBO +void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) { + u8 *tag = *tag_p; + + *tag++ = MFIE_TYPE_GENERIC; //0 + *tag++ = 7; + *tag++ = 0x00; + *tag++ = 0xe0; + *tag++ = 0x4c; + *tag++ = 0x01;//5 + *tag++ = 0x02; + *tag++ = 0x11; + *tag++ = 0x00; + + *tag_p = tag; + printk(KERN_ALERT "This is enable turbo mode IE process\n"); +} +#endif + +void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + int nh; + nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM; + +/* + * if the queue is full but we have newer frames then + * just overwrites the oldest. + * + * if (nh == ieee->mgmt_queue_tail) + * return -1; + */ + ieee->mgmt_queue_head = nh; + ieee->mgmt_queue_ring[nh] = skb; + + //return 0; +} + +struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee) +{ + struct sk_buff *ret; + + if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head) + return NULL; + + ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; + + ieee->mgmt_queue_tail = + (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM; + + return ret; +} + +void init_mgmt_queue(struct ieee80211_device *ieee) +{ + ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; +} + + +void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl); + +inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) +{ + unsigned long flags; + short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; + struct ieee80211_hdr_3addr *header= + (struct ieee80211_hdr_3addr *) skb->data; + + + spin_lock_irqsave(&ieee->lock, flags); + + /* called with 2nd param 0, no mgmt lock required */ + ieee80211_sta_wakeup(ieee,0); + + if(single){ + if(ieee->queue_stop){ + + enqueue_mgmt(ieee,skb); + }else{ + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* avoid watchdog triggers */ + ieee->dev->trans_start = jiffies; + ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + }else{ + spin_unlock_irqrestore(&ieee->lock, flags); + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* avoid watchdog triggers */ + ieee->dev->trans_start = jiffies; + ieee->softmac_hard_start_xmit(skb,ieee->dev); + + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); + } +} + + +inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) +{ + + short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; + struct ieee80211_hdr_3addr *header = + (struct ieee80211_hdr_3addr *) skb->data; + + + if(single){ + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* avoid watchdog triggers */ + ieee->dev->trans_start = jiffies; + ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); + + }else{ + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* avoid watchdog triggers */ + ieee->dev->trans_start = jiffies; + ieee->softmac_hard_start_xmit(skb,ieee->dev); + + } +// dev_kfree_skb_any(skb);//edit by thomas +} +//by amy for power save +inline struct sk_buff *ieee80211_disassociate_skb( + struct ieee80211_network *beacon, + struct ieee80211_device *ieee, + u8 asRsn) +{ + struct sk_buff *skb; + struct ieee80211_disassoc_frame *disass; + + skb = dev_alloc_skb(sizeof(struct ieee80211_disassoc_frame)); + if (!skb) + return NULL; + + disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame)); + disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); + disass->header.duration_id = 0; + + memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN); + + disass->reasoncode = asRsn; + return skb; +} +void +SendDisassociation( + struct ieee80211_device *ieee, + u8* asSta, + u8 asRsn +) +{ + struct ieee80211_network *beacon = &ieee->current_network; + struct sk_buff *skb; + skb = ieee80211_disassociate_skb(beacon,ieee,asRsn); + if (skb){ + softmac_mgmt_xmit(skb, ieee); + //dev_kfree_skb_any(skb);//edit by thomas + } +} + +//by amy for power save +inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) +{ + unsigned int len,rate_len; + u8 *tag; + struct sk_buff *skb; + struct ieee80211_probe_request *req; + +#ifdef _RTL8187_EXT_PATCH_ + short extMore = 0; + if(ieee->ext_patch_ieee80211_probe_req_1) + extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee); +#endif + + len = ieee->current_network.ssid_len; + + rate_len = ieee80211_MFIE_rate_len(ieee); + +#ifdef _RTL8187_EXT_PATCH_ + if(!extMore) +#endif + skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + + 2 + len + rate_len); +#ifdef _RTL8187_EXT_PATCH_ + else + skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + + 2 + len + rate_len+128); // MESHID + CAP +#endif + + if (!skb) + return NULL; + + req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); + req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + req->header.duration_id = 0; //FIXME: is this OK ? + + memset(req->header.addr1, 0xff, ETH_ALEN); + memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memset(req->header.addr3, 0xff, ETH_ALEN); + + tag = (u8 *) skb_put(skb,len+2+rate_len); + + *tag++ = MFIE_TYPE_SSID; + *tag++ = len; + memcpy(tag, ieee->current_network.ssid, len); + tag += len; + ieee80211_MFIE_Brate(ieee,&tag); + ieee80211_MFIE_Grate(ieee,&tag); + +#ifdef _RTL8187_EXT_PATCH_ + if(extMore) + ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag); +#endif + return skb; +} + +struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee); + +//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +//void ext_ieee80211_send_beacon_wq(struct work_struct *work) +//{ +// struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_send_beacon_wq); +//#else +void ext_ieee80211_send_beacon_wq(struct ieee80211_device *ieee) +{ +//#endif + + struct sk_buff *skb; + + //unsigned long flags; + + skb = ieee80211_get_beacon_(ieee); + + if (skb){ + softmac_mgmt_xmit(skb, ieee); + ieee->softmac_stats.tx_beacons++; + dev_kfree_skb_any(skb);//edit by thomas + } + + + //printk(KERN_WARNING "[1] beacon sending!\n"); + ieee->beacon_timer.expires = jiffies + + (MSECS( ieee->current_network.beacon_interval -5)); + + //spin_lock_irqsave(&ieee->beacon_lock,flags); + if(ieee->beacon_txing) + add_timer(&ieee->beacon_timer); + //spin_unlock_irqrestore(&ieee->beacon_lock,flags); +} + +void ieee80211_send_beacon(struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + + //unsigned long flags; + + skb = ieee80211_get_beacon_(ieee); + + if (skb){ + softmac_mgmt_xmit(skb, ieee); + ieee->softmac_stats.tx_beacons++; + dev_kfree_skb_any(skb);//edit by thomas + } + + //printk(KERN_WARNING "[1] beacon sending!\n"); + ieee->beacon_timer.expires = jiffies + + (MSECS( ieee->current_network.beacon_interval -5)); + + //spin_lock_irqsave(&ieee->beacon_lock,flags); + if(ieee->beacon_txing) + add_timer(&ieee->beacon_timer); + //spin_unlock_irqrestore(&ieee->beacon_lock,flags); +} + + +void ieee80211_send_beacon_cb(unsigned long _ieee) +{ + struct ieee80211_device *ieee = + (struct ieee80211_device *) _ieee; + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock, flags); + ieee80211_send_beacon(ieee); + spin_unlock_irqrestore(&ieee->beacon_lock, flags); +} + +#ifdef _RTL8187_EXT_PATCH_ + +inline struct sk_buff *ieee80211_probe_req_with_SSID(struct ieee80211_device *ieee, char *ssid, int len_ssid) +{ + unsigned int len,rate_len; + u8 *tag; + struct sk_buff *skb; + struct ieee80211_probe_request *req; + +#ifdef _RTL8187_EXT_PATCH_ + short extMore = 0; + if(ieee->ext_patch_ieee80211_probe_req_1) + extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee); +#endif + + len = len_ssid; + + rate_len = ieee80211_MFIE_rate_len(ieee); + +#ifdef _RTL8187_EXT_PATCH_ + if(!extMore) +#endif + skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + + 2 + len + rate_len); +#ifdef _RTL8187_EXT_PATCH_ + else + skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + + 2 + len + rate_len+128); // MESHID + CAP +#endif + + if (!skb) + return NULL; + + req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); + req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + req->header.duration_id = 0; //FIXME: is this OK ? + + memset(req->header.addr1, 0xff, ETH_ALEN); + memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memset(req->header.addr3, 0xff, ETH_ALEN); + + tag = (u8 *) skb_put(skb,len+2+rate_len); + + *tag++ = MFIE_TYPE_SSID; + *tag++ = len; + if(len) + { + memcpy(tag, ssid, len); + tag += len; + } + + ieee80211_MFIE_Brate(ieee,&tag); + ieee80211_MFIE_Grate(ieee,&tag); + +#ifdef _RTL8187_EXT_PATCH_ + if(extMore) + ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag); +#endif + return skb; +} + +#endif // _RTL8187_EXT_PATCH_ + + +void ieee80211_send_probe(struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode) + skb = ieee80211_probe_req_with_SSID(ieee, NULL, 0); + else +#endif + skb = ieee80211_probe_req(ieee); + if (skb){ + softmac_mgmt_xmit(skb, ieee); + ieee->softmac_stats.tx_probe_rq++; + //dev_kfree_skb_any(skb);//edit by thomas + } +} + +void ieee80211_send_probe_requests(struct ieee80211_device *ieee) +{ + if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){ + ieee80211_send_probe(ieee); + ieee80211_send_probe(ieee); + } +} + +/* this performs syncro scan blocking the caller until all channels + * in the allowed channel map has been checked. + */ +void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) +{ + short ch = 0; +#ifdef ENABLE_DOT11D + u8 channel_map[MAX_CHANNEL_NUMBER+1]; + memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); +#endif + down(&ieee->scan_sem); +// printk("==================> Sync scan\n"); +// dump_chnl_map(channel_map); + + while(1) + { + + do{ + ch++; + if (ch > MAX_CHANNEL_NUMBER) + goto out; /* scan completed */ + +#ifdef ENABLE_DOT11D + }while(!channel_map[ch]); +#else + }while(!ieee->channel_map[ch]); +#endif + /* this fuction can be called in two situations + * 1- We have switched to ad-hoc mode and we are + * performing a complete syncro scan before conclude + * there are no interesting cell and to create a + * new one. In this case the link state is + * IEEE80211_NOLINK until we found an interesting cell. + * If so the ieee8021_new_net, called by the RX path + * will set the state to IEEE80211_LINKED, so we stop + * scanning + * 2- We are linked and the root uses run iwlist scan. + * So we switch to IEEE80211_LINKED_SCANNING to remember + * that we are still logically linked (not interested in + * new network events, despite for updating the net list, + * but we are temporarly 'unlinked' as the driver shall + * not filter RX frames and the channel is changing. + * So the only situation in witch are interested is to check + * if the state become LINKED because of the #1 situation + */ + + if (ieee->state == IEEE80211_LINKED) + goto out; + + ieee->set_chan(ieee->dev, ch); +// printk("=====>channel=%d ",ch); +#ifdef ENABLE_DOT11D + if(channel_map[ch] == 1) +#endif + { +// printk("====send probe request\n"); + ieee80211_send_probe_requests(ieee); + } + /* this prevent excessive time wait when we + * need to wait for a syncro scan to end.. + */ + if (ieee->sync_scan_hurryup) + goto out; + + + msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME); + + } +out: + ieee->sync_scan_hurryup = 0; + up(&ieee->scan_sem); +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); +#endif +} + +void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee) +{ + int ch; + unsigned int watch_dog = 0; +#ifdef ENABLE_DOT11D + u8 channel_map[MAX_CHANNEL_NUMBER+1]; + memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); +#endif + down(&ieee->scan_sem); + ch = ieee->current_network.channel; +// if(ieee->sync_scan_hurryup) +// { + +// printk("stop scan sync\n"); +// goto out; +// } +// printk("=======hh===============>ips scan\n"); + while(1) + { + /* this fuction can be called in two situations + * 1- We have switched to ad-hoc mode and we are + * performing a complete syncro scan before conclude + * there are no interesting cell and to create a + * new one. In this case the link state is + * IEEE80211_NOLINK until we found an interesting cell. + * If so the ieee8021_new_net, called by the RX path + * will set the state to IEEE80211_LINKED, so we stop + * scanning + * 2- We are linked and the root uses run iwlist scan. + * So we switch to IEEE80211_LINKED_SCANNING to remember + * that we are still logically linked (not interested in + * new network events, despite for updating the net list, + * but we are temporarly 'unlinked' as the driver shall + * not filter RX frames and the channel is changing. + * So the only situation in witch are interested is to check + * if the state become LINKED because of the #1 situation + */ + if (ieee->state == IEEE80211_LINKED) + { + goto out; + } +#ifdef ENABLE_DOT11D + if(channel_map[ieee->current_network.channel] > 0) +#endif + { + ieee->set_chan(ieee->dev, ieee->current_network.channel); +// printk("======>channel=%d ",ieee->current_network.channel); + } +#ifdef ENABLE_DOT11D + if(channel_map[ieee->current_network.channel] == 1) +#endif + { +// printk("====send probe request\n"); + ieee80211_send_probe_requests(ieee); + } + /* this prevent excessive time wait when we + * need to wait for a syncro scan to end.. + */ +// if (ieee->sync_scan_hurryup) +// goto out; + + msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME); + + do{ + if (watch_dog++ >= MAX_CHANNEL_NUMBER) + // if (++watch_dog >= 15);//MAX_CHANNEL_NUMBER) //YJ,modified,080630 + goto out; /* scan completed */ + + ieee->current_network.channel = (ieee->current_network.channel + 1)%MAX_CHANNEL_NUMBER; +#ifdef ENABLE_DOT11D + }while(!channel_map[ieee->current_network.channel]); +#else + }while(!ieee->channel_map[ieee->current_network.channel]); +#endif + } +out: + //ieee->sync_scan_hurryup = 0; + //ieee->set_chan(ieee->dev, ch); + //ieee->current_network.channel = ch; + ieee->actscanning = false; + up(&ieee->scan_sem); +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); +#endif +} + + +#if 0 +/* called both by wq with ieee->lock held */ +void ieee80211_softmac_scan(struct ieee80211_device *ieee) +{ + short watchdog = 0; + + do{ + ieee->current_network.channel = + (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; + if (watchdog++ > MAX_CHANNEL_NUMBER) + return; /* no good chans */ + + }while(!ieee->channel_map[ieee->current_network.channel]); + + + schedule_work(&ieee->softmac_scan_wq); +} +#endif +#ifdef ENABLE_IPS +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_softmac_scan_wq(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); +#else +void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) +{ +#endif + static short watchdog = 0; +#ifdef ENABLE_DOT11D + u8 channel_map[MAX_CHANNEL_NUMBER+1]; + memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); +#endif +// printk("ieee80211_softmac_scan_wq ENABLE_IPS\n"); +// printk("in %s\n",__FUNCTION__); + down(&ieee->scan_sem); + + do{ + ieee->current_network.channel = + (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; + if (watchdog++ > MAX_CHANNEL_NUMBER) + goto out; /* no good chans */ + +#ifdef ENABLE_DOT11D + }while(!channel_map[ieee->current_network.channel]); +#else + }while(!ieee->channel_map[ieee->current_network.channel]); +#endif + + //printk("current_network.channel:%d\n", ieee->current_network.channel); + if (ieee->scanning == 0 ) + { + printk("error out, scanning = 0\n"); + goto out; + } + ieee->set_chan(ieee->dev, ieee->current_network.channel); +#ifdef ENABLE_DOT11D + if(channel_map[ieee->current_network.channel] == 1) +#endif + ieee80211_send_probe_requests(ieee); + + queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); + up(&ieee->scan_sem); + return; +out: + ieee->actscanning = false; + watchdog = 0; + ieee->scanning = 0; + up(&ieee->scan_sem); + +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); +#endif + return; +} +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_softmac_scan_wq(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, softmac_scan_wq); +#else +void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) +{ +#endif + + short watchdog = 0; +#ifdef ENABLE_DOT11D + u8 channel_map[MAX_CHANNEL_NUMBER+1]; + memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); +#endif +// printk("enter scan wq,watchdog is %d\n",watchdog); + down(&ieee->scan_sem); + + do{ + ieee->current_network.channel = + (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; + if (watchdog++ > MAX_CHANNEL_NUMBER) + goto out; /* no good chans */ + +#ifdef ENABLE_DOT11D + }while(!channel_map[ieee->current_network.channel]); +#else + }while(!ieee->channel_map[ieee->current_network.channel]); +#endif + +// printk("current_network.channel:%d\n", ieee->current_network.channel); + if (ieee->scanning == 0 ) + { + printk("error out, scanning = 0\n"); + goto out; + } + ieee->set_chan(ieee->dev, ieee->current_network.channel); +#ifdef ENABLE_DOT11D + if(channel_map[ieee->current_network.channel] == 1) +#endif + ieee80211_send_probe_requests(ieee); + + queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); +out: + up(&ieee->scan_sem); +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); +#endif +} + +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +void ieee80211_softmac_scan_cb(unsigned long _dev) +{ + unsigned long flags; + struct ieee80211_device *ieee = (struct ieee80211_device *)_dev; + + spin_lock_irqsave(&ieee->lock, flags); + ieee80211_softmac_scan(ieee); + spin_unlock_irqrestore(&ieee->lock, flags); +} +#endif + + +void ieee80211_beacons_start(struct ieee80211_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock,flags); + + ieee->beacon_txing = 1; + ieee80211_send_beacon(ieee); + + spin_unlock_irqrestore(&ieee->beacon_lock,flags); +} + +void ieee80211_beacons_stop(struct ieee80211_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock,flags); + + ieee->beacon_txing = 0; + del_timer_sync(&ieee->beacon_timer); + + spin_unlock_irqrestore(&ieee->beacon_lock,flags); + +} + + +void ieee80211_stop_send_beacons(struct ieee80211_device *ieee) +{ + if(ieee->stop_send_beacons) + ieee->stop_send_beacons(ieee->dev); + if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) + ieee80211_beacons_stop(ieee); +} + + +void ieee80211_start_send_beacons(struct ieee80211_device *ieee) +{ + if(ieee->start_send_beacons) + ieee->start_send_beacons(ieee->dev); + if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS) + ieee80211_beacons_start(ieee); +} + + +void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) +{ +// unsigned long flags; + + //ieee->sync_scan_hurryup = 1; + + down(&ieee->scan_sem); +// spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->scanning == 1){ + ieee->scanning = 0; + //del_timer_sync(&ieee->scan_timer); + cancel_delayed_work(&ieee->softmac_scan_wq); + } + +// spin_unlock_irqrestore(&ieee->lock, flags); + up(&ieee->scan_sem); +} + +void ieee80211_stop_scan(struct ieee80211_device *ieee) +{ + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) + ieee80211_softmac_stop_scan(ieee); + else + ieee->stop_scan(ieee->dev); +} + +/* called with ieee->lock held */ +void ieee80211_start_scan(struct ieee80211_device *ieee) +{ +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee) ) + { + if(IS_COUNTRY_IE_VALID(ieee)) + { + RESET_CIE_WATCHDOG(ieee); + } + } +#endif + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ + if (ieee->scanning == 0) + { + ieee->scanning = 1; + //ieee80211_softmac_scan(ieee); + // queue_work(ieee->wq, &ieee->softmac_scan_wq); + //care this,1203,2007,by lawrence +#if 1 + queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq,0); +#endif + } + }else + ieee->start_scan(ieee->dev); + +} + +/* called with wx_sem held */ +void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) +{ +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee) ) + { + if(IS_COUNTRY_IE_VALID(ieee)) + { + RESET_CIE_WATCHDOG(ieee); + } + } +#endif + ieee->sync_scan_hurryup = 0; + + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) + ieee80211_softmac_scan_syncro(ieee); + else + ieee->scan_syncro(ieee->dev); + +} + +inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *beacon, + struct ieee80211_device *ieee, int challengelen) +{ + struct sk_buff *skb; + struct ieee80211_authentication *auth; + + skb = dev_alloc_skb(sizeof(struct ieee80211_authentication) + challengelen); + + if (!skb) return NULL; + + auth = (struct ieee80211_authentication *) + skb_put(skb, sizeof(struct ieee80211_authentication)); + + auth->header.frame_ctl = IEEE80211_STYPE_AUTH; + if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP; + + auth->header.duration_id = 0x013a; //FIXME + + memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); + + auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; + + auth->transaction = cpu_to_le16(ieee->associate_seq); + ieee->associate_seq++; + + auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); + + return skb; + +} + +static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest) +{ + u8 *tag; + int beacon_size; + struct ieee80211_probe_response *beacon_buf; + struct sk_buff *skb; + int encrypt; + int atim_len,erp_len; + struct ieee80211_crypt_data* crypt; + + char *ssid = ieee->current_network.ssid; + int ssid_len = ieee->current_network.ssid_len; + int rate_len = ieee->current_network.rates_len+2; + int rate_ex_len = ieee->current_network.rates_ex_len; + int wpa_ie_len = ieee->wpa_ie_len; + if(rate_ex_len > 0) rate_ex_len+=2; + + if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) + atim_len = 4; + else + atim_len = 0; + + if(ieee80211_is_54g(ieee->current_network)) + erp_len = 3; + else + erp_len = 0; + + beacon_size = sizeof(struct ieee80211_probe_response)+ + ssid_len + +3 //channel + +rate_len + +rate_ex_len + +atim_len + +wpa_ie_len + +erp_len; + + skb = dev_alloc_skb(beacon_size); + + if (!skb) + return NULL; + + beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size); + + memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); + memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); + + beacon_buf->header.duration_id = 0; //FIXME + beacon_buf->beacon_interval = + cpu_to_le16(ieee->current_network.beacon_interval); + beacon_buf->capability = + cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); + + if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) + cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); + + crypt = ieee->crypt[ieee->tx_keyidx]; + + encrypt = ieee->host_encrypt && crypt && crypt->ops && + ((0 == strcmp(crypt->ops->name, "WEP")) || wpa_ie_len); + + if (encrypt) + beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + + beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); + + beacon_buf->info_element.id = MFIE_TYPE_SSID; + beacon_buf->info_element.len = ssid_len; + + tag = (u8*) beacon_buf->info_element.data; + + memcpy(tag, ssid, ssid_len); + + tag += ssid_len; + + *(tag++) = MFIE_TYPE_RATES; + *(tag++) = rate_len-2; + memcpy(tag,ieee->current_network.rates,rate_len-2); + tag+=rate_len-2; + + *(tag++) = MFIE_TYPE_DS_SET; + *(tag++) = 1; + *(tag++) = ieee->current_network.channel; + + if(atim_len){ + *(tag++) = MFIE_TYPE_IBSS_SET; + *(tag++) = 2; + *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); + tag+=2; + } + + if(erp_len){ + *(tag++) = MFIE_TYPE_ERP; + *(tag++) = 1; + *(tag++) = 0; + } + + if(rate_ex_len){ + *(tag++) = MFIE_TYPE_RATES_EX; + *(tag++) = rate_ex_len-2; + memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); + tag+=rate_ex_len-2; + } + + if (wpa_ie_len) + { + if (ieee->iw_mode == IW_MODE_ADHOC) + {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07 + memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); + } + + memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + } + + skb->dev = ieee->dev; + return skb; +} +#ifdef _RTL8187_EXT_PATCH_ +struct sk_buff* ieee80211_ext_probe_resp_by_net(struct ieee80211_device *ieee, u8 *dest, struct ieee80211_network *net) +{ + u8 *tag; + int beacon_size; + struct ieee80211_probe_response *beacon_buf; + struct sk_buff *skb; + int encrypt; + int atim_len,erp_len; + struct ieee80211_crypt_data* crypt; + u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; + int wpa_ie_len = ieee->wpa_ie_len; + char *ssid = net->ssid; + int ssid_len = net->ssid_len; + + int rate_len = ieee->current_network.rates_len+2; + int rate_ex_len = ieee->current_network.rates_ex_len; + if(rate_ex_len > 0) rate_ex_len+=2; + + if( ieee->meshScanMode&4) + ieee->current_network.channel = ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee); + if( ieee->meshScanMode&6) + { + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->ext_stop_scan_wq); +#else + schedule_task(&ieee->ext_stop_scan_wq); +#endif + } + if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) // use current_network here + atim_len = 4; + else + atim_len = 0; + + if(ieee80211_is_54g(*net)) + erp_len = 3; + else + erp_len = 0; + + beacon_size = sizeof(struct ieee80211_probe_response)+ + ssid_len + +3 //channel + +rate_len + +rate_ex_len + +atim_len + +erp_len; +//b + skb = dev_alloc_skb(beacon_size+196); + + if (!skb) + return NULL; + + beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size); + + memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); + memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); + + beacon_buf->header.duration_id = 0; //FIXME + + beacon_buf->beacon_interval = + cpu_to_le16(ieee->current_network.beacon_interval); // use current_network here + beacon_buf->capability = + cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); + + if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) + cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); + + crypt = ieee->crypt[ieee->tx_keyidx]; + + encrypt = ieee->host_encrypt && crypt && crypt->ops && + ((0 == strcmp(crypt->ops->name, "WEP"))||wpa_ie_len); + + if (encrypt) + beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + + beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); + + beacon_buf->info_element.id = MFIE_TYPE_SSID; + beacon_buf->info_element.len = ssid_len; + + tag = (u8*) beacon_buf->info_element.data; + + // brocad cast / probe rsp + if(memcmp(dest, broadcast_addr, ETH_ALEN )) + memcpy(tag, ssid, ssid_len); + else + ssid_len=0; + + tag += ssid_len; + +//get_bssrate_set(priv, _SUPPORTEDRATES_IE_, &pbssrate, &bssrate_len); +//pbuf = set_ie(pbuf, _SUPPORTEDRATES_IE_, bssrate_len, pbssrate, &frlen); + + *(tag++) = MFIE_TYPE_RATES; + *(tag++) = rate_len-2; + memcpy(tag,ieee->current_network.rates,rate_len-2); + tag+=rate_len-2; + + *(tag++) = MFIE_TYPE_DS_SET; + *(tag++) = 1; + *(tag++) = ieee->current_network.channel; // use current_network here + + + if(atim_len){ + *(tag++) = MFIE_TYPE_IBSS_SET; + *(tag++) = 2; + *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); // use current_network here + tag+=2; + } + + if(erp_len){ + *(tag++) = MFIE_TYPE_ERP; + *(tag++) = 1; + *(tag++) = 0; + } + + if(rate_ex_len){ + *(tag++) = MFIE_TYPE_RATES_EX; + *(tag++) = rate_ex_len-2; + memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); + tag+=rate_ex_len-2; + } + if (wpa_ie_len) + memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + + skb->dev = ieee->dev; + return skb; +} +#endif // _RTL8187_EXT_PATCH_ + +struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) +{ + struct sk_buff *skb; + u8* tag; + + struct ieee80211_crypt_data* crypt; + struct ieee80211_assoc_response_frame *assoc; + short encrypt; + + unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); + int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len; + + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + assoc = (struct ieee80211_assoc_response_frame *) + skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); + + assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); + memcpy(assoc->header.addr1, dest,ETH_ALEN); + memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); + memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? + WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); + + + if(ieee->short_slot) + assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); + + if (ieee->host_encrypt) + crypt = ieee->crypt[ieee->tx_keyidx]; + else crypt = NULL; + + encrypt = ( crypt && crypt->ops); + + if (encrypt) + assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + assoc->status = 0; + assoc->aid = cpu_to_le16(ieee->assoc_id); + if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; + else ieee->assoc_id++; + + tag = (u8*) skb_put(skb, rate_len); + + ieee80211_MFIE_Brate(ieee, &tag); + ieee80211_MFIE_Grate(ieee, &tag); + + return skb; +} + +struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest) +{ + struct sk_buff *skb; + struct ieee80211_authentication *auth; + + skb = dev_alloc_skb(sizeof(struct ieee80211_authentication)+1); + + if (!skb) + return NULL; + + skb->len = sizeof(struct ieee80211_authentication); + + auth = (struct ieee80211_authentication *)skb->data; + + auth->status = cpu_to_le16(status); + auth->transaction = cpu_to_le16(2); + auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); + +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode) + memcpy(auth->header.addr3, dest, ETH_ALEN); +#else + memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); +#endif + memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr1, dest, ETH_ALEN); + auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH); + return skb; + + +} + +struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) +{ + struct sk_buff *skb; + struct ieee80211_hdr_3addr* hdr; + + skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr)); + + if (!skb) + return NULL; + + hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr)); + + memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); + memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); + + hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | + (pwr ? IEEE80211_FCTL_PM:0)); + + return skb; + + +} + + +void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest) +{ + struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest); + + if (buf){ + softmac_mgmt_xmit(buf, ieee); + dev_kfree_skb_any(buf);//edit by thomas + } +} + + +void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8* dest) +{ + struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest); + + if (buf){ + softmac_mgmt_xmit(buf, ieee); + dev_kfree_skb_any(buf);//edit by thomas + } +} + + +void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest) +{ + + struct sk_buff *buf = ieee80211_probe_resp(ieee, dest); + + if (buf) { + softmac_mgmt_xmit(buf, ieee); + dev_kfree_skb_any(buf);//edit by thomas + } +} + + +inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + //unsigned long flags; + + struct ieee80211_assoc_request_frame *hdr; + u8 *tag; + //short info_addr = 0; + //int i; + //u16 suite_count = 0; + //u8 suit_select = 0; + unsigned int wpa_len = beacon->wpa_ie_len; + //struct net_device *dev = ieee->dev; + //union iwreq_data wrqu; + //u8 *buff; + //u8 *p; +#if 1 + // for testing purpose + unsigned int rsn_len = beacon->rsn_ie_len; +#else + unsigned int rsn_len = beacon->rsn_ie_len - 4; +#endif + unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); + unsigned int wmm_info_len = beacon->QoS_Enable?9:0; +#ifdef THOMAS_TURBO + unsigned int turbo_info_len = beacon->Turbo_Enable?9:0; +#endif + + u8 encry_proto = ieee->wpax_type_notify & 0xff; + //u8 pairwise_type = (ieee->wpax_type_notify >> 8) & 0xff; + //u8 authen_type = (ieee->wpax_type_notify >> 16) & 0xff; + + int len = 0; + + //[0] Notify type of encryption: WPA/WPA2 + //[1] pair wise type + //[2] authen type + if(ieee->wpax_type_set) { + if (IEEE_PROTO_WPA == encry_proto) { + rsn_len = 0; + } else if (IEEE_PROTO_RSN == encry_proto) { + wpa_len = 0; + } + } +#ifdef THOMAS_TURBO + len = sizeof(struct ieee80211_assoc_request_frame)+ + + beacon->ssid_len//essid tagged val + + rate_len//rates tagged val + + wpa_len + + rsn_len + + wmm_info_len + + turbo_info_len; +#else + len = sizeof(struct ieee80211_assoc_request_frame)+ + + beacon->ssid_len//essid tagged val + + rate_len//rates tagged val + + wpa_len + + rsn_len + + wmm_info_len; +#endif + +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode) + skb = dev_alloc_skb(len+256); // stanley + else +#endif + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + hdr = (struct ieee80211_assoc_request_frame *) + skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); + + + hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; + hdr->header.duration_id= 37; //FIXME + memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); + memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John + + hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS); + if (beacon->capability & WLAN_CAPABILITY_PRIVACY ) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); + + if(ieee->short_slot) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); + +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_1) + ieee->ext_patch_ieee80211_association_req_1(hdr); +#endif + + hdr->listen_interval = 0xa; //FIXME + + hdr->info_element.id = MFIE_TYPE_SSID; + + hdr->info_element.len = beacon->ssid_len; + tag = skb_put(skb, beacon->ssid_len); + memcpy(tag, beacon->ssid, beacon->ssid_len); + + tag = skb_put(skb, rate_len); + + ieee80211_MFIE_Brate(ieee, &tag); + ieee80211_MFIE_Grate(ieee, &tag); + + //add rsn==0 condition for ap's mix security mode(wpa+wpa2), john2007.8.9 + //choose AES encryption as default algorithm while using mixed mode +#if 0 + if(rsn_len == 0){ + + tag = skb_put(skb,wpa_len); + + if(wpa_len) { + + + //{add by david. 2006.8.31 + //fix linksys compatibility bug + //} + if(wpa_len > 24) {//22+2, mean include the capability + beacon->wpa_ie[wpa_len - 2] = 0; + } + //multicast cipher OUI + if( beacon->wpa_ie[11]==0x2 ){ //0x0050f202 is the oui of tkip + ieee->broadcast_key_type = KEY_TYPE_TKIP; + } + else if( beacon->wpa_ie[11]==0x4 ){//0x0050f204 is the oui of ccmp + ieee->broadcast_key_type = KEY_TYPE_CCMP; + } + //unicast cipher OUI + if( beacon->wpa_ie[14]==0 + && beacon->wpa_ie[15]==0x50 + && beacon->wpa_ie[16]==0xf2 + && beacon->wpa_ie[17]==0x2 ){ //0x0050f202 is the oui of tkip + ieee->pairwise_key_type = KEY_TYPE_TKIP; + } + + else if( beacon->wpa_ie[14]==0 + && beacon->wpa_ie[15]==0x50 + && beacon->wpa_ie[16]==0xf2 + && beacon->wpa_ie[17]==0x4 ){//0x0050f204 is the oui of ccmp + ieee->pairwise_key_type = KEY_TYPE_CCMP; + } + //indicate the wpa_ie content to WPA_SUPPLICANT + buff = kmalloc(IW_CUSTOM_MAX, GFP_ATOMIC); + memset(buff, 0, IW_CUSTOM_MAX); + p=buff; + p += sprintf(p, "ASSOCINFO(ReqIEs="); + for(i=0;i<wpa_len;i++){ + p += sprintf(p, "%02x", beacon->wpa_ie[i]); + } + p += sprintf(p, ")"); + memset(&wrqu, 0, sizeof(wrqu) ); + wrqu.data.length = p - buff; + + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buff); + memcpy(tag,beacon->wpa_ie,wpa_len); + } + + } + + if(rsn_len > 22) { + + if( beacon->rsn_ie[4]==0x0 && + beacon->rsn_ie[5]==0xf && + beacon->rsn_ie[6]==0xac){ + + switch(beacon->rsn_ie[7]){ + case 0x1: + ieee->broadcast_key_type = KEY_TYPE_WEP40; + break; + case 0x2: + ieee->broadcast_key_type = KEY_TYPE_TKIP; + break; + case 0x4: + ieee->broadcast_key_type = KEY_TYPE_CCMP; + break; + case 0x5: + ieee->broadcast_key_type = KEY_TYPE_WEP104; + break; + default: + printk("fault suite type in RSN broadcast key\n"); + break; + } + } + + if( beacon->rsn_ie[10]==0x0 && + beacon->rsn_ie[11]==0xf && + beacon->rsn_ie[12]==0xac){ + if(beacon->rsn_ie[8]==1){//not mixed mode + switch(beacon->rsn_ie[13]){ + case 0x2: + ieee->pairwise_key_type = KEY_TYPE_TKIP; + break; + case 0x4: + ieee->pairwise_key_type = KEY_TYPE_CCMP; + break; + default: + printk("fault suite type in RSN pairwise key\n"); + break; + } + } + else if(beacon->rsn_ie[8]==2){//mixed mode + ieee->pairwise_key_type = KEY_TYPE_CCMP; + } + } + + + + tag = skb_put(skb,22); + memcpy(tag,(beacon->rsn_ie + info_addr),8); + tag[1] = 20; + tag += 8; + info_addr += 8; + + spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); + for (i = 0; i < 2; i++) { + tag[0] = 1; + tag[1] = 0; + tag += 2; + suite_count = beacon->rsn_ie[info_addr] + \ + (beacon->rsn_ie[info_addr + 1] << 8); + info_addr += 2; + if(1 == suite_count) { + memcpy(tag,(beacon->rsn_ie + info_addr),4); + info_addr += 4; + } else { + // if the wpax_type_notify has been set by the application, + // just use it, otherwise just use the default one. + if(ieee->wpax_type_set) { + suit_select = ((0 == i) ? pairwise_type:authen_type)&0x0f ; + memcpy(tag,rsn_authen_cipher_suite[suit_select],4); + } else { + //default set as ccmp, or none authentication + if(i == 0) { + memcpy(tag,rsn_authen_cipher_suite[4],4); + } else { + memcpy(tag,rsn_authen_cipher_suite[2],4); + } + + } + + info_addr += (suite_count * 4); + } + tag += 4; + } + spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); + + tag[0] = 0; + tag[1] = beacon->rsn_ie[info_addr+1]; + + } else { + tag = skb_put(skb,rsn_len); + if(rsn_len) { + + + if( beacon->rsn_ie[4]==0x0 && + beacon->rsn_ie[5]==0xf && + beacon->rsn_ie[6]==0xac){ + switch(beacon->rsn_ie[7]){ + case 0x1: + ieee->broadcast_key_type = KEY_TYPE_WEP40; + break; + case 0x2: + ieee->broadcast_key_type = KEY_TYPE_TKIP; + break; + case 0x4: + ieee->broadcast_key_type = KEY_TYPE_CCMP; + break; + case 0x5: + ieee->broadcast_key_type = KEY_TYPE_WEP104; + break; + default: + printk("fault suite type in RSN broadcast key\n"); + break; + } + } + if( beacon->rsn_ie[10]==0x0 && + beacon->rsn_ie[11]==0xf && + beacon->rsn_ie[12]==0xac){ + if(beacon->rsn_ie[8]==1){//not mixed mode + switch(beacon->rsn_ie[13]){ + case 0x2: + ieee->pairwise_key_type = KEY_TYPE_TKIP; + break; + case 0x4: + ieee->pairwise_key_type = KEY_TYPE_CCMP; + break; + default: + printk("fault suite type in RSN pairwise key\n"); + break; + } + + } + else if(beacon->rsn_ie[8]==2){//mixed mode + ieee->pairwise_key_type = KEY_TYPE_CCMP; + } + } + + + beacon->rsn_ie[rsn_len - 2] = 0; + memcpy(tag,beacon->rsn_ie,rsn_len); + } + } +#else + tag = skb_put(skb,ieee->wpa_ie_len); + memcpy(tag,ieee->wpa_ie,ieee->wpa_ie_len); +#endif + tag = skb_put(skb,wmm_info_len); + if(wmm_info_len) { + ieee80211_WMM_Info(ieee, &tag); + } +#ifdef THOMAS_TURBO + tag = skb_put(skb,turbo_info_len); + if(turbo_info_len) { + ieee80211_TURBO_Info(ieee, &tag); + } +#endif + +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_2) + ieee->ext_patch_ieee80211_association_req_2(ieee, beacon, skb); +#endif + + return skb; +} + +void ieee80211_associate_abort(struct ieee80211_device *ieee) +{ + + unsigned long flags; + spin_lock_irqsave(&ieee->lock, flags); + + ieee->associate_seq++; + + /* don't scan, and avoid to have the RX path possibily + * try again to associate. Even do not react to AUTH or + * ASSOC response. Just wait for the retry wq to be scheduled. + * Here we will check if there are good nets to associate + * with, so we retry or just get back to NO_LINK and scanning + */ + if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){ + IEEE80211_DEBUG_MGMT("Authentication failed\n"); + ieee->softmac_stats.no_auth_rs++; + }else{ + IEEE80211_DEBUG_MGMT("Association failed\n"); + ieee->softmac_stats.no_ass_rs++; + } + + ieee->state = IEEE80211_ASSOCIATING_RETRY; + + queue_delayed_work(ieee->wq, &ieee->associate_retry_wq,IEEE80211_SOFTMAC_ASSOC_RETRY_TIME); + + spin_unlock_irqrestore(&ieee->lock, flags); +} + +void ieee80211_associate_abort_cb(unsigned long dev) +{ + ieee80211_associate_abort((struct ieee80211_device *) dev); +} + + +void ieee80211_associate_step1(struct ieee80211_device *ieee) +{ + struct ieee80211_network *beacon = &ieee->current_network; + struct sk_buff *skb; + + IEEE80211_DEBUG_MGMT("Stopping scan\n"); + ieee->softmac_stats.tx_auth_rq++; + skb=ieee80211_authentication_req(beacon, ieee, 0); +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->iw_mode == ieee->iw_ext_mode ) { + if(skb) + softmac_mgmt_xmit(skb, ieee); + return; + }else +#endif + if (!skb){ + + ieee80211_associate_abort(ieee); + } + else{ + ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ; + IEEE80211_DEBUG_MGMT("Sending authentication request\n"); + //printk("---Sending authentication request\n"); + softmac_mgmt_xmit(skb, ieee); + //BUGON when you try to add_timer twice, using mod_timer may be better, john0709 + if(!timer_pending(&ieee->associate_timer)){ + ieee->associate_timer.expires = jiffies + (HZ / 2); + add_timer(&ieee->associate_timer); + } + //If call dev_kfree_skb_any,a warning will ocur.... + //KERNEL: assertion (!atomic_read(&skb->users)) failed at net/core/dev.c (1708) + //So ... 1204 by lawrence. + //printk("\nIn %s,line %d call kfree skb.",__FUNCTION__,__LINE__); + //dev_kfree_skb_any(skb);//edit by thomas + } +} + +void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) +{ + u8 *c; + struct sk_buff *skb; + struct ieee80211_network *beacon = &ieee->current_network; +// int hlen = sizeof(struct ieee80211_authentication); + del_timer_sync(&ieee->associate_timer); + ieee->associate_seq++; + ieee->softmac_stats.tx_auth_rq++; + + skb = ieee80211_authentication_req(beacon, ieee, chlen+2); + if (!skb) + ieee80211_associate_abort(ieee); + else{ + c = skb_put(skb, chlen+2); + *(c++) = MFIE_TYPE_CHALLENGE; + *(c++) = chlen; + memcpy(c, challenge, chlen); + + IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n"); + + ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr )); + + softmac_mgmt_xmit(skb, ieee); + if (!timer_pending(&ieee->associate_timer)){ + //printk("=========>add timer again, to crash\n"); + ieee->associate_timer.expires = jiffies + (HZ / 2); + add_timer(&ieee->associate_timer); + } + dev_kfree_skb_any(skb);//edit by thomas + } + kfree(challenge); +} + +#ifdef _RTL8187_EXT_PATCH_ + +// based on ieee80211_assoc_resp +struct sk_buff* ieee80211_assoc_resp_by_net(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type) +{ + struct sk_buff *skb; + u8* tag; + + struct ieee80211_crypt_data* crypt; + struct ieee80211_assoc_response_frame *assoc; + short encrypt; + + unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); + int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len; + + if(ieee->iw_mode == ieee->iw_ext_mode) + skb = dev_alloc_skb(len+256); // stanley + else + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + assoc = (struct ieee80211_assoc_response_frame *) + skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); + + assoc->header.frame_ctl = cpu_to_le16(pkt_type); + + memcpy(assoc->header.addr1, dest,ETH_ALEN); + memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); + memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? + WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); + + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_1) + ieee->ext_patch_ieee80211_assoc_resp_by_net_1(assoc); + + if(ieee->short_slot) + assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); + + if (ieee->host_encrypt) + crypt = ieee->crypt[ieee->tx_keyidx]; + else crypt = NULL; + + encrypt = ( crypt && crypt->ops); + + if (encrypt) + assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + assoc->status = 0; + assoc->aid = cpu_to_le16(ieee->assoc_id); + if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; + else ieee->assoc_id++; + + assoc->info_element.id = 230; // Stanley, an unused id (just a hot fix) + assoc->info_element.len = 0; + + tag = (u8*) skb_put(skb, rate_len); + + ieee80211_MFIE_Brate(ieee, &tag); + ieee80211_MFIE_Grate(ieee, &tag); + + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_2) + ieee->ext_patch_ieee80211_assoc_resp_by_net_2(ieee, pstat, pkt_type, skb); + + return skb; +} + +// based on ieee80211_resp_to_assoc_rq +void ieee80211_ext_issue_assoc_rsp(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type) +{ + struct sk_buff *buf = ieee80211_assoc_resp_by_net(ieee, dest, status, pstat, pkt_type); + + if (buf) + softmac_mgmt_xmit(buf, ieee); +} + +// based on ieee80211_associate_step2 +void ieee80211_ext_issue_assoc_req(struct ieee80211_device *ieee, struct ieee80211_network *pstat) +{ + + struct sk_buff* skb; + + // printk("@@@@@ ieee80211_ext_issue_assoc_req on channel: %d\n", ieee->current_network.channel); + + ieee->softmac_stats.tx_ass_rq++; + skb=ieee80211_association_req(pstat, ieee); + if (skb) + softmac_mgmt_xmit(skb, ieee); +} + +void ieee80211_ext_issue_disassoc(struct ieee80211_device *ieee, struct ieee80211_network *pstat, int reason, unsigned char extReason) +{ + // do nothing + // printk("@@@@@ ieee80211_ext_issue_disassoc\n"); + return; +} +#endif // _RTL8187_EXT_PATCH_ + +void ieee80211_associate_step2(struct ieee80211_device *ieee) +{ + struct sk_buff* skb; + struct ieee80211_network *beacon = &ieee->current_network; + + del_timer_sync(&ieee->associate_timer); + + IEEE80211_DEBUG_MGMT("Sending association request\n"); + ieee->softmac_stats.tx_ass_rq++; + skb=ieee80211_association_req(beacon, ieee); + if (!skb) + ieee80211_associate_abort(ieee); + else{ + softmac_mgmt_xmit(skb, ieee); + if (!timer_pending(&ieee->associate_timer)){ + ieee->associate_timer.expires = jiffies + (HZ / 2); + add_timer(&ieee->associate_timer); + } + //dev_kfree_skb_any(skb);//edit by thomas + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_associate_complete_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq); +#else +void ieee80211_associate_complete_wq(struct ieee80211_device *ieee) +{ +#endif + printk(KERN_INFO "Associated successfully\n"); + if(ieee80211_is_54g(ieee->current_network) && + (ieee->modulation & IEEE80211_OFDM_MODULATION)){ + + ieee->rate = 540; + printk(KERN_INFO"Using G rates\n"); + }else{ + ieee->rate = 110; + printk(KERN_INFO"Using B rates\n"); + } + ieee->link_change(ieee->dev); + notify_wx_assoc_event(ieee); + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + netif_carrier_on(ieee->dev); +} + +void ieee80211_associate_complete(struct ieee80211_device *ieee) +{ + int i; + del_timer_sync(&ieee->associate_timer); + + for(i = 0; i < 6; i++) { + //ieee->seq_ctrl[i] = 0; + } + ieee->state = IEEE80211_LINKED; + IEEE80211_DEBUG_MGMT("Successfully associated\n"); + + queue_work(ieee->wq, &ieee->associate_complete_wq); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_associate_procedure_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq); +#else +void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee) +{ +#endif + ieee->sync_scan_hurryup = 1; + down(&ieee->wx_sem); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + + ieee80211_stop_scan(ieee); + ieee->set_chan(ieee->dev, ieee->current_network.channel); + + ieee->associate_seq = 1; + ieee80211_associate_step1(ieee); + + up(&ieee->wx_sem); +} +#ifdef _RTL8187_EXT_PATCH_ +// based on ieee80211_associate_procedure_wq + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +void ieee80211_ext_stop_scan_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_stop_scan_wq); +#else +void ieee80211_ext_stop_scan_wq(struct ieee80211_device *ieee) +{ +#endif + if (ieee->scanning == 0) + { + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel + && ( ieee->current_network.channel == ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee) ) ) + return; + } + + ieee->sync_scan_hurryup = 1; + + down(&ieee->wx_sem); + + // printk("@@@@@@@@@@ ieee80211_ext_stop_scan_wq\n"); + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + + ieee80211_stop_scan(ieee); + + // set channel + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel) + ieee->set_chan(ieee->dev, ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee)); + else + ieee->set_chan(ieee->dev, ieee->current_network.channel); + // + up(&ieee->wx_sem); +} + + +void ieee80211_ext_send_11s_beacon(struct ieee80211_device *ieee) +{ + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->ext_send_beacon_wq); + #else + schedule_task(&ieee->ext_send_beacon_wq); + #endif + +} + +#endif // _RTL8187_EXT_PATCH_ + +inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net) +{ + u8 tmp_ssid[IW_ESSID_MAX_SIZE+1]; + int tmp_ssid_len = 0; + + short apset,ssidset,ssidbroad,apmatch,ssidmatch; + + /* we are interested in new new only if we are not associated + * and we are not associating / authenticating + */ + if (ieee->state != IEEE80211_NOLINK) + return; + + if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS)) + return; + + if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS)) + return; + + + if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){ + /* if the user specified the AP MAC, we need also the essid + * This could be obtained by beacons or, if the network does not + * broadcast it, it can be put manually. + */ + apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 ); + ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0'; + ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0'); + apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0); + + if(ieee->current_network.ssid_len != net->ssid_len) + ssidmatch = 0; + else + ssidmatch = (0==strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len)); + + //printk("cur: %s, %d, net:%s, %d\n", ieee->current_network.ssid, ieee->current_network.ssid_len, net->ssid, net->ssid_len); + //printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch); + + if ( /* if the user set the AP check if match. + * if the network does not broadcast essid we check the user supplyed ANY essid + * if the network does broadcast and the user does not set essid it is OK + * if the network does broadcast and the user did set essid chech if essid match + */ + ( apset && apmatch && + ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) || + /* if the ap is not set, check that the user set the bssid + * and the network does bradcast and that those two bssid matches + */ + (!apset && ssidset && ssidbroad && ssidmatch) + ){ + + + /* if the essid is hidden replace it with the + * essid provided by the user. + */ + if (!ssidbroad){ + strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE); + tmp_ssid_len = ieee->current_network.ssid_len; + } + memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network)); + + if (!ssidbroad){ + strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE); + ieee->current_network.ssid_len = tmp_ssid_len; + } + printk(KERN_INFO"Linking with %s: channel is %d\n",ieee->current_network.ssid,ieee->current_network.channel); + + if (ieee->iw_mode == IW_MODE_INFRA){ + ieee->state = IEEE80211_ASSOCIATING; + ieee->beinretry = false; + queue_work(ieee->wq, &ieee->associate_procedure_wq); + }else{ + if(ieee80211_is_54g(ieee->current_network) && + (ieee->modulation & IEEE80211_OFDM_MODULATION)){ + ieee->rate = 540; + printk(KERN_INFO"Using G rates\n"); + }else{ + ieee->rate = 110; + printk(KERN_INFO"Using B rates\n"); + } + ieee->state = IEEE80211_LINKED; + ieee->beinretry = false; + } + + } + } + +} + +void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee) +{ + unsigned long flags; + struct ieee80211_network *target; + + spin_lock_irqsave(&ieee->lock, flags); + list_for_each_entry(target, &ieee->network_list, list) { + + /* if the state become different that NOLINK means + * we had found what we are searching for + */ + + if (ieee->state != IEEE80211_NOLINK) + break; + + if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies)) + ieee80211_softmac_new_net(ieee, target); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + +} + + +static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen) +{ + struct ieee80211_authentication *a; + u8 *t; + if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ + IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len); + return 0xcafe; + } + *challenge = NULL; + a = (struct ieee80211_authentication*) skb->data; + if(skb->len > (sizeof(struct ieee80211_authentication) +3)){ + t = skb->data + sizeof(struct ieee80211_authentication); + + if(*(t++) == MFIE_TYPE_CHALLENGE){ + *chlen = *(t++); + *challenge = (u8*)kmalloc(*chlen, GFP_ATOMIC); + memcpy(*challenge, t, *chlen); + } + } + + return cpu_to_le16(a->status); + +} + + +int auth_rq_parse(struct sk_buff *skb,u8* dest) +{ + struct ieee80211_authentication *a; + + if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ + IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len); + return -1; + } + a = (struct ieee80211_authentication*) skb->data; + + memcpy(dest,a->header.addr2, ETH_ALEN); + + if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) + return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; + + return WLAN_STATUS_SUCCESS; +} + +static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src) +{ + u8 *tag; + u8 *skbend; + u8 *ssid=NULL; + u8 ssidlen = 0; + + struct ieee80211_hdr_3addr *header = + (struct ieee80211_hdr_3addr *) skb->data; + + if (skb->len < sizeof (struct ieee80211_hdr_3addr )) + return -1; /* corrupted */ + + memcpy(src,header->addr2, ETH_ALEN); + + skbend = (u8*)skb->data + skb->len; + + tag = skb->data + sizeof (struct ieee80211_hdr_3addr ); + + while (tag+1 < skbend){ + if (*tag == 0){ + ssid = tag+2; + ssidlen = *(tag+1); + break; + } + tag++; /* point to the len field */ + tag = tag + *(tag); /* point to the last data byte of the tag */ + tag++; /* point to the next tag */ + } + + //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src)); + if (ssidlen == 0) return 1; + + if (!ssid) return 1; /* ssid not found in tagged param */ + return (!strncmp(ssid, ieee->current_network.ssid, ssidlen)); + +} + +int assoc_rq_parse(struct sk_buff *skb,u8* dest) +{ + struct ieee80211_assoc_request_frame *a; + + if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) - + sizeof(struct ieee80211_info_element))) { + + IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len); + return -1; + } + + a = (struct ieee80211_assoc_request_frame*) skb->data; + + memcpy(dest,a->header.addr2,ETH_ALEN); + + return 0; +} + +static inline u16 assoc_parse(struct sk_buff *skb, int *aid) +{ + struct ieee80211_assoc_response_frame *a; + if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){ + IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); + return 0xcafe; + } + + a = (struct ieee80211_assoc_response_frame*) skb->data; + *aid = le16_to_cpu(a->aid) & 0x3fff; + return le16_to_cpu(a->status); +} + +static inline void +ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + u8 dest[ETH_ALEN]; + + //IEEE80211DMESG("Rx probe"); + ieee->softmac_stats.rx_probe_rq++; + //DMESG("Dest is "MACSTR, MAC2STR(dest)); + if (probe_rq_parse(ieee, skb, dest)){ + //IEEE80211DMESG("Was for me!"); + ieee->softmac_stats.tx_probe_rs++; + ieee80211_resp_to_probe(ieee, dest); + } +} + +inline void +ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + u8 dest[ETH_ALEN]; + int status; + //IEEE80211DMESG("Rx probe"); + ieee->softmac_stats.rx_auth_rq++; + + if ((status = auth_rq_parse(skb, dest))!= -1){ + ieee80211_resp_to_auth(ieee, status, dest); + } + //DMESG("Dest is "MACSTR, MAC2STR(dest)); + +} + + inline void +ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + + u8 dest[ETH_ALEN]; + //unsigned long flags; + + ieee->softmac_stats.rx_ass_rq++; + if (assoc_rq_parse(skb,dest) != -1){ + ieee80211_resp_to_assoc_rq(ieee, dest); + } + + printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest)); + //FIXME + #if 0 + spin_lock_irqsave(&ieee->lock,flags); + add_associate(ieee,dest); + spin_unlock_irqrestore(&ieee->lock,flags); + #endif +} + + + +void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr) +{ + + struct sk_buff *buf = ieee80211_null_func(ieee, pwr); + + if (buf) + softmac_ps_mgmt_xmit(buf, ieee); + +} + + +short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l) +{ +#if 0 + int timeout = ieee->ps_timeout; +#else + int timeout = 0; +#endif + u8 dtim; + /*if(ieee->ps == IEEE80211_PS_DISABLED || + ieee->iw_mode != IW_MODE_INFRA || + ieee->state != IEEE80211_LINKED) + + return 0; + */ + dtim = ieee->current_network.dtim_data; + //printk("DTIM\n"); + + if(!(dtim & IEEE80211_DTIM_VALID)) + return 0; + else + timeout = ieee->current_network.beacon_interval; + + //printk("VALID\n"); + ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID; + + if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps)) + return 2; + + if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))) + return 0; + + if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))) + return 0; + + if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) && + (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) + return 0; +#if 0 + if(time_l){ + *time_l = ieee->current_network.last_dtim_sta_time[0] + + (ieee->current_network.beacon_interval + * ieee->current_network.dtim_period) * 1000; + } +#else + if(time_l){ + *time_l = ieee->current_network.last_dtim_sta_time[0] + + MSECS((ieee->current_network.beacon_interval)); + //* ieee->current_network.dtim_period)); + //printk("beacon_interval:%x, dtim_period:%x, totol to Msecs:%x, HZ:%x\n", ieee->current_network.beacon_interval, ieee->current_network.dtim_period, MSECS(((ieee->current_network.beacon_interval * ieee->current_network.dtim_period))), HZ); + } + +#endif + if(time_h){ + *time_h = ieee->current_network.last_dtim_sta_time[1]; + if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0]) + *time_h += 1; + } + + return 1; + + +} + +inline void ieee80211_sta_ps(struct ieee80211_device *ieee) +{ + + u32 th,tl; + short sleep; + + unsigned long flags,flags2; + + spin_lock_irqsave(&ieee->lock, flags); + + if((ieee->ps == IEEE80211_PS_DISABLED || + + ieee->iw_mode != IW_MODE_INFRA || + ieee->state != IEEE80211_LINKED)){ + + //#warning CHECK_LOCK_HERE + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + ieee80211_sta_wakeup(ieee, 1); + + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + + sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl); +// printk("===>%s,%d[2 wake, 1 sleep, 0 do nothing], ieee->sta_sleep = %d\n",__FUNCTION__, sleep,ieee->sta_sleep); + /* 2 wake, 1 sleep, 0 do nothing */ + if(sleep == 0) + goto out; + + if(sleep == 1){ + + if(ieee->sta_sleep == 1) + ieee->enter_sleep_state(ieee->dev,th,tl); + + else if(ieee->sta_sleep == 0){ + // printk("send null 1\n"); + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + if(ieee->ps_is_queue_empty(ieee->dev)){ + + + ieee->sta_sleep = 2; + + ieee->ps_request_tx_ack(ieee->dev); + + ieee80211_sta_ps_send_null_frame(ieee,1); + + ieee->ps_th = th; + ieee->ps_tl = tl; + } + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + + } + + + }else if(sleep == 2){ +//#warning CHECK_LOCK_HERE + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + // printk("send wakeup packet\n"); + ieee80211_sta_wakeup(ieee,1); + + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + +out: + spin_unlock_irqrestore(&ieee->lock, flags); + +} + +void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl) +{ + if(ieee->sta_sleep == 0){ + if(nl){ + // printk("Warning: driver is probably failing to report TX ps error\n"); + ieee->ps_request_tx_ack(ieee->dev); + ieee80211_sta_ps_send_null_frame(ieee, 0); + } + return; + + } + + if(ieee->sta_sleep == 1) + ieee->sta_wake_up(ieee->dev); + + ieee->sta_sleep = 0; + + if(nl){ + ieee->ps_request_tx_ack(ieee->dev); + ieee80211_sta_ps_send_null_frame(ieee, 0); + } +} + +void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success) +{ + unsigned long flags,flags2; + + spin_lock_irqsave(&ieee->lock, flags); + if(ieee->sta_sleep == 2){ + /* Null frame with PS bit set */ + if(success){ + + // printk("==================> %s::enter sleep state\n",__FUNCTION__); + ieee->sta_sleep = 1; + ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl); + } + /* if the card report not success we can't be sure the AP + * has not RXed so we can't assume the AP believe us awake + */ + } + /* 21112005 - tx again null without PS bit if lost */ + else { + + if((ieee->sta_sleep == 0) && !success){ + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + ieee80211_sta_ps_send_null_frame(ieee, 0); + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + } + spin_unlock_irqrestore(&ieee->lock, flags); +} + +inline int +ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype) +{ + struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data; + u16 errcode; + u8* challenge=NULL; + int chlen=0; + int aid=0; + struct ieee80211_assoc_response_frame *assoc_resp; + struct ieee80211_info_element *info_element; + + if(!ieee->proto_started) + return 0; + + if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && + ieee->iw_mode == IW_MODE_INFRA && + ieee->state == IEEE80211_LINKED)) + + tasklet_schedule(&ieee->ps_task); + + if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && + WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) + ieee->last_rx_ps_time = jiffies; + + switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { + + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + + IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED && + ieee->iw_mode == IW_MODE_INFRA){ + if (0 == (errcode=assoc_parse(skb, &aid))){ + u16 left; + + ieee->state=IEEE80211_LINKED; + ieee->assoc_id = aid; + ieee->softmac_stats.rx_ass_ok++; + + //printk(KERN_WARNING "nic_type = %s", (rx_stats->nic_type == 1)?"rtl8187":"rtl8187B"); + if(1 == rx_stats->nic_type) //card type is 8187 + { + goto associate_complete; + } + assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data; + info_element = &assoc_resp->info_element; + left = skb->len - ((void*)info_element - (void*)assoc_resp); + + while (left >= sizeof(struct ieee80211_info_element_hdr)) { + if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { + printk(KERN_WARNING "[re]associate reeponse error!"); + return 1; + } + switch (info_element->id) { + case MFIE_TYPE_GENERIC: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len); + if (info_element->len >= 8 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x02 && + info_element->data[4] == 0x01) { + // Not care about version at present. + //WMM Parameter Element + memcpy(ieee->current_network.wmm_param,(u8*)(info_element->data\ + + 8),(info_element->len - 8)); + + if (((ieee->current_network.wmm_info^info_element->data[6])& \ + 0x0f)||(!ieee->init_wmmparam_flag)) { + //refresh paramete element for current network + // update the register parameter for hardware + ieee->init_wmmparam_flag = 1; + queue_work(ieee->wq, &ieee->wmm_param_update_wq); + + } + //update info_element for current network + ieee->current_network.wmm_info = info_element->data[6]; + } + break; + default: + //nothing to do at present!!! + break; + } + + left -= sizeof(struct ieee80211_info_element_hdr) + + info_element->len; + info_element = (struct ieee80211_info_element *) + &info_element->data[info_element->len]; + } + if(!ieee->init_wmmparam_flag) //legacy AP, reset the AC_xx_param register + { + queue_work(ieee->wq,&ieee->wmm_param_update_wq); + ieee->init_wmmparam_flag = 1;//indicate AC_xx_param upated since last associate + } +associate_complete: + ieee80211_associate_complete(ieee); + }else{ + ieee->softmac_stats.rx_ass_err++; + IEEE80211_DEBUG_MGMT( + "Association response status code 0x%x\n", + errcode); + ieee80211_associate_abort(ieee); + } + } +#ifdef _RTL8187_EXT_PATCH_ + else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp) + { + ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp(ieee, skb); + } +#endif + break; + + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->iw_mode == IW_MODE_MASTER) + + ieee80211_rx_assoc_rq(ieee, skb); +#ifdef _RTL8187_EXT_PATCH_ + else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req) + { + ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req(ieee, skb); + } +#endif + break; + + case IEEE80211_STYPE_AUTH: + +#ifdef _RTL8187_EXT_PATCH_ +printk("IEEE80211_STYPE_AUTH\n"); + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth) + if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth(ieee, skb, rx_stats) ); +#endif + if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){ + if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING && + ieee->iw_mode == IW_MODE_INFRA){ + + IEEE80211_DEBUG_MGMT("Received authentication response"); + + if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){ + if(ieee->open_wep || !challenge){ + ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED; + ieee->softmac_stats.rx_auth_rs_ok++; + + ieee80211_associate_step2(ieee); + }else{ + ieee80211_auth_challenge(ieee, challenge, chlen); + } + }else{ + ieee->softmac_stats.rx_auth_rs_err++; + IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); + ieee80211_associate_abort(ieee); + } + + }else if (ieee->iw_mode == IW_MODE_MASTER){ + ieee80211_rx_auth_rq(ieee, skb); + } + } + break; + + case IEEE80211_STYPE_PROBE_REQ: + + if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) && + ((ieee->iw_mode == IW_MODE_ADHOC || + ieee->iw_mode == IW_MODE_MASTER) && + ieee->state == IEEE80211_LINKED)) + + ieee80211_rx_probe_rq(ieee, skb); + break; + + case IEEE80211_STYPE_DISASSOC: + case IEEE80211_STYPE_DEAUTH: +#ifdef _RTL8187_EXT_PATCH_ +printk("IEEE80211_STYPE_DEAUTH\n"); + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth) + if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth(ieee, skb, rx_stats) ) ; +#endif + /* FIXME for now repeat all the association procedure + * both for disassociation and deauthentication + */ + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + (ieee->state == IEEE80211_LINKED) && + (ieee->iw_mode == IW_MODE_INFRA) && + (!memcmp(header->addr2,ieee->current_network.bssid,ETH_ALEN))){ + ieee->state = IEEE80211_ASSOCIATING; + ieee->softmac_stats.reassoc++; + + //notify_wx_assoc_event(ieee); //YJ,del,080828, do not notify os here + queue_work(ieee->wq, &ieee->associate_procedure_wq); + } + + break; + + default: + return -1; + break; + } + + //dev_kfree_skb_any(skb); + return 0; +} + + + +/* following are for a simplier TX queue management. + * Instead of using netif_[stop/wake]_queue the driver + * will uses these two function (plus a reset one), that + * will internally uses the kernel netif_* and takes + * care of the ieee802.11 fragmentation. + * So the driver receives a fragment per time and might + * call the stop function when it want without take care + * to have enought room to TX an entire packet. + * This might be useful if each fragment need it's own + * descriptor, thus just keep a total free memory > than + * the max fragmentation treshold is not enought.. If the + * ieee802.11 stack passed a TXB struct then you needed + * to keep N free descriptors where + * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD + * In this way you need just one and the 802.11 stack + * will take care of buffering fragments and pass them to + * to the driver later, when it wakes the queue. + */ + +void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee) +{ + + + unsigned long flags; + int i; +#ifdef _RTL8187_EXT_PATCH_ + int rate = ieee->rate; +#endif + + spin_lock_irqsave(&ieee->lock,flags); + #if 0 + if(ieee->queue_stop){ + IEEE80211DMESG("EE: IEEE hard_start_xmit invoked when kernel queue should be stopped"); + netif_stop_queue(ieee->dev); + ieee->ieee_stats.swtxstop++; + //dev_kfree_skb_any(skb); + err = 1; + goto exit; + } + + ieee->stats.tx_bytes+=skb->len; + + + txb=ieee80211_skb_to_txb(ieee,skb); + + + if(txb==NULL){ + IEEE80211DMESG("WW: IEEE stack failed to provide txb"); + //dev_kfree_skb_any(skb); + err = 1; + goto exit; + } + #endif + +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_softmac_xmit_get_rate && txb->nr_frags) + { + rate = ieee->ext_patch_ieee80211_softmac_xmit_get_rate(ieee, txb->fragments[0]); + } +#endif + /* called with 2nd parm 0, no tx mgmt lock required */ + ieee80211_sta_wakeup(ieee,0); + + for(i = 0; i < txb->nr_frags; i++) { + + if (ieee->queue_stop){ + ieee->tx_pending.txb = txb; + ieee->tx_pending.frag = i; + goto exit; + }else{ + ieee->softmac_data_hard_start_xmit( + txb->fragments[i], +#ifdef _RTL8187_EXT_PATCH_ + ieee->dev, rate); +#else + ieee->dev,ieee->rate); +#endif + //(i+1)<txb->nr_frags); + ieee->stats.tx_packets++; + ieee->stats.tx_bytes += txb->fragments[i]->len; + ieee->dev->trans_start = jiffies; + } + } + + ieee80211_txb_free(txb); + + exit: + spin_unlock_irqrestore(&ieee->lock,flags); + +} + +/* called with ieee->lock acquired */ +void ieee80211_resume_tx(struct ieee80211_device *ieee) +{ + int i; + for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) { + + if (ieee->queue_stop){ + ieee->tx_pending.frag = i; + return; + }else{ + + ieee->softmac_data_hard_start_xmit( + ieee->tx_pending.txb->fragments[i], + ieee->dev,ieee->rate); + //(i+1)<ieee->tx_pending.txb->nr_frags); + ieee->stats.tx_packets++; + ieee->dev->trans_start = jiffies; + } + } + + + ieee80211_txb_free(ieee->tx_pending.txb); + ieee->tx_pending.txb = NULL; +} + + +void ieee80211_reset_queue(struct ieee80211_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->lock,flags); + init_mgmt_queue(ieee); + if (ieee->tx_pending.txb){ + ieee80211_txb_free(ieee->tx_pending.txb); + ieee->tx_pending.txb = NULL; + } + ieee->queue_stop = 0; + spin_unlock_irqrestore(&ieee->lock,flags); + +} + +void ieee80211_wake_queue(struct ieee80211_device *ieee) +{ + + unsigned long flags; + struct sk_buff *skb; + struct ieee80211_hdr_3addr *header; + + spin_lock_irqsave(&ieee->lock,flags); + if (! ieee->queue_stop) goto exit; + + ieee->queue_stop = 0; + + if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){ + while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){ + + header = (struct ieee80211_hdr_3addr *) skb->data; + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + //printk(KERN_ALERT "ieee80211_wake_queue \n"); + ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); + dev_kfree_skb_any(skb);//edit by thomas + } + } + if (!ieee->queue_stop && ieee->tx_pending.txb) + ieee80211_resume_tx(ieee); + + if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){ + ieee->softmac_stats.swtxawake++; + netif_wake_queue(ieee->dev); + } + +exit : + spin_unlock_irqrestore(&ieee->lock,flags); +} + + +void ieee80211_stop_queue(struct ieee80211_device *ieee) +{ + //unsigned long flags; + //spin_lock_irqsave(&ieee->lock,flags); + + if (! netif_queue_stopped(ieee->dev)){ + netif_stop_queue(ieee->dev); + ieee->softmac_stats.swtxstop++; + } + ieee->queue_stop = 1; + //spin_unlock_irqrestore(&ieee->lock,flags); + +} + + +inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) +{ + + get_random_bytes(ieee->current_network.bssid, ETH_ALEN); + + /* an IBSS cell address must have the two less significant + * bits of the first byte = 2 + */ + ieee->current_network.bssid[0] &= ~0x01; + ieee->current_network.bssid[0] |= 0x02; +} + +/* called in user context only */ +void ieee80211_start_master_bss(struct ieee80211_device *ieee) +{ + ieee->assoc_id = 1; + + if (ieee->current_network.ssid_len == 0){ + strncpy(ieee->current_network.ssid, + IEEE80211_DEFAULT_TX_ESSID, + IW_ESSID_MAX_SIZE); + + ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); + ieee->ssid_set = 1; + } + + memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); + + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->state = IEEE80211_LINKED; + ieee->link_change(ieee->dev); + notify_wx_assoc_event(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); +} + +void ieee80211_start_monitor_mode(struct ieee80211_device *ieee) +{ + if(ieee->raw_tx){ + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + } +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_start_ibss_wq(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); +#else +void ieee80211_start_ibss_wq(struct ieee80211_device *ieee) +{ +#endif + + /* iwconfig mode ad-hoc will schedule this and return + * on the other hand this will block further iwconfig SET + * operations because of the wx_sem hold. + * Anyway some most set operations set a flag to speed-up + * (abort) this wq (when syncro scanning) before sleeping + * on the semaphore + */ + + down(&ieee->wx_sem); + + + if (ieee->current_network.ssid_len == 0){ + strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID); + ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); + ieee->ssid_set = 1; + } + + /* check if we have this cell in our network list */ + ieee80211_softmac_check_all_nets(ieee); + +#ifdef ENABLE_DOT11D + if(ieee->state == IEEE80211_NOLINK) + ieee->current_network.channel = 10; +#endif + /* if not then the state is not linked. Maybe the user swithced to + * ad-hoc mode just after being in monitor mode, or just after + * being very few time in managed mode (so the card have had no + * time to scan all the chans..) or we have just run up the iface + * after setting ad-hoc mode. So we have to give another try.. + * Here, in ibss mode, should be safe to do this without extra care + * (in bss mode we had to make sure no-one tryed to associate when + * we had just checked the ieee->state and we was going to start the + * scan) beacause in ibss mode the ieee80211_new_net function, when + * finds a good net, just set the ieee->state to IEEE80211_LINKED, + * so, at worst, we waste a bit of time to initiate an unneeded syncro + * scan, that will stop at the first round because it sees the state + * associated. + */ + if (ieee->state == IEEE80211_NOLINK) + ieee80211_start_scan_syncro(ieee); + + /* the network definitively is not here.. create a new cell */ + if (ieee->state == IEEE80211_NOLINK){ + printk("creating new IBSS cell\n"); + if(!ieee->wap_set) + ieee80211_randomize_cell(ieee); + + if(ieee->modulation & IEEE80211_CCK_MODULATION){ + + ieee->current_network.rates_len = 4; + + ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + }else + ieee->current_network.rates_len = 0; + + if(ieee->modulation & IEEE80211_OFDM_MODULATION){ + ieee->current_network.rates_ex_len = 8; + + ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; + ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; + ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; + ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; + ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; + ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; + ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; + ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; + + ieee->rate = 540; + }else{ + ieee->current_network.rates_ex_len = 0; + ieee->rate = 110; + } + + // By default, WMM function will be disabled in IBSS mode + ieee->current_network.QoS_Enable = 0; + + ieee->current_network.atim_window = 0; + ieee->current_network.capability = WLAN_CAPABILITY_IBSS; + if(ieee->short_slot) + ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT; + + } + + ieee->state = IEEE80211_LINKED; + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->link_change(ieee->dev); + + notify_wx_assoc_event(ieee); + + ieee80211_start_send_beacons(ieee); + printk(KERN_WARNING "after sending beacon packet!\n"); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + + up(&ieee->wx_sem); +} +inline void ieee80211_start_ibss(struct ieee80211_device *ieee) +{ + queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 100); +} + +/* this is called only in user context, with wx_sem held */ +void ieee80211_start_bss(struct ieee80211_device *ieee) +{ + unsigned long flags; +#ifdef ENABLE_DOT11D + // + // Ref: 802.11d 11.1.3.3 + // STA shall not start a BSS unless properly formed Beacon frame including a Country IE. + // + if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) + { + if(! ieee->bGlobalDomain) + { + return; + } + } +#endif + /* check if we have already found the net we + * are interested in (if any). + * if not (we are disassociated and we are not + * in associating / authenticating phase) start the background scanning. + */ + ieee80211_softmac_check_all_nets(ieee); + + /* ensure no-one start an associating process (thus setting + * the ieee->state to ieee80211_ASSOCIATING) while we + * have just cheked it and we are going to enable scan. + * The ieee80211_new_net function is always called with + * lock held (from both ieee80211_softmac_check_all_nets and + * the rx path), so we cannot be in the middle of such function + */ + spin_lock_irqsave(&ieee->lock, flags); + +//#ifdef ENABLE_IPS +// printk("start bss ENABLE_IPS\n"); +//#else + if (ieee->state == IEEE80211_NOLINK){ + ieee->actscanning = true; + ieee80211_start_scan(ieee); + } +//#endif + spin_unlock_irqrestore(&ieee->lock, flags); +} + +/* called only in userspace context */ +void ieee80211_disassociate(struct ieee80211_device *ieee) +{ + netif_carrier_off(ieee->dev); + + if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) + ieee80211_reset_queue(ieee); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + Dot11d_Reset(ieee); +#endif + ieee->state = IEEE80211_NOLINK; + ieee->link_change(ieee->dev); + notify_wx_assoc_event(ieee); + +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_associate_retry_wq(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); +#else +void ieee80211_associate_retry_wq(struct ieee80211_device *ieee) +{ +#endif + unsigned long flags; + down(&ieee->wx_sem); + if(!ieee->proto_started) + goto exit; + if(ieee->state != IEEE80211_ASSOCIATING_RETRY) + goto exit; + /* until we do not set the state to IEEE80211_NOLINK + * there are no possibility to have someone else trying + * to start an association procdure (we get here with + * ieee->state = IEEE80211_ASSOCIATING). + * When we set the state to IEEE80211_NOLINK it is possible + * that the RX path run an attempt to associate, but + * both ieee80211_softmac_check_all_nets and the + * RX path works with ieee->lock held so there are no + * problems. If we are still disassociated then start a scan. + * the lock here is necessary to ensure no one try to start + * an association procedure when we have just checked the + * state and we are going to start the scan. + */ + ieee->state = IEEE80211_NOLINK; + ieee->beinretry = true; + ieee80211_softmac_check_all_nets(ieee); + + spin_lock_irqsave(&ieee->lock, flags); + + if(ieee->state == IEEE80211_NOLINK){ + ieee->beinretry = false; + ieee->actscanning = true; + ieee80211_start_scan(ieee); + } + //YJ,add,080828, notify os here + if(ieee->state == IEEE80211_NOLINK) + { + notify_wx_assoc_event(ieee); + } + //YJ,add,080828,end + spin_unlock_irqrestore(&ieee->lock, flags); + +exit: + up(&ieee->wx_sem); +} + +struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) +{ + u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; + + struct sk_buff *skb = NULL; + struct ieee80211_probe_response *b; + +//rz +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_get_beacon_get_probersp ) + skb = ieee->ext_patch_get_beacon_get_probersp(ieee, broadcast_addr, &(ieee->current_network)); + else + skb = ieee80211_probe_resp(ieee, broadcast_addr); +#else + skb = ieee80211_probe_resp(ieee, broadcast_addr); +#endif +// + if (!skb) + return NULL; + + b = (struct ieee80211_probe_response *) skb->data; + b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON); + + return skb; + +} + +struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + struct ieee80211_probe_response *b; + + skb = ieee80211_get_beacon_(ieee); + if(!skb) + return NULL; + + b = (struct ieee80211_probe_response *) skb->data; + b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + return skb; +} + +void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee) +{ + ieee->sync_scan_hurryup = 1; + down(&ieee->wx_sem); + ieee80211_stop_protocol(ieee); + up(&ieee->wx_sem); +} + + +void ieee80211_stop_protocol(struct ieee80211_device *ieee) +{ + if (!ieee->proto_started) + return; + + ieee->proto_started = 0; + +#ifdef _RTL8187_EXT_PATCH_ + if(ieee->ext_patch_ieee80211_stop_protocol) + ieee->ext_patch_ieee80211_stop_protocol(ieee); +//if call queue_delayed_work,can call this,or do nothing.. +//edit by lawrence,20071118 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +// cancel_delayed_work(&ieee->ext_stop_scan_wq); +// cancel_delayed_work(&ieee->ext_send_beacon_wq); +#endif +#endif // _RTL8187_EXT_PATCH_ + + ieee80211_stop_send_beacons(ieee); + if((ieee->iw_mode == IW_MODE_INFRA)&&(ieee->state == IEEE80211_LINKED)) { + SendDisassociation(ieee,NULL,WLAN_REASON_DISASSOC_STA_HAS_LEFT); + } + del_timer_sync(&ieee->associate_timer); + cancel_delayed_work(&ieee->associate_retry_wq); + cancel_delayed_work(&ieee->start_ibss_wq); + ieee80211_stop_scan(ieee); + + ieee80211_disassociate(ieee); +} + +void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee) +{ + ieee->sync_scan_hurryup = 0; + down(&ieee->wx_sem); + ieee80211_start_protocol(ieee); + up(&ieee->wx_sem); +} + +void ieee80211_start_protocol(struct ieee80211_device *ieee) +{ + short ch = 0; + int i = 0; + + if (ieee->proto_started) + return; + + ieee->proto_started = 1; + + if (ieee->current_network.channel == 0){ + do{ + ch++; + if (ch > MAX_CHANNEL_NUMBER) + return; /* no channel found */ + +#ifdef ENABLE_DOT11D + }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]); +#else + }while(!ieee->channel_map[ch]); +#endif + + ieee->current_network.channel = ch; + } + + if (ieee->current_network.beacon_interval == 0) + ieee->current_network.beacon_interval = 100; + ieee->set_chan(ieee->dev,ieee->current_network.channel); + + for(i = 0; i < 17; i++) { + ieee->last_rxseq_num[i] = -1; + ieee->last_rxfrag_num[i] = -1; + ieee->last_packet_time[i] = 0; + } + + ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers. + + + /* if the user set the MAC of the ad-hoc cell and then + * switch to managed mode, shall we make sure that association + * attempts does not fail just because the user provide the essid + * and the nic is still checking for the AP MAC ?? + */ + switch (ieee->iw_mode) { + case IW_MODE_AUTO: + ieee->iw_mode = IW_MODE_INFRA; + //not set break here intentionly + case IW_MODE_INFRA: + ieee80211_start_bss(ieee); + break; + + case IW_MODE_ADHOC: + ieee80211_start_ibss(ieee); + break; + + case IW_MODE_MASTER: + ieee80211_start_master_bss(ieee); + break; + + case IW_MODE_MONITOR: + ieee80211_start_monitor_mode(ieee); + break; + + default: +#ifdef _RTL8187_EXT_PATCH_ + if((ieee->iw_mode == ieee->iw_ext_mode) &&\ + ieee->ext_patch_ieee80211_start_protocol &&\ + ieee->ext_patch_ieee80211_start_protocol(ieee)) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->ext_stop_scan_wq); +#endif + // By default, WMM function will be disabled in + // EXTENSION mode + ieee->current_network.QoS_Enable = 0; + + if(ieee->modulation & IEEE80211_CCK_MODULATION){ + ieee->current_network.rates_len = 4; + ieee->current_network.rates[0] = \ + IEEE80211_BASIC_RATE_MASK | \ + IEEE80211_CCK_RATE_1MB; + ieee->current_network.rates[1] = \ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_CCK_RATE_2MB; + ieee->current_network.rates[2] = \ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_CCK_RATE_5MB; + ieee->current_network.rates[3] = \ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_CCK_RATE_11MB; + }else + ieee->current_network.rates_len = 0; + + if(ieee->modulation & IEEE80211_OFDM_MODULATION){ + ieee->current_network.rates_ex_len = 8; + ieee->current_network.rates_ex[0] = \ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_OFDM_RATE_6MB; + ieee->current_network.rates_ex[1] = \ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_OFDM_RATE_9MB; + ieee->current_network.rates_ex[2] = \ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_OFDM_RATE_12MB; + ieee->current_network.rates_ex[3] = \ + IEEE80211_BASIC_RATE_MASK | \ + IEEE80211_OFDM_RATE_18MB; + ieee->current_network.rates_ex[4] =\ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_OFDM_RATE_24MB; + ieee->current_network.rates_ex[5] =\ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_OFDM_RATE_36MB; + ieee->current_network.rates_ex[6] = \ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_OFDM_RATE_48MB; + ieee->current_network.rates_ex[7] =\ + IEEE80211_BASIC_RATE_MASK |\ + IEEE80211_OFDM_RATE_54MB; + ieee->rate = 540; + }else{ + ieee->current_network.rates_ex_len = 0; + ieee->rate = 110; + } + + /* + spin_lock_irqsave(&ieee->lock, flags); + if (ieee->state == IEEE80211_NOLINK) + ieee80211_start_scan(ieee); + // ieee->set_chan(ieee->dev, 8); + + spin_unlock_irqrestore(&ieee->lock, flags); + */ + memcpy(ieee->current_network.bssid, ieee->dev->dev_addr,\ + ETH_ALEN); + ieee->link_change(ieee->dev); + notify_wx_assoc_event(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + } else { + ieee->iw_mode = IW_MODE_INFRA; + ieee80211_start_bss(ieee); + } +#else + ieee->iw_mode = IW_MODE_INFRA; + ieee80211_start_bss(ieee); + +#endif + break; + } +} + + +#define DRV_NAME "Ieee80211" +void ieee80211_softmac_init(struct ieee80211_device *ieee) +{ + int i; + memset(&ieee->current_network, 0, sizeof(struct ieee80211_network)); + + ieee->state = IEEE80211_NOLINK; + ieee->sync_scan_hurryup = 0; + for(i = 0; i < 5; i++) { + ieee->seq_ctrl[i] = 0; + } + + ieee->assoc_id = 0; + ieee->queue_stop = 0; + ieee->scanning = 0; + ieee->softmac_features = 0; //so IEEE2100-like driver are happy + ieee->wap_set = 0; + ieee->ssid_set = 0; + ieee->proto_started = 0; + ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE; + ieee->rate = 3; +//#ifdef ENABLE_LPS + ieee->ps = IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST; +//#else +// ieee->ps = IEEE80211_PS_DISABLED; +//#endif + ieee->sta_sleep = 0; +//by amy + ieee->bInactivePs = false; + ieee->actscanning = false; + ieee->ListenInterval = 2; + ieee->NumRxDataInPeriod = 0; //YJ,add,080828 + ieee->NumRxBcnInPeriod = 0; //YJ,add,080828 + ieee->NumRxOkTotal = 0;//+by amy 080312 + ieee->NumRxUnicast = 0;//YJ,add,080828,for keep alive + ieee->beinretry = false; + ieee->bHwRadioOff = false; +//by amy +#ifdef _RTL8187_EXT_PATCH_ + ieee->iw_ext_mode = 999; +#endif + + init_mgmt_queue(ieee); +#if 0 + init_timer(&ieee->scan_timer); + ieee->scan_timer.data = (unsigned long)ieee; + ieee->scan_timer.function = ieee80211_softmac_scan_cb; +#endif + ieee->tx_pending.txb = NULL; + + init_timer(&ieee->associate_timer); + ieee->associate_timer.data = (unsigned long)ieee; + ieee->associate_timer.function = ieee80211_associate_abort_cb; + + init_timer(&ieee->beacon_timer); + ieee->beacon_timer.data = (unsigned long) ieee; + ieee->beacon_timer.function = ieee80211_send_beacon_cb; + +#ifdef PF_SYNCTHREAD + ieee->wq = create_workqueue(DRV_NAME,0); +#else + ieee->wq = create_workqueue(DRV_NAME); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)//added by lawrence,070702 + INIT_DELAYED_WORK(&ieee->start_ibss_wq,(void*) ieee80211_start_ibss_wq); + INIT_WORK(&ieee->associate_complete_wq,(void*) ieee80211_associate_complete_wq); + INIT_WORK(&ieee->associate_procedure_wq,(void*) ieee80211_associate_procedure_wq); + INIT_DELAYED_WORK(&ieee->softmac_scan_wq,(void*) ieee80211_softmac_scan_wq); + INIT_DELAYED_WORK(&ieee->associate_retry_wq,(void*) ieee80211_associate_retry_wq); + INIT_WORK(&ieee->wx_sync_scan_wq,(void*) ieee80211_wx_sync_scan_wq); +// INIT_WORK(&ieee->watch_dog_wq,(void*) ieee80211_watch_dog_wq); +//added by lawrence,20071118 +#ifdef _RTL8187_EXT_PATCH_ + INIT_WORK(&ieee->ext_stop_scan_wq,(void*) ieee80211_ext_stop_scan_wq); + //INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ieee80211_beacons_start,ieee); + INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ext_ieee80211_send_beacon_wq); +#endif //_RTL8187_EXT_PATCH_ +#else + INIT_WORK(&ieee->start_ibss_wq,(void*) ieee80211_start_ibss_wq,ieee); + INIT_WORK(&ieee->associate_retry_wq,(void*) ieee80211_associate_retry_wq,ieee); + INIT_WORK(&ieee->associate_complete_wq,(void*) ieee80211_associate_complete_wq,ieee); + INIT_WORK(&ieee->associate_procedure_wq,(void*) ieee80211_associate_procedure_wq,ieee); + INIT_WORK(&ieee->softmac_scan_wq,(void*) ieee80211_softmac_scan_wq,ieee); + INIT_WORK(&ieee->wx_sync_scan_wq,(void*) ieee80211_wx_sync_scan_wq,ieee); +// INIT_WORK(&ieee->watch_dog_wq,(void*) ieee80211_watch_dog_wq,ieee); +#ifdef _RTL8187_EXT_PATCH_ + INIT_WORK(&ieee->ext_stop_scan_wq,(void*) ieee80211_ext_stop_scan_wq,ieee); + //INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ieee80211_beacons_start,ieee); + INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ext_ieee80211_send_beacon_wq,ieee); +#endif +#endif + sema_init(&ieee->wx_sem, 1); + sema_init(&ieee->scan_sem, 1); + + spin_lock_init(&ieee->mgmt_tx_lock); + spin_lock_init(&ieee->beacon_lock); + + tasklet_init(&ieee->ps_task, + (void(*)(unsigned long)) ieee80211_sta_ps, + (unsigned long)ieee); +#ifdef ENABLE_DOT11D + ieee->pDot11dInfo = kmalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC); +#endif +} + +void ieee80211_softmac_free(struct ieee80211_device *ieee) +{ + down(&ieee->wx_sem); + + del_timer_sync(&ieee->associate_timer); + cancel_delayed_work(&ieee->associate_retry_wq); + + + //add for RF power on power of by lizhaoming 080512 + cancel_delayed_work(&ieee->GPIOChangeRFWorkItem); + +#ifdef _RTL8187_EXT_PATCH_ + cancel_delayed_work(&ieee->ext_stop_scan_wq); + cancel_delayed_work(&ieee->ext_send_beacon_wq); +#endif + destroy_workqueue(ieee->wq); +#ifdef ENABLE_DOT11D + if(NULL != ieee->pDot11dInfo) + kfree(ieee->pDot11dInfo); +#endif + up(&ieee->wx_sem); +} + +/******************************************************** + * Start of WPA code. * + * this is stolen from the ipw2200 driver * + ********************************************************/ + + +static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value) +{ + /* This is called when wpa_supplicant loads and closes the driver + * interface. */ + printk("%s WPA\n",value ? "enabling" : "disabling"); + ieee->wpa_enabled = value; + return 0; +} + + +void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len) +{ + /* make sure WPA is enabled */ + ieee80211_wpa_enable(ieee, 1); + + ieee80211_disassociate(ieee); +} + + +static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, int reason) +{ + + int ret = 0; + + switch (command) { + case IEEE_MLME_STA_DEAUTH: + // silently ignore + break; + + case IEEE_MLME_STA_DISASSOC: + ieee80211_disassociate(ieee); + break; + + default: + printk("Unknown MLME request: %d\n", command); + ret = -EOPNOTSUPP; + } + + return ret; +} + + +static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee, + struct ieee_param *param, int plen) +{ + u8 *buf; + + if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || + (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) + return -EINVAL; + + if (param->u.wpa_ie.len) { + buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = param->u.wpa_ie.len; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + + ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); + return 0; +} + +#define AUTH_ALG_OPEN_SYSTEM 0x1 +#define AUTH_ALG_SHARED_KEY 0x2 + +static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value) +{ + + struct ieee80211_security sec = { + .flags = SEC_AUTH_MODE, + }; + int ret = 0; + + if (value & AUTH_ALG_SHARED_KEY) { + sec.auth_mode = WLAN_AUTH_SHARED_KEY; + ieee->open_wep = 0; + } else { + sec.auth_mode = WLAN_AUTH_OPEN; + ieee->open_wep = 1; + } + + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + else + ret = -EOPNOTSUPP; + + return ret; +} + +static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value) +{ + int ret=0; + unsigned long flags; + + switch (name) { + case IEEE_PARAM_WPA_ENABLED: + ret = ieee80211_wpa_enable(ieee, value); + break; + + case IEEE_PARAM_TKIP_COUNTERMEASURES: + ieee->tkip_countermeasures=value; + 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. + */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = value, + }; + ieee->drop_unencrypted = value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } + else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + break; + } + + case IEEE_PARAM_PRIVACY_INVOKED: + ieee->privacy_invoked=value; + break; + + case IEEE_PARAM_AUTH_ALGS: + ret = ieee80211_wpa_set_auth_algs(ieee, value); + break; + + case IEEE_PARAM_IEEE_802_1X: + ieee->ieee802_1x=value; + break; + case IEEE_PARAM_WPAX_SELECT: + // added for WPA2 mixed mode + //printk(KERN_WARNING "------------------------>wpax value = %x\n", value); + spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); + ieee->wpax_type_set = 1; + ieee->wpax_type_notify = value; + spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); + break; + + default: + printk("Unknown WPA param: %d\n",name); + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* implementation borrowed from hostap driver */ + +static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, + struct ieee_param *param, int param_len) +{ + int ret = 0; + + struct ieee80211_crypto_ops *ops; + struct ieee80211_crypt_data **crypt; + + struct ieee80211_security sec = { + .flags = 0, + }; + + param->u.crypt.err = 0; + param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; + + if (param_len != + (int) ((char *) param->u.crypt.key - (char *) param) + + param->u.crypt.key_len) { + printk("Len mismatch %d, %d\n", param_len, + param->u.crypt.key_len); + return -EINVAL; + } + if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && + param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (param->u.crypt.idx >= WEP_KEYS) + return -EINVAL; + crypt = &ieee->crypt[param->u.crypt.idx]; + } else { + return -EINVAL; + } + + if (strcmp(param->u.crypt.alg, "none") == 0) { + if (crypt) { + sec.enabled = 0; + // FIXME FIXME + //sec.encrypt = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL; + ieee80211_crypt_delayed_deinit(ieee, crypt); + } + goto done; + } + sec.enabled = 1; +// FIXME FIXME +// sec.encrypt = 1; + sec.flags |= SEC_ENABLED; + + /* IPW HW cannot build TKIP MIC, host decryption still needed. */ + if (!(ieee->host_encrypt || ieee->host_decrypt) && + strcmp(param->u.crypt.alg, "TKIP")) + goto skip_host_crypt; + + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { + request_module("ieee80211_crypt_wep"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { + request_module("ieee80211_crypt_tkip"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { + request_module("ieee80211_crypt_ccmp"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } + if (ops == NULL) { + printk("unknown crypto alg '%s'\n", param->u.crypt.alg); + param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct ieee80211_crypt_data *new_crypt; + + ieee80211_crypt_delayed_deinit(ieee, crypt); + + new_crypt = (struct ieee80211_crypt_data *) + kmalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); + new_crypt->ops = ops; + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = + new_crypt->ops->init(param->u.crypt.idx); + + if (new_crypt->priv == NULL) { + kfree(new_crypt); + param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; + ret = -EINVAL; + goto done; + } + + *crypt = new_crypt; + } + + if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(param->u.crypt.key, + param->u.crypt.key_len, param->u.crypt.seq, + (*crypt)->priv) < 0) { + printk("key setting failed\n"); + param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; + ret = -EINVAL; + goto done; + } + + skip_host_crypt: + if (param->u.crypt.set_tx) { + ieee->tx_keyidx = param->u.crypt.idx; + sec.active_key = param->u.crypt.idx; + sec.flags |= SEC_ACTIVE_KEY; + } else + sec.flags &= ~SEC_ACTIVE_KEY; + + if (param->u.crypt.alg != NULL) { + memcpy(sec.keys[param->u.crypt.idx], + param->u.crypt.key, + param->u.crypt.key_len); + sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; + sec.flags |= (1 << param->u.crypt.idx); + + if (strcmp(param->u.crypt.alg, "WEP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + } + done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && + ieee->reset_port(ieee->dev)) { + printk("reset_port failed\n"); + param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; + return -EINVAL; + } + + return ret; +} + +int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p) +{ + struct ieee_param *param; + int ret=0; + + down(&ieee->wx_sem); + //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); + + if (p->length < sizeof(struct ieee_param) || !p->pointer){ + ret = -EINVAL; + goto out; + } + + param = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); + if (param == NULL){ + ret = -ENOMEM; + goto out; + } + if (copy_from_user(param, p->pointer, p->length)) { + kfree(param); + ret = -EFAULT; + goto out; + } + + switch (param->cmd) { + + case IEEE_CMD_SET_WPA_PARAM: + ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name, + param->u.wpa_param.value); + break; + + case IEEE_CMD_SET_WPA_IE: + ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length); + break; + + case IEEE_CMD_SET_ENCRYPTION: + ret = ieee80211_wpa_set_encryption(ieee, param, p->length); + break; + + case IEEE_CMD_MLME: + ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command, + param->u.mlme.reason_code); + break; + + default: + printk("Unknown WPA supplicant request: %d\n",param->cmd); + ret = -EOPNOTSUPP; + break; + } + + if (ret == 0 && copy_to_user(p->pointer, param, p->length)) + ret = -EFAULT; + + kfree(param); +out: + up(&ieee->wx_sem); + + return ret; +} + +void notify_wx_assoc_event(struct ieee80211_device *ieee) +{ + union iwreq_data wrqu; + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (ieee->state == IEEE80211_LINKED) + memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN); + else + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); +} + + +#if 0 +EXPORT_SYMBOL(ieee80211_get_beacon); +EXPORT_SYMBOL(ieee80211_wake_queue); +EXPORT_SYMBOL(ieee80211_stop_queue); +EXPORT_SYMBOL(ieee80211_reset_queue); +EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); +EXPORT_SYMBOL(ieee80211_softmac_start_protocol); +EXPORT_SYMBOL(ieee80211_is_shortslot); +EXPORT_SYMBOL(ieee80211_is_54g); +EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl); +EXPORT_SYMBOL(ieee80211_ps_tx_ack); +EXPORT_SYMBOL(ieee80211_start_protocol); +EXPORT_SYMBOL(ieee80211_stop_protocol); +EXPORT_SYMBOL(notify_wx_assoc_event); +EXPORT_SYMBOL(ieee80211_stop_send_beacons); +EXPORT_SYMBOL(SendDisassociation); +EXPORT_SYMBOL(ieee80211_disassociate); +EXPORT_SYMBOL(ieee80211_start_scan); +EXPORT_SYMBOL(ieee80211_softmac_ips_scan_syncro); +#ifdef _RTL8187_EXT_PATCH_ +EXPORT_SYMBOL(ieee80211_ext_issue_assoc_req); +EXPORT_SYMBOL(ieee80211_ext_issue_disassoc); +EXPORT_SYMBOL(ieee80211_ext_issue_assoc_rsp); +EXPORT_SYMBOL(softmac_mgmt_xmit); +EXPORT_SYMBOL(ieee80211_ext_probe_resp_by_net); +EXPORT_SYMBOL(ieee80211_start_scan); +EXPORT_SYMBOL(ieee80211_stop_scan); +EXPORT_SYMBOL(ieee80211_ext_send_11s_beacon); +EXPORT_SYMBOL(ieee80211_rx_auth_rq); +EXPORT_SYMBOL(ieee80211_associate_step1); +#endif // _RTL8187_EXT_PATCH_ +EXPORT_SYMBOL(ieee80211_sta_ps_send_null_frame); +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c new file mode 100644 index 0000000..43b8aec --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c @@ -0,0 +1,602 @@ +/* IEEE 802.11 SoftMAC layer + * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> + * + * Mostly extracted from the rtl8180-sa2400 driver for the + * in-kernel generic ieee802.11 stack. + * + * Some pieces of code might be stolen from ipw2100 driver + * copyright of who own it's copyright ;-) + * + * PS wx handler mostly stolen from hostap, copyright who + * own it's copyright ;-) + * + * released under the GPL + */ + + +#include "ieee80211.h" + +/* FIXME: add A freqs */ + +const long ieee80211_wlan_frequencies[] = { + 2412, 2417, 2422, 2427, + 2432, 2437, 2442, 2447, + 2452, 2457, 2462, 2467, + 2472, 2484 +}; + + +int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct iw_freq *fwrq = & wrqu->freq; +// printk("in %s\n",__FUNCTION__); + down(&ieee->wx_sem); + + if(ieee->iw_mode == IW_MODE_INFRA){ + ret = -EOPNOTSUPP; + goto out; + } + + /* if setting by freq convert to channel */ + if (fwrq->e == 1) { + if ((fwrq->m >= (int) 2.412e8 && + fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + + while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) + c++; + + /* hack to fall through */ + fwrq->e = 0; + fwrq->m = c + 1; + } + } + + if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ + ret = -EOPNOTSUPP; + goto out; + + }else { /* Set the channel */ + + + ieee->current_network.channel = fwrq->m; + ieee->set_chan(ieee->dev, ieee->current_network.channel); + + if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) + if(ieee->state == IEEE80211_LINKED){ + + ieee80211_stop_send_beacons(ieee); + ieee80211_start_send_beacons(ieee); + } + } + + ret = 0; +out: + up(&ieee->wx_sem); + return ret; +} + + +int ieee80211_wx_get_freq(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct iw_freq *fwrq = & wrqu->freq; + + if (ieee->current_network.channel == 0) + return -1; + + fwrq->m = ieee->current_network.channel; + fwrq->e = 0; + + return 0; +} + +int ieee80211_wx_get_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + unsigned long flags; + + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + + if (ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + /* We want avoid to give to the user inconsistent infos*/ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->state != IEEE80211_LINKED && + ieee->state != IEEE80211_LINKED_SCANNING && + ieee->wap_set == 0) + + memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + else + memcpy(wrqu->ap_addr.sa_data, + ieee->current_network.bssid, ETH_ALEN); + + spin_unlock_irqrestore(&ieee->lock, flags); + + return 0; +} + + +int ieee80211_wx_set_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + + int ret = 0; + u8 zero[] = {0,0,0,0,0,0}; + unsigned long flags; + + short ifup = ieee->proto_started;//dev->flags & IFF_UP; + struct sockaddr *temp = (struct sockaddr *)awrq; + + //printk("=======Set WAP:"); + ieee->sync_scan_hurryup = 1; + + down(&ieee->wx_sem); + /* use ifconfig hw ether */ + if (ieee->iw_mode == IW_MODE_MASTER){ + ret = -1; + goto out; + } + + if (temp->sa_family != ARPHRD_ETHER){ + ret = -EINVAL; + goto out; + } + + if (ifup) + ieee80211_stop_protocol(ieee); + + /* just to avoid to give inconsistent infos in the + * get wx method. not really needed otherwise + */ + spin_lock_irqsave(&ieee->lock, flags); + + memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); + ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; + //printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]); + + spin_unlock_irqrestore(&ieee->lock, flags); + + if (ifup) + ieee80211_start_protocol(ieee); + +out: + up(&ieee->wx_sem); + return ret; +} + + int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b) +{ + int len,ret = 0; + unsigned long flags; + + if (ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + /* We want avoid to give to the user inconsistent infos*/ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->current_network.ssid[0] == '\0' || + ieee->current_network.ssid_len == 0){ + ret = -1; + goto out; + } + + if (ieee->state != IEEE80211_LINKED && + ieee->state != IEEE80211_LINKED_SCANNING && + ieee->ssid_set == 0){ + ret = -1; + goto out; + } + len = ieee->current_network.ssid_len; + wrqu->essid.length = len; + strncpy(b,ieee->current_network.ssid,len); + wrqu->essid.flags = 1; + +out: + spin_unlock_irqrestore(&ieee->lock, flags); + + return ret; + +} + +int ieee80211_wx_set_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + u32 target_rate = wrqu->bitrate.value; + + //added by lizhaoming for auto mode + if(target_rate == -1){ + ieee->rate = 110; + } else { + ieee->rate = target_rate/100000; + } + //FIXME: we might want to limit rate also in management protocols. + return 0; +} + + + +int ieee80211_wx_get_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + wrqu->bitrate.value = ieee->rate * 100000; + + return 0; +} + +int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + + ieee->sync_scan_hurryup = 1; + + down(&ieee->wx_sem); + + if (wrqu->mode == ieee->iw_mode) + goto out; + + if (wrqu->mode == IW_MODE_MONITOR){ + + ieee->dev->type = ARPHRD_IEEE80211; + }else{ + ieee->dev->type = ARPHRD_ETHER; + } + + if (!ieee->proto_started){ + ieee->iw_mode = wrqu->mode; + }else{ + ieee80211_stop_protocol(ieee); + ieee->iw_mode = wrqu->mode; + ieee80211_start_protocol(ieee); + } + +out: + up(&ieee->wx_sem); + return 0; +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +void ieee80211_wx_sync_scan_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); +#else +void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee) +{ +#endif +//void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee) +//{ + short chan; + + chan = ieee->current_network.channel; + + netif_carrier_off(ieee->dev); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + + ieee80211_stop_send_beacons(ieee); + + ieee->state = IEEE80211_LINKED_SCANNING; + ieee->link_change(ieee->dev); + + ieee80211_start_scan_syncro(ieee); + + ieee->set_chan(ieee->dev, chan); + + ieee->state = IEEE80211_LINKED; + ieee->link_change(ieee->dev); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) + ieee80211_start_send_beacons(ieee); + + netif_carrier_on(ieee->dev); + + //YJ,add,080828, In prevent of lossing ping packet during scanning + //ieee80211_sta_ps_send_null_frame(ieee, false); + //YJ,add,080828,end + + up(&ieee->wx_sem); + +} + +int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret = 0; + + down(&ieee->wx_sem); + + if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){ + ret = -1; + goto out; + } + //YJ,add,080828 + //In prevent of lossing ping packet during scanning + //ieee80211_sta_ps_send_null_frame(ieee, true); + //YJ,add,080828,end + + if ( ieee->state == IEEE80211_LINKED){ + queue_work(ieee->wq, &ieee->wx_sync_scan_wq); + /* intentionally forget to up sem */ + return 0; + } + +out: + up(&ieee->wx_sem); + return ret; +} + +int ieee80211_wx_set_essid(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + + int ret=0,len; + short proto_started; + unsigned long flags; + + ieee->sync_scan_hurryup = 1; + + down(&ieee->wx_sem); + + proto_started = ieee->proto_started; + + if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ + ret= -E2BIG; + goto out; + } + + if (ieee->iw_mode == IW_MODE_MONITOR){ + ret= -1; + goto out; + } + + if(proto_started) + ieee80211_stop_protocol(ieee); + + /* this is just to be sure that the GET wx callback + * has consisten infos. not needed otherwise + */ + spin_lock_irqsave(&ieee->lock, flags); + + if (wrqu->essid.flags && wrqu->essid.length) { +//YJ,modified,080819 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; +#else + len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE; +#endif + memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819 + strncpy(ieee->current_network.ssid, extra, len); + ieee->current_network.ssid_len = len; + ieee->ssid_set = 1; +//YJ,modified,080819,end + + //YJ,add,080819,for hidden ap + if(len == 0){ + memset(ieee->current_network.bssid, 0, ETH_ALEN); + ieee->current_network.capability = 0; + } + //YJ,add,080819,for hidden ap,end + } + else{ + ieee->ssid_set = 0; + ieee->current_network.ssid[0] = '\0'; + ieee->current_network.ssid_len = 0; + } + //printk("==========set essid %s!\n",ieee->current_network.ssid); + spin_unlock_irqrestore(&ieee->lock, flags); + + if (proto_started) + ieee80211_start_protocol(ieee); +out: + up(&ieee->wx_sem); + return ret; +} + + int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + + wrqu->mode = ieee->iw_mode; + return 0; +} + + int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + int *parms = (int *)extra; + int enable = (parms[0] > 0); + short prev = ieee->raw_tx; + + down(&ieee->wx_sem); + + if(enable) + ieee->raw_tx = 1; + else + ieee->raw_tx = 0; + + printk(KERN_INFO"raw TX is %s\n", + ieee->raw_tx ? "enabled" : "disabled"); + + if(ieee->iw_mode == IW_MODE_MONITOR) + { + if(prev == 0 && ieee->raw_tx){ + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + } + + if(prev && ieee->raw_tx == 1) + netif_carrier_off(ieee->dev); + } + + up(&ieee->wx_sem); + + return 0; +} + +int ieee80211_wx_get_name(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + strcpy(wrqu->name, "802.11"); + if(ieee->modulation & IEEE80211_CCK_MODULATION){ + strcat(wrqu->name, "b"); + if(ieee->modulation & IEEE80211_OFDM_MODULATION) + strcat(wrqu->name, "/g"); + }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) + strcat(wrqu->name, "g"); + + if((ieee->state == IEEE80211_LINKED) || + (ieee->state == IEEE80211_LINKED_SCANNING)) + strcat(wrqu->name," linked"); + else if(ieee->state != IEEE80211_NOLINK) + strcat(wrqu->name," link.."); + + + return 0; +} + + +/* this is mostly stolen from hostap */ +int ieee80211_wx_set_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; + + if( + (!ieee->sta_wake_up) || + (!ieee->ps_request_tx_ack) || + (!ieee->enter_sleep_state) || + (!ieee->ps_is_queue_empty)){ + + printk("ERROR. PS mode is tryied to be use but\ +driver missed a callback\n\n"); + + return -1; + } + + down(&ieee->wx_sem); + + if (wrqu->power.disabled){ + ieee->ps = IEEE80211_PS_DISABLED; + + goto exit; + } + switch (wrqu->power.flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + ieee->ps = IEEE80211_PS_UNICAST; + + break; + case IW_POWER_ALL_R: + ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; + break; + + case IW_POWER_ON: + ieee->ps = IEEE80211_PS_DISABLED; + break; + + default: + ret = -EINVAL; + goto exit; + } + + if (wrqu->power.flags & IW_POWER_TIMEOUT) { + + ieee->ps_timeout = wrqu->power.value / 1000; + printk("Timeout %d\n",ieee->ps_timeout); + } + + if (wrqu->power.flags & IW_POWER_PERIOD) { + + ret = -EOPNOTSUPP; + goto exit; + //wrq->value / 1024; + + } +exit: + up(&ieee->wx_sem); + return ret; + +} + +/* this is stolen from hostap */ +int ieee80211_wx_get_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret =0; + + down(&ieee->wx_sem); + + if(ieee->ps == IEEE80211_PS_DISABLED){ + wrqu->power.disabled = 1; + goto exit; + } + + wrqu->power.disabled = 0; + +// if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + wrqu->power.flags = IW_POWER_TIMEOUT; + wrqu->power.value = ieee->ps_timeout * 1000; +// } else { +// ret = -EOPNOTSUPP; +// goto exit; + //wrqu->power.flags = IW_POWER_PERIOD; + //wrqu->power.value = ieee->current_network.dtim_period * + // ieee->current_network.beacon_interval * 1024; +// } + + + if (ieee->ps & IEEE80211_PS_MBCAST) + wrqu->power.flags |= IW_POWER_ALL_R; + else + wrqu->power.flags |= IW_POWER_UNICAST_R; + +exit: + up(&ieee->wx_sem); + return ret; + +} + +#if 0 +EXPORT_SYMBOL(ieee80211_wx_get_essid); +EXPORT_SYMBOL(ieee80211_wx_set_essid); +EXPORT_SYMBOL(ieee80211_wx_set_rate); +EXPORT_SYMBOL(ieee80211_wx_get_rate); +EXPORT_SYMBOL(ieee80211_wx_set_wap); +EXPORT_SYMBOL(ieee80211_wx_get_wap); +EXPORT_SYMBOL(ieee80211_wx_set_mode); +EXPORT_SYMBOL(ieee80211_wx_get_mode); +EXPORT_SYMBOL(ieee80211_wx_set_scan); +EXPORT_SYMBOL(ieee80211_wx_get_freq); +EXPORT_SYMBOL(ieee80211_wx_set_freq); +EXPORT_SYMBOL(ieee80211_wx_set_rawtx); +EXPORT_SYMBOL(ieee80211_wx_get_name); +EXPORT_SYMBOL(ieee80211_wx_set_power); +EXPORT_SYMBOL(ieee80211_wx_get_power); +EXPORT_SYMBOL(ieee80211_wlan_frequencies); +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c new file mode 100644 index 0000000..33a0687 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -0,0 +1,828 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2004 Intel 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., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos <ipw2100-admin@linux.intel.com> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +****************************************************************************** + + Few modifications for Realtek's Wi-Fi drivers by + Andrea Merello <andreamrl@tiscali.it> + + A special thanks goes to Realtek for their support ! + +******************************************************************************/ + +#include <linux/compiler.h> +//#include <linux/config.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/in6.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/wireless.h> +#include <linux/etherdevice.h> +#include <asm/uaccess.h> +#include <linux/if_vlan.h> + +#include "ieee80211.h" + + +/* + + +802.11 Data Frame + + +802.11 frame_contorl for data frames - 2 bytes + ,-----------------------------------------------------------------------------------------. +bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | + |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| +val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | + |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| +desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep | + | | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | | + '-----------------------------------------------------------------------------------------' + /\ + | +802.11 Data Frame | + ,--------- 'ctrl' expands to >-----------' + | + ,--'---,-------------------------------------------------------------. +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 non-data bytes `----.----' + | + .- 'Frame data' expands to <---------------------------' + | + V + ,---------------------------------------------------. +Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | + |------|------|---------|----------|------|---------| +Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | + | DSAP | SSAP | | | | Packet | + | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | + `-----------------------------------------| | +Total: 8 non-data bytes `----.----' + | + .- 'IP Packet' expands, if WEP enabled, to <--' + | + V + ,-----------------------. +Bytes | 4 | 0-2296 | 4 | + |-----|-----------|-----| +Desc. | IV | Encrypted | ICV | + | | IP Packet | | + `-----------------------' +Total: 8 non-data bytes + + +802.3 Ethernet Data Frame + + ,-----------------------------------------. +Bytes | 6 | 6 | 2 | Variable | 4 | + |-------|-------|------|-----------|------| +Desc. | Dest. | Source| Type | IP Packet | fcs | + | MAC | MAC | | | | + `-----------------------------------------' +Total: 18 non-data bytes + +In the event that fragmentation is required, the incoming payload is split into +N parts of size ieee->fts. The first fragment contains the SNAP header and the +remaining packets are just data. + +If encryption is enabled, each fragment payload size is reduced by enough space +to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) +So if you have 1500 bytes of payload with ieee->fts set to 500 without +encryption it will take 3 frames. With WEP it will take 4 frames as the +payload of each frame is reduced to 492 bytes. + +* SKB visualization +* +* ,- skb->data +* | +* | ETHERNET HEADER ,-<-- PAYLOAD +* | | 14 bytes from skb->data +* | 2 bytes for Type --> ,T. | (sizeof ethhdr) +* | | | | +* |,-Dest.--. ,--Src.---. | | | +* | 6 bytes| | 6 bytes | | | | +* v | | | | | | +* 0 | v 1 | v | v 2 +* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +* ^ | ^ | ^ | +* | | | | | | +* | | | | `T' <---- 2 bytes for Type +* | | | | +* | | '---SNAP--' <-------- 6 bytes for SNAP +* | | +* `-IV--' <-------------------- 4 bytes for IV (WEP) +* +* SNAP HEADER +* +*/ + +static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; +static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; + +static inline int ieee80211_put_snap(u8 *data, u16 h_proto) +{ + struct ieee80211_snap_hdr *snap; + 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); +} + +int ieee80211_encrypt_fragment( + struct ieee80211_device *ieee, + struct sk_buff *frag, + int hdr_len) +{ + struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx]; + int res; + + /*added to care about null crypt condition, to solve that system hangs when shared keys error*/ + if (!crypt || !crypt->ops) + return -1; + +#ifdef CONFIG_IEEE80211_CRYPT_TKIP + struct ieee80211_hdr *header; + + if (ieee->tkip_countermeasures && + crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { + header = (struct ieee80211_hdr *) frag->data; + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "TX packet to " MAC_FMT "\n", + ieee->dev->name, MAC_ARG(header->addr1)); + } + return -1; + } +#endif + /* To encrypt, frame format is: + * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ + + // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. + /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so + * call both MSDU and MPDU encryption functions from here. */ + atomic_inc(&crypt->refcnt); + res = 0; + if (crypt->ops->encrypt_msdu) + res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); + if (res == 0 && crypt->ops->encrypt_mpdu) + res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); + + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_INFO "%s: Encryption failed: len=%d.\n", + ieee->dev->name, frag->len); + ieee->ieee_stats.tx_discards++; + return -1; + } + + return 0; +} + + +void ieee80211_txb_free(struct ieee80211_txb *txb) { + int i; + if (unlikely(!txb)) + return; + for (i = 0; i < txb->nr_frags; i++) + if (txb->fragments[i]) + dev_kfree_skb_any(txb->fragments[i]); + kfree(txb); +} + +struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, + int gfp_mask) +{ + struct ieee80211_txb *txb; + int i; + txb = kmalloc( + sizeof(struct ieee80211_txb) + (sizeof(u8*) * nr_frags), + gfp_mask); + if (!txb) + return NULL; + + memset(txb, 0, sizeof(struct ieee80211_txb)); + txb->nr_frags = nr_frags; + txb->frag_size = txb_size; + + for (i = 0; i < nr_frags; i++) { + txb->fragments[i] = dev_alloc_skb(txb_size); + if (unlikely(!txb->fragments[i])) { + i--; + break; + } + } + if (unlikely(i != nr_frags)) { + while (i >= 0) + dev_kfree_skb_any(txb->fragments[i--]); + kfree(txb); + return NULL; + } + return txb; +} + +// Classify the to-be send data packet +// Need to acquire the sent queue index. +static int +ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network) +{ + struct ether_header *eh = (struct ether_header*)skb->data; + unsigned int wme_UP = 0; + + if(!network->QoS_Enable) { + skb->priority = 0; + return(wme_UP); + } + + if(eh->ether_type == __constant_htons(ETHERTYPE_IP)) { + const struct iphdr *ih = (struct iphdr*)(skb->data + \ + sizeof(struct ether_header)); + wme_UP = (ih->tos >> 5)&0x07; + } else if (vlan_tx_tag_present(skb)) {//vtag packet +#ifndef VLAN_PRI_SHIFT +#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */ +#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */ +#endif + u32 tag = vlan_tx_tag_get(skb); + wme_UP = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + } else if(ETH_P_PAE == ntohs(((struct ethhdr *)skb->data)->h_proto)) { + //printk(KERN_WARNING "type = normal packet\n"); + wme_UP = 7; + } + + skb->priority = wme_UP; + return(wme_UP); +} + +#ifdef _RTL8187_EXT_PATCH_ +// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held +struct ieee80211_txb *ieee80211_ext_alloc_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + struct ieee80211_device *ieee = netdev_priv(dev); +#else + struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; +#endif + struct ieee80211_txb *txb = NULL; + struct ieee80211_hdr_3addr *frag_hdr; + int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; + int ether_type; + int bytes, QOS_ctl; + struct sk_buff *skb_frag; + + ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); + + /* Advance the SKB to the start of the payload */ + skb_pull(skb, sizeof(struct ethhdr)); + + /* Determine total amount of storage required for TXB packets */ + bytes = skb->len + SNAP_SIZE + sizeof(u16); + + /* Determine fragmentation size based on destination (multicast + * and broadcast are not fragmented) */ + // if (is_multicast_ether_addr(dest) || + // is_broadcast_ether_addr(dest)) { + if (is_multicast_ether_addr(header->addr1) || + is_broadcast_ether_addr(header->addr1)) { + frag_size = MAX_FRAG_THRESHOLD; + QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; + } + else { + //printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size); + frag_size = ieee->fts;//default:392 + QOS_ctl = 0; + } + + if(isQoS) { + QOS_ctl |= skb->priority; //set in the ieee80211_classify + *pQOS_ctl = cpu_to_le16(QOS_ctl); + } + //printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl); + /* Determine amount of payload per fragment. Regardless of if + * this stack is providing the full 802.11 header, one will + * eventually be affixed to this fragment -- so we must account for + * it when determining the amount of payload space. */ + //bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0)); + bytes_per_frag = frag_size - hdr_len; + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + bytes_per_frag -= IEEE80211_FCS_LEN; + + /* Each fragment may need to have room for encryptiong pre/postfix */ + if (isEncrypt) + bytes_per_frag -= crypt->ops->extra_prefix_len + + crypt->ops->extra_postfix_len; + + /* Number of fragments is the total bytes_per_frag / + * payload_per_fragment */ + nr_frags = bytes / bytes_per_frag; + bytes_last_frag = bytes % bytes_per_frag; + if (bytes_last_frag) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + + /* When we allocate the TXB we allocate enough space for the reserve + * and full fragment bytes (bytes_per_frag doesn't include prefix, + * postfix, header, FCS, etc.) */ + txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); + if (unlikely(!txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + return NULL; + } + txb->encrypted = isEncrypt; + txb->payload_size = bytes; + + for (i = 0; i < nr_frags; i++) { + skb_frag = txb->fragments[i]; + skb_frag->priority = UP2AC(skb->priority); + if (isEncrypt) + skb_reserve(skb_frag, crypt->ops->extra_prefix_len); + + frag_hdr = (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); + memcpy(frag_hdr, (void *)header, hdr_len); + + /* If this is not the last fragment, then add the MOREFRAGS + * bit to the frame control */ + if (i != nr_frags - 1) { + frag_hdr->frame_ctl = cpu_to_le16( + header->frame_ctl | IEEE80211_FCTL_MOREFRAGS); + bytes = bytes_per_frag; + + } else { + /* The last fragment takes the remaining length */ + bytes = bytes_last_frag; + } + + frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); + //frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i); + // + + /* Put a SNAP header on the first fragment */ + if (i == 0) { + ieee80211_put_snap( + skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), ether_type); + bytes -= SNAP_SIZE + sizeof(u16); + } + + memcpy(skb_put(skb_frag, bytes), skb->data, bytes); + + /* Advance the SKB... */ + skb_pull(skb, bytes); + + /* Encryption routine will move the header forward in order + * to insert the IV between the header and the payload */ + if (isEncrypt) + ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + } + // Advance sequence number in data frame. + //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + // stanley, just for debug +/* +{ + int j=0; + for(j=0;j<nr_frags;j++) + { + int i; + struct sk_buff *skb = txb->fragments[j]; + printk("send(%d): ", j); + for (i=0;i<skb->len;i++) + printk("%02X ", skb->data[i]&0xff); + printk("\n"); + } +} +*/ + + return txb; +} + + +// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held +// Assume no encryption, no FCS computing +struct ieee80211_txb *ieee80211_ext_reuse_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + struct ieee80211_device *ieee = netdev_priv(dev); +#else + struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; +#endif + struct ieee80211_txb *txb = NULL; + struct ieee80211_hdr_3addr *frag_hdr; + int ether_type; + int bytes, QOS_ctl; + + ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); + + /* Advance the SKB to the start of the payload */ + skb_pull(skb, sizeof(struct ethhdr)); + + /* Determine total amount of storage required for TXB packets */ + bytes = skb->len + SNAP_SIZE + sizeof(u16); + + if (is_multicast_ether_addr(header->addr1) || + is_broadcast_ether_addr(header->addr1)) { + QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; + } + else { + QOS_ctl = 0; + } + + if(isQoS) { + QOS_ctl |= skb->priority; //set in the ieee80211_classify + *pQOS_ctl = cpu_to_le16(QOS_ctl); + } + + txb = kmalloc( sizeof(struct ieee80211_txb) + sizeof(u8*), GFP_ATOMIC ); + if (unlikely(!txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + return NULL; + } + + txb->nr_frags = 1; + txb->frag_size = bytes; + txb->encrypted = isEncrypt; + txb->payload_size = bytes; + + txb->fragments[0] = skb; + ieee80211_put_snap( + skb_push(skb, SNAP_SIZE + sizeof(u16)), ether_type); + frag_hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, hdr_len); + memcpy(frag_hdr, (void *)header, hdr_len); + frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | 0); + skb->priority = UP2AC(skb->priority); + + // Advance sequence number in data frame. + //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + return txb; +} + +#endif // _RTL8187_EXT_PATCH_ + +/* SKBs are added to the ieee->tx_queue. */ +int ieee80211_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + struct ieee80211_txb *txb = NULL; + struct ieee80211_hdr_3addr_QOS *frag_hdr; + int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; + unsigned long flags; + struct net_device_stats *stats = &ieee->stats; + int ether_type, encrypt; + int bytes, fc, QOS_ctl, hdr_len; + struct sk_buff *skb_frag; + //struct ieee80211_hdr header = { /* Ensure zero initialized */ + // .duration_id = 0, + // .seq_ctl = 0 + //}; + struct ieee80211_hdr_3addr_QOS header = { /* Ensure zero initialized */ + .duration_id = 0, + .seq_ctl = 0, + .QOS_ctl = 0 + }; + u8 dest[ETH_ALEN], src[ETH_ALEN]; + + struct ieee80211_crypt_data* crypt; + + //printk(KERN_WARNING "upper layer packet!\n"); + spin_lock_irqsave(&ieee->lock, flags); + + /* If there is no driver handler to take the TXB, dont' bother + * creating it... */ + if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))|| + ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { + printk(KERN_WARNING "%s: No xmit handler.\n", + ieee->dev->name); + goto success; + } + + ieee80211_classify(skb,&ieee->current_network); + if(likely(ieee->raw_tx == 0)){ + + if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { + printk(KERN_WARNING "%s: skb too small (%d).\n", + ieee->dev->name, skb->len); + goto success; + } + + +#ifdef _RTL8187_EXT_PATCH_ + // note, skb->priority which was set by ieee80211_classify, and used by physical tx + if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_xmit)) + { + txb = ieee->ext_patch_ieee80211_xmit(skb, dev); + goto success; + } +#endif + + ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); + + crypt = ieee->crypt[ieee->tx_keyidx]; + + encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && + ieee->host_encrypt && crypt && crypt->ops; + + if (!encrypt && ieee->ieee802_1x && + ieee->drop_unencrypted && ether_type != ETH_P_PAE) { + stats->tx_dropped++; + goto success; + } + + #ifdef CONFIG_IEEE80211_DEBUG + if (crypt && !encrypt && ether_type == ETH_P_PAE) { + struct eapol *eap = (struct eapol *)(skb->data + + sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16)); + IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n", + eap_get_type(eap->type)); + } + #endif + + /* Save source and destination addresses */ + memcpy(&dest, skb->data, ETH_ALEN); + memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN); + + /* Advance the SKB to the start of the payload */ + skb_pull(skb, sizeof(struct ethhdr)); + + /* Determine total amount of storage required for TXB packets */ + bytes = skb->len + SNAP_SIZE + sizeof(u16); + + if(ieee->current_network.QoS_Enable) { + if (encrypt) + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA | + IEEE80211_FCTL_WEP; + else + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA; + + } else { + if (encrypt) + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | + IEEE80211_FCTL_WEP; + else + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + } + + if (ieee->iw_mode == IW_MODE_INFRA) { + fc |= IEEE80211_FCTL_TODS; + /* To DS: Addr1 = BSSID, Addr2 = SA, + Addr3 = DA */ + memcpy(&header.addr1, ieee->current_network.bssid, ETH_ALEN); + memcpy(&header.addr2, &src, ETH_ALEN); + memcpy(&header.addr3, &dest, ETH_ALEN); + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, + Addr3 = BSSID */ + memcpy(&header.addr1, dest, ETH_ALEN); + memcpy(&header.addr2, src, ETH_ALEN); + memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN); + } + // printk(KERN_WARNING "essid MAC address is "MAC_FMT, MAC_ARG(&header.addr1)); + header.frame_ctl = cpu_to_le16(fc); + //hdr_len = IEEE80211_3ADDR_LEN; + + /* Determine fragmentation size based on destination (multicast + * and broadcast are not fragmented) */ +// if (is_multicast_ether_addr(dest) || +// is_broadcast_ether_addr(dest)) { + if (is_multicast_ether_addr(header.addr1) || + is_broadcast_ether_addr(header.addr1)) { + frag_size = MAX_FRAG_THRESHOLD; + QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; + } + else { + //printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size); + frag_size = ieee->fts;//default:392 + QOS_ctl = 0; + } + + if (ieee->current_network.QoS_Enable) { + hdr_len = IEEE80211_3ADDR_LEN + 2; + QOS_ctl |= skb->priority; //set in the ieee80211_classify + header.QOS_ctl = cpu_to_le16(QOS_ctl); + } else { + hdr_len = IEEE80211_3ADDR_LEN; + } + //printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl); + /* Determine amount of payload per fragment. Regardless of if + * this stack is providing the full 802.11 header, one will + * eventually be affixed to this fragment -- so we must account for + * it when determining the amount of payload space. */ + //bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0)); + bytes_per_frag = frag_size - hdr_len; + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + bytes_per_frag -= IEEE80211_FCS_LEN; + + /* Each fragment may need to have room for encryptiong pre/postfix */ + if (encrypt) + bytes_per_frag -= crypt->ops->extra_prefix_len + + crypt->ops->extra_postfix_len; + + /* Number of fragments is the total bytes_per_frag / + * payload_per_fragment */ + nr_frags = bytes / bytes_per_frag; + bytes_last_frag = bytes % bytes_per_frag; + if (bytes_last_frag) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + + /* When we allocate the TXB we allocate enough space for the reserve + * and full fragment bytes (bytes_per_frag doesn't include prefix, + * postfix, header, FCS, etc.) */ + txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); + if (unlikely(!txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + goto failed; + } + txb->encrypted = encrypt; + txb->payload_size = bytes; + + for (i = 0; i < nr_frags; i++) { + skb_frag = txb->fragments[i]; + skb_frag->priority = UP2AC(skb->priority); + if (encrypt) + skb_reserve(skb_frag, crypt->ops->extra_prefix_len); + + frag_hdr = (struct ieee80211_hdr_3addr_QOS *)skb_put(skb_frag, hdr_len); + memcpy(frag_hdr, &header, hdr_len); + + /* If this is not the last fragment, then add the MOREFRAGS + * bit to the frame control */ + if (i != nr_frags - 1) { + frag_hdr->frame_ctl = cpu_to_le16( + fc | IEEE80211_FCTL_MOREFRAGS); + bytes = bytes_per_frag; + + } else { + /* The last fragment takes the remaining length */ + bytes = bytes_last_frag; + } + if(ieee->current_network.QoS_Enable) { + // add 1 only indicate to corresponding seq number control 2006/7/12 + frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i); + //printk(KERN_WARNING "skb->priority = %d,", skb->priority); + //printk(KERN_WARNING "type:%d: seq = %d\n",UP2AC(skb->priority),ieee->seq_ctrl[UP2AC(skb->priority)+1]); + } else { + frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); + } + //frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i); + // + + /* Put a SNAP header on the first fragment */ + if (i == 0) { + ieee80211_put_snap( + skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), + ether_type); + bytes -= SNAP_SIZE + sizeof(u16); + } + + memcpy(skb_put(skb_frag, bytes), skb->data, bytes); + + /* Advance the SKB... */ + skb_pull(skb, bytes); + + /* Encryption routine will move the header forward in order + * to insert the IV between the header and the payload */ + if (encrypt) + ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + } + // Advance sequence number in data frame. + //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); + if (ieee->current_network.QoS_Enable) { + if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) + ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; + else + ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; + } else { + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + } + //--- + }else{ + if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) { + printk(KERN_WARNING "%s: skb too small (%d).\n", + ieee->dev->name, skb->len); + goto success; + } + + txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC); + if(!txb){ + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + goto failed; + } + + txb->encrypted = 0; + txb->payload_size = skb->len; + memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len); + } + + success: + spin_unlock_irqrestore(&ieee->lock, flags); +#ifdef _RTL8187_EXT_PATCH_ + // Sometimes, extension mode can reuse skb (by txb->fragments[0]) + if( ! ((ieee->iw_mode == ieee->iw_ext_mode) && txb && (txb->fragments[0] == skb)) ) +#endif + dev_kfree_skb_any(skb); + if (txb) { + if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE){ + ieee80211_softmac_xmit(txb, ieee); + }else{ + if ((*ieee->hard_start_xmit)(txb, dev) == 0) { + stats->tx_packets++; + stats->tx_bytes += txb->payload_size; + return 0; + } + ieee80211_txb_free(txb); + } + } + + return 0; + + failed: + spin_unlock_irqrestore(&ieee->lock, flags); + netif_stop_queue(dev); + stats->tx_errors++; + return 1; + +} + +#if 0 +EXPORT_SYMBOL(ieee80211_txb_free); +#ifdef _RTL8187_EXT_PATCH_ +EXPORT_SYMBOL(ieee80211_alloc_txb); +EXPORT_SYMBOL(ieee80211_ext_alloc_txb); +EXPORT_SYMBOL(ieee80211_ext_reuse_txb); +#endif // _RTL8187_EXT_PATCH_ +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c new file mode 100644 index 0000000..c7d9f4f --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c @@ -0,0 +1,884 @@ +/****************************************************************************** + + Copyright(c) 2004 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + <jkmaline@cc.hut.fi> + Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + + 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., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos <ipw2100-admin@linux.intel.com> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include <linux/wireless.h> +#include <linux/version.h> +#include <linux/kmod.h> +#include <linux/module.h> + +#include "ieee80211.h" +static const char *ieee80211_modes[] = { + "?", "a", "b", "ab", "g", "ag", "bg", "abg" +}; + +#ifdef FEDORACORE_9 +#define IN_FEDORACORE_9 1 +#else +#define IN_FEDORACORE_9 0 +#endif + +#define MAX_CUSTOM_LEN 64 +static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee, + char *start, char *stop, + struct ieee80211_network *network, + struct iw_request_info *info) +{ + char custom[MAX_CUSTOM_LEN]; + char *p; + struct iw_event iwe; + int i, j; + u8 max_rate, rate; + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); +#else + start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); +#endif + + /* Remaining entries will be displayed in the order we provide them */ + + /* Add the ESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + //YJ,modified,080903,for hidden ap + //if (network->flags & NETWORK_EMPTY_ESSID) { + if (network->ssid_len == 0) { + //YJ,modified,080903,end + iwe.u.data.length = sizeof("<hidden>"); +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>"); +#else + start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); +#endif + } else { + iwe.u.data.length = min(network->ssid_len, (u8)32); +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); +#else + start = iwe_stream_add_point(start, stop, &iwe, network->ssid); +#endif + } + //printk("ESSID: %s\n",network->ssid); + /* Add the protocol name */ + iwe.cmd = SIOCGIWNAME; + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]); +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); +#else + start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); +#endif + + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + if (network->capability & + (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) { + if (network->capability & WLAN_CAPABILITY_BSS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); +#else + start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); +#endif + } + + /* Add frequency/channel */ + iwe.cmd = SIOCGIWFREQ; +/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); + iwe.u.freq.e = 3; */ + iwe.u.freq.m = network->channel; + iwe.u.freq.e = 0; + iwe.u.freq.i = 0; +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); +#else + start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); +#endif + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (network->capability & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); +#else + start = iwe_stream_add_point(start, stop, &iwe, network->ssid); +#endif + + /* Add basic and extended rates */ + max_rate = 0; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); + for (i = 0, j = 0; i < network->rates_len; ) { + if (j < network->rates_ex_len && + ((network->rates_ex[j] & 0x7F) < + (network->rates[i] & 0x7F))) + rate = network->rates_ex[j++] & 0x7F; + else + rate = network->rates[i++] & 0x7F; + if (rate > max_rate) + max_rate = rate; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); + } + for (; j < network->rates_ex_len; j++) { + rate = network->rates_ex[j] & 0x7F; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); + if (rate > max_rate) + max_rate = rate; + } + + iwe.cmd = SIOCGIWRATE; + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.value = max_rate * 500000; +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); +#else + start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN); +#endif + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = p - custom; + if (iwe.u.data.length) +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); +#else + start = iwe_stream_add_point(start, stop, &iwe, custom); +#endif + + /* Add quality statistics */ + /* TODO: Fix these values... */ + if (network->stats.signal == 0 || network->stats.rssi == 0) + printk("========>signal:%d, rssi:%d\n", network->stats.signal, network->stats.rssi); + iwe.cmd = IWEVQUAL; +// printk("SIGNAL: %d,RSSI: %d,NOISE: %d\n",network->stats.signal,network->stats.rssi,network->stats.noise); + iwe.u.qual.qual = network->stats.signalstrength; + iwe.u.qual.level = network->stats.signal; + iwe.u.qual.noise = network->stats.noise; + iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; + if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) + iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; + if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) + iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; + if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) + iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; + iwe.u.qual.updated = 7; +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); +#else + start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); +#endif + + iwe.cmd = IWEVCUSTOM; + p = custom; + + iwe.u.data.length = p - custom; + if (iwe.u.data.length) +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); +#else + start = iwe_stream_add_point(start, stop, &iwe, custom); +#endif + +#if 0 + if (ieee->wpa_enabled && network->wpa_ie_len){ + char buf[MAX_WPA_IE_LEN * 2 + 30]; + // printk("WPA IE\n"); + u8 *p = buf; + p += sprintf(p, "wpa_ie="); + for (i = 0; i < network->wpa_ie_len; i++) { + p += sprintf(p, "%02x", network->wpa_ie[i]); + } + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, buf); +#else + start = iwe_stream_add_point(start, stop, &iwe, buf); +#endif + } + + if (ieee->wpa_enabled && network->rsn_ie_len){ + char buf[MAX_WPA_IE_LEN * 2 + 30]; + + u8 *p = buf; + p += sprintf(p, "rsn_ie="); + for (i = 0; i < network->rsn_ie_len; i++) { + p += sprintf(p, "%02x", network->rsn_ie[i]); + } + + +#else + memset(&iwe, 0, sizeof(iwe)); + if (network->wpa_ie_len) { + // printk("wpa_ie_len:%d\n", network->wpa_ie_len); + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->wpa_ie, network->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->wpa_ie_len; +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, buf); +#else + start = iwe_stream_add_point(start, stop, &iwe, buf); +#endif + } + + memset(&iwe, 0, sizeof(iwe)); + if (network->rsn_ie_len) { + // printk("=====>rsn_ie_len:\n", network->rsn_ie_len); + #if 0 + { + int i; + for (i=0; i<network->rsn_ie_len; i++); + printk("%2x ", network->rsn_ie[i]); + printk("\n"); + } + #endif + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->rsn_ie, network->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->rsn_ie_len; +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, buf); +#else + start = iwe_stream_add_point(start, stop, &iwe, buf); +#endif + } + +#endif + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); + iwe.u.data.length = p - custom; + if (iwe.u.data.length) +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); +#else + start = iwe_stream_add_point(start, stop, &iwe, custom); +#endif + + return start; +} + +int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ieee80211_network *network; + unsigned long flags; + int err = 0; + char *ev = extra; + char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA; + //char *stop = ev + IW_SCAN_MAX_DATA; + int i = 0; + + IEEE80211_DEBUG_WX("Getting scan\n"); + down(&ieee->wx_sem); + spin_lock_irqsave(&ieee->lock, flags); + + if(!ieee->bHwRadioOff) + { + list_for_each_entry(network, &ieee->network_list, list) { + i++; + + if((stop-ev)<200) + { + err = -E2BIG; + break; + } + if (ieee->scan_age == 0 || + time_after(network->last_scanned + ieee->scan_age, jiffies)) + { + ev = rtl818x_translate_scan(ieee, ev, stop, network, info); + } + else + IEEE80211_DEBUG_SCAN( + "Not showing network '%s (" + MAC_FMT ")' due to age (%lums).\n", + escape_essid(network->ssid, + network->ssid_len), + MAC_ARG(network->bssid), + (jiffies - network->last_scanned) / (HZ / 100)); + } + } + spin_unlock_irqrestore(&ieee->lock, flags); + up(&ieee->wx_sem); + wrqu->data.length = ev - extra; + wrqu->data.flags = 0; + IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); + + return err; +} + +int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + struct net_device *dev = ieee->dev; + struct ieee80211_security sec = { + .flags = 0 + }; + int i, key, key_provided, len; + struct ieee80211_crypt_data **crypt; + + IEEE80211_DEBUG_WX("SET_ENCODE\n"); + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + key_provided = 1; + } else { + key_provided = 0; + key = ieee->tx_keyidx; + } + + IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? + "provided" : "default"); + + crypt = &ieee->crypt[key]; + + if (erq->flags & IW_ENCODE_DISABLED) { + if (key_provided && *crypt) { + IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", + key); + ieee80211_crypt_delayed_deinit(ieee, crypt); + } else + IEEE80211_DEBUG_WX("Disabling encryption.\n"); + + /* Check all the keys to see if any are still configured, + * and if no key index was provided, de-init them all */ + for (i = 0; i < WEP_KEYS; i++) { + if (ieee->crypt[i] != NULL) { + if (key_provided) + break; + ieee80211_crypt_delayed_deinit( + ieee, &ieee->crypt[i]); + } + } + + if (i == WEP_KEYS) { + sec.enabled = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL; + } + + goto done; + } + + + + sec.enabled = 1; + sec.flags |= SEC_ENABLED; + + if (*crypt != NULL && (*crypt)->ops != NULL && + strcmp((*crypt)->ops->name, "WEP") != 0) { + /* changing to use WEP; deinit previously used algorithm + * on this key */ + ieee80211_crypt_delayed_deinit(ieee, crypt); + } + + if (*crypt == NULL) { + struct ieee80211_crypt_data *new_crypt; + + /* take WEP into use */ + new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data), + GFP_KERNEL); + if (new_crypt == NULL) + return -ENOMEM; + memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); + new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + if (!new_crypt->ops) { + request_module("ieee80211_crypt_wep"); + new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + } + + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(key); + + if (!new_crypt->ops || !new_crypt->priv) { + kfree(new_crypt); + new_crypt = NULL; + + printk(KERN_WARNING "%s: could not initialize WEP: " + "load module ieee80211_crypt_wep\n", + dev->name); + return -EOPNOTSUPP; + } + *crypt = new_crypt; + } + + /* If a new key was provided, set it up */ + if (erq->length > 0) { + len = erq->length <= 5 ? 5 : 13; + memcpy(sec.keys[key], keybuf, erq->length); + if (len > erq->length) + memset(sec.keys[key] + erq->length, 0, + len - erq->length); + IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", + key, escape_essid(sec.keys[key], len), + erq->length, len); + sec.key_sizes[key] = len; + (*crypt)->ops->set_key(sec.keys[key], len, NULL, + (*crypt)->priv); + sec.flags |= (1 << key); + /* This ensures a key will be activated if no key is + * explicitely set */ + if (key == sec.active_key) + sec.flags |= SEC_ACTIVE_KEY; + ieee->tx_keyidx = key;//by wb 080312 + } else { + len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, + NULL, (*crypt)->priv); + if (len == 0) { + /* Set a default key of all 0 */ + IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", + key); + memset(sec.keys[key], 0, 13); + (*crypt)->ops->set_key(sec.keys[key], 13, NULL, + (*crypt)->priv); + sec.key_sizes[key] = 13; + sec.flags |= (1 << key); + } + + /* No key data - just set the default TX key index */ + if (key_provided) { + IEEE80211_DEBUG_WX( + "Setting key %d to default Tx key.\n", key); + ieee->tx_keyidx = key; + sec.active_key = key; + sec.flags |= SEC_ACTIVE_KEY; + } + } + + done: + ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); + sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; + sec.flags |= SEC_AUTH_MODE; + IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? + "OPEN" : "SHARED KEY"); + + /* For now we just support WEP, so only set that security level... + * TODO: When WPA is added this is one place that needs to change */ + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ + + if (ieee->set_security) + ieee->set_security(dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); + return -EINVAL; + } + return 0; +} + +int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + int len, key; + struct ieee80211_crypt_data *crypt; + + IEEE80211_DEBUG_WX("GET_ENCODE\n"); + + if(ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + } else + key = ieee->tx_keyidx; + + crypt = ieee->crypt[key]; + erq->flags = key + 1; + + if (crypt == NULL || crypt->ops == NULL) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + + if (strcmp(crypt->ops->name, "WEP") != 0) { + /* only WEP is supported with wireless extensions, so just + * report that encryption is used */ + erq->length = 0; + erq->flags |= IW_ENCODE_ENABLED; + return 0; + } + + len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); + erq->length = (len >= 0 ? len : 0); + + erq->flags |= IW_ENCODE_ENABLED; + + if (ieee->open_wep) + erq->flags |= IW_ENCODE_OPEN; + else + erq->flags |= IW_ENCODE_RESTRICTED; + + return 0; +} + +int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct net_device *dev = ieee->dev; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int i, idx, ret = 0; + int group_key = 0; + const char *alg, *module; + struct ieee80211_crypto_ops *ops; + struct ieee80211_crypt_data **crypt; + + struct ieee80211_security sec = { + .flags = 0, + }; + //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg); + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > WEP_KEYS) + return -EINVAL; + idx--; + } else + idx = ieee->tx_keyidx; + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + crypt = &ieee->crypt[idx]; + group_key = 1; + } else { + /* some Cisco APs use idx>0 for unicast in dynamic WEP */ + //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg); + if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) + return -EINVAL; + if (ieee->iw_mode == IW_MODE_INFRA) + crypt = &ieee->crypt[idx]; + else + return -EINVAL; + } + + sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT; + if ((encoding->flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE) { + if (*crypt) + ieee80211_crypt_delayed_deinit(ieee, crypt); + + for (i = 0; i < WEP_KEYS; i++) + if (ieee->crypt[i] != NULL) + break; + + if (i == WEP_KEYS) { + sec.enabled = 0; + // sec.encrypt = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_LEVEL; + } + //printk("disabled: flag:%x\n", encoding->flags); + goto done; + } + + sec.enabled = 1; + // sec.encrypt = 1; +#if 0 + if (group_key ? !ieee->host_mc_decrypt : + !(ieee->host_encrypt || ieee->host_decrypt || + ieee->host_encrypt_msdu)) + goto skip_host_crypt; +#endif + switch (ext->alg) { + case IW_ENCODE_ALG_WEP: + alg = "WEP"; + module = "ieee80211_crypt_wep"; + break; + case IW_ENCODE_ALG_TKIP: + alg = "TKIP"; + module = "ieee80211_crypt_tkip"; + break; + case IW_ENCODE_ALG_CCMP: + alg = "CCMP"; + module = "ieee80211_crypt_ccmp"; + break; + default: + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + ret = -EINVAL; + goto done; + } +// printk("8-09-08-9=====>%s, alg name:%s\n",__FUNCTION__, alg); + + ops = ieee80211_get_crypto_ops(alg); + if (ops == NULL) { + request_module(module); + ops = ieee80211_get_crypto_ops(alg); + } + if (ops == NULL) { + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + printk("========>unknown crypto alg %d\n", ext->alg); + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct ieee80211_crypt_data *new_crypt; + + ieee80211_crypt_delayed_deinit(ieee, crypt); + + new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + new_crypt->ops = ops; + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(idx); + if (new_crypt->priv == NULL) { + kfree(new_crypt); + ret = -EINVAL; + goto done; + } + *crypt = new_crypt; + + } + + if (ext->key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, + (*crypt)->priv) < 0) { + IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); + printk("key setting failed\n"); + ret = -EINVAL; + goto done; + } +#if 1 + //skip_host_crypt: + //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags); + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + ieee->tx_keyidx = idx; + sec.active_key = idx; + sec.flags |= SEC_ACTIVE_KEY; + } + + if (ext->alg != IW_ENCODE_ALG_NONE) { + memcpy(sec.keys[idx], ext->key, ext->key_len); + sec.key_sizes[idx] = ext->key_len; + sec.flags |= (1 << idx); + if (ext->alg == IW_ENCODE_ALG_WEP) { + // sec.encode_alg[idx] = SEC_ALG_WEP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (ext->alg == IW_ENCODE_ALG_TKIP) { + // sec.encode_alg[idx] = SEC_ALG_TKIP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (ext->alg == IW_ENCODE_ALG_CCMP) { + // sec.encode_alg[idx] = SEC_ALG_CCMP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + /* Don't set sec level for group keys. */ + if (group_key) + sec.flags &= ~SEC_LEVEL; + } +#endif +done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); + return -EINVAL; + } + + return ret; +} +int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_mlme *mlme = (struct iw_mlme *) extra; +// printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __FUNCTION__, mlme->cmd); +#if 1 + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + case IW_MLME_DISASSOC: + // printk("disassoc now\n"); + ieee80211_disassociate(ieee); + break; + default: + return -EOPNOTSUPP; + } +#endif + return 0; +} + +int ieee80211_wx_set_auth(struct ieee80211_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ +/* + struct ieee80211_security sec = { + .flags = SEC_AUTH_MODE, + } +*/ + //printk("set auth:flag:%x, data value:%x\n", data->flags, data->value); + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + /*need to support wpa2 here*/ + //printk("wpa version:%x\n", data->value); + break; + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * * Host AP driver does not use these parameters and allows + * * wpa_supplicant to control them internally. + * */ + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + ieee->tkip_countermeasures = data->value; + break; + case IW_AUTH_DROP_UNENCRYPTED: + ieee->drop_unencrypted = data->value; + break; + + case IW_AUTH_80211_AUTH_ALG: + ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0; + //printk("open_wep:%d\n", ieee->open_wep); + break; + +#if 1 + case IW_AUTH_WPA_ENABLED: + ieee->wpa_enabled = (data->value)?1:0; + //printk("enalbe wpa:%d\n", ieee->wpa_enabled); + break; + +#endif + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = data->value; + break; + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = data->value; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +#if 1 +int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) +{ +#if 0 + printk("====>%s()\n", __FUNCTION__); + { + int i; + for (i=0; i<len; i++) + printk("%2x ", ie[i]&0xff); + printk("\n"); + } +#endif + u8 *buf = NULL; + + if (len>MAX_WPA_IE_LEN || (len && ie == NULL)) + { + printk("return error out, len:%d\n", len); + return -EINVAL; + } + + if (len) + { + if (len != ie[1]+2){ + printk("len:%d, ie:%d\n", len, ie[1]); + return -EINVAL; + } + buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + memcpy(buf, ie, len); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = len; + } + else{ + if (ieee->wpa_ie) + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } +// printk("<=====out %s()\n", __FUNCTION__); + + return 0; + +} +#endif + +#if 0 +EXPORT_SYMBOL(ieee80211_wx_set_gen_ie); +EXPORT_SYMBOL(ieee80211_wx_set_mlme); +EXPORT_SYMBOL(ieee80211_wx_set_auth); +EXPORT_SYMBOL(ieee80211_wx_set_encode_ext); +EXPORT_SYMBOL(ieee80211_wx_get_scan); +EXPORT_SYMBOL(ieee80211_wx_set_encode); +EXPORT_SYMBOL(ieee80211_wx_get_encode); +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/internal.h b/drivers/staging/rtl8187se/ieee80211/internal.h new file mode 100644 index 0000000..ddc2235 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/internal.h @@ -0,0 +1,115 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#ifndef _CRYPTO_INTERNAL_H +#define _CRYPTO_INTERNAL_H + + +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/init.h> +#include <asm/hardirq.h> +#include <asm/softirq.h> +#include <asm/kmap_types.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)) +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +static inline void cond_resched(void) +{ + if (need_resched()) { + set_current_state(TASK_RUNNING); + schedule(); + } +} +#endif + +extern enum km_type crypto_km_types[]; + +static inline enum km_type crypto_kmap_type(int out) +{ + return crypto_km_types[(in_softirq() ? 2 : 0) + out]; +} + +static inline void *crypto_kmap(struct page *page, int out) +{ + return kmap_atomic(page, crypto_kmap_type(out)); +} + +static inline void crypto_kunmap(void *vaddr, int out) +{ + kunmap_atomic(vaddr, crypto_kmap_type(out)); +} + +static inline void crypto_yield(struct crypto_tfm *tfm) +{ + if (!in_softirq()) + cond_resched(); +} + +static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) +{ + return (void *)&tfm[1]; +} + +struct crypto_alg *crypto_alg_lookup(const char *name); + +#ifdef CONFIG_KMOD +void crypto_alg_autoload(const char *name); +struct crypto_alg *crypto_alg_mod_lookup(const char *name); +#else +static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) +{ + return crypto_alg_lookup(name); +} +#endif + +#ifdef CONFIG_CRYPTO_HMAC +int crypto_alloc_hmac_block(struct crypto_tfm *tfm); +void crypto_free_hmac_block(struct crypto_tfm *tfm); +#else +static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm) +{ + return 0; +} + +static inline void crypto_free_hmac_block(struct crypto_tfm *tfm) +{ } +#endif + +#ifdef CONFIG_PROC_FS +void __init crypto_init_proc(void); +#else +static inline void crypto_init_proc(void) +{ } +#endif + +int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); +int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); +int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); + +int crypto_init_digest_ops(struct crypto_tfm *tfm); +int crypto_init_cipher_ops(struct crypto_tfm *tfm); +int crypto_init_compress_ops(struct crypto_tfm *tfm); + +void crypto_exit_digest_ops(struct crypto_tfm *tfm); +void crypto_exit_cipher_ops(struct crypto_tfm *tfm); +void crypto_exit_compress_ops(struct crypto_tfm *tfm); + +#endif /* _CRYPTO_INTERNAL_H */ + diff --git a/drivers/staging/rtl8187se/ieee80211/kmap_types.h b/drivers/staging/rtl8187se/ieee80211/kmap_types.h new file mode 100644 index 0000000..de67bb0 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/kmap_types.h @@ -0,0 +1,20 @@ +#ifndef __KMAP_TYPES_H + +#define __KMAP_TYPES_H + + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; + +#define _ASM_KMAP_TYPES_H + +#endif diff --git a/drivers/staging/rtl8187se/ieee80211/michael_mic.c b/drivers/staging/rtl8187se/ieee80211/michael_mic.c new file mode 100644 index 0000000..df256e4 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/michael_mic.c @@ -0,0 +1,194 @@ +/* + * Cryptographic API + * + * Michael MIC (IEEE 802.11i/TKIP) keyed digest + * + * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/string.h> +//#include <linux/crypto.h> +#include "rtl_crypto.h" + + +struct michael_mic_ctx { + u8 pending[4]; + size_t pending_len; + + u32 l, r; +}; + + +static inline u32 rotl(u32 val, int bits) +{ + return (val << bits) | (val >> (32 - bits)); +} + + +static inline u32 rotr(u32 val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + + +static inline u32 xswap(u32 val) +{ + return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); +} + + +#define michael_block(l, r) \ +do { \ + r ^= rotl(l, 17); \ + l += r; \ + r ^= xswap(l); \ + l += r; \ + r ^= rotl(l, 3); \ + l += r; \ + r ^= rotr(l, 2); \ + l += r; \ +} while (0) + + +static inline u32 get_le32(const u8 *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + + +static inline void put_le32(u8 *p, u32 v) +{ + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +} + + +static void michael_init(void *ctx) +{ + struct michael_mic_ctx *mctx = ctx; + mctx->pending_len = 0; +} + + +static void michael_update(void *ctx, const u8 *data, unsigned int len) +{ + struct michael_mic_ctx *mctx = ctx; + + if (mctx->pending_len) { + int flen = 4 - mctx->pending_len; + if (flen > len) + flen = len; + memcpy(&mctx->pending[mctx->pending_len], data, flen); + mctx->pending_len += flen; + data += flen; + len -= flen; + + if (mctx->pending_len < 4) + return; + + mctx->l ^= get_le32(mctx->pending); + michael_block(mctx->l, mctx->r); + mctx->pending_len = 0; + } + + while (len >= 4) { + mctx->l ^= get_le32(data); + michael_block(mctx->l, mctx->r); + data += 4; + len -= 4; + } + + if (len > 0) { + mctx->pending_len = len; + memcpy(mctx->pending, data, len); + } +} + + +static void michael_final(void *ctx, u8 *out) +{ + struct michael_mic_ctx *mctx = ctx; + u8 *data = mctx->pending; + + /* Last block and padding (0x5a, 4..7 x 0) */ + switch (mctx->pending_len) { + case 0: + mctx->l ^= 0x5a; + break; + case 1: + mctx->l ^= data[0] | 0x5a00; + break; + case 2: + mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000; + break; + case 3: + mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) | + 0x5a000000; + break; + } + michael_block(mctx->l, mctx->r); + /* l ^= 0; */ + michael_block(mctx->l, mctx->r); + + put_le32(out, mctx->l); + put_le32(out + 4, mctx->r); +} + + +static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen, + u32 *flags) +{ + struct michael_mic_ctx *mctx = ctx; + if (keylen != 8) { + if (flags) + *flags = CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + mctx->l = get_le32(key); + mctx->r = get_le32(key + 4); + return 0; +} + + +static struct crypto_alg michael_mic_alg = { + .cra_name = "michael_mic", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = 8, + .cra_ctxsize = sizeof(struct michael_mic_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = 8, + .dia_init = michael_init, + .dia_update = michael_update, + .dia_final = michael_final, + .dia_setkey = michael_setkey } } +}; + + +static int __init michael_mic_init(void) +{ + return crypto_register_alg(&michael_mic_alg); +} + + +static void __exit michael_mic_exit(void) +{ + crypto_unregister_alg(&michael_mic_alg); +} + + +module_init(michael_mic_init); +module_exit(michael_mic_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Michael MIC"); +MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>"); diff --git a/drivers/staging/rtl8187se/ieee80211/proc.c b/drivers/staging/rtl8187se/ieee80211/proc.c new file mode 100644 index 0000000..4f3f9ed --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/proc.c @@ -0,0 +1,116 @@ +/* + * Scatterlist Cryptographic API. + * + * Procfs information. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include <linux/init.h> +//#include <linux/crypto.h> +#include "rtl_crypto.h" +#include <linux/rwsem.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include "internal.h" + +extern struct list_head crypto_alg_list; +extern struct rw_semaphore crypto_alg_sem; + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + struct list_head *v; + loff_t n = *pos; + + down_read(&crypto_alg_sem); + list_for_each(v, &crypto_alg_list) + if (!n--) + return list_entry(v, struct crypto_alg, cra_list); + return NULL; +} + +static void *c_next(struct seq_file *m, void *p, loff_t *pos) +{ + struct list_head *v = p; + + (*pos)++; + v = v->next; + return (v == &crypto_alg_list) ? + NULL : list_entry(v, struct crypto_alg, cra_list); +} + +static void c_stop(struct seq_file *m, void *p) +{ + up_read(&crypto_alg_sem); +} + +static int c_show(struct seq_file *m, void *p) +{ + struct crypto_alg *alg = (struct crypto_alg *)p; + + seq_printf(m, "name : %s\n", alg->cra_name); + seq_printf(m, "module : %s\n", + (alg->cra_module ? + alg->cra_module->name : + "kernel")); + + switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_CIPHER: + seq_printf(m, "type : cipher\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "min keysize : %u\n", + alg->cra_cipher.cia_min_keysize); + seq_printf(m, "max keysize : %u\n", + alg->cra_cipher.cia_max_keysize); + break; + + case CRYPTO_ALG_TYPE_DIGEST: + seq_printf(m, "type : digest\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "digestsize : %u\n", + alg->cra_digest.dia_digestsize); + break; + case CRYPTO_ALG_TYPE_COMPRESS: + seq_printf(m, "type : compression\n"); + break; + default: + seq_printf(m, "type : unknown\n"); + break; + } + + seq_putc(m, '\n'); + return 0; +} + +static struct seq_operations crypto_seq_ops = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show +}; + +static int crypto_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &crypto_seq_ops); +} + +static struct file_operations proc_crypto_ops = { + .open = crypto_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +void __init crypto_init_proc(void) +{ + struct proc_dir_entry *proc; + + proc = create_proc_entry("crypto", 0, NULL); + if (proc) + proc->proc_fops = &proc_crypto_ops; +} diff --git a/drivers/staging/rtl8187se/ieee80211/rtl_crypto.h b/drivers/staging/rtl8187se/ieee80211/rtl_crypto.h new file mode 100644 index 0000000..9ed0ca4 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/rtl_crypto.h @@ -0,0 +1,399 @@ +/* + * Scatterlist Cryptographic API. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * + * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> + * and Nettle, by Niels Mé°ˆler. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#ifndef _LINUX_CRYPTO_H +#define _LINUX_CRYPTO_H + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/string.h> +#include <asm/page.h> +#include <asm/errno.h> + +#define crypto_register_alg crypto_register_alg_rtl +#define crypto_unregister_alg crypto_unregister_alg_rtl +#define crypto_alloc_tfm crypto_alloc_tfm_rtl +#define crypto_free_tfm crypto_free_tfm_rtl +#define crypto_alg_available crypto_alg_available_rtl + +/* + * Algorithm masks and types. + */ +#define CRYPTO_ALG_TYPE_MASK 0x000000ff +#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 +#define CRYPTO_ALG_TYPE_DIGEST 0x00000002 +#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 + +/* + * Transform masks and values (for crt_flags). + */ +#define CRYPTO_TFM_MODE_MASK 0x000000ff +#define CRYPTO_TFM_REQ_MASK 0x000fff00 +#define CRYPTO_TFM_RES_MASK 0xfff00000 + +#define CRYPTO_TFM_MODE_ECB 0x00000001 +#define CRYPTO_TFM_MODE_CBC 0x00000002 +#define CRYPTO_TFM_MODE_CFB 0x00000004 +#define CRYPTO_TFM_MODE_CTR 0x00000008 + +#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 +#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 +#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 +#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 +#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 +#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 + +/* + * Miscellaneous stuff. + */ +#define CRYPTO_UNSPEC 0 +#define CRYPTO_MAX_ALG_NAME 64 + +struct scatterlist; + +/* + * Algorithms: modular crypto algorithm implementations, managed + * via crypto_register_alg() and crypto_unregister_alg(). + */ +struct cipher_alg { + unsigned int cia_min_keysize; + unsigned int cia_max_keysize; + int (*cia_setkey)(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags); + void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); + void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); +}; + +struct digest_alg { + unsigned int dia_digestsize; + void (*dia_init)(void *ctx); + void (*dia_update)(void *ctx, const u8 *data, unsigned int len); + void (*dia_final)(void *ctx, u8 *out); + int (*dia_setkey)(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags); +}; + +struct compress_alg { + int (*coa_init)(void *ctx); + void (*coa_exit)(void *ctx); + int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define cra_cipher cra_u.cipher +#define cra_digest cra_u.digest +#define cra_compress cra_u.compress + +struct crypto_alg { + struct list_head cra_list; + u32 cra_flags; + unsigned int cra_blocksize; + unsigned int cra_ctxsize; + const char cra_name[CRYPTO_MAX_ALG_NAME]; + + union { + struct cipher_alg cipher; + struct digest_alg digest; + struct compress_alg compress; + } cra_u; + + struct module *cra_module; +}; + +/* + * Algorithm registration interface. + */ +int crypto_register_alg(struct crypto_alg *alg); +int crypto_unregister_alg(struct crypto_alg *alg); + +/* + * Algorithm query interface. + */ +int crypto_alg_available(const char *name, u32 flags); + +/* + * Transforms: user-instantiated objects which encapsulate algorithms + * and core processing logic. Managed via crypto_alloc_tfm() and + * crypto_free_tfm(), as well as the various helpers below. + */ +struct crypto_tfm; + +struct cipher_tfm { + void *cit_iv; + unsigned int cit_ivsize; + u32 cit_mode; + int (*cit_setkey)(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen); + int (*cit_encrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_encrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + int (*cit_decrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_decrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + void (*cit_xor_block)(u8 *dst, const u8 *src); +}; + +struct digest_tfm { + void (*dit_init)(struct crypto_tfm *tfm); + void (*dit_update)(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); + void (*dit_final)(struct crypto_tfm *tfm, u8 *out); + void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, + unsigned int nsg, u8 *out); + int (*dit_setkey)(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen); +#ifdef CONFIG_CRYPTO_HMAC + void *dit_hmac_block; +#endif +}; + +struct compress_tfm { + int (*cot_compress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*cot_decompress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define crt_cipher crt_u.cipher +#define crt_digest crt_u.digest +#define crt_compress crt_u.compress + +struct crypto_tfm { + + u32 crt_flags; + + union { + struct cipher_tfm cipher; + struct digest_tfm digest; + struct compress_tfm compress; + } crt_u; + + struct crypto_alg *__crt_alg; +}; + +/* + * Transform user interface. + */ + +/* + * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm. + * If that fails and the kernel supports dynamically loadable modules, it + * will then attempt to load a module of the same name or alias. A refcount + * is grabbed on the algorithm which is then associated with the new transform. + * + * crypto_free_tfm() frees up the transform and any associated resources, + * then drops the refcount on the associated algorithm. + */ +struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); +void crypto_free_tfm(struct crypto_tfm *tfm); + +/* + * Transform helpers which query the underlying algorithm. + */ +static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_name; +} + +static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + + if (alg->cra_module) + return alg->cra_module->name; + else + return NULL; +} + +static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; +} + +static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_min_keysize; +} + +static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_max_keysize; +} + +static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_ivsize; +} + +static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_blocksize; +} + +static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + return tfm->__crt_alg->cra_digest.dia_digestsize; +} + +/* + * API wrappers. + */ +static inline void crypto_digest_init(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_init(tfm); +} + +static inline void crypto_digest_update(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_update(tfm, sg, nsg); +} + +static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_final(tfm, out); +} + +static inline void crypto_digest_digest(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_digest(tfm, sg, nsg, out); +} + +static inline int crypto_digest_setkey(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + if (tfm->crt_digest.dit_setkey == NULL) + return -ENOSYS; + return tfm->crt_digest.dit_setkey(tfm, key, keylen); +} + +static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_setkey(tfm, key, keylen); +} + +static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); +} + +static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); +} + +static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); +} + +static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); +} + +static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, + const u8 *src, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(tfm->crt_cipher.cit_iv, src, len); +} + +static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, + u8 *dst, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(dst, tfm->crt_cipher.cit_iv, len); +} + +static inline int crypto_comp_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); +} + +static inline int crypto_comp_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); +} + +/* + * HMAC support. + */ +#ifdef CONFIG_CRYPTO_HMAC +void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen); +void crypto_hmac_update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); +void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, + unsigned int *keylen, u8 *out); +void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, + struct scatterlist *sg, unsigned int nsg, u8 *out); +#endif /* CONFIG_CRYPTO_HMAC */ + +#endif /* _LINUX_CRYPTO_H */ + diff --git a/drivers/staging/rtl8187se/ieee80211/scatterwalk.c b/drivers/staging/rtl8187se/ieee80211/scatterwalk.c new file mode 100644 index 0000000..49f401f --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/scatterwalk.c @@ -0,0 +1,126 @@ +/* + * Cryptographic API. + * + * Cipher operations. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * 2002 Adam J. Richter <adam@yggdrasil.com> + * 2004 Jean-Luc Cooke <jlcooke@certainkey.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include "kmap_types.h" + +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/highmem.h> +#include <asm/scatterlist.h> +#include "internal.h" +#include "scatterwalk.h" + +enum km_type crypto_km_types[] = { + KM_USER0, + KM_USER1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, +}; + +void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch) +{ + if (nbytes <= walk->len_this_page && + (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <= + PAGE_CACHE_SIZE) + return walk->data; + else + return scratch; +} + +static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) +{ + if (out) + memcpy(sgdata, buf, nbytes); + else + memcpy(buf, sgdata, nbytes); +} + +void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) +{ + unsigned int rest_of_page; + + walk->sg = sg; + + walk->page = sg->page; + walk->len_this_segment = sg->length; + + rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); + walk->len_this_page = min(sg->length, rest_of_page); + walk->offset = sg->offset; +} + +void scatterwalk_map(struct scatter_walk *walk, int out) +{ + walk->data = crypto_kmap(walk->page, out) + walk->offset; +} + +static void scatterwalk_pagedone(struct scatter_walk *walk, int out, + unsigned int more) +{ + /* walk->data may be pointing the first byte of the next page; + however, we know we transfered at least one byte. So, + walk->data - 1 will be a virtual address in the mapped page. */ + + if (out) + flush_dcache_page(walk->page); + + if (more) { + walk->len_this_segment -= walk->len_this_page; + + if (walk->len_this_segment) { + walk->page++; + walk->len_this_page = min(walk->len_this_segment, + (unsigned)PAGE_CACHE_SIZE); + walk->offset = 0; + } + else + scatterwalk_start(walk, sg_next(walk->sg)); + } +} + +void scatterwalk_done(struct scatter_walk *walk, int out, int more) +{ + crypto_kunmap(walk->data, out); + if (walk->len_this_page == 0 || !more) + scatterwalk_pagedone(walk, out, more); +} + +/* + * Do not call this unless the total length of all of the fragments + * has been verified as multiple of the block size. + */ +int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, + size_t nbytes, int out) +{ + if (buf != walk->data) { + while (nbytes > walk->len_this_page) { + memcpy_dir(buf, walk->data, walk->len_this_page, out); + buf += walk->len_this_page; + nbytes -= walk->len_this_page; + + crypto_kunmap(walk->data, out); + scatterwalk_pagedone(walk, out, 1); + scatterwalk_map(walk, out); + } + + memcpy_dir(buf, walk->data, nbytes, out); + } + + walk->offset += nbytes; + walk->len_this_page -= nbytes; + walk->len_this_segment -= nbytes; + return 0; +} diff --git a/drivers/staging/rtl8187se/ieee80211/scatterwalk.h b/drivers/staging/rtl8187se/ieee80211/scatterwalk.h new file mode 100644 index 0000000..b164465 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/scatterwalk.h @@ -0,0 +1,51 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com> + * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _CRYPTO_SCATTERWALK_H +#define _CRYPTO_SCATTERWALK_H +#include <linux/mm.h> +#include <asm/scatterlist.h> + +struct scatter_walk { + struct scatterlist *sg; + struct page *page; + void *data; + unsigned int len_this_page; + unsigned int len_this_segment; + unsigned int offset; +}; + +/* Define sg_next is an inline routine now in case we want to change + scatterlist to a linked list later. */ +static inline struct scatterlist *sg_next(struct scatterlist *sg) +{ + return sg + 1; +} + +static inline int scatterwalk_samebuf(struct scatter_walk *walk_in, + struct scatter_walk *walk_out, + void *src_p, void *dst_p) +{ + return walk_in->page == walk_out->page && + walk_in->offset == walk_out->offset && + walk_in->data == src_p && walk_out->data == dst_p; +} + +void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch); +void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); +int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); +void scatterwalk_map(struct scatter_walk *walk, int out); +void scatterwalk_done(struct scatter_walk *walk, int out, int more); + +#endif /* _CRYPTO_SCATTERWALK_H */ diff --git a/drivers/staging/rtl8187se/ieee80211_crypt.h b/drivers/staging/rtl8187se/ieee80211_crypt.h new file mode 100644 index 0000000..b58a3bc --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211_crypt.h @@ -0,0 +1,86 @@ +/* + * Original code based on Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * <jkmaline@cc.hut.fi> + * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * <jketreno@linux.intel.com> + * + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +/* + * This file defines the interface to the ieee80211 crypto module. + */ +#ifndef IEEE80211_CRYPT_H +#define IEEE80211_CRYPT_H + +#include <linux/skbuff.h> + +struct ieee80211_crypto_ops { + const char *name; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void * (*init)(int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit)(void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key)(void *key, int len, u8 *seq, void *priv); + int (*get_key)(void *key, int len, u8 *seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + char * (*print_stats)(char *p, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_prefix_len, extra_postfix_len; + + struct module *owner; +}; + +struct ieee80211_crypt_data { + struct list_head list; /* delayed deletion list */ + struct ieee80211_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); +int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); +struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); +void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); +void ieee80211_crypt_deinit_handler(unsigned long); +void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, + struct ieee80211_crypt_data **crypt); + +#endif diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h new file mode 100644 index 0000000..12215fc --- /dev/null +++ b/drivers/staging/rtl8187se/r8180.h @@ -0,0 +1,761 @@ +/* + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official realtek driver + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of those projects and the Ndiswrapper + project Authors. +*/ + +#ifndef R8180H +#define R8180H + + +#define RTL8180_MODULE_NAME "rtl8180" +#define DMESG(x,a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a) +#define DMESGW(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a) +#define DMESGE(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a) + +#include <linux/module.h> +#include <linux/kernel.h> +//#include <linux/config.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/rtnetlink.h> //for rtnl_lock() +#include <linux/wireless.h> +#include <linux/timer.h> +#include <linux/proc_fs.h> // Necessary because we use the proc fs +#include <linux/if_arp.h> +#include "ieee80211.h" +#include <asm/io.h> +//#include <asm/semaphore.h> + +#define EPROM_93c46 0 +#define EPROM_93c56 1 + +#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 + +#define DEFAULT_FRAG_THRESHOLD 2342U +#define MIN_FRAG_THRESHOLD 256U +//#define MAX_FRAG_THRESHOLD 2342U +#define DEFAULT_RTS_THRESHOLD 2342U +#define MIN_RTS_THRESHOLD 0U +#define MAX_RTS_THRESHOLD 2342U +#define DEFAULT_BEACONINTERVAL 0x64U +#define DEFAULT_BEACON_ESSID "Rtl8180" + +#define DEFAULT_SSID "" +#define DEFAULT_RETRY_RTS 7 +#define DEFAULT_RETRY_DATA 7 +#define PRISM_HDR_SIZE 64 + +#ifdef CONFIG_RTL8185B + +#define MGNT_QUEUE 0 +#define BK_QUEUE 1 +#define BE_QUEUE 2 +#define VI_QUEUE 3 +#define VO_QUEUE 4 +#define HIGH_QUEUE 5 +#define BEACON_QUEUE 6 + +#define LOW_QUEUE BE_QUEUE +#define NORMAL_QUEUE MGNT_QUEUE + +#define aSifsTime 10 + +#define sCrcLng 4 +#define sAckCtsLng 112 // bits in ACK and CTS frames +//+by amy 080312 +#define RATE_ADAPTIVE_TIMER_PERIOD 300 + +typedef enum _WIRELESS_MODE { + WIRELESS_MODE_UNKNOWN = 0x00, + WIRELESS_MODE_A = 0x01, + WIRELESS_MODE_B = 0x02, + WIRELESS_MODE_G = 0x04, + WIRELESS_MODE_AUTO = 0x08, +} WIRELESS_MODE; + +typedef enum _VERSION_8185{ + // RTL8185 + VERSION_8185_UNKNOWN, + VERSION_8185_C, // C-cut + VERSION_8185_D, // D-cut + // RTL8185B + VERSION_8185B_B, // B-cut + VERSION_8185B_D, // D-cut + VERSION_8185B_E, // E-cut + //RTL8187S-PCIE + VERSION_8187S_B, // B-cut + VERSION_8187S_C, // C-cut + VERSION_8187S_D, // D-cut + +}VERSION_8185,*PVERSION_8185; +typedef struct ChnlAccessSetting { + u16 SIFS_Timer; + u16 DIFS_Timer; + u16 SlotTimeTimer; + u16 EIFS_Timer; + u16 CWminIndex; + u16 CWmaxIndex; +}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING; + +typedef enum{ + NIC_8185 = 1, + NIC_8185B + } nic_t; + +typedef u32 AC_CODING; +#define AC0_BE 0 // ACI: 0x00 // Best Effort +#define AC1_BK 1 // ACI: 0x01 // Background +#define AC2_VI 2 // ACI: 0x10 // Video +#define AC3_VO 3 // ACI: 0x11 // Voice +#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. + +// +// ECWmin/ECWmax field. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. +// +typedef union _ECW{ + u8 charData; + struct + { + u8 ECWmin:4; + u8 ECWmax:4; + }f; // Field +}ECW, *PECW; + +// +// ACI/AIFSN Field. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. +// +typedef union _ACI_AIFSN{ + u8 charData; + + struct + { + u8 AIFSN:4; + u8 ACM:1; + u8 ACI:2; + u8 Reserved:1; + }f; // Field +}ACI_AIFSN, *PACI_AIFSN; + +// +// AC Parameters Record Format. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. +// +typedef union _AC_PARAM{ + u32 longData; + u8 charData[4]; + + struct + { + ACI_AIFSN AciAifsn; + ECW Ecw; + u16 TXOPLimit; + }f; // Field +}AC_PARAM, *PAC_PARAM; + +/* it is a wrong definition. -xiong-2006-11-17 +typedef struct ThreeWireReg { + u16 longData; + struct { + u8 enableB; + u8 data; + u8 clk; + u8 read_write; + } struc; +} ThreeWireReg; +*/ + +typedef union _ThreeWire{ + struct _ThreeWireStruc{ + u16 data:1; + u16 clk:1; + u16 enableB:1; + u16 read_write:1; + u16 resv1:12; +// u2Byte resv2:14; +// u2Byte ThreeWireEnable:1; +// u2Byte resv3:1; + }struc; + u16 longData; +}ThreeWireReg; + +#endif + +typedef struct buffer +{ + struct buffer *next; + u32 *buf; + dma_addr_t dma; +} buffer; + +//YJ,modified,080828 +typedef struct Stats +{ + unsigned long txrdu; + unsigned long rxrdu; + unsigned long rxnolast; + unsigned long rxnodata; +// unsigned long rxreset; +// unsigned long rxwrkaround; + unsigned long rxnopointer; + unsigned long txnperr; + unsigned long txresumed; + unsigned long rxerr; + unsigned long rxoverflow; + unsigned long rxint; + unsigned long txbkpokint; + unsigned long txbepoking; + unsigned long txbkperr; + unsigned long txbeperr; + unsigned long txnpokint; + unsigned long txhpokint; + unsigned long txhperr; + unsigned long ints; + unsigned long shints; + unsigned long txoverflow; + unsigned long rxdmafail; + unsigned long txbeacon; + unsigned long txbeaconerr; + unsigned long txlpokint; + unsigned long txlperr; + unsigned long txretry;//retry number tony 20060601 + unsigned long rxcrcerrmin;//crc error (0-500) + unsigned long rxcrcerrmid;//crc error (500-1000) + unsigned long rxcrcerrmax;//crc error (>1000) + unsigned long rxicverr;//ICV error +} Stats; + +#define MAX_LD_SLOT_NUM 10 +#define KEEP_ALIVE_INTERVAL 20 // in seconds. +#define CHECK_FOR_HANG_PERIOD 2 //be equal to watchdog check time +#define DEFAULT_KEEP_ALIVE_LEVEL 1 +#define DEFAULT_SLOT_NUM 2 +#define POWER_PROFILE_AC 0 +#define POWER_PROFILE_BATTERY 1 + +typedef struct _link_detect_t +{ + u32 RxFrameNum[MAX_LD_SLOT_NUM]; // number of Rx Frame / CheckForHang_period to determine link status + u16 SlotNum; // number of CheckForHang period to determine link status, default is 2 + u16 SlotIndex; + + u32 NumTxOkInPeriod; //number of packet transmitted during CheckForHang + u32 NumRxOkInPeriod; //number of packet received during CheckForHang + + u8 IdleCount; // (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD) + u32 LastNumTxUnicast; + u32 LastNumRxUnicast; + + bool bBusyTraffic; //when it is set to 1, UI cann't scan at will. +}link_detect_t, *plink_detect_t; + +//YJ,modified,080828,end + +//by amy for led +//================================================================================ +// LED customization. +//================================================================================ + +typedef enum _LED_STRATEGY_8185{ + SW_LED_MODE0, // + SW_LED_MODE1, // + HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes) +}LED_STRATEGY_8185, *PLED_STRATEGY_8185; +//by amy for led +//by amy for power save +typedef 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_MODE; + +typedef enum _RT_RF_POWER_STATE +{ + eRfOn, + eRfSleep, + eRfOff +}RT_RF_POWER_STATE; + +enum _ReasonCode{ + unspec_reason = 0x1, + auth_not_valid = 0x2, + deauth_lv_ss = 0x3, + inactivity = 0x4, + ap_overload = 0x5, + class2_err = 0x6, + class3_err = 0x7, + disas_lv_ss = 0x8, + asoc_not_auth = 0x9, + + //----MIC_CHECK + mic_failure = 0xe, + //----END MIC_CHECK + + // Reason code defined in 802.11i D10.0 p.28. + invalid_IE = 0x0d, + four_way_tmout = 0x0f, + two_way_tmout = 0x10, + IE_dismatch = 0x11, + invalid_Gcipher = 0x12, + invalid_Pcipher = 0x13, + invalid_AKMP = 0x14, + unsup_RSNIEver = 0x15, + invalid_RSNIE = 0x16, + auth_802_1x_fail= 0x17, + ciper_reject = 0x18, + + // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15. + QoS_unspec = 0x20, // 32 + QAP_bandwidth = 0x21, // 33 + poor_condition = 0x22, // 34 + no_facility = 0x23, // 35 + // Where is 36??? + req_declined = 0x25, // 37 + invalid_param = 0x26, // 38 + req_not_honored= 0x27, // 39 + TS_not_created = 0x2F, // 47 + DL_not_allowed = 0x30, // 48 + dest_not_exist = 0x31, // 49 + dest_not_QSTA = 0x32, // 50 +}; +typedef enum _RT_PS_MODE +{ + eActive, // Active/Continuous access. + eMaxPs, // Max power save mode. + eFastPs // Fast power save mode. +}RT_PS_MODE; +//by amy for power save +typedef struct r8180_priv +{ + struct pci_dev *pdev; + + short epromtype; + int irq; + struct ieee80211_device *ieee80211; + + short card_8185; /* O: rtl8180, 1:rtl8185 V B/C, 2:rtl8185 V D, 3:rtl8185B */ + short card_8185_Bversion; /* if TCR reports card V B/C this discriminates */ + short phy_ver; /* meaningful for rtl8225 1:A 2:B 3:C */ + short enable_gpio0; + enum card_type {PCI,MINIPCI,CARDBUS,USB/*rtl8187*/}card_type; + short hw_plcp_len; + short plcp_preamble_mode; // 0:auto 1:short 2:long + + spinlock_t irq_lock; + spinlock_t irq_th_lock; + spinlock_t tx_lock; + spinlock_t ps_lock; + spinlock_t rf_ps_lock; + + u16 irq_mask; + short irq_enabled; + struct net_device *dev; + short chan; + short sens; + short max_sens; + u8 chtxpwr[15]; //channels from 1 to 14, 0 not used + u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used + //u8 challow[15]; //channels from 1 to 14, 0 not used + u8 channel_plan; // it's the channel plan index + short up; + short crcmon; //if 1 allow bad crc frame reception in monitor mode + short prism_hdr; + + struct timer_list scan_timer; + /*short scanpending; + short stopscan;*/ + spinlock_t scan_lock; + u8 active_probe; + //u8 active_scan_num; + struct semaphore wx_sem; + struct semaphore rf_state; + short hw_wep; + + short digphy; + short antb; + short diversity; + u8 cs_treshold; + short rcr_csense; + short rf_chip; + u32 key0[4]; + short (*rf_set_sens)(struct net_device *dev,short sens); + void (*rf_set_chan)(struct net_device *dev,short ch); + void (*rf_close)(struct net_device *dev); + void (*rf_init)(struct net_device *dev); + void (*rf_sleep)(struct net_device *dev); + void (*rf_wakeup)(struct net_device *dev); + //short rate; + short promisc; + /*stats*/ + struct Stats stats; + struct _link_detect_t link_detect; //YJ,add,080828 + struct iw_statistics wstats; + struct proc_dir_entry *dir_dev; + + /*RX stuff*/ + u32 *rxring; + u32 *rxringtail; + dma_addr_t rxringdma; + struct buffer *rxbuffer; + struct buffer *rxbufferhead; + int rxringcount; + u16 rxbuffersize; + + struct sk_buff *rx_skb; + + short rx_skb_complete; + + u32 rx_prevlen; + + /*TX stuff*/ +/* + u32 *txlpring; + u32 *txhpring; + u32 *txnpring; + dma_addr_t txlpringdma; + dma_addr_t txhpringdma; + dma_addr_t txnpringdma; + u32 *txlpringtail; + u32 *txhpringtail; + u32 *txnpringtail; + u32 *txlpringhead; + u32 *txhpringhead; + u32 *txnpringhead; + struct buffer *txlpbufs; + struct buffer *txhpbufs; + struct buffer *txnpbufs; + struct buffer *txlpbufstail; + struct buffer *txhpbufstail; + struct buffer *txnpbufstail; +*/ + u32 *txmapring; + u32 *txbkpring; + u32 *txbepring; + u32 *txvipring; + u32 *txvopring; + u32 *txhpring; + dma_addr_t txmapringdma; + dma_addr_t txbkpringdma; + dma_addr_t txbepringdma; + dma_addr_t txvipringdma; + dma_addr_t txvopringdma; + dma_addr_t txhpringdma; + u32 *txmapringtail; + u32 *txbkpringtail; + u32 *txbepringtail; + u32 *txvipringtail; + u32 *txvopringtail; + u32 *txhpringtail; + u32 *txmapringhead; + u32 *txbkpringhead; + u32 *txbepringhead; + u32 *txvipringhead; + u32 *txvopringhead; + u32 *txhpringhead; + struct buffer *txmapbufs; + struct buffer *txbkpbufs; + struct buffer *txbepbufs; + struct buffer *txvipbufs; + struct buffer *txvopbufs; + struct buffer *txhpbufs; + struct buffer *txmapbufstail; + struct buffer *txbkpbufstail; + struct buffer *txbepbufstail; + struct buffer *txvipbufstail; + struct buffer *txvopbufstail; + struct buffer *txhpbufstail; + + int txringcount; + int txbuffsize; + //struct tx_pendingbuf txnp_pending; + //struct tasklet_struct irq_tx_tasklet; + struct tasklet_struct irq_rx_tasklet; + u8 dma_poll_mask; + //short tx_suspend; + + /* adhoc/master mode stuff */ + u32 *txbeaconringtail; + dma_addr_t txbeaconringdma; + u32 *txbeaconring; + int txbeaconcount; + struct buffer *txbeaconbufs; + struct buffer *txbeaconbufstail; + //char *master_essid; + //u16 master_beaconinterval; + //u32 master_beaconsize; + //u16 beacon_interval; + + u8 retry_data; + u8 retry_rts; + u16 rts; + +//add for RF power on power off by lizhaoming 080512 + u8 RegThreeWireMode; // See "Three wire mode" defined above, 2006.05.31, by rcnjko. + +//by amy for led + LED_STRATEGY_8185 LedStrategy; +//by amy for led + +//by amy for power save + struct timer_list watch_dog_timer; + bool bInactivePs; + bool bSwRfProcessing; + RT_RF_POWER_STATE eInactivePowerState; + RT_RF_POWER_STATE eRFPowerState; + u32 RfOffReason; + bool RFChangeInProgress; + bool bInHctTest; + bool SetRFPowerStateInProgress; + u8 RFProgType; + bool bLeisurePs; + RT_PS_MODE dot11PowerSaveMode; + //u32 NumRxOkInPeriod; //YJ,del,080828 + //u32 NumTxOkInPeriod; //YJ,del,080828 + u8 TxPollingTimes; + + bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake untill receive data or timeout. + u8 WaitBufDataBcnCount; + u8 WaitBufDataTimeOut; + +//by amy for power save +//by amy for antenna + u8 EEPROMSwAntennaDiversity; + bool EEPROMDefaultAntenna1; + u8 RegSwAntennaDiversityMechanism; + bool bSwAntennaDiverity; + u8 RegDefaultAntenna; + bool bDefaultAntenna1; + u8 SignalStrength; + long Stats_SignalStrength; + long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average. + u8 SignalQuality; // in 0-100 index. + long Stats_SignalQuality; + long RecvSignalPower; // in dBm. + long Stats_RecvSignalPower; + u8 LastRxPktAntenna; // +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25. + u32 AdRxOkCnt; + long AdRxSignalStrength; + u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx). + u8 AdTickCount; // Times of SwAntennaDiversityTimer happened. + u8 AdCheckPeriod; // # of period SwAntennaDiversityTimer to check Rx signal strength for SW Antenna Diversity. + u8 AdMinCheckPeriod; // Min value of AdCheckPeriod. + u8 AdMaxCheckPeriod; // Max value of AdCheckPeriod. + long AdRxSsThreshold; // Signal strength threshold to switch antenna. + long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold. + bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna. + long AdRxSsBeforeSwitched; // Rx signal strength before we swithed antenna. + struct timer_list SwAntennaDiversityTimer; +//by amy for antenna +//{by amy 080312 +// + // Crystal calibration. + // Added by Roger, 2007.12.11. + // + bool bXtalCalibration; // Crystal calibration. + u8 XtalCal_Xin; // Crystal calibration for Xin. 0~7.5pF + u8 XtalCal_Xout; // Crystal calibration for Xout. 0~7.5pF + // + // Tx power tracking with thermal meter indication. + // Added by Roger, 2007.12.11. + // + bool bTxPowerTrack; // Tx Power tracking. + u8 ThermalMeter; // Thermal meter reference indication. + // + // Dynamic Initial Gain Adjustment Mechanism. Added by Bruce, 2007-02-14. + // + bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow. + bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko. + u32 FalseAlarmRegValue; + u8 RegDigOfdmFaUpTh; // Upper threhold of OFDM false alarm, which is used in DIG. + u8 DIG_NumberFallbackVote; + u8 DIG_NumberUpgradeVote; + // For HW antenna diversity, added by Roger, 2008.01.30. + u32 AdMainAntennaRxOkCnt; // Main antenna Rx OK count. + u32 AdAuxAntennaRxOkCnt; // Aux antenna Rx OK count. + bool bHWAdSwitched; // TRUE if we has switched default antenna by HW evaluation. + // RF High Power upper/lower threshold. + u8 RegHiPwrUpperTh; + u8 RegHiPwrLowerTh; + // RF RSSI High Power upper/lower Threshold. + u8 RegRSSIHiPwrUpperTh; + u8 RegRSSIHiPwrLowerTh; + // Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, by Bruce, 2007-04-12. + u8 CurCCKRSSI; + bool bCurCCKPkt; + // + // High Power Mechanism. Added by amy, 080312. + // + bool bToUpdateTxPwr; + long UndecoratedSmoothedSS; + long UndercorateSmoothedRxPower; + u8 RSSI; + char RxPower; + u8 InitialGain; + //For adjust Dig Threshhold during Legacy/Leisure Power Save Mode + u32 DozePeriodInPast2Sec; + // Don't access BB/RF under disable PLL situation. + u8 InitialGainBackUp; + u8 RegBModeGainStage; +//by amy for rate adaptive + struct timer_list rateadapter_timer; + u32 RateAdaptivePeriod; + bool bEnhanceTxPwr; + bool bUpdateARFR; + int ForcedDataRate; // Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.) + u32 NumTxUnicast; //YJ,add,080828,for keep alive + u8 keepAliveLevel; //YJ,add,080828,for KeepAlive + unsigned long NumTxOkTotal; + u16 LastRetryCnt; + u16 LastRetryRate; + unsigned long LastTxokCnt; + unsigned long LastRxokCnt; + u16 CurrRetryCnt; + unsigned long LastTxOKBytes; + unsigned long NumTxOkBytesTotal; + u8 LastFailTxRate; + long LastFailTxRateSS; + u8 FailTxRateCount; + u32 LastTxThroughput; + //for up rate + unsigned short bTryuping; + u8 CurrTxRate; //the rate before up + u16 CurrRetryRate; + u16 TryupingCount; + u8 TryDownCountLowData; + u8 TryupingCountNoData; + + u8 CurrentOperaRate; +//by amy for rate adaptive +//by amy 080312} +// short wq_hurryup; +// struct workqueue_struct *workqueue; + struct work_struct reset_wq; + struct work_struct watch_dog_wq; + struct work_struct tx_irq_wq; + short ack_tx_to_ieee; + + u8 PowerProfile; +#ifdef CONFIG_RTL8185B + u32 CSMethod; + u8 cck_txpwr_base; + u8 ofdm_txpwr_base; + u8 dma_poll_stop_mask; + + //u8 RegThreeWireMode; + u8 MWIEnable; + u16 ShortRetryLimit; + u16 LongRetryLimit; + u16 EarlyRxThreshold; + u32 TransmitConfig; + u32 ReceiveConfig; + u32 IntrMask; + + struct ChnlAccessSetting ChannelAccessSetting; +#endif +}r8180_priv; + +#define MANAGE_PRIORITY 0 +#define BK_PRIORITY 1 +#define BE_PRIORITY 2 +#define VI_PRIORITY 3 +#define VO_PRIORITY 4 +#define HI_PRIORITY 5 +#define BEACON_PRIORITY 6 + +#define LOW_PRIORITY VI_PRIORITY +#define NORM_PRIORITY VO_PRIORITY +//AC2Queue mapping +#define AC2Q(_ac) (((_ac) == WME_AC_VO) ? VO_PRIORITY : \ + ((_ac) == WME_AC_VI) ? VI_PRIORITY : \ + ((_ac) == WME_AC_BK) ? BK_PRIORITY : \ + BE_PRIORITY) + +short rtl8180_tx(struct net_device *dev,u8* skbuf, int len,int priority, + short morefrag,short fragdesc,int rate); + +u8 read_nic_byte(struct net_device *dev, int x); +u32 read_nic_dword(struct net_device *dev, int x); +u16 read_nic_word(struct net_device *dev, int x) ; +void write_nic_byte(struct net_device *dev, int x,u8 y); +void write_nic_word(struct net_device *dev, int x,u16 y); +void write_nic_dword(struct net_device *dev, int x,u32 y); +void force_pci_posting(struct net_device *dev); + +void rtl8180_rtx_disable(struct net_device *); +void rtl8180_rx_enable(struct net_device *); +void rtl8180_tx_enable(struct net_device *); +void rtl8180_start_scanning(struct net_device *dev); +void rtl8180_start_scanning_s(struct net_device *dev); +void rtl8180_stop_scanning(struct net_device *dev); +void rtl8180_disassociate(struct net_device *dev); +//void fix_rx_fifo(struct net_device *dev); +void rtl8180_set_anaparam(struct net_device *dev,u32 a); +void rtl8185_set_anaparam2(struct net_device *dev,u32 a); +void rtl8180_set_hw_wep(struct net_device *dev); +void rtl8180_no_hw_wep(struct net_device *dev); +void rtl8180_update_msr(struct net_device *dev); +//void rtl8180_BSS_create(struct net_device *dev); +void rtl8180_beacon_tx_disable(struct net_device *dev); +void rtl8180_beacon_rx_disable(struct net_device *dev); +void rtl8180_conttx_enable(struct net_device *dev); +void rtl8180_conttx_disable(struct net_device *dev); +int rtl8180_down(struct net_device *dev); +int rtl8180_up(struct net_device *dev); +void rtl8180_commit(struct net_device *dev); +void rtl8180_set_chan(struct net_device *dev,short ch); +void rtl8180_set_master_essid(struct net_device *dev,char *essid); +void rtl8180_update_beacon_security(struct net_device *dev); +void write_phy(struct net_device *dev, u8 adr, u8 data); +void write_phy_cck(struct net_device *dev, u8 adr, u32 data); +void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data); +void rtl8185_tx_antenna(struct net_device *dev, u8 ant); +void rtl8185_rf_pins_enable(struct net_device *dev); +void IBSS_randomize_cell(struct net_device *dev); +void IPSEnter(struct net_device *dev); +void IPSLeave(struct net_device *dev); +int get_curr_tx_free_desc(struct net_device *dev, int priority); +void UpdateInitialGain(struct net_device *dev); +bool SetAntennaConfig87SE(struct net_device *dev, u8 DefaultAnt, bool bAntDiversity); + +//#ifdef CONFIG_RTL8185B +void rtl8185b_adapter_start(struct net_device *dev); +void rtl8185b_rx_enable(struct net_device *dev); +void rtl8185b_tx_enable(struct net_device *dev); +void rtl8180_reset(struct net_device *dev); +void rtl8185b_irq_enable(struct net_device *dev); +void fix_rx_fifo(struct net_device *dev); +void fix_tx_fifo(struct net_device *dev); +void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch); +#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) +void rtl8180_rate_adapter(struct work_struct * work); +#else +void rtl8180_rate_adapter(struct net_device *dev); +#endif +//#endif +bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource); + +#endif diff --git a/drivers/staging/rtl8187se/r8180_93cx6.c b/drivers/staging/rtl8187se/r8180_93cx6.c new file mode 100644 index 0000000..7e4711f --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_93cx6.c @@ -0,0 +1,146 @@ +/* + This files contains card eeprom (93c46 or 93c56) programming routines, + memory is addressed by 16 bits words. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official realtek driver. + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon. + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + We want to tanks the Authors of those projects and the Ndiswrapper + project Authors. +*/ + +#include "r8180_93cx6.h" + +void eprom_cs(struct net_device *dev, short bit) +{ + if(bit) + write_nic_byte(dev, EPROM_CMD, + (1<<EPROM_CS_SHIFT) | \ + read_nic_byte(dev, EPROM_CMD)); //enable EPROM + else + write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev, EPROM_CMD)\ + &~(1<<EPROM_CS_SHIFT)); //disable EPROM + + force_pci_posting(dev); + udelay(EPROM_DELAY); +} + + +void eprom_ck_cycle(struct net_device *dev) +{ + write_nic_byte(dev, EPROM_CMD, + (1<<EPROM_CK_SHIFT) | read_nic_byte(dev,EPROM_CMD)); + force_pci_posting(dev); + udelay(EPROM_DELAY); + write_nic_byte(dev, EPROM_CMD, + read_nic_byte(dev, EPROM_CMD) &~ (1<<EPROM_CK_SHIFT)); + force_pci_posting(dev); + udelay(EPROM_DELAY); +} + + +void eprom_w(struct net_device *dev,short bit) +{ + if(bit) + write_nic_byte(dev, EPROM_CMD, (1<<EPROM_W_SHIFT) | \ + read_nic_byte(dev,EPROM_CMD)); + else + write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev,EPROM_CMD)\ + &~(1<<EPROM_W_SHIFT)); + + force_pci_posting(dev); + udelay(EPROM_DELAY); +} + + +short eprom_r(struct net_device *dev) +{ + short bit; + + bit=(read_nic_byte(dev, EPROM_CMD) & (1<<EPROM_R_SHIFT) ); + udelay(EPROM_DELAY); + + if(bit) return 1; + return 0; +} + + +void eprom_send_bits_string(struct net_device *dev, short b[], int len) +{ + int i; + + for(i=0; i<len; i++){ + eprom_w(dev, b[i]); + eprom_ck_cycle(dev); + } +} + + +u32 eprom_read(struct net_device *dev, u32 addr) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + short read_cmd[]={1,1,0}; + short addr_str[8]; + int i; + int addr_len; + u32 ret; + + ret=0; + //enable EPROM programming + write_nic_byte(dev, EPROM_CMD, + (EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT)); + force_pci_posting(dev); + udelay(EPROM_DELAY); + + if (priv->epromtype==EPROM_93c56){ + addr_str[7]=addr & 1; + addr_str[6]=addr & (1<<1); + addr_str[5]=addr & (1<<2); + addr_str[4]=addr & (1<<3); + addr_str[3]=addr & (1<<4); + addr_str[2]=addr & (1<<5); + addr_str[1]=addr & (1<<6); + addr_str[0]=addr & (1<<7); + addr_len=8; + }else{ + addr_str[5]=addr & 1; + addr_str[4]=addr & (1<<1); + addr_str[3]=addr & (1<<2); + addr_str[2]=addr & (1<<3); + addr_str[1]=addr & (1<<4); + addr_str[0]=addr & (1<<5); + addr_len=6; + } + eprom_cs(dev, 1); + eprom_ck_cycle(dev); + eprom_send_bits_string(dev, read_cmd, 3); + eprom_send_bits_string(dev, addr_str, addr_len); + + //keep chip pin D to low state while reading. + //I'm unsure if it is necessary, but anyway shouldn't hurt + eprom_w(dev, 0); + + for(i=0;i<16;i++){ + //eeprom needs a clk cycle between writing opcode&adr + //and reading data. (eeprom outs a dummy 0) + eprom_ck_cycle(dev); + ret |= (eprom_r(dev)<<(15-i)); + } + + eprom_cs(dev, 0); + eprom_ck_cycle(dev); + + //disable EPROM programming + write_nic_byte(dev, EPROM_CMD, + (EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT)); + return ret; +} diff --git a/drivers/staging/rtl8187se/r8180_93cx6.h b/drivers/staging/rtl8187se/r8180_93cx6.h new file mode 100644 index 0000000..a028a51 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_93cx6.h @@ -0,0 +1,59 @@ +/* + This is part of rtl8180 OpenSource driver + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the official realtek driver + Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of such projects and the Ndiswrapper project Authors. +*/ + +/*This files contains card eeprom (93c46 or 93c56) programming routines*/ +/*memory is addressed by WORDS*/ + +#include "r8180.h" +#include "r8180_hw.h" + +#define EPROM_DELAY 10 + +#define EPROM_ANAPARAM_ADDRLWORD 0xd +#define EPROM_ANAPARAM_ADDRHWORD 0xe + +#define RFCHIPID 0x6 +#define RFCHIPID_INTERSIL 1 +#define RFCHIPID_RFMD 2 +#define RFCHIPID_PHILIPS 3 +#define RFCHIPID_MAXIM 4 +#define RFCHIPID_GCT 5 +#define RFCHIPID_RTL8225 9 +#ifdef CONFIG_RTL8185B +#define RF_ZEBRA2 11 +#define EPROM_TXPW_BASE 0x05 +#define RF_ZEBRA4 12 +#endif +#define RFCHIPID_RTL8255 0xa +#define RF_PARAM 0x19 +#define RF_PARAM_DIGPHY_SHIFT 0 +#define RF_PARAM_ANTBDEFAULT_SHIFT 1 +#define RF_PARAM_CARRIERSENSE_SHIFT 2 +#define RF_PARAM_CARRIERSENSE_MASK (3<<2) +#define ENERGY_TRESHOLD 0x17 +#define EPROM_VERSION 0x1E +#define MAC_ADR 0x7 + +#define CIS 0x18 + +#define EPROM_TXPW_OFDM_CH1_2 0x20 + +//#define EPROM_TXPW_CH1_2 0x10 +#define EPROM_TXPW_CH1_2 0x30 +#define EPROM_TXPW_CH3_4 0x11 +#define EPROM_TXPW_CH5_6 0x12 +#define EPROM_TXPW_CH7_8 0x13 +#define EPROM_TXPW_CH9_10 0x14 +#define EPROM_TXPW_CH11_12 0x15 +#define EPROM_TXPW_CH13_14 0x16 + +u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c new file mode 100644 index 0000000..3845598 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -0,0 +1,6826 @@ +/* + This is part of rtl818x pci OpenSource driver - v 0.1 + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public License) + + Parts of this driver are based on the GPL part of the official + Realtek driver. + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon. + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + Parts of BB/RF code are derived from David Young rtl8180 netbsd driver. + + RSSI calc function from 'The Deuce' + + Some ideas borrowed from the 8139too.c driver included in linux kernel. + + We (I?) want to thanks the Authors of those projecs and also the + Ndiswrapper's project Authors. + + A big big thanks goes also to Realtek corp. for their help in my attempt to + add RTL8185 and RTL8225 support, and to David Young also. +*/ + +#if 0 +double __floatsidf (int i) { return i; } +unsigned int __fixunsdfsi (double d) { return d; } +double __adddf3(double a, double b) { return a+b; } +double __addsf3(float a, float b) { return a+b; } +double __subdf3(double a, double b) { return a-b; } +double __extendsfdf2(float a) {return a;} +#endif + + +#undef DEBUG_TX_DESC2 +#undef RX_DONT_PASS_UL +#undef DEBUG_EPROM +#undef DEBUG_RX_VERBOSE +#undef DUMMY_RX +#undef DEBUG_ZERO_RX +#undef DEBUG_RX_SKB +#undef DEBUG_TX_FRAG +#undef DEBUG_RX_FRAG +#undef DEBUG_TX_FILLDESC +#undef DEBUG_TX +#undef DEBUG_IRQ +#undef DEBUG_RX +#undef DEBUG_RXALLOC +#undef DEBUG_REGISTERS +#undef DEBUG_RING +#undef DEBUG_IRQ_TASKLET +#undef DEBUG_TX_ALLOC +#undef DEBUG_TX_DESC + +//#define DEBUG_TX +//#define DEBUG_TX_DESC2 +//#define DEBUG_RX +//#define DEBUG_RX_SKB + +//#define CONFIG_RTL8180_IO_MAP +#include <linux/syscalls.h> +//#include <linux/fcntl.h> +//#include <asm/uaccess.h> +#include "r8180_hw.h" +#include "r8180.h" +#include "r8180_sa2400.h" /* PHILIPS Radio frontend */ +#include "r8180_max2820.h" /* MAXIM Radio frontend */ +#include "r8180_gct.h" /* GCT Radio frontend */ +#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ +#include "r8180_rtl8255.h" /* RTL8255 Radio frontend */ +#include "r8180_93cx6.h" /* Card EEPROM */ +#include "r8180_wx.h" +#include "r8180_dm.h" + +#ifdef CONFIG_RTL8180_PM +#include "r8180_pm.h" +#endif + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +#ifdef CONFIG_RTL8185B +//#define CONFIG_RTL8180_IO_MAP +#endif + +#ifndef PCI_VENDOR_ID_BELKIN + #define PCI_VENDOR_ID_BELKIN 0x1799 +#endif +#ifndef PCI_VENDOR_ID_DLINK + #define PCI_VENDOR_ID_DLINK 0x1186 +#endif + +static struct pci_device_id rtl8180_pci_id_tbl[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_REALTEK, +// .device = 0x8180, + .device = 0x8199, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 0, + }, + { + .vendor = PCI_VENDOR_ID_BELKIN, + .device = 0x6001, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 1, + }, + { /* Belkin F5D6020 v3 */ + .vendor = PCI_VENDOR_ID_BELKIN, + .device = 0x6020, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 2, + }, + { /* D-Link DWL-610 */ + .vendor = PCI_VENDOR_ID_DLINK, + .device = 0x3300, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 3, + }, + { + .vendor = PCI_VENDOR_ID_REALTEK, + .device = 0x8185, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = 4, + }, + { + .vendor = 0, + .device = 0, + .subvendor = 0, + .subdevice = 0, + .driver_data = 0, + } +}; + + +static char* ifname = "wlan%d"; +static int hwseqnum = 0; +//static char* ifname = "ath%d"; +static int hwwep = 0; +static int channels = 0x3fff; + +#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) +#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl); +MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>"); +MODULE_DESCRIPTION("Linux driver for Realtek RTL8180 / RTL8185 WiFi cards"); + + + +/* +MODULE_PARM(ifname, "s"); +MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); + +MODULE_PARM(hwseqnum,"i"); +MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); + +MODULE_PARM(hwwep,"i"); +MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); + +MODULE_PARM(channels,"i"); +MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) +module_param(ifname, charp, S_IRUGO|S_IWUSR ); +module_param(hwseqnum,int, S_IRUGO|S_IWUSR); +module_param(hwwep,int, S_IRUGO|S_IWUSR); +module_param(channels,int, S_IRUGO|S_IWUSR); +#else +MODULE_PARM(ifname, "s"); +MODULE_PARM(hwseqnum,"i"); +MODULE_PARM(hwwep,"i"); +MODULE_PARM(channels,"i"); +#endif + +MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); +//MODULE_PARM_DESC(devname," Net interface name, ath%d=default"); +MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); +MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); +MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); + + +static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); + +static void __devexit rtl8180_pci_remove(struct pci_dev *pdev); + +static void rtl8180_shutdown (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + dev->stop(dev); + pci_disable_device(pdev); +} + +static struct pci_driver rtl8180_pci_driver = { + .name = RTL8180_MODULE_NAME, /* Driver name */ + .id_table = rtl8180_pci_id_tbl, /* PCI_ID table */ + .probe = rtl8180_pci_probe, /* probe fn */ + .remove = __devexit_p(rtl8180_pci_remove),/* remove fn */ +#ifdef CONFIG_RTL8180_PM + .suspend = rtl8180_suspend, /* PM suspend fn */ + .resume = rtl8180_resume, /* PM resume fn */ +#else + .suspend = NULL, /* PM suspend fn */ + .resume = NULL, /* PM resume fn */ +#endif + .shutdown = rtl8180_shutdown, +}; + + + +#ifdef CONFIG_RTL8180_IO_MAP + +u8 read_nic_byte(struct net_device *dev, int x) +{ + return 0xff&inb(dev->base_addr +x); +} + +u32 read_nic_dword(struct net_device *dev, int x) +{ + return inl(dev->base_addr +x); +} + +u16 read_nic_word(struct net_device *dev, int x) +{ + return inw(dev->base_addr +x); +} + +void write_nic_byte(struct net_device *dev, int x,u8 y) +{ + outb(y&0xff,dev->base_addr +x); +} + +void write_nic_word(struct net_device *dev, int x,u16 y) +{ + outw(y,dev->base_addr +x); +} + +void write_nic_dword(struct net_device *dev, int x,u32 y) +{ + outl(y,dev->base_addr +x); +} + +#else /* RTL_IO_MAP */ + +u8 read_nic_byte(struct net_device *dev, int x) +{ + return 0xff&readb((u8*)dev->mem_start +x); +} + +u32 read_nic_dword(struct net_device *dev, int x) +{ + return readl((u8*)dev->mem_start +x); +} + +u16 read_nic_word(struct net_device *dev, int x) +{ + return readw((u8*)dev->mem_start +x); +} + +void write_nic_byte(struct net_device *dev, int x,u8 y) +{ + writeb(y,(u8*)dev->mem_start +x); + udelay(20); +} + +void write_nic_dword(struct net_device *dev, int x,u32 y) +{ + writel(y,(u8*)dev->mem_start +x); + udelay(20); +} + +void write_nic_word(struct net_device *dev, int x,u16 y) +{ + writew(y,(u8*)dev->mem_start +x); + udelay(20); +} + +#endif /* RTL_IO_MAP */ + + + + + +inline void force_pci_posting(struct net_device *dev) +{ + read_nic_byte(dev,EPROM_CMD); +#ifndef CONFIG_RTL8180_IO_MAP + mb(); +#endif +} + + +irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs); +void set_nic_rxring(struct net_device *dev); +void set_nic_txring(struct net_device *dev); +static struct net_device_stats *rtl8180_stats(struct net_device *dev); +void rtl8180_commit(struct net_device *dev); +void rtl8180_start_tx_beacon(struct net_device *dev); + +/**************************************************************************** + -----------------------------PROCFS STUFF------------------------- +*****************************************************************************/ + +static struct proc_dir_entry *rtl8180_proc = NULL; + +static int proc_get_registers(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n; + + int max=0xff; + + /* This dump the current register page */ + for(n=0;n<=max;) + { + //printk( "\nD: %2x> ", n); + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2x ",read_nic_byte(dev,n)); + + // printk("%2x ",read_nic_byte(dev,n)); + } + len += snprintf(page + len, count - len,"\n"); + + + + *eof = 1; + return len; + +} + +int get_curr_tx_free_desc(struct net_device *dev, int priority); + +static int proc_get_stats_hw(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + //struct net_device *dev = data; + //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + int len = 0; +#ifdef CONFIG_RTL8185B + +#else + len += snprintf(page + len, count - len, + "NIC int: %lu\n" + "Total int: %lu\n" + "--------------------\n" + "LP avail desc %d\n" + "NP avail desc %d\n" + "--------------------\n" + "LP phys dma addr %x\n" + "LP NIC ptr %x\n" + "LP virt 32base %x\n" + "LP virt 32tail %x\n" + "--------------------\n" + "NP phys dma addr %x\n" + "NP NIC ptr %x\n" + "NP virt 32base %x\n" + "NP virt 32tail %x\n" + "--------------------\n" + "BP phys dma addr %x\n" + "BP NIC ptr %x\n" + "BP virt 32base %x\n" + "BP virt 32tail %x\n", + priv->stats.ints, + priv->stats.shints, + get_curr_tx_free_desc(dev,LOW_PRIORITY), + get_curr_tx_free_desc(dev,NORM_PRIORITY), + (u32)priv->txvipringdma, + read_nic_dword(dev,TLPDA), + (u32)priv->txvipring, + (u32)priv->txvipringtail, + (u32)priv->txvopringdma, + read_nic_dword(dev,TNPDA), + (u32)priv->txvopring, + (u32)priv->txvopringtail, + (u32)priv->txbeaconringdma, + read_nic_dword(dev,TBDA), + (u32)priv->txbeaconring, + (u32)priv->txbeaconringtail); +#endif + *eof = 1; + return len; +} + + +static int proc_get_stats_rx(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + int len = 0; + + len += snprintf(page + len, count - len, + /* "RX descriptor not available: %lu\n" + "RX incomplete (missing last descriptor): %lu\n" + "RX not data: %lu\n" + //"RX descriptor pointer reset: %lu\n" + "RX descriptor pointer lost: %lu\n" + //"RX pointer workaround: %lu\n" + "RX error int: %lu\n" + "RX fifo overflow: %lu\n" + "RX int: %lu\n" + "RX packet: %lu\n" + "RX bytes: %lu\n" + "RX DMA fail: %lu\n", + priv->stats.rxrdu, + priv->stats.rxnolast, + priv->stats.rxnodata, + //priv->stats.rxreset, + priv->stats.rxnopointer, + //priv->stats.rxwrkaround, + priv->stats.rxerr, + priv->stats.rxoverflow, + priv->stats.rxint, + priv->ieee80211->stats.rx_packets, + priv->ieee80211->stats.rx_bytes, + priv->stats.rxdmafail */ + "RX OK: %lu\n" + "RX Retry: %lu\n" + "RX CRC Error(0-500): %lu\n" + "RX CRC Error(500-1000): %lu\n" + "RX CRC Error(>1000): %lu\n" + "RX ICV Error: %lu\n", + priv->stats.rxint, + priv->stats.rxerr, + priv->stats.rxcrcerrmin, + priv->stats.rxcrcerrmid, + priv->stats.rxcrcerrmax, + priv->stats.rxicverr + ); + + *eof = 1; + return len; +} + +#if 0 +static int proc_get_stats_ieee(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + int len = 0; + + len += snprintf(page + len, count - len, + "TXed association requests: %u\n" + "TXed authentication requests: %u\n" + "RXed successful association response: %u\n" + "RXed failed association response: %u\n" + "RXed successful authentication response: %u\n" + "RXed failed authentication response: %u\n" + "Association requests without response: %u\n" + "Authentication requests without response: %u\n" + "TX probe response: %u\n" + "RX probe request: %u\n" + "TX probe request: %lu\n" + "RX authentication requests: %lu\n" + "RX association requests: %lu\n" + "Reassociations: %lu\n", + priv->ieee80211->ieee_stats.tx_ass, + priv->ieee80211->ieee_stats.tx_aut, + priv->ieee80211->ieee_stats.rx_ass_ok, + priv->ieee80211->ieee_stats.rx_ass_err, + priv->ieee80211->ieee_stats.rx_aut_ok, + priv->ieee80211->ieee_stats.rx_aut_err, + priv->ieee80211->ieee_stats.ass_noresp, + priv->ieee80211->ieee_stats.aut_noresp, + priv->ieee80211->ieee_stats.tx_probe, + priv->ieee80211->ieee_stats.rx_probe, + priv->ieee80211->ieee_stats.tx_probe_rq, + priv->ieee80211->ieee_stats.rx_auth_rq, + priv->ieee80211->ieee_stats.rx_assoc_rq, + priv->ieee80211->ieee_stats.reassoc); + + *eof = 1; + return len; +} +#endif +#if 0 +static int proc_get_stats_ap(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct mac_htable_t *list; + int i; + int len = 0; + + if(priv->ieee80211->iw_mode != IW_MODE_MASTER){ + len += snprintf(page + len, count - len, + "Card is not acting as AP...\n" + ); + }else{ + len += snprintf(page + len, count - len, + "List of associated STA:\n" + ); + + for(i=0;i<MAC_HTABLE_ENTRY;i++) + for (list = priv->ieee80211->assoc_htable[i]; list!=NULL; list = list->next){ + len += snprintf(page + len, count - len, + MACSTR"\n",MAC2STR(list->adr)); + } + + } + *eof = 1; + return len; +} +#endif + +static int proc_get_stats_tx(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + int len = 0; + unsigned long totalOK; + + totalOK=priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint; + len += snprintf(page + len, count - len, + /* "TX normal priority ok int: %lu\n" + "TX normal priority error int: %lu\n" + "TX high priority ok int: %lu\n" + "TX high priority failed error int: %lu\n" + "TX low priority ok int: %lu\n" + "TX low priority failed error int: %lu\n" + "TX bytes: %lu\n" + "TX packets: %lu\n" + "TX queue resume: %lu\n" + "TX queue stopped?: %d\n" + "TX fifo overflow: %lu\n" + //"SW TX stop: %lu\n" + //"SW TX wake: %lu\n" + "TX beacon: %lu\n" + "TX beacon aborted: %lu\n", + priv->stats.txnpokint, + priv->stats.txnperr, + priv->stats.txhpokint, + priv->stats.txhperr, + priv->stats.txlpokint, + priv->stats.txlperr, + priv->ieee80211->stats.tx_bytes, + priv->ieee80211->stats.tx_packets, + priv->stats.txresumed, + netif_queue_stopped(dev), + priv->stats.txoverflow, + //priv->ieee80211->ieee_stats.swtxstop, + //priv->ieee80211->ieee_stats.swtxawake, + priv->stats.txbeacon, + priv->stats.txbeaconerr */ + "TX OK: %lu\n" + "TX Error: %lu\n" + "TX Retry: %lu\n" + "TX beacon OK: %lu\n" + "TX beacon error: %lu\n", + totalOK, + priv->stats.txnperr+priv->stats.txhperr+priv->stats.txlperr, + priv->stats.txretry, + priv->stats.txbeacon, + priv->stats.txbeaconerr + ); + + *eof = 1; + return len; +} + + +#if WIRELESS_EXT < 17 +static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + return &priv->wstats; +} +#endif +void rtl8180_proc_module_init(void) +{ + DMESG("Initializing proc filesystem"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, proc_net); +#else + rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, init_net.proc_net); +#endif +} + + +void rtl8180_proc_module_remove(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + remove_proc_entry(RTL8180_MODULE_NAME, proc_net); +#else + remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net); +#endif +} + + +void rtl8180_proc_remove_one(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + if (priv->dir_dev) { + remove_proc_entry("stats-hw", priv->dir_dev); + remove_proc_entry("stats-tx", priv->dir_dev); + remove_proc_entry("stats-rx", priv->dir_dev); +// remove_proc_entry("stats-ieee", priv->dir_dev); +// remove_proc_entry("stats-ap", priv->dir_dev); + remove_proc_entry("registers", priv->dir_dev); + remove_proc_entry(dev->name, rtl8180_proc); + priv->dir_dev = NULL; + } +} + + +void rtl8180_proc_init_one(struct net_device *dev) +{ + struct proc_dir_entry *e; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + priv->dir_dev = create_proc_entry(dev->name, + S_IFDIR | S_IRUGO | S_IXUGO, + rtl8180_proc); + if (!priv->dir_dev) { + DMESGE("Unable to initialize /proc/net/rtl8180/%s\n", + dev->name); + return; + } + + e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_hw, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8180/%s/stats-hw\n", + dev->name); + } + + e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_rx, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8180/%s/stats-rx\n", + dev->name); + } + + + e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_tx, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8180/%s/stats-tx\n", + dev->name); + } + #if 0 + e = create_proc_read_entry("stats-ieee", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_ieee, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8180/%s/stats-ieee\n", + dev->name); + } + #endif + #if 0 + e = create_proc_read_entry("stats-ap", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_ap, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8180/%s/stats-ap\n", + dev->name); + } + #endif + + e = create_proc_read_entry("registers", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8180/%s/registers\n", + dev->name); + } +} +/**************************************************************************** + -----------------------------MISC STUFF------------------------- +*****************************************************************************/ +/* + FIXME: check if we can use some standard already-existent + data type+functions in kernel +*/ + +short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma, + struct buffer **bufferhead) +{ +#ifdef DEBUG_RING + DMESG("adding buffer to TX/RX struct"); +#endif + + struct buffer *tmp; + + if(! *buffer){ + + *buffer = kmalloc(sizeof(struct buffer),GFP_KERNEL); + + if (*buffer == NULL) { + DMESGE("Failed to kmalloc head of TX/RX struct"); + return -1; + } + (*buffer)->next=*buffer; + (*buffer)->buf=buf; + (*buffer)->dma=dma; + if(bufferhead !=NULL) + (*bufferhead) = (*buffer); + return 0; + } + tmp=*buffer; + + while(tmp->next!=(*buffer)) tmp=tmp->next; + if ((tmp->next= kmalloc(sizeof(struct buffer),GFP_KERNEL)) == NULL){ + DMESGE("Failed to kmalloc TX/RX struct"); + return -1; + } + tmp->next->buf=buf; + tmp->next->dma=dma; + tmp->next->next=*buffer; + + return 0; +} + + +void buffer_free(struct net_device *dev,struct buffer **buffer,int len,short +consistent) +{ + + struct buffer *tmp,*next; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct pci_dev *pdev=priv->pdev; + //int i; + + if(! *buffer) return; + + /*for(tmp=*buffer; tmp->next != *buffer; tmp=tmp->next) + + */ + tmp=*buffer; + do{ + next=tmp->next; + if(consistent){ + pci_free_consistent(pdev,len, + tmp->buf,tmp->dma); + }else{ + pci_unmap_single(pdev, tmp->dma, + len,PCI_DMA_FROMDEVICE); + kfree(tmp->buf); + } + kfree(tmp); + tmp = next; + } + while(next != *buffer); + + *buffer=NULL; +} + + +void print_buffer(u32 *buffer, int len) +{ + int i; + u8 *buf =(u8*)buffer; + + printk("ASCII BUFFER DUMP (len: %x):\n",len); + + for(i=0;i<len;i++) + printk("%c",buf[i]); + + printk("\nBINARY BUFFER DUMP (len: %x):\n",len); + + for(i=0;i<len;i++) + printk("%02x",buf[i]); + + printk("\n"); +} + + +int get_curr_tx_free_desc(struct net_device *dev, int priority) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32* tail; + u32* head; + int ret; + + switch (priority){ + case MANAGE_PRIORITY: + head = priv->txmapringhead; + tail = priv->txmapringtail; + break; + case BK_PRIORITY: + head = priv->txbkpringhead; + tail = priv->txbkpringtail; + break; + case BE_PRIORITY: + head = priv->txbepringhead; + tail = priv->txbepringtail; + break; + case VI_PRIORITY: + head = priv->txvipringhead; + tail = priv->txvipringtail; + break; + case VO_PRIORITY: + head = priv->txvopringhead; + tail = priv->txvopringtail; + break; + case HI_PRIORITY: + head = priv->txhpringhead; + tail = priv->txhpringtail; + break; + default: + return -1; + } + + //DMESG("%x %x", head, tail); + + /* FIXME FIXME FIXME FIXME */ + +#if 0 + if( head <= tail ) return priv->txringcount-1 - (tail - head)/8; + return (head - tail)/8/4; +#else + if( head <= tail ) + ret = priv->txringcount - (tail - head)/8; + else + ret = (head - tail)/8; + + if(ret > priv->txringcount ) DMESG("BUG"); + return ret; +#endif +} + + +short check_nic_enought_desc(struct net_device *dev, int priority) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = netdev_priv(dev); + + int requiredbyte, required; + requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data); + + if(ieee->current_network.QoS_Enable) { + requiredbyte += 2; + }; + + required = requiredbyte / (priv->txbuffsize-4); + if (requiredbyte % priv->txbuffsize) required++; + /* for now we keep two free descriptor as a safety boundary + * between the tail and the head + */ + + return (required+2 < get_curr_tx_free_desc(dev,priority)); +} + + +/* This function is only for debuging purpose */ +void check_tx_ring(struct net_device *dev, int pri) +{ + static int maxlog =3; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32* tmp; + struct buffer *buf; + int i; + int nic; + u32* tail; + u32* head; + u32* begin; + u32 nicbegin; + struct buffer* buffer; + + maxlog --; + if (maxlog <0 ) return; + + switch(pri) { + case MANAGE_PRIORITY: + tail = priv->txmapringtail; + begin = priv->txmapring; + head = priv->txmapringhead; + nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR); + buffer = priv->txmapbufs; + nicbegin = priv->txmapringdma; + break; + + + case BK_PRIORITY: + tail = priv->txbkpringtail; + begin = priv->txbkpring; + head = priv->txbkpringhead; + nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR); + buffer = priv->txbkpbufs; + nicbegin = priv->txbkpringdma; + break; + + case BE_PRIORITY: + tail = priv->txbepringtail; + begin = priv->txbepring; + head = priv->txbepringhead; + nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR); + buffer = priv->txbepbufs; + nicbegin = priv->txbepringdma; + break; + + case VI_PRIORITY: + tail = priv->txvipringtail; + begin = priv->txvipring; + head = priv->txvipringhead; + nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR); + buffer = priv->txvipbufs; + nicbegin = priv->txvipringdma; + break; + + + case VO_PRIORITY: + tail = priv->txvopringtail; + begin = priv->txvopring; + head = priv->txvopringhead; + nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR); + buffer = priv->txvopbufs; + nicbegin = priv->txvopringdma; + break; + + case HI_PRIORITY: + tail = priv->txhpringtail; + begin = priv->txhpring; + head = priv->txhpringhead; + nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR); + buffer = priv->txhpbufs; + nicbegin = priv->txhpringdma; + break; + + default: + return ; + break; + } + + if(!priv->txvopbufs) + DMESGE ("NIC TX ack, but TX queue corrupted!"); + else{ + + for(i=0,buf=buffer, tmp=begin; + tmp<begin+(priv->txringcount)*8; + tmp+=8,buf=buf->next,i++) + + DMESG("BUF%d %s %x %s. Next : %x",i, + *tmp & (1<<31) ? "filled" : "empty", + *(buf->buf), + *tmp & (1<<15)? "ok": "err", *(tmp+4)); + } + + DMESG("nic at %d", + (nic-nicbegin) / 8 /4); + DMESG("tail at %d", ((int)tail - (int)begin) /8 /4); + DMESG("head at %d", ((int)head - (int)begin) /8 /4); + DMESG("check free desc returns %d", check_nic_enought_desc(dev,pri)); + DMESG("free desc is %d\n", get_curr_tx_free_desc(dev,pri)); + //rtl8180_reset(dev); + return; +} + + + +/* this function is only for debugging purpose */ +void check_rxbuf(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32* tmp; + struct buffer *buf; + u8 rx_desc_size; + +#ifdef CONFIG_RTL8185B + rx_desc_size = 8; +#else + rx_desc_size = 4; +#endif + + if(!priv->rxbuffer) + DMESGE ("NIC RX ack, but RX queue corrupted!"); + + else{ + + for(buf=priv->rxbuffer, tmp=priv->rxring; + tmp < priv->rxring+(priv->rxringcount)*rx_desc_size; + tmp+=rx_desc_size, buf=buf->next) + + DMESG("BUF %s %x", + *tmp & (1<<31) ? "empty" : "filled", + *(buf->buf)); + } + + return; +} + + +void dump_eprom(struct net_device *dev) +{ + int i; + for(i=0; i<63; i++) + DMESG("EEPROM addr %x : %x", i, eprom_read(dev,i)); +} + + +void rtl8180_dump_reg(struct net_device *dev) +{ + int i; + int n; + int max=0xff; + + DMESG("Dumping NIC register map"); + + for(n=0;n<=max;) + { + printk( "\nD: %2x> ", n); + for(i=0;i<16 && n<=max;i++,n++) + printk("%2x ",read_nic_byte(dev,n)); + } + printk("\n"); +} + + +void fix_tx_fifo(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32 *tmp; + int i; +#ifdef DEBUG_TX_ALLOC + DMESG("FIXING TX FIFOs"); +#endif + for (tmp=priv->txmapring, i=0; + i < priv->txringcount; + tmp+=8, i++){ + *tmp = *tmp &~ (1<<31); + } + + for (tmp=priv->txbkpring, i=0; + i < priv->txringcount; + tmp+=8, i++) { + *tmp = *tmp &~ (1<<31); + } + + for (tmp=priv->txbepring, i=0; + i < priv->txringcount; + tmp+=8, i++){ + *tmp = *tmp &~ (1<<31); + } + for (tmp=priv->txvipring, i=0; + i < priv->txringcount; + tmp+=8, i++) { + *tmp = *tmp &~ (1<<31); + } + + for (tmp=priv->txvopring, i=0; + i < priv->txringcount; + tmp+=8, i++){ + *tmp = *tmp &~ (1<<31); + } + + for (tmp=priv->txhpring, i=0; + i < priv->txringcount; + tmp+=8,i++){ + *tmp = *tmp &~ (1<<31); + } + + for (tmp=priv->txbeaconring, i=0; + i < priv->txbeaconcount; + tmp+=8, i++){ + *tmp = *tmp &~ (1<<31); + } +#ifdef DEBUG_TX_ALLOC + DMESG("TX FIFOs FIXED"); +#endif + priv->txmapringtail = priv->txmapring; + priv->txmapringhead = priv->txmapring; + priv->txmapbufstail = priv->txmapbufs; + + priv->txbkpringtail = priv->txbkpring; + priv->txbkpringhead = priv->txbkpring; + priv->txbkpbufstail = priv->txbkpbufs; + + priv->txbepringtail = priv->txbepring; + priv->txbepringhead = priv->txbepring; + priv->txbepbufstail = priv->txbepbufs; + + priv->txvipringtail = priv->txvipring; + priv->txvipringhead = priv->txvipring; + priv->txvipbufstail = priv->txvipbufs; + + priv->txvopringtail = priv->txvopring; + priv->txvopringhead = priv->txvopring; + priv->txvopbufstail = priv->txvopbufs; + + priv->txhpringtail = priv->txhpring; + priv->txhpringhead = priv->txhpring; + priv->txhpbufstail = priv->txhpbufs; + + priv->txbeaconringtail = priv->txbeaconring; + priv->txbeaconbufstail = priv->txbeaconbufs; + set_nic_txring(dev); + + ieee80211_reset_queue(priv->ieee80211); + priv->ack_tx_to_ieee = 0; +} + + +void fix_rx_fifo(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32 *tmp; + struct buffer *rxbuf; + u8 rx_desc_size; + +#ifdef CONFIG_RTL8185B + rx_desc_size = 8; // 4*8 = 32 bytes +#else + rx_desc_size = 4; +#endif + +#ifdef DEBUG_RXALLOC + DMESG("FIXING RX FIFO"); + check_rxbuf(dev); +#endif + + for (tmp=priv->rxring, rxbuf=priv->rxbufferhead; + (tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size); + tmp+=rx_desc_size,rxbuf=rxbuf->next){ + *(tmp+2) = rxbuf->dma; + *tmp=*tmp &~ 0xfff; + *tmp=*tmp | priv->rxbuffersize; + *tmp |= (1<<31); + } + +#ifdef DEBUG_RXALLOC + DMESG("RX FIFO FIXED"); + check_rxbuf(dev); +#endif + + priv->rxringtail=priv->rxring; + priv->rxbuffer=priv->rxbufferhead; + priv->rx_skb_complete=1; + set_nic_rxring(dev); +} + + +/**************************************************************************** + ------------------------------HW STUFF--------------------------- +*****************************************************************************/ + +unsigned char QUALITY_MAP[] = { + 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61, + 0x61, 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5d, 0x5c, + 0x5b, 0x5a, 0x59, 0x57, 0x56, 0x54, 0x52, 0x4f, + 0x4c, 0x49, 0x45, 0x41, 0x3c, 0x37, 0x31, 0x29, + 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, + 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e, + 0x1d, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x12, 0x11, 0x0f, + 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x01, 0x00 +}; + +unsigned char STRENGTH_MAP[] = { + 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, + 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50, + 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f, + 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b, + 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, + 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, + 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f, + 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, + 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07, + 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x00 +}; + +void rtl8180_RSSI_calc(struct net_device *dev, u8 *rssi, u8 *qual){ + //void Mlme_UpdateRssiSQ(struct net_device *dev, u8 *rssi, u8 *qual){ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32 temp; + u32 temp2; + u32 temp3; + u32 lsb; + u32 q; + u32 orig_qual; + u8 _rssi; + + q = *qual; + orig_qual = *qual; + _rssi = 0; // avoid gcc complains.. + + if (q <= 0x4e) { + temp = QUALITY_MAP[q]; + } else { + if( q & 0x80 ) { + temp = 0x32; + } else { + temp = 1; + } + } + + *qual = temp; + temp2 = *rssi; + + switch(priv->rf_chip){ + case RFCHIPID_RFMD: + lsb = temp2 & 1; + temp2 &= 0x7e; + if ( !lsb || !(temp2 <= 0x3c) ) { + temp2 = 0x64; + } else { + temp2 = 100 * temp2 / 0x3c; + } + *rssi = temp2 & 0xff; + _rssi = temp2 & 0xff; + break; + case RFCHIPID_INTERSIL: + lsb = temp2; + temp2 &= 0xfffffffe; + temp2 *= 251; + temp3 = temp2; + temp2 <<= 6; + temp3 += temp2; + temp3 <<= 1; + temp2 = 0x4950df; + temp2 -= temp3; + lsb &= 1; + if ( temp2 <= 0x3e0000 ) { + if ( temp2 < 0xffef0000 ) + temp2 = 0xffef0000; + } else { + temp2 = 0x3e0000; + } + if ( !lsb ) { + temp2 -= 0xf0000; + } else { + temp2 += 0xf0000; + } + + temp3 = 0x4d0000; + temp3 -= temp2; + temp3 *= 100; + temp3 = temp3 / 0x6d; + temp3 >>= 0x10; + _rssi = temp3 & 0xff; + *rssi = temp3 & 0xff; + break; + case RFCHIPID_GCT: + lsb = temp2 & 1; + temp2 &= 0x7e; + if ( ! lsb || !(temp2 <= 0x3c) ){ + temp2 = 0x64; + } else { + temp2 = (100 * temp2) / 0x3c; + } + *rssi = temp2 & 0xff; + _rssi = temp2 & 0xff; + break; + case RFCHIPID_PHILIPS: + if( orig_qual <= 0x4e ){ + _rssi = STRENGTH_MAP[orig_qual]; + *rssi = _rssi; + } else { + orig_qual -= 0x80; + if ( !orig_qual ){ + _rssi = 1; + *rssi = 1; + } else { + _rssi = 0x32; + *rssi = 0x32; + } + } + break; + + /* case 4 */ + case RFCHIPID_MAXIM: + lsb = temp2 & 1; + temp2 &= 0x7e; + temp2 >>= 1; + temp2 += 0x42; + if( lsb != 0 ){ + temp2 += 0xa; + } + *rssi = temp2 & 0xff; + _rssi = temp2 & 0xff; + break; + } + + if ( _rssi < 0x64 ){ + if ( _rssi == 0 ) { + *rssi = 1; + } + } else { + *rssi = 0x64; + } + + return; +} + + +void rtl8180_irq_enable(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + priv->irq_enabled = 1; +/* + write_nic_word(dev,INTA_MASK,INTA_RXOK | INTA_RXDESCERR | INTA_RXOVERFLOW |\ + INTA_TXOVERFLOW | INTA_HIPRIORITYDESCERR | INTA_HIPRIORITYDESCOK |\ + INTA_NORMPRIORITYDESCERR | INTA_NORMPRIORITYDESCOK |\ + INTA_LOWPRIORITYDESCERR | INTA_LOWPRIORITYDESCOK | INTA_TIMEOUT); +*/ + write_nic_word(dev,INTA_MASK, priv->irq_mask); +} + + +void rtl8180_irq_disable(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + +#ifdef CONFIG_RTL8185B + write_nic_dword(dev,IMR,0); +#else + write_nic_word(dev,INTA_MASK,0); +#endif + force_pci_posting(dev); + priv->irq_enabled = 0; +} + + +void rtl8180_set_mode(struct net_device *dev,int mode) +{ + u8 ecmd; + ecmd=read_nic_byte(dev, EPROM_CMD); + ecmd=ecmd &~ EPROM_CMD_OPERATING_MODE_MASK; + ecmd=ecmd | (mode<<EPROM_CMD_OPERATING_MODE_SHIFT); + ecmd=ecmd &~ (1<<EPROM_CS_SHIFT); + ecmd=ecmd &~ (1<<EPROM_CK_SHIFT); + write_nic_byte(dev, EPROM_CMD, ecmd); +} + +void rtl8180_adapter_start(struct net_device *dev); +void rtl8180_beacon_tx_enable(struct net_device *dev); + +void rtl8180_update_msr(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u8 msr; + u32 rxconf; + + msr = read_nic_byte(dev, MSR); + msr &= ~ MSR_LINK_MASK; + + rxconf=read_nic_dword(dev,RX_CONF); + + if(priv->ieee80211->state == IEEE80211_LINKED) + { + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) + msr |= (MSR_LINK_ADHOC<<MSR_LINK_SHIFT); + else if (priv->ieee80211->iw_mode == IW_MODE_MASTER) + msr |= (MSR_LINK_MASTER<<MSR_LINK_SHIFT); + else if (priv->ieee80211->iw_mode == IW_MODE_INFRA) + msr |= (MSR_LINK_MANAGED<<MSR_LINK_SHIFT); + else + msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT); + rxconf |= (1<<RX_CHECK_BSSID_SHIFT); + + }else { + msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT); + rxconf &= ~(1<<RX_CHECK_BSSID_SHIFT); + } + + write_nic_byte(dev, MSR, msr); + write_nic_dword(dev, RX_CONF, rxconf); + +} + + + +void rtl8180_set_chan(struct net_device *dev,short ch) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + if((ch > 14) || (ch < 1)) + { + printk("In %s: Invalid chnanel %d\n", __FUNCTION__, ch); + return; + } + + priv->chan=ch; + //printk("in %s:channel is %d\n",__FUNCTION__,ch); + priv->rf_set_chan(dev,priv->chan); + +} + + +void rtl8180_rx_enable(struct net_device *dev) +{ + u8 cmd; + u32 rxconf; + /* for now we accept data, management & ctl frame*/ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + rxconf=read_nic_dword(dev,RX_CONF); + rxconf = rxconf &~ MAC_FILTER_MASK; + rxconf = rxconf | (1<<ACCEPT_MNG_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_DATA_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_BCAST_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_MCAST_FRAME_SHIFT); +// rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT); + if (dev->flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); + + if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ + dev->flags & IFF_PROMISC){ + rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT); + }else{ + rxconf = rxconf | (1<<ACCEPT_NICMAC_FRAME_SHIFT); + if(priv->card_8185 == 0) + rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT); + } + + /*if(priv->ieee80211->iw_mode == IW_MODE_MASTER){ + rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT); + rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT); + }*/ + + if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){ + rxconf = rxconf | (1<<ACCEPT_CTL_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_ICVERR_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_PWR_FRAME_SHIFT); + } + + if( priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) + rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT); + + //if(!priv->card_8185){ + rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK; + rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<<RX_FIFO_THRESHOLD_SHIFT); + //} + + rxconf = rxconf | (1<<RX_AUTORESETPHY_SHIFT); + rxconf = rxconf &~ MAX_RX_DMA_MASK; + rxconf = rxconf | (MAX_RX_DMA_2048<<MAX_RX_DMA_SHIFT); + + //if(!priv->card_8185) + rxconf = rxconf | RCR_ONLYERLPKT; + + rxconf = rxconf &~ RCR_CS_MASK; + if(!priv->card_8185) + rxconf |= (priv->rcr_csense<<RCR_CS_SHIFT); +// rxconf &=~ 0xfff00000; +// rxconf |= 0x90100000;//9014f76f; + write_nic_dword(dev, RX_CONF, rxconf); + + fix_rx_fifo(dev); + +#ifdef DEBUG_RX + DMESG("rxconf: %x %x",rxconf ,read_nic_dword(dev,RX_CONF)); +#endif + cmd=read_nic_byte(dev,CMD); + write_nic_byte(dev,CMD,cmd | (1<<CMD_RX_ENABLE_SHIFT)); + + /* In rtl8139 driver seems that DMA threshold has to be written + * after enabling RX, so we rewrite RX_CONFIG register + */ + //mdelay(100); +// write_nic_dword(dev, RX_CONF, rxconf); + +} + + +void set_nic_txring(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + + write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma); +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma); +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma); +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma); +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma); +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma); +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + + write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma); +} + + +void rtl8180_conttx_enable(struct net_device *dev) +{ + u32 txconf; + txconf = read_nic_dword(dev,TX_CONF); + txconf = txconf &~ TX_LOOPBACK_MASK; + txconf = txconf | (TX_LOOPBACK_CONTINUE <<TX_LOOPBACK_SHIFT); + write_nic_dword(dev,TX_CONF,txconf); +} + + +void rtl8180_conttx_disable(struct net_device *dev) +{ + u32 txconf; + txconf = read_nic_dword(dev,TX_CONF); + txconf = txconf &~ TX_LOOPBACK_MASK; + txconf = txconf | (TX_LOOPBACK_NONE <<TX_LOOPBACK_SHIFT); + write_nic_dword(dev,TX_CONF,txconf); +} + + +void rtl8180_tx_enable(struct net_device *dev) +{ + u8 cmd; + u8 tx_agc_ctl; + u8 byte; + u32 txconf; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + txconf= read_nic_dword(dev,TX_CONF); + + + if(priv->card_8185){ + + + byte = read_nic_byte(dev,CW_CONF); + byte &= ~(1<<CW_CONF_PERPACKET_CW_SHIFT); + byte &= ~(1<<CW_CONF_PERPACKET_RETRY_SHIFT); + write_nic_byte(dev, CW_CONF, byte); + + tx_agc_ctl = read_nic_byte(dev, TX_AGC_CTL); + tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_GAIN_SHIFT); + tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT); + tx_agc_ctl |=(1<<TX_AGC_CTL_FEEDBACK_ANT); + write_nic_byte(dev, TX_AGC_CTL, tx_agc_ctl); + /* + write_nic_word(dev, 0x5e, 0x01); + force_pci_posting(dev); + mdelay(1); + write_nic_word(dev, 0xfe, 0x10); + force_pci_posting(dev); + mdelay(1); + write_nic_word(dev, 0x5e, 0x00); + force_pci_posting(dev); + mdelay(1); + */ + write_nic_byte(dev, 0xec, 0x3f); /* Disable early TX */ + } + + if(priv->card_8185){ + + txconf = txconf &~ (1<<TCR_PROBE_NOTIMESTAMP_SHIFT); + + }else{ + + if(hwseqnum) + txconf= txconf &~ (1<<TX_CONF_HEADER_AUTOICREMENT_SHIFT); + else + txconf= txconf | (1<<TX_CONF_HEADER_AUTOICREMENT_SHIFT); + } + + txconf = txconf &~ TX_LOOPBACK_MASK; + txconf = txconf | (TX_LOOPBACK_NONE <<TX_LOOPBACK_SHIFT); + txconf = txconf &~ TCR_DPRETRY_MASK; + txconf = txconf &~ TCR_RTSRETRY_MASK; + txconf = txconf | (priv->retry_data<<TX_DPRETRY_SHIFT); + txconf = txconf | (priv->retry_rts<<TX_RTSRETRY_SHIFT); + txconf = txconf &~ (1<<TX_NOCRC_SHIFT); + + if(priv->card_8185){ + if(priv->hw_plcp_len) + txconf = txconf &~ TCR_PLCP_LEN; + else + txconf = txconf | TCR_PLCP_LEN; + }else{ + txconf = txconf &~ TCR_SAT; + } + txconf = txconf &~ TCR_MXDMA_MASK; + txconf = txconf | (TCR_MXDMA_2048<<TCR_MXDMA_SHIFT); + txconf = txconf | TCR_CWMIN; + txconf = txconf | TCR_DISCW; + +// if(priv->ieee80211->hw_wep) +// txconf=txconf &~ (1<<TX_NOICV_SHIFT); +// else + txconf=txconf | (1<<TX_NOICV_SHIFT); + + write_nic_dword(dev,TX_CONF,txconf); + + + fix_tx_fifo(dev); + +#ifdef DEBUG_TX + DMESG("txconf: %x %x",txconf,read_nic_dword(dev,TX_CONF)); +#endif + + cmd=read_nic_byte(dev,CMD); + write_nic_byte(dev,CMD,cmd | (1<<CMD_TX_ENABLE_SHIFT)); + +// mdelay(100); + write_nic_dword(dev,TX_CONF,txconf); +// #endif +/* + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); + write_nic_byte(dev, TX_DMA_POLLING, priv->dma_poll_mask); + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); + */ +} + + +void rtl8180_beacon_tx_enable(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); +#ifdef CONFIG_RTL8185B + priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ); + write_nic_byte(dev,TPPollStop, priv->dma_poll_mask); +#else + priv->dma_poll_mask &=~(1<<TX_DMA_STOP_BEACON_SHIFT); + write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); +#endif + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); +} + + +void rtl8180_beacon_tx_disable(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); +#ifdef CONFIG_RTL8185B + priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ; + write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); +#else + priv->dma_poll_mask |= (1<<TX_DMA_STOP_BEACON_SHIFT); + write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); +#endif + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); + +} + + +void rtl8180_rtx_disable(struct net_device *dev) +{ + u8 cmd; + struct r8180_priv *priv = ieee80211_priv(dev); + + cmd=read_nic_byte(dev,CMD); + write_nic_byte(dev, CMD, cmd &~ \ + ((1<<CMD_RX_ENABLE_SHIFT)|(1<<CMD_TX_ENABLE_SHIFT))); + force_pci_posting(dev); + mdelay(10); + /*while (read_nic_byte(dev,CMD) & (1<<CMD_RX_ENABLE_SHIFT)) + udelay(10); + */ + + if(!priv->rx_skb_complete) + dev_kfree_skb_any(priv->rx_skb); +} + +#if 0 +int alloc_tx_beacon_desc_ring(struct net_device *dev, int count) +{ + int i; + u32 *tmp; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + priv->txbeaconring = (u32*)pci_alloc_consistent(priv->pdev, + sizeof(u32)*8*count, + &priv->txbeaconringdma); + if (!priv->txbeaconring) return -1; + for (tmp=priv->txbeaconring,i=0;i<count;i++){ + *tmp = *tmp &~ (1<<31); // descriptor empty, owned by the drv + /* + *(tmp+2) = (u32)dma_tmp; + *(tmp+3) = bufsize; + */ + if(i+1<count) + *(tmp+4) = (u32)priv->txbeaconringdma+((i+1)*8*4); + else + *(tmp+4) = (u32)priv->txbeaconringdma; + + tmp=tmp+8; + } + return 0; +} +#endif + +short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count, + int addr) +{ + int i; + u32 *desc; + u32 *tmp; + dma_addr_t dma_desc, dma_tmp; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct pci_dev *pdev = priv->pdev; + void *buf; + + if((bufsize & 0xfff) != bufsize) { + DMESGE ("TX buffer allocation too large"); + return 0; + } + desc = (u32*)pci_alloc_consistent(pdev, + sizeof(u32)*8*count+256, &dma_desc); + if(desc==NULL) return -1; + if(dma_desc & 0xff){ + + /* + * descriptor's buffer must be 256 byte aligned + * we shouldn't be here, since we set DMA mask ! + */ + DMESGW("Fixing TX alignment"); + desc = (u32*)((u8*)desc + 256); +#if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR)) + desc = (u32*)((u64)desc &~ 0xff); + dma_desc = (dma_addr_t)((u8*)dma_desc + 256); + dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff); +#else + desc = (u32*)((u32)desc &~ 0xff); + dma_desc = (dma_addr_t)((u8*)dma_desc + 256); + dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff); +#endif + } + tmp=desc; + for (i=0;i<count;i++) + { + buf = (void*)pci_alloc_consistent(pdev,bufsize,&dma_tmp); + if (buf == NULL) return -ENOMEM; + + switch(addr) { +#if 0 + case TX_NORMPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txnpbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer NP"); + return -ENOMEM; + } + break; + + case TX_LOWPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txlpbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer LP"); + return -ENOMEM; + } + break; + + case TX_HIGHPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer HP"); + return -ENOMEM; + } + break; +#else + case TX_MANAGEPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txmapbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer NP"); + return -ENOMEM; + } + break; + + case TX_BKPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txbkpbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer LP"); + return -ENOMEM; + } + break; + case TX_BEPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txbepbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer NP"); + return -ENOMEM; + } + break; + + case TX_VIPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txvipbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer LP"); + return -ENOMEM; + } + break; + case TX_VOPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txvopbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer NP"); + return -ENOMEM; + } + break; +#endif + case TX_HIGHPRIORITY_RING_ADDR: + if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer HP"); + return -ENOMEM; + } + break; + case TX_BEACON_RING_ADDR: + if(-1 == buffer_add(&(priv->txbeaconbufs),buf,dma_tmp,NULL)){ + DMESGE("Unable to allocate mem for buffer BP"); + return -ENOMEM; + } + break; + } + *tmp = *tmp &~ (1<<31); // descriptor empty, owned by the drv + *(tmp+2) = (u32)dma_tmp; + *(tmp+3) = bufsize; + + if(i+1<count) + *(tmp+4) = (u32)dma_desc+((i+1)*8*4); + else + *(tmp+4) = (u32)dma_desc; + + tmp=tmp+8; + } + + switch(addr) { + case TX_MANAGEPRIORITY_RING_ADDR: + priv->txmapringdma=dma_desc; + priv->txmapring=desc; + break; + + case TX_BKPRIORITY_RING_ADDR: + priv->txbkpringdma=dma_desc; + priv->txbkpring=desc; + break; + + case TX_BEPRIORITY_RING_ADDR: + priv->txbepringdma=dma_desc; + priv->txbepring=desc; + break; + + case TX_VIPRIORITY_RING_ADDR: + priv->txvipringdma=dma_desc; + priv->txvipring=desc; + break; + + case TX_VOPRIORITY_RING_ADDR: + priv->txvopringdma=dma_desc; + priv->txvopring=desc; + break; + + case TX_HIGHPRIORITY_RING_ADDR: + priv->txhpringdma=dma_desc; + priv->txhpring=desc; + break; + + case TX_BEACON_RING_ADDR: + priv->txbeaconringdma=dma_desc; + priv->txbeaconring=desc; + break; + + } + +#ifdef DEBUG_TX + DMESG("Tx dma physical address: %x",dma_desc); +#endif + + return 0; +} + + +void free_tx_desc_rings(struct net_device *dev) +{ + + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct pci_dev *pdev=priv->pdev; + int count = priv->txringcount; + + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txmapring, priv->txmapringdma); + buffer_free(dev,&(priv->txmapbufs),priv->txbuffsize,1); + + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txbkpring, priv->txbkpringdma); + buffer_free(dev,&(priv->txbkpbufs),priv->txbuffsize,1); + + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txbepring, priv->txbepringdma); + buffer_free(dev,&(priv->txbepbufs),priv->txbuffsize,1); + + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txvipring, priv->txvipringdma); + buffer_free(dev,&(priv->txvipbufs),priv->txbuffsize,1); + + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txvopring, priv->txvopringdma); + buffer_free(dev,&(priv->txvopbufs),priv->txbuffsize,1); + + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txhpring, priv->txhpringdma); + buffer_free(dev,&(priv->txhpbufs),priv->txbuffsize,1); + + count = priv->txbeaconcount; + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txbeaconring, priv->txbeaconringdma); + buffer_free(dev,&(priv->txbeaconbufs),priv->txbuffsize,1); +} + +#if 0 +void free_beacon_desc_ring(struct net_device *dev,int count) +{ + + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct pci_dev *pdev=priv->pdev; + + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->txbeaconring, priv->txbeaconringdma); + + if (priv->beacon_buf) + pci_free_consistent(priv->pdev, + priv->master_beaconsize,priv->beacon_buf,priv->beacondmabuf); + +} +#endif +void free_rx_desc_ring(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct pci_dev *pdev = priv->pdev; + + int count = priv->rxringcount; + +#ifdef CONFIG_RTL8185B + pci_free_consistent(pdev, sizeof(u32)*8*count+256, + priv->rxring, priv->rxringdma); +#else + pci_free_consistent(pdev, sizeof(u32)*4*count+256, + priv->rxring, priv->rxringdma); +#endif + + buffer_free(dev,&(priv->rxbuffer),priv->rxbuffersize,0); +} + + +short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) +{ + int i; + u32 *desc; + u32 *tmp; + dma_addr_t dma_desc,dma_tmp; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct pci_dev *pdev=priv->pdev; + void *buf; + u8 rx_desc_size; + +#ifdef CONFIG_RTL8185B + rx_desc_size = 8; // 4*8 = 32 bytes +#else + rx_desc_size = 4; +#endif + + if((bufsize & 0xfff) != bufsize){ + DMESGE ("RX buffer allocation too large"); + return -1; + } + + desc = (u32*)pci_alloc_consistent(pdev,sizeof(u32)*rx_desc_size*count+256, + &dma_desc); + + if(dma_desc & 0xff){ + + /* + * descriptor's buffer must be 256 byte aligned + * should never happen since we specify the DMA mask + */ + + DMESGW("Fixing RX alignment"); + desc = (u32*)((u8*)desc + 256); +#if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR)) + desc = (u32*)((u64)desc &~ 0xff); + dma_desc = (dma_addr_t)((u8*)dma_desc + 256); + dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff); +#else + desc = (u32*)((u32)desc &~ 0xff); + dma_desc = (dma_addr_t)((u8*)dma_desc + 256); + dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff); +#endif + } + + priv->rxring=desc; + priv->rxringdma=dma_desc; + tmp=desc; + + for (i=0;i<count;i++){ + + if ((buf= kmalloc(bufsize * sizeof(u8),GFP_ATOMIC)) == NULL){ + DMESGE("Failed to kmalloc RX buffer"); + return -1; + } + + dma_tmp = pci_map_single(pdev,buf,bufsize * sizeof(u8), + PCI_DMA_FROMDEVICE); + +#ifdef DEBUG_ZERO_RX + int j; + for(j=0;j<bufsize;j++) ((u8*)buf)[i] = 0; +#endif + + //buf = (void*)pci_alloc_consistent(pdev,bufsize,&dma_tmp); + if(-1 == buffer_add(&(priv->rxbuffer), buf,dma_tmp, + &(priv->rxbufferhead))){ + DMESGE("Unable to allocate mem RX buf"); + return -1; + } + *tmp = 0; //zero pads the header of the descriptor + *tmp = *tmp |( bufsize&0xfff); + *(tmp+2) = (u32)dma_tmp; + *tmp = *tmp |(1<<31); // descriptor void, owned by the NIC + +#ifdef DEBUG_RXALLOC + DMESG("Alloc %x size buffer, DMA mem @ %x, virtual mem @ %x", + (u32)(bufsize&0xfff), (u32)dma_tmp, (u32)buf); +#endif + + tmp=tmp+rx_desc_size; + } + + *(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); // this is the last descriptor + + +#ifdef DEBUG_RXALLOC + DMESG("RX DMA physical address: %x",dma_desc); +#endif + + return 0; +} + + +void set_nic_rxring(struct net_device *dev) +{ + u8 pgreg; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + //rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + + pgreg=read_nic_byte(dev, PGSELECT); + write_nic_byte(dev, PGSELECT, pgreg &~ (1<<PGSELECT_PG_SHIFT)); + + //rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + + write_nic_dword(dev, RXRING_ADDR,priv->rxringdma); +} + + +void rtl8180_reset(struct net_device *dev) +{ + //u32 txconf = 0x80e00707; //FIXME: Make me understandable + u8 cr; + + //write_nic_dword(dev,TX_CONF,txconf); + + rtl8180_irq_disable(dev); + + cr=read_nic_byte(dev,CMD); + cr = cr & 2; + cr = cr | (1<<CMD_RST_SHIFT); + write_nic_byte(dev,CMD,cr); + + force_pci_posting(dev); + + mdelay(200); + + if(read_nic_byte(dev,CMD) & (1<<CMD_RST_SHIFT)) + DMESGW("Card reset timeout!"); + else + DMESG("Card successfully reset"); + +//#ifndef CONFIG_RTL8185B + rtl8180_set_mode(dev,EPROM_CMD_LOAD); + force_pci_posting(dev); + mdelay(200); +//#endif +} + +inline u16 ieeerate2rtlrate(int rate) +{ + switch(rate){ + case 10: + return 0; + case 20: + return 1; + case 55: + return 2; + case 110: + return 3; + case 60: + return 4; + case 90: + return 5; + case 120: + return 6; + case 180: + return 7; + case 240: + return 8; + case 360: + return 9; + case 480: + return 10; + case 540: + return 11; + default: + return 3; + + } +} + +static u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540,720}; +inline u16 rtl8180_rate2rate(short rate) +{ + if (rate >12) return 10; + return rtl_rate[rate]; +} +inline u8 rtl8180_IsWirelessBMode(u16 rate) +{ + if( ((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220) ) + return 1; + else return 0; +} +u16 N_DBPSOfRate(u16 DataRate); +u16 ComputeTxTime( + u16 FrameLength, + u16 DataRate, + u8 bManagementFrame, + u8 bShortPreamble +) +{ + u16 FrameTime; + u16 N_DBPS; + u16 Ceiling; + + if( rtl8180_IsWirelessBMode(DataRate) ) + { + if( bManagementFrame || !bShortPreamble || DataRate == 10 ) + { // long preamble + FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10))); + } + else + { // Short preamble + FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10))); + } + if( ( FrameLength*8 % (DataRate/10) ) != 0 ) //Get the Ceilling + FrameTime ++; + } else { //802.11g DSSS-OFDM PLCP length field calculation. + N_DBPS = N_DBPSOfRate(DataRate); + Ceiling = (16 + 8*FrameLength + 6) / N_DBPS + + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0); + FrameTime = (u16)(16 + 4 + 4*Ceiling + 6); + } + return FrameTime; +} +u16 N_DBPSOfRate(u16 DataRate) +{ + u16 N_DBPS = 24; + + switch(DataRate) + { + case 60: + N_DBPS = 24; + break; + + case 90: + N_DBPS = 36; + break; + + case 120: + N_DBPS = 48; + break; + + case 180: + N_DBPS = 72; + break; + + case 240: + N_DBPS = 96; + break; + + case 360: + N_DBPS = 144; + break; + + case 480: + N_DBPS = 192; + break; + + case 540: + N_DBPS = 216; + break; + + default: + break; + } + + return N_DBPS; +} + +//{by amy 080312 +// +// Description: +// For Netgear case, they want good-looking singal strength. +// 2004.12.05, by rcnjko. +// +long +NetgearSignalStrengthTranslate( + long LastSS, + long CurrSS + ) +{ + long RetSS; + + // Step 1. Scale mapping. + if(CurrSS >= 71 && CurrSS <= 100) + { + RetSS = 90 + ((CurrSS - 70) / 3); + } + else if(CurrSS >= 41 && CurrSS <= 70) + { + RetSS = 78 + ((CurrSS - 40) / 3); + } + else if(CurrSS >= 31 && CurrSS <= 40) + { + RetSS = 66 + (CurrSS - 30); + } + else if(CurrSS >= 21 && CurrSS <= 30) + { + RetSS = 54 + (CurrSS - 20); + } + else if(CurrSS >= 5 && CurrSS <= 20) + { + RetSS = 42 + (((CurrSS - 5) * 2) / 3); + } + else if(CurrSS == 4) + { + RetSS = 36; + } + else if(CurrSS == 3) + { + RetSS = 27; + } + else if(CurrSS == 2) + { + RetSS = 18; + } + else if(CurrSS == 1) + { + RetSS = 9; + } + else + { + RetSS = CurrSS; + } + //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); + + // Step 2. Smoothing. + if(LastSS > 0) + { + RetSS = ((LastSS * 5) + (RetSS)+ 5) / 6; + } + //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); + + return RetSS; +} +// +// Description: +// Translate 0-100 signal strength index into dBm. +// +long +TranslateToDbm8185( + u8 SignalStrengthIndex // 0-100 index. + ) +{ + long SignalPower; // in dBm. + + // Translate to dBm (x=0.5y-95). + SignalPower = (long)((SignalStrengthIndex + 1) >> 1); + SignalPower -= 95; + + return SignalPower; +} +// +// Description: +// Perform signal smoothing for dynamic mechanism. +// This is different with PerformSignalSmoothing8185 in smoothing fomula. +// No dramatic adjustion is apply because dynamic mechanism need some degree +// of correctness. Ported from 8187B. +// 2007-02-26, by Bruce. +// +void +PerformUndecoratedSignalSmoothing8185( + struct r8180_priv *priv, + bool bCckRate + ) +{ + + + // Determin the current packet is CCK rate. + priv->bCurCCKPkt = bCckRate; + + if(priv->UndecoratedSmoothedSS >= 0) + { + priv->UndecoratedSmoothedSS = ( (priv->UndecoratedSmoothedSS * 5) + (priv->SignalStrength * 10) ) / 6; + } + else + { + priv->UndecoratedSmoothedSS = priv->SignalStrength * 10; + } + + priv->UndercorateSmoothedRxPower = ( (priv->UndercorateSmoothedRxPower * 50) + (priv->RxPower* 11)) / 60; + +// printk("Sommthing SignalSterngth (%d) => UndecoratedSmoothedSS (%d)\n", priv->SignalStrength, priv->UndecoratedSmoothedSS); +// printk("Sommthing RxPower (%d) => UndecoratedRxPower (%d)\n", priv->RxPower, priv->UndercorateSmoothedRxPower); + + //if(priv->CurCCKRSSI >= 0 && bCckRate) + if(bCckRate) + { + priv->CurCCKRSSI = priv->RSSI; + } + else + { + priv->CurCCKRSSI = 0; + } + + // Boundary checking. + // TODO: The overflow condition does happen, if we want to fix, + // we shall recalculate thresholds first. + if(priv->UndecoratedSmoothedSS > 100) + { +// printk("UndecoratedSmoothedSS(%d) overflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength); + } + if(priv->UndecoratedSmoothedSS < 0) + { +// printk("UndecoratedSmoothedSS(%d) underflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength); + } + +} + +//by amy 080312} + +/* This is rough RX isr handling routine*/ +void rtl8180_rx(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct sk_buff *tmp_skb; + + //struct sk_buff *skb; + short first,last; + u32 len; + int lastlen; + unsigned char quality, signal; + u8 rate; + //u32 *prism_hdr; + u32 *tmp,*tmp2; + u8 rx_desc_size; + u8 padding; + //u32 count=0; + char rxpower = 0; + u32 RXAGC = 0; + long RxAGC_dBm = 0; + u8 LNA=0, BB=0; + u8 LNA_gain[4]={02, 17, 29, 39}; + u8 Antenna = 0; + struct ieee80211_hdr *hdr;//by amy + u16 fc,type; + u8 bHwError = 0,bCRC = 0,bICV = 0; + //bHwError = 0; + //bCRC = 0; + //bICV = 0; + bool bCckRate = false; + u8 RSSI = 0; + long SignalStrengthIndex = 0;//+by amy 080312 +// u8 SignalStrength = 0; + struct ieee80211_rx_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + // .mac_time = jiffies, + .freq = IEEE80211_24GHZ_BAND, + }; + +#ifdef CONFIG_RTL8185B + stats.nic_type = NIC_8185B; + rx_desc_size = 8; + +#else + stats.nic_type = NIC_8185; + rx_desc_size = 4; +#endif + //printk("receive frame!%d\n",count++); + //if (!priv->rxbuffer) DMESG ("EE: NIC RX ack, but RX queue corrupted!"); + //else { + + if ((*(priv->rxringtail)) & (1<<31)) { + + /* we have got an RX int, but the descriptor + * we are pointing is empty*/ + + priv->stats.rxnodata++; + priv->ieee80211->stats.rx_errors++; + + /* if (! *(priv->rxring) & (1<<31)) { + + priv->stats.rxreset++; + priv->rxringtail=priv->rxring; + priv->rxbuffer=priv->rxbufferhead; + + }else{*/ + + #if 0 + /* Maybe it is possible that the NIC has skipped some descriptors or + * it has reset its internal pointer to the beginning of the ring + * we search for the first filled descriptor in the ring, or we break + * putting again the pointer in the old location if we do not found any. + * This is quite dangerous, what does happen if the nic writes + * two descriptor (say A and B) when we have just checked the descriptor + * A and we are going to check the descriptor B..This might happen if the + * interrupt was dummy, there was not really filled descriptors and + * the NIC didn't lose pointer + */ + + //priv->stats.rxwrkaround++; + + tmp = priv->rxringtail; + while (*(priv->rxringtail) & (1<<31)){ + + priv->rxringtail+=4; + + if(priv->rxringtail >= + (priv->rxring)+(priv->rxringcount )*4) + priv->rxringtail=priv->rxring; + + priv->rxbuffer=(priv->rxbuffer->next); + + if(priv->rxringtail == tmp ){ + //DMESG("EE: Could not find RX pointer"); + priv->stats.rxnopointer++; + break; + } + } + #else + + tmp2 = NULL; + tmp = priv->rxringtail; + do{ + if(tmp == priv->rxring) + //tmp = priv->rxring + (priv->rxringcount )*rx_desc_size; xiong-2006-11-15 + tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size; + else + tmp -= rx_desc_size; + + if(! (*tmp & (1<<31))) + tmp2 = tmp; + }while(tmp != priv->rxring); + + if(tmp2) priv->rxringtail = tmp2; + #endif + //} + } + + /* while there are filled descriptors */ + while(!(*(priv->rxringtail) & (1<<31))){ + if(*(priv->rxringtail) & (1<<26)) + DMESGW("RX buffer overflow"); + if(*(priv->rxringtail) & (1<<12)) + priv->stats.rxicverr++; + + if(*(priv->rxringtail) & (1<<27)){ + priv->stats.rxdmafail++; + //DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); + goto drop; + } + + pci_dma_sync_single_for_cpu(priv->pdev, + priv->rxbuffer->dma, + priv->rxbuffersize * \ + sizeof(u8), + PCI_DMA_FROMDEVICE); + + first = *(priv->rxringtail) & (1<<29) ? 1:0; + if(first) priv->rx_prevlen=0; + + last = *(priv->rxringtail) & (1<<28) ? 1:0; + if(last){ + lastlen=((*priv->rxringtail) &0xfff); + + /* if the last descriptor (that should + * tell us the total packet len) tell + * us something less than the descriptors + * len we had until now, then there is some + * problem.. + * workaround to prevent kernel panic + */ + if(lastlen < priv->rx_prevlen) + len=0; + else + len=lastlen-priv->rx_prevlen; + + if(*(priv->rxringtail) & (1<<13)) { +//lastlen=((*priv->rxringtail) &0xfff); + if ((*(priv->rxringtail) & 0xfff) <500) + priv->stats.rxcrcerrmin++; + else if ((*(priv->rxringtail) & 0x0fff) >1000) + priv->stats.rxcrcerrmax++; + else + priv->stats.rxcrcerrmid++; + + } + + }else{ + len = priv->rxbuffersize; + } + +#ifdef CONFIG_RTL8185B + if(first && last) { + padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; + }else if(first) { + padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; + if(padding) { + len -= 2; + } + }else { + padding = 0; + } +#ifdef CONFIG_RTL818X_S + padding = 0; +#endif +#endif + priv->rx_prevlen+=len; + + if(priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100){ + /* HW is probably passing several buggy frames + * without FD or LD flag set. + * Throw this garbage away to prevent skb + * memory exausting + */ + if(!priv->rx_skb_complete) + dev_kfree_skb_any(priv->rx_skb); + priv->rx_skb_complete = 1; + } + +#ifdef DEBUG_RX_FRAG + DMESG("Iteration.. len %x",len); + if(first) DMESG ("First descriptor"); + if(last) DMESG("Last descriptor"); + +#endif +#ifdef DEBUG_RX_VERBOSE + print_buffer( priv->rxbuffer->buf, len); +#endif + +#ifdef CONFIG_RTL8185B + signal=(unsigned char)(((*(priv->rxringtail+3))& (0x00ff0000))>>16); + signal=(signal&0xfe)>>1; // Modify by hikaru 6.6 + + quality=(unsigned char)((*(priv->rxringtail+3)) & (0xff)); + + stats.mac_time[0] = *(priv->rxringtail+1); + stats.mac_time[1] = *(priv->rxringtail+2); + rxpower =((char)(((*(priv->rxringtail+4))& (0x00ff0000))>>16))/2 - 42; + RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>> 8)) & (0x7f); + +#else + signal=((*(priv->rxringtail+1))& (0xff0000))>>16; + signal=(signal&0xfe)>>1; // Modify by hikaru 6.6 + + quality=((*(priv->rxringtail+1)) & (0xff)); + + stats.mac_time[0] = *(priv->rxringtail+2); + stats.mac_time[1] = *(priv->rxringtail+3); +#endif + rate=((*(priv->rxringtail)) & + ((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20; + + stats.rate = rtl8180_rate2rate(rate); + //DMESG("%d",rate); + Antenna = (((*(priv->rxringtail +3))& (0x00008000)) == 0 )? 0:1 ; +// printk("in rtl8180_rx():Antenna is %d\n",Antenna); +//by amy for antenna + if(!rtl8180_IsWirelessBMode(stats.rate)) + { // OFDM rate. + + RxAGC_dBm = rxpower+1; //bias + } + else + { // CCK rate. + RxAGC_dBm = signal;//bit 0 discard + + LNA = (u8) (RxAGC_dBm & 0x60 ) >> 5 ; //bit 6~ bit 5 + BB = (u8) (RxAGC_dBm & 0x1F); // bit 4 ~ bit 0 + + RxAGC_dBm = -( LNA_gain[LNA] + (BB *2) ); //Pin_11b=-(LNA_gain+BB_gain) (dBm) + + RxAGC_dBm +=4; //bias + } + + if(RxAGC_dBm & 0x80) //absolute value + RXAGC= ~(RxAGC_dBm)+1; + bCckRate = rtl8180_IsWirelessBMode(stats.rate); + // Translate RXAGC into 1-100. + if(!rtl8180_IsWirelessBMode(stats.rate)) + { // OFDM rate. + if(RXAGC>90) + RXAGC=90; + else if(RXAGC<25) + RXAGC=25; + RXAGC=(90-RXAGC)*100/65; + } + else + { // CCK rate. + if(RXAGC>95) + RXAGC=95; + else if(RXAGC<30) + RXAGC=30; + RXAGC=(95-RXAGC)*100/65; + } + priv->SignalStrength = (u8)RXAGC; + priv->RecvSignalPower = RxAGC_dBm ; // It can use directly by SD3 CMLin + priv->RxPower = rxpower; + priv->RSSI = RSSI; +//{by amy 080312 + // SQ translation formular is provided by SD3 DZ. 2006.06.27, by rcnjko. + if(quality >= 127) + quality = 1;//0; //0 will cause epc to show signal zero , walk aroud now; + else if(quality < 27) + quality = 100; + else + quality = 127 - quality; + priv->SignalQuality = quality; + if(!priv->card_8185) + printk("check your card type\n"); + + stats.signal = (u8)quality;//priv->wstats.qual.level = priv->SignalStrength; + stats.signalstrength = RXAGC; + if(stats.signalstrength > 100) + stats.signalstrength = 100; + stats.signalstrength = (stats.signalstrength * 70)/100 + 30; + // printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); + stats.rssi = priv->wstats.qual.qual = priv->SignalQuality; + stats.noise = priv->wstats.qual.noise = 100 - priv ->wstats.qual.qual; +//by amy 080312} + bHwError = (((*(priv->rxringtail))& (0x00000fff)) == 4080)| (((*(priv->rxringtail))& (0x04000000)) != 0 ) + | (((*(priv->rxringtail))& (0x08000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x10000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x20000000)) != 0 ); + bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13; + bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12; + hdr = (struct ieee80211_hdr *)priv->rxbuffer->buf; + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + + if((IEEE80211_FTYPE_CTL != type) && + (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) + && (!bHwError) && (!bCRC)&& (!bICV)) + { +//by amy 080312 + // Perform signal smoothing for dynamic mechanism on demand. + // This is different with PerformSignalSmoothing8185 in smoothing fomula. + // No dramatic adjustion is apply because dynamic mechanism need some degree + // of correctness. 2007.01.23, by shien chang. + PerformUndecoratedSignalSmoothing8185(priv,bCckRate); + // + // For good-looking singal strength. + // + SignalStrengthIndex = NetgearSignalStrengthTranslate( + priv->LastSignalStrengthInPercent, + priv->SignalStrength); + + priv->LastSignalStrengthInPercent = SignalStrengthIndex; + priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex); + // + // We need more correct power of received packets and the "SignalStrength" of RxStats is beautified, + // so we record the correct power here. + // + priv->Stats_SignalQuality =(long) (priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6; + priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower -1) / 6; + + // Figure out which antenna that received the lasted packet. + priv->LastRxPktAntenna = Antenna ? 1 : 0; // 0: aux, 1: main. +//by amy 080312 + SwAntennaDiversityRxOk8185(dev, priv->SignalStrength); + } + +//by amy for antenna + + + + + + +#ifndef DUMMY_RX + if(first){ + if(!priv->rx_skb_complete){ + /* seems that HW sometimes fails to reiceve and + doesn't provide the last descriptor */ +#ifdef DEBUG_RX_SKB + DMESG("going to free incomplete skb"); +#endif + dev_kfree_skb_any(priv->rx_skb); + priv->stats.rxnolast++; +#ifdef DEBUG_RX_SKB + DMESG("free incomplete skb OK"); +#endif + } + /* support for prism header has been originally added by Christian */ + if(priv->prism_hdr && priv->ieee80211->iw_mode == IW_MODE_MONITOR){ + +#if 0 + priv->rx_skb = dev_alloc_skb(len+2+PRISM_HDR_SIZE); + if(! priv->rx_skb) goto drop; + + prism_hdr = (u32*) skb_put(priv->rx_skb,PRISM_HDR_SIZE); + prism_hdr[0]=htonl(0x80211001); //version + prism_hdr[1]=htonl(0x40); //length + prism_hdr[2]=htonl(stats.mac_time[1]); //mactime (HIGH) + prism_hdr[3]=htonl(stats.mac_time[0]); //mactime (LOW) + rdtsc(prism_hdr[5], prism_hdr[4]); //hostime (LOW+HIGH) + prism_hdr[4]=htonl(prism_hdr[4]); //Byte-Order aendern + prism_hdr[5]=htonl(prism_hdr[5]); //Byte-Order aendern + prism_hdr[6]=0x00; //phytype + prism_hdr[7]=htonl(priv->chan); //channel + prism_hdr[8]=htonl(stats.rate); //datarate + prism_hdr[9]=0x00; //antenna + prism_hdr[10]=0x00; //priority + prism_hdr[11]=0x00; //ssi_type + prism_hdr[12]=htonl(stats.signal); //ssi_signal + prism_hdr[13]=htonl(stats.noise); //ssi_noise + prism_hdr[14]=0x00; //preamble + prism_hdr[15]=0x00; //encoding + +#endif + }else{ + priv->rx_skb = dev_alloc_skb(len+2); + if( !priv->rx_skb) goto drop; +#ifdef DEBUG_RX_SKB + DMESG("Alloc initial skb %x",len+2); +#endif + } + + priv->rx_skb_complete=0; + priv->rx_skb->dev=dev; + }else{ + /* if we are here we should have already RXed + * the first frame. + * If we get here and the skb is not allocated then + * we have just throw out garbage (skb not allocated) + * and we are still rxing garbage.... + */ + if(!priv->rx_skb_complete){ + + tmp_skb= dev_alloc_skb(priv->rx_skb->len +len+2); + + if(!tmp_skb) goto drop; + + tmp_skb->dev=dev; +#ifdef DEBUG_RX_SKB + DMESG("Realloc skb %x",len+2); +#endif + +#ifdef DEBUG_RX_SKB + DMESG("going copy prev frag %x",priv->rx_skb->len); +#endif + memcpy(skb_put(tmp_skb,priv->rx_skb->len), + priv->rx_skb->data, + priv->rx_skb->len); +#ifdef DEBUG_RX_SKB + DMESG("skb copy prev frag complete"); +#endif + + dev_kfree_skb_any(priv->rx_skb); +#ifdef DEBUG_RX_SKB + DMESG("prev skb free ok"); +#endif + + priv->rx_skb=tmp_skb; + } + } +#ifdef DEBUG_RX_SKB + DMESG("going to copy current payload %x",len); +#endif + if(!priv->rx_skb_complete) { +#ifdef CONFIG_RTL8185B + if(padding) { + memcpy(skb_put(priv->rx_skb,len), + (((unsigned char *)priv->rxbuffer->buf) + 2),len); + } else { +#endif + memcpy(skb_put(priv->rx_skb,len), + priv->rxbuffer->buf,len); +#ifdef CONFIG_RTL8185B + } +#endif + } +#ifdef DEBUG_RX_SKB + DMESG("current fragment skb copy complete"); +#endif + + if(last && !priv->rx_skb_complete){ + +#ifdef DEBUG_RX_SKB + DMESG("Got last fragment"); +#endif + + if(priv->rx_skb->len > 4) + skb_trim(priv->rx_skb,priv->rx_skb->len-4); +#ifdef DEBUG_RX_SKB + DMESG("yanked out crc, passing to the upper layer"); +#endif + +#ifndef RX_DONT_PASS_UL + if(!ieee80211_rx(priv->ieee80211, + priv->rx_skb, &stats)){ +#ifdef DEBUG_RX + DMESGW("Packet not consumed"); +#endif +#endif // RX_DONT_PASS_UL + + dev_kfree_skb_any(priv->rx_skb); +#ifndef RX_DONT_PASS_UL + } +#endif +#ifdef DEBUG_RX + else{ + DMESG("Rcv frag"); + } +#endif + priv->rx_skb_complete=1; + } + +#endif //DUMMY_RX + + pci_dma_sync_single_for_device(priv->pdev, + priv->rxbuffer->dma, + priv->rxbuffersize * \ + sizeof(u8), + PCI_DMA_FROMDEVICE); + + +drop: // this is used when we have not enought mem + + /* restore the descriptor */ + *(priv->rxringtail+2)=priv->rxbuffer->dma; + *(priv->rxringtail)=*(priv->rxringtail) &~ 0xfff; + *(priv->rxringtail)= + *(priv->rxringtail) | priv->rxbuffersize; + + *(priv->rxringtail)= + *(priv->rxringtail) | (1<<31); + //^empty descriptor + + //wmb(); + +#ifdef DEBUG_RX + DMESG("Current descriptor: %x",(u32)priv->rxringtail); +#endif + //unsigned long flags; + //spin_lock_irqsave(&priv->irq_lock,flags); + + priv->rxringtail+=rx_desc_size; + if(priv->rxringtail >= + (priv->rxring)+(priv->rxringcount )*rx_desc_size) + priv->rxringtail=priv->rxring; + + //spin_unlock_irqrestore(&priv->irq_lock,flags); + + + priv->rxbuffer=(priv->rxbuffer->next); + + } + + + +// if(get_curr_tx_free_desc(dev,priority)) +// ieee80211_sta_ps_sleep(priv->ieee80211, &tmp, &tmp2); + + + +} + + +void rtl8180_dma_kick(struct net_device *dev, int priority) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); +/* + + switch(priority){ + + case LOW_PRIORITY: + + write_nic_byte(dev,TX_DMA_POLLING, + (1<< TX_DMA_POLLING_LOWPRIORITY_SHIFT) | + priv->dma_poll_mask); + break; + + case NORM_PRIORITY: + + write_nic_byte(dev,TX_DMA_POLLING, + (1<< TX_DMA_POLLING_NORMPRIORITY_SHIFT) | + priv->dma_poll_mask); + break; + + case HI_PRIORITY: + + write_nic_byte(dev,TX_DMA_POLLING, + (1<< TX_DMA_POLLING_HIPRIORITY_SHIFT) | + priv->dma_poll_mask); + break; + + } +*/ + write_nic_byte(dev, TX_DMA_POLLING, + (1 << (priority + 1)) | priv->dma_poll_mask); + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); + + force_pci_posting(dev); +} + +#if 0 +void rtl8180_tx_queues_stop(struct net_device *dev) +{ + //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u8 dma_poll_mask = (1<<TX_DMA_STOP_LOWPRIORITY_SHIFT); + dma_poll_mask |= (1<<TX_DMA_STOP_HIPRIORITY_SHIFT); + dma_poll_mask |= (1<<TX_DMA_STOP_NORMPRIORITY_SHIFT); + dma_poll_mask |= (1<<TX_DMA_STOP_BEACON_SHIFT); + + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); + write_nic_byte(dev,TX_DMA_POLLING,dma_poll_mask); + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); +} +#endif + +void rtl8180_data_hard_stop(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); +#ifdef CONFIG_RTL8185B + priv->dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ; + write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); +#else + priv->dma_poll_mask |= (1<<TX_DMA_STOP_LOWPRIORITY_SHIFT); + write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); +#endif + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); +} + + +void rtl8180_data_hard_resume(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); +#ifdef CONFIG_RTL8185B + priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ); + write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); +#else + priv->dma_poll_mask &= ~(1<<TX_DMA_STOP_LOWPRIORITY_SHIFT); + write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); +#endif + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); +} + + +/* this function TX data frames when the ieee80211 stack requires this. + * It checks also if we need to stop the ieee tx queue, eventually do it + */ +void rtl8180_hard_data_xmit(struct sk_buff *skb,struct net_device *dev, int +rate) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + int mode; + struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; + short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS; + unsigned long flags; + int priority; + //static int count = 0; + + mode = priv->ieee80211->iw_mode; + + rate = ieeerate2rtlrate(rate); + /* + * This function doesn't require lock because we make + * sure it's called with the tx_lock already acquired. + * this come from the kernel's hard_xmit callback (trought + * the ieee stack, or from the try_wake_queue (again trought + * the ieee stack. + */ +#ifdef CONFIG_RTL8185B + priority = AC2Q(skb->priority); +#else + priority = LOW_PRIORITY; +#endif + spin_lock_irqsave(&priv->tx_lock,flags); + + if(priv->ieee80211->bHwRadioOff) + { + spin_unlock_irqrestore(&priv->tx_lock,flags); + + return; + } + + //printk(KERN_WARNING "priority = %d@%d\n", priority, count++); + if (!check_nic_enought_desc(dev, priority)){ + //DMESG("Error: no descriptor left by previous TX (avail %d) ", + // get_curr_tx_free_desc(dev, priority)); + DMESGW("Error: no descriptor left by previous TX (avail %d) ", + get_curr_tx_free_desc(dev, priority)); + //printk(KERN_WARNING "==============================================================> \n"); + ieee80211_stop_queue(priv->ieee80211); + } + rtl8180_tx(dev, skb->data, skb->len, priority, morefrag,0,rate); + if (!check_nic_enought_desc(dev, priority)) + ieee80211_stop_queue(priv->ieee80211); + + //dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&priv->tx_lock,flags); + +} + +/* This is a rough attempt to TX a frame + * This is called by the ieee 80211 stack to TX management frames. + * If the ring is full packet are dropped (for data frame the queue + * is stopped before this can happen). For this reason it is better + * if the descriptors are larger than the largest management frame + * we intend to TX: i'm unsure what the HW does if it will not found + * the last fragment of a frame because it has been dropped... + * Since queues for Management and Data frames are different we + * might use a different lock than tx_lock (for example mgmt_tx_lock) + */ +/* these function may loops if invoked with 0 descriptors or 0 len buffer*/ +int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + unsigned long flags; + + int priority; + +#ifdef CONFIG_RTL8185B + priority = MANAGE_PRIORITY; +#else + priority = NORM_PRIORITY; +#endif + + spin_lock_irqsave(&priv->tx_lock,flags); + + if(priv->ieee80211->bHwRadioOff) + { + spin_unlock_irqrestore(&priv->tx_lock,flags); + + dev_kfree_skb_any(skb); + return 0; + } + + rtl8180_tx(dev, skb->data, skb->len, priority, + 0, 0,ieeerate2rtlrate(priv->ieee80211->basic_rate)); + + priv->ieee80211->stats.tx_bytes+=skb->len; + priv->ieee80211->stats.tx_packets++; + spin_unlock_irqrestore(&priv->tx_lock,flags); + + dev_kfree_skb_any(skb); + return 0; +} + +// longpre 144+48 shortpre 72+24 +u16 rtl8180_len2duration(u32 len, short rate,short* ext) +{ + u16 duration; + u16 drift; + *ext=0; + + switch(rate){ + case 0://1mbps + *ext=0; + duration = ((len+4)<<4) /0x2; + drift = ((len+4)<<4) % 0x2; + if(drift ==0 ) break; + duration++; + break; + + case 1://2mbps + *ext=0; + duration = ((len+4)<<4) /0x4; + drift = ((len+4)<<4) % 0x4; + if(drift ==0 ) break; + duration++; + break; + + case 2: //5.5mbps + *ext=0; + duration = ((len+4)<<4) /0xb; + drift = ((len+4)<<4) % 0xb; + if(drift ==0 ) + break; + duration++; + break; + + default: + case 3://11mbps + *ext=0; + duration = ((len+4)<<4) /0x16; + drift = ((len+4)<<4) % 0x16; + if(drift ==0 ) + break; + duration++; + if(drift > 6) + break; + *ext=1; + break; + } + + return duration; +} + + +void rtl8180_prepare_beacon(struct net_device *dev) +{ + + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + struct sk_buff *skb; + + u16 word = read_nic_word(dev, BcnItv); + word &= ~BcnItv_BcnItv; // clear Bcn_Itv + word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval);//0x64; + write_nic_word(dev, BcnItv, word); + + + skb = ieee80211_get_beacon(priv->ieee80211); + if(skb){ + rtl8180_tx(dev,skb->data,skb->len,BEACON_PRIORITY, + 0,0,ieeerate2rtlrate(priv->ieee80211->basic_rate)); + dev_kfree_skb_any(skb); + } + #if 0 + //DMESG("size %x",len); + if(*tail & (1<<31)){ + + //DMESG("No more beacon TX desc"); + return ; + + } + //while(! *tail & (1<<31)){ + *tail= 0; // zeroes header + + *tail = *tail| (1<<29) ; //fist segment of the packet + *tail = (*tail) | (1<<28); // last segment + // *tail = *tail | (1<<18); // this is a beacon frame + *(tail+3)=*(tail+3) &~ 0xfff; + *(tail+3)=*(tail+3) | len; // buffer lenght + *tail = *tail |len; + // zeroes the second 32-bits dword of the descriptor + *(tail+1)= 0; + *tail = *tail | (rate << 24); + + duration = rtl8180_len2duration(len,rate,&ext); + + *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16); + + *tail = *tail | (1<<31); + //^ descriptor ready to be txed + if((tail - begin)/8 == priv->txbeaconcount-1) + tail=begin; + else + tail=tail+8; + //} +#endif +} + +/* This function do the real dirty work: it enqueues a TX command + * descriptor in the ring buffer, copyes the frame in a TX buffer + * and kicks the NIC to ensure it does the DMA transfer. + */ +short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority, + short morefrag, short descfrag, int rate) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32 *tail,*temp_tail; + u32 *begin; + u32 *buf; + int i; + int remain; + int buflen; + int count; + //u16 AckCtsTime; + //u16 FrameTime; + u16 duration; + short ext; + struct buffer* buflist; + //unsigned long flags; +#ifdef CONFIG_RTL8185B + struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf; + u8 dest[ETH_ALEN]; + u8 bUseShortPreamble = 0; + u8 bCTSEnable = 0; + u8 bRTSEnable = 0; + //u16 RTSRate = 22; + //u8 RetryLimit = 0; + u16 Duration = 0; + u16 RtsDur = 0; + u16 ThisFrameTime = 0; + u16 TxDescDuration = 0; + u8 ownbit_flag = false; //added by david woo for sync Tx, 2007.12.14 +#endif + + switch(priority) { + case MANAGE_PRIORITY: + tail=priv->txmapringtail; + begin=priv->txmapring; + buflist = priv->txmapbufstail; + count = priv->txringcount; + break; + + case BK_PRIORITY: + tail=priv->txbkpringtail; + begin=priv->txbkpring; + buflist = priv->txbkpbufstail; + count = priv->txringcount; + break; + + case BE_PRIORITY: + tail=priv->txbepringtail; + begin=priv->txbepring; + buflist = priv->txbepbufstail; + count = priv->txringcount; + break; + + case VI_PRIORITY: + tail=priv->txvipringtail; + begin=priv->txvipring; + buflist = priv->txvipbufstail; + count = priv->txringcount; + break; + + case VO_PRIORITY: + tail=priv->txvopringtail; + begin=priv->txvopring; + buflist = priv->txvopbufstail; + count = priv->txringcount; + break; + + case HI_PRIORITY: + tail=priv->txhpringtail; + begin=priv->txhpring; + buflist = priv->txhpbufstail; + count = priv->txringcount; + break; + + case BEACON_PRIORITY: + tail=priv->txbeaconringtail; + begin=priv->txbeaconring; + buflist = priv->txbeaconbufstail; + count = priv->txbeaconcount; + break; + + default: + return -1; + break; + } + + //printk("in rtl8180_tx(): rate is %d\n",priv->ieee80211->rate); +#if 1 + memcpy(&dest, frag_hdr->addr1, ETH_ALEN); + if (is_multicast_ether_addr(dest) || + is_broadcast_ether_addr(dest)) + { + Duration = 0; + RtsDur = 0; + bRTSEnable = 0; + bCTSEnable = 0; + + ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble); + TxDescDuration = ThisFrameTime; + } else {// Unicast packet + //u8 AckRate; + u16 AckTime; + + //YJ,add,080828,for Keep alive + priv->NumTxUnicast++; + + // Figure out ACK rate according to BSS basic rate and Tx rate, 2006.03.08 by rcnjko. + //AckRate = ComputeAckRate( pMgntInfo->mBrates, (u1Byte)(pTcb->DataRate) ); + // Figure out ACK time according to the AckRate and assume long preamble is used on receiver, 2006.03.08, by rcnjko. + //AckTime = ComputeTxTime( sAckCtsLng/8, AckRate, FALSE, FALSE); + //For simplicity, just use the 1M basic rate + //AckTime = ComputeTxTime(14, 540,0, 0); // AckCTSLng = 14 use 1M bps send + AckTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send + //AckTime = ComputeTxTime(14, 2,false, false); // AckCTSLng = 14 use 1M bps send + + if ( ((len + sCrcLng) > priv->rts) && priv->rts ) + { // RTS/CTS. + u16 RtsTime, CtsTime; + //u16 CtsRate; + bRTSEnable = 1; + bCTSEnable = 0; + + // Rate and time required for RTS. + RtsTime = ComputeTxTime( sAckCtsLng/8,priv->ieee80211->basic_rate, 0, 0); + // Rate and time required for CTS. + CtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send + + // Figure out time required to transmit this frame. + ThisFrameTime = ComputeTxTime(len + sCrcLng, + rtl8180_rate2rate(rate), + 0, + bUseShortPreamble); + + // RTS-CTS-ThisFrame-ACK. + RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime; + + TxDescDuration = RtsTime + RtsDur; + } + else {// Normal case. + bCTSEnable = 0; + bRTSEnable = 0; + RtsDur = 0; + + ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble); + TxDescDuration = ThisFrameTime + aSifsTime + AckTime; + } + + if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment + // ThisFrame-ACK. + Duration = aSifsTime + AckTime; + } else { // One or more fragments remained. + u16 NextFragTime; + NextFragTime = ComputeTxTime( len + sCrcLng, //pretend following packet length equal current packet + rtl8180_rate2rate(rate), + 0, + bUseShortPreamble ); + + //ThisFrag-ACk-NextFrag-ACK. + Duration = NextFragTime + 3*aSifsTime + 2*AckTime; + } + + } // End of Unicast packet + + frag_hdr->duration_id = Duration; +#endif + + buflen=priv->txbuffsize; + remain=len; + temp_tail = tail; +//printk("================================>buflen = %d, remain = %d!\n", buflen,remain); + while(remain!=0){ +#ifdef DEBUG_TX_FRAG + DMESG("TX iteration"); +#endif +#ifdef DEBUG_TX + DMESG("TX: filling descriptor %x",(u32)tail); +#endif + mb(); + if(!buflist){ + DMESGE("TX buffer error, cannot TX frames. pri %d.", priority); + //spin_unlock_irqrestore(&priv->tx_lock,flags); + return -1; + } + buf=buflist->buf; + + if( (*tail & (1<<31)) && (priority != BEACON_PRIORITY)){ + + DMESGW("No more TX desc, returning %x of %x", + remain,len); + priv->stats.txrdu++; +#ifdef DEBUG_TX_DESC + check_tx_ring(dev,priority); + // netif_stop_queue(dev); + // netif_carrier_off(dev); +#endif + // spin_unlock_irqrestore(&priv->tx_lock,flags); + + return remain; + + } + + *tail= 0; // zeroes header + *(tail+1) = 0; + *(tail+3) = 0; + *(tail+5) = 0; + *(tail+6) = 0; + *(tail+7) = 0; + + if(priv->card_8185){ + //FIXME: this should be triggered by HW encryption parameters. + *tail |= (1<<15); //no encrypt +// *tail |= (1<<30); //raise int when completed + } + // *tail = *tail | (1<<16); + if(remain==len && !descfrag) { + ownbit_flag = false; //added by david woo,2007.12.14 +#ifdef DEBUG_TX_FRAG + DMESG("First descriptor"); +#endif + *tail = *tail| (1<<29) ; //fist segment of the packet + *tail = *tail |(len); + } else { + ownbit_flag = true; + } + + for(i=0;i<buflen&& remain >0;i++,remain--){ + ((u8*)buf)[i]=txbuf[i]; //copy data into descriptor pointed DMAble buffer + if(remain == 4 && i+4 >= buflen) break; + /* ensure the last desc has at least 4 bytes payload */ + + } + txbuf = txbuf + i; + *(tail+3)=*(tail+3) &~ 0xfff; + *(tail+3)=*(tail+3) | i; // buffer lenght + // Use short preamble or not + if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE) + if (priv->plcp_preamble_mode==1 && rate!=0) // short mode now, not long! + // *tail |= (1<<16); // enable short preamble mode. + +#ifdef CONFIG_RTL8185B + if(bCTSEnable) { + *tail |= (1<<18); + } + + if(bRTSEnable) //rts enable + { + *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19);//RTS RATE + *tail |= (1<<23);//rts enable + *(tail+1) |=(RtsDur&0xffff);//RTS Duration + } + *(tail+3) |= ((TxDescDuration&0xffff)<<16); //DURATION +// *(tail+3) |= (0xe6<<16); + *(tail+5) |= (11<<8);//(priv->retry_data<<8); //retry lim ; +#else + //Use RTS or not +#ifdef CONFIG_RTL8187B + if ( (len>priv->rts) && priv->rts && priority!=MANAGE_PRIORITY){ +#else + if ( (len>priv->rts) && priv->rts && priority==LOW_PRIORITY){ +#endif + *tail |= (1<<23); //enalbe RTS function + *tail |= (0<<19); //use 1M bps send RTS packet + AckCtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send + FrameTime = ComputeTxTime(len + 4, rtl8180_rate2rate(rate), 0, *tail&(1<<16)); + // RTS/CTS time is calculate as follow + duration = FrameTime + 3*10 + 2*AckCtsTime; //10us is the SifsTime; + *(tail+1) |= duration; //Need to edit here! ----hikaru + }else{ + *(tail+1)= 0; // zeroes the second 32-bits dword of the descriptor + } +#endif + + *tail = *tail | ((rate&0xf) << 24); + //DMESG("rate %d",rate); + + if(priv->card_8185){ + + #if 0 + *(tail+5)&= ~(1<<24); /* tx ant 0 */ + + *(tail+5) &= ~(1<<23); /* random tx agc 23-16 */ + *(tail+5) |= (1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16); + + *(tail+5) &= +~((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)); + *(tail+5) |= (7<<8); // Max retry limit + + *(tail+5) &= ~((1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0)); + *(tail+5) |= (8<<4); // Max contention window + *(tail+6) |= 4; // Min contention window + #endif + // *(tail+5) = 0; + } + + /* hw_plcp_len is not used for rtl8180 chip */ + /* FIXME */ + if(priv->card_8185 == 0 || !priv->hw_plcp_len){ + + duration = rtl8180_len2duration(len, + rate,&ext); + + +#ifdef DEBUG_TX + DMESG("PLCP duration %d",duration ); + //DMESG("drift %d",drift); + DMESG("extension %s", (ext==1) ? "on":"off"); +#endif + *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16); + if(ext) *(tail+1) = *(tail+1) |(1<<31); //plcp length extension + } + + if(morefrag) *tail = (*tail) | (1<<17); // more fragment + if(!remain) *tail = (*tail) | (1<<28); // last segment of frame + +#ifdef DEBUG_TX_FRAG + if(!remain)DMESG("Last descriptor"); + if(morefrag)DMESG("More frag"); +#endif + *(tail+5) = *(tail+5)|(2<<27); + *(tail+7) = *(tail+7)|(1<<4); + + wmb(); + if(ownbit_flag) + { + *tail = *tail | (1<<31); // descriptor ready to be txed + } + +#ifdef DEBUG_TX_DESC2 + printk("tx desc is:\n"); + DMESG("%8x %8x %8x %8x %8x %8x %8x %8x", tail[0], tail[1], tail[2], tail[3], + tail[4], tail[5], tail[6], tail[7]); +#endif + + if((tail - begin)/8 == count-1) + tail=begin; + + else + tail=tail+8; + + buflist=buflist->next; + + mb(); + + switch(priority) { + case MANAGE_PRIORITY: + priv->txmapringtail=tail; + priv->txmapbufstail=buflist; + break; + + case BK_PRIORITY: + priv->txbkpringtail=tail; + priv->txbkpbufstail=buflist; + break; + + case BE_PRIORITY: + priv->txbepringtail=tail; + priv->txbepbufstail=buflist; + break; + + case VI_PRIORITY: + priv->txvipringtail=tail; + priv->txvipbufstail=buflist; + break; + + case VO_PRIORITY: + priv->txvopringtail=tail; + priv->txvopbufstail=buflist; + break; + + case HI_PRIORITY: + priv->txhpringtail=tail; + priv->txhpbufstail = buflist; + break; + + case BEACON_PRIORITY: + /* the HW seems to be happy with the 1st + * descriptor filled and the 2nd empty... + * So always update descriptor 1 and never + * touch 2nd + */ + // priv->txbeaconringtail=tail; + // priv->txbeaconbufstail=buflist; + + break; + + } + + //rtl8180_dma_kick(dev,priority); + } + *temp_tail = *temp_tail | (1<<31); // descriptor ready to be txed + rtl8180_dma_kick(dev,priority); + //spin_unlock_irqrestore(&priv->tx_lock,flags); + + return 0; + +} + + +void rtl8180_irq_rx_tasklet(struct r8180_priv * priv); + + +void rtl8180_link_change(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u16 beacon_interval; + + struct ieee80211_network *net = &priv->ieee80211->current_network; +// rtl8180_adapter_start(dev); + rtl8180_update_msr(dev); + + + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); + + write_nic_dword(dev,BSSID,((u32*)net->bssid)[0]); + write_nic_word(dev,BSSID+4,((u16*)net->bssid)[2]); + + + beacon_interval = read_nic_dword(dev,BEACON_INTERVAL); + beacon_interval &= ~ BEACON_INTERVAL_MASK; + beacon_interval |= net->beacon_interval; + write_nic_dword(dev, BEACON_INTERVAL, beacon_interval); + + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + + + /* + u16 atim = read_nic_dword(dev,ATIM); + u16 = u16 &~ ATIM_MASK; + u16 = u16 | beacon->atim; + */ +#if 0 + if (net->capability & WLAN_CAPABILITY_PRIVACY) { + if (priv->hw_wep) { + DMESG("Enabling hardware WEP support"); + rtl8180_set_hw_wep(dev); + priv->ieee80211->host_encrypt=0; + priv->ieee80211->host_decrypt=0; + } +#ifndef CONFIG_IEEE80211_NOWEP + else { + priv->ieee80211->host_encrypt=1; + priv->ieee80211->host_decrypt=1; + } +#endif + } +#ifndef CONFIG_IEEE80211_NOWEP + else{ + priv->ieee80211->host_encrypt=0; + priv->ieee80211->host_decrypt=0; + } +#endif +#endif + + + if(priv->card_8185) + rtl8180_set_chan(dev, priv->chan); + + +} + +void rtl8180_rq_tx_ack(struct net_device *dev){ + + struct r8180_priv *priv = ieee80211_priv(dev); +// printk("====================>%s\n",__FUNCTION__); + write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)|CONFIG4_PWRMGT); + priv->ack_tx_to_ieee = 1; +} + +short rtl8180_is_tx_queue_empty(struct net_device *dev){ + + struct r8180_priv *priv = ieee80211_priv(dev); + u32* d; + + for (d = priv->txmapring; + d < priv->txmapring + priv->txringcount;d+=8) + if(*d & (1<<31)) return 0; + + for (d = priv->txbkpring; + d < priv->txbkpring + priv->txringcount;d+=8) + if(*d & (1<<31)) return 0; + + for (d = priv->txbepring; + d < priv->txbepring + priv->txringcount;d+=8) + if(*d & (1<<31)) return 0; + + for (d = priv->txvipring; + d < priv->txvipring + priv->txringcount;d+=8) + if(*d & (1<<31)) return 0; + + for (d = priv->txvopring; + d < priv->txvopring + priv->txringcount;d+=8) + if(*d & (1<<31)) return 0; + + for (d = priv->txhpring; + d < priv->txhpring + priv->txringcount;d+=8) + if(*d & (1<<31)) return 0; + return 1; +} +/* FIXME FIXME 5msecs is random */ +#define HW_WAKE_DELAY 5 + +void rtl8180_hw_wakeup(struct net_device *dev) +{ + unsigned long flags; + + struct r8180_priv *priv = ieee80211_priv(dev); + + spin_lock_irqsave(&priv->ps_lock,flags); + //DMESG("Waken up!"); + write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)&~CONFIG4_PWRMGT); + + if(priv->rf_wakeup) + priv->rf_wakeup(dev); +// mdelay(HW_WAKE_DELAY); + spin_unlock_irqrestore(&priv->ps_lock,flags); +} + +void rtl8180_hw_sleep_down(struct net_device *dev) +{ + unsigned long flags; + + struct r8180_priv *priv = ieee80211_priv(dev); + + spin_lock_irqsave(&priv->ps_lock,flags); + //DMESG("Sleep!"); + + if(priv->rf_sleep) + priv->rf_sleep(dev); + spin_unlock_irqrestore(&priv->ps_lock,flags); +} + + +void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl) +{ + + struct r8180_priv *priv = ieee80211_priv(dev); + + u32 rb = jiffies; + unsigned long flags; + + spin_lock_irqsave(&priv->ps_lock,flags); + + /* Writing HW register with 0 equals to disable + * the timer, that is not really what we want + */ + tl -= MSECS(4+16+7); + + //if(tl == 0) tl = 1; + + /* FIXME HACK FIXME HACK */ +// force_pci_posting(dev); + //mdelay(1); + +// rb = read_nic_dword(dev, TSFTR); + + /* If the interval in witch we are requested to sleep is too + * short then give up and remain awake + */ + if(((tl>=rb)&& (tl-rb) <= MSECS(MIN_SLEEP_TIME)) + ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) { + spin_unlock_irqrestore(&priv->ps_lock,flags); + printk("too short to sleep\n"); + return; + } + +// write_nic_dword(dev, TimerInt, tl); +// rb = read_nic_dword(dev, TSFTR); + { + u32 tmp = (tl>rb)?(tl-rb):(rb-tl); + // if (tl<rb) + + //lzm,add,080828 + priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp); + + queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); //as tl may be less than rb + } + /* if we suspect the TimerInt is gone beyond tl + * while setting it, then give up + */ +#if 1 + if(((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME)))|| + ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) { + spin_unlock_irqrestore(&priv->ps_lock,flags); + return; + } +#endif +// if(priv->rf_sleep) +// priv->rf_sleep(dev); + + queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq); + spin_unlock_irqrestore(&priv->ps_lock,flags); +} + + +//void rtl8180_wmm_param_update(struct net_device *dev,u8 *ac_param) +#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) +void rtl8180_wmm_param_update(struct work_struct * work) +{ + struct ieee80211_device * ieee = container_of(work, struct ieee80211_device,wmm_param_update_wq); + //struct r8180_priv *priv = (struct r8180_priv*)(ieee->priv); + struct net_device *dev = ieee->dev; +#else +void rtl8180_wmm_param_update(struct ieee80211_device *ieee) +{ + struct net_device *dev = ieee->dev; + struct r8180_priv *priv = ieee80211_priv(dev); +#endif + u8 *ac_param = (u8 *)(ieee->current_network.wmm_param); + u8 mode = ieee->current_network.mode; + AC_CODING eACI; + AC_PARAM AcParam; + PAC_PARAM pAcParam; + u8 i; + +#ifndef CONFIG_RTL8185B + //for legacy 8185 keep the PARAM unchange. + return; +#else + if(!ieee->current_network.QoS_Enable){ + //legacy ac_xx_param update + AcParam.longData = 0; + AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS. + AcParam.f.AciAifsn.f.ACM = 0; + AcParam.f.Ecw.f.ECWmin = 3; // Follow 802.11 CWmin. + AcParam.f.Ecw.f.ECWmax = 7; // Follow 802.11 CWmax. + AcParam.f.TXOPLimit = 0; + for(eACI = 0; eACI < AC_MAX; eACI++){ + AcParam.f.AciAifsn.f.ACI = (u8)eACI; + { + u8 u1bAIFS; + u32 u4bAcParam; + pAcParam = (PAC_PARAM)(&AcParam); + // Retrive paramters to udpate. + u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN *(((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; + u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)| + (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)| + (((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)| + (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); + switch(eACI){ + case AC1_BK: + write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); + break; + + case AC0_BE: + write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); + break; + + case AC2_VI: + write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); + break; + + case AC3_VO: + write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); + break; + + default: + printk(KERN_WARNING "SetHwReg8185():invalid ACI: %d!\n", eACI); + break; + } + } + } + return; + } + + for(i = 0; i < AC_MAX; i++){ + //AcParam.longData = 0; + pAcParam = (AC_PARAM * )ac_param; + { + AC_CODING eACI; + u8 u1bAIFS; + u32 u4bAcParam; + + // Retrive paramters to udpate. + eACI = pAcParam->f.AciAifsn.f.ACI; + //Mode G/A: slotTimeTimer = 9; Mode B: 20 + u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; + u4bAcParam = ( (((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | + (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | + (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | + (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); + + switch(eACI){ + case AC1_BK: + write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); + break; + + case AC0_BE: + write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); + break; + + case AC2_VI: + write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); + break; + + case AC3_VO: + write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); + break; + + default: + printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI); + break; + } + } + ac_param += (sizeof(AC_PARAM)); + } +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_tx_irq_wq(struct work_struct *work); +#else +void rtl8180_tx_irq_wq(struct net_device *dev); +#endif + + + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_restart_wq(struct work_struct *work); +//void rtl8180_rq_tx_ack(struct work_struct *work); +#else + void rtl8180_restart_wq(struct net_device *dev); +//void rtl8180_rq_tx_ack(struct net_device *dev); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_watch_dog_wq(struct work_struct *work); +#else +void rtl8180_watch_dog_wq(struct net_device *dev); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_hw_wakeup_wq(struct work_struct *work); +#else +void rtl8180_hw_wakeup_wq(struct net_device *dev); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_hw_sleep_wq(struct work_struct *work); +#else +void rtl8180_hw_sleep_wq(struct net_device *dev); +#endif + + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_sw_antenna_wq(struct work_struct *work); +#else +void rtl8180_sw_antenna_wq(struct net_device *dev); +#endif + void rtl8180_watch_dog(struct net_device *dev); +void watch_dog_adaptive(unsigned long data) +{ + struct r8180_priv* priv = ieee80211_priv((struct net_device *)data); +// DMESG("---->watch_dog_adaptive()\n"); + if(!priv->up) + { + DMESG("<----watch_dog_adaptive():driver is not up!\n"); + return; + } + + // queue_work(priv->ieee80211->wq,&priv->ieee80211->watch_dog_wq); +//{by amy 080312 +#if 1 + // Tx High Power Mechanism. +#ifdef HIGH_POWER + if(CheckHighPower((struct net_device *)data)) + { + queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq); + } +#endif + +#ifdef CONFIG_RTL818X_S + // Tx Power Tracking on 87SE. +#ifdef TX_TRACK + //if( priv->bTxPowerTrack ) //lzm mod 080826 + if( CheckTxPwrTracking((struct net_device *)data)); + TxPwrTracking87SE((struct net_device *)data); +#endif +#endif + + // Perform DIG immediately. +#ifdef SW_DIG + if(CheckDig((struct net_device *)data) == true) + { + queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq); + } +#endif +#endif +//by amy 080312} + rtl8180_watch_dog((struct net_device *)data); + + + queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem); + + priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME); + add_timer(&priv->watch_dog_timer); +// DMESG("<----watch_dog_adaptive()\n"); +} + +#ifdef ENABLE_DOT11D + +static CHANNEL_LIST ChannelPlan[] = { + {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, //FCC + {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Spain. Change to ETSI. + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //France. Change to ETSI. + {{14,36,40,44,48,52,56,60,64},9}, //MKK + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},//MKK1 + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Israel. + {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, // For 11a , TELEC + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 + {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} //world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826 +}; + +static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee) +{ + int i; + + //lzm add 080826 + ieee->MinPassiveChnlNum=MAX_CHANNEL_NUMBER+1; + ieee->IbssStartChnl=0; + + switch (channel_plan) + { + case COUNTRY_CODE_FCC: + case COUNTRY_CODE_IC: + case COUNTRY_CODE_ETSI: + case COUNTRY_CODE_SPAIN: + case COUNTRY_CODE_FRANCE: + case COUNTRY_CODE_MKK: + case COUNTRY_CODE_MKK1: + case COUNTRY_CODE_ISRAEL: + case COUNTRY_CODE_TELEC: + { + Dot11d_Init(ieee); + ieee->bGlobalDomain = false; + if (ChannelPlan[channel_plan].Len != 0){ + // Clear old channel map + memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); + // Set new channel map + for (i=0;i<ChannelPlan[channel_plan].Len;i++) + { + if(ChannelPlan[channel_plan].Channel[i] <= 14) + GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1; + } + } + break; + } + case COUNTRY_CODE_GLOBAL_DOMAIN: + { + GET_DOT11D_INFO(ieee)->bEnabled = 0; + Dot11d_Reset(ieee); + ieee->bGlobalDomain = true; + break; + } + case COUNTRY_CODE_WORLD_WIDE_13_INDEX://lzm add 080826 + { + ieee->MinPassiveChnlNum=12; + ieee->IbssStartChnl= 10; + break; + } + default: + { + Dot11d_Init(ieee); + ieee->bGlobalDomain = false; + memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); + for (i=1;i<=14;i++) + { + GET_DOT11D_INFO(ieee)->channel_map[i] = 1; + } + break; + } + } +} +#endif + +//Add for RF power on power off by lizhaoming 080512 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void GPIOChangeRFWorkItemCallBack(struct work_struct *work); +#else +void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee); +#endif + +//YJ,add,080828 +static void rtl8180_statistics_init(struct Stats *pstats) +{ + memset(pstats, 0, sizeof(struct Stats)); +} +static void rtl8180_link_detect_init(plink_detect_t plink_detect) +{ + memset(plink_detect, 0, sizeof(link_detect_t)); + plink_detect->SlotNum = DEFAULT_SLOT_NUM; +} +//YJ,add,080828,end + +short rtl8180_init(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u16 word; + u16 version; + u8 hw_version; + //u8 config3; + u32 usValue; + u16 tmpu16; + int i, j; + +#ifdef ENABLE_DOT11D +#if 0 + for(i=0;i<0xFF;i++) { + if(i%16 == 0) + printk("\n[%x]: ", i/16); + printk("\t%4.4x", eprom_read(dev,i)); + } +#endif + priv->channel_plan = eprom_read(dev, EEPROM_COUNTRY_CODE>>1) & 0xFF; + if(priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN){ + printk("rtl8180_init:Error channel plan! Set to default.\n"); + priv->channel_plan = 0; + } + //priv->channel_plan = 9; //Global Domain + + DMESG("Channel plan is %d\n",priv->channel_plan); + rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211); +#else + int ch; + //Set Default Channel Plan + if(!channels){ + DMESG("No channels, aborting"); + return -1; + } + ch=channels; + priv->channel_plan = 0;//hikaru + // set channels 1..14 allowed in given locale + for (i=1; i<=14; i++) { + (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01); + ch >>= 1; + } +#endif + + //memcpy(priv->stats,0,sizeof(struct Stats)); + + //FIXME: these constants are placed in a bad pleace. + priv->txbuffsize = 2048;//1024; + priv->txringcount = 32;//32; + priv->rxbuffersize = 2048;//1024; + priv->rxringcount = 64;//32; + priv->txbeaconcount = 2; + priv->rx_skb_complete = 1; + //priv->txnp_pending.ispending=0; + /* ^^ the SKB does not containt a partial RXed + * packet (is empty) + */ + +#ifdef CONFIG_RTL8185B +#ifdef CONFIG_RTL818X_S + priv->RegThreeWireMode = HW_THREE_WIRE_SI; +#else + priv->RegThreeWireMode = SW_THREE_WIRE; +#endif +#endif + +//Add for RF power on power off by lizhaoming 080512 + priv->RFChangeInProgress = false; + priv->SetRFPowerStateInProgress = false; + priv->RFProgType = 0; + priv->bInHctTest = false; + + priv->irq_enabled=0; + +//YJ,modified,080828 +#if 0 + priv->stats.rxdmafail=0; + priv->stats.txrdu=0; + priv->stats.rxrdu=0; + priv->stats.rxnolast=0; + priv->stats.rxnodata=0; + //priv->stats.rxreset=0; + //priv->stats.rxwrkaround=0; + priv->stats.rxnopointer=0; + priv->stats.txnperr=0; + priv->stats.txresumed=0; + priv->stats.rxerr=0; + priv->stats.rxoverflow=0; + priv->stats.rxint=0; + priv->stats.txnpokint=0; + priv->stats.txhpokint=0; + priv->stats.txhperr=0; + priv->stats.ints=0; + priv->stats.shints=0; + priv->stats.txoverflow=0; + priv->stats.txbeacon=0; + priv->stats.txbeaconerr=0; + priv->stats.txlperr=0; + priv->stats.txlpokint=0; + priv->stats.txretry=0;//tony 20060601 + priv->stats.rxcrcerrmin=0; + priv->stats.rxcrcerrmid=0; + priv->stats.rxcrcerrmax=0; + priv->stats.rxicverr=0; +#else + rtl8180_statistics_init(&priv->stats); + rtl8180_link_detect_init(&priv->link_detect); +#endif +//YJ,modified,080828,end + + + priv->ack_tx_to_ieee = 0; + priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; + priv->ieee80211->iw_mode = IW_MODE_INFRA; + priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | + IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | + IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE; + priv->ieee80211->active_scan = 1; + priv->ieee80211->rate = 110; //11 mbps + priv->ieee80211->modulation = IEEE80211_CCK_MODULATION; + priv->ieee80211->host_encrypt = 1; + priv->ieee80211->host_decrypt = 1; + priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup; + priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack; + priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep; + priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty; + + priv->hw_wep = hwwep; + priv->prism_hdr=0; + priv->dev=dev; + priv->retry_rts = DEFAULT_RETRY_RTS; + priv->retry_data = DEFAULT_RETRY_DATA; + priv->RFChangeInProgress = false; + priv->SetRFPowerStateInProgress = false; + priv->RFProgType = 0; + priv->bInHctTest = false; + priv->bInactivePs = true;//false; + priv->ieee80211->bInactivePs = priv->bInactivePs; + priv->bSwRfProcessing = false; + priv->eRFPowerState = eRfOff; + priv->RfOffReason = 0; + priv->LedStrategy = SW_LED_MODE0; + //priv->NumRxOkInPeriod = 0; //YJ,del,080828 + //priv->NumTxOkInPeriod = 0; //YJ,del,080828 + priv->TxPollingTimes = 0;//lzm add 080826 + priv->bLeisurePs = true; + priv->dot11PowerSaveMode = eActive; +//by amy for antenna + priv->AdMinCheckPeriod = 5; + priv->AdMaxCheckPeriod = 10; +// Lower signal strength threshold to fit the HW participation in antenna diversity. +by amy 080312 + priv->AdMaxRxSsThreshold = 30;//60->30 + priv->AdRxSsThreshold = 20;//50->20 + priv->AdCheckPeriod = priv->AdMinCheckPeriod; + priv->AdTickCount = 0; + priv->AdRxSignalStrength = -1; + priv->RegSwAntennaDiversityMechanism = 0; + priv->RegDefaultAntenna = 0; + priv->SignalStrength = 0; + priv->AdRxOkCnt = 0; + priv->CurrAntennaIndex = 0; + priv->AdRxSsBeforeSwitched = 0; + init_timer(&priv->SwAntennaDiversityTimer); + priv->SwAntennaDiversityTimer.data = (unsigned long)dev; + priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback; +//by amy for antenna +//{by amy 080312 + priv->bDigMechanism = 1; + priv->InitialGain = 6; + priv->bXtalCalibration = false; + priv->XtalCal_Xin = 0; + priv->XtalCal_Xout = 0; + priv->bTxPowerTrack = false; + priv->ThermalMeter = 0; + priv->FalseAlarmRegValue = 0; + priv->RegDigOfdmFaUpTh = 0xc; // Upper threhold of OFDM false alarm, which is used in DIG. + priv->DIG_NumberFallbackVote = 0; + priv->DIG_NumberUpgradeVote = 0; + priv->LastSignalStrengthInPercent = 0; + priv->Stats_SignalStrength = 0; + priv->LastRxPktAntenna = 0; + priv->SignalQuality = 0; // in 0-100 index. + priv->Stats_SignalQuality = 0; + priv->RecvSignalPower = 0; // in dBm. + priv->Stats_RecvSignalPower = 0; + priv->AdMainAntennaRxOkCnt = 0; + priv->AdAuxAntennaRxOkCnt = 0; + priv->bHWAdSwitched = false; + priv->bRegHighPowerMechanism = true; + priv->RegHiPwrUpperTh = 77; + priv->RegHiPwrLowerTh = 75; + priv->RegRSSIHiPwrUpperTh = 70; + priv->RegRSSIHiPwrLowerTh = 20; + priv->bCurCCKPkt = false; + priv->UndecoratedSmoothedSS = -1; + priv->bToUpdateTxPwr = false; + priv->CurCCKRSSI = 0; + priv->RxPower = 0; + priv->RSSI = 0; + //YJ,add,080828 + priv->NumTxOkTotal = 0; + priv->NumTxUnicast = 0; + priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL; + priv->PowerProfile = POWER_PROFILE_AC; + //YJ,add,080828,end +//by amy for rate adaptive + priv->CurrRetryCnt=0; + priv->LastRetryCnt=0; + priv->LastTxokCnt=0; + priv->LastRxokCnt=0; + priv->LastRetryRate=0; + priv->bTryuping=0; + priv->CurrTxRate=0; + priv->CurrRetryRate=0; + priv->TryupingCount=0; + priv->TryupingCountNoData=0; + priv->TryDownCountLowData=0; + priv->LastTxOKBytes=0; + priv->LastFailTxRate=0; + priv->LastFailTxRateSS=0; + priv->FailTxRateCount=0; + priv->LastTxThroughput=0; + priv->NumTxOkBytesTotal=0; + priv->ForcedDataRate = 0; + priv->RegBModeGainStage = 1; + +//by amy for rate adaptive +//by amy 080312} + priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0; + spin_lock_init(&priv->irq_lock); + spin_lock_init(&priv->irq_th_lock); + spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->ps_lock); + spin_lock_init(&priv->rf_ps_lock); + sema_init(&priv->wx_sem,1); + sema_init(&priv->rf_state,1); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) + INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq); + INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq); + INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq); + INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq); + //INIT_DELAYED_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq); + //INIT_DELAYED_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_wq); + INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update); + INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter);//+by amy 080312 + INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq);//+by amy 080312 + INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq);//+by amy 080312 + + //add for RF power on power off by lizhaoming 080512 + INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack); +#else + INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev); + INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq,dev); + //INIT_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq,dev); + INIT_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq,dev); + INIT_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq,dev); + //INIT_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_wq,dev); + INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update,priv->ieee80211); + INIT_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter,dev);//+by amy 080312 + INIT_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq,dev);//+by amy 080312 + INIT_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq,dev);//+by amy 080312 + + //add for RF power on power off by lizhaoming 080512 + INIT_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack, priv->ieee80211); +#endif + //INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev); + + tasklet_init(&priv->irq_rx_tasklet, + (void(*)(unsigned long)) rtl8180_irq_rx_tasklet, + (unsigned long)priv); +//by amy + init_timer(&priv->watch_dog_timer); + priv->watch_dog_timer.data = (unsigned long)dev; + priv->watch_dog_timer.function = watch_dog_adaptive; +//by amy + +//{by amy 080312 +//by amy for rate adaptive + init_timer(&priv->rateadapter_timer); + priv->rateadapter_timer.data = (unsigned long)dev; + priv->rateadapter_timer.function = timer_rate_adaptive; + priv->RateAdaptivePeriod= RATE_ADAPTIVE_TIMER_PERIOD; + priv->bEnhanceTxPwr=false; +//by amy for rate adaptive +//by amy 080312} + //priv->ieee80211->func = + // kmalloc(sizeof(struct ieee80211_helper_functions),GFP_KERNEL); + //memset(priv->ieee80211->func, 0, + // sizeof(struct ieee80211_helper_functions)); + + priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit; + priv->ieee80211->set_chan = rtl8180_set_chan; + priv->ieee80211->link_change = rtl8180_link_change; + priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit; + priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop; + priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume; + + priv->ieee80211->init_wmmparam_flag = 0; + + priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon; + priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable; + priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; + +#ifdef CONFIG_RTL8185B + priv->MWIEnable = 0; + + priv->ShortRetryLimit = 7; + priv->LongRetryLimit = 7; + priv->EarlyRxThreshold = 7; + + priv->CSMethod = (0x01 << 29); + + priv->TransmitConfig = + 1<<TCR_DurProcMode_OFFSET | //for RTL8185B, duration setting by HW + (7<<TCR_MXDMA_OFFSET) | // Max DMA Burst Size per Tx DMA Burst, 7: reservied. + (priv->ShortRetryLimit<<TCR_SRL_OFFSET) | // Short retry limit + (priv->LongRetryLimit<<TCR_LRL_OFFSET) | // Long retry limit + (0 ? TCR_SAT : 0); // FALSE: HW provies PLCP length and LENGEXT, TURE: SW proiveds them + + priv->ReceiveConfig = +#ifdef CONFIG_RTL818X_S +#else + priv->CSMethod | +#endif +// RCR_ENMARP | + RCR_AMF | RCR_ADF | //accept management/data + RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. + RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC + //RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet + (7<<RCR_MXDMA_OFFSET) | // Max DMA Burst Size per Rx DMA Burst, 7: unlimited. + (priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) | // Rx FIFO Threshold, 7: No Rx threshold. + (priv->EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0); + + priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER | + IMR_THPDER | IMR_THPDOK | + IMR_TVODER | IMR_TVODOK | + IMR_TVIDER | IMR_TVIDOK | + IMR_TBEDER | IMR_TBEDOK | + IMR_TBKDER | IMR_TBKDOK | + IMR_RDU | // To handle the defragmentation not enough Rx descriptors case. Annie, 2006-03-27. + IMR_RER | IMR_ROK | + IMR_RQoSOK; // <NOTE> ROK and RQoSOK are mutually exclusive, so, we must handle RQoSOK interrupt to receive QoS frames, 2005.12.09, by rcnjko. + + priv->InitialGain = 6; +#endif + + hw_version =( read_nic_dword(dev, TCR) & TCR_HWVERID_MASK)>>TCR_HWVERID_SHIFT; + + switch (hw_version){ +#ifdef CONFIG_RTL8185B + case HW_VERID_R8185B_B: +#ifdef CONFIG_RTL818X_S + priv->card_8185 = VERSION_8187S_C; + DMESG("MAC controller is a RTL8187SE b/g"); + priv->phy_ver = 2; + break; +#else + DMESG("MAC controller is a RTL8185B b/g"); + priv->card_8185 = 3; + priv->phy_ver = 2; + break; +#endif +#endif + case HW_VERID_R8185_ABC: + DMESG("MAC controller is a RTL8185 b/g"); + priv->card_8185 = 1; + /* you should not find a card with 8225 PHY ver < C*/ + priv->phy_ver = 2; + break; + + case HW_VERID_R8185_D: + DMESG("MAC controller is a RTL8185 b/g (V. D)"); + priv->card_8185 = 2; + /* you should not find a card with 8225 PHY ver < C*/ + priv->phy_ver = 2; + break; + + case HW_VERID_R8180_ABCD: + DMESG("MAC controller is a RTL8180"); + priv->card_8185 = 0; + break; + + case HW_VERID_R8180_F: + DMESG("MAC controller is a RTL8180 (v. F)"); + priv->card_8185 = 0; + break; + + default: + DMESGW("MAC chip not recognized: version %x. Assuming RTL8180",hw_version); + priv->card_8185 = 0; + break; + } + + if(priv->card_8185){ + priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION; + priv->ieee80211->short_slot = 1; + } + /* you should not found any 8185 Ver B Card */ + priv->card_8185_Bversion = 0; + +#ifdef CONFIG_RTL8185B +#ifdef CONFIG_RTL818X_S + // just for sync 85 + priv->card_type = PCI; + DMESG("This is a PCI NIC"); +#else + config3 = read_nic_byte(dev, CONFIG3); + if(config3 & 0x8){ + priv->card_type = CARDBUS; + DMESG("This is a CARDBUS NIC"); + } + else if( config3 & 0x4){ + priv->card_type = MINIPCI; + DMESG("This is a MINI-PCI NIC"); + }else{ + priv->card_type = PCI; + DMESG("This is a PCI NIC"); + } +#endif +#endif + priv->enable_gpio0 = 0; + +//by amy for antenna +#ifdef CONFIG_RTL8185B + usValue = eprom_read(dev, EEPROM_SW_REVD_OFFSET); + DMESG("usValue is 0x%x\n",usValue); +#ifdef CONFIG_RTL818X_S + //3Read AntennaDiversity + // SW Antenna Diversity. + if( (usValue & EEPROM_SW_AD_MASK) != EEPROM_SW_AD_ENABLE ) + { + priv->EEPROMSwAntennaDiversity = false; + //printk("EEPROM Disable SW Antenna Diversity\n"); + } + else + { + priv->EEPROMSwAntennaDiversity = true; + //printk("EEPROM Enable SW Antenna Diversity\n"); + } + // Default Antenna to use. + if( (usValue & EEPROM_DEF_ANT_MASK) != EEPROM_DEF_ANT_1 ) + { + priv->EEPROMDefaultAntenna1 = false; + //printk("EEPROM Default Antenna 0\n"); + } + else + { + priv->EEPROMDefaultAntenna1 = true; + //printk("EEPROM Default Antenna 1\n"); + } + + // + // Antenna diversity mechanism. Added by Roger, 2007.11.05. + // + if( priv->RegSwAntennaDiversityMechanism == 0 ) // Auto + {// 0: default from EEPROM. + priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity; + } + else + {// 1:disable antenna diversity, 2: enable antenna diversity. + priv->bSwAntennaDiverity = ((priv->RegSwAntennaDiversityMechanism == 1)? false : true); + } + //printk("bSwAntennaDiverity = %d\n", priv->bSwAntennaDiverity); + + + // + // Default antenna settings. Added by Roger, 2007.11.05. + // + if( priv->RegDefaultAntenna == 0) + {// 0: default from EEPROM. + priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1; + } + else + {// 1: main, 2: aux. + priv->bDefaultAntenna1 = ((priv->RegDefaultAntenna== 2) ? true : false); + } + //printk("bDefaultAntenna1 = %d\n", priv->bDefaultAntenna1); +#endif +#endif +//by amy for antenna + /* rtl8185 can calc plcp len in HW.*/ + priv->hw_plcp_len = 1; + + priv->plcp_preamble_mode = 2; + /*the eeprom type is stored in RCR register bit #6 */ + if (RCR_9356SEL & read_nic_dword(dev, RCR)){ + priv->epromtype=EPROM_93c56; + //DMESG("Reported EEPROM chip is a 93c56 (2Kbit)"); + }else{ + priv->epromtype=EPROM_93c46; + //DMESG("Reported EEPROM chip is a 93c46 (1Kbit)"); + } + + dev->get_stats = rtl8180_stats; + + dev->dev_addr[0]=eprom_read(dev,MAC_ADR) & 0xff; + dev->dev_addr[1]=(eprom_read(dev,MAC_ADR) & 0xff00)>>8; + dev->dev_addr[2]=eprom_read(dev,MAC_ADR+1) & 0xff; + dev->dev_addr[3]=(eprom_read(dev,MAC_ADR+1) & 0xff00)>>8; + dev->dev_addr[4]=eprom_read(dev,MAC_ADR+2) & 0xff; + dev->dev_addr[5]=(eprom_read(dev,MAC_ADR+2) & 0xff00)>>8; + //DMESG("Card MAC address is "MAC_FMT, MAC_ARG(dev->dev_addr)); + + + for(i=1,j=0; i<14; i+=2,j++){ + + word = eprom_read(dev,EPROM_TXPW_CH1_2 + j); + priv->chtxpwr[i]=word & 0xff; + priv->chtxpwr[i+1]=(word & 0xff00)>>8; +#ifdef DEBUG_EPROM + DMESG("tx word %x:%x",j,word); + DMESG("ch %d pwr %x",i,priv->chtxpwr[i]); + DMESG("ch %d pwr %x",i+1,priv->chtxpwr[i+1]); +#endif + } + if(priv->card_8185){ + for(i=1,j=0; i<14; i+=2,j++){ + + word = eprom_read(dev,EPROM_TXPW_OFDM_CH1_2 + j); + priv->chtxpwr_ofdm[i]=word & 0xff; + priv->chtxpwr_ofdm[i+1]=(word & 0xff00)>>8; +#ifdef DEBUG_EPROM + DMESG("ofdm tx word %x:%x",j,word); + DMESG("ofdm ch %d pwr %x",i,priv->chtxpwr_ofdm[i]); + DMESG("ofdm ch %d pwr %x",i+1,priv->chtxpwr_ofdm[i+1]); +#endif + } + } +//{by amy 080312 + //3Read crystal calibtration and thermal meter indication on 87SE. + + // By SD3 SY's request. Added by Roger, 2007.12.11. + + tmpu16 = eprom_read(dev, EEPROM_RSV>>1); + + //printk("ReadAdapterInfo8185(): EEPROM_RSV(%04x)\n", tmpu16); + + // Crystal calibration for Xin and Xout resp. + priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK; // 0~7.5pF + priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK)>>4; // 0~7.5pF + if((tmpu16 & EEPROM_XTAL_CAL_ENABLE)>>12) + priv->bXtalCalibration = true; + + // Thermal meter reference indication. + priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK)>>8); + if((tmpu16 & EEPROM_THERMAL_METER_ENABLE)>>13) + priv->bTxPowerTrack = true; + +//by amy 080312} +#ifdef CONFIG_RTL8185B + word = eprom_read(dev,EPROM_TXPW_BASE); + priv->cck_txpwr_base = word & 0xf; + priv->ofdm_txpwr_base = (word>>4) & 0xf; +#endif + + version = eprom_read(dev,EPROM_VERSION); + DMESG("EEPROM version %x",version); + if( (!priv->card_8185) && version < 0x0101){ + DMESG ("EEPROM version too old, assuming defaults"); + DMESG ("If you see this message *plase* send your \ +DMESG output to andreamrl@tiscali.it THANKS"); + priv->digphy=1; + priv->antb=0; + priv->diversity=1; + priv->cs_treshold=0xc; + priv->rcr_csense=1; + priv->rf_chip=RFCHIPID_PHILIPS; + }else{ + if(!priv->card_8185){ + u8 rfparam = eprom_read(dev,RF_PARAM); + DMESG("RfParam: %x",rfparam); + + priv->digphy = rfparam & (1<<RF_PARAM_DIGPHY_SHIFT) ? 0:1; + priv->antb = rfparam & (1<<RF_PARAM_ANTBDEFAULT_SHIFT) ? 1:0; + + priv->rcr_csense = (rfparam & RF_PARAM_CARRIERSENSE_MASK) >> + RF_PARAM_CARRIERSENSE_SHIFT; + + priv->diversity = + (read_nic_byte(dev,CONFIG2)&(1<<CONFIG2_ANTENNA_SHIFT)) ? 1:0; + }else{ + priv->rcr_csense = 3; + } + + priv->cs_treshold = (eprom_read(dev,ENERGY_TRESHOLD)&0xff00) >>8; + + priv->rf_chip = 0xff & eprom_read(dev,RFCHIPID); + } + +#ifdef CONFIG_RTL8185B +#ifdef CONFIG_RTL818X_S + priv->rf_chip = RF_ZEBRA4; + priv->rf_sleep = rtl8225z4_rf_sleep; + priv->rf_wakeup = rtl8225z4_rf_wakeup; +#else + priv->rf_chip = RF_ZEBRA2; +#endif + //DMESG("Card reports RF frontend Realtek 8225z2"); + //DMESGW("This driver has EXPERIMENTAL support for this chipset."); + //DMESGW("use it with care and at your own risk and"); + DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!"); + + priv->rf_close = rtl8225z2_rf_close; + priv->rf_init = rtl8225z2_rf_init; + priv->rf_set_chan = rtl8225z2_rf_set_chan; + priv->rf_set_sens = NULL; + //priv->rf_sleep = rtl8225_rf_sleep; + //priv->rf_wakeup = rtl8225_rf_wakeup; + +#else + /* check RF frontend chipset */ + switch (priv->rf_chip) { + + case RFCHIPID_RTL8225: + + if(priv->card_8185){ + DMESG("Card reports RF frontend Realtek 8225"); + DMESGW("This driver has EXPERIMENTAL support for this chipset."); + DMESGW("use it with care and at your own risk and"); + DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); + + priv->rf_close = rtl8225_rf_close; + priv->rf_init = rtl8225_rf_init; + priv->rf_set_chan = rtl8225_rf_set_chan; + priv->rf_set_sens = NULL; + priv->rf_sleep = rtl8225_rf_sleep; + priv->rf_wakeup = rtl8225_rf_wakeup; + + }else{ + DMESGW("Detected RTL8225 radio on a card recognized as RTL8180"); + DMESGW("This could not be... something went wrong...."); + return -ENODEV; + } + break; + + case RFCHIPID_RTL8255: + if(priv->card_8185){ + DMESG("Card reports RF frontend Realtek 8255"); + DMESGW("This driver has EXPERIMENTAL support for this chipset."); + DMESGW("use it with care and at your own risk and"); + DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); + + priv->rf_close = rtl8255_rf_close; + priv->rf_init = rtl8255_rf_init; + priv->rf_set_chan = rtl8255_rf_set_chan; + priv->rf_set_sens = NULL; + priv->rf_sleep = NULL; + priv->rf_wakeup = NULL; + + }else{ + DMESGW("Detected RTL8255 radio on a card recognized as RTL8180"); + DMESGW("This could not be... something went wrong...."); + return -ENODEV; + } + break; + + + case RFCHIPID_INTERSIL: + DMESGW("Card reports RF frontend by Intersil."); + DMESGW("This driver has NO support for this chipset."); + return -ENODEV; + break; + + case RFCHIPID_RFMD: + DMESGW("Card reports RF frontend by RFMD."); + DMESGW("This driver has NO support for this chipset."); + return -ENODEV; + break; + + case RFCHIPID_GCT: + DMESGW("Card reports RF frontend by GCT."); + DMESGW("This driver has EXPERIMENTAL support for this chipset."); + DMESGW("use it with care and at your own risk and"); + DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); + priv->rf_close = gct_rf_close; + priv->rf_init = gct_rf_init; + priv->rf_set_chan = gct_rf_set_chan; + priv->rf_set_sens = NULL; + priv->rf_sleep = NULL; + priv->rf_wakeup = NULL; + break; + + case RFCHIPID_MAXIM: + DMESGW("Card reports RF frontend by MAXIM."); + DMESGW("This driver has EXPERIMENTAL support for this chipset."); + DMESGW("use it with care and at your own risk and"); + DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); + priv->rf_close = maxim_rf_close; + priv->rf_init = maxim_rf_init; + priv->rf_set_chan = maxim_rf_set_chan; + priv->rf_set_sens = NULL; + priv->rf_sleep = NULL; + priv->rf_wakeup = NULL; + break; + + case RFCHIPID_PHILIPS: + DMESG("Card reports RF frontend by Philips."); + DMESG("OK! Philips SA2400 radio chipset is supported."); + priv->rf_close = sa2400_rf_close; + priv->rf_init = sa2400_rf_init; + priv->rf_set_chan = sa2400_rf_set_chan; + priv->rf_set_sens = sa2400_rf_set_sens; + priv->sens = SA2400_RF_DEF_SENS; /* default sensitivity */ + priv->max_sens = SA2400_RF_MAX_SENS; /* maximum sensitivity */ + priv->rf_sleep = NULL; + priv->rf_wakeup = NULL; + + if(priv->digphy){ + DMESGW("Digital PHY found"); + DMESGW("Philips DIGITAL PHY is untested! *Please*\ + report success/failure to <andreamrl@tiscali.it>"); + }else{ + DMESG ("Analog PHY found"); + } + + break; + + default: + DMESGW("Unknown RF module %x",priv->rf_chip); + DMESGW("Exiting..."); + return -1; + + } +#endif + + + if(!priv->card_8185){ + if(priv->antb) + DMESG ("Antenna B is default antenna"); + else + DMESG ("Antenna A is default antenna"); + + if(priv->diversity) + DMESG ("Antenna diversity is enabled"); + else + DMESG("Antenna diversity is disabled"); + + DMESG("Carrier sense %d",priv->rcr_csense); + } + + if (0!=alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount)) + return -ENOMEM; + + if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, + TX_MANAGEPRIORITY_RING_ADDR)) + return -ENOMEM; + + if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, + TX_BKPRIORITY_RING_ADDR)) + return -ENOMEM; + + if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, + TX_BEPRIORITY_RING_ADDR)) + return -ENOMEM; + + if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, + TX_VIPRIORITY_RING_ADDR)) + return -ENOMEM; + + if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, + TX_VOPRIORITY_RING_ADDR)) + return -ENOMEM; + + if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, + TX_HIGHPRIORITY_RING_ADDR)) + return -ENOMEM; + + if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount, + TX_BEACON_RING_ADDR)) + return -ENOMEM; + + + //priv->beacon_buf=NULL; + + if(!priv->card_8185){ + + if(read_nic_byte(dev, CONFIG0) & (1<<CONFIG0_WEP40_SHIFT)) + DMESG ("40-bit WEP is supported in hardware"); + else + DMESG ("40-bit WEP is NOT supported in hardware"); + + if(read_nic_byte(dev,CONFIG0) & (1<<CONFIG0_WEP104_SHIFT)) + DMESG ("104-bit WEP is supported in hardware"); + else + DMESG ("104-bit WEP is NOT supported in hardware"); + } +#if !defined(SA_SHIRQ) + if(request_irq(dev->irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)){ +#else + if(request_irq(dev->irq, (void *)rtl8180_interrupt, SA_SHIRQ, dev->name, dev)){ +#endif + DMESGE("Error allocating IRQ %d",dev->irq); + return -1; + }else{ + priv->irq=dev->irq; + DMESG("IRQ %d",dev->irq); + } + +#ifdef DEBUG_EPROM + dump_eprom(dev); +#endif + + return 0; + +} + + +void rtl8180_no_hw_wep(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + if(!priv->card_8185) + { + u8 security; + + security = read_nic_byte(dev, SECURITY); + security &=~(1<<SECURITY_WEP_TX_ENABLE_SHIFT); + security &=~(1<<SECURITY_WEP_RX_ENABLE_SHIFT); + + write_nic_byte(dev, SECURITY, security); + + }else{ + + //FIXME!!! + } + /* + write_nic_dword(dev,TX_CONF,read_nic_dword(dev,TX_CONF) | + (1<<TX_NOICV_SHIFT) ); + */ +// priv->ieee80211->hw_wep=0; +} + + +void rtl8180_set_hw_wep(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u8 pgreg; + u8 security; + u32 key0_word4; + + pgreg=read_nic_byte(dev, PGSELECT); + write_nic_byte(dev, PGSELECT, pgreg &~ (1<<PGSELECT_PG_SHIFT)); + + key0_word4 = read_nic_dword(dev, KEY0+4+4+4); + key0_word4 &= ~ 0xff; + key0_word4 |= priv->key0[3]& 0xff; + write_nic_dword(dev,KEY0,(priv->key0[0])); + write_nic_dword(dev,KEY0+4,(priv->key0[1])); + write_nic_dword(dev,KEY0+4+4,(priv->key0[2])); + write_nic_dword(dev,KEY0+4+4+4,(key0_word4)); + + /* + TX_CONF,read_nic_dword(dev,TX_CONF) &~(1<<TX_NOICV_SHIFT)); + */ + + security = read_nic_byte(dev,SECURITY); + security |= (1<<SECURITY_WEP_TX_ENABLE_SHIFT); + security |= (1<<SECURITY_WEP_RX_ENABLE_SHIFT); + security &= ~ SECURITY_ENCRYP_MASK; + security |= (SECURITY_ENCRYP_104<<SECURITY_ENCRYP_SHIFT); + + write_nic_byte(dev, SECURITY, security); + + DMESG("key %x %x %x %x",read_nic_dword(dev,KEY0+4+4+4), + read_nic_dword(dev,KEY0+4+4),read_nic_dword(dev,KEY0+4), + read_nic_dword(dev,KEY0)); + + //priv->ieee80211->hw_wep=1; +} + + +void rtl8185_rf_pins_enable(struct net_device *dev) +{ +// u16 tmp; +// tmp = read_nic_word(dev, RFPinsEnable); + write_nic_word(dev, RFPinsEnable, 0x1fff);// | tmp); +// write_nic_word(dev, RFPinsEnable,7 | tmp); +} + + +void rtl8185_set_anaparam2(struct net_device *dev, u32 a) +{ + u8 conf3; + + rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + + conf3 = read_nic_byte(dev, CONFIG3); + write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT)); + write_nic_dword(dev, ANAPARAM2, a); + + conf3 = read_nic_byte(dev, CONFIG3); + write_nic_byte(dev, CONFIG3, conf3 &~(1<<CONFIG3_ANAPARAM_W_SHIFT)); + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + +} + + +void rtl8180_set_anaparam(struct net_device *dev, u32 a) +{ + u8 conf3; + + rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + + conf3 = read_nic_byte(dev, CONFIG3); + write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT)); + write_nic_dword(dev, ANAPARAM, a); + + conf3 = read_nic_byte(dev, CONFIG3); + write_nic_byte(dev, CONFIG3, conf3 &~(1<<CONFIG3_ANAPARAM_W_SHIFT)); + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); +} + + +void rtl8185_tx_antenna(struct net_device *dev, u8 ant) +{ + write_nic_byte(dev, TX_ANTENNA, ant); + force_pci_posting(dev); + mdelay(1); +} + + +void rtl8185_write_phy(struct net_device *dev, u8 adr, u32 data) +{ + //u8 phyr; + u32 phyw; + //int i; + + adr |= 0x80; + + phyw= ((data<<8) | adr); +#if 0 + + write_nic_dword(dev, PHY_ADR, phyw); + + //read_nic_dword(dev, PHY_ADR); + for(i=0;i<10;i++){ + write_nic_dword(dev, PHY_ADR, 0xffffff7f & phyw); + phyr = read_nic_byte(dev, PHY_READ); + if(phyr == (data&0xff)) break; + + } +#else + // Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. + write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24)); + write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16)); + write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8)); + write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff) )); +#endif + /* this is ok to fail when we write AGC table. check for AGC table might be + * done by masking with 0x7f instead of 0xff + */ + //if(phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data,adr); +} + + +inline void write_phy_ofdm (struct net_device *dev, u8 adr, u32 data) +{ + data = data & 0xff; + rtl8185_write_phy(dev, adr, data); +} + + +void write_phy_cck (struct net_device *dev, u8 adr, u32 data) +{ + data = data & 0xff; + rtl8185_write_phy(dev, adr, data | 0x10000); +} + + +/* 70*3 = 210 ms + * I hope this is enougth + */ +#define MAX_PHY 70 +void write_phy(struct net_device *dev, u8 adr, u8 data) +{ + u32 phy; + int i; + + phy = 0xff0000; + phy |= adr; + phy |= 0x80; /* this should enable writing */ + phy |= (data<<8); + + //PHY_ADR, PHY_R and PHY_W are contig and treated as one dword + write_nic_dword(dev,PHY_ADR, phy); + + phy= 0xffff00; + phy |= adr; + + write_nic_dword(dev,PHY_ADR, phy); + for(i=0;i<MAX_PHY;i++){ + phy=read_nic_dword(dev,PHY_ADR); + phy= phy & 0xff0000; + phy= phy >> 16; + if(phy == data){ //SUCCESS! + force_pci_posting(dev); + mdelay(3); //random value +#ifdef DEBUG_BB + DMESG("Phy wr %x,%x",adr,data); +#endif + return; + }else{ + force_pci_posting(dev); + mdelay(3); //random value + } + } + DMESGW ("Phy writing %x %x failed!", adr,data); +} + +void rtl8185_set_rate(struct net_device *dev) +{ + int i; + u16 word; + int basic_rate,min_rr_rate,max_rr_rate; + +// struct r8180_priv *priv = ieee80211_priv(dev); + + //if (ieee80211_is_54g(priv->ieee80211->current_network) && +// priv->ieee80211->state == IEEE80211_LINKED){ + basic_rate = ieeerate2rtlrate(240); + min_rr_rate = ieeerate2rtlrate(60); + max_rr_rate = ieeerate2rtlrate(240); + +// +// }else{ +// basic_rate = ieeerate2rtlrate(20); +// min_rr_rate = ieeerate2rtlrate(10); +// max_rr_rate = ieeerate2rtlrate(110); +// } + + write_nic_byte(dev, RESP_RATE, + max_rr_rate<<MAX_RESP_RATE_SHIFT| min_rr_rate<<MIN_RESP_RATE_SHIFT); + + word = read_nic_word(dev, BRSR); + word &= ~BRSR_MBR_8185; + + + for(i=0;i<=basic_rate;i++) + word |= (1<<i); + + write_nic_word(dev, BRSR, word); + //DMESG("RR:%x BRSR: %x", read_nic_byte(dev,RESP_RATE),read_nic_word(dev,BRSR)); +} + + + +void rtl8180_adapter_start(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32 anaparam; + u16 word; + u8 config3; +// int i; + + rtl8180_rtx_disable(dev); + rtl8180_reset(dev); + + /* seems that 0xffff or 0xafff will cause + * HW interrupt line crash + */ + + //priv->irq_mask = 0xafff; +// priv->irq_mask = 0x4fcf; + + /* enable beacon timeout, beacon TX ok and err + * LP tx ok and err, HP TX ok and err, NP TX ok and err, + * RX ok and ERR, and GP timer */ + priv->irq_mask = 0x6fcf; + + priv->dma_poll_mask = 0; + + rtl8180_beacon_tx_disable(dev); + + if(priv->card_type == CARDBUS ){ + config3=read_nic_byte(dev, CONFIG3); + write_nic_byte(dev,CONFIG3,config3 | CONFIG3_FuncRegEn); + write_nic_word(dev,FEMR, FEMR_INTR | FEMR_WKUP | FEMR_GWAKE | + read_nic_word(dev, FEMR)); + } + rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff ); + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + + rtl8180_update_msr(dev); + + if(!priv->card_8185){ + anaparam = eprom_read(dev,EPROM_ANAPARAM_ADDRLWORD); + anaparam |= eprom_read(dev,EPROM_ANAPARAM_ADDRHWORD)<<16; + + rtl8180_set_anaparam(dev,anaparam); + } + /* These might be unnecessary since we do in rx_enable / tx_enable */ + fix_rx_fifo(dev); + fix_tx_fifo(dev); + /*set_nic_rxring(dev); + set_nic_txring(dev);*/ + + rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + + /* + The following is very strange. seems to be that 1 means test mode, + but we need to acknolwledges the nic when a packet is ready + altought we set it to 0 + */ + + write_nic_byte(dev, + CONFIG2, read_nic_byte(dev,CONFIG2) &~\ + (1<<CONFIG2_DMA_POLLING_MODE_SHIFT)); + //^the nic isn't in test mode + if(priv->card_8185) + write_nic_byte(dev, + CONFIG2, read_nic_byte(dev,CONFIG2)|(1<<4)); + + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); + + write_nic_dword(dev,INT_TIMEOUT,0); +#ifdef DEBUG_REGISTERS + rtl8180_dump_reg(dev); +#endif + + if(!priv->card_8185) + { + /* + experimental - this might be needed to calibrate AGC, + anyway it shouldn't hurt + */ + write_nic_byte(dev, CONFIG5, + read_nic_byte(dev, CONFIG5) | (1<<AGCRESET_SHIFT)); + read_nic_byte(dev, CONFIG5); + udelay(15); + write_nic_byte(dev, CONFIG5, + read_nic_byte(dev, CONFIG5) &~ (1<<AGCRESET_SHIFT)); + }else{ + + write_nic_byte(dev, WPA_CONFIG, 0); + //write_nic_byte(dev, TESTR, 0xd); + } + + rtl8180_no_hw_wep(dev); + + if(priv->card_8185){ + rtl8185_set_rate(dev); + write_nic_byte(dev, RATE_FALLBACK, 0x81); + // write_nic_byte(dev, 0xdf, 0x15); + }else{ + word = read_nic_word(dev, BRSR); + word &= ~BRSR_MBR; + word &= ~BRSR_BPLCP; + word |= ieeerate2rtlrate(priv->ieee80211->basic_rate); +//by amy + word |= 0x0f; +//by amy + write_nic_word(dev, BRSR, word); + } + + + if(priv->card_8185){ + write_nic_byte(dev, GP_ENABLE,read_nic_byte(dev, GP_ENABLE) & ~(1<<6)); + + //FIXME cfg 3 ClkRun enable - isn't it ReadOnly ? + rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + write_nic_byte(dev,CONFIG3, read_nic_byte(dev, CONFIG3) +|(1<<CONFIG3_CLKRUN_SHIFT)); + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + + } + + priv->rf_init(dev); + + if(priv->rf_set_sens != NULL) + priv->rf_set_sens(dev,priv->sens); + rtl8180_irq_enable(dev); + + netif_start_queue(dev); + /*DMESG ("lfree %d",get_curr_tx_free_desc(dev,LOW_PRIORITY)); + + DMESG ("nfree %d",get_curr_tx_free_desc(dev,NORM_PRIORITY)); + + DMESG ("hfree %d",get_curr_tx_free_desc(dev,HI_PRIORITY)); + if(check_nic_enought_desc(dev,NORM_PRIORITY)) DMESG("NORM OK"); + if(check_nic_enought_desc(dev,HI_PRIORITY)) DMESG("HI OK"); + if(check_nic_enought_desc(dev,LOW_PRIORITY)) DMESG("LOW OK");*/ +} + + + +/* this configures registers for beacon tx and enables it via + * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might + * be used to stop beacon transmission + */ +void rtl8180_start_tx_beacon(struct net_device *dev) +{ +// struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u16 word; +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + + DMESG("Enabling beacon TX"); + //write_nic_byte(dev, 0x42,0xe6);// TCR +// set_nic_txring(dev); +// fix_tx_fifo(dev); + rtl8180_prepare_beacon(dev); + rtl8180_irq_disable(dev); + rtl8180_beacon_tx_enable(dev); +#if 0 + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); + //write_nic_byte(dev,0x9d,0x20); //DMA Poll + //write_nic_word(dev,0x7a,0); + //write_nic_word(dev,0x7a,0x8000); + +#if 0 + word = read_nic_word(dev, BcnItv); + word &= ~BcnItv_BcnItv; // clear Bcn_Itv + word |= priv->ieee80211->current_network.beacon_interval;//0x64; + write_nic_word(dev, BcnItv, word); +#endif +#endif + word = read_nic_word(dev, AtimWnd) &~ AtimWnd_AtimWnd; + write_nic_word(dev, AtimWnd,word);// word |= +//priv->ieee80211->current_network.atim_window); + + word = read_nic_word(dev, BintrItv); + word &= ~BintrItv_BintrItv; + word |= 1000;/*priv->ieee80211->current_network.beacon_interval * + ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); + // FIXME: check if correct ^^ worked with 0x3e8; + */ + write_nic_word(dev, BintrItv, word); + + + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + +// rtl8180_beacon_tx_enable(dev); +#ifdef CONFIG_RTL8185B + rtl8185b_irq_enable(dev); +#else + rtl8180_irq_enable(dev); +#endif + /* VV !!!!!!!!!! VV*/ + /* + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); + write_nic_byte(dev,0x9d,0x00); + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); +*/ +// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); + +} + + + +/*************************************************************************** + -------------------------------NET STUFF--------------------------- +***************************************************************************/ +static struct net_device_stats *rtl8180_stats(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + return &priv->ieee80211->stats; +} +// +// Change current and default preamble mode. +// 2005.01.06, by rcnjko. +// +bool +MgntActSet_802_11_PowerSaveMode( + struct r8180_priv *priv, + RT_PS_MODE rtPsMode +) +{ + + // Currently, we do not change power save mode on IBSS mode. + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) + { + return false; + } + + // + // <RJ_NOTE> If we make HW to fill up the PwrMgt bit for us, + // some AP will not response to our mgnt frames with PwrMgt bit set, + // e.g. cannot associate the AP. + // So I commented out it. 2005.02.16, by rcnjko. + // +// // Change device's power save mode. +// Adapter->HalFunc.SetPSModeHandler( Adapter, rtPsMode ); + + // Update power save mode configured. +// priv->dot11PowerSaveMode = rtPsMode; + priv->ieee80211->ps = rtPsMode; + // Determine ListenInterval. +#if 0 + if(priv->dot11PowerSaveMode == eMaxPs) + { + priv->ieee80211->ListenInterval = 10; + } + else + { + priv->ieee80211->ListenInterval = 2; + } +#endif + return true; +} + +//================================================================================ +// Leisure Power Save in linked state. +//================================================================================ + +// +// Description: +// Enter the leisure power save mode. +// +void +LeisurePSEnter( + struct r8180_priv *priv + ) +{ + if (priv->bLeisurePs) + { + if (priv->ieee80211->ps == IEEE80211_PS_DISABLED) + { + //printk("----Enter PS\n"); + MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);//IEEE80211_PS_ENABLE + } + } +} + + +// +// Description: +// Leave the leisure power save mode. +// +void +LeisurePSLeave( + struct r8180_priv *priv + ) +{ + if (priv->bLeisurePs) + { + if (priv->ieee80211->ps != IEEE80211_PS_DISABLED) + { + //printk("----Leave PS\n"); + MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED); + } + } +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_hw_wakeup_wq (struct work_struct *work) +{ +// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); +// struct ieee80211_device * ieee = (struct ieee80211_device*) +// container_of(work, struct ieee80211_device, watch_dog_wq); + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq); + struct net_device *dev = ieee->dev; +#else +void rtl8180_hw_wakeup_wq(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); +#endif + +// printk("dev is %d\n",dev); +// printk("&*&(^*(&(&=========>%s()\n", __FUNCTION__); + rtl8180_hw_wakeup(dev); + +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_hw_sleep_wq (struct work_struct *work) +{ +// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); +// struct ieee80211_device * ieee = (struct ieee80211_device*) +// container_of(work, struct ieee80211_device, watch_dog_wq); + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq); + struct net_device *dev = ieee->dev; +#else +void rtl8180_hw_sleep_wq(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); +#endif + + rtl8180_hw_sleep_down(dev); +} + +//YJ,add,080828,for KeepAlive +static void MgntLinkKeepAlive(struct r8180_priv *priv ) +{ + if (priv->keepAliveLevel == 0) + return; + + if(priv->ieee80211->state == IEEE80211_LINKED) + { + // + // Keep-Alive. + // + //printk("LastTx:%d Tx:%d LastRx:%d Rx:%ld Idle:%d\n",priv->link_detect.LastNumTxUnicast,priv->NumTxUnicast, priv->link_detect.LastNumRxUnicast, priv->ieee80211->NumRxUnicast, priv->link_detect.IdleCount); + + if ( (priv->keepAliveLevel== 2) || + (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast && + priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast ) + ) + { + priv->link_detect.IdleCount++; + + // + // Send a Keep-Alive packet packet to AP if we had been idle for a while. + // + if(priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1) ) + { + priv->link_detect.IdleCount = 0; + ieee80211_sta_ps_send_null_frame(priv->ieee80211, false); + } + } + else + { + priv->link_detect.IdleCount = 0; + } + priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast; + priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast; + } +} +//YJ,add,080828,for KeepAlive,end + +static u8 read_acadapter_file(char *filename); +void rtl8180_watch_dog(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + bool bEnterPS = false; + bool bBusyTraffic = false; + u32 TotalRxNum = 0; + u16 SlotIndex = 0; + u16 i = 0; +#ifdef ENABLE_IPS + if(priv->ieee80211->actscanning == false){ + if((priv->ieee80211->iw_mode != IW_MODE_ADHOC) && (priv->ieee80211->state == IEEE80211_NOLINK) && (priv->ieee80211->beinretry == false) && (priv->eRFPowerState == eRfOn)){ + IPSEnter(dev); + } + } +#endif + //YJ,add,080828,for link state check + if((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)){ + SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum; + priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod; + for( i=0; i<priv->link_detect.SlotNum; i++ ) + TotalRxNum+= priv->link_detect.RxFrameNum[i]; + //printk("&&&&&=== TotalRxNum = %d\n", TotalRxNum); + if(TotalRxNum == 0){ + priv->ieee80211->state = IEEE80211_ASSOCIATING; + queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq); + } + } + + //YJ,add,080828,for KeepAlive + MgntLinkKeepAlive(priv); + + //YJ,add,080828,for LPS +#ifdef ENABLE_LPS + if(priv->PowerProfile == POWER_PROFILE_BATTERY ) + { + //Turn on LeisurePS on battery power + //printk("!!!!!On battery power\n"); + priv->bLeisurePs = true; + } + else if(priv->PowerProfile == POWER_PROFILE_AC ) + { + // Turn off LeisurePS on AC power + //printk("----On AC power\n"); + LeisurePSLeave(priv); + priv->bLeisurePs= false; + } +#endif + +#if 0 +#ifndef ENABLE_LPS + if(priv->ieee80211->state == IEEE80211_LINKED){ + if( priv->NumRxOkInPeriod> 666 || + priv->NumTxOkInPeriod > 666 ) { + bBusyTraffic = true; + } + if((priv->ieee80211->NumRxData + priv->NumTxOkInPeriod)<8) { + bEnterPS= true; + } + if(bEnterPS) { + LeisurePSEnter(priv); + } + else { + LeisurePSLeave(priv); + } + } + else { + LeisurePSLeave(priv); + } +#endif + priv->NumRxOkInPeriod = 0; + priv->NumTxOkInPeriod = 0; + priv->ieee80211->NumRxData = 0; +#else +#ifdef ENABLE_LPS + if(priv->ieee80211->state == IEEE80211_LINKED){ + priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod; + //printk("TxOk=%d RxOk=%d\n", priv->link_detect.NumTxOkInPeriod, priv->link_detect.NumRxOkInPeriod); + if( priv->link_detect.NumRxOkInPeriod> 666 || + priv->link_detect.NumTxOkInPeriod> 666 ) { + bBusyTraffic = true; + } + if(((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8) + || (priv->link_detect.NumRxOkInPeriod > 2)) { + bEnterPS= false; + } + else { + bEnterPS= true; + } + + if(bEnterPS) { + LeisurePSEnter(priv); + } + else { + LeisurePSLeave(priv); + } + } + else{ + LeisurePSLeave(priv); + } +#endif + priv->link_detect.bBusyTraffic = bBusyTraffic; + priv->link_detect.NumRxOkInPeriod = 0; + priv->link_detect.NumTxOkInPeriod = 0; + priv->ieee80211->NumRxDataInPeriod = 0; + priv->ieee80211->NumRxBcnInPeriod = 0; +#endif +} +int _rtl8180_up(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //int i; + + priv->up=1; + + DMESG("Bringing up iface"); +#ifdef CONFIG_RTL8185B + rtl8185b_adapter_start(dev); + rtl8185b_rx_enable(dev); + rtl8185b_tx_enable(dev); +#else + rtl8180_adapter_start(dev); + rtl8180_rx_enable(dev); + rtl8180_tx_enable(dev); +#endif +#ifdef ENABLE_IPS + if(priv->bInactivePs){ + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) + IPSLeave(dev); + } +#endif +//by amy 080312 +#ifdef RATE_ADAPT + timer_rate_adaptive((unsigned long)dev); +#endif +//by amy 080312 + watch_dog_adaptive((unsigned long)dev); +#ifdef SW_ANTE + if(priv->bSwAntennaDiverity) + SwAntennaDiversityTimerCallback(dev); +#endif +// IPSEnter(dev); + ieee80211_softmac_start_protocol(priv->ieee80211); + +//Add for RF power on power off by lizhaoming 080512 +// priv->eRFPowerState = eRfOn; +// printk("\n--------Start queue_work:GPIOChangeRFWorkItem"); +// queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->GPIOChangeRFWorkItem,1000); + + return 0; +} + + +int rtl8180_open(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret; + + down(&priv->wx_sem); + ret = rtl8180_up(dev); + up(&priv->wx_sem); + return ret; + +} + + +int rtl8180_up(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + if (priv->up == 1) return -1; + + return _rtl8180_up(dev); +} + + +int rtl8180_close(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret; + + down(&priv->wx_sem); + ret = rtl8180_down(dev); + up(&priv->wx_sem); + + return ret; + +} + +int rtl8180_down(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + if (priv->up == 0) return -1; + + priv->up=0; + + ieee80211_softmac_stop_protocol(priv->ieee80211); + /* FIXME */ + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + rtl8180_rtx_disable(dev); + rtl8180_irq_disable(dev); + del_timer_sync(&priv->watch_dog_timer); + //cancel_delayed_work(&priv->ieee80211->watch_dog_wq); +//{by amy 080312 + del_timer_sync(&priv->rateadapter_timer); + cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); +//by amy 080312} + cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); + cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); + cancel_delayed_work(&priv->ieee80211->hw_dig_wq); + cancel_delayed_work(&priv->ieee80211->tx_pw_wq); + del_timer_sync(&priv->SwAntennaDiversityTimer); + SetZebraRFPowerState8185(dev,eRfOff); + //ieee80211_softmac_stop_protocol(priv->ieee80211); + memset(&(priv->ieee80211->current_network),0,sizeof(struct ieee80211_network)); + priv->ieee80211->state = IEEE80211_NOLINK; + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_restart_wq(struct work_struct *work) +{ + struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); + struct net_device *dev = priv->dev; +#else +void rtl8180_restart_wq(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); +#endif + down(&priv->wx_sem); + + rtl8180_commit(dev); + + up(&priv->wx_sem); +} + +void rtl8180_restart(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //rtl8180_commit(dev); + schedule_work(&priv->reset_wq); + //DMESG("TXTIMEOUT"); +} + + +void rtl8180_commit(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + if (priv->up == 0) return ; +//+by amy 080312 + del_timer_sync(&priv->watch_dog_timer); + //cancel_delayed_work(&priv->ieee80211->watch_dog_wq); +//{by amy 080312 +//by amy for rate adaptive + del_timer_sync(&priv->rateadapter_timer); + cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); +//by amy for rate adaptive +//by amy 080312} + cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); + cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); + cancel_delayed_work(&priv->ieee80211->hw_dig_wq); + cancel_delayed_work(&priv->ieee80211->tx_pw_wq); + del_timer_sync(&priv->SwAntennaDiversityTimer); + ieee80211_softmac_stop_protocol(priv->ieee80211); + rtl8180_irq_disable(dev); + rtl8180_rtx_disable(dev); + _rtl8180_up(dev); +} + + +static void r8180_set_multicast(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + short promisc; + + //down(&priv->wx_sem); + + promisc = (dev->flags & IFF_PROMISC) ? 1:0; + + if (promisc != priv->promisc) + rtl8180_restart(dev); + + priv->promisc = promisc; + + //up(&priv->wx_sem); +} + +#if 0 +/* this is called by the kernel when it needs to TX a 802.3 encapsulated frame*/ +int rtl8180_8023_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_lock,flags); + ret = ieee80211_r8180_8023_hardstartxmit(skb,priv->ieee80211); + spin_unlock_irqrestore(&priv->tx_lock,flags); + return ret; +} +#endif + +int r8180_set_mac_adr(struct net_device *dev, void *mac) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct sockaddr *addr = mac; + + down(&priv->wx_sem); + + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + + if(priv->ieee80211->iw_mode == IW_MODE_MASTER) + memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN); + + if (priv->up) { + rtl8180_down(dev); + rtl8180_up(dev); + } + + up(&priv->wx_sem); + + return 0; +} + +/* based on ipw2200 driver */ +int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + struct iwreq *wrq = (struct iwreq *) rq; + int ret=-1; + switch (cmd) { + case RTL_IOCTL_WPA_SUPPLICANT: + ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); + return ret; + + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + + + +/**************************************************************************** + -----------------------------PCI STUFF--------------------------- +*****************************************************************************/ + + +static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned long ioaddr = 0; + struct net_device *dev = NULL; + struct r8180_priv *priv= NULL; + //u8 *ptr; + u8 unit = 0; + +#ifdef CONFIG_RTL8180_IO_MAP + unsigned long pio_start, pio_len, pio_flags; +#else + unsigned long pmem_start, pmem_len, pmem_flags; +#endif //end #ifdef RTL_IO_MAP + + DMESG("Configuring chip resources"); + + if( pci_enable_device (pdev) ){ + DMESG("Failed to enable PCI device"); + return -EIO; + } + + pci_set_master(pdev); + //pci_set_wmi(pdev); + pci_set_dma_mask(pdev, 0xffffff00ULL); + pci_set_consistent_dma_mask(pdev,0xffffff00ULL); + dev = alloc_ieee80211(sizeof(struct r8180_priv)); + if (!dev) + return -ENOMEM; + priv = ieee80211_priv(dev); + priv->ieee80211 = netdev_priv(dev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + SET_MODULE_OWNER(dev); +#endif + pci_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + priv = ieee80211_priv(dev); +// memset(priv,0,sizeof(struct r8180_priv)); + priv->pdev=pdev; + + +#ifdef CONFIG_RTL8180_IO_MAP + + pio_start = (unsigned long)pci_resource_start (pdev, 0); + pio_len = (unsigned long)pci_resource_len (pdev, 0); + pio_flags = (unsigned long)pci_resource_flags (pdev, 0); + + if (!(pio_flags & IORESOURCE_IO)) { + DMESG("region #0 not a PIO resource, aborting"); + goto fail; + } + + //DMESG("IO space @ 0x%08lx", pio_start ); + if( ! request_region( pio_start, pio_len, RTL8180_MODULE_NAME ) ){ + DMESG("request_region failed!"); + goto fail; + } + + ioaddr = pio_start; + dev->base_addr = ioaddr; // device I/O address + +#else + + pmem_start = pci_resource_start(pdev, 1); + pmem_len = pci_resource_len(pdev, 1); + pmem_flags = pci_resource_flags (pdev, 1); + + if (!(pmem_flags & IORESOURCE_MEM)) { + DMESG("region #1 not a MMIO resource, aborting"); + goto fail; + } + + //DMESG("Memory mapped space @ 0x%08lx ", pmem_start); + if( ! request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) { + DMESG("request_mem_region failed!"); + goto fail; + } + + + ioaddr = (unsigned long)ioremap_nocache( pmem_start, pmem_len); + if( ioaddr == (unsigned long)NULL ){ + DMESG("ioremap failed!"); + // release_mem_region( pmem_start, pmem_len ); + goto fail1; + } + + dev->mem_start = ioaddr; // shared mem start + dev->mem_end = ioaddr + pci_resource_len(pdev, 0); // shared mem end + +#endif //end #ifdef RTL_IO_MAP + +#ifdef CONFIG_RTL8185B + //pci_read_config_byte(pdev, 0x05, ptr); + //pci_write_config_byte(pdev, 0x05, (*ptr) & (~0x04)); + pci_read_config_byte(pdev, 0x05, &unit); + pci_write_config_byte(pdev, 0x05, unit & (~0x04)); +#endif + + dev->irq = pdev->irq; + priv->irq = 0; + + dev->open = rtl8180_open; + dev->stop = rtl8180_close; + //dev->hard_start_xmit = ieee80211_xmit; + dev->tx_timeout = rtl8180_restart; + dev->wireless_handlers = &r8180_wx_handlers_def; + dev->do_ioctl = rtl8180_ioctl; + dev->set_multicast_list = r8180_set_multicast; + dev->set_mac_address = r8180_set_mac_adr; + +#if WIRELESS_EXT >= 12 +#if WIRELESS_EXT < 17 + dev->get_wireless_stats = r8180_get_wireless_stats; +#endif + dev->wireless_handlers = (struct iw_handler_def *) &r8180_wx_handlers_def; +#endif + + dev->type=ARPHRD_ETHER; + dev->watchdog_timeo = HZ*3; //added by david woo, 2007.12.13 + + if (dev_alloc_name(dev, ifname) < 0){ + DMESG("Oops: devname already taken! Trying wlan%%d...\n"); + ifname = "wlan%d"; + // ifname = "ath%d"; + dev_alloc_name(dev, ifname); + } + + + if(rtl8180_init(dev)!=0){ + DMESG("Initialization failed"); + goto fail1; + } + + netif_carrier_off(dev); + + register_netdev(dev); + + rtl8180_proc_init_one(dev); + + DMESG("Driver probe completed\n"); + return 0; + +fail1: + +#ifdef CONFIG_RTL8180_IO_MAP + + if( dev->base_addr != 0 ){ + + release_region(dev->base_addr, + pci_resource_len(pdev, 0) ); + } +#else + if( dev->mem_start != (unsigned long)NULL ){ + iounmap( (void *)dev->mem_start ); + release_mem_region( pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1) ); + } +#endif //end #ifdef RTL_IO_MAP + + +fail: + if(dev){ + + if (priv->irq) { + free_irq(dev->irq, dev); + dev->irq=0; + } + free_ieee80211(dev); + } + + pci_disable_device(pdev); + + DMESG("wlan driver load failed\n"); + pci_set_drvdata(pdev, NULL); + return -ENODEV; + +} + + +static void __devexit rtl8180_pci_remove(struct pci_dev *pdev) +{ + struct r8180_priv *priv; + struct net_device *dev = pci_get_drvdata(pdev); + if(dev){ + + unregister_netdev(dev); + + priv=ieee80211_priv(dev); + + rtl8180_proc_remove_one(dev); + rtl8180_down(dev); + priv->rf_close(dev); + rtl8180_reset(dev); + //rtl8180_rtx_disable(dev); + //rtl8180_irq_disable(dev); + mdelay(10); + //write_nic_word(dev,INTA,read_nic_word(dev,INTA)); + //force_pci_posting(dev); + //mdelay(10); + + if(priv->irq){ + + DMESG("Freeing irq %d",dev->irq); + free_irq(dev->irq, dev); + priv->irq=0; + + } + + free_rx_desc_ring(dev); + free_tx_desc_rings(dev); + // free_beacon_desc_ring(dev,priv->txbeaconcount); + +#ifdef CONFIG_RTL8180_IO_MAP + + if( dev->base_addr != 0 ){ + + release_region(dev->base_addr, + pci_resource_len(pdev, 0) ); + } +#else + if( dev->mem_start != (unsigned long)NULL ){ + iounmap( (void *)dev->mem_start ); + release_mem_region( pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1) ); + } +#endif /*end #ifdef RTL_IO_MAP*/ + + free_ieee80211(dev); + } + pci_disable_device(pdev); + + DMESG("wlan driver removed\n"); +} + + +/* fun with the built-in ieee80211 stack... */ +extern int ieee80211_crypto_init(void); +extern void ieee80211_crypto_deinit(void); +extern int ieee80211_crypto_tkip_init(void); +extern void ieee80211_crypto_tkip_exit(void); +extern int ieee80211_crypto_ccmp_init(void); +extern void ieee80211_crypto_ccmp_exit(void); +extern int ieee80211_crypto_wep_init(void); +extern void ieee80211_crypto_wep_exit(void); + +static int __init rtl8180_pci_module_init(void) +{ + int ret; + + ret = ieee80211_crypto_init(); + if (ret) { + printk(KERN_ERR "ieee80211_crypto_init() failed %d\n", ret); + return ret; + } + ret = ieee80211_crypto_tkip_init(); + if (ret) { + printk(KERN_ERR "ieee80211_crypto_tkip_init() failed %d\n", ret); + return ret; + } + ret = ieee80211_crypto_ccmp_init(); + if (ret) { + printk(KERN_ERR "ieee80211_crypto_ccmp_init() failed %d\n", ret); + return ret; + } + ret = ieee80211_crypto_wep_init(); + if (ret) { + printk(KERN_ERR "ieee80211_crypto_wep_init() failed %d\n", ret); + return ret; + } + + printk(KERN_INFO "\nLinux kernel driver for RTL8180 \ +/ RTL8185 based WLAN cards\n"); + printk(KERN_INFO "Copyright (c) 2004-2005, Andrea Merello\n"); + DMESG("Initializing module"); + DMESG("Wireless extensions version %d", WIRELESS_EXT); + rtl8180_proc_module_init(); + +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) + if(0!=pci_module_init(&rtl8180_pci_driver)) +#else + if(0!=pci_register_driver(&rtl8180_pci_driver)) +#endif + //if(0!=pci_module_init(&rtl8180_pci_driver)) + { + DMESG("No device found"); + /*pci_unregister_driver (&rtl8180_pci_driver);*/ + return -ENODEV; + } + return 0; +} + + +static void __exit rtl8180_pci_module_exit(void) +{ + pci_unregister_driver (&rtl8180_pci_driver); + rtl8180_proc_module_remove(); + ieee80211_crypto_deinit(); + ieee80211_crypto_tkip_exit(); + ieee80211_crypto_ccmp_exit(); + ieee80211_crypto_wep_exit(); + DMESG("Exiting"); +} + + +void rtl8180_try_wake_queue(struct net_device *dev, int pri) +{ + unsigned long flags; + short enough_desc; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + spin_lock_irqsave(&priv->tx_lock,flags); + enough_desc = check_nic_enought_desc(dev,pri); + spin_unlock_irqrestore(&priv->tx_lock,flags); + + if(enough_desc) + ieee80211_wake_queue(priv->ieee80211); +} + +/***************************************************************************** + -----------------------------IRQ STUFF--------------------------- +******************************************************************************/ + +void rtl8180_tx_isr(struct net_device *dev, int pri,short error) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + u32 *tail; //tail virtual addr + u32 *head; //head virtual addr + u32 *begin;//start of ring virtual addr + u32 *nicv; //nic pointer virtual addr +// u32 *txdv; //packet just TXed + u32 nic; //nic pointer physical addr + u32 nicbegin;// start of ring physical addr +// short txed; + unsigned long flag; + /* physical addr are ok on 32 bits since we set DMA mask*/ + + int offs; + int j,i; + int hd; + if (error) priv->stats.txretry++; //tony 20060601 + spin_lock_irqsave(&priv->tx_lock,flag); + switch(pri) { + case MANAGE_PRIORITY: + tail = priv->txmapringtail; + begin = priv->txmapring; + head = priv->txmapringhead; + nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR); + nicbegin = priv->txmapringdma; + break; + + case BK_PRIORITY: + tail = priv->txbkpringtail; + begin = priv->txbkpring; + head = priv->txbkpringhead; + nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR); + nicbegin = priv->txbkpringdma; + break; + + case BE_PRIORITY: + tail = priv->txbepringtail; + begin = priv->txbepring; + head = priv->txbepringhead; + nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR); + nicbegin = priv->txbepringdma; + break; + + case VI_PRIORITY: + tail = priv->txvipringtail; + begin = priv->txvipring; + head = priv->txvipringhead; + nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR); + nicbegin = priv->txvipringdma; + break; + + case VO_PRIORITY: + tail = priv->txvopringtail; + begin = priv->txvopring; + head = priv->txvopringhead; + nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR); + nicbegin = priv->txvopringdma; + break; + + case HI_PRIORITY: + tail = priv->txhpringtail; + begin = priv->txhpring; + head = priv->txhpringhead; + nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR); + nicbegin = priv->txhpringdma; + break; + + default: + spin_unlock_irqrestore(&priv->tx_lock,flag); + return ; + } +/* DMESG("%x %s %x %x",((int)nic & 0xfff)/8/4, + *(priv->txnpring + ((int)nic&0xfff)/4/8) & (1<<31) ? "filled" : "empty", + (priv->txnpringtail - priv->txnpring)/8,(priv->txnpringhead - +priv->txnpring)/8); +*/ + //nicv = (u32*) ((nic - nicbegin) + (int)begin); + nicv = (u32*) ((nic - nicbegin) + (u8*)begin); + if((head <= tail && (nicv > tail || nicv < head)) || + (head > tail && (nicv > tail && nicv < head))){ + + DMESGW("nic has lost pointer"); +#ifdef DEBUG_TX_DESC + //check_tx_ring(dev,NORM_PRIORITY); + check_tx_ring(dev,pri); +#endif + spin_unlock_irqrestore(&priv->tx_lock,flag); + rtl8180_restart(dev); + return; + } + + /* we check all the descriptors between the head and the nic, + * but not the currenly pointed by the nic (the next to be txed) + * and the previous of the pointed (might be in process ??) + */ + //if (head == nic) return; + //DMESG("%x %x",head,nic); + offs = (nic - nicbegin); + //DMESG("%x %x %x",nic ,(u32)nicbegin, (int)nic -nicbegin); + + offs = offs / 8 /4; + + hd = (head - begin) /8; + + if(offs >= hd) + j = offs - hd; + else + j = offs + (priv->txringcount -1 -hd); + // j= priv->txringcount -1- (hd - offs); + + j-=2; + if(j<0) j=0; + + + for(i=0;i<j;i++) + { +// printk("+++++++++++++check status desc\n"); + if((*head) & (1<<31)) + break; + if(((*head)&(0x10000000)) != 0){ +// printk("++++++++++++++last desc,retry count is %d\n",((*head) & (0x000000ff))); + priv->CurrRetryCnt += (u16)((*head) & (0x000000ff)); +#if 1 + if(!error) + { + priv->NumTxOkTotal++; +// printk("NumTxOkTotal is %d\n",priv->NumTxOkTotal++); + } +#endif + // printk("in function %s:curr_retry_count is %d\n",__FUNCTION__,((*head) & (0x000000ff))); + } + if(!error){ + priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff); + } +// printk("in function %s:curr_txokbyte_count is %d\n",__FUNCTION__,(*(head+3)) & (0x00000fff)); + *head = *head &~ (1<<31); + + if((head - begin)/8 == priv->txringcount-1) + head=begin; + + else + head+=8; + } +#if 0 + if(nicv == begin) + txdv = begin + (priv->txringcount -1)*8; + else + txdv = nicv - 8; + + txed = !(txdv[0] &(1<<31)); + + if(txed){ + if(!(txdv[0] & (1<<15))) error = 1; + //if(!(txdv[0] & (1<<30))) error = 1; + if(error)DMESG("%x",txdv[0]); + } +#endif + //DMESG("%x",txdv[0]); + /* the head has been moved to the last certainly TXed + * (or at least processed by the nic) packet. + * The driver take forcefully owning of all these packets + * If the packet previous of the nic pointer has been + * processed this doesn't matter: it will be checked + * here at the next round. Anyway if no more packet are + * TXed no memory leak occour at all. + */ + + switch(pri) { + case MANAGE_PRIORITY: + priv->txmapringhead = head; + //printk("1==========================================> priority check!\n"); + if(priv->ack_tx_to_ieee){ + // try to implement power-save mode 2008.1.22 + // printk("2==========================================> priority check!\n"); +#if 1 + if(rtl8180_is_tx_queue_empty(dev)){ + // printk("tx queue empty, after send null sleep packet, try to sleep !\n"); + priv->ack_tx_to_ieee = 0; + ieee80211_ps_tx_ack(priv->ieee80211,!error); + } +#endif + } + break; + + case BK_PRIORITY: + priv->txbkpringhead = head; + break; + + case BE_PRIORITY: + priv->txbepringhead = head; + break; + + case VI_PRIORITY: + priv->txvipringhead = head; + break; + + case VO_PRIORITY: + priv->txvopringhead = head; + break; + + case HI_PRIORITY: + priv->txhpringhead = head; + break; + } + + /*DMESG("%x %x %x", (priv->txnpringhead - priv->txnpring) /8 , + (priv->txnpringtail - priv->txnpring) /8, + offs ); + */ + + spin_unlock_irqrestore(&priv->tx_lock,flag); + +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8180_tx_irq_wq(struct work_struct *work) +{ + //struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct ieee80211_device * ieee = (struct ieee80211_device*) + container_of(dwork, struct ieee80211_device, watch_dog_wq); + struct net_device *dev = ieee->dev; +#else +void rtl8180_tx_irq_wq(struct net_device *dev) +{ + //struct r8180_priv *priv = ieee80211_priv(dev); +#endif + rtl8180_tx_isr(dev,MANAGE_PRIORITY,0); +} +irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) netdev; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + unsigned long flags; + u32 inta; + + /* We should return IRQ_NONE, but for now let me keep this */ + if(priv->irq_enabled == 0) return IRQ_HANDLED; + + spin_lock_irqsave(&priv->irq_th_lock,flags); + +#ifdef CONFIG_RTL8185B + //ISR: 4bytes + inta = read_nic_dword(dev, ISR);// & priv->IntrMask; + write_nic_dword(dev,ISR,inta); // reset int situation +#else + inta = read_nic_word(dev,INTA) & priv->irq_mask; + write_nic_word(dev,INTA,inta); // reset int situation +#endif + + priv->stats.shints++; + + //DMESG("Enter interrupt, ISR value = 0x%08x", inta); + + if(!inta){ + spin_unlock_irqrestore(&priv->irq_th_lock,flags); + return IRQ_HANDLED; + /* + most probably we can safely return IRQ_NONE, + but for now is better to avoid problems + */ + } + + if(inta == 0xffff){ + /* HW disappared */ + spin_unlock_irqrestore(&priv->irq_th_lock,flags); + return IRQ_HANDLED; + } + + priv->stats.ints++; +#ifdef DEBUG_IRQ + DMESG("NIC irq %x",inta); +#endif + //priv->irqpending = inta; + + + if(!netif_running(dev)) { + spin_unlock_irqrestore(&priv->irq_th_lock,flags); + return IRQ_HANDLED; + } + + if(inta & ISR_TimeOut){ + write_nic_dword(dev, TimerInt, 0); + //DMESG("=================>waking up"); +// rtl8180_hw_wakeup(dev); + } + + if(inta & ISR_TBDOK){ + priv->stats.txbeacon++; + } + + if(inta & ISR_TBDER){ + priv->stats.txbeaconerr++; + } + + if(inta & IMR_TMGDOK ) { +// priv->NumTxOkTotal++; + rtl8180_tx_isr(dev,MANAGE_PRIORITY,0); +// schedule_work(&priv->tx_irq_wq); + + } + + if(inta & ISR_THPDER){ +#ifdef DEBUG_TX + DMESG ("TX high priority ERR"); +#endif + priv->stats.txhperr++; + rtl8180_tx_isr(dev,HI_PRIORITY,1); + priv->ieee80211->stats.tx_errors++; + } + + if(inta & ISR_THPDOK){ //High priority tx ok +#ifdef DEBUG_TX + DMESG ("TX high priority OK"); +#endif +// priv->NumTxOkTotal++; + //priv->NumTxOkInPeriod++; //YJ,del,080828 + priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 + priv->stats.txhpokint++; + rtl8180_tx_isr(dev,HI_PRIORITY,0); + } + + if(inta & ISR_RER) { + priv->stats.rxerr++; +#ifdef DEBUG_RX + DMESGW("RX error int"); +#endif + } +#ifdef CONFIG_RTL8185B + if(inta & ISR_TBKDER){ //corresponding to BK_PRIORITY + priv->stats.txbkperr++; + priv->ieee80211->stats.tx_errors++; +#ifdef DEBUG_TX + DMESGW("TX bkp error int"); +#endif + //tasklet_schedule(&priv->irq_tx_tasklet); + rtl8180_tx_isr(dev,BK_PRIORITY,1); + rtl8180_try_wake_queue(dev, BE_PRIORITY); + } + + if(inta & ISR_TBEDER){ //corresponding to BE_PRIORITY + priv->stats.txbeperr++; + priv->ieee80211->stats.tx_errors++; +#ifdef DEBUG_TX + DMESGW("TX bep error int"); +#endif + rtl8180_tx_isr(dev,BE_PRIORITY,1); + //tasklet_schedule(&priv->irq_tx_tasklet); + rtl8180_try_wake_queue(dev, BE_PRIORITY); + } +#endif + if(inta & ISR_TNPDER){ //corresponding to VO_PRIORITY + priv->stats.txnperr++; + priv->ieee80211->stats.tx_errors++; +#ifdef DEBUG_TX + DMESGW("TX np error int"); +#endif + //tasklet_schedule(&priv->irq_tx_tasklet); + rtl8180_tx_isr(dev,NORM_PRIORITY,1); +#ifdef CONFIG_RTL8185B + rtl8180_try_wake_queue(dev, NORM_PRIORITY); +#endif + } + + if(inta & ISR_TLPDER){ //corresponding to VI_PRIORITY + priv->stats.txlperr++; + priv->ieee80211->stats.tx_errors++; +#ifdef DEBUG_TX + DMESGW("TX lp error int"); +#endif + rtl8180_tx_isr(dev,LOW_PRIORITY,1); + //tasklet_schedule(&priv->irq_tx_tasklet); + rtl8180_try_wake_queue(dev, LOW_PRIORITY); + } + + if(inta & ISR_ROK){ +#ifdef DEBUG_RX + DMESG("Frame arrived !"); +#endif + //priv->NumRxOkInPeriod++; //YJ,del,080828 + priv->stats.rxint++; + tasklet_schedule(&priv->irq_rx_tasklet); + } + + if(inta & ISR_RQoSOK ){ +#ifdef DEBUG_RX + DMESG("QoS Frame arrived !"); +#endif + //priv->NumRxOkInPeriod++; //YJ,del,080828 + priv->stats.rxint++; + tasklet_schedule(&priv->irq_rx_tasklet); + } + if(inta & ISR_BcnInt) { + //DMESG("Preparing Beacons"); + rtl8180_prepare_beacon(dev); + } + + if(inta & ISR_RDU){ +//#ifdef DEBUG_RX + DMESGW("No RX descriptor available"); + priv->stats.rxrdu++; +//#endif + tasklet_schedule(&priv->irq_rx_tasklet); + /*queue_work(priv->workqueue ,&priv->restart_work);*/ + + } + if(inta & ISR_RXFOVW){ +#ifdef DEBUG_RX + DMESGW("RX fifo overflow"); +#endif + priv->stats.rxoverflow++; + tasklet_schedule(&priv->irq_rx_tasklet); + //queue_work(priv->workqueue ,&priv->restart_work); + } + + if(inta & ISR_TXFOVW) priv->stats.txoverflow++; + + if(inta & ISR_TNPDOK){ //Normal priority tx ok +#ifdef DEBUG_TX + DMESG ("TX normal priority OK"); +#endif +// priv->NumTxOkTotal++; + //priv->NumTxOkInPeriod++; //YJ,del,080828 + priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 + // priv->ieee80211->stats.tx_packets++; + priv->stats.txnpokint++; + rtl8180_tx_isr(dev,NORM_PRIORITY,0); + } + + if(inta & ISR_TLPDOK){ //Low priority tx ok +#ifdef DEBUG_TX + DMESG ("TX low priority OK"); +#endif +// priv->NumTxOkTotal++; + //priv->NumTxOkInPeriod++; //YJ,del,080828 + priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 + // priv->ieee80211->stats.tx_packets++; + priv->stats.txlpokint++; + rtl8180_tx_isr(dev,LOW_PRIORITY,0); + rtl8180_try_wake_queue(dev, LOW_PRIORITY); + } + +#ifdef CONFIG_RTL8185B + if(inta & ISR_TBKDOK){ //corresponding to BK_PRIORITY + priv->stats.txbkpokint++; +#ifdef DEBUG_TX + DMESGW("TX bk priority ok"); +#endif +// priv->NumTxOkTotal++; + //priv->NumTxOkInPeriod++; //YJ,del,080828 + priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 + rtl8180_tx_isr(dev,BK_PRIORITY,0); + rtl8180_try_wake_queue(dev, BE_PRIORITY); + } + + if(inta & ISR_TBEDOK){ //corresponding to BE_PRIORITY + priv->stats.txbeperr++; +#ifdef DEBUG_TX + DMESGW("TX be priority ok"); +#endif +// priv->NumTxOkTotal++; + //priv->NumTxOkInPeriod++; //YJ,del,080828 + priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 + rtl8180_tx_isr(dev,BE_PRIORITY,0); + rtl8180_try_wake_queue(dev, BE_PRIORITY); + } +#endif + force_pci_posting(dev); + spin_unlock_irqrestore(&priv->irq_th_lock,flags); + + return IRQ_HANDLED; +} + + +void rtl8180_irq_rx_tasklet(struct r8180_priv* priv) +{ +// unsigned long flags; + +/* spin_lock_irqsave(&priv->irq_lock, flags); + priv->irq_mask &=~IMR_ROK; + priv->irq_mask &=~IMR_RDU; + + rtl8180_irq_enable(priv->dev); + spin_unlock_irqrestore(&priv->irq_lock, flags); +*/ + rtl8180_rx(priv->dev); + +/* spin_lock_irqsave(&priv->irq_lock, flags); + priv->irq_mask |= IMR_ROK; + priv->irq_mask |= IMR_RDU; + rtl8180_irq_enable(priv->dev); + spin_unlock_irqrestore(&priv->irq_lock, flags); +*/ +} + +/**************************************************************************** +lizhaoming--------------------------- RF power on/power off ----------------- +*****************************************************************************/ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void GPIOChangeRFWorkItemCallBack(struct work_struct *work) +{ + //struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work); + struct net_device *dev = ieee->dev; + struct r8180_priv *priv = ieee80211_priv(dev); +#else +void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee) +{ + struct net_device *dev = ieee->dev; + struct r8180_priv *priv = ieee80211_priv(dev); +#endif + + //u16 tmp2byte; + u8 btPSR; + u8 btConfig0; + RT_RF_POWER_STATE eRfPowerStateToSet; + bool bActuallySet=false; + + char *argv[3]; + static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh"; + static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL}; + static int readf_count = 0; + //printk("============>%s in \n", __func__); + +#ifdef ENABLE_LPS + if(readf_count % 10 == 0) + priv->PowerProfile = read_acadapter_file("/proc/acpi/ac_adapter/AC0/state"); + + readf_count = (readf_count+1)%0xffff; +#endif +#if 0 + if(priv->up == 0)//driver stopped + { + printk("\nDo nothing..."); + goto out; + } + else +#endif + { + // We should turn off LED before polling FF51[4]. + + //Turn off LED. + btPSR = read_nic_byte(dev, PSR); + write_nic_byte(dev, PSR, (btPSR & ~BIT3)); + + //It need to delay 4us suggested by Jong, 2008-01-16 + udelay(4); + + //HW radio On/Off according to the value of FF51[4](config0) + btConfig0 = btPSR = read_nic_byte(dev, CONFIG0); + + //Turn on LED. + write_nic_byte(dev, PSR, btPSR| BIT3); + + eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff; + + if((priv->ieee80211->bHwRadioOff == true) && (eRfPowerStateToSet == eRfOn)) + { + priv->ieee80211->bHwRadioOff = false; + bActuallySet = true; + } + else if((priv->ieee80211->bHwRadioOff == false) && (eRfPowerStateToSet == eRfOff)) + { + priv->ieee80211->bHwRadioOff = true; + bActuallySet = true; + } + + if(bActuallySet) + { + MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); + + /* To update the UI status for Power status changed */ + if(priv->ieee80211->bHwRadioOff == true) + argv[1] = "RFOFF"; + else{ + //if(!priv->RfOffReason) + argv[1] = "RFON"; + //else + // argv[1] = "RFOFF"; + } + argv[0] = RadioPowerPath; + argv[2] = NULL; + + call_usermodehelper(RadioPowerPath,argv,envp,1); + } + + } + +} + +static u8 read_acadapter_file(char *filename) +{ +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) +#if 0 + int fd; + char buf[1]; + char ret[50]; + int i = 0; + int n = 0; + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = sys_open(filename, O_RDONLY, 0); + if (fd >= 0) { + while (sys_read(fd, buf, 1) == 1) + { + i++; + if(i>10) + { + if(buf[0]!=' ') + { + ret[n]=buf[0]; + n++; + } + } + } + sys_close(fd); + } + ret[n]='\0'; +// printk("%s \n", ret); + set_fs(old_fs); + + if(strncmp(ret, "off-line",8) == 0) + { + return 1; + } +#endif + return 0; +} + +/*************************************************************************** + ------------------- module init / exit stubs ---------------- +****************************************************************************/ +module_init(rtl8180_pci_module_init); +module_exit(rtl8180_pci_module_exit); + diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c new file mode 100644 index 0000000..742dc11 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_dm.c @@ -0,0 +1,1725 @@ +//#include "r8180.h"
+#include "r8180_dm.h"
+#include "r8180_hw.h"
+#include "r8180_93cx6.h"
+//{by amy 080312
+
+//
+// Description:
+// Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise.
+//
+//+by amy 080312
+#define RATE_ADAPTIVE_TIMER_PERIOD 300
+
+bool CheckHighPower(struct net_device *dev)
+{
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee80211;
+
+ if(!priv->bRegHighPowerMechanism)
+ {
+ return false;
+ }
+
+ if(ieee->state == IEEE80211_LINKED_SCANNING)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//
+// Description:
+// Update Tx power level if necessary.
+// See also DoRxHighPower() and SetTxPowerLevel8185() for reference.
+//
+// Note:
+// The reason why we udpate Tx power level here instead of DoRxHighPower()
+// is the number of IO to change Tx power is much more than chane TR switch
+// and they are related to OFDM and MAC registers.
+// So, we don't want to update it so frequently in per-Rx packet base.
+//
+void
+DoTxHighPower(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ u16 HiPwrUpperTh = 0;
+ u16 HiPwrLowerTh = 0;
+ u8 RSSIHiPwrUpperTh;
+ u8 RSSIHiPwrLowerTh;
+ u8 u1bTmp;
+ char OfdmTxPwrIdx, CckTxPwrIdx;
+
+ //printk("----> DoTxHighPower()\n");
+
+ HiPwrUpperTh = priv->RegHiPwrUpperTh;
+ HiPwrLowerTh = priv->RegHiPwrLowerTh;
+
+ HiPwrUpperTh = HiPwrUpperTh * 10;
+ HiPwrLowerTh = HiPwrLowerTh * 10;
+ RSSIHiPwrUpperTh = priv->RegRSSIHiPwrUpperTh;
+ RSSIHiPwrLowerTh = priv->RegRSSIHiPwrLowerTh;
+
+ //lzm add 080826
+ OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel];
+ CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel];
+
+ // printk("DoTxHighPower() - UndecoratedSmoothedSS:%d, CurCCKRSSI = %d , bCurCCKPkt= %d \n", priv->UndecoratedSmoothedSS, priv->CurCCKRSSI, priv->bCurCCKPkt );
+
+ if((priv->UndecoratedSmoothedSS > HiPwrUpperTh) ||
+ (priv->bCurCCKPkt && (priv->CurCCKRSSI > RSSIHiPwrUpperTh)))
+ {
+ // Stevenl suggested that degrade 8dbm in high power sate. 2007-12-04 Isaiah
+
+ // printk("=====>DoTxHighPower() - High Power - UndecoratedSmoothedSS:%d, HiPwrUpperTh = %d \n", priv->UndecoratedSmoothedSS, HiPwrUpperTh );
+ priv->bToUpdateTxPwr = true;
+ u1bTmp= read_nic_byte(dev, CCK_TXAGC);
+
+ // If it never enter High Power.
+ if( CckTxPwrIdx == u1bTmp)
+ {
+ u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0; // 8dbm
+ write_nic_byte(dev, CCK_TXAGC, u1bTmp);
+
+ u1bTmp= read_nic_byte(dev, OFDM_TXAGC);
+ u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0; // 8dbm
+ write_nic_byte(dev, OFDM_TXAGC, u1bTmp);
+ }
+
+ }
+ else if((priv->UndecoratedSmoothedSS < HiPwrLowerTh) &&
+ (!priv->bCurCCKPkt || priv->CurCCKRSSI < RSSIHiPwrLowerTh))
+ {
+ // printk("DoTxHighPower() - lower Power - UndecoratedSmoothedSS:%d, HiPwrUpperTh = %d \n", priv->UndecoratedSmoothedSS, HiPwrLowerTh );
+ if(priv->bToUpdateTxPwr)
+ {
+ priv->bToUpdateTxPwr = false;
+ //SD3 required.
+ u1bTmp= read_nic_byte(dev, CCK_TXAGC);
+ if(u1bTmp < CckTxPwrIdx)
+ {
+ //u1bTmp = ((u1bTmp+16) > 35) ? 35: (u1bTmp+16); // 8dbm
+ //write_nic_byte(dev, CCK_TXAGC, u1bTmp);
+ write_nic_byte(dev, CCK_TXAGC, CckTxPwrIdx);
+ }
+
+ u1bTmp= read_nic_byte(dev, OFDM_TXAGC);
+ if(u1bTmp < OfdmTxPwrIdx)
+ {
+ //u1bTmp = ((u1bTmp+16) > 35) ? 35: (u1bTmp+16); // 8dbm
+ //write_nic_byte(dev, OFDM_TXAGC, u1bTmp);
+ write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx);
+ }
+ }
+ }
+
+ //printk("<---- DoTxHighPower()\n");
+}
+
+
+//
+// Description:
+// Callback function of UpdateTxPowerWorkItem.
+// Because of some event happend, e.g. CCX TPC, High Power Mechanism,
+// We update Tx power of current channel again.
+//
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void rtl8180_tx_pw_wq (struct work_struct *work)
+{
+// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
+// struct ieee80211_device * ieee = (struct ieee80211_device*)
+// container_of(work, struct ieee80211_device, watch_dog_wq);
+ struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,tx_pw_wq);
+ struct net_device *dev = ieee->dev;
+#else
+void rtl8180_tx_pw_wq(struct net_device *dev)
+{
+ // struct r8180_priv *priv = ieee80211_priv(dev);
+#endif
+
+// printk("----> UpdateTxPowerWorkItemCallback()\n");
+
+ DoTxHighPower(dev);
+
+// printk("<---- UpdateTxPowerWorkItemCallback()\n");
+}
+
+
+//
+// Description:
+// Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise.
+//
+bool
+CheckDig(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee80211;
+
+ if(!priv->bDigMechanism)
+ return false;
+
+ if(ieee->state != IEEE80211_LINKED)
+ return false;
+
+ //if(priv->CurrentOperaRate < 36) // Schedule Dig under all OFDM rates. By Bruce, 2007-06-01.
+ if((priv->ieee80211->rate/5) < 36) // Schedule Dig under all OFDM rates. By Bruce, 2007-06-01.
+ return false;
+ return true;
+}
+//
+// Description:
+// Implementation of DIG for Zebra and Zebra2.
+//
+void
+DIG_Zebra(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ u16 CCKFalseAlarm, OFDMFalseAlarm;
+ u16 OfdmFA1, OfdmFA2;
+ int InitialGainStep = 7; // The number of initial gain stages.
+ int LowestGainStage = 4; // The capable lowest stage of performing dig workitem.
+ u32 AwakePeriodIn2Sec=0;
+
+ //printk("---------> DIG_Zebra()\n");
+
+ CCKFalseAlarm = (u16)(priv->FalseAlarmRegValue & 0x0000ffff);
+ OFDMFalseAlarm = (u16)((priv->FalseAlarmRegValue >> 16) & 0x0000ffff);
+ OfdmFA1 = 0x15;
+ OfdmFA2 = ((u16)(priv->RegDigOfdmFaUpTh)) << 8;
+
+// printk("DIG**********CCK False Alarm: %#X \n",CCKFalseAlarm);
+// printk("DIG**********OFDM False Alarm: %#X \n",OFDMFalseAlarm);
+
+ // The number of initial gain steps is different, by Bruce, 2007-04-13.
+ if (priv->InitialGain == 0 ) //autoDIG
+ { // Advised from SD3 DZ
+ priv->InitialGain = 4; // In 87B, m74dBm means State 4 (m82dBm)
+ }
+ //if(pHalData->VersionID != VERSION_8187B_B)
+ { // Advised from SD3 DZ
+ OfdmFA1 = 0x20;
+ }
+
+#if 1 //lzm reserved 080826
+ AwakePeriodIn2Sec = (2000-priv ->DozePeriodInPast2Sec);
+ //printk("&&& DozePeriod=%d AwakePeriod=%d\n", priv->DozePeriodInPast2Sec, AwakePeriodIn2Sec);
+ priv ->DozePeriodInPast2Sec=0;
+
+ if(AwakePeriodIn2Sec)
+ {
+ //RT_TRACE(COMP_DIG, DBG_TRACE, ("DIG: AwakePeriodIn2Sec(%d) - FATh(0x%X , 0x%X) ->",AwakePeriodIn2Sec, OfdmFA1, OfdmFA2));
+ // adjuest DIG threshold.
+ OfdmFA1 = (u16)((OfdmFA1*AwakePeriodIn2Sec) / 2000) ;
+ OfdmFA2 = (u16)((OfdmFA2*AwakePeriodIn2Sec) / 2000) ;
+ //RT_TRACE(COMP_DIG, DBG_TRACE, ("( 0x%X , 0x%X)\n", OfdmFA1, OfdmFA2));
+ }
+ else
+ {
+ ;//RT_TRACE(COMP_DIG, DBG_WARNING, ("ERROR!! AwakePeriodIn2Sec should not be ZERO!!\n"));
+ }
+#endif
+
+ InitialGainStep = 8;
+ LowestGainStage = priv->RegBModeGainStage; // Lowest gain stage.
+
+ if (OFDMFalseAlarm > OfdmFA1)
+ {
+ if (OFDMFalseAlarm > OfdmFA2)
+ {
+ priv->DIG_NumberFallbackVote++;
+ if (priv->DIG_NumberFallbackVote >1)
+ {
+ //serious OFDM False Alarm, need fallback
+ if (priv->InitialGain < InitialGainStep)
+ {
+ priv->InitialGainBackUp= priv->InitialGain;
+
+ priv->InitialGain = (priv->InitialGain + 1);
+// printk("DIG**********OFDM False Alarm: %#X, OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2);
+// printk("DIG+++++++ fallback OFDM:%d \n", priv->InitialGain);
+ UpdateInitialGain(dev);
+ }
+ priv->DIG_NumberFallbackVote = 0;
+ priv->DIG_NumberUpgradeVote=0;
+ }
+ }
+ else
+ {
+ if (priv->DIG_NumberFallbackVote)
+ priv->DIG_NumberFallbackVote--;
+ }
+ priv->DIG_NumberUpgradeVote=0;
+ }
+ else
+ {
+ if (priv->DIG_NumberFallbackVote)
+ priv->DIG_NumberFallbackVote--;
+ priv->DIG_NumberUpgradeVote++;
+
+ if (priv->DIG_NumberUpgradeVote>9)
+ {
+ if (priv->InitialGain > LowestGainStage) // In 87B, m78dBm means State 4 (m864dBm)
+ {
+ priv->InitialGainBackUp= priv->InitialGain;
+
+ priv->InitialGain = (priv->InitialGain - 1);
+// printk("DIG**********OFDM False Alarm: %#X, OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2);
+// printk("DIG--------- Upgrade OFDM:%d \n", priv->InitialGain);
+ UpdateInitialGain(dev);
+ }
+ priv->DIG_NumberFallbackVote = 0;
+ priv->DIG_NumberUpgradeVote=0;
+ }
+ }
+
+// printk("DIG+++++++ OFDM:%d\n", priv->InitialGain);
+ //printk("<--------- DIG_Zebra()\n");
+}
+
+//
+// Description:
+// Dispatch DIG implementation according to RF.
+//
+void
+DynamicInitGain(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = ieee80211_priv(dev);
+
+ switch(priv->rf_chip)
+ {
+ case RF_ZEBRA2: // [AnnieWorkaround] For Zebra2, 2005-08-01.
+ case RF_ZEBRA4:
+ DIG_Zebra( dev );
+ break;
+
+ default:
+ printk("DynamicInitGain(): unknown RFChipID(%d) !!!\n", priv->rf_chip);
+ break;
+ }
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void rtl8180_hw_dig_wq (struct work_struct *work)
+{
+// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
+// struct ieee80211_device * ieee = (struct ieee80211_device*)
+// container_of(work, struct ieee80211_device, watch_dog_wq);
+ struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq);
+ struct net_device *dev = ieee->dev;
+#else
+void rtl8180_hw_dig_wq(struct net_device *dev)
+{
+
+#endif
+ struct r8180_priv *priv = ieee80211_priv(dev);
+
+ // Read CCK and OFDM False Alarm.
+ priv->FalseAlarmRegValue = read_nic_dword(dev, CCK_FALSE_ALARM);
+
+
+ // Adjust Initial Gain dynamically.
+ DynamicInitGain(dev);
+
+}
+
+int
+IncludedInSupportedRates(
+ struct r8180_priv *priv,
+ u8 TxRate )
+{
+ u8 rate_len;
+ u8 rate_ex_len;
+ u8 RateMask = 0x7F;
+ u8 idx;
+ unsigned short Found = 0;
+ u8 NaiveTxRate = TxRate&RateMask;
+
+ rate_len = priv->ieee80211->current_network.rates_len;
+ rate_ex_len = priv->ieee80211->current_network.rates_ex_len;
+ for( idx=0; idx< rate_len; idx++ )
+ {
+ if( (priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate )
+ {
+ Found = 1;
+ goto found_rate;
+ }
+ }
+ for( idx=0; idx< rate_ex_len; idx++ )
+ {
+ if( (priv->ieee80211->current_network.rates_ex[idx] & RateMask) == NaiveTxRate )
+ {
+ Found = 1;
+ goto found_rate;
+ }
+ }
+ return Found;
+ found_rate:
+ return Found;
+}
+
+//
+// Description:
+// Get the Tx rate one degree up form the input rate in the supported rates.
+// Return the upgrade rate if it is successed, otherwise return the input rate.
+// By Bruce, 2007-06-05.
+//
+u8
+GetUpgradeTxRate(
+ struct net_device *dev,
+ u8 rate
+ )
+{
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ u8 UpRate;
+
+ // Upgrade 1 degree.
+ switch(rate)
+ {
+ case 108: // Up to 54Mbps.
+ UpRate = 108;
+ break;
+
+ case 96: // Up to 54Mbps.
+ UpRate = 108;
+ break;
+
+ case 72: // Up to 48Mbps.
+ UpRate = 96;
+ break;
+
+ case 48: // Up to 36Mbps.
+ UpRate = 72;
+ break;
+
+ case 36: // Up to 24Mbps.
+ UpRate = 48;
+ break;
+
+ case 22: // Up to 18Mbps.
+ UpRate = 36;
+ break;
+
+ case 11: // Up to 11Mbps.
+ UpRate = 22;
+ break;
+
+ case 4: // Up to 5.5Mbps.
+ UpRate = 11;
+ break;
+
+ case 2: // Up to 2Mbps.
+ UpRate = 4;
+ break;
+
+ default:
+ printk("GetUpgradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate);
+ return rate;
+ }
+ // Check if the rate is valid.
+ if(IncludedInSupportedRates(priv, UpRate))
+ {
+// printk("GetUpgradeTxRate(): GetUpgrade Tx rate(%d) from %d !\n", UpRate, priv->CurrentOperaRate);
+ return UpRate;
+ }
+ else
+ {
+ //printk("GetUpgradeTxRate(): Tx rate (%d) is not in supported rates\n", UpRate);
+ return rate;
+ }
+ return rate;
+}
+//
+// Description:
+// Get the Tx rate one degree down form the input rate in the supported rates.
+// Return the degrade rate if it is successed, otherwise return the input rate.
+// By Bruce, 2007-06-05.
+//
+u8
+GetDegradeTxRate(
+ struct net_device *dev,
+ u8 rate
+ )
+{
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ u8 DownRate;
+
+ // Upgrade 1 degree.
+ switch(rate)
+ {
+ case 108: // Down to 48Mbps.
+ DownRate = 96;
+ break;
+
+ case 96: // Down to 36Mbps.
+ DownRate = 72;
+ break;
+
+ case 72: // Down to 24Mbps.
+ DownRate = 48;
+ break;
+
+ case 48: // Down to 18Mbps.
+ DownRate = 36;
+ break;
+
+ case 36: // Down to 11Mbps.
+ DownRate = 22;
+ break;
+
+ case 22: // Down to 5.5Mbps.
+ DownRate = 11;
+ break;
+
+ case 11: // Down to 2Mbps.
+ DownRate = 4;
+ break;
+
+ case 4: // Down to 1Mbps.
+ DownRate = 2;
+ break;
+
+ case 2: // Down to 1Mbps.
+ DownRate = 2;
+ break;
+
+ default:
+ printk("GetDegradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate);
+ return rate;
+ }
+ // Check if the rate is valid.
+ if(IncludedInSupportedRates(priv, DownRate))
+ {
+// printk("GetDegradeTxRate(): GetDegrade Tx rate(%d) from %d!\n", DownRate, priv->CurrentOperaRate);
+ return DownRate;
+ }
+ else
+ {
+ //printk("GetDegradeTxRate(): Tx rate (%d) is not in supported rates\n", DownRate);
+ return rate;
+ }
+ return rate;
+}
+//
+// Helper function to determine if specified data rate is
+// CCK rate.
+// 2005.01.25, by rcnjko.
+//
+bool
+MgntIsCckRate(
+ u16 rate
+ )
+{
+ bool bReturn = false;
+
+ if((rate <= 22) && (rate != 12) && (rate != 18))
+ {
+ bReturn = true;
+ }
+
+ return bReturn;
+}
+#ifdef CONFIG_RTL818X_S
+//
+// Description:
+// Tx Power tracking mechanism routine on 87SE.
+// Created by Roger, 2007.12.11.
+//
+void
+TxPwrTracking87SE(
+ struct net_device *dev
+)
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ u8 tmpu1Byte, CurrentThermal, Idx;
+ char CckTxPwrIdx, OfdmTxPwrIdx;
+ //u32 u4bRfReg;
+
+ tmpu1Byte = read_nic_byte(dev, EN_LPF_CAL);
+ CurrentThermal = (tmpu1Byte & 0xf0)>>4; //[ 7:4]: thermal meter indication.
+ CurrentThermal = (CurrentThermal>0x0c)? 0x0c:CurrentThermal;//lzm add 080826
+
+ //printk("TxPwrTracking87SE(): CurrentThermal(%d)\n", CurrentThermal);
+
+ if( CurrentThermal != priv->ThermalMeter)
+ {
+// printk("TxPwrTracking87SE(): Thermal meter changed!!!\n");
+
+ // Update Tx Power level on each channel.
+ for(Idx = 1; Idx<15; Idx++)
+ {
+ CckTxPwrIdx = priv->chtxpwr[Idx];
+ OfdmTxPwrIdx = priv->chtxpwr_ofdm[Idx];
+
+ if( CurrentThermal > priv->ThermalMeter )
+ { // higher thermal meter.
+ CckTxPwrIdx += (CurrentThermal - priv->ThermalMeter)*2;
+ OfdmTxPwrIdx += (CurrentThermal - priv->ThermalMeter)*2;
+
+ if(CckTxPwrIdx >35)
+ CckTxPwrIdx = 35; // Force TxPower to maximal index.
+ if(OfdmTxPwrIdx >35)
+ OfdmTxPwrIdx = 35;
+ }
+ else
+ { // lower thermal meter.
+ CckTxPwrIdx -= (priv->ThermalMeter - CurrentThermal)*2;
+ OfdmTxPwrIdx -= (priv->ThermalMeter - CurrentThermal)*2;
+
+ if(CckTxPwrIdx <0)
+ CckTxPwrIdx = 0;
+ if(OfdmTxPwrIdx <0)
+ OfdmTxPwrIdx = 0;
+ }
+
+ // Update TxPower level on CCK and OFDM resp.
+ priv->chtxpwr[Idx] = CckTxPwrIdx;
+ priv->chtxpwr_ofdm[Idx] = OfdmTxPwrIdx;
+ }
+
+ // Update TxPower level immediately.
+ rtl8225z2_SetTXPowerLevel(dev, priv->ieee80211->current_network.channel);
+ }
+ priv->ThermalMeter = CurrentThermal;
+}
+void
+StaRateAdaptive87SE(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ unsigned long CurrTxokCnt;
+ u16 CurrRetryCnt;
+ u16 CurrRetryRate;
+ //u16 i,idx;
+ unsigned long CurrRxokCnt;
+ bool bTryUp = false;
+ bool bTryDown = false;
+ u8 TryUpTh = 1;
+ u8 TryDownTh = 2;
+ u32 TxThroughput;
+ long CurrSignalStrength;
+ bool bUpdateInitialGain = false;
+ u8 u1bOfdm=0, u1bCck = 0;
+ char OfdmTxPwrIdx, CckTxPwrIdx;
+
+ priv->RateAdaptivePeriod= RATE_ADAPTIVE_TIMER_PERIOD;
+
+
+ CurrRetryCnt = priv->CurrRetryCnt;
+ CurrTxokCnt = priv->NumTxOkTotal - priv->LastTxokCnt;
+ CurrRxokCnt = priv->ieee80211->NumRxOkTotal - priv->LastRxokCnt;
+ CurrSignalStrength = priv->Stats_RecvSignalPower;
+ TxThroughput = (u32)(priv->NumTxOkBytesTotal - priv->LastTxOKBytes);
+ priv->LastTxOKBytes = priv->NumTxOkBytesTotal;
+ priv->CurrentOperaRate = priv->ieee80211->rate/5;
+ //printk("priv->CurrentOperaRate is %d\n",priv->CurrentOperaRate);
+ //2 Compute retry ratio.
+ if (CurrTxokCnt>0)
+ {
+ CurrRetryRate = (u16)(CurrRetryCnt*100/CurrTxokCnt);
+ }
+ else
+ { // It may be serious retry. To distinguish serious retry or no packets modified by Bruce
+ CurrRetryRate = (u16)(CurrRetryCnt*100/1);
+ }
+
+
+ //
+ // Added by Roger, 2007.01.02.
+ // For debug information.
+ //
+ //printk("\n(1) pHalData->LastRetryRate: %d \n",priv->LastRetryRate);
+ //printk("(2) RetryCnt = %d \n", CurrRetryCnt);
+ //printk("(3) TxokCnt = %d \n", CurrTxokCnt);
+ //printk("(4) CurrRetryRate = %d \n", CurrRetryRate);
+ //printk("(5) CurrSignalStrength = %d \n",CurrSignalStrength);
+ //printk("(6) TxThroughput is %d\n",TxThroughput);
+ //printk("priv->NumTxOkBytesTotal is %d\n",priv->NumTxOkBytesTotal);
+
+ priv->LastRetryCnt = priv->CurrRetryCnt;
+ priv->LastTxokCnt = priv->NumTxOkTotal;
+ priv->LastRxokCnt = priv->ieee80211->NumRxOkTotal;
+ priv->CurrRetryCnt = 0;
+
+ //2No Tx packets, return to init_rate or not?
+ if (CurrRetryRate==0 && CurrTxokCnt == 0)
+ {
+ //
+ //After 9 (30*300ms) seconds in this condition, we try to raise rate.
+ //
+ priv->TryupingCountNoData++;
+
+// printk("No Tx packets, TryupingCountNoData(%d)\n", priv->TryupingCountNoData);
+ //[TRC Dell Lab] Extend raised period from 4.5sec to 9sec, Isaiah 2008-02-15 18:00
+ if (priv->TryupingCountNoData>30)
+ {
+ priv->TryupingCountNoData = 0;
+ priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate);
+ // Reset Fail Record
+ priv->LastFailTxRate = 0;
+ priv->LastFailTxRateSS = -200;
+ priv->FailTxRateCount = 0;
+ }
+ goto SetInitialGain;
+ }
+ else
+ {
+ priv->TryupingCountNoData=0; //Reset trying up times.
+ }
+
+
+ //
+ // For Netgear case, I comment out the following signal strength estimation,
+ // which can results in lower rate to transmit when sample is NOT enough (e.g. PING request).
+ // 2007.04.09, by Roger.
+ //
+
+ //
+ // Restructure rate adaptive as the following main stages:
+ // (1) Add retry threshold in 54M upgrading condition with signal strength.
+ // (2) Add the mechanism to degrade to CCK rate according to signal strength
+ // and retry rate.
+ // (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated
+ // situation, Initial Gain Update is upon on DIG mechanism except CCK rate.
+ // (4) Add the mehanism of trying to upgrade tx rate.
+ // (5) Record the information of upping tx rate to avoid trying upping tx rate constantly.
+ // By Bruce, 2007-06-05.
+ //
+ //
+
+ // 11Mbps or 36Mbps
+ // Check more times in these rate(key rates).
+ //
+ if(priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72)
+ {
+ TryUpTh += 9;
+ }
+ //
+ // Let these rates down more difficult.
+ //
+ if(MgntIsCckRate(priv->CurrentOperaRate) || priv->CurrentOperaRate == 36)
+ {
+ TryDownTh += 1;
+ }
+
+ //1 Adjust Rate.
+ if (priv->bTryuping == true)
+ {
+ //2 For Test Upgrading mechanism
+ // Note:
+ // Sometimes the throughput is upon on the capability bwtween the AP and NIC,
+ // thus the low data rate does not improve the performance.
+ // We randomly upgrade the data rate and check if the retry rate is improved.
+
+ // Upgrading rate did not improve the retry rate, fallback to the original rate.
+ if ( (CurrRetryRate > 25) && TxThroughput < priv->LastTxThroughput)
+ {
+ //Not necessary raising rate, fall back rate.
+ bTryDown = true;
+ //printk("case1-1: Not necessary raising rate, fall back rate....\n");
+ //printk("case1-1: pMgntInfo->CurrentOperaRate =%d, TxThroughput = %d, LastThroughput = %d\n",
+ // priv->CurrentOperaRate, TxThroughput, priv->LastTxThroughput);
+ }
+ else
+ {
+ priv->bTryuping = false;
+ }
+ }
+ else if (CurrSignalStrength > -47 && (CurrRetryRate < 50))
+ {
+ //2For High Power
+ //
+ // Added by Roger, 2007.04.09.
+ // Return to highest data rate, if signal strength is good enough.
+ // SignalStrength threshold(-50dbm) is for RTL8186.
+ // Revise SignalStrength threshold to -51dbm.
+ //
+ // Also need to check retry rate for safety, by Bruce, 2007-06-05.
+ if(priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate )
+ {
+ bTryUp = true;
+ // Upgrade Tx Rate directly.
+ priv->TryupingCount += TryUpTh;
+ }
+// printk("case2: StaRateAdaptive87SE: Power(%d) is high enough!!. \n", CurrSignalStrength);
+
+ }
+ else if(CurrTxokCnt > 9 && CurrTxokCnt< 100 && CurrRetryRate >= 600)
+ {
+ //2 For Serious Retry
+ //
+ // Traffic is not busy but our Tx retry is serious.
+ //
+ bTryDown = true;
+ // Let Rate Mechanism to degrade tx rate directly.
+ priv->TryDownCountLowData += TryDownTh;
+// printk("case3: RA: Tx Retry is serious. Degrade Tx Rate to %d directly...\n", priv->CurrentOperaRate);
+ }
+ else if ( priv->CurrentOperaRate == 108 )
+ {
+ //2For 54Mbps
+ // Air Link
+ if ( (CurrRetryRate>26)&&(priv->LastRetryRate>25))
+// if ( (CurrRetryRate>40)&&(priv->LastRetryRate>39))
+ {
+ //Down to rate 48Mbps.
+ bTryDown = true;
+ }
+ // Cable Link
+ else if ( (CurrRetryRate>17)&&(priv->LastRetryRate>16) && (CurrSignalStrength > -72))
+// else if ( (CurrRetryRate>17)&&(priv->LastRetryRate>16) && (CurrSignalStrength > -72))
+ {
+ //Down to rate 48Mbps.
+ bTryDown = true;
+ }
+
+ if(bTryDown && (CurrSignalStrength < -75)) //cable link
+ {
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ //printk("case4---54M \n");
+
+ }
+ else if ( priv->CurrentOperaRate == 96 )
+ {
+ //2For 48Mbps
+ //Air Link
+ if ( ((CurrRetryRate>48) && (priv->LastRetryRate>47)))
+// if ( ((CurrRetryRate>65) && (priv->LastRetryRate>64)))
+
+ {
+ //Down to rate 36Mbps.
+ bTryDown = true;
+ }
+ //Cable Link
+ else if ( ((CurrRetryRate>21) && (priv->LastRetryRate>20)) && (CurrSignalStrength > -74))
+ {
+ //Down to rate 36Mbps.
+ bTryDown = true;
+ }
+ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
+// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
+ {
+ bTryDown = true;
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ else if ( (CurrRetryRate<8) && (priv->LastRetryRate<8) ) //TO DO: need to consider (RSSI)
+// else if ( (CurrRetryRate<28) && (priv->LastRetryRate<8) )
+ {
+ bTryUp = true;
+ }
+
+ if(bTryDown && (CurrSignalStrength < -75))
+ {
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ //printk("case5---48M \n");
+ }
+ else if ( priv->CurrentOperaRate == 72 )
+ {
+ //2For 36Mbps
+ if ( (CurrRetryRate>43) && (priv->LastRetryRate>41))
+// if ( (CurrRetryRate>60) && (priv->LastRetryRate>59))
+ {
+ //Down to rate 24Mbps.
+ bTryDown = true;
+ }
+ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
+// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
+ {
+ bTryDown = true;
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ else if ( (CurrRetryRate<15) && (priv->LastRetryRate<16)) //TO DO: need to consider (RSSI)
+// else if ( (CurrRetryRate<35) && (priv->LastRetryRate<36))
+ {
+ bTryUp = true;
+ }
+
+ if(bTryDown && (CurrSignalStrength < -80))
+ {
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ //printk("case6---36M \n");
+ }
+ else if ( priv->CurrentOperaRate == 48 )
+ {
+ //2For 24Mbps
+ // Air Link
+ if ( ((CurrRetryRate>63) && (priv->LastRetryRate>62)))
+// if ( ((CurrRetryRate>83) && (priv->LastRetryRate>82)))
+ {
+ //Down to rate 18Mbps.
+ bTryDown = true;
+ }
+ //Cable Link
+ else if ( ((CurrRetryRate>33) && (priv->LastRetryRate>32)) && (CurrSignalStrength > -82) )
+// else if ( ((CurrRetryRate>50) && (priv->LastRetryRate>49)) && (CurrSignalStrength > -82) )
+ {
+ //Down to rate 18Mbps.
+ bTryDown = true;
+ }
+ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
+// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
+
+ {
+ bTryDown = true;
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ else if ( (CurrRetryRate<20) && (priv->LastRetryRate<21)) //TO DO: need to consider (RSSI)
+// else if ( (CurrRetryRate<40) && (priv->LastRetryRate<41))
+ {
+ bTryUp = true;
+ }
+
+ if(bTryDown && (CurrSignalStrength < -82))
+ {
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ //printk("case7---24M \n");
+ }
+ else if ( priv->CurrentOperaRate == 36 )
+ {
+ //2For 18Mbps
+ // original (109, 109)
+ //[TRC Dell Lab] (90, 91), Isaiah 2008-02-18 23:24
+ // (85, 86), Isaiah 2008-02-18 24:00
+ if ( ((CurrRetryRate>85) && (priv->LastRetryRate>86)))
+// if ( ((CurrRetryRate>115) && (priv->LastRetryRate>116)))
+ {
+ //Down to rate 11Mbps.
+ bTryDown = true;
+ }
+ //[TRC Dell Lab] Isaiah 2008-02-18 23:24
+ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 ))
+// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 ))
+ {
+ bTryDown = true;
+ priv->TryDownCountLowData += TryDownTh;
+ }
+ else if ( (CurrRetryRate<22) && (priv->LastRetryRate<23)) //TO DO: need to consider (RSSI)
+// else if ( (CurrRetryRate<42) && (priv->LastRetryRate<43))
+ {
+ bTryUp = true;
+ }
+ //printk("case8---18M \n");
+ }
+ else if ( priv->CurrentOperaRate == 22 )
+ {
+ //2For 11Mbps
+ if (CurrRetryRate>95)
+// if (CurrRetryRate>155)
+ {
+ bTryDown = true;
+ }
+ else if ( (CurrRetryRate<29) && (priv->LastRetryRate <30) )//TO DO: need to consider (RSSI)
+// else if ( (CurrRetryRate<49) && (priv->LastRetryRate <50) )
+ {
+ bTryUp = true;
+ }
+ //printk("case9---11M \n");
+ }
+ else if ( priv->CurrentOperaRate == 11 )
+ {
+ //2For 5.5Mbps
+ if (CurrRetryRate>149)
+// if (CurrRetryRate>189)
+ {
+ bTryDown = true;
+ }
+ else if ( (CurrRetryRate<60) && (priv->LastRetryRate < 65))
+// else if ( (CurrRetryRate<80) && (priv->LastRetryRate < 85))
+
+ {
+ bTryUp = true;
+ }
+ //printk("case10---5.5M \n");
+ }
+ else if ( priv->CurrentOperaRate == 4 )
+ {
+ //2For 2 Mbps
+ if((CurrRetryRate>99) && (priv->LastRetryRate>99))
+// if((CurrRetryRate>199) && (priv->LastRetryRate>199))
+ {
+ bTryDown = true;
+ }
+ else if ( (CurrRetryRate < 65) && (priv->LastRetryRate < 70))
+// else if ( (CurrRetryRate < 85) && (priv->LastRetryRate < 90))
+ {
+ bTryUp = true;
+ }
+ //printk("case11---2M \n");
+ }
+ else if ( priv->CurrentOperaRate == 2 )
+ {
+ //2For 1 Mbps
+ if( (CurrRetryRate<70) && (priv->LastRetryRate<75))
+// if( (CurrRetryRate<90) && (priv->LastRetryRate<95))
+ {
+ bTryUp = true;
+ }
+ //printk("case12---1M \n");
+ }
+
+ if(bTryUp && bTryDown)
+ printk("StaRateAdaptive87B(): Tx Rate tried upping and downing simultaneously!\n");
+
+ //1 Test Upgrading Tx Rate
+ // Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC.
+ // To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate.
+ if(!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0)
+ && priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate && priv->FailTxRateCount < 2)
+ {
+ if(jiffies% (CurrRetryRate + 101) == 0)
+ {
+ bTryUp = true;
+ priv->bTryuping = true;
+ //printk("StaRateAdaptive87SE(): Randomly try upgrading...\n");
+ }
+ }
+
+ //1 Rate Mechanism
+ if(bTryUp)
+ {
+ priv->TryupingCount++;
+ priv->TryDownCountLowData = 0;
+
+ {
+// printk("UP: pHalData->TryupingCount = %d\n", priv->TryupingCount);
+// printk("UP: TryUpTh(%d)+ (FailTxRateCount(%d))^2 =%d\n",
+// TryUpTh, priv->FailTxRateCount, (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount) );
+// printk("UP: pHalData->bTryuping=%d\n", priv->bTryuping);
+
+ }
+
+ //
+ // Check more times if we need to upgrade indeed.
+ // Because the largest value of pHalData->TryupingCount is 0xFFFF and
+ // the largest value of pHalData->FailTxRateCount is 0x14,
+ // this condition will be satisfied at most every 2 min.
+ //
+
+ if((priv->TryupingCount > (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount)) ||
+ (CurrSignalStrength > priv->LastFailTxRateSS) || priv->bTryuping)
+ {
+ priv->TryupingCount = 0;
+ //
+ // When transfering from CCK to OFDM, DIG is an important issue.
+ //
+ if(priv->CurrentOperaRate == 22)
+ bUpdateInitialGain = true;
+
+ // The difference in throughput between 48Mbps and 36Mbps is 8M.
+ // So, we must be carefully in this rate scale. Isaiah 2008-02-15.
+ //
+ if( ((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) &&
+ (priv->FailTxRateCount > 2) )
+ priv->RateAdaptivePeriod= (RATE_ADAPTIVE_TIMER_PERIOD/2);
+
+ // (1)To avoid upgrade frequently to the fail tx rate, add the FailTxRateCount into the threshold.
+ // (2)If the signal strength is increased, it may be able to upgrade.
+
+ priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate);
+// printk("StaRateAdaptive87SE(): Upgrade Tx Rate to %d\n", priv->CurrentOperaRate);
+
+ //[TRC Dell Lab] Bypass 12/9/6, Isaiah 2008-02-18 20:00
+ if(priv->CurrentOperaRate ==36)
+ {
+ priv->bUpdateARFR=true;
+ write_nic_word(dev, ARFR, 0x0F8F); //bypass 12/9/6
+// printk("UP: ARFR=0xF8F\n");
+ }
+ else if(priv->bUpdateARFR)
+ {
+ priv->bUpdateARFR=false;
+ write_nic_word(dev, ARFR, 0x0FFF); //set 1M ~ 54Mbps.
+// printk("UP: ARFR=0xFFF\n");
+ }
+
+ // Update Fail Tx rate and count.
+ if(priv->LastFailTxRate != priv->CurrentOperaRate)
+ {
+ priv->LastFailTxRate = priv->CurrentOperaRate;
+ priv->FailTxRateCount = 0;
+ priv->LastFailTxRateSS = -200; // Set lowest power.
+ }
+ }
+ }
+ else
+ {
+ if(priv->TryupingCount > 0)
+ priv->TryupingCount --;
+ }
+
+ if(bTryDown)
+ {
+ priv->TryDownCountLowData++;
+ priv->TryupingCount = 0;
+ {
+// printk("DN: pHalData->TryDownCountLowData = %d\n",priv->TryDownCountLowData);
+// printk("DN: TryDownTh =%d\n", TryDownTh);
+// printk("DN: pHalData->bTryuping=%d\n", priv->bTryuping);
+ }
+
+ //Check if Tx rate can be degraded or Test trying upgrading should fallback.
+ if(priv->TryDownCountLowData > TryDownTh || priv->bTryuping)
+ {
+ priv->TryDownCountLowData = 0;
+ priv->bTryuping = false;
+ // Update fail information.
+ if(priv->LastFailTxRate == priv->CurrentOperaRate)
+ {
+ priv->FailTxRateCount ++;
+ // Record the Tx fail rate signal strength.
+ if(CurrSignalStrength > priv->LastFailTxRateSS)
+ {
+ priv->LastFailTxRateSS = CurrSignalStrength;
+ }
+ }
+ else
+ {
+ priv->LastFailTxRate = priv->CurrentOperaRate;
+ priv->FailTxRateCount = 1;
+ priv->LastFailTxRateSS = CurrSignalStrength;
+ }
+ priv->CurrentOperaRate = GetDegradeTxRate(dev, priv->CurrentOperaRate);
+
+ // Reduce chariot training time at weak signal strength situation. SD3 ED demand.
+ //[TRC Dell Lab] Revise Signal Threshold from -75 to -80 , Isaiah 2008-02-18 20:00
+ if( (CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72 ))
+ {
+ priv->CurrentOperaRate = 72;
+// printk("DN: weak signal strength (%d), degrade to 36Mbps\n", CurrSignalStrength);
+ }
+
+ //[TRC Dell Lab] Bypass 12/9/6, Isaiah 2008-02-18 20:00
+ if(priv->CurrentOperaRate ==36)
+ {
+ priv->bUpdateARFR=true;
+ write_nic_word(dev, ARFR, 0x0F8F); //bypass 12/9/6
+// printk("DN: ARFR=0xF8F\n");
+ }
+ else if(priv->bUpdateARFR)
+ {
+ priv->bUpdateARFR=false;
+ write_nic_word(dev, ARFR, 0x0FFF); //set 1M ~ 54Mbps.
+// printk("DN: ARFR=0xFFF\n");
+ }
+
+ //
+ // When it is CCK rate, it may need to update initial gain to receive lower power packets.
+ //
+ if(MgntIsCckRate(priv->CurrentOperaRate))
+ {
+ bUpdateInitialGain = true;
+ }
+// printk("StaRateAdaptive87SE(): Degrade Tx Rate to %d\n", priv->CurrentOperaRate);
+ }
+ }
+ else
+ {
+ if(priv->TryDownCountLowData > 0)
+ priv->TryDownCountLowData --;
+ }
+
+ // Keep the Tx fail rate count to equal to 0x15 at most.
+ // Reduce the fail count at least to 10 sec if tx rate is tending stable.
+ if(priv->FailTxRateCount >= 0x15 ||
+ (!bTryUp && !bTryDown && priv->TryDownCountLowData == 0 && priv->TryupingCount && priv->FailTxRateCount > 0x6))
+ {
+ priv->FailTxRateCount --;
+ }
+
+
+ OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel];
+ CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel];
+
+ //[TRC Dell Lab] Mac0x9e increase 2 level in 36M~18M situation, Isaiah 2008-02-18 24:00
+ if((priv->CurrentOperaRate < 96) &&(priv->CurrentOperaRate > 22))
+ {
+ u1bCck = read_nic_byte(dev, CCK_TXAGC);
+ u1bOfdm = read_nic_byte(dev, OFDM_TXAGC);
+
+ // case 1: Never enter High power
+ if(u1bCck == CckTxPwrIdx )
+ {
+ if(u1bOfdm != (OfdmTxPwrIdx+2) )
+ {
+ priv->bEnhanceTxPwr= true;
+ u1bOfdm = ((u1bOfdm+2) > 35) ? 35: (u1bOfdm+2);
+ write_nic_byte(dev, OFDM_TXAGC, u1bOfdm);
+// printk("Enhance OFDM_TXAGC : +++++ u1bOfdm= 0x%x\n", u1bOfdm);
+ }
+ }
+ // case 2: enter high power
+ else if(u1bCck < CckTxPwrIdx)
+ {
+ if(!priv->bEnhanceTxPwr)
+ {
+ priv->bEnhanceTxPwr= true;
+ u1bOfdm = ((u1bOfdm+2) > 35) ? 35: (u1bOfdm+2);
+ write_nic_byte(dev, OFDM_TXAGC, u1bOfdm);
+ //RT_TRACE(COMP_RATE, DBG_TRACE, ("Enhance OFDM_TXAGC(2) : +++++ u1bOfdm= 0x%x\n", u1bOfdm));
+ }
+ }
+ }
+ else if(priv->bEnhanceTxPwr) //54/48/11/5.5/2/1
+ {
+ u1bCck = read_nic_byte(dev, CCK_TXAGC);
+ u1bOfdm = read_nic_byte(dev, OFDM_TXAGC);
+
+ // case 1: Never enter High power
+ if(u1bCck == CckTxPwrIdx )
+ {
+ priv->bEnhanceTxPwr= false;
+ write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx);
+ //printk("Recover OFDM_TXAGC : ===== u1bOfdm= 0x%x\n", OfdmTxPwrIdx);
+ }
+ // case 2: enter high power
+ else if(u1bCck < CckTxPwrIdx)
+ {
+ priv->bEnhanceTxPwr= false;
+ u1bOfdm = ((u1bOfdm-2) > 0) ? (u1bOfdm-2): 0;
+ write_nic_byte(dev, OFDM_TXAGC, u1bOfdm);
+ //RT_TRACE(COMP_RATE, DBG_TRACE, ("Recover OFDM_TXAGC(2): ===== u1bOfdm= 0x%x\n", u1bOfdm));
+
+ }
+ }
+
+ //
+ // We need update initial gain when we set tx rate "from OFDM to CCK" or
+ // "from CCK to OFDM".
+ //
+SetInitialGain:
+ if(bUpdateInitialGain)
+ {
+ if(MgntIsCckRate(priv->CurrentOperaRate)) // CCK
+ {
+ if(priv->InitialGain > priv->RegBModeGainStage)
+ {
+ priv->InitialGainBackUp= priv->InitialGain;
+
+ if(CurrSignalStrength < -85) // Low power, OFDM [0x17] = 26.
+ {
+ //SD3 SYs suggest that CurrSignalStrength < -65, ofdm 0x17=26.
+ priv->InitialGain = priv->RegBModeGainStage;
+ }
+ else if(priv->InitialGain > priv->RegBModeGainStage + 1)
+ {
+ priv->InitialGain -= 2;
+ }
+ else
+ {
+ priv->InitialGain --;
+ }
+ printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate);
+ UpdateInitialGain(dev);
+ }
+ }
+ else // OFDM
+ {
+ if(priv->InitialGain < 4)
+ {
+ priv->InitialGainBackUp= priv->InitialGain;
+
+ priv->InitialGain ++;
+ printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate);
+ UpdateInitialGain(dev);
+ }
+ }
+ }
+
+ //Record the related info
+ priv->LastRetryRate = CurrRetryRate;
+ priv->LastTxThroughput = TxThroughput;
+ priv->ieee80211->rate = priv->CurrentOperaRate * 5;
+}
+
+#endif
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20)
+void rtl8180_rate_adapter(struct work_struct * work)
+{
+ struct delayed_work *dwork = container_of(work,struct delayed_work,work);
+ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,rate_adapter_wq);
+ struct net_device *dev = ieee->dev;
+#else
+void rtl8180_rate_adapter(struct net_device *dev)
+{
+
+#endif
+ //struct r8180_priv *priv = ieee80211_priv(dev);
+// DMESG("---->rtl8180_rate_adapter");
+ StaRateAdaptive87SE(dev);
+// DMESG("<----rtl8180_rate_adapter");
+}
+void timer_rate_adaptive(unsigned long data)
+{
+ struct r8180_priv* priv = ieee80211_priv((struct net_device *)data);
+ //DMESG("---->timer_rate_adaptive()\n");
+ if(!priv->up)
+ {
+// DMESG("<----timer_rate_adaptive():driver is not up!\n");
+ return;
+ }
+ if((priv->ieee80211->iw_mode != IW_MODE_MASTER)
+ && (priv->ieee80211->state == IEEE80211_LINKED) &&
+ (priv->ForcedDataRate == 0) )
+ {
+// DMESG("timer_rate_adaptive():schedule rate_adapter_wq\n");
+#ifdef CONFIG_RTL818X_S
+ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->rate_adapter_wq);
+// StaRateAdaptive87SE((struct net_device *)data);
+#endif
+ }
+ priv->rateadapter_timer.expires = jiffies + MSECS(priv->RateAdaptivePeriod);
+ add_timer(&priv->rateadapter_timer);
+ //DMESG("<----timer_rate_adaptive()\n");
+}
+//by amy 080312}
+void
+SwAntennaDiversityRxOk8185(
+ struct net_device *dev,
+ u8 SignalStrength
+ )
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+
+// printk("+SwAntennaDiversityRxOk8185: RxSs: %d\n", SignalStrength);
+
+ priv->AdRxOkCnt++;
+
+ if( priv->AdRxSignalStrength != -1)
+ {
+ priv->AdRxSignalStrength = ((priv->AdRxSignalStrength*7) + (SignalStrength*3)) / 10;
+ }
+ else
+ { // Initialization case.
+ priv->AdRxSignalStrength = SignalStrength;
+ }
+//{+by amy 080312
+ if( priv->LastRxPktAntenna ) //Main antenna.
+ priv->AdMainAntennaRxOkCnt++;
+ else // Aux antenna.
+ priv->AdAuxAntennaRxOkCnt++;
+//+by amy 080312
+// printk("-SwAntennaDiversityRxOk8185: AdRxOkCnt: %d AdRxSignalStrength: %d\n", priv->AdRxOkCnt, priv->AdRxSignalStrength);
+}
+//
+// Description:
+// Change Antenna Switch.
+//
+bool
+SetAntenna8185(
+ struct net_device *dev,
+ u8 u1bAntennaIndex
+ )
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ bool bAntennaSwitched = false;
+
+// printk("+SetAntenna8185(): Antenna is switching to: %d \n", u1bAntennaIndex);
+
+ switch(u1bAntennaIndex)
+ {
+ case 0:
+ switch(priv->rf_chip)
+ {
+ case RF_ZEBRA2:
+ case RF_ZEBRA4:
+#ifdef CONFIG_RTL8185B
+#ifdef CONFIG_RTL818X_S
+ // Mac register, main antenna
+ write_nic_byte(dev, ANTSEL, 0x03);
+ //base band
+ write_phy_cck(dev,0x11, 0x9b); // Config CCK RX antenna.
+ write_phy_ofdm(dev, 0x0d, 0x5c); // Config OFDM RX antenna.
+
+#else
+ // Mac register, main antenna
+ write_nic_byte(dev, ANTSEL, 0x03);
+ //base band
+ write_phy_cck(dev, 0x10, 0x9b); // Config CCK RX antenna.
+ write_phy_ofdm(dev, 0x0d, 0x5c); // Config OFDM RX antenna.
+#endif
+#endif
+
+ bAntennaSwitched = true;
+ break;
+
+ default:
+ printk("SetAntenna8185: unkown RFChipID(%d)\n", priv->rf_chip);
+ break;
+ }
+ break;
+
+ case 1:
+ switch(priv->rf_chip)
+ {
+ case RF_ZEBRA2:
+ case RF_ZEBRA4:
+#ifdef CONFIG_RTL8185B
+#ifdef CONFIG_RTL818X_S
+ // Mac register, aux antenna
+ write_nic_byte(dev, ANTSEL, 0x00);
+ //base band
+ write_phy_cck(dev, 0x11, 0xbb); // Config CCK RX antenna.
+ write_phy_ofdm(dev, 0x0d, 0x54); // Config OFDM RX antenna.
+#else
+ // Mac register, aux antenna
+ write_nic_byte(dev, ANTSEL, 0x00);
+ //base band
+ write_phy_cck(dev, 0x10, 0xbb); // Config CCK RX antenna.
+ write_phy_ofdm(dev, 0x0d, 0x54); // Config OFDM RX antenna.
+#endif
+#endif
+
+ bAntennaSwitched = true;
+ break;
+
+ default:
+ printk("SetAntenna8185: unkown RFChipID(%d)\n", priv->rf_chip);
+ break;
+ }
+ break;
+
+ default:
+ printk("SetAntenna8185: unkown u1bAntennaIndex(%d)\n", u1bAntennaIndex);
+ break;
+ }
+
+ if(bAntennaSwitched)
+ {
+ priv->CurrAntennaIndex = u1bAntennaIndex;
+ }
+
+// printk("-SetAntenna8185(): return (%#X)\n", bAntennaSwitched);
+
+ return bAntennaSwitched;
+}
+//
+// Description:
+// Toggle Antenna switch.
+//
+bool
+SwitchAntenna(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+
+ bool bResult;
+
+ if(priv->CurrAntennaIndex == 0)
+ {
+#if 0//lzm del 080826
+//by amy 080312
+#ifdef CONFIG_RTL818X_S
+ if(priv->bSwAntennaDiverity)
+ bResult = SetAntennaConfig87SE(dev, 1, true);
+ else
+#endif
+#endif
+ bResult = SetAntenna8185(dev, 1);
+//by amy 080312
+// printk("SwitchAntenna(): switching to antenna 1 ......\n");
+// bResult = SetAntenna8185(dev, 1);//-by amy 080312
+ }
+ else
+ {
+#if 0//lzm del 080826
+//by amy 080312
+#ifdef CONFIG_RTL818X_S
+ if(priv->bSwAntennaDiverity)
+ bResult = SetAntennaConfig87SE(dev, 0, true);
+ else
+#endif
+#endif
+ bResult = SetAntenna8185(dev, 0);
+//by amy 080312
+// printk("SwitchAntenna(): switching to antenna 0 ......\n");
+// bResult = SetAntenna8185(dev, 0);//-by amy 080312
+ }
+
+ return bResult;
+}
+//
+// Description:
+// Engine of SW Antenna Diversity mechanism.
+// Since 8187 has no Tx part information,
+// this implementation is only dependend on Rx part information.
+//
+// 2006.04.17, by rcnjko.
+//
+void
+SwAntennaDiversity(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ bool bSwCheckSS=false;
+// printk("+SwAntennaDiversity(): CurrAntennaIndex: %d\n", priv->CurrAntennaIndex);
+// printk("AdTickCount is %d\n",priv->AdTickCount);
+//by amy 080312
+ if(bSwCheckSS)
+ {
+ priv->AdTickCount++;
+
+ printk("(1) AdTickCount: %d, AdCheckPeriod: %d\n",
+ priv->AdTickCount, priv->AdCheckPeriod);
+ printk("(2) AdRxSignalStrength: %ld, AdRxSsThreshold: %ld\n",
+ priv->AdRxSignalStrength, priv->AdRxSsThreshold);
+ }
+// priv->AdTickCount++;//-by amy 080312
+
+ // Case 1. No Link.
+ if(priv->ieee80211->state != IEEE80211_LINKED)
+ {
+ // printk("SwAntennaDiversity(): Case 1. No Link.\n");
+
+ priv->bAdSwitchedChecking = false;
+ // I switch antenna here to prevent any one of antenna is broken before link established, 2006.04.18, by rcnjko..
+ SwitchAntenna(dev);
+ }
+ // Case 2. Linked but no packet received.
+ else if(priv->AdRxOkCnt == 0)
+ {
+ // printk("SwAntennaDiversity(): Case 2. Linked but no packet received.\n");
+
+ priv->bAdSwitchedChecking = false;
+ SwitchAntenna(dev);
+ }
+ // Case 3. Evaluate last antenna switch action and undo it if necessary.
+ else if(priv->bAdSwitchedChecking == true)
+ {
+ // printk("SwAntennaDiversity(): Case 3. Evaluate last antenna switch action.\n");
+
+ priv->bAdSwitchedChecking = false;
+
+ // Adjust Rx signal strength threashold.
+ priv->AdRxSsThreshold = (priv->AdRxSignalStrength + priv->AdRxSsBeforeSwitched) / 2;
+
+ priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ?
+ priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;
+ if(priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched)
+ { // Rx signal strength is not improved after we swtiched antenna. => Swich back.
+// printk("SwAntennaDiversity(): Rx Signal Strength is not improved, CurrRxSs: %d, LastRxSs: %d\n",
+// priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched);
+//by amy 080312
+ // Increase Antenna Diversity checking period due to bad decision.
+ priv->AdCheckPeriod *= 2;
+//by amy 080312
+ // Increase Antenna Diversity checking period.
+ if(priv->AdCheckPeriod > priv->AdMaxCheckPeriod)
+ priv->AdCheckPeriod = priv->AdMaxCheckPeriod;
+
+ // Wrong deceision => switch back.
+ SwitchAntenna(dev);
+ }
+ else
+ { // Rx Signal Strength is improved.
+// printk("SwAntennaDiversity(): Rx Signal Strength is improved, CurrRxSs: %d, LastRxSs: %d\n",
+// priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched);
+
+ // Reset Antenna Diversity checking period to its min value.
+ priv->AdCheckPeriod = priv->AdMinCheckPeriod;
+ }
+
+// printk("SwAntennaDiversity(): AdRxSsThreshold: %d, AdCheckPeriod: %d\n",
+// priv->AdRxSsThreshold, priv->AdCheckPeriod);
+ }
+ // Case 4. Evaluate if we shall switch antenna now.
+ // Cause Table Speed is very fast in TRC Dell Lab, we check it every time.
+ else// if(priv->AdTickCount >= priv->AdCheckPeriod)//-by amy 080312
+ {
+// printk("SwAntennaDiversity(): Case 4. Evaluate if we shall switch antenna now.\n");
+
+ priv->AdTickCount = 0;
+
+ //
+ // <Roger_Notes> We evaluate RxOk counts for each antenna first and than
+ // evaluate signal strength.
+ // The following operation can overcome the disability of CCA on both two antennas
+ // When signal strength was extremely low or high.
+ // 2008.01.30.
+ //
+
+ //
+ // Evaluate RxOk count from each antenna if we shall switch default antenna now.
+ // Added by Roger, 2008.02.21.
+//{by amy 080312
+ if((priv->AdMainAntennaRxOkCnt < priv->AdAuxAntennaRxOkCnt)
+ && (priv->CurrAntennaIndex == 0))
+ { // We set Main antenna as default but RxOk count was less than Aux ones.
+
+ // printk("SwAntennaDiversity(): Main antenna RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",
+ // priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt);
+
+ // Switch to Aux antenna.
+ SwitchAntenna(dev);
+ priv->bHWAdSwitched = true;
+ }
+ else if((priv->AdAuxAntennaRxOkCnt < priv->AdMainAntennaRxOkCnt)
+ && (priv->CurrAntennaIndex == 1))
+ { // We set Aux antenna as default but RxOk count was less than Main ones.
+
+ // printk("SwAntennaDiversity(): Aux antenna RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",
+ // priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt);
+
+ // Switch to Main antenna.
+ SwitchAntenna(dev);
+ priv->bHWAdSwitched = true;
+ }
+ else
+ {// Default antenna is better.
+
+ // printk("SwAntennaDiversity(): Default antenna is better., AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",
+ // priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt);
+
+ // Still need to check current signal strength.
+ priv->bHWAdSwitched = false;
+ }
+ //
+ // <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna
+ // didn't changed by HW evaluation.
+ // 2008.02.27.
+ //
+ // [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05
+ // For example, Throughput of aux is better than main antenna(about 10M v.s 2M),
+ // but AdRxSignalStrength is less than main.
+ // Our guess is that main antenna have lower throughput and get many change
+ // to receive more CCK packets(ex.Beacon) which have stronger SignalStrength.
+ //
+ if( (!priv->bHWAdSwitched) && (bSwCheckSS))
+ {
+//by amy 080312}
+ // Evaluate Rx signal strength if we shall switch antenna now.
+ if(priv->AdRxSignalStrength < priv->AdRxSsThreshold)
+ { // Rx signal strength is weak => Switch Antenna.
+// printk("SwAntennaDiversity(): Rx Signal Strength is weak, CurrRxSs: %d, RxSsThreshold: %d\n",
+// priv->AdRxSignalStrength, priv->AdRxSsThreshold);
+
+ priv->AdRxSsBeforeSwitched = priv->AdRxSignalStrength;
+ priv->bAdSwitchedChecking = true;
+
+ SwitchAntenna(dev);
+ }
+ else
+ { // Rx signal strength is OK.
+// printk("SwAntennaDiversity(): Rx Signal Strength is OK, CurrRxSs: %d, RxSsThreshold: %d\n",
+// priv->AdRxSignalStrength, priv->AdRxSsThreshold);
+
+ priv->bAdSwitchedChecking = false;
+ // Increase Rx signal strength threashold if necessary.
+ if( (priv->AdRxSignalStrength > (priv->AdRxSsThreshold + 10)) && // Signal is much stronger than current threshold
+ priv->AdRxSsThreshold <= priv->AdMaxRxSsThreshold) // Current threhold is not yet reach upper limit.
+ {
+ priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2;
+ priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ?
+ priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;//+by amy 080312
+ }
+
+ // Reduce Antenna Diversity checking period if possible.
+ if( priv->AdCheckPeriod > priv->AdMinCheckPeriod )
+ {
+ priv->AdCheckPeriod /= 2;
+ }
+ }
+ }
+ }
+//by amy 080312
+ // Reset antenna diversity Rx related statistics.
+ priv->AdRxOkCnt = 0;
+ priv->AdMainAntennaRxOkCnt = 0;
+ priv->AdAuxAntennaRxOkCnt = 0;
+//by amy 080312
+
+// priv->AdRxOkCnt = 0;//-by amy 080312
+
+// printk("-SwAntennaDiversity()\n");
+}
+
+//
+// Description:
+// Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise.
+//
+bool
+CheckTxPwrTracking( struct net_device *dev)
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+
+ if(!priv->bTxPowerTrack)
+ {
+ return false;
+ }
+
+//lzm reserved 080826
+ //if(priv->bScanInProgress)
+ //{
+ // return false;
+ //}
+
+ //if 87SE is in High Power , don't do Tx Power Tracking. asked by SD3 ED. 2008-08-08 Isaiah
+ if(priv->bToUpdateTxPwr)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+//
+// Description:
+// Timer callback function of SW Antenna Diversity.
+//
+void
+SwAntennaDiversityTimerCallback(
+ struct net_device *dev
+ )
+{
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ RT_RF_POWER_STATE rtState;
+
+ //printk("+SwAntennaDiversityTimerCallback()\n");
+
+ //
+ // We do NOT need to switch antenna while RF is off.
+ // 2007.05.09, added by Roger.
+ //
+ rtState = priv->eRFPowerState;
+ do{
+ if (rtState == eRfOff)
+ {
+// printk("SwAntennaDiversityTimer - RF is OFF.\n");
+ break;
+ }
+ else if (rtState == eRfSleep)
+ {
+ // Don't access BB/RF under Disable PLL situation.
+ //RT_TRACE((COMP_RF|COMP_ANTENNA), DBG_LOUD, ("SwAntennaDiversityTimerCallback(): RF is Sleep => skip it\n"));
+ break;
+ }
+ SwAntennaDiversity(dev);
+
+ }while(false);
+
+ if(priv->up)
+ {
+ priv->SwAntennaDiversityTimer.expires = jiffies + MSECS(ANTENNA_DIVERSITY_TIMER_PERIOD);
+ add_timer(&priv->SwAntennaDiversityTimer);
+ }
+
+ //printk("-SwAntennaDiversityTimerCallback()\n");
+}
+
diff --git a/drivers/staging/rtl8187se/r8180_dm.h b/drivers/staging/rtl8187se/r8180_dm.h new file mode 100644 index 0000000..3de92f0 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_dm.h @@ -0,0 +1,41 @@ +#ifndef R8180_DM_H
+#define R8180_DM_H
+
+#include "r8180.h"
+//#include "r8180_hw.h"
+//#include "r8180_93cx6.h"
+void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength);
+bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex);
+bool SwitchAntenna( struct net_device *dev);
+void SwAntennaDiversity(struct net_device *dev );
+void SwAntennaDiversityTimerCallback(struct net_device *dev);
+bool CheckDig(struct net_device *dev);
+bool CheckHighPower(struct net_device *dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void rtl8180_hw_dig_wq (struct work_struct *work);
+#else
+void rtl8180_hw_dig_wq(struct net_device *dev);
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
+void rtl8180_tx_pw_wq (struct work_struct *work);
+#else
+void rtl8180_tx_pw_wq(struct net_device *dev);
+#endif
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20)
+void rtl8180_rate_adapter(struct work_struct * work);
+
+#else
+void rtl8180_rate_adapter(struct net_device *dev);
+
+#endif
+void TxPwrTracking87SE(struct net_device *dev);
+bool CheckTxPwrTracking(struct net_device *dev);
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20)
+void rtl8180_rate_adapter(struct work_struct * work);
+#else
+void rtl8180_rate_adapter(struct net_device *dev);
+#endif
+void timer_rate_adaptive(unsigned long data);
+
+
+#endif
diff --git a/drivers/staging/rtl8187se/r8180_gct.c b/drivers/staging/rtl8187se/r8180_gct.c new file mode 100644 index 0000000..86cb427 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_gct.c @@ -0,0 +1,296 @@ +/* + This files contains GCT radio frontend programming routines. + + This is part of rtl8180 OpenSource driver + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official realtek driver + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + Code from Rtw8180 NetBSD driver by David Young has been really useful to + understand some things and gets some ideas + + Code from rtl8181 project has been useful to me to understand some things. + + Some code from 'Deuce' work + + We want to tanks the Authors of such projects and the Ndiswrapper + project Authors. +*/ + + +#include "r8180.h" +#include "r8180_hw.h" +#include "r8180_gct.h" + + +//#define DEBUG_GCT + +/* the following experiment are just experiments. + * this means if you enable them you can have every kind + * of result, included damage the RF chip, so don't + * touch them if you don't know what you are doing. + * In any case, if you do it, do at your own risk + */ + +//#define GCT_EXPERIMENT1 //improve RX sensivity + +//#define GCT_EXPERIMENT2 + +//#define GCT_EXPERIMENT3 //iprove a bit RX signal quality ? + +//#define GCT_EXPERIMENT4 //maybe solve some brokeness with experiment1 ? + +//#define GCT_EXPERIMENT5 + +//#define GCT_EXPERIMENT6 //not good + + +u32 gct_chan[] = { + 0x0, //dummy channel 0 + 0x0, //1 + 0x1, //2 + 0x2, //3 + 0x3, //4 + 0x4, //5 + 0x5, //6 + 0x6, //7 + 0x7, //8 + 0x8, //9 + 0x9, //10 + 0xa, //11 + 0xb, //12 + 0xc, //13 + 0xd, //14 +}; + +int gct_encode[16] = { + 0, 8, 4, 0xC, + 2, 0xA, 6, 0xE, + 1, 9, 5, 0xD, + 3, 0xB, 7, 0xF +}; + +void gct_rf_stabilize(struct net_device *dev) +{ + force_pci_posting(dev); + mdelay(3); //for now use a great value.. we may optimize in future +} + + +void write_gct(struct net_device *dev, u8 adr, u32 data) +{ +// struct r8180_priv *priv = ieee80211_priv(dev); + u32 phy_config; + + phy_config = gct_encode[(data & 0xf00) >> 8]; + phy_config |= gct_encode[(data & 0xf0) >> 4 ] << 4; + phy_config |= gct_encode[(data & 0xf) ] << 8; + phy_config |= gct_encode[(adr >> 1) & 0xf ] << 12; + phy_config |= (adr & 1 ) << 16; + phy_config |= gct_encode[(data & 0xf000)>>12] << 24; + + phy_config |= 0x90000000; // MAC will bang bits to the chip + + + write_nic_dword(dev,PHY_CONFIG,phy_config); +#ifdef DEBUG_GCT + DMESG("Writing GCT: %x (adr %x)",phy_config,adr); +#endif + gct_rf_stabilize(dev); +} + + + +void gct_write_phy_antenna(struct net_device *dev,short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u8 ant; + + ant = GCT_ANTENNA; + if(priv->antb) /*default antenna is antenna B */ + ant |= BB_ANTENNA_B; + if(ch == 14) + ant |= BB_ANTATTEN_CHAN14; + write_phy(dev,0x10,ant); + //DMESG("BB antenna %x ",ant); +} + + +void gct_rf_set_chan(struct net_device *dev, short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32 txpw = 0xff & priv->chtxpwr[ch]; + u32 chan = gct_chan[ch]; + + //write_phy(dev,3,txpw); +#ifdef DEBUG_GCT + DMESG("Gct set channel"); +#endif + /* set TX power */ + write_gct(dev,0x15,0); + write_gct(dev,6, txpw); + write_gct(dev,0x15, 0x10); + write_gct(dev,0x15,0); + + /*set frequency*/ + write_gct(dev,7, 0); + write_gct(dev,0xB, chan); + write_gct(dev,7, 0x1000); + +#ifdef DEBUG_GCT + DMESG("Gct set channel > write phy antenna"); +#endif + + + gct_write_phy_antenna(dev,ch); + +} + + +void gct_rf_close(struct net_device *dev) +{ + u32 anaparam; + + anaparam = read_nic_dword(dev,ANAPARAM); + anaparam &= 0x000fffff; + anaparam |= 0x3f900000; + rtl8180_set_anaparam(dev, anaparam); + + write_gct(dev, 0x7, 0); + write_gct(dev, 0x1f, 0x45); + write_gct(dev, 0x1f, 0x5); + write_gct(dev, 0x0, 0x8e4); +} + + +void gct_rf_init(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //u32 anaparam; + + + write_nic_byte(dev,PHY_DELAY,0x6); //this is general + write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general + + //DMESG("%x", read_nic_dword(dev,ANAPARAM)); + /* we should set anaparm here*/ + //rtl8180_set_anaparam(dev,anaparam); + + write_gct(dev,0x1f,0); + write_gct(dev,0x1f,0); + write_gct(dev,0x1f,0x40); + write_gct(dev,0x1f,0x60); + write_gct(dev,0x1f,0x61); + write_gct(dev,0x1f,0x61); + write_gct(dev,0x0,0xae4); + write_gct(dev,0x1f,0x1); + write_gct(dev,0x1f,0x41); + write_gct(dev,0x1f,0x61); + write_gct(dev,0x1,0x1a23); + write_gct(dev,0x2,0x4971); + write_gct(dev,0x3,0x41de); + write_gct(dev,0x4,0x2d80); +#ifdef GCT_EXPERIMENT1 + //write_gct(dev,0x5,0x6810); // from zydas driver. sens+ but quite slow + //write_gct(dev,0x5,0x681f); //good+ (somewhat stable, better sens, performance decent) + write_gct(dev,0x5,0x685f); //good performances, not sure sens is really so beeter + //write_gct(dev,0x5,0x687f); //good performances, maybe sens is not improved + //write_gct(dev,0x5,0x689f); //like above + //write_gct(dev,0x5,0x685e); //bad + //write_gct(dev,0x5,0x68ff); //good+ (somewhat stable, better sens(?), performance decent) + //write_gct(dev,0x5,0x68f0); //bad + //write_gct(dev,0x5,0x6cff); //sens+ but not so good + //write_gct(dev,0x5,0x6dff); //sens+,apparentely very good but broken + //write_gct(dev,0x5,0x65ff); //sens+,good + //write_gct(dev,0x5,0x78ff); //sens + but almost broken + //write_gct(dev,0x5,0x7810); //- //snes + but broken + //write_gct(dev,0x5,0x781f); //-- //sens + + //write_gct(dev,0x5,0x78f0); //low sens +#else + write_gct(dev,0x5,0x61ff); //best performance but weak sensitivity +#endif +#ifdef GCT_EXPERIMENT2 + write_gct(dev,0x6,0xe); +#else + write_gct(dev,0x6,0x0); +#endif + write_gct(dev,0x7,0x0); + write_gct(dev,0x8,0x7533); + write_gct(dev,0x9,0xc401); + write_gct(dev,0xa,0x0); + write_gct(dev,0xc,0x1c7); + write_gct(dev,0xd,0x29d3); + write_gct(dev,0xe,0x2e8); + write_gct(dev,0x10,0x192); +#ifdef GCT_EXPERIMENT3 + write_gct(dev,0x11,0x246); +#else + write_gct(dev,0x11,0x248); +#endif + write_gct(dev,0x12,0x0); + write_gct(dev,0x13,0x20c4); +#ifdef GCT_EXPERIMENT4 + write_gct(dev,0x14,0xf488); +#else + write_gct(dev,0x14,0xf4fc); +#endif +#ifdef GCT_EXPERIMENT5 + write_gct(dev,0x15,0xb152); +#else + write_gct(dev,0x15,0x0); +#endif +#ifdef GCT_EXPERIMENT6 + write_gct(dev,0x1e,0x1); +#endif + write_gct(dev,0x16,0x1500); + + write_gct(dev,0x7,0x1000); + /*write_gct(dev,0x15,0x0); + write_gct(dev,0x6,0x15); + write_gct(dev,0x15,0x8); + write_gct(dev,0x15,0x0); +*/ + write_phy(dev,0,0xa8); + +/* write_gct(dev,0x15,0x0); + write_gct(dev,0x6,0x12); + write_gct(dev,0x15,0x8); + write_gct(dev,0x15,0x0); +*/ + write_phy(dev,3,0x0); + write_phy(dev,4,0xc0); /* lna det*/ + write_phy(dev,5,0x90); + write_phy(dev,6,0x1e); + write_phy(dev,7,0x64); + +#ifdef DEBUG_GCT + DMESG("Gct init> write phy antenna"); +#endif + + gct_write_phy_antenna(dev,priv->chan); + + write_phy(dev,0x11,0x88); + if(!priv->diversity) + write_phy(dev,0x12,0xc0); + else + write_phy(dev,0x12,0x40); + + write_phy(dev,0x13,0x90 | priv->cs_treshold ); + + write_phy(dev,0x19,0x0); + write_phy(dev,0x1a,0xa0); + write_phy(dev,0x1b,0x44); + +#ifdef DEBUG_GCT + DMESG("Gct init > set channel2"); +#endif + + gct_rf_set_chan(dev,priv->chan); +} diff --git a/drivers/staging/rtl8187se/r8180_gct.h b/drivers/staging/rtl8187se/r8180_gct.h new file mode 100644 index 0000000..fe965ca --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_gct.h @@ -0,0 +1,25 @@ +/* + This is part of rtl8180 OpenSource driver - v 0.20 + Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the official realtek driver + Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of such projects and the Ndiswrapper project Authors. +*/ + +#define GCT_ANTENNA 0xA3 + + +// we use the untouched eeprom value- cross your finger ;-) +#define GCT_ANAPARAM_PWR1_ON ?? +#define GCT_ANAPARAM_PWR0_ON ?? + + + +void gct_rf_init(struct net_device *dev); +void gct_rf_set_chan(struct net_device *dev,short ch); + +void gct_rf_close(struct net_device *dev); diff --git a/drivers/staging/rtl8187se/r8180_hw.h b/drivers/staging/rtl8187se/r8180_hw.h new file mode 100644 index 0000000..bf38934 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_hw.h @@ -0,0 +1,956 @@ +/* + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official Realtek driver. + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon. + Parts of this driver are based on the Intel Pro Wireless + 2100 GPL driver. + + We want to tanks the Authors of those projects + and the Ndiswrapper project Authors. +*/ + +/* Mariusz Matuszek added full registers definition with Realtek's name */ + +/* this file contains register definitions for the rtl8180 MAC controller */ +#ifndef R8180_HW +#define R8180_HW + +#define CONFIG_RTL8185B //support for rtl8185B, xiong-2006-11-15 +#define CONFIG_RTL818X_S + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#define MAX_SLEEP_TIME (10000) +#define MIN_SLEEP_TIME (50) + +#define BB_ANTATTEN_CHAN14 0x0c +#define BB_ANTENNA_B 0x40 + +#define BB_HOST_BANG (1<<30) +#define BB_HOST_BANG_EN (1<<2) +#define BB_HOST_BANG_CLK (1<<1) +#define BB_HOST_BANG_DATA 1 + +#define ANAPARAM_TXDACOFF_SHIFT 27 +#define ANAPARAM_PWR0_MASK ((1<<30)|(1<<29)|(1<<28)) +#define ANAPARAM_PWR0_SHIFT 28 +#define ANAPARAM_PWR1_MASK ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)) +#define ANAPARAM_PWR1_SHIFT 20 + +#define MAC0 0 +#define MAC1 1 +#define MAC2 2 +#define MAC3 3 +#define MAC4 4 +#define MAC5 5 +#define CMD 0x37 +#define CMD_RST_SHIFT 4 +#define CMD_RESERVED_MASK ((1<<1) | (1<<5) | (1<<6) | (1<<7)) +#define CMD_RX_ENABLE_SHIFT 3 +#define CMD_TX_ENABLE_SHIFT 2 + +#define EPROM_CMD 0x50 +#define EPROM_CMD_RESERVED_MASK ((1<<5)|(1<<4)) +#define EPROM_CMD_OPERATING_MODE_SHIFT 6 +#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_NORMAL 0 +#define EPROM_CMD_LOAD 1 +#define EPROM_CMD_PROGRAM 2 +#define EPROM_CS_SHIFT 3 +#define EPROM_CK_SHIFT 2 +#define EPROM_W_SHIFT 1 +#define EPROM_R_SHIFT 0 +#define CONFIG2_DMA_POLLING_MODE_SHIFT 3 +#define INTA 0x3e +#define INTA_TXOVERFLOW (1<<15) +#define INTA_TIMEOUT (1<<14) +#define INTA_BEACONTIMEOUT (1<<13) +#define INTA_ATIM (1<<12) +#define INTA_BEACONDESCERR (1<<11) +#define INTA_BEACONDESCOK (1<<10) +#define INTA_HIPRIORITYDESCERR (1<<9) +#define INTA_HIPRIORITYDESCOK (1<<8) +#define INTA_NORMPRIORITYDESCERR (1<<7) +#define INTA_NORMPRIORITYDESCOK (1<<6) +#define INTA_RXOVERFLOW (1<<5) +#define INTA_RXDESCERR (1<<4) +#define INTA_LOWPRIORITYDESCERR (1<<3) +#define INTA_LOWPRIORITYDESCOK (1<<2) +#define INTA_RXCRCERR (1<<1) +#define INTA_RXOK (1) +#define INTA_MASK 0x3c +#define RXRING_ADDR 0xe4 // page 0 +#define PGSELECT 0x5e +#define PGSELECT_PG_SHIFT 0 +#define RX_CONF 0x44 +#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ +(1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) +#define RX_CHECK_BSSID_SHIFT 23 +#define ACCEPT_PWR_FRAME_SHIFT 22 +#define ACCEPT_MNG_FRAME_SHIFT 20 +#define ACCEPT_CTL_FRAME_SHIFT 19 +#define ACCEPT_DATA_FRAME_SHIFT 18 +#define ACCEPT_ICVERR_FRAME_SHIFT 12 +#define ACCEPT_CRCERR_FRAME_SHIFT 5 +#define ACCEPT_BCAST_FRAME_SHIFT 3 +#define ACCEPT_MCAST_FRAME_SHIFT 2 +#define ACCEPT_ALLMAC_FRAME_SHIFT 0 +#define ACCEPT_NICMAC_FRAME_SHIFT 1 +#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) +#define RX_FIFO_THRESHOLD_SHIFT 13 +#define RX_FIFO_THRESHOLD_128 3 +#define RX_FIFO_THRESHOLD_256 4 +#define RX_FIFO_THRESHOLD_512 5 +#define RX_FIFO_THRESHOLD_1024 6 +#define RX_FIFO_THRESHOLD_NONE 7 +#define RX_AUTORESETPHY_SHIFT 28 +#define EPROM_TYPE_SHIFT 6 +#define TX_CONF 0x40 +#define TX_CONF_HEADER_AUTOICREMENT_SHIFT 30 +#define TX_LOOPBACK_SHIFT 17 +#define TX_LOOPBACK_MAC 1 +#define TX_LOOPBACK_BASEBAND 2 +#define TX_LOOPBACK_NONE 0 +#define TX_LOOPBACK_CONTINUE 3 +#define TX_LOOPBACK_MASK ((1<<17)|(1<<18)) +#define TX_DPRETRY_SHIFT 0 +#define R8180_MAX_RETRY 255 +#define TX_RTSRETRY_SHIFT 8 +#define TX_NOICV_SHIFT 19 +#define TX_NOCRC_SHIFT 16 +#define TX_DMA_POLLING 0xd9 +#define TX_DMA_POLLING_BEACON_SHIFT 7 +#define TX_DMA_POLLING_HIPRIORITY_SHIFT 6 +#define TX_DMA_POLLING_NORMPRIORITY_SHIFT 5 +#define TX_DMA_POLLING_LOWPRIORITY_SHIFT 4 +#define TX_DMA_STOP_BEACON_SHIFT 3 +#define TX_DMA_STOP_HIPRIORITY_SHIFT 2 +#define TX_DMA_STOP_NORMPRIORITY_SHIFT 1 +#define TX_DMA_STOP_LOWPRIORITY_SHIFT 0 +#define TX_MANAGEPRIORITY_RING_ADDR 0x0C +#define TX_BKPRIORITY_RING_ADDR 0x10 +#define TX_BEPRIORITY_RING_ADDR 0x14 +#define TX_VIPRIORITY_RING_ADDR 0x20 +#define TX_VOPRIORITY_RING_ADDR 0x24 +#define TX_HIGHPRIORITY_RING_ADDR 0x28 +//AC_VI and Low priority share the sane queue +#define TX_LOWPRIORITY_RING_ADDR TX_VIPRIORITY_RING_ADDR +//AC_VO and Norm priority share the same queue +#define TX_NORMPRIORITY_RING_ADDR TX_VOPRIORITY_RING_ADDR + +#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) +#define MAX_RX_DMA_2048 7 +#define MAX_RX_DMA_1024 6 +#define MAX_RX_DMA_SHIFT 10 +#define INT_TIMEOUT 0x48 +#define CONFIG3_CLKRUN_SHIFT 2 +#define CONFIG3_ANAPARAM_W_SHIFT 6 +#define ANAPARAM 0x54 +#define BEACON_INTERVAL 0x70 +#define BEACON_INTERVAL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)| \ +(1<<6)|(1<<7)|(1<<8)|(1<<9)) +#define ATIM_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)| \ +(1<<8)|(1<<9)) +#define ATIM 0x72 +#define EPROM_CS_SHIFT 3 +#define EPROM_CK_SHIFT 2 +#define PHY_DELAY 0x78 +#define PHY_CONFIG 0x80 +#define PHY_ADR 0x7c +#define PHY_READ 0x7e +#define CARRIER_SENSE_COUNTER 0x79 //byte +#define SECURITY 0x5f //1209 this is sth wrong +#define SECURITY_WEP_TX_ENABLE_SHIFT 1 +#define SECURITY_WEP_RX_ENABLE_SHIFT 0 +#define SECURITY_ENCRYP_104 1 +#define SECURITY_ENCRYP_SHIFT 4 +#define SECURITY_ENCRYP_MASK ((1<<4)|(1<<5)) +#define KEY0 0x90 //1209 this is sth wrong +#define CONFIG2_ANTENNA_SHIFT 6 +#define TX_BEACON_RING_ADDR 0x4c +#define CONFIG0_WEP40_SHIFT 7 +#define CONFIG0_WEP104_SHIFT 6 +#define AGCRESET_SHIFT 5 + + + +/* + * Operational registers offsets in PCI (I/O) space. + * RealTek names are used. + */ + +#define IDR0 0x0000 +#define IDR1 0x0001 +#define IDR2 0x0002 +#define IDR3 0x0003 +#define IDR4 0x0004 +#define IDR5 0x0005 + +/* 0x0006 - 0x0007 - reserved */ + +#define MAR0 0x0008 +#define MAR1 0x0009 +#define MAR2 0x000A +#define MAR3 0x000B +#define MAR4 0x000C +#define MAR5 0x000D +#define MAR6 0x000E +#define MAR7 0x000F + +/* 0x0010 - 0x0017 - reserved */ + +#define TSFTR 0x0018 +#define TSFTR_END 0x001F + +#define TLPDA 0x0020 +#define TLPDA_END 0x0023 +#define TNPDA 0x0024 +#define TNPDA_END 0x0027 +#define THPDA 0x0028 +#define THPDA_END 0x002B + +#define BSSID 0x002E +#define BSSID_END 0x0033 + +#define CR 0x0037 + +#ifdef CONFIG_RTL8185B +#define RF_SW_CONFIG 0x8 // store data which is transmitted to RF for driver +#define RF_SW_CFG_SI BIT1 +#define PIFS 0x2C // PCF InterFrame Spacing Timer Setting. +#define EIFS 0x2D // Extended InterFrame Space Timer, in unit of 4 us. + +#define BRSR 0x34 // Basic rate set + +#define IMR 0x006C +#define ISR 0x003C +#else +#define BRSR 0x002C +#define BRSR_END 0x002D + +/* 0x0034 - 0x0034 - reserved */ +#define EIFS 0x0035 + +#define IMR 0x003C +#define IMR_END 0x003D +#define ISR 0x003E +#define ISR_END 0x003F +#endif + +#define TCR 0x0040 +#define TCR_END 0x0043 + +#define RCR 0x0044 +#define RCR_END 0x0047 + +#define TimerInt 0x0048 +#define TimerInt_END 0x004B + +#define TBDA 0x004C +#define TBDA_END 0x004F + +#define CR9346 0x0050 + +#define CONFIG0 0x0051 +#define CONFIG1 0x0052 +#define CONFIG2 0x0053 + +#define ANA_PARM 0x0054 +#define ANA_PARM_END 0x0x0057 + +#define MSR 0x0058 + +#define CONFIG3 0x0059 +#define CONFIG4 0x005A +#ifdef CONFIG_RTL8185B +#ifdef CONFIG_RTL818X_S + // SD3 szuyitasi: Mac0x57= CC -> B0 Mac0x60= D1 -> C6 + // Mac0x60 = 0x000004C6 power save parameters + #define ANAPARM_ASIC_ON 0xB0054D00 + #define ANAPARM2_ASIC_ON 0x000004C6 + + #define ANAPARM_ON ANAPARM_ASIC_ON + #define ANAPARM2_ON ANAPARM2_ASIC_ON +#else + // SD3 CMLin: + #define ANAPARM_ASIC_ON 0x45090658 + #define ANAPARM2_ASIC_ON 0x727f3f52 + + #define ANAPARM_ON ANAPARM_ASIC_ON + #define ANAPARM2_ON ANAPARM2_ASIC_ON +#endif +#endif + +#define TESTR 0x005B + +/* 0x005C - 0x005D - reserved */ + +#define PSR 0x005E + +/* 0x0060 - 0x006F - reserved */ + +#define BcnItv 0x0070 +#define BcnItv_END 0x0071 + +#define AtimWnd 0x0072 +#define AtimWnd_END 0x0073 + +#define BintrItv 0x0074 +#define BintrItv_END 0x0075 + +#define AtimtrItv 0x0076 +#define AtimtrItv_END 0x0077 + +#define PhyDelay 0x0078 + +#define CRCount 0x0079 + +/* 0x007A - 0x007B - reserved */ + +#define PhyAddr 0x007C +#define PhyDataW 0x007D +#define PhyDataR 0x007E + +#define PhyCFG 0x0080 +#define PhyCFG_END 0x0083 + +/* following are for rtl8185 */ +#define RFPinsOutput 0x80 +#define RFPinsEnable 0x82 +#define RF_TIMING 0x8c +#define RFPinsSelect 0x84 +#define ANAPARAM2 0x60 +#define RF_PARA 0x88 +#define RFPinsInput 0x86 +#define GP_ENABLE 0x90 +#define GPIO 0x91 +#define SW_CONTROL_GPIO 0x400 +#define TX_ANTENNA 0x9f +#define TX_GAIN_OFDM 0x9e +#define TX_GAIN_CCK 0x9d +#define WPA_CONFIG 0xb0 +#define TX_AGC_CTL 0x9c +#define TX_AGC_CTL_PERPACKET_GAIN_SHIFT 0 +#define TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT 1 +#define TX_AGC_CTL_FEEDBACK_ANT 2 +#define RESP_RATE 0x34 +#define SIFS 0xb4 +#define DIFS 0xb5 + +#define SLOT 0xb6 +#define CW_CONF 0xbc +#define CW_CONF_PERPACKET_RETRY_SHIFT 1 +#define CW_CONF_PERPACKET_CW_SHIFT 0 +#define CW_VAL 0xbd +#define MAX_RESP_RATE_SHIFT 4 +#define MIN_RESP_RATE_SHIFT 0 +#define RATE_FALLBACK 0xbe +/* + * 0x0084 - 0x00D3 is selected to page 1 when PSEn bit (bit0, PSR) + * is set to 1 + */ + +#define Wakeup0 0x0084 +#define Wakeup0_END 0x008B + +#define Wakeup1 0x008C +#define Wakeup1_END 0x0093 + +#define Wakeup2LD 0x0094 +#define Wakeup2LD_END 0x009B +#define Wakeup2HD 0x009C +#define Wakeup2HD_END 0x00A3 + +#define Wakeup3LD 0x00A4 +#define Wakeup3LD_END 0x00AB +#define Wakeup3HD 0x00AC +#define Wakeup3HD_END 0x00B3 + +#define Wakeup4LD 0x00B4 +#define Wakeup4LD_END 0x00BB +#define Wakeup4HD 0x00BC +#define Wakeup4HD_END 0x00C3 + +#define CRC0 0x00C4 +#define CRC0_END 0x00C5 +#define CRC1 0x00C6 +#define CRC1_END 0x00C7 +#define CRC2 0x00C8 +#define CRC2_END 0x00C9 +#define CRC3 0x00CA +#define CRC3_END 0x00CB +#define CRC4 0x00CC +#define CRC4_END 0x00CD + +/* 0x00CE - 0x00D3 - reserved */ + + + +/* + * 0x0084 - 0x00D3 is selected to page 0 when PSEn bit (bit0, PSR) + * is set to 0 + */ + +/* 0x0084 - 0x008F - reserved */ + +#define DK0 0x0090 +#define DK0_END 0x009F +#define DK1 0x00A0 +#define DK1_END 0x00AF +#define DK2 0x00B0 +#define DK2_END 0x00BF +#define DK3 0x00C0 +#define DK3_END 0x00CF + +/* 0x00D0 - 0x00D3 - reserved */ + + + + + +/* 0x00D4 - 0x00D7 - reserved */ + +#define CONFIG5 0x00D8 + +#define TPPoll 0x00D9 + +/* 0x00DA - 0x00DB - reserved */ + +#ifdef CONFIG_RTL818X_S +#define PHYPR 0xDA //0xDA - 0x0B PHY Parameter Register. +#endif + +#define CWR 0x00DC +#define CWR_END 0x00DD + +#define RetryCTR 0x00DE + +/* 0x00DF - 0x00E3 - reserved */ + +#define RDSAR 0x00E4 +#define RDSAR_END 0x00E7 + +/* 0x00E8 - 0x00EF - reserved */ +#ifdef CONFIG_RTL818X_S +#define LED_CONTROL 0xED +#endif + +#define FER 0x00F0 +#define FER_END 0x00F3 + +#ifdef CONFIG_RTL8185B +#define FEMR 0x1D4 // Function Event Mask register +#else +#define FEMR 0x00F4 +#define FEMR_END 0x00F7 +#endif + +#define FPSR 0x00F8 +#define FPSR_END 0x00FB + +#define FFER 0x00FC +#define FFER_END 0x00FF + + + +/* + * Bitmasks for specific register functions. + * Names are derived from the register name and function name. + * + * <REGISTER>_<FUNCTION>[<bit>] + * + * this leads to some awkward names... + */ + +#define BRSR_BPLCP ((1<< 8)) +#define BRSR_MBR ((1<< 1)|(1<< 0)) +#define BRSR_MBR_8185 ((1<< 11)|(1<< 10)|(1<< 9)|(1<< 8)|(1<< 7)|(1<< 6)|(1<< 5)|(1<< 4)|(1<< 3)|(1<< 2)|(1<< 1)|(1<< 0)) +#define BRSR_MBR0 ((1<< 0)) +#define BRSR_MBR1 ((1<< 1)) + +#define CR_RST ((1<< 4)) +#define CR_RE ((1<< 3)) +#define CR_TE ((1<< 2)) +#define CR_MulRW ((1<< 0)) + +#ifdef CONFIG_RTL8185B +#define IMR_Dot11hInt ((1<< 25)) // 802.11h Measurement Interrupt +#define IMR_BcnDmaInt ((1<< 24)) // Beacon DMA Interrupt // What differenct between BcnDmaInt and BcnInt??? +#define IMR_WakeInt ((1<< 23)) // Wake Up Interrupt +#define IMR_TXFOVW ((1<< 22)) // Tx FIFO Overflow Interrupt +#define IMR_TimeOut1 ((1<< 21)) // Time Out Interrupt 1 +#define IMR_BcnInt ((1<< 20)) // Beacon Time out Interrupt +#define IMR_ATIMInt ((1<< 19)) // ATIM Time Out Interrupt +#define IMR_TBDER ((1<< 18)) // Tx Beacon Descriptor Error Interrupt +#define IMR_TBDOK ((1<< 17)) // Tx Beacon Descriptor OK Interrupt +#define IMR_THPDER ((1<< 16)) // Tx High Priority Descriptor Error Interrupt +#define IMR_THPDOK ((1<< 15)) // Tx High Priority Descriptor OK Interrupt +#define IMR_TVODER ((1<< 14)) // Tx AC_VO Descriptor Error Interrupt +#define IMR_TVODOK ((1<< 13)) // Tx AC_VO Descriptor OK Interrupt +#define IMR_FOVW ((1<< 12)) // Rx FIFO Overflow Interrupt +#define IMR_RDU ((1<< 11)) // Rx Descriptor Unavailable Interrupt +#define IMR_TVIDER ((1<< 10)) // Tx AC_VI Descriptor Error Interrupt +#define IMR_TVIDOK ((1<< 9)) // Tx AC_VI Descriptor OK Interrupt +#define IMR_RER ((1<< 8)) // Rx Error Interrupt +#define IMR_ROK ((1<< 7)) // Receive OK Interrupt +#define IMR_TBEDER ((1<< 6)) // Tx AC_BE Descriptor Error Interrupt +#define IMR_TBEDOK ((1<< 5)) // Tx AC_BE Descriptor OK Interrupt +#define IMR_TBKDER ((1<< 4)) // Tx AC_BK Descriptor Error Interrupt +#define IMR_TBKDOK ((1<< 3)) // Tx AC_BK Descriptor OK Interrupt +#define IMR_RQoSOK ((1<< 2)) // Rx QoS OK Interrupt +#define IMR_TimeOut2 ((1<< 1)) // Time Out Interrupt 2 +#define IMR_TimeOut3 ((1<< 0)) // Time Out Interrupt 3 +#define IMR_TMGDOK ((1<<30)) +#define ISR_Dot11hInt ((1<< 25)) // 802.11h Measurement Interrupt +#define ISR_BcnDmaInt ((1<< 24)) // Beacon DMA Interrupt // What differenct between BcnDmaInt and BcnInt??? +#define ISR_WakeInt ((1<< 23)) // Wake Up Interrupt +#define ISR_TXFOVW ((1<< 22)) // Tx FIFO Overflow Interrupt +#define ISR_TimeOut1 ((1<< 21)) // Time Out Interrupt 1 +#define ISR_BcnInt ((1<< 20)) // Beacon Time out Interrupt +#define ISR_ATIMInt ((1<< 19)) // ATIM Time Out Interrupt +#define ISR_TBDER ((1<< 18)) // Tx Beacon Descriptor Error Interrupt +#define ISR_TBDOK ((1<< 17)) // Tx Beacon Descriptor OK Interrupt +#define ISR_THPDER ((1<< 16)) // Tx High Priority Descriptor Error Interrupt +#define ISR_THPDOK ((1<< 15)) // Tx High Priority Descriptor OK Interrupt +#define ISR_TVODER ((1<< 14)) // Tx AC_VO Descriptor Error Interrupt +#define ISR_TVODOK ((1<< 13)) // Tx AC_VO Descriptor OK Interrupt +#define ISR_FOVW ((1<< 12)) // Rx FIFO Overflow Interrupt +#define ISR_RDU ((1<< 11)) // Rx Descriptor Unavailable Interrupt +#define ISR_TVIDER ((1<< 10)) // Tx AC_VI Descriptor Error Interrupt +#define ISR_TVIDOK ((1<< 9)) // Tx AC_VI Descriptor OK Interrupt +#define ISR_RER ((1<< 8)) // Rx Error Interrupt +#define ISR_ROK ((1<< 7)) // Receive OK Interrupt +#define ISR_TBEDER ((1<< 6)) // Tx AC_BE Descriptor Error Interrupt +#define ISR_TBEDOK ((1<< 5)) // Tx AC_BE Descriptor OK Interrupt +#define ISR_TBKDER ((1<< 4)) // Tx AC_BK Descriptor Error Interrupt +#define ISR_TBKDOK ((1<< 3)) // Tx AC_BK Descriptor OK Interrupt +#define ISR_RQoSOK ((1<< 2)) // Rx QoS OK Interrupt +#define ISR_TimeOut2 ((1<< 1)) // Time Out Interrupt 2 +#define ISR_TimeOut3 ((1<< 0)) // Time Out Interrupt 3 + +//these definition is used for Tx/Rx test temporarily +#define ISR_TLPDER ISR_TVIDER +#define ISR_TLPDOK ISR_TVIDOK +#define ISR_TNPDER ISR_TVODER +#define ISR_TNPDOK ISR_TVODOK +#define ISR_TimeOut ISR_TimeOut1 +#define ISR_RXFOVW ISR_FOVW + +#else +#define IMR_TXFOVW ((1<<15)) +#define IMR_TimeOut ((1<<14)) +#define IMR_BcnInt ((1<<13)) +#define IMR_ATIMInt ((1<<12)) +#define IMR_TBDER ((1<<11)) +#define IMR_TBDOK ((1<<10)) +#define IMR_THPDER ((1<< 9)) +#define IMR_THPDOK ((1<< 8)) +#define IMR_TNPDER ((1<< 7)) +#define IMR_TNPDOK ((1<< 6)) +#define IMR_RXFOVW ((1<< 5)) +#define IMR_RDU ((1<< 4)) +#define IMR_TLPDER ((1<< 3)) +#define IMR_TLPDOK ((1<< 2)) +#define IMR_RER ((1<< 1)) +#define IMR_ROK ((1<< 0)) + +#define ISR_TXFOVW ((1<<15)) +#define ISR_TimeOut ((1<<14)) +#define ISR_BcnInt ((1<<13)) +#define ISR_ATIMInt ((1<<12)) +#define ISR_TBDER ((1<<11)) +#define ISR_TBDOK ((1<<10)) +#define ISR_THPDER ((1<< 9)) +#define ISR_THPDOK ((1<< 8)) +#define ISR_TNPDER ((1<< 7)) +#define ISR_TNPDOK ((1<< 6)) +#define ISR_RXFOVW ((1<< 5)) +#define ISR_RDU ((1<< 4)) +#define ISR_TLPDER ((1<< 3)) +#define ISR_TLPDOK ((1<< 2)) +#define ISR_RER ((1<< 1)) +#define ISR_ROK ((1<< 0)) +#endif + +#define HW_VERID_R8180_F 3 +#define HW_VERID_R8180_ABCD 2 +#define HW_VERID_R8185_ABC 4 +#define HW_VERID_R8185_D 5 +#ifdef CONFIG_RTL8185B +#define HW_VERID_R8185B_B 6 +#endif + +#define TCR_CWMIN ((1<<31)) +#define TCR_SWSEQ ((1<<30)) +#define TCR_HWVERID_MASK ((1<<27)|(1<<26)|(1<<25)) +#define TCR_HWVERID_SHIFT 25 +#define TCR_SAT ((1<<24)) +#define TCR_PLCP_LEN TCR_SAT // rtl8180 +#define TCR_MXDMA_MASK ((1<<23)|(1<<22)|(1<<21)) +#define TCR_MXDMA_1024 6 +#define TCR_MXDMA_2048 7 +#define TCR_MXDMA_SHIFT 21 +#define TCR_DISCW ((1<<20)) +#define TCR_ICV ((1<<19)) +#define TCR_LBK ((1<<18)|(1<<17)) +#define TCR_LBK1 ((1<<18)) +#define TCR_LBK0 ((1<<17)) +#define TCR_CRC ((1<<16)) +#define TCR_DPRETRY_MASK ((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define TCR_RTSRETRY_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)) +#define TCR_PROBE_NOTIMESTAMP_SHIFT 29 //rtl8185 + +#define RCR_ONLYERLPKT ((1<<31)) +#define RCR_CS_SHIFT 29 +#define RCR_CS_MASK ((1<<30) | (1<<29)) +#define RCR_ENMARP ((1<<28)) +#define RCR_CBSSID ((1<<23)) +#define RCR_APWRMGT ((1<<22)) +#define RCR_ADD3 ((1<<21)) +#define RCR_AMF ((1<<20)) +#define RCR_ACF ((1<<19)) +#define RCR_ADF ((1<<18)) +#define RCR_RXFTH ((1<<15)|(1<<14)|(1<<13)) +#define RCR_RXFTH2 ((1<<15)) +#define RCR_RXFTH1 ((1<<14)) +#define RCR_RXFTH0 ((1<<13)) +#define RCR_AICV ((1<<12)) +#define RCR_MXDMA ((1<<10)|(1<< 9)|(1<< 8)) +#define RCR_MXDMA2 ((1<<10)) +#define RCR_MXDMA1 ((1<< 9)) +#define RCR_MXDMA0 ((1<< 8)) +#define RCR_9356SEL ((1<< 6)) +#define RCR_ACRC32 ((1<< 5)) +#define RCR_AB ((1<< 3)) +#define RCR_AM ((1<< 2)) +#define RCR_APM ((1<< 1)) +#define RCR_AAP ((1<< 0)) + +#define CR9346_EEM ((1<<7)|(1<<6)) +#define CR9346_EEM1 ((1<<7)) +#define CR9346_EEM0 ((1<<6)) +#define CR9346_EECS ((1<<3)) +#define CR9346_EESK ((1<<2)) +#define CR9346_EED1 ((1<<1)) +#define CR9346_EED0 ((1<<0)) + +#define CONFIG0_WEP104 ((1<<6)) +#define CONFIG0_LEDGPO_En ((1<<4)) +#define CONFIG0_Aux_Status ((1<<3)) +#define CONFIG0_GL ((1<<1)|(1<<0)) +#define CONFIG0_GL1 ((1<<1)) +#define CONFIG0_GL0 ((1<<0)) + +#define CONFIG1_LEDS ((1<<7)|(1<<6)) +#define CONFIG1_LEDS1 ((1<<7)) +#define CONFIG1_LEDS0 ((1<<6)) +#define CONFIG1_LWACT ((1<<4)) +#define CONFIG1_MEMMAP ((1<<3)) +#define CONFIG1_IOMAP ((1<<2)) +#define CONFIG1_VPD ((1<<1)) +#define CONFIG1_PMEn ((1<<0)) + +#define CONFIG2_LCK ((1<<7)) +#define CONFIG2_ANT ((1<<6)) +#define CONFIG2_DPS ((1<<3)) +#define CONFIG2_PAPE_sign ((1<<2)) +#define CONFIG2_PAPE_time ((1<<1)|(1<<0)) +#define CONFIG2_PAPE_time1 ((1<<1)) +#define CONFIG2_PAPE_time0 ((1<<0)) + +#define CONFIG3_GNTSel ((1<<7)) +#define CONFIG3_PARM_En ((1<<6)) +#define CONFIG3_Magic ((1<<5)) +#define CONFIG3_CardB_En ((1<<3)) +#define CONFIG3_CLKRUN_En ((1<<2)) +#define CONFIG3_FuncRegEn ((1<<1)) +#define CONFIG3_FBtbEn ((1<<0)) + +#define CONFIG4_VCOPDN ((1<<7)) +#define CONFIG4_PWROFF ((1<<6)) +#define CONFIG4_PWRMGT ((1<<5)) +#define CONFIG4_LWPME ((1<<4)) +#define CONFIG4_LWPTN ((1<<2)) +#define CONFIG4_RFTYPE ((1<<1)|(1<<0)) +#define CONFIG4_RFTYPE1 ((1<<1)) +#define CONFIG4_RFTYPE0 ((1<<0)) + +#define CONFIG5_TX_FIFO_OK ((1<<7)) +#define CONFIG5_RX_FIFO_OK ((1<<6)) +#define CONFIG5_CALON ((1<<5)) +#define CONFIG5_EACPI ((1<<2)) +#define CONFIG5_LANWake ((1<<1)) +#define CONFIG5_PME_STS ((1<<0)) + +#define MSR_LINK_MASK ((1<<2)|(1<<3)) +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 2 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 + +#define PSR_GPO ((1<<7)) +#define PSR_GPI ((1<<6)) +#define PSR_LEDGPO1 ((1<<5)) +#define PSR_LEDGPO0 ((1<<4)) +#define PSR_UWF ((1<<1)) +#define PSR_PSEn ((1<<0)) + +#define SCR_KM ((1<<5)|(1<<4)) +#define SCR_KM1 ((1<<5)) +#define SCR_KM0 ((1<<4)) +#define SCR_TXSECON ((1<<1)) +#define SCR_RXSECON ((1<<0)) + +#define BcnItv_BcnItv (0x01FF) + +#define AtimWnd_AtimWnd (0x01FF) + +#define BintrItv_BintrItv (0x01FF) + +#define AtimtrItv_AtimtrItv (0x01FF) + +#define PhyDelay_PhyDelay ((1<<2)|(1<<1)|(1<<0)) + +#define TPPoll_BQ ((1<<7)) +#define TPPoll_HPQ ((1<<6)) +#define TPPoll_NPQ ((1<<5)) +#define TPPoll_LPQ ((1<<4)) +#define TPPoll_SBQ ((1<<3)) +#define TPPoll_SHPQ ((1<<2)) +#define TPPoll_SNPQ ((1<<1)) +#define TPPoll_SLPQ ((1<<0)) + +#define CWR_CW (0x01FF) + +#define FER_INTR ((1<<15)) +#define FER_GWAKE ((1<< 4)) + +#define FEMR_INTR ((1<<15)) +#define FEMR_WKUP ((1<<14)) +#define FEMR_GWAKE ((1<< 4)) + +#define FPSR_INTR ((1<<15)) +#define FPSR_GWAKE ((1<< 4)) + +#define FFER_INTR ((1<<15)) +#define FFER_GWAKE ((1<< 4)) + +#ifdef CONFIG_RTL8185B +// Three wire mode. +#define SW_THREE_WIRE 0 +#define HW_THREE_WIRE 2 +//RTL8187S by amy +#define HW_THREE_WIRE_PI 5 +#define HW_THREE_WIRE_SI 6 +//by amy +#define TCR_LRL_OFFSET 0 +#define TCR_SRL_OFFSET 8 +#define TCR_MXDMA_OFFSET 21 +#define TCR_DISReqQsize_OFFSET 28 +#define TCR_DurProcMode_OFFSET 30 + +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + +#define TMGDS 0x0C // Tx Management Descriptor Address +#define TBKDS 0x10 // Tx AC_BK Descriptor Address +#define TBEDS 0x14 // Tx AC_BE Descriptor Address +#define TLPDS 0x20 // Tx AC_VI Descriptor Address +#define TNPDS 0x24 // Tx AC_VO Descriptor Address +#define THPDS 0x28 // Tx Hign Priority Descriptor Address + +#define TBDS 0x4c // Beacon descriptor queue start address + +#define RDSA 0xE4 // Receive descriptor queue start address + +#define AckTimeOutReg 0x79 // ACK timeout register, in unit of 4 us. + +#define RFTiming 0x8C + +#define TPPollStop 0x93 + +#define TXAGC_CTL 0x9C // <RJ_TODO_8185B> TX_AGC_CONTROL (0x9C seems be removed at 8185B, see p37). +#define CCK_TXAGC 0x9D +#define OFDM_TXAGC 0x9E +#define ANTSEL 0x9F + +#define ACM_CONTROL 0x00BF // ACM Control Registe + +#define RTL8185B_VER_REG 0xE1 + +#define IntMig 0xE2 // Interrupt Migration (0xE2 ~ 0xE3) + +#define TID_AC_MAP 0xE8 // TID to AC Mapping Register + +#define ANAPARAM3 0xEE // <RJ_TODO_8185B> How to use it? + +#define AC_VO_PARAM 0xF0 // AC_VO Parameters Record +#define AC_VI_PARAM 0xF4 // AC_VI Parameters Record +#define AC_BE_PARAM 0xF8 // AC_BE Parameters Record +#define AC_BK_PARAM 0xFC // AC_BK Parameters Record + +#ifdef CONFIG_RTL818X_S +#define BcnTimingAdjust 0x16A // Beacon Timing Adjust Register. +#define GPIOCtrl 0x16B // GPIO Control Register. +#define PSByGC 0x180 // 0x180 - 0x183 Power Saving by Gated Clock. +#endif +#define ARFR 0x1E0 // Auto Rate Fallback Register (0x1e0 ~ 0x1e2) + +#define RFSW_CTRL 0x272 // 0x272-0x273. +#define SW_3W_DB0 0x274 // Software 3-wire data buffer bit 31~0. +#define SW_3W_DB1 0x278 // Software 3-wire data buffer bit 63~32. +#define SW_3W_CMD0 0x27C // Software 3-wire Control/Status Register. +#define SW_3W_CMD1 0x27D // Software 3-wire Control/Status Register. + +#ifdef CONFIG_RTL818X_S +#define PI_DATA_READ 0X360 // 0x360 - 0x361 Parallel Interface Data Register. +#define SI_DATA_READ 0x362 // 0x362 - 0x363 Serial Interface Data Register. +#endif + +//---------------------------------------------------------------------------- +// 8185B TPPoll bits (offset 0xd9, 1 byte) +//---------------------------------------------------------------------------- +#define TPPOLL_BQ (0x01 << 7) +#define TPPOLL_HPQ (0x01 << 6) +#define TPPOLL_AC_VOQ (0x01 << 5) +#define TPPOLL_AC_VIQ (0x01 << 4) +#define TPPOLL_AC_BEQ (0x01 << 3) +#define TPPOLL_AC_BKQ (0x01 << 2) +#define TPPOLL_AC_MGQ (0x01 << 1) + +//---------------------------------------------------------------------------- +// 8185B TPPollStop bits (offset 0x93, 1 byte) +//---------------------------------------------------------------------------- +#define TPPOLLSTOP_BQ (0x01 << 7) +#define TPPOLLSTOP_HPQ (0x01 << 6) +#define TPPOLLSTOP_AC_VOQ (0x01 << 5) +#define TPPOLLSTOP_AC_VIQ (0x01 << 4) +#define TPPOLLSTOP_AC_BEQ (0x01 << 3) +#define TPPOLLSTOP_AC_BKQ (0x01 << 2) +#define TPPOLLSTOP_AC_MGQ (0x01 << 1) + + +#define MSR_LINK_ENEDCA (1<<4) + +//---------------------------------------------------------------------------- +// 8187B AC_XX_PARAM bits +//---------------------------------------------------------------------------- +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +//---------------------------------------------------------------------------- +// 8187B ACM_CONTROL bits (Offset 0xBF, 1 Byte) +//---------------------------------------------------------------------------- +#define VOQ_ACM_EN (0x01 << 7) //BIT7 +#define VIQ_ACM_EN (0x01 << 6) //BIT6 +#define BEQ_ACM_EN (0x01 << 5) //BIT5 +#define ACM_HW_EN (0x01 << 4) //BIT4 +#define TXOPSEL (0x01 << 3) //BIT3 +#define VOQ_ACM_CTL (0x01 << 2) //BIT2 // Set to 1 when AC_VO used time reaches or exceeds the admitted time +#define VIQ_ACM_CTL (0x01 << 1) //BIT1 // Set to 1 when AC_VI used time reaches or exceeds the admitted time +#define BEQ_ACM_CTL (0x01 << 0) //BIT0 // Set to 1 when AC_BE used time reaches or exceeds the admitted time + + +//---------------------------------------------------------------------------- +// 8185B SW_3W_CMD bits (Offset 0x27C-0x27D, 16bit) +//---------------------------------------------------------------------------- +#define SW_3W_CMD0_HOLD ((1<< 7)) +#define SW_3W_CMD1_RE ((1<< 0)) // BIT8 +#define SW_3W_CMD1_WE ((1<< 1)) // BIT9 +#define SW_3W_CMD1_DONE ((1<< 2)) // BIT10 + +#define BB_HOST_BANG_RW (1<<3) + +//---------------------------------------------------------------------------- +// 8185B RATE_FALLBACK_CTL bits (Offset 0xBE, 8bit) +//---------------------------------------------------------------------------- +#define RATE_FALLBACK_CTL_ENABLE ((1<< 7)) +#define RATE_FALLBACK_CTL_ENABLE_RTSCTS ((1<< 6)) +// Auto rate fallback per 2^n retry. +#define RATE_FALLBACK_CTL_AUTO_STEP0 0x00 +#define RATE_FALLBACK_CTL_AUTO_STEP1 0x01 +#define RATE_FALLBACK_CTL_AUTO_STEP2 0x02 +#define RATE_FALLBACK_CTL_AUTO_STEP3 0x03 + + +#define RTL8225z2_ANAPARAM_OFF 0x55480658 +#define RTL8225z2_ANAPARAM2_OFF 0x72003f70 +//by amy for power save +#define RF_CHANGE_BY_SW BIT31 +#define RF_CHANGE_BY_HW BIT30 +#define RF_CHANGE_BY_PS BIT29 +#define RF_CHANGE_BY_IPS BIT28 +//by amy for power save +//by amy for antenna +#define EEPROM_SW_REVD_OFFSET 0x3f +// BIT[8-9] is for SW Antenna Diversity. Only the value EEPROM_SW_AD_ENABLE means enable, other values are diable. +#define EEPROM_SW_AD_MASK 0x0300 +#define EEPROM_SW_AD_ENABLE 0x0100 + +// BIT[10-11] determine if Antenna 1 is the Default Antenna. Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE. +#define EEPROM_DEF_ANT_MASK 0x0C00 +#define EEPROM_DEF_ANT_1 0x0400 +//by amy for antenna +//{by amy 080312 +//0x7C, 0x7D Crystal calibration and Tx Power tracking mechanism. Added by Roger. 2007.12.10. +#define EEPROM_RSV 0x7C +#define EEPROM_XTAL_CAL_MASK 0x00FF // 0x7C[7:0], Crystal calibration mask. +#define EEPROM_XTAL_CAL_XOUT_MASK 0x0F // 0x7C[3:0], Crystal calibration for Xout. +#define EEPROM_XTAL_CAL_XIN_MASK 0xF0 // 0x7C[7:4], Crystal calibration for Xin. +#define EEPROM_THERMAL_METER_MASK 0x0F00 // 0x7D[3:0], Thermal meter reference level. +#define EEPROM_XTAL_CAL_ENABLE 0x1000 // 0x7D[4], Crystal calibration enabled/disabled BIT. +#define EEPROM_THERMAL_METER_ENABLE 0x2000 // 0x7D[5], Thermal meter enabled/disabled BIT. +#define EEPROM_CID_RSVD1 0x3F +#define EN_LPF_CAL 0x238 // Enable LPF Calibration. +#define PWR_METER_EN BIT1 +// <RJ_TODO_8185B> where are false alarm counters in 8185B? +#define CCK_FALSE_ALARM 0xD0 +#define OFDM_FALSE_ALARM 0xD2 +//by amy 080312} + +//YJ,add for Country IE, 080630 +#define EEPROM_COUNTRY_CODE 0x2E +//YJ,add,080630,end +#endif + +#endif diff --git a/drivers/staging/rtl8187se/r8180_max2820.c b/drivers/staging/rtl8187se/r8180_max2820.c new file mode 100644 index 0000000..cea0846 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_max2820.c @@ -0,0 +1,240 @@ +/* + This files contains MAXIM MAX2820 radio frontend programming routines. + + This is part of rtl8180 OpenSource driver + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official realtek driver + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + NetBSD rtl8180 driver from Dave Young has been really useful to + understand how to program the MAXIM radio. Thanks a lot!!! + + 'The Deuce' tested this and fixed some bugs. + + Code from rtl8181 project has been useful to me to understand some things. + + We want to tanks the Authors of such projects and the Ndiswrapper + project Authors. +*/ + + +#include "r8180.h" +#include "r8180_hw.h" +#include "r8180_max2820.h" + + +//#define DEBUG_MAXIM + +u32 maxim_chan[] = { + 0, //dummy channel 0 + 12, //1 + 17, //2 + 22, //3 + 27, //4 + 32, //5 + 37, //6 + 42, //7 + 47, //8 + 52, //9 + 57, //10 + 62, //11 + 67, //12 + 72, //13 + 84, //14 +}; + +#if 0 +/* maxim expects 4 bit address MSF, then 12 bit data MSF*/ +void write_maxim(struct net_device *dev,u8 adr, u32 data) +{ + + int shift; + short bit; + u16 word; + + adr = adr &0xf; + word = (u16)data & 0xfff; + word |= (adr<<12); + /*write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | BB_HOST_BANG_EN); + read_nic_dword(dev,PHY_CONFIG); + mdelay(1); + + write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | BB_HOST_BANG_EN | BB_HOST_BANG_CLK); + read_nic_dword(dev,PHY_CONFIG); + mdelay(1); + */ + + /* MAX2820 will sample data on rising edge of clock */ + for(shift = 15;shift >=0; shift--){ + bit = word>>shift & 1; + + write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA)); + + read_nic_dword(dev,PHY_CONFIG); + mdelay(2); + + write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | + (bit<<BB_HOST_BANG_DATA) | BB_HOST_BANG_CLK); /* sample data */ + + read_nic_dword(dev,PHY_CONFIG); + mdelay(1); + + write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | + (bit<<BB_HOST_BANG_DATA)); + + read_nic_dword(dev,PHY_CONFIG); + mdelay(2); + + } + write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA)| + BB_HOST_BANG_EN); + read_nic_dword(dev,PHY_CONFIG); + mdelay(2); + + /* The shift register fill flush to the requested register the + * last 12 bits data shifted in + */ + write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA)| + BB_HOST_BANG_EN | BB_HOST_BANG_CLK); + read_nic_dword(dev,PHY_CONFIG); + mdelay(2); + + write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<<BB_HOST_BANG_DATA)| + BB_HOST_BANG_EN); + read_nic_dword(dev,PHY_CONFIG); + mdelay(2); + + +#ifdef DEBUG_MAXIM + DMESG("Writing maxim: %x (adr %x)",phy_config,adr); +#endif + +} +#endif + +void write_maxim(struct net_device *dev,u8 adr, u32 data) { + u32 temp; + temp = 0x90 + (data & 0xf); + temp <<= 16; + temp += adr; + temp <<= 8; + temp += (data >> 4) & 0xff; +#ifdef DEBUG_MAXIM + DMESG("write_maxim: %08x", temp); +#endif + write_nic_dword(dev, PHY_CONFIG, temp); + force_pci_posting(dev); + mdelay(1); +} + + +void maxim_write_phy_antenna(struct net_device *dev,short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u8 ant; + + ant = MAXIM_ANTENNA; + if(priv->antb) /*default antenna is antenna B */ + ant |= BB_ANTENNA_B; + if(ch == 14) + ant |= BB_ANTATTEN_CHAN14; + write_phy(dev,0x10,ant); + //DMESG("BB antenna %x ",ant); +} + + +void maxim_rf_set_chan(struct net_device *dev, short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32 txpw = 0xff & priv->chtxpwr[ch]; + u32 chan = maxim_chan[ch]; + + /*While philips SA2400 drive the PA bias + *seems that for MAXIM we delegate this + *to the BB + */ + + //write_maxim(dev,5,txpw); + write_phy(dev,3,txpw); + + maxim_write_phy_antenna(dev,ch); + write_maxim(dev,3,chan); +} + + +void maxim_rf_close(struct net_device *dev) +{ + write_phy(dev, 3, 0x8); + write_maxim(dev, 1, 0); +} + + +void maxim_rf_init(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32 anaparam; + + write_nic_byte(dev,PHY_DELAY,0x6); //this is general + write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general + + /*these are maxim specific*/ + anaparam = read_nic_dword(dev,ANAPARAM); + anaparam = anaparam &~ (ANAPARAM_TXDACOFF_SHIFT); + anaparam = anaparam &~ANAPARAM_PWR1_MASK; + anaparam = anaparam &~ANAPARAM_PWR0_MASK; + anaparam |= (MAXIM_ANAPARAM_PWR1_ON<<ANAPARAM_PWR1_SHIFT); + anaparam |= (MAXIM_ANAPARAM_PWR0_ON<<ANAPARAM_PWR0_SHIFT); + + //rtl8180_set_anaparam(dev,anaparam); + + /* MAXIM from netbsd driver */ + + write_maxim(dev,0, 7); /* test mode as indicated in datasheet*/ + write_maxim(dev,1, 0x1e); /* enable register*/ + write_maxim(dev,2, 1); /* synt register */ + + + maxim_rf_set_chan(dev,priv->chan); + + write_maxim(dev,4, 0x313); /* rx register*/ + + /* PA is driven directly by the BB, we keep the MAXIM bias + * at the highest value in the boubt tha pleacing it to lower + * values may introduce some further attenuation somewhere.. + */ + + write_maxim(dev,5, 0xf); + + + /*baseband configuration*/ + write_phy(dev,0,0x88); //sys1 + write_phy(dev,3,0x8); //txagc + write_phy(dev,4,0xf8); // lnadet + write_phy(dev,5,0x90); // ifagcinit + write_phy(dev,6,0x1a); // ifagclimit + write_phy(dev,7,0x64); // ifagcdet + + /*Should be done something more here??*/ + + maxim_write_phy_antenna(dev,priv->chan); + + write_phy(dev,0x11,0x88); //trl + if(priv->diversity) + write_phy(dev,0x12,0xc7); + else + write_phy(dev,0x12,0x47); + + write_phy(dev,0x13,0x9b); + + write_phy(dev,0x19,0x0); //CHESTLIM + write_phy(dev,0x1a,0x9f); //CHSQLIM + + maxim_rf_set_chan(dev,priv->chan); +} diff --git a/drivers/staging/rtl8187se/r8180_max2820.h b/drivers/staging/rtl8187se/r8180_max2820.h new file mode 100644 index 0000000..5d4fb55 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_max2820.h @@ -0,0 +1,21 @@ +/* + This is part of rtl8180 OpenSource driver + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the official realtek driver + Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of such projects and the Ndiswrapper project Authors. +*/ + +#define MAXIM_ANTENNA 0xb3 +#define MAXIM_ANAPARAM_PWR1_ON 0x8 +#define MAXIM_ANAPARAM_PWR0_ON 0x0 + + +void maxim_rf_init(struct net_device *dev); +void maxim_rf_set_chan(struct net_device *dev,short ch); + +void maxim_rf_close(struct net_device *dev); diff --git a/drivers/staging/rtl8187se/r8180_pm.c b/drivers/staging/rtl8187se/r8180_pm.c new file mode 100644 index 0000000..3851b93 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_pm.c @@ -0,0 +1,90 @@ +/* + Power management interface routines. + Written by Mariusz Matuszek. + This code is currently just a placeholder for later work and + does not do anything useful. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) +*/ + +#ifdef CONFIG_RTL8180_PM + + +#include "r8180_hw.h" +#include "r8180_pm.h" +#include "r8180.h" + +int rtl8180_save_state (struct pci_dev *dev, u32 state) +{ + printk(KERN_NOTICE "r8180 save state call (state %u).\n", state); + return(-EAGAIN); +} + +int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); +// struct r8180_priv *priv = ieee80211_priv(dev); + + if (!netif_running(dev)) + goto out_pci_suspend; + + dev->stop(dev); + + netif_device_detach(dev); + +out_pci_suspend: + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev,pci_choose_state(pdev,state)); + return 0; +} + +int rtl8180_resume (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); +// struct r8180_priv *priv = ieee80211_priv(dev); + int err; + u32 val; + + pci_set_power_state(pdev, PCI_D0); + + err = pci_enable_device(pdev); + if(err) { + printk(KERN_ERR "%s: pci_enable_device failed on resume\n", + dev->name); + + return err; + } + pci_restore_state(pdev); + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries + * from interfering with C3 CPU state. pci_restore_state won't help + * here since it only restores the first 64 bytes pci config header. + */ + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + + if(!netif_running(dev)) + goto out; + + dev->open(dev); + netif_device_attach(dev); +out: + return 0; +} + + +int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable) +{ + printk(KERN_NOTICE "r8180 enable wake call (state %u, enable %d).\n", + state, enable); + return(-EAGAIN); +} + + + +#endif //CONFIG_RTL8180_PM diff --git a/drivers/staging/rtl8187se/r8180_pm.h b/drivers/staging/rtl8187se/r8180_pm.h new file mode 100644 index 0000000..7958b3a --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_pm.h @@ -0,0 +1,28 @@ +/* + Power management interface routines. + Written by Mariusz Matuszek. + This code is currently just a placeholder for later work and + does not do anything useful. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + +*/ + +#ifdef CONFIG_RTL8180_PM + +#ifndef R8180_PM_H +#define R8180_PM_H + +#include <linux/types.h> +#include <linux/pci.h> + +int rtl8180_save_state (struct pci_dev *dev, u32 state); +int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state); +int rtl8180_resume (struct pci_dev *pdev); +int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable); + +#endif //R8180_PM_H + +#endif // CONFIG_RTL8180_PM diff --git a/drivers/staging/rtl8187se/r8180_rtl8225.c b/drivers/staging/rtl8187se/r8180_rtl8225.c new file mode 100644 index 0000000..96ed029 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_rtl8225.c @@ -0,0 +1,933 @@ +/* + This is part of the rtl8180-sa2400 driver + released under the GPL (See file COPYING for details). + Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> + + This files contains programming code for the rtl8225 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + + + +#include "r8180_hw.h" +#include "r8180_rtl8225.h" + + +u8 rtl8225_gain[]={ + 0x23,0x88,0x7c,0xa5,// -82dbm + 0x23,0x88,0x7c,0xb5,// -82dbm + 0x23,0x88,0x7c,0xc5,// -82dbm + 0x33,0x80,0x79,0xc5,// -78dbm + 0x43,0x78,0x76,0xc5,// -74dbm + 0x53,0x60,0x73,0xc5,// -70dbm + 0x63,0x58,0x70,0xc5,// -66dbm +}; + +#if 0 +u8 rtl8225_init_gain[]={ + //0x00,0x00,0x00,0x00,//0x00,0x00,0x00,0x00, + 0x33,0x80,0x6c,0xc5,//0x00,0x49,0x06,0xb5,//Gain = 0 ~ -78dbm + 0x43,0x78,0x69,0xc5,//0x00,0x45,0x06,0xb1,//Gain = 1 ~ -74dbm + 0x53,0x60,0x66,0xc5,//0x00,0x41,0x06,0xab,//Gain = 2 ~ -70dbm + 0x63,0x58,0x63,0xc5,//0x00,0x3d,0x06,0xa5,//Gain = 3 ~ -66dbm + 0x73,0x50,0x62,0xc5,//0x00,0x39,0x06,0xa1,//Gain = 4 ~ -62dbm + 0x83,0x43,0x61,0xc5,//0x00,0x35,0x06,0x9b,//Gain = 5 ~ -58dbm + 0x93,0x38,0x5a,0xc5,//0x00,0x31,0x06,0x99,//Gain = 6 ~ -54dbm +}; +#endif +#ifdef CONFIG_RTL818X_S +u32 rtl8225_chan[] ={ + 0, + 0x0080, //ch1 + 0x0100, //ch2 + 0x0180, //ch3 + 0x0200, //ch4 + 0x0280, + 0x0300, + 0x0380, + 0x0400, + 0x0480, + 0x0500, + 0x0580, + 0x0600, + 0x0680, + 0x074A, //ch14 +}; +#else +u32 rtl8225_chan[] = { + 0, //dummy channel 0 + 0x085c, //1 + 0x08dc, //2 + 0x095c, //3 + 0x09dc, //4 + 0x0a5c, //5 + 0x0adc, //6 + 0x0b5c, //7 + 0x0bdc, //8 + 0x0c5c, //9 + 0x0cdc, //10 + 0x0d5c, //11 + 0x0ddc, //12 + 0x0e5c, //13 + //0x0f5c, //14 + 0x0f72, // 14 +}; +#endif + +u16 rtl8225bcd_rxgain[]={ + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, + 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb + +}; + + +#if 0 +u16 rtl8225bc_rxgain[]={ + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x039a, 0x039b, 0x039c, 0x039d, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb + +}; + + +u16 rtl8225a_rxgain[]={ + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, + 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad +}; +#endif + +u8 rtl8225_agc[]={ + 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96, + 0x95,0x94,0x93,0x92,0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86, + 0x85,0x84,0x83,0x82,0x81,0x80,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36, + 0x35,0x34,0x33,0x32,0x31,0x30,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26, + 0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16, + 0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06, + 0x05,0x04,0x03,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +}; + + +u8 rtl8225_tx_gain_cck_ofdm[]={ + 0x02,0x06,0x0e,0x1e,0x3e,0x7e +}; + + +u8 rtl8225_tx_power_ofdm[]={ + 0x80,0x90,0xa2,0xb5,0xcb,0xe4 +}; + + +u8 rtl8225_tx_power_cck_ch14[]={ + 0x18,0x17,0x15,0x0c,0x00,0x00,0x00,0x00, + 0x1b,0x1a,0x17,0x0e,0x00,0x00,0x00,0x00, + 0x1f,0x1e,0x1a,0x0f,0x00,0x00,0x00,0x00, + 0x22,0x21,0x1d,0x11,0x00,0x00,0x00,0x00, + 0x26,0x25,0x21,0x13,0x00,0x00,0x00,0x00, + 0x2b,0x2a,0x25,0x15,0x00,0x00,0x00,0x00 +}; + + +u8 rtl8225_tx_power_cck[]={ + 0x18,0x17,0x15,0x11,0x0c,0x08,0x04,0x02, + 0x1b,0x1a,0x17,0x13,0x0e,0x09,0x04,0x02, + 0x1f,0x1e,0x1a,0x15,0x10,0x0a,0x05,0x02, + 0x22,0x21,0x1d,0x18,0x11,0x0b,0x06,0x02, + 0x26,0x25,0x21,0x1b,0x14,0x0d,0x06,0x03, + 0x2b,0x2a,0x25,0x1e,0x16,0x0e,0x07,0x03 +}; + + +void rtl8225_set_gain(struct net_device *dev, short gain) +{ + write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]); + write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]); + write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]); + write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]); +} +#if 0 + +void rtl8225_set_gain(struct net_device *dev, short gain) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); + + if(priv->card_8185 == 2) + write_phy_ofdm(dev, 0x21, 0x27); + else + write_phy_ofdm(dev, 0x21, 0x37); + + write_phy_ofdm(dev, 0x25, 0x20); + write_phy_ofdm(dev, 0x11, 0x6); + + if(priv->card_8185 == 1 && priv->card_8185_Bversion) + write_phy_ofdm(dev, 0x27, 0x8); + else + write_phy_ofdm(dev, 0x27, 0x88); + + write_phy_ofdm(dev, 0x14, 0); + write_phy_ofdm(dev, 0x16, 0); + write_phy_ofdm(dev, 0x15, 0x40); + write_phy_ofdm(dev, 0x17, 0x40); + + write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]); + write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]); + write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]); + write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]); + //rtl8225_set_gain_usb(dev, gain); +} +#endif + + +void write_rtl8225(struct net_device *dev, u8 adr, u16 data) +{ + int i; + u16 out,select; + u8 bit; + u32 bangdata = (data << 4) | (adr & 0xf); + struct r8180_priv *priv = ieee80211_priv(dev); + + out = read_nic_word(dev, RFPinsOutput) & 0xfff3; + + write_nic_word(dev,RFPinsEnable, + (read_nic_word(dev,RFPinsEnable) | 0x7)); + + select = read_nic_word(dev, RFPinsSelect); + + write_nic_word(dev, RFPinsSelect, select | 0x7 | + ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); + + force_pci_posting(dev); + udelay(10); + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); + + force_pci_posting(dev); + udelay(2); + + write_nic_word(dev, RFPinsOutput, out); + + force_pci_posting(dev); + udelay(10); + + + for(i=15; i>=0;i--){ + + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out); + + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + + i--; + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + + write_nic_word(dev, RFPinsOutput, bit | out); + + } + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); + + force_pci_posting(dev); + udelay(10); + + write_nic_word(dev, RFPinsOutput, out | + ((priv->card_type == USB) ? 4 : BB_HOST_BANG_EN)); + + write_nic_word(dev, RFPinsSelect, select | + ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); + + if(priv->card_type == USB) + mdelay(2); + else + rtl8185_rf_pins_enable(dev); +} + +void rtl8225_rf_close(struct net_device *dev) +{ + write_rtl8225(dev, 0x4, 0x1f); + + force_pci_posting(dev); + mdelay(1); + + rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF); + rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF); +} + +void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + int GainIdx; + int GainSetting; + int i; + u8 power; + u8 *cck_power_table; + u8 max_cck_power_level; + u8 max_ofdm_power_level; + u8 min_ofdm_power_level; + u8 cck_power_level = 0xff & priv->chtxpwr[ch]; + u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch]; + + if(priv->card_type == USB){ + max_cck_power_level = 11; + max_ofdm_power_level = 25; // 12 -> 25 + min_ofdm_power_level = 10; + }else{ + max_cck_power_level = 35; + max_ofdm_power_level = 35; + min_ofdm_power_level = 0; + } + /* CCK power setting */ + if(cck_power_level > max_cck_power_level) + cck_power_level = max_cck_power_level; + GainIdx=cck_power_level % 6; + GainSetting=cck_power_level / 6; + + if(ch == 14) + cck_power_table = rtl8225_tx_power_cck_ch14; + else + cck_power_table = rtl8225_tx_power_cck; + +// if(priv->card_8185 == 1 && priv->card_8185_Bversion ){ + /*Ver B*/ +// write_nic_byte(dev, TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[GainSetting]); +// }else{ + /*Ver C - D */ + write_nic_byte(dev, TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1); +// } + + for(i=0;i<8;i++){ + + power = cck_power_table[GainIdx * 8 + i]; + write_phy_cck(dev, 0x44 + i, power); + } + + /* FIXME Is this delay really needeed ? */ + force_pci_posting(dev); + mdelay(1); + + /* OFDM power setting */ +// Old: +// if(ofdm_power_level > max_ofdm_power_level) +// ofdm_power_level = 35; +// ofdm_power_level += min_ofdm_power_level; +// Latest: + if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level)) + ofdm_power_level = max_ofdm_power_level; + else + ofdm_power_level += min_ofdm_power_level; + if(ofdm_power_level > 35) + ofdm_power_level = 35; +// + + GainIdx=ofdm_power_level % 6; + GainSetting=ofdm_power_level / 6; +#if 1 +// if(priv->card_type == USB){ + rtl8185_set_anaparam2(dev,RTL8225_ANAPARAM2_ON); + + write_phy_ofdm(dev,2,0x42); + write_phy_ofdm(dev,6,0); + write_phy_ofdm(dev,8,0); +// } +#endif +// if(priv->card_8185 == 1 && priv->card_8185_Bversion){ +// /*Ver B*/ +// write_nic_byte(dev, TX_GAIN_OFDM, rtl8225_tx_gain_cck_ofdm[GainSetting]); +// }else{ + /*Ver C - D */ + write_nic_byte(dev, TX_GAIN_OFDM, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1); +// } + + + power = rtl8225_tx_power_ofdm[GainIdx]; + + write_phy_ofdm(dev, 0x5, power); + write_phy_ofdm(dev, 0x7, power); + + force_pci_posting(dev); + mdelay(1); + //write_nic_byte(dev, TX_AGC_CONTROL,4); +} +#if 0 +/* switch between mode B and G */ +void rtl8225_set_mode(struct net_device *dev, short modeb) +{ + write_phy_ofdm(dev, 0x15, (modeb ? 0x0 : 0x40)); + write_phy_ofdm(dev, 0x17, (modeb ? 0x0 : 0x40)); +} +#endif +void rtl8225_rf_set_chan(struct net_device *dev, short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + short gset = (priv->ieee80211->state == IEEE80211_LINKED && + ieee80211_is_54g(priv->ieee80211->current_network)) || + priv->ieee80211->iw_mode == IW_MODE_MONITOR; + + rtl8225_SetTXPowerLevel(dev, ch); + + write_rtl8225(dev, 0x7, rtl8225_chan[ch]); + + force_pci_posting(dev); + mdelay(10); + + // A mode sifs 0x44, difs 34-14, slot 9, eifs 23, cwm 3, cwM 7, ctstoself 0x10 + if(gset){ + write_nic_byte(dev,SIFS,0x22);// SIFS: 0x22 + write_nic_byte(dev,DIFS,0x14); //DIFS: 20 + //write_nic_byte(dev,DIFS,20); //DIFS: 20 + }else{ + write_nic_byte(dev,SIFS,0x44);// SIFS: 0x22 + write_nic_byte(dev,DIFS,50 - 14); //DIFS: 36 + } + if(priv->ieee80211->state == IEEE80211_LINKED && + ieee80211_is_shortslot(priv->ieee80211->current_network)) + write_nic_byte(dev,SLOT,0x9); //SLOT: 9 + + else + write_nic_byte(dev,SLOT,0x14); //SLOT: 20 (0x14) + + + if(gset){ + write_nic_byte(dev,EIFS,81);//91 - 20); // EIFS: 91 (0x5B) + write_nic_byte(dev,CW_VAL,0x73); //CW VALUE: 0x37 + //DMESG("using G net params"); + }else{ + write_nic_byte(dev,EIFS,81); // EIFS: 91 (0x5B) + write_nic_byte(dev,CW_VAL,0xa5); //CW VALUE: 0x37 + //DMESG("using B net params"); + } + + +} + +void rtl8225_host_pci_init(struct net_device *dev) +{ + write_nic_word(dev, RFPinsOutput, 0x480); + + rtl8185_rf_pins_enable(dev); + + //if(priv->card_8185 == 2 && priv->enable_gpio0 ) /* version D */ + //write_nic_word(dev, RFPinsSelect, 0x88); + //else + write_nic_word(dev, RFPinsSelect, 0x88 | SW_CONTROL_GPIO); /* 0x488 | SW_CONTROL_GPIO */ + + write_nic_byte(dev, GP_ENABLE, 0); + + force_pci_posting(dev); + mdelay(200); + + write_nic_word(dev, GP_ENABLE, 0xff & (~(1<<6))); /* bit 6 is for RF on/off detection */ + + +} + +void rtl8225_host_usb_init(struct net_device *dev) +{ + #if 0 + write_nic_byte(dev,RFPinsSelect+1,0); + + write_nic_byte(dev,GPIO,0); + + write_nic_byte_E(dev,0x53,read_nic_byte_E(dev,0x53) | (1<<7)); + + write_nic_byte(dev,RFPinsSelect+1,4); + + write_nic_byte(dev,GPIO,0x20); + + write_nic_byte(dev,GP_ENABLE,0); + + + /* Config BB & RF */ + write_nic_word(dev, RFPinsOutput, 0x80); + + write_nic_word(dev, RFPinsSelect, 0x80); + + write_nic_word(dev, RFPinsEnable, 0x80); + + + mdelay(100); + + mdelay(1000); +#endif + +} + +void rtl8225_rf_sleep(struct net_device *dev) +{ + write_rtl8225(dev,0x4,0xdff); + force_pci_posting(dev); + mdelay(1); + rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_SLEEP); + rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_SLEEP); + force_pci_posting(dev); +} + +void rtl8225_rf_wakeup(struct net_device *dev) +{ + write_rtl8225(dev,0x4,0x9ff); + rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); + rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); + force_pci_posting(dev); +} + +void rtl8225_rf_init(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int i; + short channel = 1; + u16 brsr; + + priv->chan = channel; + + rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); + + + if(priv->card_type == USB) + rtl8225_host_usb_init(dev); + else + rtl8225_host_pci_init(dev); + + write_nic_dword(dev, RF_TIMING, 0x000a8008); + + brsr = read_nic_word(dev, BRSR); + + write_nic_word(dev, BRSR, 0xffff); + + #if 0 + if(priv->card_8185 == 1){/* version C or B */ + if(priv->card_8185_Bversion) /* version B*/ + write_nic_dword(dev, RF_PARA, 0x44); + else /* version C */ + write_nic_dword(dev, RF_PARA, 0x100044); + }else{ /* version D */ + if(priv->enable_gpio0) + write_nic_dword(dev, RF_PARA, 0x20100044); + else /* also USB */ + write_nic_dword(dev, RF_PARA, 0x100044); + } + #endif + + write_nic_dword(dev, RF_PARA, 0x100044); + + #if 1 //0->1 + rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + write_nic_byte(dev, CONFIG3, 0x44); + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + #endif + + if(priv->card_type == USB){ + rtl8185_rf_pins_enable(dev); + + mdelay(1000); + } + + write_rtl8225(dev, 0x0, 0x67); mdelay(1); + + + write_rtl8225(dev, 0x1, 0xfe0); mdelay(1); + + write_rtl8225(dev, 0x2, 0x44d); mdelay(1); + + write_rtl8225(dev, 0x3, 0x441); mdelay(1); + + if(priv->card_type == USB) + write_rtl8225(dev, 0x4, 0x486); + else + write_rtl8225(dev, 0x4, 0x8be); + + mdelay(1); + + + #if 0 + }else if(priv->phy_ver == 1){ + /* version A */ + write_rtl8225(dev, 0x5, 0xbc0 + 2); + }else{ + #endif + /* version B & C */ + + if(priv->card_type == USB) + write_rtl8225(dev, 0x5, 0xbc0); + else if(priv->card_type == MINIPCI) + write_rtl8225(dev, 0x5, 0xbc0 + 3 +(6<<3)); + else + write_rtl8225(dev, 0x5, 0xbc0 + (6<<3)); + + mdelay(1); +// } + + write_rtl8225(dev, 0x6, 0xae6); mdelay(1); + + write_rtl8225(dev, 0x7, ((priv->card_type == USB)? 0x82a : rtl8225_chan[channel])); mdelay(1); + + write_rtl8225(dev, 0x8, 0x1f); mdelay(1); + + write_rtl8225(dev, 0x9, 0x334); mdelay(1); + + write_rtl8225(dev, 0xa, 0xfd4); mdelay(1); + + write_rtl8225(dev, 0xb, 0x391); mdelay(1); + + write_rtl8225(dev, 0xc, 0x50); mdelay(1); + + + write_rtl8225(dev, 0xd, 0x6db); mdelay(1); + + write_rtl8225(dev, 0xe, 0x29); mdelay(1); + + write_rtl8225(dev, 0xf, 0x914); + + if(priv->card_type == USB){ + //force_pci_posting(dev); + mdelay(100); + } + + write_rtl8225(dev, 0x2, 0xc4d); + + if(priv->card_type == USB){ + // force_pci_posting(dev); + mdelay(200); + + write_rtl8225(dev, 0x2, 0x44d); + + // force_pci_posting(dev); + mdelay(100); + + }//End of if(priv->card_type == USB) + /* FIXME!! rtl8187 we have to check if calibrarion + * is successful and eventually cal. again (repeat + * the two write on reg 2) + */ + force_pci_posting(dev); + + mdelay(100); //200 for 8187 + + //if(priv->card_type != USB) /* maybe not needed even for 8185 */ +// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); + + write_rtl8225(dev, 0x0, 0x127); + + for(i=0;i<95;i++){ + write_rtl8225(dev, 0x1, (u8)(i+1)); + + #if 0 + if(priv->phy_ver == 1) + /* version A */ + write_rtl8225(dev, 0x2, rtl8225a_rxgain[i]); + else + #endif + /* version B & C & D*/ + + write_rtl8225(dev, 0x2, rtl8225bcd_rxgain[i]); + } + + write_rtl8225(dev, 0x0, 0x27); + + +// //if(priv->card_type != USB){ +// write_rtl8225(dev, 0x2, 0x44d); +// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); +// write_rtl8225(dev, 0x2, 0x47d); +// +// force_pci_posting(dev); +// mdelay(100); +// +// write_rtl8225(dev, 0x2, 0x44d); +// //} + + write_rtl8225(dev, 0x0, 0x22f); + + if(priv->card_type != USB) + rtl8185_rf_pins_enable(dev); + + for(i=0;i<128;i++){ + write_phy_ofdm(dev, 0xb, rtl8225_agc[i]); + + mdelay(1); + write_phy_ofdm(dev, 0xa, (u8)i+ 0x80); + + mdelay(1); + } + + force_pci_posting(dev); + mdelay(1); + + write_phy_ofdm(dev, 0x0, 0x1); mdelay(1); + write_phy_ofdm(dev, 0x1, 0x2); mdelay(1); + write_phy_ofdm(dev, 0x2, ((priv->card_type == USB)? 0x42 : 0x62)); mdelay(1); + write_phy_ofdm(dev, 0x3, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x4, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x5, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x6, 0x40); mdelay(1); + write_phy_ofdm(dev, 0x7, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x8, 0x40); mdelay(1); + write_phy_ofdm(dev, 0x9, 0xfe); mdelay(1); + + #if 0 + if(priv->card_type == USB){ + write_phy_ofdm(dev, 0xa, 0x9); + }else{ + if(priv->card_8185 == 1 && priv->card_8185_Bversion){ + /* Ver B + * maybe later version can accept this also? + */ + write_phy_ofdm(dev, 0xa, 0x6); + write_phy_ofdm(dev, 0x18, 0x6f); + }else{ + #endif + /* ver C & D */ + write_phy_ofdm(dev, 0xa, 0x9); mdelay(1); + + //write_phy_ofdm(dev, 0x18, 0xef); + // } + //} + write_phy_ofdm(dev, 0xb, 0x80); mdelay(1); + + write_phy_ofdm(dev, 0xc, 0x1);mdelay(1); + + + //if(priv->card_type != USB) + //write_phy_ofdm(dev, 0xd, 0x33); // <> + + write_phy_ofdm(dev, 0xe, 0xd3);mdelay(1); + + + #if 0 + if(priv->card_8185 == 1){ + if(priv->card_8185_Bversion) + write_phy_ofdm(dev, 0xf, 0x20);/*ver B*/ + else + write_phy_ofdm(dev, 0xf, 0x28);/*ver C*/ + }else{ + #endif + write_phy_ofdm(dev, 0xf, 0x38);mdelay(1); +/*ver D & 8187*/ +// } + +// if(priv->card_8185 == 1 && priv->card_8185_Bversion) +// write_phy_ofdm(dev, 0x10, 0x04);/*ver B*/ +// else + write_phy_ofdm(dev, 0x10, 0x84);mdelay(1); +/*ver C & D & 8187*/ + + write_phy_ofdm(dev, 0x11, 0x06);mdelay(1); +/*agc resp time 700*/ + + +// if(priv->card_8185 == 2){ + /* Ver D & 8187*/ + write_phy_ofdm(dev, 0x12, 0x20);mdelay(1); + + write_phy_ofdm(dev, 0x13, 0x20);mdelay(1); + +#if 0 + }else{ + /* Ver B & C*/ + write_phy_ofdm(dev, 0x12, 0x0); + write_phy_ofdm(dev, 0x13, 0x0); + } +#endif + write_phy_ofdm(dev, 0x14, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x15, 0x40); mdelay(1); + write_phy_ofdm(dev, 0x16, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x17, 0x40); mdelay(1); + +// if (priv->card_type == USB) +// write_phy_ofdm(dev, 0x18, 0xef); + + write_phy_ofdm(dev, 0x18, 0xef);mdelay(1); + + + write_phy_ofdm(dev, 0x19, 0x19); mdelay(1); + write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1); + +// if (priv->card_type != USB){ +// if(priv->card_8185 == 1 && priv->card_8185_Bversion) +// write_phy_ofdm(dev, 0x1b, 0x66); /* Ver B */ +// else + write_phy_ofdm(dev, 0x1b, 0x76);mdelay(1); + /* Ver C & D */ //FIXME:MAYBE not needed +// } + + write_phy_ofdm(dev, 0x1c, 0x4);mdelay(1); + +#if 0 + if(priv->card_8185 == 1){ + if(priv->card_8185_Bversion){ + /*ver B*/ + write_phy_ofdm(dev, 0x1e, 0x95); + write_phy_ofdm(dev, 0x1f, 0x55); + }else{ + /*ver C*/ + write_phy_ofdm(dev, 0x1e, 0x90); + write_phy_ofdm(dev, 0x1f, 0x34); + + } + }else{ +#endif + /*ver D & 8187*/ + write_phy_ofdm(dev, 0x1e, 0x95);mdelay(1); + + write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1); + +// } + + write_phy_ofdm(dev, 0x20, 0x1f);mdelay(1); + + write_phy_ofdm(dev, 0x21, 0x27);mdelay(1); + + write_phy_ofdm(dev, 0x22, 0x16);mdelay(1); + +// if(priv->card_type != USB) + //write_phy_ofdm(dev, 0x23, 0x43); //FIXME maybe not needed // <> + + write_phy_ofdm(dev, 0x24, 0x46); mdelay(1); + write_phy_ofdm(dev, 0x25, 0x20); mdelay(1); + write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); +#if 0 + if(priv->card_8185 == 1 && priv->card_8185_Bversion) + write_phy_ofdm(dev, 0x27, 0x08); /* Ver B. might work also fo ver C&D ?*/ + else +#endif + write_phy_ofdm(dev, 0x27, 0x88); mdelay(1); +/* Ver C & D & 8187*/ + + // <> Set init. gain to m74dBm. + write_phy_ofdm(dev, 0x0d, 0x43); mdelay(1); + write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1); + write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1); + write_phy_ofdm(dev, 0x23, 0x78); mdelay(1); + + //if(priv->card_type == USB); + // rtl8225_set_gain_usb(dev, 1); /* FIXME this '2' is random */ + + write_phy_cck(dev, 0x0, 0x98); mdelay(1); + write_phy_cck(dev, 0x3, 0x20); mdelay(1); + write_phy_cck(dev, 0x4, 0x7e); mdelay(1); + write_phy_cck(dev, 0x5, 0x12); mdelay(1); + write_phy_cck(dev, 0x6, 0xfc); mdelay(1); +#if 0 + if(priv->card_8185 == 1 && priv->card_8185_Bversion) + write_phy_cck(dev, 0x7, 0xd8); /* Ver B */ + else +#endif + write_phy_cck(dev, 0x7, 0x78);mdelay(1); + /* Ver C & D & 8187*/ + + write_phy_cck(dev, 0x8, 0x2e);mdelay(1); + + write_phy_cck(dev, 0x10, ((priv->card_type == USB) ? 0x9b: 0x93)); mdelay(1); + write_phy_cck(dev, 0x11, 0x88); mdelay(1); + write_phy_cck(dev, 0x12, 0x47); mdelay(1); +#if 0 + if(priv->card_8185 == 1 && priv->card_8185_Bversion) + write_phy_cck(dev, 0x13, 0x98); /* Ver B */ + else +#endif + write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ + + write_phy_cck(dev, 0x19, 0x0); + write_phy_cck(dev, 0x1a, 0xa0); + write_phy_cck(dev, 0x1b, 0x8); + write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ + + write_phy_cck(dev, 0x41, 0x8d);mdelay(1); + + + write_phy_cck(dev, 0x42, 0x15); mdelay(1); + write_phy_cck(dev, 0x43, 0x18); mdelay(1); + write_phy_cck(dev, 0x44, 0x1f); mdelay(1); + write_phy_cck(dev, 0x45, 0x1e); mdelay(1); + write_phy_cck(dev, 0x46, 0x1a); mdelay(1); + write_phy_cck(dev, 0x47, 0x15); mdelay(1); + write_phy_cck(dev, 0x48, 0x10); mdelay(1); + write_phy_cck(dev, 0x49, 0xa); mdelay(1); + write_phy_cck(dev, 0x4a, 0x5); mdelay(1); + write_phy_cck(dev, 0x4b, 0x2); mdelay(1); + write_phy_cck(dev, 0x4c, 0x5);mdelay(1); + + + write_nic_byte(dev, 0x5b, 0x0d); mdelay(1); + + + +// <> +// // TESTR 0xb 8187 +// write_phy_cck(dev, 0x10, 0x93);// & 0xfb); +// +// //if(priv->card_type != USB){ +// write_phy_ofdm(dev, 0x2, 0x62); +// write_phy_ofdm(dev, 0x6, 0x0); +// write_phy_ofdm(dev, 0x8, 0x0); +// //} + + rtl8225_SetTXPowerLevel(dev, channel); + + write_phy_cck(dev, 0x10, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ + write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* Rx ant A, 0x10 for B */ + + rtl8185_tx_antenna(dev, 0x3); /* TX ant A, 0x0 for B */ + + /* switch to high-speed 3-wire + * last digit. 2 for both cck and ofdm + */ + if(priv->card_type == USB) + write_nic_dword(dev, 0x94, 0x3dc00002); + else{ + write_nic_dword(dev, 0x94, 0x15c00002); + rtl8185_rf_pins_enable(dev); + } + +// if(priv->card_type != USB) +// rtl8225_set_gain(dev, 4); /* FIXME this '1' is random */ // <> +// rtl8225_set_mode(dev, 1); /* FIXME start in B mode */ // <> +// +// /* make sure is waken up! */ +// write_rtl8225(dev,0x4, 0x9ff); +// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); +// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); + + rtl8225_rf_set_chan(dev, priv->chan); + + write_nic_word(dev,BRSR,brsr); + +} diff --git a/drivers/staging/rtl8187se/r8180_rtl8225.h b/drivers/staging/rtl8187se/r8180_rtl8225.h new file mode 100644 index 0000000..458de66 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_rtl8225.h @@ -0,0 +1,44 @@ +/* + This is part of the rtl8180-sa2400 driver + released under the GPL (See file COPYING for details). + Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> + + This files contains programming code for the rtl8225 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + +#include "r8180.h" + +#define RTL8225_ANAPARAM_ON 0xa0000b59 +#define RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8225_ANAPARAM2_OFF 0x840dec11 +#define RTL8225_ANAPARAM2_ON 0x860dec11 +#define RTL8225_ANAPARAM_SLEEP 0xa00bab59 +#define RTL8225_ANAPARAM2_SLEEP 0x840dec11 + +#ifdef CONFIG_RTL8185B +void rtl8225z2_rf_init(struct net_device *dev); +void rtl8225z2_rf_set_chan(struct net_device *dev,short ch); +void rtl8225z2_rf_close(struct net_device *dev); + +void rtl8225_host_pci_init(struct net_device *dev); +void rtl8225_host_usb_init(struct net_device *dev); + +void write_rtl8225(struct net_device *dev, u8 adr, u16 data); +void RF_WriteReg(struct net_device *dev, u8 offset, u32 data); +u32 RF_ReadReg(struct net_device *dev, u8 offset); +#endif +void rtl8225_rf_init(struct net_device *dev); +void rtl8225_rf_set_chan(struct net_device *dev,short ch); +void rtl8225_rf_close(struct net_device *dev); +void rtl8225_rf_sleep(struct net_device *dev); +void rtl8225_rf_wakeup(struct net_device *dev); +void rtl8180_set_mode(struct net_device *dev,int mode); +void rtl8180_set_mode(struct net_device *dev,int mode); +bool SetZebraRFPowerState8185(struct net_device *dev,RT_RF_POWER_STATE eRFPowerState); +void rtl8225z4_rf_sleep(struct net_device *dev); +void rtl8225z4_rf_wakeup(struct net_device *dev); + diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c new file mode 100644 index 0000000..90a574d --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c @@ -0,0 +1,1587 @@ +/* + This is part of the rtl8180-sa2400 driver + released under the GPL (See file COPYING for details). + Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> + + This files contains programming code for the rtl8225 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + +#include "r8180_hw.h" +#include "r8180_rtl8225.h" +#include "r8180_93cx6.h" + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +#ifdef CONFIG_RTL8185B + +extern u8 rtl8225_agc[]; + +extern u32 rtl8225_chan[]; + +//2005.11.16 +u8 rtl8225z2_threshold[]={ + 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd, +}; + +// 0xd 0x19 0x1b 0x21 +u8 rtl8225z2_gain_bg[]={ + 0x23, 0x15, 0xa5, // -82-1dbm + 0x23, 0x15, 0xb5, // -82-2dbm + 0x23, 0x15, 0xc5, // -82-3dbm + 0x33, 0x15, 0xc5, // -78dbm + 0x43, 0x15, 0xc5, // -74dbm + 0x53, 0x15, 0xc5, // -70dbm + 0x63, 0x15, 0xc5, // -66dbm +}; + +u8 rtl8225z2_gain_a[]={ + 0x13,0x27,0x5a,//,0x37,// -82dbm + 0x23,0x23,0x58,//,0x37,// -82dbm + 0x33,0x1f,0x56,//,0x37,// -82dbm + 0x43,0x1b,0x54,//,0x37,// -78dbm + 0x53,0x17,0x51,//,0x37,// -74dbm + 0x63,0x24,0x4f,//,0x37,// -70dbm + 0x73,0x0f,0x4c,//,0x37,// -66dbm +}; +#if 0 +u32 rtl8225_chan[] = { + 0, //dummy channel 0 + 0x085c, //1 + 0x08dc, //2 + 0x095c, //3 + 0x09dc, //4 + 0x0a5c, //5 + 0x0adc, //6 + 0x0b5c, //7 + 0x0bdc, //8 + 0x0c5c, //9 + 0x0cdc, //10 + 0x0d5c, //11 + 0x0ddc, //12 + 0x0e5c, //13 + //0x0f5c, //14 + 0x0f72, // 14 +}; +#endif + +//- +u16 rtl8225z2_rxgain[]={ + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb + +}; + +//2005.11.16, +u8 ZEBRA2_CCK_OFDM_GAIN_SETTING[]={ + 0x00,0x01,0x02,0x03,0x04,0x05, + 0x06,0x07,0x08,0x09,0x0a,0x0b, + 0x0c,0x0d,0x0e,0x0f,0x10,0x11, + 0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d, + 0x1e,0x1f,0x20,0x21,0x22,0x23, +}; + +#if 0 +//- +u8 rtl8225_agc[]={ + 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96, + 0x95,0x94,0x93,0x92,0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86, + 0x85,0x84,0x83,0x82,0x81,0x80,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36, + 0x35,0x34,0x33,0x32,0x31,0x30,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26, + 0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16, + 0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06, + 0x05,0x04,0x03,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +}; +#endif +/* + from 0 to 0x23 +u8 rtl8225_tx_gain_cck_ofdm[]={ + 0x02,0x06,0x0e,0x1e,0x3e,0x7e +}; +*/ + +//- +u8 rtl8225z2_tx_power_ofdm[]={ + 0x42,0x00,0x40,0x00,0x40 +}; + + +//- +u8 rtl8225z2_tx_power_cck_ch14[]={ + 0x36,0x35,0x2e,0x1b,0x00,0x00,0x00,0x00 +}; + + +//- +u8 rtl8225z2_tx_power_cck[]={ + 0x36,0x35,0x2e,0x25,0x1c,0x12,0x09,0x04 +}; + + +void rtl8225z2_set_gain(struct net_device *dev, short gain) +{ + u8* rtl8225_gain; + struct r8180_priv *priv = ieee80211_priv(dev); + + u8 mode = priv->ieee80211->mode; + + if(mode == IEEE_B || mode == IEEE_G) + rtl8225_gain = rtl8225z2_gain_bg; + else + rtl8225_gain = rtl8225z2_gain_a; + + //write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 3]); + //write_phy_ofdm(dev, 0x19, rtl8225_gain[gain * 3 + 1]); + //write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 3 + 2]); + //2005.11.17, by ch-hsu + write_phy_ofdm(dev, 0x0b, rtl8225_gain[gain * 3]); + write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 3 + 1]); + write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 3 + 2]); + write_phy_ofdm(dev, 0x21, 0x37); + +} + +#if 0 + +void rtl8225_set_gain(struct net_device *dev, short gain) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); + + if(priv->card_8185 == 2) + write_phy_ofdm(dev, 0x21, 0x27); + else + write_phy_ofdm(dev, 0x21, 0x37); + + write_phy_ofdm(dev, 0x25, 0x20); + write_phy_ofdm(dev, 0x11, 0x6); + + if(priv->card_8185 == 1 && priv->card_8185_Bversion) + write_phy_ofdm(dev, 0x27, 0x8); + else + write_phy_ofdm(dev, 0x27, 0x88); + + write_phy_ofdm(dev, 0x14, 0); + write_phy_ofdm(dev, 0x16, 0); + write_phy_ofdm(dev, 0x15, 0x40); + write_phy_ofdm(dev, 0x17, 0x40); + + write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]); + write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]); + write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]); + write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]); + //rtl8225_set_gain_usb(dev, gain); +} +#endif + +u32 read_rtl8225(struct net_device *dev, u8 adr) +{ + u32 data2Write = ((u32)(adr & 0x1f)) << 27; + u32 dataRead; + u32 mask; + u16 oval,oval2,oval3,tmp; +// ThreeWireReg twreg; +// ThreeWireReg tdata; + int i; + short bit, rw; + + u8 wLength = 6; + u8 rLength = 12; + u8 low2high = 0; + + oval = read_nic_word(dev, RFPinsOutput); + oval2 = read_nic_word(dev, RFPinsEnable); + oval3 = read_nic_word(dev, RFPinsSelect); + + write_nic_word(dev, RFPinsEnable, (oval2|0xf)); + write_nic_word(dev, RFPinsSelect, (oval3|0xf)); + + dataRead = 0; + + oval &= ~0xf; + + write_nic_word(dev, RFPinsOutput, oval | BB_HOST_BANG_EN ); udelay(4); + + write_nic_word(dev, RFPinsOutput, oval ); udelay(5); + + rw = 0; + + mask = (low2high) ? 0x01 : (((u32)0x01)<<(32-1)); + for(i = 0; i < wLength/2; i++) + { + bit = ((data2Write&mask) != 0) ? 1 : 0; + write_nic_word(dev, RFPinsOutput, bit|oval | rw); udelay(1); + + write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); + write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); + + mask = (low2high) ? (mask<<1): (mask>>1); + + if(i == 2) + { + rw = BB_HOST_BANG_RW; + write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); + write_nic_word(dev, RFPinsOutput, bit|oval | rw); udelay(2); + break; + } + + bit = ((data2Write&mask) != 0) ? 1: 0; + + write_nic_word(dev, RFPinsOutput, oval|bit|rw| BB_HOST_BANG_CLK); udelay(2); + write_nic_word(dev, RFPinsOutput, oval|bit|rw| BB_HOST_BANG_CLK); udelay(2); + + write_nic_word(dev, RFPinsOutput, oval| bit |rw); udelay(1); + + mask = (low2high) ? (mask<<1) : (mask>>1); + } + + //twreg.struc.clk = 0; + //twreg.struc.data = 0; + write_nic_word(dev, RFPinsOutput, rw|oval); udelay(2); + mask = (low2high) ? 0x01 : (((u32)0x01) << (12-1)); + + // We must set data pin to HW controled, otherwise RF can't driver it and + // value RF register won't be able to read back properly. 2006.06.13, by rcnjko. + write_nic_word(dev, RFPinsEnable, (oval2 & (~0x01))); + + for(i = 0; i < rLength; i++) + { + write_nic_word(dev, RFPinsOutput, rw|oval); udelay(1); + + write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); + write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); + write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); + tmp = read_nic_word(dev, RFPinsInput); + + dataRead |= (tmp & BB_HOST_BANG_CLK ? mask : 0); + + write_nic_word(dev, RFPinsOutput, (rw|oval)); udelay(2); + + mask = (low2high) ? (mask<<1) : (mask>>1); + } + + write_nic_word(dev, RFPinsOutput, BB_HOST_BANG_EN|BB_HOST_BANG_RW|oval); udelay(2); + + write_nic_word(dev, RFPinsEnable, oval2); + write_nic_word(dev, RFPinsSelect, oval3); // Set To SW Switch + write_nic_word(dev, RFPinsOutput, 0x3a0); + + return dataRead; + +} +#if 0 +void write_rtl8225(struct net_device *dev, u8 adr, u16 data) +{ + int i; + u16 out,select; + u8 bit; + u32 bangdata = (data << 4) | (adr & 0xf); + struct r8180_priv *priv = ieee80211_priv(dev); + + out = read_nic_word(dev, RFPinsOutput) & 0xfff3; + + write_nic_word(dev,RFPinsEnable, + (read_nic_word(dev,RFPinsEnable) | 0x7)); + + select = read_nic_word(dev, RFPinsSelect); + + write_nic_word(dev, RFPinsSelect, select | 0x7 | + ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); + + force_pci_posting(dev); + udelay(10); + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); + + force_pci_posting(dev); + udelay(2); + + write_nic_word(dev, RFPinsOutput, out); + + force_pci_posting(dev); + udelay(10); + + + for(i=15; i>=0;i--){ + + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out); + + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + + i--; + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + + write_nic_word(dev, RFPinsOutput, bit | out); + + } + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); + + force_pci_posting(dev); + udelay(10); + + write_nic_word(dev, RFPinsOutput, out | + ((priv->card_type == USB) ? 4 : BB_HOST_BANG_EN)); + + write_nic_word(dev, RFPinsSelect, select | + ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); + + if(priv->card_type == USB) + mdelay(2); + else + rtl8185_rf_pins_enable(dev); +} + +#endif +short rtl8225_is_V_z2(struct net_device *dev) +{ + short vz2 = 1; + //int i; + /* sw to reg pg 1 */ + //write_rtl8225(dev, 0, 0x1b7); + //write_rtl8225(dev, 0, 0x0b7); + + /* reg 8 pg 1 = 23*/ + //printk(KERN_WARNING "RF Rigisters:\n"); +#if 0 + for(i = 0; i <= 0xf; i++) + printk(KERN_WARNING "%08x,", read_rtl8225(dev, i)); + //printk(KERN_WARNING "reg[9]@pg1 = 0x%x\n", read_rtl8225(dev, 0x0F)); + +// printk(KERN_WARNING "RF:\n"); +#endif + if( read_rtl8225(dev, 8) != 0x588) + vz2 = 0; + + else /* reg 9 pg 1 = 24 */ + if( read_rtl8225(dev, 9) != 0x700) + vz2 = 0; + + /* sw back to pg 0 */ + write_rtl8225(dev, 0, 0xb7); + + return vz2; + +} + +#if 0 +void rtl8225_rf_close(struct net_device *dev) +{ + write_rtl8225(dev, 0x4, 0x1f); + + force_pci_posting(dev); + mdelay(1); + + rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF); + rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF); +} +#endif +#if 0 +short rtl8225_rf_set_sens(struct net_device *dev, short sens) +{ + if (sens <0 || sens > 6) return -1; + + if(sens > 4) + write_rtl8225(dev, 0x0c, 0x850); + else + write_rtl8225(dev, 0x0c, 0x50); + + sens= 6-sens; + rtl8225_set_gain(dev, sens); + + write_phy_cck(dev, 0x41, rtl8225_threshold[sens]); + return 0; + +} +#endif + + +void rtl8225z2_rf_close(struct net_device *dev) +{ + RF_WriteReg(dev, 0x4, 0x1f); + + force_pci_posting(dev); + mdelay(1); + + rtl8180_set_anaparam(dev, RTL8225z2_ANAPARAM_OFF); + rtl8185_set_anaparam2(dev, RTL8225z2_ANAPARAM2_OFF); +} + +#ifdef ENABLE_DOT11D +// +// Description: +// Map dBm into Tx power index according to +// current HW model, for example, RF and PA, and +// current wireless mode. +// +s8 +DbmToTxPwrIdx( + struct r8180_priv *priv, + WIRELESS_MODE WirelessMode, + s32 PowerInDbm + ) +{ + bool bUseDefault = true; + s8 TxPwrIdx = 0; + +#ifdef CONFIG_RTL818X_S + // + // 071011, SD3 SY: + // OFDM Power in dBm = Index * 0.5 + 0 + // CCK Power in dBm = Index * 0.25 + 13 + // + if(priv->card_8185 >= VERSION_8187S_B) + { + s32 tmp = 0; + + if(WirelessMode == WIRELESS_MODE_G) + { + bUseDefault = false; + tmp = (2 * PowerInDbm); + + if(tmp < 0) + TxPwrIdx = 0; + else if(tmp > 40) // 40 means 20 dBm. + TxPwrIdx = 40; + else + TxPwrIdx = (s8)tmp; + } + else if(WirelessMode == WIRELESS_MODE_B) + { + bUseDefault = false; + tmp = (4 * PowerInDbm) - 52; + + if(tmp < 0) + TxPwrIdx = 0; + else if(tmp > 28) // 28 means 20 dBm. + TxPwrIdx = 28; + else + TxPwrIdx = (s8)tmp; + } + } +#endif + + // + // TRUE if we want to use a default implementation. + // We shall set it to FALSE when we have exact translation formular + // for target IC. 070622, by rcnjko. + // + if(bUseDefault) + { + if(PowerInDbm < 0) + TxPwrIdx = 0; + else if(PowerInDbm > 35) + TxPwrIdx = 35; + else + TxPwrIdx = (u8)PowerInDbm; + } + + return TxPwrIdx; +} +#endif + +void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + +// int GainIdx; +// int GainSetting; + //int i; + //u8 power; + //u8 *cck_power_table; + u8 max_cck_power_level; + //u8 min_cck_power_level; + u8 max_ofdm_power_level; + u8 min_ofdm_power_level; +// u8 cck_power_level = 0xff & priv->chtxpwr[ch];//-by amy 080312 +// u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch];//-by amy 080312 + char cck_power_level = (char)(0xff & priv->chtxpwr[ch]);//+by amy 080312 + char ofdm_power_level = (char)(0xff & priv->chtxpwr_ofdm[ch]);//+by amy 080312 +#if 0 + // + // CCX 2 S31, AP control of client transmit power: + // 1. We shall not exceed Cell Power Limit as possible as we can. + // 2. Tolerance is +/- 5dB. + // 3. 802.11h Power Contraint takes higher precedence over CCX Cell Power Limit. + // + // TODO: + // 1. 802.11h power contraint + // + // 071011, by rcnjko. + // + if( priv->OpMode == RT_OP_MODE_INFRASTRUCTURE && + priv->bWithCcxCellPwr && + ch == priv->dot11CurrentChannelNumber) + { + u8 CckCellPwrIdx = DbmToTxPwrIdx(dev, WIRELESS_MODE_B, pMgntInfo->CcxCellPwr); + u8 OfdmCellPwrIdx = DbmToTxPwrIdx(dev, WIRELESS_MODE_G, pMgntInfo->CcxCellPwr); + + printk("CCX Cell Limit: %d dBm => CCK Tx power index : %d, OFDM Tx power index: %d\n", + priv->CcxCellPwr, CckCellPwrIdx, OfdmCellPwrIdx); + printk("EEPROM channel(%d) => CCK Tx power index: %d, OFDM Tx power index: %d\n", + channel, CckTxPwrIdx, OfdmTxPwrIdx); + + if(cck_power_level > CckCellPwrIdx) + cck_power_level = CckCellPwrIdx; + if(ofdm_power_level > OfdmCellPwrIdx) + ofdm_power_level = OfdmCellPwrIdx; + + printk("Altered CCK Tx power index : %d, OFDM Tx power index: %d\n", + CckTxPwrIdx, OfdmTxPwrIdx); + } +#endif +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(priv->ieee80211) && + IS_DOT11D_STATE_DONE(priv->ieee80211) ) + { + //PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(priv->ieee80211); + u8 MaxTxPwrInDbm = DOT11D_GetMaxTxPwrInDbm(priv->ieee80211, ch); + u8 CckMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_B, MaxTxPwrInDbm); + u8 OfdmMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_G, MaxTxPwrInDbm); + + //printk("Max Tx Power dBm (%d) => CCK Tx power index : %d, OFDM Tx power index: %d\n", MaxTxPwrInDbm, CckMaxPwrIdx, OfdmMaxPwrIdx); + + //printk("EEPROM channel(%d) => CCK Tx power index: %d, OFDM Tx power index: %d\n", + // ch, cck_power_level, ofdm_power_level); + + if(cck_power_level > CckMaxPwrIdx) + cck_power_level = CckMaxPwrIdx; + if(ofdm_power_level > OfdmMaxPwrIdx) + ofdm_power_level = OfdmMaxPwrIdx; + } + + //priv->CurrentCckTxPwrIdx = cck_power_level; + //priv->CurrentOfdmTxPwrIdx = ofdm_power_level; +#endif + + max_cck_power_level = 15; + max_ofdm_power_level = 25; // 12 -> 25 + min_ofdm_power_level = 10; + +#ifdef CONFIG_RTL8185B +#ifdef CONFIG_RTL818X_S + + if(cck_power_level > 35) + { + cck_power_level = 35; + } + // + // Set up CCK TXAGC. suggested by SD3 SY. + // + write_nic_byte(dev, CCK_TXAGC, (ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)cck_power_level]) ); + //printk("CCK TX power is %x\n", (ZEBRA2_CCK_OFDM_GAIN_SETTING[cck_power_level])); + force_pci_posting(dev); + mdelay(1); +#else + + /* CCK power setting */ + if(cck_power_level > max_cck_power_level) + cck_power_level = max_cck_power_level; + + cck_power_level += priv->cck_txpwr_base; + + if(cck_power_level > 35) + cck_power_level = 35; + + if(ch == 14) + cck_power_table = rtl8225z2_tx_power_cck_ch14; + else + cck_power_table = rtl8225z2_tx_power_cck; + + + for(i=0;i<8;i++){ + + power = cck_power_table[i]; + write_phy_cck(dev, 0x44 + i, power); + } + + //write_nic_byte(dev, TX_GAIN_CCK, power); + //2005.11.17, + write_nic_byte(dev, CCK_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)cck_power_level]); + + force_pci_posting(dev); + mdelay(1); +#endif +#endif + /* OFDM power setting */ +// Old: +// if(ofdm_power_level > max_ofdm_power_level) +// ofdm_power_level = 35; +// ofdm_power_level += min_ofdm_power_level; +// Latest: +/* if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level)) + ofdm_power_level = max_ofdm_power_level; + else + ofdm_power_level += min_ofdm_power_level; + + ofdm_power_level += priv->ofdm_txpwr_base; +*/ + if(ofdm_power_level > 35) + ofdm_power_level = 35; + +// rtl8185_set_anaparam2(dev,RTL8225_ANAPARAM2_ON); + + //rtl8185_set_anaparam2(dev, ANAPARM2_ASIC_ON); + + if (priv->up == 0) { + //must add these for rtl8185B down, xiong-2006-11-21 + write_phy_ofdm(dev,2,0x42); + write_phy_ofdm(dev,5,0); + write_phy_ofdm(dev,6,0x40); + write_phy_ofdm(dev,7,0); + write_phy_ofdm(dev,8,0x40); + } + + //write_nic_byte(dev, TX_GAIN_OFDM, ofdm_power_level); + //2005.11.17, +#ifdef CONFIG_RTL818X_S + write_nic_byte(dev, OFDM_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)ofdm_power_level]); +#else + write_nic_byte(dev, OFDM_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)ofdm_power_level]*2); +#endif + if(ofdm_power_level<=11) + { +// write_nic_dword(dev,PHY_ADR,0x00005c87); +// write_nic_dword(dev,PHY_ADR,0x00005c89); + write_phy_ofdm(dev,0x07,0x5c); + write_phy_ofdm(dev,0x09,0x5c); + } + if(ofdm_power_level<=17) + { +// write_nic_dword(dev,PHY_ADR,0x00005487); +// write_nic_dword(dev,PHY_ADR,0x00005489); + write_phy_ofdm(dev,0x07,0x54); + write_phy_ofdm(dev,0x09,0x54); + } + else + { +// write_nic_dword(dev,PHY_ADR,0x00005087); +// write_nic_dword(dev,PHY_ADR,0x00005089); + write_phy_ofdm(dev,0x07,0x50); + write_phy_ofdm(dev,0x09,0x50); + } + force_pci_posting(dev); + mdelay(1); + +} +#if 0 +/* switch between mode B and G */ +void rtl8225_set_mode(struct net_device *dev, short modeb) +{ + write_phy_ofdm(dev, 0x15, (modeb ? 0x0 : 0x40)); + write_phy_ofdm(dev, 0x17, (modeb ? 0x0 : 0x40)); +} +#endif + +void rtl8225z2_rf_set_chan(struct net_device *dev, short ch) +{ +/* + short gset = (priv->ieee80211->state == IEEE80211_LINKED && + ieee80211_is_54g(priv->ieee80211->current_network)) || + priv->ieee80211->iw_mode == IW_MODE_MONITOR; +*/ + rtl8225z2_SetTXPowerLevel(dev, ch); + + RF_WriteReg(dev, 0x7, rtl8225_chan[ch]); + + //YJ,add,080828, if set channel failed, write again + if((RF_ReadReg(dev, 0x7) & 0x0F80) != rtl8225_chan[ch]) + { + RF_WriteReg(dev, 0x7, rtl8225_chan[ch]); + } + + mdelay(1); + + force_pci_posting(dev); + mdelay(10); +//deleted by David : 2006/8/9 +#if 0 + write_nic_byte(dev,SIFS,0x22);// SIFS: 0x22 + + if(gset) + write_nic_byte(dev,DIFS,20); //DIFS: 20 + else + write_nic_byte(dev,DIFS,0x24); //DIFS: 36 + + if(priv->ieee80211->state == IEEE80211_LINKED && + ieee80211_is_shortslot(priv->ieee80211->current_network)) + write_nic_byte(dev,SLOT,0x9); //SLOT: 9 + + else + write_nic_byte(dev,SLOT,0x14); //SLOT: 20 (0x14) + + + if(gset){ + write_nic_byte(dev,EIFS,91 - 20); // EIFS: 91 (0x5B) + write_nic_byte(dev,CW_VAL,0x73); //CW VALUE: 0x37 + //DMESG("using G net params"); + }else{ + write_nic_byte(dev,EIFS,91 - 0x24); // EIFS: 91 (0x5B) + write_nic_byte(dev,CW_VAL,0xa5); //CW VALUE: 0x37 + //DMESG("using B net params"); + } +#endif + +} +#if 0 +void rtl8225_host_pci_init(struct net_device *dev) +{ + write_nic_word(dev, RFPinsOutput, 0x480); + + rtl8185_rf_pins_enable(dev); + + //if(priv->card_8185 == 2 && priv->enable_gpio0 ) /* version D */ + //write_nic_word(dev, RFPinsSelect, 0x88); + //else + write_nic_word(dev, RFPinsSelect, 0x88 | SW_CONTROL_GPIO); /* 0x488 | SW_CONTROL_GPIO */ + + write_nic_byte(dev, GP_ENABLE, 0); + + force_pci_posting(dev); + mdelay(200); + + write_nic_word(dev, GP_ENABLE, 0xff & (~(1<<6))); /* bit 6 is for RF on/off detection */ + + +} + +void rtl8225_host_usb_init(struct net_device *dev) +{ + write_nic_byte(dev,RFPinsSelect+1,0); + + write_nic_byte(dev,GPIO,0); + + write_nic_byte_E(dev,0x53,read_nic_byte_E(dev,0x53) | (1<<7)); + + write_nic_byte(dev,RFPinsSelect+1,4); + + write_nic_byte(dev,GPIO,0x20); + + write_nic_byte(dev,GP_ENABLE,0); + + + /* Config BB & RF */ + write_nic_word(dev, RFPinsOutput, 0x80); + + write_nic_word(dev, RFPinsSelect, 0x80); + + write_nic_word(dev, RFPinsEnable, 0x80); + + + mdelay(100); + + mdelay(1000); + +} +#endif +void rtl8225z2_rf_init(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int i; + short channel = 1; + u16 brsr; + u32 data,addr; + + priv->chan = channel; + +// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); + + + if(priv->card_type == USB) + rtl8225_host_usb_init(dev); + else + rtl8225_host_pci_init(dev); + + write_nic_dword(dev, RF_TIMING, 0x000a8008); + + brsr = read_nic_word(dev, BRSR); + + write_nic_word(dev, BRSR, 0xffff); + + + write_nic_dword(dev, RF_PARA, 0x100044); + + #if 1 //0->1 + rtl8180_set_mode(dev, EPROM_CMD_CONFIG); + write_nic_byte(dev, CONFIG3, 0x44); + rtl8180_set_mode(dev, EPROM_CMD_NORMAL); + #endif + + + rtl8185_rf_pins_enable(dev); + +// mdelay(1000); + + write_rtl8225(dev, 0x0, 0x2bf); mdelay(1); + + + write_rtl8225(dev, 0x1, 0xee0); mdelay(1); + + write_rtl8225(dev, 0x2, 0x44d); mdelay(1); + + write_rtl8225(dev, 0x3, 0x441); mdelay(1); + + + write_rtl8225(dev, 0x4, 0x8c3);mdelay(1); + + + + write_rtl8225(dev, 0x5, 0xc72);mdelay(1); +// } + + write_rtl8225(dev, 0x6, 0xe6); mdelay(1); + + write_rtl8225(dev, 0x7, ((priv->card_type == USB)? 0x82a : rtl8225_chan[channel])); mdelay(1); + + write_rtl8225(dev, 0x8, 0x3f); mdelay(1); + + write_rtl8225(dev, 0x9, 0x335); mdelay(1); + + write_rtl8225(dev, 0xa, 0x9d4); mdelay(1); + + write_rtl8225(dev, 0xb, 0x7bb); mdelay(1); + + write_rtl8225(dev, 0xc, 0x850); mdelay(1); + + + write_rtl8225(dev, 0xd, 0xcdf); mdelay(1); + + write_rtl8225(dev, 0xe, 0x2b); mdelay(1); + + write_rtl8225(dev, 0xf, 0x114); + + + mdelay(100); + + + //if(priv->card_type != USB) /* maybe not needed even for 8185 */ +// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); + + write_rtl8225(dev, 0x0, 0x1b7); + + for(i=0;i<95;i++){ + write_rtl8225(dev, 0x1, (u8)(i+1)); + + #if 0 + if(priv->phy_ver == 1) + /* version A */ + write_rtl8225(dev, 0x2, rtl8225a_rxgain[i]); + else + #endif + /* version B & C & D*/ + + write_rtl8225(dev, 0x2, rtl8225z2_rxgain[i]); + } + write_rtl8225(dev, 0x3, 0x80); + write_rtl8225(dev, 0x5, 0x4); + + write_rtl8225(dev, 0x0, 0xb7); + + write_rtl8225(dev, 0x2, 0xc4d); + + if(priv->card_type == USB){ + // force_pci_posting(dev); + mdelay(200); + + write_rtl8225(dev, 0x2, 0x44d); + + // force_pci_posting(dev); + mdelay(100); + + }//End of if(priv->card_type == USB) + /* FIXME!! rtl8187 we have to check if calibrarion + * is successful and eventually cal. again (repeat + * the two write on reg 2) + */ + // Check for calibration status, 2005.11.17, + data = read_rtl8225(dev, 6); + if (!(data&0x00000080)) + { + write_rtl8225(dev, 0x02, 0x0c4d); + force_pci_posting(dev); mdelay(200); + write_rtl8225(dev, 0x02, 0x044d); + force_pci_posting(dev); mdelay(100); + data = read_rtl8225(dev, 6); + if (!(data&0x00000080)) + { + DMESGW("RF Calibration Failed!!!!\n"); + } + } + //force_pci_posting(dev); + + mdelay(200); //200 for 8187 + + +// //if(priv->card_type != USB){ +// write_rtl8225(dev, 0x2, 0x44d); +// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); +// write_rtl8225(dev, 0x2, 0x47d); +// +// force_pci_posting(dev); +// mdelay(100); +// +// write_rtl8225(dev, 0x2, 0x44d); +// //} + + write_rtl8225(dev, 0x0, 0x2bf); + + if(priv->card_type != USB) + rtl8185_rf_pins_enable(dev); + //set up ZEBRA AGC table, 2005.11.17, + for(i=0;i<128;i++){ + data = rtl8225_agc[i]; + + addr = i + 0x80; //enable writing AGC table + write_phy_ofdm(dev, 0xb, data); + + mdelay(1); + write_phy_ofdm(dev, 0xa, addr); + + mdelay(1); + } +#if 0 + for(i=0;i<128;i++){ + write_phy_ofdm(dev, 0xb, rtl8225_agc[i]); + + mdelay(1); + write_phy_ofdm(dev, 0xa, (u8)i+ 0x80); + + mdelay(1); + } +#endif + + force_pci_posting(dev); + mdelay(1); + + write_phy_ofdm(dev, 0x0, 0x1); mdelay(1); + write_phy_ofdm(dev, 0x1, 0x2); mdelay(1); + write_phy_ofdm(dev, 0x2, ((priv->card_type == USB)? 0x42 : 0x62)); mdelay(1); + write_phy_ofdm(dev, 0x3, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x4, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x5, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x6, 0x40); mdelay(1); + write_phy_ofdm(dev, 0x7, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x8, 0x40); mdelay(1); + write_phy_ofdm(dev, 0x9, 0xfe); mdelay(1); + + write_phy_ofdm(dev, 0xa, 0x8); mdelay(1); + + //write_phy_ofdm(dev, 0x18, 0xef); + // } + //} + write_phy_ofdm(dev, 0xb, 0x80); mdelay(1); + + write_phy_ofdm(dev, 0xc, 0x1);mdelay(1); + + + //if(priv->card_type != USB) + write_phy_ofdm(dev, 0xd, 0x43); + + write_phy_ofdm(dev, 0xe, 0xd3);mdelay(1); + + + #if 0 + if(priv->card_8185 == 1){ + if(priv->card_8185_Bversion) + write_phy_ofdm(dev, 0xf, 0x20);/*ver B*/ + else + write_phy_ofdm(dev, 0xf, 0x28);/*ver C*/ + }else{ + #endif + write_phy_ofdm(dev, 0xf, 0x38);mdelay(1); +/*ver D & 8187*/ +// } + +// if(priv->card_8185 == 1 && priv->card_8185_Bversion) +// write_phy_ofdm(dev, 0x10, 0x04);/*ver B*/ +// else + write_phy_ofdm(dev, 0x10, 0x84);mdelay(1); +/*ver C & D & 8187*/ + + write_phy_ofdm(dev, 0x11, 0x07);mdelay(1); +/*agc resp time 700*/ + + +// if(priv->card_8185 == 2){ + /* Ver D & 8187*/ + write_phy_ofdm(dev, 0x12, 0x20);mdelay(1); + + write_phy_ofdm(dev, 0x13, 0x20);mdelay(1); + +#if 0 + }else{ + /* Ver B & C*/ + write_phy_ofdm(dev, 0x12, 0x0); + write_phy_ofdm(dev, 0x13, 0x0); + } +#endif + write_phy_ofdm(dev, 0x14, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x15, 0x40); mdelay(1); + write_phy_ofdm(dev, 0x16, 0x0); mdelay(1); + write_phy_ofdm(dev, 0x17, 0x40); mdelay(1); + +// if (priv->card_type == USB) +// write_phy_ofdm(dev, 0x18, 0xef); + + write_phy_ofdm(dev, 0x18, 0xef);mdelay(1); + + + write_phy_ofdm(dev, 0x19, 0x19); mdelay(1); + write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1); + write_phy_ofdm(dev, 0x1b, 0x15);mdelay(1); + + write_phy_ofdm(dev, 0x1c, 0x4);mdelay(1); + + write_phy_ofdm(dev, 0x1d, 0xc5);mdelay(1); //2005.11.17, + + write_phy_ofdm(dev, 0x1e, 0x95);mdelay(1); + + write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1); + +// } + + write_phy_ofdm(dev, 0x20, 0x1f);mdelay(1); + + write_phy_ofdm(dev, 0x21, 0x17);mdelay(1); + + write_phy_ofdm(dev, 0x22, 0x16);mdelay(1); + +// if(priv->card_type != USB) + write_phy_ofdm(dev, 0x23, 0x80);mdelay(1); //FIXME maybe not needed // <> + + write_phy_ofdm(dev, 0x24, 0x46); mdelay(1); + write_phy_ofdm(dev, 0x25, 0x00); mdelay(1); + write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); + + write_phy_ofdm(dev, 0x27, 0x88); mdelay(1); + + + // <> Set init. gain to m74dBm. + + rtl8225z2_set_gain(dev,4); + + write_phy_cck(dev, 0x0, 0x98); mdelay(1); + write_phy_cck(dev, 0x3, 0x20); mdelay(1); + write_phy_cck(dev, 0x4, 0x7e); mdelay(1); + write_phy_cck(dev, 0x5, 0x12); mdelay(1); + write_phy_cck(dev, 0x6, 0xfc); mdelay(1); + + write_phy_cck(dev, 0x7, 0x78);mdelay(1); + /* Ver C & D & 8187*/ + + write_phy_cck(dev, 0x8, 0x2e);mdelay(1); + + write_phy_cck(dev, 0x10, ((priv->card_type == USB) ? 0x9b: 0x93)); mdelay(1); + write_phy_cck(dev, 0x11, 0x88); mdelay(1); + write_phy_cck(dev, 0x12, 0x47); mdelay(1); +#if 0 + if(priv->card_8185 == 1 && priv->card_8185_Bversion) + write_phy_cck(dev, 0x13, 0x98); /* Ver B */ + else +#endif + write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ + + write_phy_cck(dev, 0x19, 0x0); + write_phy_cck(dev, 0x1a, 0xa0); + write_phy_cck(dev, 0x1b, 0x8); + write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ + + write_phy_cck(dev, 0x41, 0x8d);mdelay(1); + + + write_phy_cck(dev, 0x42, 0x15); mdelay(1); + write_phy_cck(dev, 0x43, 0x18); mdelay(1); + + + write_phy_cck(dev, 0x44, 0x36); mdelay(1); + write_phy_cck(dev, 0x45, 0x35); mdelay(1); + write_phy_cck(dev, 0x46, 0x2e); mdelay(1); + write_phy_cck(dev, 0x47, 0x25); mdelay(1); + write_phy_cck(dev, 0x48, 0x1c); mdelay(1); + write_phy_cck(dev, 0x49, 0x12); mdelay(1); + write_phy_cck(dev, 0x4a, 0x9); mdelay(1); + write_phy_cck(dev, 0x4b, 0x4); mdelay(1); + write_phy_cck(dev, 0x4c, 0x5);mdelay(1); + + + write_nic_byte(dev, 0x5b, 0x0d); mdelay(1); + + + +// <> +// // TESTR 0xb 8187 +// write_phy_cck(dev, 0x10, 0x93);// & 0xfb); +// +// //if(priv->card_type != USB){ +// write_phy_ofdm(dev, 0x2, 0x62); +// write_phy_ofdm(dev, 0x6, 0x0); +// write_phy_ofdm(dev, 0x8, 0x0); +// //} + + rtl8225z2_SetTXPowerLevel(dev, channel); +#ifdef CONFIG_RTL818X_S + write_phy_cck(dev, 0x11, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ +#else + write_phy_cck(dev, 0x10, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ +#endif + write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* Rx ant A, 0x10 for B */ + + rtl8185_tx_antenna(dev, 0x3); /* TX ant A, 0x0 for B */ + + /* switch to high-speed 3-wire + * last digit. 2 for both cck and ofdm + */ + if(priv->card_type == USB) + write_nic_dword(dev, 0x94, 0x3dc00002); + else{ + write_nic_dword(dev, 0x94, 0x15c00002); + rtl8185_rf_pins_enable(dev); + } + +// if(priv->card_type != USB) +// rtl8225_set_gain(dev, 4); /* FIXME this '1' is random */ // <> +// rtl8225_set_mode(dev, 1); /* FIXME start in B mode */ // <> +// +// /* make sure is waken up! */ +// write_rtl8225(dev,0x4, 0x9ff); +// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); +// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); + + rtl8225_rf_set_chan(dev, priv->chan); + + //write_nic_word(dev,BRSR,brsr); + + //rtl8225z2_rf_set_mode(dev); +} + +void rtl8225z2_rf_set_mode(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + if(priv->ieee80211->mode == IEEE_A) + { + write_rtl8225(dev, 0x5, 0x1865); + write_nic_dword(dev, RF_PARA, 0x10084); + write_nic_dword(dev, RF_TIMING, 0xa8008); + write_phy_ofdm(dev, 0x0, 0x0); + write_phy_ofdm(dev, 0xa, 0x6); + write_phy_ofdm(dev, 0xb, 0x99); + write_phy_ofdm(dev, 0xf, 0x20); + write_phy_ofdm(dev, 0x11, 0x7); + + rtl8225z2_set_gain(dev,4); + + write_phy_ofdm(dev,0x15, 0x40); + write_phy_ofdm(dev,0x17, 0x40); + + write_nic_dword(dev, 0x94,0x10000000); + }else{ + + write_rtl8225(dev, 0x5, 0x1864); + write_nic_dword(dev, RF_PARA, 0x10044); + write_nic_dword(dev, RF_TIMING, 0xa8008); + write_phy_ofdm(dev, 0x0, 0x1); + write_phy_ofdm(dev, 0xa, 0x6); + write_phy_ofdm(dev, 0xb, 0x99); + write_phy_ofdm(dev, 0xf, 0x20); + write_phy_ofdm(dev, 0x11, 0x7); + + rtl8225z2_set_gain(dev,4); + + write_phy_ofdm(dev,0x15, 0x40); + write_phy_ofdm(dev,0x17, 0x40); + + write_nic_dword(dev, 0x94,0x04000002); + } +} + +//lzm mod 080826 +//#define MAX_DOZE_WAITING_TIMES_85B 64 +//#define MAX_POLLING_24F_TIMES_87SE 5 +#define MAX_DOZE_WAITING_TIMES_85B 20 +#define MAX_POLLING_24F_TIMES_87SE 10 +#define LPS_MAX_SLEEP_WAITING_TIMES_87SE 5 + +bool +SetZebraRFPowerState8185( + struct net_device *dev, + RT_RF_POWER_STATE eRFPowerState + ) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u8 btCR9346, btConfig3; + bool bActionAllowed= true, bTurnOffBB = true;//lzm mod 080826 + //u32 DWordContent; + u8 u1bTmp; + int i; + //u16 u2bTFPC = 0; + bool bResult = true; + u8 QueueID; + + if(priv->SetRFPowerStateInProgress == true) + return false; + + priv->SetRFPowerStateInProgress = true; + + // enable EEM0 and EEM1 in 9346CR + btCR9346 = read_nic_byte(dev, CR9346); + write_nic_byte(dev, CR9346, (btCR9346|0xC0) ); + // enable PARM_En in Config3 + btConfig3 = read_nic_byte(dev, CONFIG3); + write_nic_byte(dev, CONFIG3, (btConfig3|CONFIG3_PARM_En) ); + + switch( priv->rf_chip ) + { + case RF_ZEBRA2: + switch( eRFPowerState ) + { + case eRfOn: + RF_WriteReg(dev,0x4,0x9FF); + + write_nic_dword(dev, ANAPARAM, ANAPARM_ON); + write_nic_dword(dev, ANAPARAM2, ANAPARM2_ON); + + write_nic_byte(dev, CONFIG4, priv->RFProgType); + + //Follow 87B, Isaiah 2007-04-27 + u1bTmp = read_nic_byte(dev, 0x24E); + write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5|BIT6))) );// 070124 SD1 Alex: turn on CCK and OFDM. + break; + + case eRfSleep: + break; + + case eRfOff: + break; + + default: + bResult = false; + break; + } + break; + + case RF_ZEBRA4: + switch( eRFPowerState ) + { + case eRfOn: + //printk("===================================power on@jiffies:%d\n",jiffies); + write_nic_word(dev, 0x37C, 0x00EC); + + //turn on AFE + write_nic_byte(dev, 0x54, 0x00); + write_nic_byte(dev, 0x62, 0x00); + + //lzm mod 080826 + //turn on RF + //RF_WriteReg(dev, 0x0, 0x009f); //mdelay(1); + //RF_WriteReg(dev, 0x4, 0x0972); //mdelay(1); + RF_WriteReg(dev, 0x0, 0x009f); udelay(500); + RF_WriteReg(dev, 0x4, 0x0972); udelay(500); + //turn on RF again, suggested by SD3 stevenl. + RF_WriteReg(dev, 0x0, 0x009f); udelay(500); + RF_WriteReg(dev, 0x4, 0x0972); udelay(500); + + //turn on BB +// write_nic_dword(dev, PhyAddr, 0x4090); //ofdm 10=00 +// write_nic_dword(dev, PhyAddr, 0x4092); //ofdm 12=00 + write_phy_ofdm(dev,0x10,0x40); + write_phy_ofdm(dev,0x12,0x40); + //Avoid power down at init time. + write_nic_byte(dev, CONFIG4, priv->RFProgType); + + u1bTmp = read_nic_byte(dev, 0x24E); + write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5|BIT6))) ); + + break; + + case eRfSleep: + // Make sure BusyQueue is empty befor turn off RFE pwoer. + //printk("===================================power sleep@jiffies:%d\n",jiffies); + + for(QueueID = 0, i = 0; QueueID < 6; ) + { + if(get_curr_tx_free_desc(dev,QueueID) == priv->txringcount) + { + QueueID++; + continue; + } +#if 0 //reserved amy + else if(priv->NdisAdapter.CurrentPowerState != NdisDeviceStateD0) + { + RT_TRACE(COMP_POWER, DBG_LOUD, ("eRfSleep: %d times TcbBusyQueue[%d] !=0 but lower power state!\n", (pMgntInfo->TxPollingTimes+1), QueueID)); + break; + } +#endif + else//lzm mod 080826 + { + priv->TxPollingTimes ++; + if(priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) + { + //RT_TRACE(COMP_POWER, DBG_WARNING, ("\n\n\n SetZebraRFPowerState8185B():eRfSleep: %d times TcbBusyQueue[%d] != 0 !!!\n\n\n", LPS_MAX_SLEEP_WAITING_TIMES_87SE, QueueID)); + bActionAllowed=false; + break; + } + else + { + udelay(10); // Windows may delay 3~16ms actually. + //RT_TRACE(COMP_POWER, DBG_LOUD, ("eRfSleep: %d times TcbBusyQueue[%d] !=0 before doze!\n", (pMgntInfo->TxPollingTimes), QueueID)); + } + } + + //lzm del 080826 + //if(i >= MAX_DOZE_WAITING_TIMES_85B) + //{ + //printk("\n\n\n SetZebraRFPowerState8185B(): %d times BusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_85B, QueueID); + //break; + //} + } + + if(bActionAllowed)//lzm add 080826 + { + //turn off BB RXIQ matrix to cut off rx signal +// write_nic_dword(dev, PhyAddr, 0x0090); //ofdm 10=00 +// write_nic_dword(dev, PhyAddr, 0x0092); //ofdm 12=00 + write_phy_ofdm(dev,0x10,0x00); + write_phy_ofdm(dev,0x12,0x00); + //turn off RF + RF_WriteReg(dev, 0x4, 0x0000); //mdelay(1); + RF_WriteReg(dev, 0x0, 0x0000); //mdelay(1); + //turn off AFE except PLL + write_nic_byte(dev, 0x62, 0xff); + write_nic_byte(dev, 0x54, 0xec); +// mdelay(10); + +#if 1 + mdelay(1); + { + int i = 0; + while (true) + { + u8 tmp24F = read_nic_byte(dev, 0x24f); + if ((tmp24F == 0x01) || (tmp24F == 0x09)) + { + bTurnOffBB = true; + break; + } + else//lzm mod 080826 + { + udelay(10); + i++; + priv->TxPollingTimes++; + + if(priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) + { + //RT_TRACE(COMP_POWER, DBG_WARNING, ("\n\n\n SetZebraRFPowerState8185B(): eRfOff: %d times Rx Mac0x24F=0x%x !!!\n\n\n", i, u1bTmp24F)); + bTurnOffBB=false; + break; + } + else + { + udelay(10);// Windows may delay 3~16ms actually. + //RT_TRACE(COMP_POWER, DBG_LOUD,("(%d)eRfSleep- u1bTmp24F= 0x%X\n", i, u1bTmp24F)); + + } + } + + //lzm del 080826 + //if (i > MAX_POLLING_24F_TIMES_87SE) + // break; + } + } +#endif + if (bTurnOffBB)//lzm mod 080826 + { + //turn off BB + u1bTmp = read_nic_byte(dev, 0x24E); + write_nic_byte(dev, 0x24E, (u1bTmp|BIT5|BIT6)); + + //turn off AFE PLL + //write_nic_byte(dev, 0x54, 0xec); + //write_nic_word(dev, 0x37C, 0x00ec); + write_nic_byte(dev, 0x54, 0xFC); //[ECS] FC-> EC->FC, asked by SD3 Stevenl + write_nic_word(dev, 0x37C, 0x00FC);//[ECS] FC-> EC->FC, asked by SD3 Stevenl + } + } + break; + + case eRfOff: + // Make sure BusyQueue is empty befor turn off RFE pwoer. + //printk("===================================power off@jiffies:%d\n",jiffies); + for(QueueID = 0, i = 0; QueueID < 6; ) + { + if(get_curr_tx_free_desc(dev,QueueID) == priv->txringcount) + { + QueueID++; + continue; + } +#if 0 + else if(Adapter->NdisAdapter.CurrentPowerState != NdisDeviceStateD0) + { + RT_TRACE(COMP_POWER, DBG_LOUD, ("%d times TcbBusyQueue[%d] !=0 but lower power state!\n", (i+1), QueueID)); + break; + } +#endif + else + { + udelay(10); + i++; + } + + if(i >= MAX_DOZE_WAITING_TIMES_85B) + { + //printk("\n\n\n SetZebraRFPowerState8185B(): %d times BusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_85B, QueueID); + break; + } + } + + //turn off BB RXIQ matrix to cut off rx signal +// write_nic_dword(dev, PhyAddr, 0x0090); //ofdm 10=00 +// write_nic_dword(dev, PhyAddr, 0x0092); //ofdm 12=00 + write_phy_ofdm(dev,0x10,0x00); + write_phy_ofdm(dev,0x12,0x00); + //turn off RF + RF_WriteReg(dev, 0x4, 0x0000); //mdelay(1); + RF_WriteReg(dev, 0x0, 0x0000); //mdelay(1); + //turn off AFE except PLL + write_nic_byte(dev, 0x62, 0xff); + write_nic_byte(dev, 0x54, 0xec); +// mdelay(10); +#if 1 + mdelay(1); + { + int i = 0; + while (true) + { + u8 tmp24F = read_nic_byte(dev, 0x24f); + if ((tmp24F == 0x01) || (tmp24F == 0x09)) + { + bTurnOffBB = true; + break; + } + else + { + bTurnOffBB = false; + udelay(10); + i++; + } + if (i > MAX_POLLING_24F_TIMES_87SE) + break; + } + } +#endif + if (bTurnOffBB)//lzm mod 080826 + { + + //turn off BB + u1bTmp = read_nic_byte(dev, 0x24E); + write_nic_byte(dev, 0x24E, (u1bTmp|BIT5|BIT6)); + //turn off AFE PLL (80M) + //write_nic_byte(dev, 0x54, 0xec); + //write_nic_word(dev, 0x37C, 0x00ec); + write_nic_byte(dev, 0x54, 0xFC); //[ECS] FC-> EC->FC, asked by SD3 Stevenl + write_nic_word(dev, 0x37C, 0x00FC); //[ECS] FC-> EC->FC, asked by SD3 Stevenl + } + + break; + + default: + bResult = false; + printk("SetZebraRFPowerState8185(): unknow state to set: 0x%X!!!\n", eRFPowerState); + break; + } + break; + } + + // disable PARM_En in Config3 + btConfig3 &= ~(CONFIG3_PARM_En); + write_nic_byte(dev, CONFIG3, btConfig3); + // disable EEM0 and EEM1 in 9346CR + btCR9346 &= ~(0xC0); + write_nic_byte(dev, CR9346, btCR9346); + + if(bResult && bActionAllowed)//lzm mod 080826 + { + // Update current RF state variable. + priv->eRFPowerState = eRFPowerState; +#if 0 + switch(priv->eRFPowerState) + { + case eRfOff: + // + //If Rf off reason is from IPS, Led should blink with no link, by Maddest 071015 + // + if(priv->RfOffReason==RF_CHANGE_BY_IPS ) + { + Adapter->HalFunc.LedControlHandler(Adapter,LED_CTL_NO_LINK); + } + else + { + // Turn off LED if RF is not ON. + Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_POWER_OFF); + } + break; + + case eRfOn: + // Turn on RF we are still linked, which might happen when + // we quickly turn off and on HW RF. 2006.05.12, by rcnjko. + if( pMgntInfo->bMediaConnect == TRUE ) + { + Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_LINK); + } + break; + + default: + // do nothing. + break; + } +#endif + + } + + priv->SetRFPowerStateInProgress = false; + + return (bResult && bActionAllowed) ; +} +void rtl8225z4_rf_sleep(struct net_device *dev) +{ + // + // Turn off RF power. + // + //printk("=========>%s()\n", __FUNCTION__); + MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS); + //mdelay(2); //FIXME +} +void rtl8225z4_rf_wakeup(struct net_device *dev) +{ + // + // Turn on RF power. + // + //printk("=========>%s()\n", __FUNCTION__); + MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS); +} +#endif + diff --git a/drivers/staging/rtl8187se/r8180_rtl8255.c b/drivers/staging/rtl8187se/r8180_rtl8255.c new file mode 100644 index 0000000..1a62444 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_rtl8255.c @@ -0,0 +1,1838 @@ +/* + This is part of the rtl8180-sa2400 driver + released under the GPL (See file COPYING for details). + Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> + + This files contains programming code for the rtl8255 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + +#define BAND_A 1 +#define BAND_BG 2 + +#include "r8180.h" +#include "r8180_hw.h" +#include "r8180_rtl8255.h" + +u32 rtl8255_chan[] = { + 0, //dummy channel 0 + 0x13, //1 + 0x115, //2 + 0x217, //3 + 0x219, //4 + 0x31b, //5 + 0x41d, //6 + 0x41f, //7 + 0x621, //8 + 0x623, //9 + 0x625, //10 + 0x627, //11 + 0x829, //12 + 0x82b, //13 + 0x92f, // 14 +}; + +static short rtl8255_gain_2G[]={ + 0x33, 0x17, 0x7c, 0xc5,//-78 + 0x43, 0x17, 0x7a, 0xc5,//-74 + 0x53, 0x17, 0x78, 0xc5,//-70 + 0x63, 0x17, 0x76, 0xc5,//-66 +}; + + +static short rtl8255_agc[]={ + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + + 0x1, 0x1, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, + 0x6, 0x6, 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xa, 0xa, + 0xb, 0xb, 0xc, 0xc, 0xd, 0xd, 0xe, 0xe, 0xf, 0xf, + + 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, + 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, + 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, + 0x1f, 0x1f, + + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, + 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, + 0x2a, 0x2a, + + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a + +}; + +void rtl8255_set_gain(struct net_device *dev, short gain) +{ + +// struct r8180_priv *priv = ieee80211_priv(dev); + + write_phy_ofdm(dev, 0x0d, rtl8255_gain_2G[gain * 4]); + write_phy_ofdm(dev, 0x23, rtl8255_gain_2G[gain * 4 + 1]); + write_phy_ofdm(dev, 0x1b, rtl8255_gain_2G[gain * 4 + 2]); + write_phy_ofdm(dev, 0x1d, rtl8255_gain_2G[gain * 4 + 3]); + //rtl8225_set_gain_usb(dev, gain); +} + +void write_rtl8255_reg0c(struct net_device *dev, u32 d1, u32 d2, u32 d3, u32 d4, +u32 d5, u32 d6, u32 d7, u32 d8, u32 d9, u32 d10) +{ + int i,j; + u16 out,select; + u8 bit; + u32 bangdata; +// struct r8180_priv *priv = ieee80211_priv(dev); + + write_nic_word(dev,RFPinsEnable, + (read_nic_word(dev,RFPinsEnable) | 0x7)); + + select = read_nic_word(dev, RFPinsSelect); + + write_nic_word(dev, RFPinsSelect, select | 0x7 | SW_CONTROL_GPIO); + + out = read_nic_word(dev, RFPinsOutput) & 0xfff3; + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); + + force_pci_posting(dev); + udelay(2); + + write_nic_word(dev, RFPinsOutput, out); + + force_pci_posting(dev); + udelay(2); + + for(j=0;j<10;j++) + { + switch(j) + { + case 9: + bangdata = d10 | 0x0c; + break; + case 8: + bangdata = d9; + break; + case 7: + bangdata = d8; + break; + case 6: + bangdata = d7; + break; + case 5: + bangdata = d6; + break; + case 4: + bangdata = d5; + break; + case 3: + bangdata = d4; + break; + case 2: + bangdata = d3; + break; + case 1: + bangdata = d2; + break; + case 0: + bangdata = d1; + break; + default: + bangdata=0xbadc0de; /* avoid gcc complaints */ + break; + } + + for(i=31; i>=0;i--){ + + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out); + force_pci_posting(dev); + udelay(1); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + force_pci_posting(dev); + udelay(1); + // write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + i--; + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + force_pci_posting(dev); + udelay(1); + // write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out); + force_pci_posting(dev); + udelay(1); + } + } + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); + force_pci_posting(dev); + udelay(10); + +// write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); + write_nic_word(dev, RFPinsSelect, select | SW_CONTROL_GPIO); +// rtl8185_rf_pins_enable(dev); + +} + +void write_rtl8255(struct net_device *dev, u8 adr, u16 data) +{ + int i; + u16 out,select; + u8 bit; + u32 bangdata = (data << 4) | (adr & 0xf); +// struct r8180_priv *priv = ieee80211_priv(dev); + + out = read_nic_word(dev, RFPinsOutput) & 0xfff3; + + write_nic_word(dev,RFPinsEnable, + (read_nic_word(dev,RFPinsEnable) | 0x7)); + + select = read_nic_word(dev, RFPinsSelect); + + write_nic_word(dev, RFPinsSelect, select | 0x7 | SW_CONTROL_GPIO); + + force_pci_posting(dev); + udelay(10); + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); + + force_pci_posting(dev); + udelay(2); + + write_nic_word(dev, RFPinsOutput, out); + + force_pci_posting(dev); + udelay(10); + + + for(i=15; i>=0;i--){ + + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + i--; + bit = (bangdata & (1<<i)) >> i; + + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); + write_nic_word(dev, RFPinsOutput, bit | out); + } + + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); + + force_pci_posting(dev); + udelay(10); + + write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); + write_nic_word(dev, RFPinsSelect, select | SW_CONTROL_GPIO); + + rtl8185_rf_pins_enable(dev); +} + +void rtl8255_rf_close(struct net_device *dev) +{ + +// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF); +// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF); +} + +void rtl8255_SetTXPowerLevel(struct net_device *dev, short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + u8 cck_power_level = 0xff & priv->chtxpwr[ch]; + u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch]; + write_nic_byte(dev, TX_GAIN_OFDM, ofdm_power_level); + write_nic_byte(dev, TX_GAIN_CCK, cck_power_level); + force_pci_posting(dev); + mdelay(1); + //write_nic_byte(dev, TX_AGC_CONTROL,4); +} +#if 0 +/* switch between mode B and G */ +void rtl8255_set_mode(struct net_device *dev, short modeb) +{ + write_phy_ofdm(dev, 0x15, (modeb ? 0x0 : 0x40)); + write_phy_ofdm(dev, 0x17, (modeb ? 0x0 : 0x40)); +} +#endif + +void rtl8255_rf_set_chan(struct net_device *dev, short ch) +{ + //write_rtl8225(dev, 0x7, rtl8225_chan[1]); + write_rtl8255(dev, 0x5, 0x65); + write_rtl8255(dev, 0x6, rtl8255_chan[ch]); + write_rtl8255(dev, 0x7, 0x7c); + write_rtl8255(dev, 0x8, 0x6); + + + force_pci_posting(dev); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); +// rtl8225_set_mode_B(dev); + + rtl8255_SetTXPowerLevel(dev, ch); + /* FIXME FIXME FIXME */ + + #if 0 + write_nic_byte(dev,DIFS,0xe); //DIFS + write_nic_byte(dev,SLOT,0x14); //SLOT + write_nic_byte(dev,EIFS,0x5b); // EIFS + //write_nic_byte(dev,0xbc,0); //CW CONFIG + write_nic_byte(dev,0xbd,0xa4); //CW VALUE + //write_nic_byte(dev,TX_AGC_CONTROL,4); + //write_nic_byte(dev, 0x9d,7); +//Apr 20 13:25:03 localhost kernel: w8. 409d<-7 // CCK AGC + /*write_nic_word(dev,0x84,0x488); + write_nic_byte(dev,0x91,0x3e); + write_nic_byte(dev,0x90,0x30); + write_nic_word(dev,0x84,0x488); + write_nic_byte(dev,0x91,0x3e); + write_nic_byte(dev,0x90,0x20); + */ + //mdelay(100); + #endif +} + +void rtl8255_init_BGband(struct net_device *dev) +{ + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804187cf, 0x40000027, + 0x92402ac0, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc00); + write_rtl8255(dev, 0x4, 0xe00); + write_rtl8255(dev, 0x4, 0xc00); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x800); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa00); + write_rtl8255(dev, 0x4, 0x800); + write_rtl8255(dev, 0x4, 0x400); + write_rtl8255(dev, 0x3, 0x26); + write_rtl8255(dev, 0x2, 0x27); + write_rtl8255(dev, 0x4, 0x600); + write_rtl8255(dev, 0x4, 0x400); + write_rtl8255(dev, 0x4, 0x400); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x600); + write_rtl8255(dev, 0x4, 0x400); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804187ce, 0x80000027, + 0x92402ac0, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc01); + write_rtl8255(dev, 0x4, 0xe01); + write_rtl8255(dev, 0x4, 0xc01); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x801); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa01); + write_rtl8255(dev, 0x4, 0x801); + write_rtl8255(dev, 0x4, 0x401); + write_rtl8255(dev, 0x3, 0x26); + write_rtl8255(dev, 0x2, 0x27); + write_rtl8255(dev, 0x4, 0x601); + write_rtl8255(dev, 0x4, 0x401); + write_rtl8255(dev, 0x4, 0x401); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x601); + write_rtl8255(dev, 0x4, 0x401); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80418bdf, 0x40000027, + 0x92402ac4, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc02); + write_rtl8255(dev, 0x4, 0xe02); + write_rtl8255(dev, 0x4, 0xc02); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x802); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa02); + write_rtl8255(dev, 0x4, 0x802); + write_rtl8255(dev, 0x4, 0x402); + write_rtl8255(dev, 0x3, 0x26); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x602); + write_rtl8255(dev, 0x4, 0x402); + write_rtl8255(dev, 0x4, 0x402); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x602); + write_rtl8255(dev, 0x4, 0x402); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80418bbf, 0x40000027, + 0x92402ac4, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc03); + write_rtl8255(dev, 0x4, 0xe03); + write_rtl8255(dev, 0x4, 0xc03); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x803); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa03); + write_rtl8255(dev, 0x4, 0x803); + write_rtl8255(dev, 0x4, 0x403); + write_rtl8255(dev, 0x3, 0x26); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x603); + write_rtl8255(dev, 0x4, 0x403); + write_rtl8255(dev, 0x4, 0x403); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x603); + write_rtl8255(dev, 0x4, 0x403); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80418b9f, 0x40000027, + 0x92402ac8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc04); + write_rtl8255(dev, 0x4, 0xe04); + write_rtl8255(dev, 0x4, 0xc04); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x804); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa04); + write_rtl8255(dev, 0x4, 0x804); + write_rtl8255(dev, 0x4, 0x404); + write_rtl8255(dev, 0x3, 0x26); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x604); + write_rtl8255(dev, 0x4, 0x404); + write_rtl8255(dev, 0x4, 0x404); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x604); + write_rtl8255(dev, 0x4, 0x404); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804183df, 0x40000027, + 0x92402ac8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc05); + write_rtl8255(dev, 0x4, 0xe05); + write_rtl8255(dev, 0x4, 0xc05); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x805); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa05); + write_rtl8255(dev, 0x4, 0x805); + write_rtl8255(dev, 0x4, 0x405); + write_rtl8255(dev, 0x3, 0x26); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x605); + write_rtl8255(dev, 0x4, 0x405); + write_rtl8255(dev, 0x4, 0x405); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x605); + write_rtl8255(dev, 0x4, 0x405); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804183cf, 0x27, + 0x92402acc, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc06); + write_rtl8255(dev, 0x4, 0xe06); + write_rtl8255(dev, 0x4, 0xc06); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x806); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa06); + write_rtl8255(dev, 0x4, 0x806); + write_rtl8255(dev, 0x4, 0x406); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x606); + write_rtl8255(dev, 0x4, 0x406); + write_rtl8255(dev, 0x4, 0x406); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x606); + write_rtl8255(dev, 0x4, 0x406); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804183af, 0x27, + 0x92402acc, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc07); + write_rtl8255(dev, 0x4, 0xe07); + write_rtl8255(dev, 0x4, 0xc07); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x807); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa07); + write_rtl8255(dev, 0x4, 0x807); + write_rtl8255(dev, 0x4, 0x407); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x607); + write_rtl8255(dev, 0x4, 0x407); + write_rtl8255(dev, 0x4, 0x407); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x607); + write_rtl8255(dev, 0x4, 0x407); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804083d7, 0x40000027, + 0x92402ad0, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc08); + write_rtl8255(dev, 0x4, 0xe08); + write_rtl8255(dev, 0x4, 0xc08); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x808); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa08); + write_rtl8255(dev, 0x4, 0x808); + write_rtl8255(dev, 0x4, 0x408); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x608); + write_rtl8255(dev, 0x4, 0x408); + write_rtl8255(dev, 0x4, 0x408); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x608); + write_rtl8255(dev, 0x4, 0x408); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804083c7, 0x27, + 0x92402ad0, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc09); + write_rtl8255(dev, 0x4, 0xe09); + write_rtl8255(dev, 0x4, 0xc09); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x809); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa09); + write_rtl8255(dev, 0x4, 0x809); + write_rtl8255(dev, 0x4, 0x409); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x609); + write_rtl8255(dev, 0x4, 0x409); + write_rtl8255(dev, 0x4, 0x409); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x609); + write_rtl8255(dev, 0x4, 0x409); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043d7, 0x40000027, + 0x92402ad4, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc0a); + write_rtl8255(dev, 0x4, 0xe0a); + write_rtl8255(dev, 0x4, 0xc0a); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x80a); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa0a); + write_rtl8255(dev, 0x4, 0x80a); + write_rtl8255(dev, 0x4, 0x40a); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x60a); + write_rtl8255(dev, 0x4, 0x40a); + write_rtl8255(dev, 0x4, 0x40a); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x60a); + write_rtl8255(dev, 0x4, 0x40a); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043d7, 0x40000027, + 0x92402ad4, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc0b); + write_rtl8255(dev, 0x4, 0xe0b); + write_rtl8255(dev, 0x4, 0xc0b); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x80b); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa0b); + write_rtl8255(dev, 0x4, 0x80b); + write_rtl8255(dev, 0x4, 0x40b); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x60b); + write_rtl8255(dev, 0x4, 0x40b); + write_rtl8255(dev, 0x4, 0x40b); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x60b); + write_rtl8255(dev, 0x4, 0x40b); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043c7, 0x27, + 0x92402ad8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc0c); + write_rtl8255(dev, 0x4, 0xe0c); + write_rtl8255(dev, 0x4, 0xc0c); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x80c); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa0c); + write_rtl8255(dev, 0x4, 0x80c); + write_rtl8255(dev, 0x4, 0x40c); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x60c); + write_rtl8255(dev, 0x4, 0x40c); + write_rtl8255(dev, 0x4, 0x40c); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x60c); + write_rtl8255(dev, 0x4, 0x40c); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043a7, 0x27, + 0x92402ad8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc0d); + write_rtl8255(dev, 0x4, 0xe0d); + write_rtl8255(dev, 0x4, 0xc0d); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x80d); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa0d); + write_rtl8255(dev, 0x4, 0x80d); + write_rtl8255(dev, 0x4, 0x40d); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x60d); + write_rtl8255(dev, 0x4, 0x40d); + write_rtl8255(dev, 0x4, 0x40d); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x60d); + write_rtl8255(dev, 0x4, 0x40d); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404387, 0x27, + 0x92402aa8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc0e); + write_rtl8255(dev, 0x4, 0xe0e); + write_rtl8255(dev, 0x4, 0xc0e); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x80e); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa0e); + write_rtl8255(dev, 0x4, 0x80e); + write_rtl8255(dev, 0x4, 0x40e); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x60e); + write_rtl8255(dev, 0x4, 0x40e); + write_rtl8255(dev, 0x4, 0x40e); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x60e); + write_rtl8255(dev, 0x4, 0x40e); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804041c7, 0x27, + 0x92402aa8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc0f); + write_rtl8255(dev, 0x4, 0xe0f); + write_rtl8255(dev, 0x4, 0xc0f); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x80f); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa0f); + write_rtl8255(dev, 0x4, 0x80f); + write_rtl8255(dev, 0x4, 0x40f); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x60f); + write_rtl8255(dev, 0x4, 0x40f); + write_rtl8255(dev, 0x4, 0x40f); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x60f); + write_rtl8255(dev, 0x4, 0x40f); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804041a7, 0x27, + 0x92402aac, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc10); + write_rtl8255(dev, 0x4, 0xe10); + write_rtl8255(dev, 0x4, 0xc10); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x810); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa10); + write_rtl8255(dev, 0x4, 0x810); + write_rtl8255(dev, 0x4, 0x410); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x610); + write_rtl8255(dev, 0x4, 0x410); + write_rtl8255(dev, 0x4, 0x410); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x610); + write_rtl8255(dev, 0x4, 0x410); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404187, 0x27, + 0x92402aac, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc11); + write_rtl8255(dev, 0x4, 0xe11); + write_rtl8255(dev, 0x4, 0xc11); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x811); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa11); + write_rtl8255(dev, 0x4, 0x811); + write_rtl8255(dev, 0x4, 0x411); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x611); + write_rtl8255(dev, 0x4, 0x411); + write_rtl8255(dev, 0x4, 0x411); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x611); + write_rtl8255(dev, 0x4, 0x411); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404186, 0x80000027, + 0x92402ab0, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc12); + write_rtl8255(dev, 0x4, 0xe12); + write_rtl8255(dev, 0x4, 0xc12); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x812); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa12); + write_rtl8255(dev, 0x4, 0x812); + write_rtl8255(dev, 0x4, 0x412); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x612); + write_rtl8255(dev, 0x4, 0x412); + write_rtl8255(dev, 0x4, 0x412); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x612); + write_rtl8255(dev, 0x4, 0x412); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404186, 0x27, + 0x92402ab0, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc13); + write_rtl8255(dev, 0x4, 0xe13); + write_rtl8255(dev, 0x4, 0xc13); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x813); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa13); + write_rtl8255(dev, 0x4, 0x813); + write_rtl8255(dev, 0x4, 0x413); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x613); + write_rtl8255(dev, 0x4, 0x413); + write_rtl8255(dev, 0x4, 0x413); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x613); + write_rtl8255(dev, 0x4, 0x413); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404146, 0x27, + 0x92402ab4, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc14); + write_rtl8255(dev, 0x4, 0xe14); + write_rtl8255(dev, 0x4, 0xc14); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x814); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa14); + write_rtl8255(dev, 0x4, 0x814); + write_rtl8255(dev, 0x4, 0x414); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x614); + write_rtl8255(dev, 0x4, 0x414); + write_rtl8255(dev, 0x4, 0x414); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x614); + write_rtl8255(dev, 0x4, 0x414); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404126, 0x27, + 0x92402ab4, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc15); + write_rtl8255(dev, 0x4, 0xe15); + write_rtl8255(dev, 0x4, 0xc15); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x815); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa15); + write_rtl8255(dev, 0x4, 0x815); + write_rtl8255(dev, 0x4, 0x415); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x615); + write_rtl8255(dev, 0x4, 0x415); + write_rtl8255(dev, 0x4, 0x415); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x615); + write_rtl8255(dev, 0x4, 0x415); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404106, 0x27, + 0x92402ab8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc16); + write_rtl8255(dev, 0x4, 0xe16); + write_rtl8255(dev, 0x4, 0xc16); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x816); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa16); + write_rtl8255(dev, 0x4, 0x816); + write_rtl8255(dev, 0x4, 0x416); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x616); + write_rtl8255(dev, 0x4, 0x416); + write_rtl8255(dev, 0x4, 0x416); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x616); + write_rtl8255(dev, 0x4, 0x416); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404105, 0x27, + 0x92402ab8, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc17); + write_rtl8255(dev, 0x4, 0xe17); + write_rtl8255(dev, 0x4, 0xc17); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x817); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa17); + write_rtl8255(dev, 0x4, 0x817); + write_rtl8255(dev, 0x4, 0x417); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x617); + write_rtl8255(dev, 0x4, 0x417); + write_rtl8255(dev, 0x4, 0x417); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x617); + write_rtl8255(dev, 0x4, 0x417); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404104, 0x80000027, + 0x92402a88, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc18); + write_rtl8255(dev, 0x4, 0xe18); + write_rtl8255(dev, 0x4, 0xc18); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x818); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa18); + write_rtl8255(dev, 0x4, 0x818); + write_rtl8255(dev, 0x4, 0x418); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x618); + write_rtl8255(dev, 0x4, 0x418); + write_rtl8255(dev, 0x4, 0x418); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x618); + write_rtl8255(dev, 0x4, 0x418); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404104, 0x27, + 0x92402a88, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc19); + write_rtl8255(dev, 0x4, 0xe19); + write_rtl8255(dev, 0x4, 0xc19); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x819); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa19); + write_rtl8255(dev, 0x4, 0x819); + write_rtl8255(dev, 0x4, 0x419); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x619); + write_rtl8255(dev, 0x4, 0x419); + write_rtl8255(dev, 0x4, 0x419); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x619); + write_rtl8255(dev, 0x4, 0x419); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404044, 0x27, + 0x92402a8c, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc1a); + write_rtl8255(dev, 0x4, 0xe1a); + write_rtl8255(dev, 0x4, 0xc1a); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x81a); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa1a); + write_rtl8255(dev, 0x4, 0x81a); + write_rtl8255(dev, 0x4, 0x41a); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x61a); + write_rtl8255(dev, 0x4, 0x41a); + write_rtl8255(dev, 0x4, 0x41a); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x61a); + write_rtl8255(dev, 0x4, 0x41a); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404024, 0x27, + 0x92402a8c, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc1b); + write_rtl8255(dev, 0x4, 0xe1b); + write_rtl8255(dev, 0x4, 0xc1b); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x81b); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa1b); + write_rtl8255(dev, 0x4, 0x81b); + write_rtl8255(dev, 0x4, 0x41b); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x61b); + write_rtl8255(dev, 0x4, 0x41b); + write_rtl8255(dev, 0x4, 0x41b); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x61b); + write_rtl8255(dev, 0x4, 0x41b); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404004, 0x27, + 0x92402a90, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc1c); + write_rtl8255(dev, 0x4, 0xe1c); + write_rtl8255(dev, 0x4, 0xc1c); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x81c); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa1c); + write_rtl8255(dev, 0x4, 0x81c); + write_rtl8255(dev, 0x4, 0x41c); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x61c); + write_rtl8255(dev, 0x4, 0x41c); + write_rtl8255(dev, 0x4, 0x41c); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x61c); + write_rtl8255(dev, 0x4, 0x41c); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404001, 0x27, + 0x92402a90, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc1d); + write_rtl8255(dev, 0x4, 0xe1d); + write_rtl8255(dev, 0x4, 0xc1d); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x81d); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa1d); + write_rtl8255(dev, 0x4, 0x81d); + write_rtl8255(dev, 0x4, 0x41d); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x61d); + write_rtl8255(dev, 0x4, 0x41d); + write_rtl8255(dev, 0x4, 0x41d); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x61d); + write_rtl8255(dev, 0x4, 0x41d); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a94, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc1e); + write_rtl8255(dev, 0x4, 0xe1e); + write_rtl8255(dev, 0x4, 0xc1e); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x81e); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa1e); + write_rtl8255(dev, 0x4, 0x81e); + write_rtl8255(dev, 0x4, 0x41e); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x61e); + write_rtl8255(dev, 0x4, 0x41e); + write_rtl8255(dev, 0x4, 0x41e); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x61e); + write_rtl8255(dev, 0x4, 0x41e); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x27, + 0x92402a94, 0xf0009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc1f); + write_rtl8255(dev, 0x4, 0xe1f); + write_rtl8255(dev, 0x4, 0xc1f); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x81f); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa1f); + write_rtl8255(dev, 0x4, 0x81f); + write_rtl8255(dev, 0x4, 0x41f); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x61f); + write_rtl8255(dev, 0x4, 0x41f); + write_rtl8255(dev, 0x4, 0x41f); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x61f); + write_rtl8255(dev, 0x4, 0x41f); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404020, 0x80000027, + 0x92402a98, 0xf8009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc20); + write_rtl8255(dev, 0x4, 0xe20); + write_rtl8255(dev, 0x4, 0xc20); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x820); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa20); + write_rtl8255(dev, 0x4, 0x820); + write_rtl8255(dev, 0x4, 0x420); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x620); + write_rtl8255(dev, 0x4, 0x420); + write_rtl8255(dev, 0x4, 0x420); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x620); + write_rtl8255(dev, 0x4, 0x420); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404020, 0x27, + 0x92402a98, 0xf8009, 0x28000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc21); + write_rtl8255(dev, 0x4, 0xe21); + write_rtl8255(dev, 0x4, 0xc21); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x821); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa21); + write_rtl8255(dev, 0x4, 0x821); + write_rtl8255(dev, 0x4, 0x421); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x621); + write_rtl8255(dev, 0x4, 0x421); + write_rtl8255(dev, 0x4, 0x421); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x621); + write_rtl8255(dev, 0x4, 0x421); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a68, 0xf0009, 0x10028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc22); + write_rtl8255(dev, 0x4, 0xe22); + write_rtl8255(dev, 0x4, 0xc22); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x822); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa22); + write_rtl8255(dev, 0x4, 0x822); + write_rtl8255(dev, 0x4, 0x422); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x622); + write_rtl8255(dev, 0x4, 0x422); + write_rtl8255(dev, 0x4, 0x422); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x622); + write_rtl8255(dev, 0x4, 0x422); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0x80000027, + 0x92402a68, 0xf0009, 0x20028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc23); + write_rtl8255(dev, 0x4, 0xe23); + write_rtl8255(dev, 0x4, 0xc23); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x823); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa23); + write_rtl8255(dev, 0x4, 0x823); + write_rtl8255(dev, 0x4, 0x423); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x623); + write_rtl8255(dev, 0x4, 0x423); + write_rtl8255(dev, 0x4, 0x423); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x623); + write_rtl8255(dev, 0x4, 0x423); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0x80000027, + 0x92402a6c, 0xf0009, 0x30028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc24); + write_rtl8255(dev, 0x4, 0xe24); + write_rtl8255(dev, 0x4, 0xc24); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x824); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa24); + write_rtl8255(dev, 0x4, 0x824); + write_rtl8255(dev, 0x4, 0x424); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x624); + write_rtl8255(dev, 0x4, 0x424); + write_rtl8255(dev, 0x4, 0x424); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x624); + write_rtl8255(dev, 0x4, 0x424); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0x80000027, + 0x92402a6c, 0xf0009, 0x40028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc25); + write_rtl8255(dev, 0x4, 0xe25); + write_rtl8255(dev, 0x4, 0xc25); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x825); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa25); + write_rtl8255(dev, 0x4, 0x825); + write_rtl8255(dev, 0x4, 0x425); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x625); + write_rtl8255(dev, 0x4, 0x425); + write_rtl8255(dev, 0x4, 0x425); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x625); + write_rtl8255(dev, 0x4, 0x425); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a70, 0xf0009, 0x60028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc26); + write_rtl8255(dev, 0x4, 0xe26); + write_rtl8255(dev, 0x4, 0xc26); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x826); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa26); + write_rtl8255(dev, 0x4, 0x826); + write_rtl8255(dev, 0x4, 0x426); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x626); + write_rtl8255(dev, 0x4, 0x426); + write_rtl8255(dev, 0x4, 0x426); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x626); + write_rtl8255(dev, 0x4, 0x426); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404031, 0x40000027, + 0x92402a70, 0xf0011, 0x60028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc27); + write_rtl8255(dev, 0x4, 0xe27); + write_rtl8255(dev, 0x4, 0xc27); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x827); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa27); + write_rtl8255(dev, 0x4, 0x827); + write_rtl8255(dev, 0x4, 0x427); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x627); + write_rtl8255(dev, 0x4, 0x427); + write_rtl8255(dev, 0x4, 0x427); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x627); + write_rtl8255(dev, 0x4, 0x427); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404011, 0x40000027, + 0x92402a74, 0xf0011, 0x60028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc28); + write_rtl8255(dev, 0x4, 0xe28); + write_rtl8255(dev, 0x4, 0xc28); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x828); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa28); + write_rtl8255(dev, 0x4, 0x828); + write_rtl8255(dev, 0x4, 0x428); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x628); + write_rtl8255(dev, 0x4, 0x428); + write_rtl8255(dev, 0x4, 0x428); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x628); + write_rtl8255(dev, 0x4, 0x428); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0xc0000027, + 0x92402a74, 0xf0011, 0x60028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc29); + write_rtl8255(dev, 0x4, 0xe29); + write_rtl8255(dev, 0x4, 0xc29); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x829); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa29); + write_rtl8255(dev, 0x4, 0x829); + write_rtl8255(dev, 0x4, 0x429); + write_rtl8255(dev, 0x3, 0x25); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x629); + write_rtl8255(dev, 0x4, 0x429); + write_rtl8255(dev, 0x4, 0x429); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x629); + write_rtl8255(dev, 0x4, 0x429); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a78, 0xf0011, 0x60028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc2a); + write_rtl8255(dev, 0x4, 0xe2a); + write_rtl8255(dev, 0x4, 0xc2a); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x82a); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa2a); + write_rtl8255(dev, 0x4, 0x82a); + write_rtl8255(dev, 0x4, 0x42a); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x62a); + write_rtl8255(dev, 0x4, 0x42a); + write_rtl8255(dev, 0x4, 0x42a); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x62a); + write_rtl8255(dev, 0x4, 0x42a); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a78, 0xf0011, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc2b); + write_rtl8255(dev, 0x4, 0xe2b); + write_rtl8255(dev, 0x4, 0xc2b); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x82b); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa2b); + write_rtl8255(dev, 0x4, 0x82b); + write_rtl8255(dev, 0x4, 0x42b); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x62b); + write_rtl8255(dev, 0x4, 0x42b); + write_rtl8255(dev, 0x4, 0x42b); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x62b); + write_rtl8255(dev, 0x4, 0x42b); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a48, 0xf0019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc2c); + write_rtl8255(dev, 0x4, 0xe2c); + write_rtl8255(dev, 0x4, 0xc2c); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x82c); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa2c); + write_rtl8255(dev, 0x4, 0x82c); + write_rtl8255(dev, 0x4, 0x42c); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x62c); + write_rtl8255(dev, 0x4, 0x42c); + write_rtl8255(dev, 0x4, 0x42c); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x62c); + write_rtl8255(dev, 0x4, 0x42c); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a48, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc2d); + write_rtl8255(dev, 0x4, 0xe2d); + write_rtl8255(dev, 0x4, 0xc2d); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x82d); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa2d); + write_rtl8255(dev, 0x4, 0x82d); + write_rtl8255(dev, 0x4, 0x42d); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x62d); + write_rtl8255(dev, 0x4, 0x42d); + write_rtl8255(dev, 0x4, 0x42d); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x62d); + write_rtl8255(dev, 0x4, 0x42d); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a4c, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc2e); + write_rtl8255(dev, 0x4, 0xe2e); + write_rtl8255(dev, 0x4, 0xc2e); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x82e); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa2e); + write_rtl8255(dev, 0x4, 0x82e); + write_rtl8255(dev, 0x4, 0x42e); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x62e); + write_rtl8255(dev, 0x4, 0x42e); + write_rtl8255(dev, 0x4, 0x42e); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x62e); + write_rtl8255(dev, 0x4, 0x42e); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a4c, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc2f); + write_rtl8255(dev, 0x4, 0xe2f); + write_rtl8255(dev, 0x4, 0xc2f); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x82f); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa2f); + write_rtl8255(dev, 0x4, 0x82f); + write_rtl8255(dev, 0x4, 0x42f); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x62f); + write_rtl8255(dev, 0x4, 0x42f); + write_rtl8255(dev, 0x4, 0x42f); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x62f); + write_rtl8255(dev, 0x4, 0x42f); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a50, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc30); + write_rtl8255(dev, 0x4, 0xe30); + write_rtl8255(dev, 0x4, 0xc30); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x830); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa30); + write_rtl8255(dev, 0x4, 0x830); + write_rtl8255(dev, 0x4, 0x430); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x630); + write_rtl8255(dev, 0x4, 0x430); + write_rtl8255(dev, 0x4, 0x430); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x630); + write_rtl8255(dev, 0x4, 0x430); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a50, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc31); + write_rtl8255(dev, 0x4, 0xe31); + write_rtl8255(dev, 0x4, 0xc31); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x831); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa31); + write_rtl8255(dev, 0x4, 0x831); + write_rtl8255(dev, 0x4, 0x431); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x631); + write_rtl8255(dev, 0x4, 0x431); + write_rtl8255(dev, 0x4, 0x431); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x631); + write_rtl8255(dev, 0x4, 0x431); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a54, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc32); + write_rtl8255(dev, 0x4, 0xe32); + write_rtl8255(dev, 0x4, 0xc32); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x832); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa32); + write_rtl8255(dev, 0x4, 0x832); + write_rtl8255(dev, 0x4, 0x432); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x632); + write_rtl8255(dev, 0x4, 0x432); + write_rtl8255(dev, 0x4, 0x432); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x632); + write_rtl8255(dev, 0x4, 0x432); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a54, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc33); + write_rtl8255(dev, 0x4, 0xe33); + write_rtl8255(dev, 0x4, 0xc33); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x833); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa33); + write_rtl8255(dev, 0x4, 0x833); + write_rtl8255(dev, 0x4, 0x433); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x633); + write_rtl8255(dev, 0x4, 0x433); + write_rtl8255(dev, 0x4, 0x433); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x633); + write_rtl8255(dev, 0x4, 0x433); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a58, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc34); + write_rtl8255(dev, 0x4, 0xe34); + write_rtl8255(dev, 0x4, 0xc34); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x834); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa34); + write_rtl8255(dev, 0x4, 0x834); + write_rtl8255(dev, 0x4, 0x434); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x634); + write_rtl8255(dev, 0x4, 0x434); + write_rtl8255(dev, 0x4, 0x434); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x634); + write_rtl8255(dev, 0x4, 0x434); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a58, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc35); + write_rtl8255(dev, 0x4, 0xe35); + write_rtl8255(dev, 0x4, 0xc35); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x835); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa35); + write_rtl8255(dev, 0x4, 0x835); + write_rtl8255(dev, 0x4, 0x435); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x4, 0x635); + write_rtl8255(dev, 0x4, 0x435); + write_rtl8255(dev, 0x4, 0x435); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x635); + write_rtl8255(dev, 0x4, 0x435); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a24, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc36); + write_rtl8255(dev, 0x4, 0xe36); + write_rtl8255(dev, 0x4, 0xc36); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x836); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa36); + write_rtl8255(dev, 0x4, 0x836); + write_rtl8255(dev, 0x4, 0x436); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x25); + write_rtl8255(dev, 0x4, 0x636); + write_rtl8255(dev, 0x4, 0x436); + write_rtl8255(dev, 0x4, 0x436); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x636); + write_rtl8255(dev, 0x4, 0x436); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a24, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc37); + write_rtl8255(dev, 0x4, 0xe37); + write_rtl8255(dev, 0x4, 0xc37); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x837); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa37); + write_rtl8255(dev, 0x4, 0x837); + write_rtl8255(dev, 0x4, 0x437); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x25); + write_rtl8255(dev, 0x4, 0x637); + write_rtl8255(dev, 0x4, 0x437); + write_rtl8255(dev, 0x4, 0x437); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x637); + write_rtl8255(dev, 0x4, 0x437); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a28, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc38); + write_rtl8255(dev, 0x4, 0xe38); + write_rtl8255(dev, 0x4, 0xc38); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x838); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa38); + write_rtl8255(dev, 0x4, 0x838); + write_rtl8255(dev, 0x4, 0x438); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x25); + write_rtl8255(dev, 0x4, 0x638); + write_rtl8255(dev, 0x4, 0x438); + write_rtl8255(dev, 0x4, 0x438); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x638); + write_rtl8255(dev, 0x4, 0x438); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a28, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc39); + write_rtl8255(dev, 0x4, 0xe39); + write_rtl8255(dev, 0x4, 0xc39); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x839); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa39); + write_rtl8255(dev, 0x4, 0x839); + write_rtl8255(dev, 0x4, 0x439); + write_rtl8255(dev, 0x3, 0x24); + write_rtl8255(dev, 0x2, 0x25); + write_rtl8255(dev, 0x4, 0x639); + write_rtl8255(dev, 0x4, 0x439); + write_rtl8255(dev, 0x4, 0x439); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x639); + write_rtl8255(dev, 0x4, 0x439); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc3a); + write_rtl8255(dev, 0x4, 0xe3a); + write_rtl8255(dev, 0x4, 0xc3a); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x83a); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa3a); + write_rtl8255(dev, 0x4, 0x83a); + write_rtl8255(dev, 0x4, 0x43a); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0x63a); + write_rtl8255(dev, 0x4, 0x43a); + write_rtl8255(dev, 0x4, 0x43a); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x63a); + write_rtl8255(dev, 0x4, 0x43a); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc3b); + write_rtl8255(dev, 0x4, 0xe3b); + write_rtl8255(dev, 0x4, 0xc3b); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x83b); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa3b); + write_rtl8255(dev, 0x4, 0x83b); + write_rtl8255(dev, 0x4, 0x43b); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0x63b); + write_rtl8255(dev, 0x4, 0x43b); + write_rtl8255(dev, 0x4, 0x43b); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x63b); + write_rtl8255(dev, 0x4, 0x43b); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc3c); + write_rtl8255(dev, 0x4, 0xe3c); + write_rtl8255(dev, 0x4, 0xc3c); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x83c); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa3c); + write_rtl8255(dev, 0x4, 0x83c); + write_rtl8255(dev, 0x4, 0x43c); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0x63c); + write_rtl8255(dev, 0x4, 0x43c); + write_rtl8255(dev, 0x4, 0x43c); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x63c); + write_rtl8255(dev, 0x4, 0x43c); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc3d); + write_rtl8255(dev, 0x4, 0xe3d); + write_rtl8255(dev, 0x4, 0xc3d); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x83d); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa3d); + write_rtl8255(dev, 0x4, 0x83d); + write_rtl8255(dev, 0x4, 0x43d); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0x63d); + write_rtl8255(dev, 0x4, 0x43d); + write_rtl8255(dev, 0x4, 0x43d); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x63d); + write_rtl8255(dev, 0x4, 0x43d); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc3e); + write_rtl8255(dev, 0x4, 0xe3e); + write_rtl8255(dev, 0x4, 0xc3e); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x83e); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa3e); + write_rtl8255(dev, 0x4, 0x83e); + write_rtl8255(dev, 0x4, 0x43e); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0x63e); + write_rtl8255(dev, 0x4, 0x43e); + write_rtl8255(dev, 0x4, 0x43e); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x63e); + write_rtl8255(dev, 0x4, 0x43e); + write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, + 0x92402a00, 0xf8011, 0x70028000, 0xc00, 0x0); + write_rtl8255(dev, 0x1, 0x807); + write_rtl8255(dev, 0x4, 0xc3f); + write_rtl8255(dev, 0x4, 0xe3f); + write_rtl8255(dev, 0x4, 0xc3f); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255(dev, 0x4, 0x83f); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0xa3f); + write_rtl8255(dev, 0x4, 0x83f); + write_rtl8255(dev, 0x4, 0x43f); + write_rtl8255(dev, 0x3, 0x0); + write_rtl8255(dev, 0x2, 0x0); + write_rtl8255(dev, 0x4, 0x63f); + write_rtl8255(dev, 0x4, 0x43f); + write_rtl8255(dev, 0x4, 0x43f); + write_rtl8255(dev, 0x3, 0x100); + write_rtl8255(dev, 0x4, 0x63f); + write_rtl8255(dev, 0x4, 0x43f); + write_rtl8255(dev, 0x4, 0x0); + write_rtl8255(dev, 0x1, 0x0); + write_rtl8255_reg0c(dev, 0x3539, 0x70000c03, 0xfef46178, 0x408000, 0x403307, + 0x924f80c0, 0xf955c, 0x8400, 0x429200, 0x1ce20); + write_rtl8255(dev, 0x1, 0x1c7); + write_rtl8255(dev, 0x2, 0x26); + write_rtl8255(dev, 0x3, 0x27); + write_rtl8255(dev, 0x1, 0x47); + write_rtl8255(dev, 0x4, 0x98c); + write_rtl8255(dev, 0x5, 0x65); + write_rtl8255(dev, 0x6, 0x13); + write_rtl8255(dev, 0x7, 0x7c); + write_rtl8255(dev, 0x8, 0x6); + write_rtl8255(dev, 0x8, 0x7); + write_rtl8255(dev, 0x8, 0x6); + write_rtl8255(dev, 0x9, 0xce2); + write_rtl8255(dev, 0xb, 0x1c5); + write_rtl8255(dev, 0xd, 0xd7f); + write_rtl8255(dev, 0xe, 0x369); + write_rtl8255(dev, 0xa, 0xd56); + write_rtl8255(dev, 0xa, 0xd57); + mdelay(20); + write_rtl8255(dev, 0xd, 0xd7e); + +} + + +void rtl8255_set_band_param(struct net_device *dev, short band) +{ + if(band != BAND_A){ + write_nic_dword(dev, 0x94, 0x3dc00002); + write_nic_dword(dev, 0x88, 0x00100040); + + write_phy_cck(dev, 0x13, 0xd0); + + write_phy_cck(dev, 0x41, 0x9d); + write_nic_dword(dev, 0x8c, 0x00082205); + write_nic_byte(dev, 0xb4, 0x66); + } +} + +void rtl8255_rf_init(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int i; + u16 brsr; +// short channel /*= priv->chan*/ = 1; + priv->chan = 1; + + write_nic_word(dev, RFPinsOutput, 0x80); + write_nic_word(dev, RFPinsSelect, 0x80 | SW_CONTROL_GPIO); + write_nic_word(dev, RFPinsEnable, 0x80); + write_nic_word(dev, RFPinsSelect, SW_CONTROL_GPIO); + + write_nic_dword(dev, RF_TIMING, 0x000f800f); + + brsr = read_nic_word(dev, BRSR); + + write_nic_word(dev, 0x2c, 0xffff); + + + rtl8180_set_anaparam(dev, RTL8255_ANAPARAM_ON); + rtl8185_set_anaparam2(dev, RTL8255_ANAPARAM2_ON); + + write_nic_dword(dev, 0x94, 0x11c00002); + + write_nic_dword(dev, RF_PARA, 0x100040); + + rtl8185_rf_pins_enable(dev); + + rtl8255_init_BGband(dev); + rtl8255_set_band_param(dev,BAND_BG); + + write_phy_cck(dev, 0x0, 0x98); + write_phy_cck(dev, 0x3, 0x20); + write_phy_cck(dev, 0x4, 0x2e); + write_phy_cck(dev, 0x5, 0x12); + write_phy_cck(dev, 0x6, 0xfc); + write_phy_cck(dev, 0x7, 0xd8); + write_phy_cck(dev, 0x8, 0x2e); + write_phy_cck(dev, 0x10, 0xd3); + write_phy_cck(dev, 0x11, 0x88); + write_phy_cck(dev, 0x12, 0x47); + write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ + + write_phy_cck(dev, 0x19, 0x0); + write_phy_cck(dev, 0x1a, 0xa0); + write_phy_cck(dev, 0x1b, 0x8); + write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ + write_phy_cck(dev, 0x41, 0x9d); /* Energy Threshold */ + //write_phy_cck(dev, 0x42, 0x0); + write_phy_cck(dev, 0x43, 0x8); + + write_nic_byte(dev, TESTR,0x8); + + for(i=0;i<128;i++){ + write_phy_ofdm(dev, 0x4b, rtl8255_agc[i]); + write_phy_ofdm(dev, 0x4a, (u8)i+ 0x80); + } + + + write_phy_ofdm(dev, 0x0, 0x1); + write_phy_ofdm(dev, 0x1, 0x2); + write_phy_ofdm(dev, 0x2, 0x43); + write_phy_ofdm(dev, 0x3, 0x0); + write_phy_ofdm(dev, 0x4, 0x0); + write_phy_ofdm(dev, 0x5, 0x0); + write_phy_ofdm(dev, 0x6, 0x40); + write_phy_ofdm(dev, 0x7, 0x0); + write_phy_ofdm(dev, 0x8, 0x40); + write_phy_ofdm(dev, 0x9, 0xfe); + write_phy_ofdm(dev, 0xa, 0x9); + write_phy_ofdm(dev, 0xb, 0x80); + write_phy_ofdm(dev, 0xc, 0x1); + write_phy_ofdm(dev, 0xd, 0x43); + write_phy_ofdm(dev, 0xe, 0xd3); + write_phy_ofdm(dev, 0xf, 0x38); + write_phy_ofdm(dev, 0x10, 0x4); + write_phy_ofdm(dev, 0x11, 0x06);/*agc resp time 700*/ + write_phy_ofdm(dev, 0x12, 0x20); + write_phy_ofdm(dev, 0x13, 0x20); + write_phy_ofdm(dev, 0x14, 0x0); + write_phy_ofdm(dev, 0x15, 0x40); + write_phy_ofdm(dev, 0x16, 0x0); + write_phy_ofdm(dev, 0x17, 0x40); + write_phy_ofdm(dev, 0x18, 0xef); + write_phy_ofdm(dev, 0x19, 0x25); + write_phy_ofdm(dev, 0x1a, 0x20); + write_phy_ofdm(dev, 0x1b, 0x7a); + write_phy_ofdm(dev, 0x1c, 0x84); + write_phy_ofdm(dev, 0x1e, 0x95); + write_phy_ofdm(dev, 0x1f, 0x75); + write_phy_ofdm(dev, 0x20, 0x1f); + write_phy_ofdm(dev, 0x21, 0x17); + write_phy_ofdm(dev, 0x22, 0x16); + write_phy_ofdm(dev, 0x23, 0x70); //FIXME maybe not needed + write_phy_ofdm(dev, 0x24, 0x70); + write_phy_ofdm(dev, 0x25, 0x0); + write_phy_ofdm(dev, 0x26, 0x10); + write_phy_ofdm(dev, 0x27, 0x88); + + + write_nic_dword(dev, 0x94, 0x3dc00002); //BAND DEPEND. +// write_nic_dword(dev, 0x94, 0x15c00002); //BAND DEPEND. + + write_phy_cck(dev, 0x4, 0x18); + write_phy_cck(dev, 0x43, 0x18); + write_phy_cck(dev, 0x6, 0xdc); + write_phy_cck(dev, 0x44, 0x2b); + write_phy_cck(dev, 0x45, 0x2b); + write_phy_cck(dev, 0x46, 0x25); + write_phy_cck(dev, 0x47, 0x15); + write_phy_cck(dev, 0x48, 0x0); + write_phy_cck(dev, 0x49, 0x0); + write_phy_cck(dev, 0x4a, 0x0); + write_phy_cck(dev, 0x4b, 0x0); +// write_phy_cck(dev, 0x4c, 0x5); +#if 0 + write_phy_cck(dev, 0x41, 0x9d); /* Energy Threshold */ + // TESTR 0xb 8187 + write_phy_cck(dev, 0x10, 0x93);// & 0xfb); +#endif + //rtl8255_set_gain(dev, 1); /* FIXME this '1' is random */ + + rtl8255_SetTXPowerLevel(dev, priv->chan); + + write_phy_cck(dev, 0x10, 0x93 |0x4); /* Rx ant B, 0xd3 for A */ + write_phy_ofdm(dev, 0x26, 0x90); /* Rx ant B, 0x10 for A */ + + rtl8185_tx_antenna(dev, 0x3); /* TX ant B, 0x0 for A*/ + /* make sure is waken up! */ + rtl8180_set_anaparam(dev, RTL8255_ANAPARAM_ON); + rtl8185_set_anaparam2(dev, RTL8255_ANAPARAM2_ON); + + rtl8255_set_band_param(dev,BAND_BG); + + write_phy_cck(dev, 0x41, 0x9d); + + rtl8255_set_gain(dev, 4); + //rtl8255_set_energy_threshold(dev); + write_phy_cck(dev, 0x41, 0x9d); + rtl8255_rf_set_chan(dev, priv->chan); + + write_nic_word(dev, BRSR, brsr); +} + diff --git a/drivers/staging/rtl8187se/r8180_rtl8255.h b/drivers/staging/rtl8187se/r8180_rtl8255.h new file mode 100644 index 0000000..be44ca6 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_rtl8255.h @@ -0,0 +1,19 @@ +/* + This is part of the rtl8180-sa2400 driver + released under the GPL (See file COPYING for details). + Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> + + This files contains programming code for the rtl8255 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + +#define RTL8255_ANAPARAM_ON 0xa0000b59 +#define RTL8255_ANAPARAM2_ON 0x840cf311 + + +void rtl8255_rf_init(struct net_device *dev); +void rtl8255_rf_set_chan(struct net_device *dev,short ch); +void rtl8255_rf_close(struct net_device *dev); diff --git a/drivers/staging/rtl8187se/r8180_sa2400.c b/drivers/staging/rtl8187se/r8180_sa2400.c new file mode 100644 index 0000000..d649560 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_sa2400.c @@ -0,0 +1,233 @@ +/* + This files contains PHILIPS SA2400 radio frontend programming routines. + + This is part of rtl8180 OpenSource driver + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official realtek driver + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + Code at http://che.ojctech.com/~dyoung/rtw/ has been useful to me to + understand some things. + + Code from rtl8181 project has been useful to me to understand some things. + + We want to tanks the Authors of such projects and the Ndiswrapper + project Authors. +*/ + + +#include "r8180.h" +#include "r8180_hw.h" +#include "r8180_sa2400.h" + + +//#define DEBUG_SA2400 + +u32 sa2400_chan[] = { + 0x0, //dummy channel 0 + 0x00096c, //1 + 0x080970, //2 + 0x100974, //3 + 0x180978, //4 + 0x000980, //5 + 0x080984, //6 + 0x100988, //7 + 0x18098c, //8 + 0x000994, //9 + 0x080998, //10 + 0x10099c, //11 + 0x1809a0, //12 + 0x0009a8, //13 + 0x0009b4, //14 +}; + + +void rf_stabilize(struct net_device *dev) +{ + force_pci_posting(dev); + mdelay(3); //for now use a great value.. we may optimize in future +} + + +void write_sa2400(struct net_device *dev,u8 adr, u32 data) +{ +// struct r8180_priv *priv = ieee80211_priv(dev); + u32 phy_config; + + // philips sa2400 expects 24 bits data + + /*if(adr == 4 && priv->digphy){ + phy_config=0x60000000; + }else{ + phy_config=0xb0000000; + }*/ + + phy_config = 0xb0000000; // MAC will bang bits to the sa2400 + + phy_config |= (((u32)(adr&0xf))<< 24); + phy_config |= (data & 0xffffff); + write_nic_dword(dev,PHY_CONFIG,phy_config); +#ifdef DEBUG_SA2400 + DMESG("Writing sa2400: %x (adr %x)",phy_config,adr); +#endif + rf_stabilize(dev); +} + + + +void sa2400_write_phy_antenna(struct net_device *dev,short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u8 ant; + + ant = SA2400_ANTENNA; + if(priv->antb) /*default antenna is antenna B */ + ant |= BB_ANTENNA_B; + if(ch == 14) + ant |= BB_ANTATTEN_CHAN14; + write_phy(dev,0x10,ant); + //DMESG("BB antenna %x ",ant); +} + + +/* from the rtl8181 embedded driver */ +short sa2400_rf_set_sens(struct net_device *dev, short sens) +{ + u8 finetune = 0; + if ((sens > 85) || (sens < 54)) return -1; + + write_sa2400(dev,5,0x1dfb | (sens-54) << 15 |(finetune<<20)); // AGC 0xc9dfb + + return 0; +} + + +void sa2400_rf_set_chan(struct net_device *dev, short ch) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32 txpw = 0xff & priv->chtxpwr[ch]; + u32 chan = sa2400_chan[ch]; + + write_sa2400(dev,7,txpw); + //write_phy(dev,0x10,0xd1); + sa2400_write_phy_antenna(dev,ch); + write_sa2400(dev,0,chan); + write_sa2400(dev,1,0xbb50); + write_sa2400(dev,2,0x80); + write_sa2400(dev,3,0); +} + + +void sa2400_rf_close(struct net_device *dev) +{ + write_sa2400(dev, 4, 0); +} + + +void sa2400_rf_init(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u32 anaparam; + u8 firdac; + + write_nic_byte(dev,PHY_DELAY,0x6); //this is general + write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general + + /*these are philips sa2400 specific*/ + anaparam = read_nic_dword(dev,ANAPARAM); + anaparam = anaparam &~ (1<<ANAPARAM_TXDACOFF_SHIFT); + + anaparam = anaparam &~ANAPARAM_PWR1_MASK; + anaparam = anaparam &~ANAPARAM_PWR0_MASK; + if(priv->digphy){ + anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON<<ANAPARAM_PWR1_SHIFT); + anaparam |= (SA2400_ANAPARAM_PWR0_ON<<ANAPARAM_PWR0_SHIFT); + }else{ + anaparam |= (SA2400_ANA_ANAPARAM_PWR1_ON<<ANAPARAM_PWR1_SHIFT); + } + + rtl8180_set_anaparam(dev,anaparam); + + firdac = (priv->digphy) ? (1<<SA2400_REG4_FIRDAC_SHIFT) : 0; + write_sa2400(dev,0,sa2400_chan[priv->chan]); + write_sa2400(dev,1,0xbb50); + write_sa2400(dev,2,0x80); + write_sa2400(dev,3,0); + write_sa2400(dev,4,0x19340 | firdac); + write_sa2400(dev,5,0xc9dfb); // AGC + write_sa2400(dev,4,0x19348 | firdac); //calibrates VCO + + if(priv->digphy) + write_sa2400(dev,4,0x1938c); /*???*/ + + write_sa2400(dev,4,0x19340 | firdac); + + write_sa2400(dev,0,sa2400_chan[priv->chan]); + write_sa2400(dev,1,0xbb50); + write_sa2400(dev,2,0x80); + write_sa2400(dev,3,0); + write_sa2400(dev,4,0x19344 | firdac); //calibrates filter + + /* new from rtl8180 embedded driver (rtl8181 project) */ + write_sa2400(dev,6,0x13ff | (1<<23)); // MANRX + write_sa2400(dev,8,0); //VCO + + if(!priv->digphy) + { + rtl8180_set_anaparam(dev, anaparam | \ + (1<<ANAPARAM_TXDACOFF_SHIFT)); + + rtl8180_conttx_enable(dev); + + write_sa2400(dev, 4, 0x19341); // calibrates DC + + /* a 5us sleep is required here, + we rely on the 3ms delay introduced in write_sa2400 + */ + write_sa2400(dev, 4, 0x19345); + /* a 20us sleep is required here, + we rely on the 3ms delay introduced in write_sa2400 + */ + rtl8180_conttx_disable(dev); + + rtl8180_set_anaparam(dev, anaparam); + } + /* end new */ + + write_sa2400(dev,4,0x19341 | firdac ); //RTX MODE + + // Set tx power level !? + + + /*baseband configuration*/ + write_phy(dev,0,0x98); + write_phy(dev,3,0x38); + write_phy(dev,4,0xe0); + write_phy(dev,5,0x90); + write_phy(dev,6,0x1a); + write_phy(dev,7,0x64); + + /*Should be done something more here??*/ + + sa2400_write_phy_antenna(dev,priv->chan); + + write_phy(dev,0x11,0x80); + if(priv->diversity) + write_phy(dev,0x12,0xc7); + else + write_phy(dev,0x12,0x47); + + write_phy(dev,0x13,0x90 | priv->cs_treshold ); + + write_phy(dev,0x19,0x0); + write_phy(dev,0x1a,0xa0); + + sa2400_rf_set_chan(dev,priv->chan); +} diff --git a/drivers/staging/rtl8187se/r8180_sa2400.h b/drivers/staging/rtl8187se/r8180_sa2400.h new file mode 100644 index 0000000..683a69b --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_sa2400.h @@ -0,0 +1,26 @@ +/* + This is part of rtl8180 OpenSource driver - v 0.7 + Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the official realtek driver + Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of such projects and the Ndiswrapper project Authors. +*/ + +#define SA2400_ANTENNA 0x91 +#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8 +#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28 +#define SA2400_ANAPARAM_PWR0_ON 0x3 + +#define SA2400_RF_MAX_SENS 85 +#define SA2400_RF_DEF_SENS 80 + +#define SA2400_REG4_FIRDAC_SHIFT 7 + +void sa2400_rf_init(struct net_device *dev); +void sa2400_rf_set_chan(struct net_device *dev,short ch); +short sa2400_rf_set_sens(struct net_device *dev,short sens); +void sa2400_rf_close(struct net_device *dev); diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c new file mode 100644 index 0000000..c77abe5 --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_wx.c @@ -0,0 +1,1644 @@ +/* + This file contains wireless extension handlers. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part + of the official realtek driver. + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon. + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + We want to tanks the Authors of those projects and the Ndiswrapper + project Authors. +*/ + + +#include "r8180.h" +#include "r8180_hw.h" +#include "r8180_sa2400.h" + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +//#define RATE_COUNT 4 +u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000, + 6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000}; + +#define RATE_COUNT (sizeof(rtl8180_rates)/sizeof(rtl8180_rates[0])) + +static CHANNEL_LIST DefaultChannelPlan[] = { +// {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, //Default channel plan + {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, //FCC + {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Spain. Change to ETSI. + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //France. Change to ETSI. + {{14,36,40,44,48,52,56,60,64},9}, //MKK + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},//MKK1 + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Israel. + {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, // For 11a , TELEC + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14} //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 +}; +static int r8180_wx_get_freq(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + return ieee80211_wx_get_freq(priv->ieee80211, a, wrqu, b); +} + + +int r8180_wx_set_key(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct iw_point *erq = &(wrqu->encoding); + + if(priv->ieee80211->bHwRadioOff) + return 0; + + if (erq->flags & IW_ENCODE_DISABLED) { + } + + +/* i = erq->flags & IW_ENCODE_INDEX; + if (i < 1 || i > 4) +*/ + + if (erq->length > 0) { + + //int len = erq->length <= 5 ? 5 : 13; + + u32* tkey= (u32*) key; + priv->key0[0] = tkey[0]; + priv->key0[1] = tkey[1]; + priv->key0[2] = tkey[2]; + priv->key0[3] = tkey[3] &0xff; + DMESG("Setting wep key to %x %x %x %x", + tkey[0],tkey[1],tkey[2],tkey[3]); + rtl8180_set_hw_wep(dev); + } + return 0; +} + + +static int r8180_wx_set_beaconinterval(struct net_device *dev, struct iw_request_info *aa, + union iwreq_data *wrqu, char *b) +{ + int *parms = (int *)b; + int bi = parms[0]; + + struct r8180_priv *priv = ieee80211_priv(dev); + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + DMESG("setting beacon interval to %x",bi); + + priv->ieee80211->current_network.beacon_interval=bi; + rtl8180_commit(dev); + up(&priv->wx_sem); + + return 0; +} + + + +static int r8180_wx_get_mode(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_mode(priv->ieee80211,a,wrqu,b); +} + + + +static int r8180_wx_get_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_rate(priv->ieee80211,info,wrqu,extra); +} + + + +static int r8180_wx_set_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8180_priv *priv = ieee80211_priv(dev); + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_rate(priv->ieee80211,info,wrqu,extra); + + up(&priv->wx_sem); + + return ret; +} + + +static int r8180_wx_set_crcmon(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int *parms = (int *)extra; + int enable = (parms[0] > 0); + short prev = priv->crcmon; + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + if(enable) + priv->crcmon=1; + else + priv->crcmon=0; + + DMESG("bad CRC in monitor mode are %s", + priv->crcmon ? "accepted" : "rejected"); + + if(prev != priv->crcmon && priv->up){ + rtl8180_down(dev); + rtl8180_up(dev); + } + + up(&priv->wx_sem); + + return 0; +} + + +static int r8180_wx_set_mode(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret; + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); +#ifdef ENABLE_IPS +// printk("set mode ENABLE_IPS\n"); + if(priv->bInactivePs){ + if(wrqu->mode == IW_MODE_ADHOC) + IPSLeave(dev); + } +#endif + ret = ieee80211_wx_set_mode(priv->ieee80211,a,wrqu,b); + + //rtl8180_commit(dev); + + up(&priv->wx_sem); + return ret; +} + +//YJ,add,080819,for hidden ap +struct iw_range_with_scan_capa +{ + /* Informative stuff (to choose between different interface) */ + __u32 throughput; /* To give an idea... */ + /* In theory this value should be the maximum benchmarked + * TCP/IP throughput, because with most of these devices the + * bit rate is meaningless (overhead an co) to estimate how + * fast the connection will go and pick the fastest one. + * I suggest people to play with Netperf or any benchmark... + */ + + /* NWID (or domain id) */ + __u32 min_nwid; /* Minimal NWID we are able to set */ + __u32 max_nwid; /* Maximal NWID we are able to set */ + + /* Old Frequency (backward compat - moved lower ) */ + __u16 old_num_channels; + __u8 old_num_frequency; + + /* Scan capabilities */ + __u8 scan_capa; +}; +//YJ,add,080819,for hidden ap + + +static int rtl8180_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; + struct r8180_priv *priv = ieee80211_priv(dev); + u16 val; + int i; + //struct iw_range_with_scan_capa* tmp = (struct iw_range_with_scan_capa*)range; //YJ,add,080819,for hidden ap + + 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: Not used in 802.11b? +// range->min_nwid; /* Minimal NWID we are able to set */ + // TODO: Not used in 802.11b? +// range->max_nwid; /* Maximal NWID we are able to set */ + + /* Old Frequency (backward compat - moved lower ) */ +// range->old_num_channels; +// range->old_num_frequency; +// range->old_freq[6]; /* Filler to keep "version" at the same offset */ + if(priv->rf_set_sens != NULL) + range->sensitivity = priv->max_sens; /* signal level threshold range */ + + range->max_qual.qual = 100; + /* TODO: Find real max RSSI and stick here */ + range->max_qual.level = 0; + range->max_qual.noise = -98; + range->max_qual.updated = 7; /* Updated all three */ + + range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ + /* TODO: Find real 'good' to 'bad' threshol 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->retry_capa; /* What retry options are supported */ +// range->retry_flags; /* How to decode max/min retry limit */ +// range->r_time_flags; /* How to decode max/min retry life */ +// range->min_retry; /* Minimal number of retries */ +// range->max_retry; /* Maximal number of retries */ +// range->min_r_time; /* Minimal retry lifetime */ +// range->max_r_time; /* Maximal retry lifetime */ + + range->num_channels = 14; + + for (i = 0, val = 0; i < 14; i++) { + + // Include only legal frequencies for some countries +#ifdef ENABLE_DOT11D + if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { +#else + if ((priv->ieee80211->channel_map)[i+1]) { +#endif + range->freq[val].i = i + 1; + range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; + range->freq[val].e = 1; + val++; + } else { + // FIXME: do we need to set anything for channels + // we don't use ? + } + + 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; + + //tmp->scan_capa = 0x01; //YJ,add,080819,for hidden ap + + return 0; +} + + +static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret; + struct ieee80211_device* ieee = priv->ieee80211; + + + if(priv->ieee80211->bHwRadioOff) + return 0; + +//YJ,add,080819, for hidden ap + //printk("==*&*&*&==>%s in\n", __func__); + //printk("=*&*&*&*===>flag:%x, %x\n", wrqu->data.flags, IW_SCAN_THIS_ESSID); + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) + { + struct iw_scan_req* req = (struct iw_scan_req*)b; + if (req->essid_len) + { + //printk("==**&*&*&**===>scan set ssid:%s\n", req->essid); + ieee->current_network.ssid_len = req->essid_len; + memcpy(ieee->current_network.ssid, req->essid, req->essid_len); + //printk("=====>network ssid:%s\n", ieee->current_network.ssid); + } + } +//YJ,add,080819, for hidden ap, end + + down(&priv->wx_sem); + if(priv->up){ +#ifdef ENABLE_IPS +// printk("set scan ENABLE_IPS\n"); + priv->ieee80211->actscanning = true; + if(priv->bInactivePs && (priv->ieee80211->state != IEEE80211_LINKED)){ + IPSLeave(dev); +// down(&priv->ieee80211->wx_sem); + +// if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || !(priv->ieee80211->proto_started)){ +// ret = -1; +// up(&priv->ieee80211->wx_sem); +// up(&priv->wx_sem); +// return ret; +// } + + // queue_work(priv->ieee80211->wq, &priv->ieee80211->wx_sync_scan_wq); + //printk("start scan============================>\n"); + ieee80211_softmac_ips_scan_syncro(priv->ieee80211); +//ieee80211_start_scan(priv->ieee80211); + /* intentionally forget to up sem */ +// up(&priv->ieee80211->wx_sem); + ret = 0; + } + else +#endif + { + //YJ,add,080828, prevent scan in BusyTraffic + //FIXME: Need to consider last scan time + if ((priv->link_detect.bBusyTraffic) && (true)) + { + ret = 0; + printk("Now traffic is busy, please try later!\n"); + } + else + //YJ,add,080828, prevent scan in BusyTraffic,end + ret = ieee80211_wx_set_scan(priv->ieee80211,a,wrqu,b); + } + } + else + ret = -1; + + up(&priv->wx_sem); + + return ret; +} + + +static int r8180_wx_get_scan(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + + int ret; + struct r8180_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + if(priv->up) + ret = ieee80211_wx_get_scan(priv->ieee80211,a,wrqu,b); + else + ret = -1; + + up(&priv->wx_sem); + return ret; +} + + +static int r8180_wx_set_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + int ret; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); +#ifdef ENABLE_IPS + //printk("set essid ENABLE_IPS\n"); + if(priv->bInactivePs) + IPSLeave(dev); +#endif +// printk("haha:set essid %s essid_len = %d essid_flgs = %d\n",b, wrqu->essid.length, wrqu->essid.flags); + + ret = ieee80211_wx_set_essid(priv->ieee80211,a,wrqu,b); + + up(&priv->wx_sem); + return ret; +} + + +static int r8180_wx_get_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct r8180_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b); + + up(&priv->wx_sem); + + return ret; +} + + +static int r8180_wx_set_freq(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct r8180_priv *priv = ieee80211_priv(dev); + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b); + + up(&priv->wx_sem); + return ret; +} + + +static int r8180_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra); +} + +static int r8180_wx_set_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + if(priv->ieee80211->bHwRadioOff) + return 0; + + if (wrqu->frag.disabled) + priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; + else { + if (wrqu->frag.value < MIN_FRAG_THRESHOLD || + wrqu->frag.value > MAX_FRAG_THRESHOLD) + return -EINVAL; + + priv->ieee80211->fts = wrqu->frag.value & ~0x1; + } + + return 0; +} + + +static int r8180_wx_get_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + wrqu->frag.value = priv->ieee80211->fts; + wrqu->frag.fixed = 0; /* no auto select */ + wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); + + return 0; +} + + +static int r8180_wx_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + int ret; + struct r8180_priv *priv = ieee80211_priv(dev); + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_wap(priv->ieee80211,info,awrq,extra); + + up(&priv->wx_sem); + return ret; + +} + + +static int r8180_wx_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + return ieee80211_wx_get_wap(priv->ieee80211,info,wrqu,extra); +} + + +static int r8180_wx_set_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + + down(&priv->wx_sem); + + if(priv->hw_wep) ret = r8180_wx_set_key(dev,info,wrqu,key); + else{ + DMESG("Setting SW wep key"); + ret = ieee80211_wx_set_encode(priv->ieee80211,info,wrqu,key); + } + + up(&priv->wx_sem); + return ret; +} + + +static int r8180_wx_get_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key); +} + + +static int r8180_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, union + iwreq_data *wrqu, char *p){ + + struct r8180_priv *priv = ieee80211_priv(dev); + int *parms=(int*)p; + int mode=parms[0]; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + priv->ieee80211->active_scan = mode; + + return 1; +} + + +/* added by christian */ +/* +static int r8180_wx_set_monitor_type(struct net_device *dev, struct iw_request_info *aa, union + iwreq_data *wrqu, char *p){ + + struct r8180_priv *priv = ieee80211_priv(dev); + int *parms=(int*)p; + int mode=parms[0]; + + if(priv->ieee80211->iw_mode != IW_MODE_MONITOR) return -1; + priv->prism_hdr = mode; + if(!mode)dev->type=ARPHRD_IEEE80211; + else dev->type=ARPHRD_IEEE80211_PRISM; + DMESG("using %s RX encap", mode ? "AVS":"80211"); + return 0; + +} +*/ +//of r8180_wx_set_monitor_type +/* end added christian */ + +static int r8180_wx_set_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int err = 0; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + if (wrqu->retry.flags & IW_RETRY_LIFETIME || + wrqu->retry.disabled){ + err = -EINVAL; + goto exit; + } + if (!(wrqu->retry.flags & IW_RETRY_LIMIT)){ + err = -EINVAL; + goto exit; + } + + if(wrqu->retry.value > R8180_MAX_RETRY){ + err= -EINVAL; + goto exit; + } + if (wrqu->retry.flags & IW_RETRY_MAX) { + priv->retry_rts = wrqu->retry.value; + DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value); + + }else { + priv->retry_data = wrqu->retry.value; + DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value); + } + + /* FIXME ! + * We might try to write directly the TX config register + * or to restart just the (R)TX process. + * I'm unsure if whole reset is really needed + */ + + rtl8180_commit(dev); + /* + if(priv->up){ + rtl8180_rtx_disable(dev); + rtl8180_rx_enable(dev); + rtl8180_tx_enable(dev); + + } + */ +exit: + up(&priv->wx_sem); + + return err; +} + +static int r8180_wx_get_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + + wrqu->retry.disabled = 0; /* can't be disabled */ + + if ((wrqu->retry.flags & IW_RETRY_TYPE) == + IW_RETRY_LIFETIME) + return -EINVAL; + + if (wrqu->retry.flags & IW_RETRY_MAX) { + wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX; + wrqu->retry.value = priv->retry_rts; + } else { + wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN; + wrqu->retry.value = priv->retry_data; + } + //DMESG("returning %d",wrqu->retry.value); + + + return 0; +} + +static int r8180_wx_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + if(priv->rf_set_sens == NULL) + return -1; /* we have not this support for this radio */ + wrqu->sens.value = priv->sens; + return 0; +} + + +static int r8180_wx_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + struct r8180_priv *priv = ieee80211_priv(dev); + + short err = 0; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + //DMESG("attempt to set sensivity to %ddb",wrqu->sens.value); + if(priv->rf_set_sens == NULL) { + err= -1; /* we have not this support for this radio */ + goto exit; + } + if(priv->rf_set_sens(dev, wrqu->sens.value) == 0) + priv->sens = wrqu->sens.value; + else + err= -EINVAL; + +exit: + up(&priv->wx_sem); + + return err; +} + + +static int r8180_wx_set_rawtx(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; + +} + +static int r8180_wx_get_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8180_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + ret = ieee80211_wx_get_power(priv->ieee80211, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; +} + +static int r8180_wx_set_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8180_priv *priv = ieee80211_priv(dev); + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + printk("=>>>>>>>>>>=============================>set power:%d,%d!\n",wrqu->power.disabled, wrqu->power.flags); + if (wrqu->power.disabled==0) { + wrqu->power.flags|=IW_POWER_ALL_R; + wrqu->power.flags|=IW_POWER_TIMEOUT; + wrqu->power.value =1000; + } + + ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; +} + +static int r8180_wx_set_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + if (wrqu->rts.disabled) + priv->rts = DEFAULT_RTS_THRESHOLD; + else { + if (wrqu->rts.value < MIN_RTS_THRESHOLD || + wrqu->rts.value > MAX_RTS_THRESHOLD) + return -EINVAL; + + priv->rts = wrqu->rts.value; + } + + return 0; +} +static int r8180_wx_get_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + + + wrqu->rts.value = priv->rts; + wrqu->rts.fixed = 0; /* no auto select */ + wrqu->rts.disabled = (wrqu->rts.value == 0); + + return 0; +} +static int dummy(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu,char *b) +{ + return -1; +} + +/* +static int r8180_wx_get_psmode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee; + int ret = 0; + + + + down(&priv->wx_sem); + + if(priv) { + ieee = priv->ieee80211; + if(ieee->ps == IEEE80211_PS_DISABLED) { + *((unsigned int *)extra) = IEEE80211_PS_DISABLED; + goto exit; + } + *((unsigned int *)extra) = IW_POWER_TIMEOUT; + if (ieee->ps & IEEE80211_PS_MBCAST) + *((unsigned int *)extra) |= IW_POWER_ALL_R; + else + *((unsigned int *)extra) |= IW_POWER_UNICAST_R; + } else + ret = -1; +exit: + up(&priv->wx_sem); + + return ret; +} +static int r8180_wx_set_psmode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //struct ieee80211_device *ieee; + int ret = 0; + + + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; + +} +*/ + +static int r8180_wx_get_iwmode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee; + int ret = 0; + + + + down(&priv->wx_sem); + + ieee = priv->ieee80211; + + strcpy(extra, "802.11"); + if(ieee->modulation & IEEE80211_CCK_MODULATION) { + strcat(extra, "b"); + if(ieee->modulation & IEEE80211_OFDM_MODULATION) + strcat(extra, "/g"); + } else if(ieee->modulation & IEEE80211_OFDM_MODULATION) + strcat(extra, "g"); + + up(&priv->wx_sem); + + return ret; +} +static int r8180_wx_set_iwmode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; + int *param = (int *)extra; + int ret = 0; + int modulation = 0, mode = 0; + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + if (*param == 1) { + modulation |= IEEE80211_CCK_MODULATION; + mode = IEEE_B; + printk(KERN_INFO "B mode!\n"); + } else if (*param == 2) { + modulation |= IEEE80211_OFDM_MODULATION; + mode = IEEE_G; + printk(KERN_INFO "G mode!\n"); + } else if (*param == 3) { + modulation |= IEEE80211_CCK_MODULATION; + modulation |= IEEE80211_OFDM_MODULATION; + mode = IEEE_B|IEEE_G; + printk(KERN_INFO "B/G mode!\n"); + } + + if(ieee->proto_started) { + ieee80211_stop_protocol(ieee); + ieee->mode = mode; + ieee->modulation = modulation; + ieee80211_start_protocol(ieee); + } else { + ieee->mode = mode; + ieee->modulation = modulation; +// ieee80211_start_protocol(ieee); + } + + up(&priv->wx_sem); + + return ret; +} +static int r8180_wx_get_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + + + down(&priv->wx_sem); + + + + *extra = (char) priv->plcp_preamble_mode; // 0:auto 1:short 2:long + up(&priv->wx_sem); + + return 0; +} +static int r8180_wx_set_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + int ret = 0; + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + if (*extra<0||*extra>2) + ret = -1; + else + priv->plcp_preamble_mode = *((short *)extra) ; + + + + up(&priv->wx_sem); + + return ret; +} +static int r8180_wx_get_siglevel(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //struct ieee80211_network *network = &(priv->ieee80211->current_network); + int ret = 0; + + + + down(&priv->wx_sem); + // Modify by hikaru 6.5 + *((int *)extra) = priv->wstats.qual.level;//for interface test ,it should be the priv->wstats.qual.level; + + + + up(&priv->wx_sem); + + return ret; +} +static int r8180_wx_get_sigqual(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //struct ieee80211_network *network = &(priv->ieee80211->current_network); + int ret = 0; + + + + down(&priv->wx_sem); + // Modify by hikaru 6.5 + *((int *)extra) = priv->wstats.qual.qual;//for interface test ,it should be the priv->wstats.qual.qual; + + + + up(&priv->wx_sem); + + return ret; +} +static int r8180_wx_reset_stats(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv =ieee80211_priv(dev); + down(&priv->wx_sem); + + priv->stats.txrdu = 0; + priv->stats.rxrdu = 0; + priv->stats.rxnolast = 0; + priv->stats.rxnodata = 0; + priv->stats.rxnopointer = 0; + priv->stats.txnperr = 0; + priv->stats.txresumed = 0; + priv->stats.rxerr = 0; + priv->stats.rxoverflow = 0; + priv->stats.rxint = 0; + + priv->stats.txnpokint = 0; + priv->stats.txhpokint = 0; + priv->stats.txhperr = 0; + priv->stats.ints = 0; + priv->stats.shints = 0; + priv->stats.txoverflow = 0; + priv->stats.rxdmafail = 0; + priv->stats.txbeacon = 0; + priv->stats.txbeaconerr = 0; + priv->stats.txlpokint = 0; + priv->stats.txlperr = 0; + priv->stats.txretry =0;//20060601 + priv->stats.rxcrcerrmin=0; + priv->stats.rxcrcerrmid=0; + priv->stats.rxcrcerrmax=0; + priv->stats.rxicverr=0; + + up(&priv->wx_sem); + + return 0; + +} +static int r8180_wx_radio_on(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv =ieee80211_priv(dev); + + if(priv->ieee80211->bHwRadioOff) + return 0; + + + down(&priv->wx_sem); + priv->rf_wakeup(dev); + + up(&priv->wx_sem); + + return 0; + +} + +static int r8180_wx_radio_off(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv =ieee80211_priv(dev); + + if(priv->ieee80211->bHwRadioOff) + return 0; + + + down(&priv->wx_sem); + priv->rf_sleep(dev); + + up(&priv->wx_sem); + + return 0; + +} +static int r8180_wx_get_channelplan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + + + + down(&priv->wx_sem); + *extra = priv->channel_plan; + + + + up(&priv->wx_sem); + + return 0; +} +static int r8180_wx_set_channelplan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //struct ieee80211_device *ieee = netdev_priv(dev); + int *val = (int *)extra; + int i; + printk("-----in fun %s\n", __FUNCTION__); + + if(priv->ieee80211->bHwRadioOff) + return 0; + + //unsigned long flags; + down(&priv->wx_sem); + if (DefaultChannelPlan[*val].Len != 0){ + priv ->channel_plan = *val; + // Clear old channel map + for (i=1;i<=MAX_CHANNEL_NUMBER;i++) + { +#ifdef ENABLE_DOT11D + GET_DOT11D_INFO(priv->ieee80211)->channel_map[i] = 0; +#else + priv->ieee80211->channel_map[i] = 0; +#endif + } + // Set new channel map + for (i=1;i<=DefaultChannelPlan[*val].Len;i++) + { +#ifdef ENABLE_DOT11D + GET_DOT11D_INFO(priv->ieee80211)->channel_map[DefaultChannelPlan[*val].Channel[i-1]] = 1; +#else + priv->ieee80211->channel_map[DefaultChannelPlan[*val].Channel[i-1]] = 1; +#endif + } + } + up(&priv->wx_sem); + + return 0; +} + +static int r8180_wx_get_version(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + //struct ieee80211_device *ieee; + + down(&priv->wx_sem); + strcpy(extra, "1020.0808"); + up(&priv->wx_sem); + + return 0; +} + +//added by amy 080818 +//receive datarate from user typing valid rate is from 2 to 108 (1 - 54M), if input 0, return to normal rate adaptive. +static int r8180_wx_set_forcerate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + u8 forcerate = *extra; + + down(&priv->wx_sem); + + printk("==============>%s(): forcerate is %d\n",__FUNCTION__,forcerate); + if((forcerate == 2) || (forcerate == 4) || (forcerate == 11) || (forcerate == 22) || (forcerate == 12) || + (forcerate == 18) || (forcerate == 24) || (forcerate == 36) || (forcerate == 48) || (forcerate == 72) || + (forcerate == 96) || (forcerate == 108)) + { + priv->ForcedDataRate = 1; + priv->ieee80211->rate = forcerate * 5; + } + else if(forcerate == 0) + { + priv->ForcedDataRate = 0; + printk("OK! return rate adaptive\n"); + } + else + printk("ERR: wrong rate\n"); + up(&priv->wx_sem); + return 0; +} + +static int r8180_wx_set_enc_ext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + struct r8180_priv *priv = ieee80211_priv(dev); + //printk("===>%s()\n", __FUNCTION__); + + int ret=0; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra); + up(&priv->wx_sem); + return ret; + +} +static int r8180_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + //printk("====>%s()\n", __FUNCTION__); + struct r8180_priv *priv = ieee80211_priv(dev); + int ret=0; + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + ret = ieee80211_wx_set_auth(priv->ieee80211, info, data, extra); + up(&priv->wx_sem); + return ret; +} + +static int r8180_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + //printk("====>%s()\n", __FUNCTION__); + + int ret=0; + struct r8180_priv *priv = ieee80211_priv(dev); + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + + down(&priv->wx_sem); +#if 1 + ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra); +#endif + up(&priv->wx_sem); + return ret; +} +static int r8180_wx_set_gen_ie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ +// printk("====>%s(), len:%d\n", __FUNCTION__, data->length); + int ret=0; + struct r8180_priv *priv = ieee80211_priv(dev); + + + if(priv->ieee80211->bHwRadioOff) + return 0; + + down(&priv->wx_sem); +#if 1 + ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->length); +#endif + up(&priv->wx_sem); + //printk("<======%s(), ret:%d\n", __FUNCTION__, ret); + return ret; + + +} +static iw_handler r8180_wx_handlers[] = +{ + NULL, /* SIOCSIWCOMMIT */ + r8180_wx_get_name, /* SIOCGIWNAME */ + dummy, /* SIOCSIWNWID */ + dummy, /* SIOCGIWNWID */ + r8180_wx_set_freq, /* SIOCSIWFREQ */ + r8180_wx_get_freq, /* SIOCGIWFREQ */ + r8180_wx_set_mode, /* SIOCSIWMODE */ + r8180_wx_get_mode, /* SIOCGIWMODE */ + r8180_wx_set_sens, /* SIOCSIWSENS */ + r8180_wx_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + rtl8180_wx_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + dummy, /* SIOCSIWSPY */ + dummy, /* SIOCGIWSPY */ + NULL, /* SIOCGIWTHRSPY */ + NULL, /* SIOCWIWTHRSPY */ + r8180_wx_set_wap, /* SIOCSIWAP */ + r8180_wx_get_wap, /* SIOCGIWAP */ + r8180_wx_set_mlme, /* SIOCSIWMLME*/ + dummy, /* SIOCGIWAPLIST -- depricated */ + r8180_wx_set_scan, /* SIOCSIWSCAN */ + r8180_wx_get_scan, /* SIOCGIWSCAN */ + r8180_wx_set_essid, /* SIOCSIWESSID */ + r8180_wx_get_essid, /* SIOCGIWESSID */ + dummy, /* SIOCSIWNICKN */ + dummy, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + r8180_wx_set_rate, /* SIOCSIWRATE */ + r8180_wx_get_rate, /* SIOCGIWRATE */ + r8180_wx_set_rts, /* SIOCSIWRTS */ + r8180_wx_get_rts, /* SIOCGIWRTS */ + r8180_wx_set_frag, /* SIOCSIWFRAG */ + r8180_wx_get_frag, /* SIOCGIWFRAG */ + dummy, /* SIOCSIWTXPOW */ + dummy, /* SIOCGIWTXPOW */ + r8180_wx_set_retry, /* SIOCSIWRETRY */ + r8180_wx_get_retry, /* SIOCGIWRETRY */ + r8180_wx_set_enc, /* SIOCSIWENCODE */ + r8180_wx_get_enc, /* SIOCGIWENCODE */ + r8180_wx_set_power, /* SIOCSIWPOWER */ + r8180_wx_get_power, /* SIOCGIWPOWER */ + NULL, /*---hole---*/ + NULL, /*---hole---*/ + r8180_wx_set_gen_ie, /* SIOCSIWGENIE */ + NULL, /* SIOCSIWGENIE */ + r8180_wx_set_auth, /* SIOCSIWAUTH */ + NULL, /* SIOCSIWAUTH */ + r8180_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ + NULL, /* SIOCSIWENCODEEXT */ + NULL, /* SIOCSIWPMKSA */ + NULL, /*---hole---*/ +}; + + +static const struct iw_priv_args r8180_private_args[] = { + { + SIOCIWFIRSTPRIV + 0x0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" + }, + { SIOCIWFIRSTPRIV + 0x1, + 0, 0, "dummy" + + }, + { + SIOCIWFIRSTPRIV + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beaconint" + }, + { SIOCIWFIRSTPRIV + 0x3, + 0, 0, "dummy" + + }, + /* added by christian */ + //{ + // SIOCIWFIRSTPRIV + 0x2, + // IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prismhdr" + //}, + /* end added by christian */ + { + SIOCIWFIRSTPRIV + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" + + }, + { SIOCIWFIRSTPRIV + 0x5, + 0, 0, "dummy" + + }, + { + SIOCIWFIRSTPRIV + 0x6, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" + + }, + { SIOCIWFIRSTPRIV + 0x7, + 0, 0, "dummy" + + }, +// { +// SIOCIWFIRSTPRIV + 0x5, +// 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpsmode" +// }, +// { +// SIOCIWFIRSTPRIV + 0x6, +// IW_PRIV_SIZE_FIXED, 0, "setpsmode" +// }, +//set/get mode have been realized in public handlers + + { + SIOCIWFIRSTPRIV + 0x8, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setiwmode" + }, + { + SIOCIWFIRSTPRIV + 0x9, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 32, "getiwmode" + }, + { + SIOCIWFIRSTPRIV + 0xA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpreamble" + }, + { + SIOCIWFIRSTPRIV + 0xB, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpreamble" + }, + { SIOCIWFIRSTPRIV + 0xC, + 0, 0, "dummy" + }, + { + SIOCIWFIRSTPRIV + 0xD, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getrssi" + }, + { SIOCIWFIRSTPRIV + 0xE, + 0, 0, "dummy" + }, + { + SIOCIWFIRSTPRIV + 0xF, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getlinkqual" + }, + { + SIOCIWFIRSTPRIV + 0x10, + 0, 0, "resetstats" + }, + { + SIOCIWFIRSTPRIV + 0x11, + 0,0, "dummy" + }, + { + SIOCIWFIRSTPRIV + 0x12, + 0, 0, "radioon" + }, + { + SIOCIWFIRSTPRIV + 0x13, + 0, 0, "radiooff" + }, + { + SIOCIWFIRSTPRIV + 0x14, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setchannel" + }, + { + SIOCIWFIRSTPRIV + 0x15, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getchannel" + }, + { + SIOCIWFIRSTPRIV + 0x16, + 0,0, "dummy" + }, + { + SIOCIWFIRSTPRIV + 0x17, + 0,IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 32, "getversion" + }, + { + SIOCIWFIRSTPRIV + 0x18, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setrate" + }, +}; + + +static iw_handler r8180_private_handler[] = { + r8180_wx_set_crcmon, /*SIOCIWSECONDPRIV*/ + dummy, + r8180_wx_set_beaconinterval, + dummy, + //r8180_wx_set_monitor_type, + r8180_wx_set_scan_type, + dummy, + r8180_wx_set_rawtx, + dummy, + r8180_wx_set_iwmode, + r8180_wx_get_iwmode, + r8180_wx_set_preamble, + r8180_wx_get_preamble, + dummy, + r8180_wx_get_siglevel, + dummy, + r8180_wx_get_sigqual, + r8180_wx_reset_stats, + dummy,//r8180_wx_get_stats + r8180_wx_radio_on, + r8180_wx_radio_off, + r8180_wx_set_channelplan, + r8180_wx_get_channelplan, + dummy, + r8180_wx_get_version, + r8180_wx_set_forcerate, +}; + +#if WIRELESS_EXT >= 17 +static inline int is_same_network(struct ieee80211_network *src, + struct ieee80211_network *dst, + struct ieee80211_device *ieee) +{ + /* A network is only a duplicate if the channel, BSSID, ESSID + * and the capability field (in particular IBSS and BSS) all match. + * We treat all <hidden> with the same BSSID and channel + * as one network */ + return (((src->ssid_len == dst->ssid_len)||(ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod, 080819,for hidden ap + //((src->ssid_len == dst->ssid_len) && + (src->channel == dst->channel) && + !memcmp(src->bssid, dst->bssid, ETH_ALEN) && + (!memcmp(src->ssid, dst->ssid, src->ssid_len)||(ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod, 080819,for hidden ap + //!memcmp(src->ssid, dst->ssid, src->ssid_len) && + ((src->capability & WLAN_CAPABILITY_IBSS) == + (dst->capability & WLAN_CAPABILITY_IBSS)) && + ((src->capability & WLAN_CAPABILITY_BSS) == + (dst->capability & WLAN_CAPABILITY_BSS))); +} + +//WB modefied to show signal to GUI on 18-01-2008 +static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + struct iw_statistics* wstats = &priv->wstats; + //struct ieee80211_network* target = NULL; + int tmp_level = 0; + int tmp_qual = 0; + int tmp_noise = 0; + //unsigned long flag; + + if (ieee->state < IEEE80211_LINKED) + { + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + return wstats; + } +#if 0 + spin_lock_irqsave(&ieee->lock, flag); + list_for_each_entry(target, &ieee->network_list, list) + { + if (is_same_network(target, &ieee->current_network, ieee)) + { + printk("it's same network:%s\n", target->ssid); +#if 0 + if (!tmp_level) + { + tmp_level = target->stats.signalstrength; + tmp_qual = target->stats.signal; + } + else + { + + tmp_level = (15*tmp_level + target->stats.signalstrength)/16; + tmp_qual = (15*tmp_qual + target->stats.signal)/16; + } +#else + tmp_level = target->stats.signal; + tmp_qual = target->stats.signalstrength; + tmp_noise = target->stats.noise; + printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); +#endif + break; + } + } + spin_unlock_irqrestore(&ieee->lock, flag); +#endif + tmp_level = (&ieee->current_network)->stats.signal; + tmp_qual = (&ieee->current_network)->stats.signalstrength; + tmp_noise = (&ieee->current_network)->stats.noise; + //printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); + +// printk("level:%d\n", tmp_level); + wstats->qual.level = tmp_level; + wstats->qual.qual = tmp_qual; + wstats->qual.noise = tmp_noise; + wstats->qual.updated = IW_QUAL_ALL_UPDATED| IW_QUAL_DBM; + return wstats; +} +#endif + + +struct iw_handler_def r8180_wx_handlers_def={ + .standard = r8180_wx_handlers, + .num_standard = sizeof(r8180_wx_handlers) / sizeof(iw_handler), + .private = r8180_private_handler, + .num_private = sizeof(r8180_private_handler) / sizeof(iw_handler), + .num_private_args = sizeof(r8180_private_args) / sizeof(struct iw_priv_args), +#if WIRELESS_EXT >= 17 + .get_wireless_stats = r8180_get_wireless_stats, +#endif + .private_args = (struct iw_priv_args *)r8180_private_args, +}; + + diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h new file mode 100644 index 0000000..b20a67d --- /dev/null +++ b/drivers/staging/rtl8187se/r8180_wx.h @@ -0,0 +1,21 @@ +/* + This is part of rtl8180 OpenSource driver - v 0.3 + Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the official realtek driver + Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of such projects and the Ndiswrapper project Authors. +*/ + +/* this file (will) contains wireless extension handlers*/ + +#ifndef R8180_WX_H +#define R8180_WX_H +#include <linux/wireless.h> +#include "ieee80211.h" +extern struct iw_handler_def r8180_wx_handlers_def; + +#endif diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c new file mode 100644 index 0000000..4b885a2 --- /dev/null +++ b/drivers/staging/rtl8187se/r8185b_init.c @@ -0,0 +1,3342 @@ +/*++ +Copyright (c) Realtek Semiconductor Corp. All rights reserved. + +Module Name: + r8185b_init.c + +Abstract: + Hardware Initialization and Hardware IO for RTL8185B + +Major Change History: + When Who What + ---------- --------------- ------------------------------- + 2006-11-15 Xiong Created + +Notes: + This file is ported from RTL8185B Windows driver. + + +--*/ + +/*--------------------------Include File------------------------------------*/ +#include <linux/spinlock.h> +#include "r8180_hw.h" +#include "r8180.h" +#include "r8180_sa2400.h" /* PHILIPS Radio frontend */ +#include "r8180_max2820.h" /* MAXIM Radio frontend */ +#include "r8180_gct.h" /* GCT Radio frontend */ +#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ +#include "r8180_rtl8255.h" /* RTL8255 Radio frontend */ +#include "r8180_93cx6.h" /* Card EEPROM */ +#include "r8180_wx.h" + +#ifdef CONFIG_RTL8180_PM +#include "r8180_pm.h" +#endif + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +#ifdef CONFIG_RTL8185B + +//#define CONFIG_RTL8180_IO_MAP + +#define TC_3W_POLL_MAX_TRY_CNT 5 +#ifdef CONFIG_RTL818X_S +static u8 MAC_REG_TABLE[][2]={ + //PAGA 0: + // 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() + // 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). + // 0x1F0~0x1F8 set in MacConfig_85BASIC() + {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42}, + {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03}, + {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03}, + {0x94, 0x0F}, {0x95, 0x32}, + {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00}, + {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32}, + {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4}, + {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00}, + {0xff, 0x00}, + + //PAGE 1: + // For Flextronics system Logo PCIHCT failure: + // 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 + {0x5e, 0x01}, + {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24}, + {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF}, + {0x82, 0xFF}, {0x83, 0x03}, + {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, //lzm add 080826 + {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22},//lzm add 080826 + {0xe2, 0x00}, + + + //PAGE 2: + {0x5e, 0x02}, + {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5}, + {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff}, + {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08}, + {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f}, + {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f}, + {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff}, + {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00}, + + //PAGA 0: + {0x5e, 0x00},{0x9f, 0x03} + }; + + +static u8 ZEBRA_AGC[]={ + 0, + 0x7E,0x7E,0x7E,0x7E,0x7D,0x7C,0x7B,0x7A,0x79,0x78,0x77,0x76,0x75,0x74,0x73,0x72, + 0x71,0x70,0x6F,0x6E,0x6D,0x6C,0x6B,0x6A,0x69,0x68,0x67,0x66,0x65,0x64,0x63,0x62, + 0x48,0x47,0x46,0x45,0x44,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x08,0x07, + 0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x11,0x12,0x13,0x15,0x16, + 0x17,0x17,0x18,0x18,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e, + 0x1f,0x1f,0x1f,0x20,0x20,0x20,0x20,0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x24, + 0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F + }; + +static u32 ZEBRA_RF_RX_GAIN_TABLE[]={ + 0x0096,0x0076,0x0056,0x0036,0x0016,0x01f6,0x01d6,0x01b6, + 0x0196,0x0176,0x00F7,0x00D7,0x00B7,0x0097,0x0077,0x0057, + 0x0037,0x00FB,0x00DB,0x00BB,0x00FF,0x00E3,0x00C3,0x00A3, + 0x0083,0x0063,0x0043,0x0023,0x0003,0x01E3,0x01C3,0x01A3, + 0x0183,0x0163,0x0143,0x0123,0x0103 + }; + +static u8 OFDM_CONFIG[]={ + // OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX + // OFDM reg0x3C[4]=1'b1: Enable RX power saving mode + // ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test + + // 0x00 + 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, + // 0x10 + 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26, + 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB, + // 0x20 + 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00, + 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00, + // 0x30 + 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e, + 0xD8, 0x3C, 0x7B, 0x10, 0x10 + }; +#else + static u8 MAC_REG_TABLE[][2]={ + //PAGA 0: + {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32}, + {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4}, + {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00}, + {0xff, 0x00}, + + //PAGE 1: + {0x5e, 0x01}, + {0x58, 0x4b}, {0x59, 0x00}, {0x5a, 0x4b}, {0x5b, 0x00}, {0x60, 0x4b}, + {0x61, 0x09}, {0x62, 0x4b}, {0x63, 0x09}, {0xce, 0x0f}, {0xcf, 0x00}, + {0xe0, 0xff}, {0xe1, 0x0f}, {0xe2, 0x00}, {0xf0, 0x4e}, {0xf1, 0x01}, + {0xf2, 0x02}, {0xf3, 0x03}, {0xf4, 0x04}, {0xf5, 0x05}, {0xf6, 0x06}, + {0xf7, 0x07}, {0xf8, 0x08}, + + + //PAGE 2: + {0x5e, 0x02}, + {0x0c, 0x04}, {0x21, 0x61}, {0x22, 0x68}, {0x23, 0x6f}, {0x24, 0x76}, + {0x25, 0x7d}, {0x26, 0x84}, {0x27, 0x8d}, {0x4d, 0x08}, {0x4e, 0x00}, + {0x50, 0x05}, {0x51, 0xf5}, {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0x1f}, + {0x55, 0x23}, {0x56, 0x45}, {0x57, 0x67}, {0x58, 0x08}, {0x59, 0x08}, + {0x5a, 0x08}, {0x5b, 0x08}, {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, + {0x63, 0x08}, {0x64, 0xcf}, {0x72, 0x56}, {0x73, 0x9a}, + + //PAGA 0: + {0x5e, 0x00}, + {0x34, 0xff}, {0x35, 0x0f}, {0x5b, 0x40}, {0x84, 0x88}, {0x85, 0x24}, + {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x07}, {0x8d, 0x00}, {0x94, 0x1b}, + {0x95, 0x12}, {0x96, 0x00}, {0x97, 0x06}, {0x9d, 0x1a}, {0x9f, 0x10}, + {0xb4, 0x22}, {0xbe, 0x80}, {0xdb, 0x00}, {0xee, 0x00}, {0x5b, 0x42}, + {0x91, 0x03}, + + //PAGE 2: + {0x5e, 0x02}, + {0x4c, 0x03}, + + //PAGE 0: + {0x5e, 0x00}, + + //PAGE 3: + {0x5e, 0x03}, + {0x9f, 0x00}, + + //PAGE 0: + {0x5e, 0x00}, + {0x8c, 0x01}, {0x8d, 0x10},{0x8e, 0x08}, {0x8f, 0x00} + }; + + +static u8 ZEBRA_AGC[]={ + 0, + 0x5e,0x5e,0x5e,0x5e,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4d,0x4b,0x49,0x47, + 0x45,0x43,0x41,0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2d,0x2b,0x29,0x27, + 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0d,0x0b,0x09,0x07, + 0x05,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x19,0x19,0x19,0x019,0x19,0x19,0x19,0x19,0x19,0x19,0x1e,0x1f,0x20,0x21,0x21,0x22, + 0x23,0x24,0x24,0x25,0x25,0x26,0x26,0x27,0x27,0x28,0x28,0x28,0x29,0x2a,0x2a,0x2b, + 0x2b,0x2b,0x2c,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2f,0x30,0x31,0x31,0x31,0x31, + 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31 + }; + +static u32 ZEBRA_RF_RX_GAIN_TABLE[]={ + 0, + 0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0408,0x0409, + 0x040a,0x040b,0x0502,0x0503,0x0504,0x0505,0x0540,0x0541, + 0x0542,0x0543,0x0544,0x0545,0x0580,0x0581,0x0582,0x0583, + 0x0584,0x0585,0x0588,0x0589,0x058a,0x058b,0x0643,0x0644, + 0x0645,0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0688, + 0x0689,0x068a,0x068b,0x068c,0x0742,0x0743,0x0744,0x0745, + 0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0788,0x0789, + 0x078a,0x078b,0x078c,0x078d,0x0790,0x0791,0x0792,0x0793, + 0x0794,0x0795,0x0798,0x0799,0x079a,0x079b,0x079c,0x079d, + 0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a8,0x07a9, + 0x03aa,0x03ab,0x03ac,0x03ad,0x03b0,0x03b1,0x03b2,0x03b3, + 0x03b4,0x03b5,0x03b8,0x03b9,0x03ba,0x03bb,0x03bb +}; + +// 2006.07.13, SD3 szuyitasi: +// OFDM.0x03=0x0C (original is 0x0F) +// Use the new SD3 given param, by shien chang, 2006.07.14 +static u8 OFDM_CONFIG[]={ + 0x10, 0x0d, 0x01, 0x0C, 0x14, 0xfb, 0x0f, 0x60, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, + 0x00, 0x00, 0xa8, 0x46, 0xb2, 0x33, 0x07, 0xa5, 0x6f, 0x55, + 0xc8, 0xb3, 0x0a, 0xe1, 0x1c, 0x8a, 0xb6, 0x83, 0x34, 0x0f, + 0x4f, 0x23, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, 0xc0, 0xc1, + 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, 0x6d, 0x3c, 0xff, 0x07 +}; +#endif + +/*--------------------------------------------------------------- + * Hardware IO + * the code is ported from Windows source code + ----------------------------------------------------------------*/ + +void +PlatformIOWrite1Byte( + struct net_device *dev, + u32 offset, + u8 data + ) +{ +#ifndef CONFIG_RTL8180_IO_MAP + write_nic_byte(dev, offset, data); + read_nic_byte(dev, offset); // To make sure write operation is completed, 2005.11.09, by rcnjko. + +#else // Port IO + u32 Page = (offset >> 8); + + switch(Page) + { + case 0: // Page 0 + write_nic_byte(dev, offset, data); + break; + + case 1: // Page 1 + case 2: // Page 2 + case 3: // Page 3 + { + u8 psr = read_nic_byte(dev, PSR); + + write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. + write_nic_byte(dev, (offset & 0xff), data); + write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. + } + break; + + default: + // Illegal page number. + DMESGE("PlatformIOWrite1Byte(): illegal page number: %d, offset: %#X", Page, offset); + break; + } +#endif +} + +void +PlatformIOWrite2Byte( + struct net_device *dev, + u32 offset, + u16 data + ) +{ +#ifndef CONFIG_RTL8180_IO_MAP + write_nic_word(dev, offset, data); + read_nic_word(dev, offset); // To make sure write operation is completed, 2005.11.09, by rcnjko. + + +#else // Port IO + u32 Page = (offset >> 8); + + switch(Page) + { + case 0: // Page 0 + write_nic_word(dev, offset, data); + break; + + case 1: // Page 1 + case 2: // Page 2 + case 3: // Page 3 + { + u8 psr = read_nic_byte(dev, PSR); + + write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. + write_nic_word(dev, (offset & 0xff), data); + write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. + } + break; + + default: + // Illegal page number. + DMESGE("PlatformIOWrite2Byte(): illegal page number: %d, offset: %#X", Page, offset); + break; + } +#endif +} +u8 PlatformIORead1Byte(struct net_device *dev, u32 offset); + +void +PlatformIOWrite4Byte( + struct net_device *dev, + u32 offset, + u32 data + ) +{ +#ifndef CONFIG_RTL8180_IO_MAP +//{by amy 080312 +if (offset == PhyAddr) + {//For Base Band configuration. + unsigned char cmdByte; + unsigned long dataBytes; + unsigned char idx; + u8 u1bTmp; + + cmdByte = (u8)(data & 0x000000ff); + dataBytes = data>>8; + + // + // 071010, rcnjko: + // The critical section is only BB read/write race condition. + // Assumption: + // 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for + // acquiring the spinlock in such context. + // 2. PlatformIOWrite4Byte() MUST NOT be recursive. + // +// NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); + + for(idx = 0; idx < 30; idx++) + { // Make sure command bit is clear before access it. + u1bTmp = PlatformIORead1Byte(dev, PhyAddr); + if((u1bTmp & BIT7) == 0) + break; + else + mdelay(10); + } + + for(idx=0; idx < 3; idx++) + { + PlatformIOWrite1Byte(dev,offset+1+idx,((u8*)&dataBytes)[idx] ); + } + write_nic_byte(dev, offset, cmdByte); + +// NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); + } +//by amy 080312} + else{ + write_nic_dword(dev, offset, data); + read_nic_dword(dev, offset); // To make sure write operation is completed, 2005.11.09, by rcnjko. + } +#else // Port IO + u32 Page = (offset >> 8); + + switch(Page) + { + case 0: // Page 0 + write_nic_word(dev, offset, data); + break; + + case 1: // Page 1 + case 2: // Page 2 + case 3: // Page 3 + { + u8 psr = read_nic_byte(dev, PSR); + + write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. + write_nic_dword(dev, (offset & 0xff), data); + write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. + } + break; + + default: + // Illegal page number. + DMESGE("PlatformIOWrite4Byte(): illegal page number: %d, offset: %#X", Page, offset); + break; + } +#endif +} + +u8 +PlatformIORead1Byte( + struct net_device *dev, + u32 offset + ) +{ + u8 data = 0; + +#ifndef CONFIG_RTL8180_IO_MAP + data = read_nic_byte(dev, offset); + +#else // Port IO + u32 Page = (offset >> 8); + + switch(Page) + { + case 0: // Page 0 + data = read_nic_byte(dev, offset); + break; + + case 1: // Page 1 + case 2: // Page 2 + case 3: // Page 3 + { + u8 psr = read_nic_byte(dev, PSR); + + write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. + data = read_nic_byte(dev, (offset & 0xff)); + write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. + } + break; + + default: + // Illegal page number. + DMESGE("PlatformIORead1Byte(): illegal page number: %d, offset: %#X", Page, offset); + break; + } +#endif + + return data; +} + +u16 +PlatformIORead2Byte( + struct net_device *dev, + u32 offset + ) +{ + u16 data = 0; + +#ifndef CONFIG_RTL8180_IO_MAP + data = read_nic_word(dev, offset); + +#else // Port IO + u32 Page = (offset >> 8); + + switch(Page) + { + case 0: // Page 0 + data = read_nic_word(dev, offset); + break; + + case 1: // Page 1 + case 2: // Page 2 + case 3: // Page 3 + { + u8 psr = read_nic_byte(dev, PSR); + + write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. + data = read_nic_word(dev, (offset & 0xff)); + write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. + } + break; + + default: + // Illegal page number. + DMESGE("PlatformIORead2Byte(): illegal page number: %d, offset: %#X", Page, offset); + break; + } +#endif + + return data; +} + +u32 +PlatformIORead4Byte( + struct net_device *dev, + u32 offset + ) +{ + u32 data = 0; + +#ifndef CONFIG_RTL8180_IO_MAP + data = read_nic_dword(dev, offset); + +#else // Port IO + u32 Page = (offset >> 8); + + switch(Page) + { + case 0: // Page 0 + data = read_nic_dword(dev, offset); + break; + + case 1: // Page 1 + case 2: // Page 2 + case 3: // Page 3 + { + u8 psr = read_nic_byte(dev, PSR); + + write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. + data = read_nic_dword(dev, (offset & 0xff)); + write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. + } + break; + + default: + // Illegal page number. + DMESGE("PlatformIORead4Byte(): illegal page number: %d, offset: %#X\n", Page, offset); + break; + } +#endif + + return data; +} + +void +SetOutputEnableOfRfPins( + struct net_device *dev + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + switch(priv->rf_chip) + { + case RFCHIPID_RTL8225: + case RF_ZEBRA2: + case RF_ZEBRA4: + write_nic_word(dev, RFPinsEnable, 0x1bff); + //write_nic_word(dev, RFPinsEnable, 0x1fff); + break; + } +} + +void +ZEBRA_RFSerialWrite( + struct net_device *dev, + u32 data2Write, + u8 totalLength, + u8 low2high + ) +{ + ThreeWireReg twreg; + int i; + u16 oval,oval2,oval3; + u32 mask; + u16 UshortBuffer; + + u8 u1bTmp; +#ifdef CONFIG_RTL818X_S + // RTL8187S HSSI Read/Write Function + u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); + u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI) + write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); +#endif + UshortBuffer = read_nic_word(dev, RFPinsOutput); + oval = UshortBuffer & 0xfff8; // We shall clear bit0, 1, 2 first, 2005.10.28, by rcnjko. + + oval2 = read_nic_word(dev, RFPinsEnable); + oval3 = read_nic_word(dev, RFPinsSelect); + + // <RJ_NOTE> 3-wire should be controled by HW when we finish SW 3-wire programming. 2005.08.10, by rcnjko. + oval3 &= 0xfff8; + + write_nic_word(dev, RFPinsEnable, (oval2|0x0007)); // Set To Output Enable + write_nic_word(dev, RFPinsSelect, (oval3|0x0007)); // Set To SW Switch + udelay(10); + + // Add this to avoid hardware and software 3-wire conflict. + // 2005.03.01, by rcnjko. + twreg.longData = 0; + twreg.struc.enableB = 1; + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); // Set SI_EN (RFLE) + udelay(2); + twreg.struc.enableB = 0; + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); // Clear SI_EN (RFLE) + udelay(10); + + mask = (low2high)?0x01:((u32)0x01<<(totalLength-1)); + + for(i=0; i<totalLength/2; i++) + { + twreg.struc.data = ((data2Write&mask)!=0) ? 1 : 0; + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); + twreg.struc.clk = 1; + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); + + mask = (low2high)?(mask<<1):(mask>>1); + twreg.struc.data = ((data2Write&mask)!=0) ? 1 : 0; + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); + twreg.struc.clk = 0; + write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); + mask = (low2high)?(mask<<1):(mask>>1); + } + + twreg.struc.enableB = 1; + twreg.struc.clk = 0; + twreg.struc.data = 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); + udelay(10); + + write_nic_word(dev, RFPinsOutput, oval|0x0004); + write_nic_word(dev, RFPinsSelect, oval3|0x0000); + + SetOutputEnableOfRfPins(dev); +} +//by amy + + +int +HwHSSIThreeWire( + struct net_device *dev, + u8 *pDataBuf, + u8 nDataBufBitCnt, + int bSI, + int bWrite + ) +{ + int bResult = 1; + u8 TryCnt; + u8 u1bTmp; + + do + { + // Check if WE and RE are cleared. + for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) + { + u1bTmp = read_nic_byte(dev, SW_3W_CMD1); + if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 ) + { + break; + } + udelay(10); + } + if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) + panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp); + + // RTL8187S HSSI Read/Write Function + u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); + + if(bSI) + { + u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI) + }else + { + u1bTmp &= ~RF_SW_CFG_SI; //reg08[1]=0 Parallel Interface(PI) + } + + write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); + + if(bSI) + { + // jong: HW SI read must set reg84[3]=0. + u1bTmp = read_nic_byte(dev, RFPinsSelect); + u1bTmp &= ~BIT3; + write_nic_byte(dev, RFPinsSelect, u1bTmp ); + } + // Fill up data buffer for write operation. + + if(bWrite) + { + if(nDataBufBitCnt == 16) + { + write_nic_word(dev, SW_3W_DB0, *((u16*)pDataBuf)); + } + else if(nDataBufBitCnt == 64) // RTL8187S shouldn't enter this case + { + write_nic_dword(dev, SW_3W_DB0, *((u32*)pDataBuf)); + write_nic_dword(dev, SW_3W_DB1, *((u32*)(pDataBuf + 4))); + } + else + { + int idx; + int ByteCnt = nDataBufBitCnt / 8; + //printk("%d\n",nDataBufBitCnt); + if ((nDataBufBitCnt % 8) != 0) + panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n", + nDataBufBitCnt); + + if (nDataBufBitCnt > 64) + panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n", + nDataBufBitCnt); + + for(idx = 0; idx < ByteCnt; idx++) + { + write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx)); + } + } + } + else //read + { + if(bSI) + { + // SI - reg274[3:0] : RF register's Address + write_nic_word(dev, SW_3W_DB0, *((u16*)pDataBuf) ); + } + else + { + // PI - reg274[15:12] : RF register's Address + write_nic_word(dev, SW_3W_DB0, (*((u16*)pDataBuf)) << 12); + } + } + + // Set up command: WE or RE. + if(bWrite) + { + write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_WE); + } + else + { + write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_RE); + } + + // Check if DONE is set. + for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) + { + u1bTmp = read_nic_byte(dev, SW_3W_CMD1); + if( (u1bTmp & SW_3W_CMD1_DONE) != 0 ) + { + break; + } + udelay(10); + } + + write_nic_byte(dev, SW_3W_CMD1, 0); + + // Read back data for read operation. + if(bWrite == 0) + { + if(bSI) + { + //Serial Interface : reg363_362[11:0] + *((u16*)pDataBuf) = read_nic_word(dev, SI_DATA_READ) ; + } + else + { + //Parallel Interface : reg361_360[11:0] + *((u16*)pDataBuf) = read_nic_word(dev, PI_DATA_READ); + } + + *((u16*)pDataBuf) &= 0x0FFF; + } + + }while(0); + + return bResult; +} +//by amy + +int +HwThreeWire( + struct net_device *dev, + u8 *pDataBuf, + u8 nDataBufBitCnt, + int bHold, + int bWrite + ) +{ + int bResult = 1; + u8 TryCnt; + u8 u1bTmp; + + do + { + // Check if WE and RE are cleared. + for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) + { + u1bTmp = read_nic_byte(dev, SW_3W_CMD1); + if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 ) + { + break; + } + udelay(10); + } + if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) + panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp); + + // Fill up data buffer for write operation. + if(nDataBufBitCnt == 16) + { + write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf)); + } + else if(nDataBufBitCnt == 64) + { + write_nic_dword(dev, SW_3W_DB0, *((u32 *)pDataBuf)); + write_nic_dword(dev, SW_3W_DB1, *((u32 *)(pDataBuf + 4))); + } + else + { + int idx; + int ByteCnt = nDataBufBitCnt / 8; + + if ((nDataBufBitCnt % 8) != 0) + panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n", + nDataBufBitCnt); + + if (nDataBufBitCnt > 64) + panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n", + nDataBufBitCnt); + + for(idx = 0; idx < ByteCnt; idx++) + { + write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx)); + } + } + + // Fill up length field. + u1bTmp = (u8)(nDataBufBitCnt - 1); // Number of bits - 1. + if(bHold) + u1bTmp |= SW_3W_CMD0_HOLD; + write_nic_byte(dev, SW_3W_CMD0, u1bTmp); + + // Set up command: WE or RE. + if(bWrite) + { + write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_WE); + } + else + { + write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_RE); + } + + // Check if WE and RE are cleared and DONE is set. + for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) + { + u1bTmp = read_nic_byte(dev, SW_3W_CMD1); + if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 && + (u1bTmp & SW_3W_CMD1_DONE) != 0 ) + { + break; + } + udelay(10); + } + if(TryCnt == TC_3W_POLL_MAX_TRY_CNT) + { + //RT_ASSERT(TryCnt != TC_3W_POLL_MAX_TRY_CNT, + // ("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear or DONE is not set!!\n", u1bTmp)); + // Workaround suggested by wcchu: clear WE here. 2006.07.07, by rcnjko. + write_nic_byte(dev, SW_3W_CMD1, 0); + } + + // Read back data for read operation. + // <RJ_TODO> I am not sure if this is correct output format of a read operation. + if(bWrite == 0) + { + if(nDataBufBitCnt == 16) + { + *((u16 *)pDataBuf) = read_nic_word(dev, SW_3W_DB0); + } + else if(nDataBufBitCnt == 64) + { + *((u32 *)pDataBuf) = read_nic_dword(dev, SW_3W_DB0); + *((u32 *)(pDataBuf + 4)) = read_nic_dword(dev, SW_3W_DB1); + } + else + { + int idx; + int ByteCnt = nDataBufBitCnt / 8; + + if ((nDataBufBitCnt % 8) != 0) + panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n", + nDataBufBitCnt); + + if (nDataBufBitCnt > 64) + panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n", + nDataBufBitCnt); + + for(idx = 0; idx < ByteCnt; idx++) + { + *(pDataBuf+idx) = read_nic_byte(dev, (SW_3W_DB0+idx)); + } + } + } + + }while(0); + + return bResult; +} + + +void +RF_WriteReg( + struct net_device *dev, + u8 offset, + u32 data + ) +{ + //RFReg reg; + u32 data2Write; + u8 len; + u8 low2high; + //u32 RF_Read = 0; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + + switch(priv->rf_chip) + { + case RFCHIPID_RTL8225: + case RF_ZEBRA2: // Annie 2006-05-12. + case RF_ZEBRA4: //by amy + switch(priv->RegThreeWireMode) + { + case SW_THREE_WIRE: + { // Perform SW 3-wire programming by driver. + data2Write = (data << 4) | (u32)(offset & 0x0f); + len = 16; + low2high = 0; + ZEBRA_RFSerialWrite(dev, data2Write, len, low2high); + } + break; + + case HW_THREE_WIRE: + { // Pure HW 3-wire. + data2Write = (data << 4) | (u32)(offset & 0x0f); + len = 16; + HwThreeWire( + dev, + (u8 *)(&data2Write), // pDataBuf, + len, // nDataBufBitCnt, + 0, // bHold, + 1); // bWrite + } + break; + #ifdef CONFIG_RTL818X_S + case HW_THREE_WIRE_PI: //Parallel Interface + { // Pure HW 3-wire. + data2Write = (data << 4) | (u32)(offset & 0x0f); + len = 16; + HwHSSIThreeWire( + dev, + (u8*)(&data2Write), // pDataBuf, + len, // nDataBufBitCnt, + 0, // bSI + 1); // bWrite + + //printk("33333\n"); + } + break; + + case HW_THREE_WIRE_SI: //Serial Interface + { // Pure HW 3-wire. + data2Write = (data << 4) | (u32)(offset & 0x0f); + len = 16; +// printk(" enter ZEBRA_RFSerialWrite\n "); +// low2high = 0; +// ZEBRA_RFSerialWrite(dev, data2Write, len, low2high); + + HwHSSIThreeWire( + dev, + (u8*)(&data2Write), // pDataBuf, + len, // nDataBufBitCnt, + 1, // bSI + 1); // bWrite + +// printk(" exit ZEBRA_RFSerialWrite\n "); + } + break; + #endif + + + default: + DMESGE("RF_WriteReg(): invalid RegThreeWireMode(%d) !!!", priv->RegThreeWireMode); + break; + } + break; + + default: + DMESGE("RF_WriteReg(): unknown RFChipID: %#X", priv->rf_chip); + break; + } +} + + +void +ZEBRA_RFSerialRead( + struct net_device *dev, + u32 data2Write, + u8 wLength, + u32 *data2Read, + u8 rLength, + u8 low2high + ) +{ + ThreeWireReg twreg; + int i; + u16 oval,oval2,oval3,tmp, wReg80; + u32 mask; + u8 u1bTmp; + ThreeWireReg tdata; + //PHAL_DATA_8187 pHalData = GetHalData8187(pAdapter); +#ifdef CONFIG_RTL818X_S + { // RTL8187S HSSI Read/Write Function + u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); + u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI) + write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); + } +#endif + + wReg80 = oval = read_nic_word(dev, RFPinsOutput); + oval2 = read_nic_word(dev, RFPinsEnable); + oval3 = read_nic_word(dev, RFPinsSelect); + + write_nic_word(dev, RFPinsEnable, oval2|0xf); + write_nic_word(dev, RFPinsSelect, oval3|0xf); + + *data2Read = 0; + + // We must clear BIT0-3 here, otherwise, + // SW_Enalbe will be true when we first call ZEBRA_RFSerialRead() after 8187MPVC open, + // which will cause the value read become 0. 2005.04.11, by rcnjko. + oval &= ~0xf; + + // Avoid collision with hardware three-wire. + twreg.longData = 0; + twreg.struc.enableB = 1; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(4); + + twreg.longData = 0; + twreg.struc.enableB = 0; + twreg.struc.clk = 0; + twreg.struc.read_write = 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(5); + + mask = (low2high) ? 0x01 : ((u32)0x01<<(32-1)); + for(i = 0; i < wLength/2; i++) + { + twreg.struc.data = ((data2Write&mask) != 0) ? 1 : 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1); + twreg.struc.clk = 1; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + + mask = (low2high) ? (mask<<1): (mask>>1); + + if(i == 2) + { + // Commented out by Jackie, 2004.08.26. <RJ_NOTE> We must comment out the following two lines for we cannot pull down VCOPDN during RF Serail Read. + //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, 0xe); // turn off data enable + //PlatformEFIOWrite2Byte(pAdapter, RFPinsSelect, 0xe); + + twreg.struc.read_write=1; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + twreg.struc.clk = 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + break; + } + twreg.struc.data = ((data2Write&mask) != 0) ? 1: 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + + twreg.struc.clk = 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1); + + mask = (low2high) ? (mask<<1) : (mask>>1); + } + + twreg.struc.clk = 0; + twreg.struc.data = 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + mask = (low2high) ? 0x01 : ((u32)0x01 << (12-1)); + + // + // 061016, by rcnjko: + // We must set data pin to HW controled, otherwise RF can't driver it and + // value RF register won't be able to read back properly. + // + write_nic_word(dev, RFPinsEnable, ( ((oval2|0x0E) & (~0x01))) ); + + for(i = 0; i < rLength; i++) + { + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1); + twreg.struc.clk = 1; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + tmp = read_nic_word(dev, RFPinsInput); + tdata.longData = tmp; + *data2Read |= tdata.struc.clk ? mask : 0; + + twreg.struc.clk = 0; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + + mask = (low2high) ? (mask<<1) : (mask>>1); + } + twreg.struc.enableB = 1; + twreg.struc.clk = 0; + twreg.struc.data = 0; + twreg.struc.read_write = 1; + write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); + + //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, oval2|0x8); // Set To Output Enable + write_nic_word(dev, RFPinsEnable, oval2); // Set To Output Enable, <RJ_NOTE> We cannot enable BIT3 here, otherwise, we will failed to switch channel. 2005.04.12. + //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, 0x1bff); + write_nic_word(dev, RFPinsSelect, oval3); // Set To SW Switch + //PlatformEFIOWrite2Byte(pAdapter, RFPinsSelect, 0x0488); + write_nic_word(dev, RFPinsOutput, 0x3a0); + //PlatformEFIOWrite2Byte(pAdapter, RFPinsOutput, 0x0480); +} + + +u32 +RF_ReadReg( + struct net_device *dev, + u8 offset + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32 data2Write; + u8 wlen; + u8 rlen; + u8 low2high; + u32 dataRead; + + switch(priv->rf_chip) + { + case RFCHIPID_RTL8225: + case RF_ZEBRA2: + case RF_ZEBRA4: + switch(priv->RegThreeWireMode) + { +#ifdef CONFIG_RTL818X_S + case HW_THREE_WIRE_PI: // For 87S Parallel Interface. + { + data2Write = ((u32)(offset&0x0f)); + wlen=16; + HwHSSIThreeWire( + dev, + (u8*)(&data2Write), // pDataBuf, + wlen, // nDataBufBitCnt, + 0, // bSI + 0); // bWrite + dataRead= data2Write; + } + break; + + case HW_THREE_WIRE_SI: // For 87S Serial Interface. + { + data2Write = ((u32)(offset&0x0f)) ; + wlen=16; + HwHSSIThreeWire( + dev, + (u8*)(&data2Write), // pDataBuf, + wlen, // nDataBufBitCnt, + 1, // bSI + 0 // bWrite + ); + dataRead= data2Write; + } + break; + +#endif + // Perform SW 3-wire programming by driver. + default: + { + data2Write = ((u32)(offset&0x1f)) << 27; // For Zebra E-cut. 2005.04.11, by rcnjko. + wlen = 6; + rlen = 12; + low2high = 0; + ZEBRA_RFSerialRead(dev, data2Write, wlen,&dataRead,rlen, low2high); + } + break; + } + break; + default: + dataRead = 0; + break; + } + + return dataRead; +} + + +// by Owen on 04/07/14 for writing BB register successfully +void +WriteBBPortUchar( + struct net_device *dev, + u32 Data + ) +{ + //u8 TimeoutCounter; + u8 RegisterContent; + u8 UCharData; + + UCharData = (u8)((Data & 0x0000ff00) >> 8); + PlatformIOWrite4Byte(dev, PhyAddr, Data); + //for(TimeoutCounter = 10; TimeoutCounter > 0; TimeoutCounter--) + { + PlatformIOWrite4Byte(dev, PhyAddr, Data & 0xffffff7f); + RegisterContent = PlatformIORead1Byte(dev, PhyDataR); + //if(UCharData == RegisterContent) + // break; + } +} + +u8 +ReadBBPortUchar( + struct net_device *dev, + u32 addr + ) +{ + //u8 TimeoutCounter; + u8 RegisterContent; + + PlatformIOWrite4Byte(dev, PhyAddr, addr & 0xffffff7f); + RegisterContent = PlatformIORead1Byte(dev, PhyDataR); + + return RegisterContent; +} +//{by amy 080312 +#ifdef CONFIG_RTL818X_S +// +// Description: +// Perform Antenna settings with antenna diversity on 87SE. +// Created by Roger, 2008.01.25. +// +bool +SetAntennaConfig87SE( + struct net_device *dev, + u8 DefaultAnt, // 0: Main, 1: Aux. + bool bAntDiversity // 1:Enable, 0: Disable. +) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + bool bAntennaSwitched = true; + + //printk("SetAntennaConfig87SE(): DefaultAnt(%d), bAntDiversity(%d)\n", DefaultAnt, bAntDiversity); + + // Threshold for antenna diversity. + write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 + + if( bAntDiversity ) // Enable Antenna Diversity. + { + if( DefaultAnt == 1 ) // aux antenna + { + // Mac register, aux antenna + write_nic_byte(dev, ANTSEL, 0x00); + + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb + write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 + + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0D, 0x54); // Reg0d : 54 + write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 + } + else // use main antenna + { + // Mac register, main antenna + write_nic_byte(dev, ANTSEL, 0x03); + //base band + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b + write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 + + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0d, 0x5c); // Reg0d : 5c + write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 + } + } + else // Disable Antenna Diversity. + { + if( DefaultAnt == 1 ) // aux Antenna + { + // Mac register, aux antenna + write_nic_byte(dev, ANTSEL, 0x00); + + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb + write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 + + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0D, 0x54); // Reg0d : 54 + write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 + } + else // main Antenna + { + // Mac register, main antenna + write_nic_byte(dev, ANTSEL, 0x03); + + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b + write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 + + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0D, 0x5c); // Reg0d : 5c + write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 + } + } + priv->CurrAntennaIndex = DefaultAnt; // Update default settings. + return bAntennaSwitched; +} +#endif +//by amy 080312 +/*--------------------------------------------------------------- + * Hardware Initialization. + * the code is ported from Windows source code + ----------------------------------------------------------------*/ + +void +ZEBRA_Config_85BASIC_HardCode( + struct net_device *dev + ) +{ + + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32 i; + u32 addr,data; + u32 u4bRegOffset, u4bRegValue, u4bRF23, u4bRF24; + u8 u1b24E; + +#ifdef CONFIG_RTL818X_S + + //============================================================================= + // 87S_PCIE :: RADIOCFG.TXT + //============================================================================= + + + // Page1 : reg16-reg30 + RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); // switch to page1 + u4bRF23= RF_ReadReg(dev, 0x08); mdelay(1); + u4bRF24= RF_ReadReg(dev, 0x09); mdelay(1); + + if (u4bRF23==0x818 && u4bRF24==0x70C && priv->card_8185 == VERSION_8187S_C) + priv->card_8185 = VERSION_8187S_D; + + // Page0 : reg0-reg15 + +// RF_WriteReg(dev, 0x00, 0x003f); mdelay(1);//1 + RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);// 1 + + RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1); + +// RF_WriteReg(dev, 0x02, 0x004c); mdelay(1);//2 + RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);// 2 + +// RF_WriteReg(dev, 0x03, 0x0000); mdelay(1);//3 + RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);// 3 + + RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); + RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1); + RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1); + RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1); + RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1); + RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1); + RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1); + RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1); + RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1); + RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); + RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1); + RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1); + + + // Page1 : reg16-reg30 + RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); + + RF_WriteReg(dev, 0x03, 0x0806); mdelay(1); + + if(priv->card_8185 < VERSION_8187S_C) + { + RF_WriteReg(dev, 0x04, 0x03f7); mdelay(1); + RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); + RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1); + } + else + { + RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1); + RF_WriteReg(dev, 0x05, 0x059b); mdelay(1); + RF_WriteReg(dev, 0x06, 0x0081); mdelay(1); + } + + + RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1); +// Don't write RF23/RF24 to make a difference between 87S C cut and D cut. asked by SD3 stevenl. +// RF_WriteReg(dev, 0x08, 0x0597); mdelay(1); +// RF_WriteReg(dev, 0x09, 0x050a); mdelay(1); + RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); + RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1); + + if(priv->card_8185 == VERSION_8187S_D) + { + RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); + RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); + RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); // RX LO buffer + } + else + { + RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); + RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); + RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); // RX LO buffer + } + + RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); + +// RF_WriteReg(dev, 0x00, 0x017f); mdelay(1);//6 + RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1);// 6 + + RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1); + RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1); + for(i=0;i<=36;i++) + { + RF_WriteReg(dev, 0x01, i); mdelay(1); + RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1); + //DbgPrint("RF - 0x%x = 0x%x", i, ZEBRA_RF_RX_GAIN_TABLE[i]); + } + + RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /// 203, 343 + //RF_WriteReg(dev, 0x06, 0x0300); mdelay(1); // 400 + RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); // 400 + + RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); // switch to reg16-reg30, and HSSI disable 137 + mdelay(10); // Deay 10 ms. //0xfd + +// RF_WriteReg(dev, 0x0c, 0x09be); mdelay(1); // 7 + //RF_WriteReg(dev, 0x0c, 0x07be); mdelay(1); + //mdelay(10); // Deay 10 ms. //0xfd + + RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); // Z4 synthesizer loop filter setting, 392 + mdelay(10); // Deay 10 ms. //0xfd + + RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); // switch to reg0-reg15, and HSSI disable + mdelay(10); // Deay 10 ms. //0xfd + + RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); // CBC on, Tx Rx disable, High gain + mdelay(10); // Deay 10 ms. //0xfd + + RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); // Z4 setted channel 1 + mdelay(10); // Deay 10 ms. //0xfd + + RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); // LC calibration + mdelay(200); // Deay 200 ms. //0xfd + mdelay(10); // Deay 10 ms. //0xfd + mdelay(10); // Deay 10 ms. //0xfd + + RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); // switch to reg16-reg30 137, and HSSI disable 137 + mdelay(10); // Deay 10 ms. //0xfd + + RF_WriteReg(dev, 0x07, 0x0000); mdelay(1); + RF_WriteReg(dev, 0x07, 0x0180); mdelay(1); + RF_WriteReg(dev, 0x07, 0x0220); mdelay(1); + RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1); + + // DAC calibration off 20070702 + RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1); + RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); +//{by amy 080312 + // For crystal calibration, added by Roger, 2007.12.11. + if( priv->bXtalCalibration ) // reg 30. + { // enable crystal calibration. + // RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0]. + // (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0 + // (3)RF signal on/off when calibration[13], default: on, set BIT13=0. + // So we should minus 4 BITs offset. + RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5)|(priv->XtalCal_Xout<<1)|BIT11|BIT9); mdelay(1); + printk("ZEBRA_Config_85BASIC_HardCode(): (%02x)\n", + (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11| BIT9); + } + else + { // using default value. Xin=6, Xout=6. + RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); + } +//by amy 080312 +// RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); //-by amy 080312 + + RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); // switch to reg0-reg15, and HSSI enable +// RF_WriteReg(dev, 0x0d, 0x009f); mdelay(1); // Rx BB start calibration, 00c//-edward + RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); // Rx BB start calibration, 00c//+edward + RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); // temperature meter off + RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); // Rx mode + mdelay(10); // Deay 10 ms. //0xfe + mdelay(10); // Deay 10 ms. //0xfe + mdelay(10); // Deay 10 ms. //0xfe + RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); // Rx mode//+edward + RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); // Rx mode//+edward + RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); // Rx mode//+edward + +#if 0//-edward + RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); + RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); + RF_WriteReg(dev, 0x00, 0x009F); mdelay(1); +#endif + RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); // Rx mode//+edward + RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); // Rx mode//+edward + //power save parameters. + u1b24E = read_nic_byte(dev, 0x24E); + write_nic_byte(dev, 0x24E, (u1b24E & (~(BIT5|BIT6)))); + + //============================================================================= + + //============================================================================= + // CCKCONF.TXT + //============================================================================= + + /* [POWER SAVE] Power Saving Parameters by jong. 2007-11-27 + CCK reg0x00[7]=1'b1 :power saving for TX (default) + CCK reg0x00[6]=1'b1: power saving for RX (default) + CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation. + CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1 + CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0 + */ +#if 0 + write_nic_dword(dev, PHY_ADR, 0x0100c880); + write_nic_dword(dev, PHY_ADR, 0x01001c86); + write_nic_dword(dev, PHY_ADR, 0x01007890); + write_nic_dword(dev, PHY_ADR, 0x0100d0ae); + write_nic_dword(dev, PHY_ADR, 0x010006af); + write_nic_dword(dev, PHY_ADR, 0x01004681); +#endif + write_phy_cck(dev,0x00,0xc8); + write_phy_cck(dev,0x06,0x1c); + write_phy_cck(dev,0x10,0x78); + write_phy_cck(dev,0x2e,0xd0); + write_phy_cck(dev,0x2f,0x06); + write_phy_cck(dev,0x01,0x46); + + // power control + write_nic_byte(dev, CCK_TXAGC, 0x10); + write_nic_byte(dev, OFDM_TXAGC, 0x1B); + write_nic_byte(dev, ANTSEL, 0x03); +#else + //============================================================================= + // RADIOCFG.TXT + //============================================================================= + + RF_WriteReg(dev, 0x00, 0x00b7); mdelay(1); + RF_WriteReg(dev, 0x01, 0x0ee0); mdelay(1); + RF_WriteReg(dev, 0x02, 0x044d); mdelay(1); + RF_WriteReg(dev, 0x03, 0x0441); mdelay(1); + RF_WriteReg(dev, 0x04, 0x08c3); mdelay(1); + RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1); + RF_WriteReg(dev, 0x06, 0x00e6); mdelay(1); + RF_WriteReg(dev, 0x07, 0x082a); mdelay(1); + RF_WriteReg(dev, 0x08, 0x003f); mdelay(1); + RF_WriteReg(dev, 0x09, 0x0335); mdelay(1); + RF_WriteReg(dev, 0x0a, 0x09d4); mdelay(1); + RF_WriteReg(dev, 0x0b, 0x07bb); mdelay(1); + RF_WriteReg(dev, 0x0c, 0x0850); mdelay(1); + RF_WriteReg(dev, 0x0d, 0x0cdf); mdelay(1); + RF_WriteReg(dev, 0x0e, 0x002b); mdelay(1); + RF_WriteReg(dev, 0x0f, 0x0114); mdelay(1); + + RF_WriteReg(dev, 0x00, 0x01b7); mdelay(1); + + + for(i=1;i<=95;i++) + { + RF_WriteReg(dev, 0x01, i); mdelay(1); + RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1); + //DbgPrint("RF - 0x%x = 0x%x", i, ZEBRA_RF_RX_GAIN_TABLE[i]); + } + + RF_WriteReg(dev, 0x03, 0x0080); mdelay(1); // write reg 18 + RF_WriteReg(dev, 0x05, 0x0004); mdelay(1); // write reg 20 + RF_WriteReg(dev, 0x00, 0x00b7); mdelay(1); // switch to reg0-reg15 + //0xfd + //0xfd + //0xfd + RF_WriteReg(dev, 0x02, 0x0c4d); mdelay(1); + mdelay(100); // Deay 100 ms. //0xfe + mdelay(100); // Deay 100 ms. //0xfe + RF_WriteReg(dev, 0x02, 0x044d); mdelay(1); + RF_WriteReg(dev, 0x00, 0x02bf); mdelay(1); //0x002f disable 6us corner change, 06f--> enable + + //============================================================================= + + //============================================================================= + // CCKCONF.TXT + //============================================================================= + + //============================================================================= + + //============================================================================= + // Follow WMAC RTL8225_Config() + //============================================================================= + + // power control + write_nic_byte(dev, CCK_TXAGC, 0x03); + write_nic_byte(dev, OFDM_TXAGC, 0x07); + write_nic_byte(dev, ANTSEL, 0x03); + + //============================================================================= + + // OFDM BBP setup +// SetOutputEnableOfRfPins(dev);//by amy +#endif + + + + //============================================================================= + // AGC.txt + //============================================================================= + +// PlatformIOWrite4Byte( dev, PhyAddr, 0x00001280); // Annie, 2006-05-05 + write_phy_ofdm(dev, 0x00, 0x12); + //WriteBBPortUchar(dev, 0x00001280); + + for (i=0; i<128; i++) + { + //DbgPrint("AGC - [%x+1] = 0x%x\n", i, ZEBRA_AGC[i+1]); + + data = ZEBRA_AGC[i+1]; + data = data << 8; + data = data | 0x0000008F; + + addr = i + 0x80; //enable writing AGC table + addr = addr << 8; + addr = addr | 0x0000008E; + + WriteBBPortUchar(dev, data); + WriteBBPortUchar(dev, addr); + WriteBBPortUchar(dev, 0x0000008E); + } + + PlatformIOWrite4Byte( dev, PhyAddr, 0x00001080); // Annie, 2006-05-05 + //WriteBBPortUchar(dev, 0x00001080); + + //============================================================================= + + //============================================================================= + // OFDMCONF.TXT + //============================================================================= + + for(i=0; i<60; i++) + { + u4bRegOffset=i; + u4bRegValue=OFDM_CONFIG[i]; + + //DbgPrint("OFDM - 0x%x = 0x%x\n", u4bRegOffset, u4bRegValue); + + WriteBBPortUchar(dev, + (0x00000080 | + (u4bRegOffset & 0x7f) | + ((u4bRegValue & 0xff) << 8))); + } + + //============================================================================= +//by amy for antenna + //============================================================================= +//{by amy 080312 +#ifdef CONFIG_RTL818X_S + // Config Sw/Hw Combinational Antenna Diversity. Added by Roger, 2008.02.26. + SetAntennaConfig87SE(dev, priv->bDefaultAntenna1, priv->bSwAntennaDiverity); +#endif +//by amy 080312} +#if 0 + // Config Sw/Hw Antenna Diversity + if( priv->bSwAntennaDiverity ) // Use SW+Hw Antenna Diversity + { + if( priv->bDefaultAntenna1 == true ) // aux antenna + { + // Mac register, aux antenna + write_nic_byte(dev, ANTSEL, 0x00); + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb + write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 + write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0d, 0x54); // Reg0d : 54 + write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 + } + else // main antenna + { + // Mac register, main antenna + write_nic_byte(dev, ANTSEL, 0x03); + //base band + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b + write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 + write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0d, 0x5c); // Reg0d : 5c + write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 + } + } + else // Disable Antenna Diversity + { + if( priv->bDefaultAntenna1 == true ) // aux Antenna + { + // Mac register, aux antenna + write_nic_byte(dev, ANTSEL, 0x00); + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb + write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 + write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0d, 0x54); // Reg0d : 54 + write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 + } + else // main Antenna + { + // Mac register, main antenna + write_nic_byte(dev, ANTSEL, 0x03); + // Config CCK RX antenna. + write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b + write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 + write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 + // Config OFDM RX antenna. + write_phy_ofdm(dev, 0x0d, 0x5c); // Reg0d : 5c + write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 + } + } +#endif +//by amy for antenna +} + + +void +UpdateInitialGain( + struct net_device *dev + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + //unsigned char* IGTable; + //u8 DIG_CurrentInitialGain = 4; + //unsigned char u1Tmp; + + //lzm add 080826 + if(priv->eRFPowerState != eRfOn) + { + //Don't access BB/RF under disable PLL situation. + //RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n")); + // Back to the original state + priv->InitialGain= priv->InitialGainBackUp; + return; + } + + switch(priv->rf_chip) + { +#if 0 + case RF_ZEBRA2: + // Dynamic set initial gain, by shien chang, 2006.07.14 + switch(priv->InitialGain) + { + case 1: //m861dBm + DMESG("RTL8185B + 8225 Initial Gain State 1: -82 dBm \n"); + write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0x86a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfa85); mdelay(1); + break; + + case 2: //m862dBm + DMESG("RTL8185B + 8225 Initial Gain State 2: -82 dBm \n"); + write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0x86a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); + break; + + case 3: //m863dBm + DMESG("RTL8185B + 8225 Initial Gain State 3: -82 dBm \n"); + write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0x96a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); + break; + + case 4: //m864dBm + DMESG("RTL8185B + 8225 Initial Gain State 4: -78 dBm \n"); + write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); + break; + + case 5: //m82dBm + DMESG("RTL8185B + 8225 Initial Gain State 5: -74 dBm \n"); + write_nic_dword(dev, PhyAddr, 0x3697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); + break; + + case 6: //m78dBm + DMESG("RTL8185B + 8225 Initial Gain State 6: -70 dBm \n"); + write_nic_dword(dev, PhyAddr, 0x4697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); + break; + + case 7: //m74dBm + DMESG("RTL8185B + 8225 Initial Gain State 7: -66 dBm \n"); + write_nic_dword(dev, PhyAddr, 0x5697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); + break; + + default: //MP + DMESG("RTL8185B + 8225 Initial Gain State 1: -82 dBm (default)\n"); + write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); + write_nic_dword(dev, PhyAddr, 0x86a4); mdelay(1); + write_nic_dword(dev, PhyAddr, 0xfa85); mdelay(1); + break; + } + break; +#endif + case RF_ZEBRA4: + // Dynamic set initial gain, follow 87B + switch(priv->InitialGain) + { + case 1: //m861dBm + //DMESG("RTL8187 + 8225 Initial Gain State 1: -82 dBm \n"); + write_phy_ofdm(dev, 0x17, 0x26); mdelay(1); + write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); + break; + + case 2: //m862dBm + //DMESG("RTL8187 + 8225 Initial Gain State 2: -82 dBm \n"); + write_phy_ofdm(dev, 0x17, 0x36); mdelay(1); + write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); + break; + + case 3: //m863dBm + //DMESG("RTL8187 + 8225 Initial Gain State 3: -82 dBm \n"); + write_phy_ofdm(dev, 0x17, 0x36); mdelay(1); + write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); + break; + + case 4: //m864dBm + //DMESG("RTL8187 + 8225 Initial Gain State 4: -78 dBm \n"); + write_phy_ofdm(dev, 0x17, 0x46); mdelay(1); + write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); + break; + + case 5: //m82dBm + //DMESG("RTL8187 + 8225 Initial Gain State 5: -74 dBm \n"); + write_phy_ofdm(dev, 0x17, 0x46); mdelay(1); + write_phy_ofdm(dev, 0x24, 0x96); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); + break; + + case 6: //m78dBm + //DMESG ("RTL8187 + 8225 Initial Gain State 6: -70 dBm \n"); + write_phy_ofdm(dev, 0x17, 0x56); mdelay(1); + write_phy_ofdm(dev, 0x24, 0x96); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); + break; + + case 7: //m74dBm + //DMESG("RTL8187 + 8225 Initial Gain State 7: -66 dBm \n"); + write_phy_ofdm(dev, 0x17, 0x56); mdelay(1); + write_phy_ofdm(dev, 0x24, 0xa6); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); + break; + + case 8: + //DMESG("RTL8187 + 8225 Initial Gain State 8:\n"); + write_phy_ofdm(dev, 0x17, 0x66); mdelay(1); + write_phy_ofdm(dev, 0x24, 0xb6); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); + break; + + + default: //MP + //DMESG("RTL8187 + 8225 Initial Gain State 1: -82 dBm (default)\n"); + write_phy_ofdm(dev, 0x17, 0x26); mdelay(1); + write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); + write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); + break; + } + break; + + + default: + DMESG("UpdateInitialGain(): unknown RFChipID: %#X\n", priv->rf_chip); + break; + } +} +#ifdef CONFIG_RTL818X_S +// +// Description: +// Tx Power tracking mechanism routine on 87SE. +// Created by Roger, 2007.12.11. +// +void +InitTxPwrTracking87SE( + struct net_device *dev +) +{ + //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u32 u4bRfReg; + + u4bRfReg = RF_ReadReg(dev, 0x02); + + // Enable Thermal meter indication. + //printk("InitTxPwrTracking87SE(): Enable thermal meter indication, Write RF[0x02] = %#x", u4bRfReg|PWR_METER_EN); + RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN); mdelay(1); +} + +#endif +void +PhyConfig8185( + struct net_device *dev + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + write_nic_dword(dev, RCR, priv->ReceiveConfig); + priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03; + // RF config + switch(priv->rf_chip) + { + case RF_ZEBRA2: + case RF_ZEBRA4: + ZEBRA_Config_85BASIC_HardCode( dev); + break; + } +//{by amy 080312 +#ifdef CONFIG_RTL818X_S + // Set default initial gain state to 4, approved by SD3 DZ, by Bruce, 2007-06-06. + if(priv->bDigMechanism) + { + if(priv->InitialGain == 0) + priv->InitialGain = 4; + //printk("PhyConfig8185(): DIG is enabled, set default initial gain index to %d\n", priv->InitialGain); + } + + // + // Enable thermal meter indication to implement TxPower tracking on 87SE. + // We initialize thermal meter here to avoid unsuccessful configuration. + // Added by Roger, 2007.12.11. + // + if(priv->bTxPowerTrack) + InitTxPwrTracking87SE(dev); + +#endif +//by amy 080312} + priv->InitialGainBackUp= priv->InitialGain; + UpdateInitialGain(dev); + + return; +} + + + + +void +HwConfigureRTL8185( + struct net_device *dev + ) +{ + //RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control. +// u8 bUNIVERSAL_CONTROL_RL = 1; + u8 bUNIVERSAL_CONTROL_RL = 0; + + u8 bUNIVERSAL_CONTROL_AGC = 1; + u8 bUNIVERSAL_CONTROL_ANT = 1; + u8 bAUTO_RATE_FALLBACK_CTL = 1; + u8 val8; + //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + //struct ieee80211_device *ieee = priv->ieee80211; + //if(IS_WIRELESS_MODE_A(dev) || IS_WIRELESS_MODE_G(dev)) +//{by amy 080312 if((ieee->mode == IEEE_G)||(ieee->mode == IEEE_A)) +// { +// write_nic_word(dev, BRSR, 0xffff); +// } +// else +// { +// write_nic_word(dev, BRSR, 0x000f); +// } +//by amy 080312} + write_nic_word(dev, BRSR, 0x0fff); + // Retry limit + val8 = read_nic_byte(dev, CW_CONF); + + if(bUNIVERSAL_CONTROL_RL) + val8 = val8 & 0xfd; + else + val8 = val8 | 0x02; + + write_nic_byte(dev, CW_CONF, val8); + + // Tx AGC + val8 = read_nic_byte(dev, TXAGC_CTL); + if(bUNIVERSAL_CONTROL_AGC) + { + write_nic_byte(dev, CCK_TXAGC, 128); + write_nic_byte(dev, OFDM_TXAGC, 128); + val8 = val8 & 0xfe; + } + else + { + val8 = val8 | 0x01 ; + } + + + write_nic_byte(dev, TXAGC_CTL, val8); + + // Tx Antenna including Feedback control + val8 = read_nic_byte(dev, TXAGC_CTL ); + + if(bUNIVERSAL_CONTROL_ANT) + { + write_nic_byte(dev, ANTSEL, 0x00); + val8 = val8 & 0xfd; + } + else + { + val8 = val8 & (val8|0x02); //xiong-2006-11-15 + } + + write_nic_byte(dev, TXAGC_CTL, val8); + + // Auto Rate fallback control + val8 = read_nic_byte(dev, RATE_FALLBACK); + val8 &= 0x7c; + if( bAUTO_RATE_FALLBACK_CTL ) + { + val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1; + + // <RJ_TODO_8185B> We shall set up the ARFR according to user's setting. + //write_nic_word(dev, ARFR, 0x0fff); // set 1M ~ 54M +//by amy +#if 0 + PlatformIOWrite2Byte(dev, ARFR, 0x0fff); // set 1M ~ 54M +#endif +#ifdef CONFIG_RTL818X_S + // Aadded by Roger, 2007.11.15. + PlatformIOWrite2Byte(dev, ARFR, 0x0fff); //set 1M ~ 54Mbps. +#else + PlatformIOWrite2Byte(dev, ARFR, 0x0c00); //set 48Mbps, 54Mbps. + // By SD3 szuyi's request. by Roger, 2007.03.26. +#endif +//by amy + } + else + { + } + write_nic_byte(dev, RATE_FALLBACK, val8); +} + + + +static void +MacConfig_85BASIC_HardCode( + struct net_device *dev) +{ + //============================================================================ + // MACREG.TXT + //============================================================================ + int nLinesRead = 0; + + u32 u4bRegOffset, u4bRegValue,u4bPageIndex = 0; + int i; + + nLinesRead=sizeof(MAC_REG_TABLE)/2; + + for(i = 0; i < nLinesRead; i++) //nLinesRead=101 + { + u4bRegOffset=MAC_REG_TABLE[i][0]; + u4bRegValue=MAC_REG_TABLE[i][1]; + + if(u4bRegOffset == 0x5e) + { + u4bPageIndex = u4bRegValue; + } + else + { + u4bRegOffset |= (u4bPageIndex << 8); + } + //DbgPrint("MAC - 0x%x = 0x%x\n", u4bRegOffset, u4bRegValue); + write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue); + } + //============================================================================ +} + + + +static void +MacConfig_85BASIC( + struct net_device *dev) +{ + + u8 u1DA; + MacConfig_85BASIC_HardCode(dev); + + //============================================================================ + + // Follow TID_AC_MAP of WMac. + write_nic_word(dev, TID_AC_MAP, 0xfa50); + + // Interrupt Migration, Jong suggested we use set 0x0000 first, 2005.12.14, by rcnjko. + write_nic_word(dev, IntMig, 0x0000); + + // Prevent TPC to cause CRC error. Added by Annie, 2006-06-10. + PlatformIOWrite4Byte(dev, 0x1F0, 0x00000000); + PlatformIOWrite4Byte(dev, 0x1F4, 0x00000000); + PlatformIOWrite1Byte(dev, 0x1F8, 0x00); + + // Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. + //PlatformIOWrite4Byte(dev, RFTiming, 0x00004001); +//by amy +#if 0 + write_nic_dword(dev, RFTiming, 0x00004001); +#endif +#ifdef CONFIG_RTL818X_S + // power save parameter based on "87SE power save parameters 20071127.doc", as follow. + + //Enable DA10 TX power saving + u1DA = read_nic_byte(dev, PHYPR); + write_nic_byte(dev, PHYPR, (u1DA | BIT2) ); + + //POWER: + write_nic_word(dev, 0x360, 0x1000); + write_nic_word(dev, 0x362, 0x1000); + + // AFE. + write_nic_word(dev, 0x370, 0x0560); + write_nic_word(dev, 0x372, 0x0560); + write_nic_word(dev, 0x374, 0x0DA4); + write_nic_word(dev, 0x376, 0x0DA4); + write_nic_word(dev, 0x378, 0x0560); + write_nic_word(dev, 0x37A, 0x0560); + write_nic_word(dev, 0x37C, 0x00EC); +// write_nic_word(dev, 0x37E, 0x00FE);//-edward + write_nic_word(dev, 0x37E, 0x00EC);//+edward +#else + write_nic_dword(dev, RFTiming, 0x00004003); +#endif + write_nic_byte(dev, 0x24E,0x01); +//by amy + +} + + + + +u8 +GetSupportedWirelessMode8185( + struct net_device *dev +) +{ + u8 btSupportedWirelessMode = 0; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + switch(priv->rf_chip) + { + case RF_ZEBRA2: + case RF_ZEBRA4: + btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G); + break; + default: + btSupportedWirelessMode = WIRELESS_MODE_B; + break; + } + + return btSupportedWirelessMode; +} + +void +ActUpdateChannelAccessSetting( + struct net_device *dev, + WIRELESS_MODE WirelessMode, + PCHANNEL_ACCESS_SETTING ChnlAccessSetting + ) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; + AC_CODING eACI; + AC_PARAM AcParam; + //PSTA_QOS pStaQos = Adapter->MgntInfo.pStaQos; + u8 bFollowLegacySetting = 0; + u8 u1bAIFS; + + // + // <RJ_TODO_8185B> + // TODO: We still don't know how to set up these registers, just follow WMAC to + // verify 8185B FPAG. + // + // <RJ_TODO_8185B> + // Jong said CWmin/CWmax register are not functional in 8185B, + // so we shall fill channel access realted register into AC parameter registers, + // even in nQBss. + // + ChnlAccessSetting->SIFS_Timer = 0x22; // Suggested by Jong, 2005.12.08. + ChnlAccessSetting->DIFS_Timer = 0x1C; // 2006.06.02, by rcnjko. + ChnlAccessSetting->SlotTimeTimer = 9; // 2006.06.02, by rcnjko. + ChnlAccessSetting->EIFS_Timer = 0x5B; // Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. + ChnlAccessSetting->CWminIndex = 3; // 2006.06.02, by rcnjko. + ChnlAccessSetting->CWmaxIndex = 7; // 2006.06.02, by rcnjko. + + write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer); + //Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_SLOT_TIME, &ChnlAccessSetting->SlotTimeTimer ); // Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. + write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); // Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. + + u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer ); + + //write_nic_byte(dev, AC_VO_PARAM, u1bAIFS); + //write_nic_byte(dev, AC_VI_PARAM, u1bAIFS); + //write_nic_byte(dev, AC_BE_PARAM, u1bAIFS); + //write_nic_byte(dev, AC_BK_PARAM, u1bAIFS); + + write_nic_byte(dev, EIFS, ChnlAccessSetting->EIFS_Timer); + + write_nic_byte(dev, AckTimeOutReg, 0x5B); // <RJ_EXPR_QOS> Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. + +#ifdef TODO + // <RJ_TODO_NOW_8185B> Update ECWmin/ECWmax, AIFS, TXOP Limit of each AC to the value defined by SPEC. + if( pStaQos->CurrentQosMode > QOS_DISABLE ) + { // QoS mode. + if(pStaQos->QBssWirelessMode == WirelessMode) + { + // Follow AC Parameters of the QBSS. + for(eACI = 0; eACI < AC_MAX; eACI++) + { + Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AC_PARAM, (pu1Byte)(&(pStaQos->WMMParamEle.AcParam[eACI])) ); + } + } + else + { + // Follow Default WMM AC Parameters. + bFollowLegacySetting = 1; + } + } + else +#endif + { // Legacy 802.11. + bFollowLegacySetting = 1; + + } + + // this setting is copied from rtl8187B. xiong-2006-11-13 + if(bFollowLegacySetting) + { + + + // + // Follow 802.11 seeting to AC parameter, all AC shall use the same parameter. + // 2005.12.01, by rcnjko. + // + AcParam.longData = 0; + AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS. + AcParam.f.AciAifsn.f.ACM = 0; + AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; // Follow 802.11 CWmin. + AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; // Follow 802.11 CWmax. + AcParam.f.TXOPLimit = 0; + + //lzm reserved 080826 +#if 1 +#ifdef THOMAS_TURBO + // For turbo mode setting. port from 87B by Isaiah 2008-08-01 + if( ieee->current_network.Turbo_Enable == 1 ) + AcParam.f.TXOPLimit = 0x01FF; +#endif + // For 87SE with Intel 4965 Ad-Hoc mode have poor throughput (19MB) + if (ieee->iw_mode == IW_MODE_ADHOC) + AcParam.f.TXOPLimit = 0x0020; +#endif + + for(eACI = 0; eACI < AC_MAX; eACI++) + { + AcParam.f.AciAifsn.f.ACI = (u8)eACI; + { + PAC_PARAM pAcParam = (PAC_PARAM)(&AcParam); + AC_CODING eACI; + u8 u1bAIFS; + u32 u4bAcParam; + + // Retrive paramters to udpate. + eACI = pAcParam->f.AciAifsn.f.ACI; + u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime; + u4bAcParam = ( (((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | + (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | + (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | + (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); + + switch(eACI) + { + case AC1_BK: + //write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); + break; + + case AC0_BE: + //write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); + break; + + case AC2_VI: + //write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); + break; + + case AC3_VO: + //write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); + break; + + default: + DMESGW( "SetHwReg8185(): invalid ACI: %d !\n", eACI); + break; + } + + // Cehck ACM bit. + // If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. + //write_nic_byte(dev, ACM_CONTROL, pAcParam->f.AciAifsn); + { + PACI_AIFSN pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn); + AC_CODING eACI = pAciAifsn->f.ACI; + + //modified Joseph + //for 8187B AsynIORead issue +#ifdef TODO + u8 AcmCtrl = pHalData->AcmControl; +#else + u8 AcmCtrl = 0; +#endif + if( pAciAifsn->f.ACM ) + { // ACM bit is 1. + switch(eACI) + { + case AC0_BE: + AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); // or 0x21 + break; + + case AC2_VI: + AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); // or 0x42 + break; + + case AC3_VO: + AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); // or 0x84 + break; + + default: + DMESGW("SetHwReg8185(): [HW_VAR_ACM_CTRL] ACM set failed: eACI is %d\n", eACI ); + break; + } + } + else + { // ACM bit is 0. + switch(eACI) + { + case AC0_BE: + AcmCtrl &= ( (~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0xDE + break; + + case AC2_VI: + AcmCtrl &= ( (~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0xBD + break; + + case AC3_VO: + AcmCtrl &= ( (~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0x7B + break; + + default: + break; + } + } + + //printk(KERN_WARNING "SetHwReg8185(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl); + +#ifdef TO_DO + pHalData->AcmControl = AcmCtrl; +#endif + //write_nic_byte(dev, ACM_CONTROL, AcmCtrl); + write_nic_byte(dev, ACM_CONTROL, 0); + } + } + } + + + } +} + +void +ActSetWirelessMode8185( + struct net_device *dev, + u8 btWirelessMode + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; + //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + u8 btSupportedWirelessMode = GetSupportedWirelessMode8185(dev); + + if( (btWirelessMode & btSupportedWirelessMode) == 0 ) + { // Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. + DMESGW("ActSetWirelessMode8185(): WirelessMode(%d) is not supported (%d)!\n", + btWirelessMode, btSupportedWirelessMode); + return; + } + + // 1. Assign wireless mode to swtich if necessary. + if (btWirelessMode == WIRELESS_MODE_AUTO) + { + if((btSupportedWirelessMode & WIRELESS_MODE_A)) + { + btWirelessMode = WIRELESS_MODE_A; + } + else if((btSupportedWirelessMode & WIRELESS_MODE_G)) + { + btWirelessMode = WIRELESS_MODE_G; + } + else if((btSupportedWirelessMode & WIRELESS_MODE_B)) + { + btWirelessMode = WIRELESS_MODE_B; + } + else + { + DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n", + btSupportedWirelessMode); + btWirelessMode = WIRELESS_MODE_B; + } + } + + + // 2. Swtich band: RF or BB specific actions, + // for example, refresh tables in omc8255, or change initial gain if necessary. + switch(priv->rf_chip) + { + case RF_ZEBRA2: + case RF_ZEBRA4: + { + // Nothing to do for Zebra to switch band. + // Update current wireless mode if we swtich to specified band successfully. + ieee->mode = (WIRELESS_MODE)btWirelessMode; + } + break; + + default: + DMESGW("ActSetWirelessMode8185(): unsupported RF: 0x%X !!!\n", priv->rf_chip); + break; + } + + // 3. Change related setting. + if( ieee->mode == WIRELESS_MODE_A ){ + DMESG("WIRELESS_MODE_A\n"); + } + else if( ieee->mode == WIRELESS_MODE_B ){ + DMESG("WIRELESS_MODE_B\n"); + } + else if( ieee->mode == WIRELESS_MODE_G ){ + DMESG("WIRELESS_MODE_G\n"); + } + + ActUpdateChannelAccessSetting( dev, ieee->mode, &priv->ChannelAccessSetting); +} + +void rtl8185b_irq_enable(struct net_device *dev) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + + priv->irq_enabled = 1; + write_nic_dword(dev, IMR, priv->IntrMask); +} +//by amy for power save +void +DrvIFIndicateDisassociation( + struct net_device *dev, + u16 reason + ) +{ + //printk("==> DrvIFIndicateDisassociation()\n"); + + // nothing is needed after disassociation request. + + //printk("<== DrvIFIndicateDisassociation()\n"); +} +void +MgntDisconnectIBSS( + struct net_device *dev +) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u8 i; + + //printk("XXXXXXXXXX MgntDisconnect IBSS\n"); + + DrvIFIndicateDisassociation(dev, unspec_reason); + +// PlatformZeroMemory( pMgntInfo->Bssid, 6 ); + for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x55; + + priv->ieee80211->state = IEEE80211_NOLINK; + + //Stop Beacon. + + // Vista add a Adhoc profile, HW radio off untill OID_DOT11_RESET_REQUEST + // Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck. + // Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send. + + // Disable Beacon Queue Own bit, suggested by jong +// Adapter->HalFunc.SetTxDescOWNHandler(Adapter, BEACON_QUEUE, 0, 0); + ieee80211_stop_send_beacons(priv->ieee80211); + + priv->ieee80211->link_change(dev); + notify_wx_assoc_event(priv->ieee80211); + + // Stop SW Beacon.Use hw beacon so do not need to do so.by amy +#if 0 + if(pMgntInfo->bEnableSwBeaconTimer) + { + // SwBeaconTimer will stop if pMgntInfo->mIbss==FALSE, see SwBeaconCallback() for details. +// comment out by haich, 2007.10.01 +//#if DEV_BUS_TYPE==USB_INTERFACE + PlatformCancelTimer( Adapter, &pMgntInfo->SwBeaconTimer); +//#endif + } +#endif + +// MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE ); + +} +void +MlmeDisassociateRequest( + struct net_device *dev, + u8* asSta, + u8 asRsn + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + u8 i; + + SendDisassociation(priv->ieee80211, asSta, asRsn ); + + if( memcmp(priv->ieee80211->current_network.bssid, asSta, 6 ) == 0 ){ + //ShuChen TODO: change media status. + //ShuChen TODO: What to do when disassociate. + DrvIFIndicateDisassociation(dev, unspec_reason); + + + // pMgntInfo->AsocTimestamp = 0; + for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x22; +// pMgntInfo->mBrates.Length = 0; +// Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_BASIC_RATE, (pu1Byte)(&pMgntInfo->mBrates) ); + + ieee80211_disassociate(priv->ieee80211); + + + } + +} + +void +MgntDisconnectAP( + struct net_device *dev, + u8 asRsn +) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + +// +// Commented out by rcnjko, 2005.01.27: +// I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE(). +// +// //2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success +// SecClearAllKeys(Adapter); + + // In WPA WPA2 need to Clear all key ... because new key will set after new handshaking. +#ifdef TODO + if( pMgntInfo->SecurityInfo.AuthMode > RT_802_11AuthModeAutoSwitch || + (pMgntInfo->bAPSuportCCKM && pMgntInfo->bCCX8021xenable) ) // In CCKM mode will Clear key + { + SecClearAllKeys(Adapter); + RT_TRACE(COMP_SEC, DBG_LOUD,("======>CCKM clear key...")) + } +#endif + // 2004.10.11, by rcnjko. + //MlmeDisassociateRequest( Adapter, pMgntInfo->Bssid, disas_lv_ss ); + MlmeDisassociateRequest( dev, priv->ieee80211->current_network.bssid, asRsn ); + + priv->ieee80211->state = IEEE80211_NOLINK; +// pMgntInfo->AsocTimestamp = 0; +} +bool +MgntDisconnect( + struct net_device *dev, + u8 asRsn +) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + // + // Schedule an workitem to wake up for ps mode, 070109, by rcnjko. + // +#ifdef TODO + if(pMgntInfo->mPss != eAwake) + { + // + // Using AwkaeTimer to prevent mismatch ps state. + // In the timer the state will be changed according to the RF is being awoke or not. By Bruce, 2007-10-31. + // + // PlatformScheduleWorkItem( &(pMgntInfo->AwakeWorkItem) ); + PlatformSetTimer( Adapter, &(pMgntInfo->AwakeTimer), 0 ); + } +#endif + + // Indication of disassociation event. + //DrvIFIndicateDisassociation(Adapter, asRsn); +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(priv->ieee80211)) + Dot11d_Reset(priv->ieee80211); +#endif + // In adhoc mode, update beacon frame. + if( priv->ieee80211->state == IEEE80211_LINKED ) + { + if( priv->ieee80211->iw_mode == IW_MODE_ADHOC ) + { +// RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> MgntDisconnectIBSS\n")); + //printk("MgntDisconnect() ===> MgntDisconnectIBSS\n"); + MgntDisconnectIBSS(dev); + } + if( priv->ieee80211->iw_mode == IW_MODE_INFRA ) + { + // We clear key here instead of MgntDisconnectAP() because that + // MgntActSet_802_11_DISASSOCIATE() is an interface called by OS, + // e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is + // used to handle disassociation related things to AP, e.g. send Disassoc + // frame to AP. 2005.01.27, by rcnjko. +// SecClearAllKeys(Adapter); + +// RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> MgntDisconnectAP\n")); + //printk("MgntDisconnect() ===> MgntDisconnectAP\n"); + MgntDisconnectAP(dev, asRsn); + } + + // Inidicate Disconnect, 2005.02.23, by rcnjko. +// MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE); + } + + return true; +} +// +// Description: +// Chang RF Power State. +// Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE. +// +// Assumption: +// PASSIVE LEVEL. +// +bool +SetRFPowerState( + struct net_device *dev, + RT_RF_POWER_STATE eRFPowerState + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + bool bResult = false; + +// printk("---------> SetRFPowerState(): eRFPowerState(%d)\n", eRFPowerState); + if(eRFPowerState == priv->eRFPowerState) + { +// printk("<--------- SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", eRFPowerState); + return bResult; + } + + switch(priv->rf_chip) + { + case RF_ZEBRA2: + case RF_ZEBRA4: + bResult = SetZebraRFPowerState8185(dev, eRFPowerState); + break; + + default: + printk("SetRFPowerState8185(): unknown RFChipID: 0x%X!!!\n", priv->rf_chip); + break;; +} +// printk("<--------- SetRFPowerState(): bResult(%d)\n", bResult); + + return bResult; +} +void +HalEnableRx8185Dummy( + struct net_device *dev + ) +{ +} +void +HalDisableRx8185Dummy( + struct net_device *dev + ) +{ +} + +bool +MgntActSet_RF_State( + struct net_device *dev, + RT_RF_POWER_STATE StateToSet, + u32 ChangeSource + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + bool bActionAllowed = false; + bool bConnectBySSID = false; + RT_RF_POWER_STATE rtState; + u16 RFWaitCounter = 0; + unsigned long flag; +// printk("===>MgntActSet_RF_State(): StateToSet(%d), ChangeSource(0x%x)\n",StateToSet, ChangeSource); + // + // Prevent the race condition of RF state change. By Bruce, 2007-11-28. + // Only one thread can change the RF state at one time, and others should wait to be executed. + // +#if 1 + while(true) + { +// down(&priv->rf_state); + spin_lock_irqsave(&priv->rf_ps_lock,flag); + if(priv->RFChangeInProgress) + { +// printk("====================>haha111111111\n"); +// up(&priv->rf_state); +// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): RF Change in progress! Wait to set..StateToSet(%d).\n", StateToSet)); + spin_unlock_irqrestore(&priv->rf_ps_lock,flag); + // Set RF after the previous action is done. + while(priv->RFChangeInProgress) + { + RFWaitCounter ++; +// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): Wait 1 ms (%d times)...\n", RFWaitCounter)); + udelay(1000); // 1 ms + + // Wait too long, return FALSE to avoid to be stuck here. + if(RFWaitCounter > 1000) // 1sec + { +// RT_ASSERT(FALSE, ("MgntActSet_RF_State(): Wait too logn to set RF\n")); + printk("MgntActSet_RF_State(): Wait too long to set RF\n"); + // TODO: Reset RF state? + return false; + } + } + } + else + { +// printk("========================>haha2\n"); + priv->RFChangeInProgress = true; +// up(&priv->rf_state); + spin_unlock_irqrestore(&priv->rf_ps_lock,flag); + break; + } + } +#endif + rtState = priv->eRFPowerState; + + + switch(StateToSet) + { + case eRfOn: + // + // Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or + // the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02. + // + priv->RfOffReason &= (~ChangeSource); + + if(! priv->RfOffReason) + { + priv->RfOffReason = 0; + bActionAllowed = true; + + if(rtState == eRfOff && ChangeSource >=RF_CHANGE_BY_HW && !priv->bInHctTest) + { + bConnectBySSID = true; + } + } + else +// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", pMgntInfo->RfOffReason, ChangeSource)); + ; + break; + + case eRfOff: + // 070125, rcnjko: we always keep connected in AP mode. + + if (priv->RfOffReason > RF_CHANGE_BY_IPS) + { + // + // 060808, Annie: + // Disconnect to current BSS when radio off. Asked by QuanTa. + // + + // + // Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(), + // because we do NOT need to set ssid to dummy ones. + // Revised by Roger, 2007.12.04. + // + MgntDisconnect( dev, disas_lv_ss ); + + // Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. + // 2007.05.28, by shien chang. +// PlatformZeroMemory( pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC ); +// pMgntInfo->NumBssDesc = 0; +// PlatformZeroMemory( pMgntInfo->bssDesc4Query, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC ); +// pMgntInfo->NumBssDesc4Query = 0; + } + + + + priv->RfOffReason |= ChangeSource; + bActionAllowed = true; + break; + + case eRfSleep: + priv->RfOffReason |= ChangeSource; + bActionAllowed = true; + break; + + default: + break; + } + + if(bActionAllowed) + { +// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, pMgntInfo->RfOffReason)); + // Config HW to the specified mode. +// printk("MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, priv->RfOffReason); + SetRFPowerState(dev, StateToSet); + + // Turn on RF. + if(StateToSet == eRfOn) + { + HalEnableRx8185Dummy(dev); + if(bConnectBySSID) + { + // by amy not supported +// MgntActSet_802_11_SSID(Adapter, Adapter->MgntInfo.Ssid.Octet, Adapter->MgntInfo.Ssid.Length, TRUE ); + } + } + // Turn off RF. + else if(StateToSet == eRfOff) + { + HalDisableRx8185Dummy(dev); + } + } + else + { + // printk("MgntActSet_RF_State(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", StateToSet, ChangeSource, priv->RfOffReason); + } + + // Release RF spinlock +// down(&priv->rf_state); + spin_lock_irqsave(&priv->rf_ps_lock,flag); + priv->RFChangeInProgress = false; +// up(&priv->rf_state); + spin_unlock_irqrestore(&priv->rf_ps_lock,flag); +// printk("<===MgntActSet_RF_State()\n"); + return bActionAllowed; +} +void +InactivePowerSave( + struct net_device *dev + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + //u8 index = 0; + + // + // This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem + // is really scheduled. + // The old code, sets this flag before scheduling the IPS workitem and however, at the same time the + // previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing + // blocks the IPS procedure of switching RF. + // By Bruce, 2007-12-25. + // + priv->bSwRfProcessing = true; + + MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS); + + // + // To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20. + // +#if 0 + while( index < 4 ) + { + if( ( pMgntInfo->SecurityInfo.PairwiseEncAlgorithm == WEP104_Encryption ) || + (pMgntInfo->SecurityInfo.PairwiseEncAlgorithm == WEP40_Encryption) ) + { + if( pMgntInfo->SecurityInfo.KeyLen[index] != 0) + pAdapter->HalFunc.SetKeyHandler(pAdapter, index, 0, FALSE, pMgntInfo->SecurityInfo.PairwiseEncAlgorithm, TRUE, FALSE); + + } + index++; + } +#endif + priv->bSwRfProcessing = false; +} + +// +// Description: +// Enter the inactive power save mode. RF will be off +// 2007.08.17, by shien chang. +// +void +IPSEnter( + struct net_device *dev + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + RT_RF_POWER_STATE rtState; + //printk("==============================>enter IPS\n"); + if (priv->bInactivePs) + { + rtState = priv->eRFPowerState; + + // + // Added by Bruce, 2007-12-25. + // Do not enter IPS in the following conditions: + // (1) RF is already OFF or Sleep + // (2) bSwRfProcessing (indicates the IPS is still under going) + // (3) Connectted (only disconnected can trigger IPS) + // (4) IBSS (send Beacon) + // (5) AP mode (send Beacon) + // + if (rtState == eRfOn && !priv->bSwRfProcessing + && (priv->ieee80211->state != IEEE80211_LINKED )) + { + // printk("IPSEnter(): Turn off RF.\n"); + priv->eInactivePowerState = eRfOff; + InactivePowerSave(dev); + } + } +// printk("priv->eRFPowerState is %d\n",priv->eRFPowerState); +} +void +IPSLeave( + struct net_device *dev + ) +{ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + RT_RF_POWER_STATE rtState; + //printk("===================================>leave IPS\n"); + if (priv->bInactivePs) + { + rtState = priv->eRFPowerState; + if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) + { +// printk("IPSLeave(): Turn on RF.\n"); + priv->eInactivePowerState = eRfOn; + InactivePowerSave(dev); + } + } +// printk("priv->eRFPowerState is %d\n",priv->eRFPowerState); +} +//by amy for power save +void rtl8185b_adapter_start(struct net_device *dev) +{ + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; + + u8 SupportedWirelessMode; + u8 InitWirelessMode; + u8 bInvalidWirelessMode = 0; + //int i; + u8 tmpu8; + //u8 u1tmp,u2tmp; + u8 btCR9346; + u8 TmpU1b; + u8 btPSR; + + //rtl8180_rtx_disable(dev); +//{by amy 080312 + write_nic_byte(dev,0x24e, (BIT5|BIT6|BIT0)); +//by amy 080312} + rtl8180_reset(dev); + + priv->dma_poll_mask = 0; + priv->dma_poll_stop_mask = 0; + + //rtl8180_beacon_tx_disable(dev); + + HwConfigureRTL8185(dev); + + write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff ); + + write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); // default network type to 'No Link' + + //write_nic_byte(dev, BRSR, 0x0); // Set BRSR= 1M + + write_nic_word(dev, BcnItv, 100); + write_nic_word(dev, AtimWnd, 2); + + //PlatformEFIOWrite2Byte(dev, FEMR, 0xFFFF); + PlatformIOWrite2Byte(dev, FEMR, 0xFFFF); + + write_nic_byte(dev, WPA_CONFIG, 0); + + MacConfig_85BASIC(dev); + + // Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. + // BT_DEMO_BOARD type + PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a); +//by amy +//#ifdef CONFIG_RTL818X_S + // for jong required +// PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x9a56); +//#endif +//by amy + //BT_QA_BOARD + //PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x9a56); + + //----------------------------------------------------------------------------- + // Set up PHY related. + //----------------------------------------------------------------------------- + // Enable Config3.PARAM_En to revise AnaaParm. + write_nic_byte(dev, CR9346, 0xc0); // enable config register write +//by amy + tmpu8 = read_nic_byte(dev, CONFIG3); +#ifdef CONFIG_RTL818X_S + write_nic_byte(dev, CONFIG3, (tmpu8 |CONFIG3_PARM_En) ); +#else + write_nic_byte(dev, CONFIG3, (tmpu8 |CONFIG3_PARM_En | CONFIG3_CLKRUN_En) ); +#endif +//by amy + // Turn on Analog power. + // Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. + write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON); + write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON); +//by amy +#ifdef CONFIG_RTL818X_S + write_nic_word(dev, ANAPARAM3, 0x0010); +#else + write_nic_byte(dev, ANAPARAM3, 0x00); +#endif +//by amy + + write_nic_byte(dev, CONFIG3, tmpu8); + write_nic_byte(dev, CR9346, 0x00); +//{by amy 080312 for led + // enable EEM0 and EEM1 in 9346CR + btCR9346 = read_nic_byte(dev, CR9346); + write_nic_byte(dev, CR9346, (btCR9346|0xC0) ); + + // B cut use LED1 to control HW RF on/off + TmpU1b = read_nic_byte(dev, CONFIG5); + TmpU1b = TmpU1b & ~BIT3; + write_nic_byte(dev,CONFIG5, TmpU1b); + + // disable EEM0 and EEM1 in 9346CR + btCR9346 &= ~(0xC0); + write_nic_byte(dev, CR9346, btCR9346); + + //Enable Led (suggested by Jong) + // B-cut RF Radio on/off 5e[3]=0 + btPSR = read_nic_byte(dev, PSR); + write_nic_byte(dev, PSR, (btPSR | BIT3)); +//by amy 080312 for led} + // setup initial timing for RFE. + write_nic_word(dev, RFPinsOutput, 0x0480); + SetOutputEnableOfRfPins(dev); + write_nic_word(dev, RFPinsSelect, 0x2488); + + // PHY config. + PhyConfig8185(dev); + + // We assume RegWirelessMode has already been initialized before, + // however, we has to validate the wireless mode here and provide a reasonble + // initialized value if necessary. 2005.01.13, by rcnjko. + SupportedWirelessMode = GetSupportedWirelessMode8185(dev); + if( (ieee->mode != WIRELESS_MODE_B) && + (ieee->mode != WIRELESS_MODE_G) && + (ieee->mode != WIRELESS_MODE_A) && + (ieee->mode != WIRELESS_MODE_AUTO)) + { // It should be one of B, G, A, or AUTO. + bInvalidWirelessMode = 1; + } + else + { // One of B, G, A, or AUTO. + // Check if the wireless mode is supported by RF. + if( (ieee->mode != WIRELESS_MODE_AUTO) && + (ieee->mode & SupportedWirelessMode) == 0 ) + { + bInvalidWirelessMode = 1; + } + } + + if(bInvalidWirelessMode || ieee->mode==WIRELESS_MODE_AUTO) + { // Auto or other invalid value. + // Assigne a wireless mode to initialize. + if((SupportedWirelessMode & WIRELESS_MODE_A)) + { + InitWirelessMode = WIRELESS_MODE_A; + } + else if((SupportedWirelessMode & WIRELESS_MODE_G)) + { + InitWirelessMode = WIRELESS_MODE_G; + } + else if((SupportedWirelessMode & WIRELESS_MODE_B)) + { + InitWirelessMode = WIRELESS_MODE_B; + } + else + { + DMESGW("InitializeAdapter8185(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n", + SupportedWirelessMode); + InitWirelessMode = WIRELESS_MODE_B; + } + + // Initialize RegWirelessMode if it is not a valid one. + if(bInvalidWirelessMode) + { + ieee->mode = (WIRELESS_MODE)InitWirelessMode; + } + } + else + { // One of B, G, A. + InitWirelessMode = ieee->mode; + } +//by amy for power save +#ifdef ENABLE_IPS +// printk("initialize ENABLE_IPS\n"); + priv->eRFPowerState = eRfOff; + priv->RfOffReason = 0; + { + // u32 tmp2; + // u32 tmp = jiffies; + MgntActSet_RF_State(dev, eRfOn, 0); + // tmp2 = jiffies; + // printk("rf on cost jiffies:%lx\n", (tmp2-tmp)*1000/HZ); + } +// DrvIFIndicateCurrentPhyStatus(priv); + // + // If inactive power mode is enabled, disable rf while in disconnected state. + // 2007.07.16, by shien chang. + // + if (priv->bInactivePs) + { + // u32 tmp2; + // u32 tmp = jiffies; + MgntActSet_RF_State(dev,eRfOff, RF_CHANGE_BY_IPS); + // tmp2 = jiffies; + // printk("rf off cost jiffies:%lx\n", (tmp2-tmp)*1000/HZ); + + } +#endif +// IPSEnter(dev); +//by amy for power save +#ifdef TODO + // Turn off RF if necessary. 2005.08.23, by rcnjko. + // We shall turn off RF after setting CMDR, otherwise, + // RF will be turnned on after we enable MAC Tx/Rx. + if(Adapter->MgntInfo.RegRfOff == TRUE) + { + SetRFPowerState8185(Adapter, RF_OFF); + } + else + { + SetRFPowerState8185(Adapter, RF_ON); + } +#endif + +/* //these is equal with above TODO. + write_nic_byte(dev, CR9346, 0xc0); // enable config register write + write_nic_byte(dev, CONFIG3, read_nic_byte(dev, CONFIG3) | CONFIG3_PARM_En); + RF_WriteReg(dev, 0x4, 0x9FF); + write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON); + write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON); + write_nic_byte(dev, CONFIG3, (read_nic_byte(dev, CONFIG3)&(~CONFIG3_PARM_En))); + write_nic_byte(dev, CR9346, 0x00); +*/ + + ActSetWirelessMode8185(dev, (u8)(InitWirelessMode)); + + //----------------------------------------------------------------------------- + + rtl8185b_irq_enable(dev); + + netif_start_queue(dev); + + } + + +void rtl8185b_rx_enable(struct net_device *dev) +{ + u8 cmd; + //u32 rxconf; + /* for now we accept data, management & ctl frame*/ + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); +#if 0 + rxconf=read_nic_dword(dev,RX_CONF); + rxconf = rxconf &~ MAC_FILTER_MASK; + rxconf = rxconf | (1<<ACCEPT_MNG_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_DATA_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_BCAST_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_MCAST_FRAME_SHIFT); +// rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT); + if (dev->flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); + + if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ + dev->flags & IFF_PROMISC){ + rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT); + }else{ + rxconf = rxconf | (1<<ACCEPT_NICMAC_FRAME_SHIFT); + if(priv->card_8185 == 0) + rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT); + } + + /*if(priv->ieee80211->iw_mode == IW_MODE_MASTER){ + rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT); + rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT); + }*/ + + if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){ + rxconf = rxconf | (1<<ACCEPT_CTL_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_ICVERR_FRAME_SHIFT); + rxconf = rxconf | (1<<ACCEPT_PWR_FRAME_SHIFT); + } + + if( priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) + rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT); + + //if(!priv->card_8185){ + rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK; + rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<<RX_FIFO_THRESHOLD_SHIFT); + //} + + rxconf = rxconf | (1<<RX_AUTORESETPHY_SHIFT); + rxconf = rxconf &~ MAX_RX_DMA_MASK; + rxconf = rxconf | (MAX_RX_DMA_2048<<MAX_RX_DMA_SHIFT); + + //if(!priv->card_8185) + rxconf = rxconf | RCR_ONLYERLPKT; + + rxconf = rxconf &~ RCR_CS_MASK; + if(!priv->card_8185) + rxconf |= (priv->rcr_csense<<RCR_CS_SHIFT); +// rxconf &=~ 0xfff00000; +// rxconf |= 0x90100000;//9014f76f; + write_nic_dword(dev, RX_CONF, rxconf); +#endif + + if (dev->flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); + + if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ + dev->flags & IFF_PROMISC){ + priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM); + priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP; + } + + /*if(priv->ieee80211->iw_mode == IW_MODE_MASTER){ + rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT); + rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT); + }*/ + + if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){ + priv->ReceiveConfig = priv->ReceiveConfig | RCR_ACF | RCR_APWRMGT | RCR_AICV; + } + + if( priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) + priv->ReceiveConfig = priv->ReceiveConfig | RCR_ACRC32; + + write_nic_dword(dev, RCR, priv->ReceiveConfig); + + fix_rx_fifo(dev); + +#ifdef DEBUG_RX + DMESG("rxconf: %x %x",priv->ReceiveConfig ,read_nic_dword(dev,RCR)); +#endif + cmd=read_nic_byte(dev,CMD); + write_nic_byte(dev,CMD,cmd | (1<<CMD_RX_ENABLE_SHIFT)); + +} + +void rtl8185b_tx_enable(struct net_device *dev) +{ + u8 cmd; + //u8 tx_agc_ctl; + u8 byte; + //u32 txconf; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + +#if 0 + txconf= read_nic_dword(dev,TX_CONF); + if(priv->card_8185){ + + + byte = read_nic_byte(dev,CW_CONF); + byte &= ~(1<<CW_CONF_PERPACKET_CW_SHIFT); + byte &= ~(1<<CW_CONF_PERPACKET_RETRY_SHIFT); + write_nic_byte(dev, CW_CONF, byte); + + tx_agc_ctl = read_nic_byte(dev, TX_AGC_CTL); + tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_GAIN_SHIFT); + tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT); + tx_agc_ctl |=(1<<TX_AGC_CTL_FEEDBACK_ANT); + write_nic_byte(dev, TX_AGC_CTL, tx_agc_ctl); + /* + write_nic_word(dev, 0x5e, 0x01); + force_pci_posting(dev); + mdelay(1); + write_nic_word(dev, 0xfe, 0x10); + force_pci_posting(dev); + mdelay(1); + write_nic_word(dev, 0x5e, 0x00); + force_pci_posting(dev); + mdelay(1); + */ + write_nic_byte(dev, 0xec, 0x3f); /* Disable early TX */ + } + + if(priv->card_8185){ + + txconf = txconf &~ (1<<TCR_PROBE_NOTIMESTAMP_SHIFT); + + }else{ + + if(hwseqnum) + txconf= txconf &~ (1<<TX_CONF_HEADER_AUTOICREMENT_SHIFT); + else + txconf= txconf | (1<<TX_CONF_HEADER_AUTOICREMENT_SHIFT); + } + + txconf = txconf &~ TX_LOOPBACK_MASK; + txconf = txconf | (TX_LOOPBACK_NONE <<TX_LOOPBACK_SHIFT); + txconf = txconf &~ TCR_DPRETRY_MASK; + txconf = txconf &~ TCR_RTSRETRY_MASK; + txconf = txconf | (priv->retry_data<<TX_DPRETRY_SHIFT); + txconf = txconf | (priv->retry_rts<<TX_RTSRETRY_SHIFT); + txconf = txconf &~ (1<<TX_NOCRC_SHIFT); + + if(priv->card_8185){ + if(priv->hw_plcp_len) + txconf = txconf &~ TCR_PLCP_LEN; + else + txconf = txconf | TCR_PLCP_LEN; + }else{ + txconf = txconf &~ TCR_SAT; + } + txconf = txconf &~ TCR_MXDMA_MASK; + txconf = txconf | (TCR_MXDMA_2048<<TCR_MXDMA_SHIFT); + txconf = txconf | TCR_CWMIN; + txconf = txconf | TCR_DISCW; + +// if(priv->ieee80211->hw_wep) +// txconf=txconf &~ (1<<TX_NOICV_SHIFT); +// else + txconf=txconf | (1<<TX_NOICV_SHIFT); + + write_nic_dword(dev,TX_CONF,txconf); +#endif + + write_nic_dword(dev, TCR, priv->TransmitConfig); + byte = read_nic_byte(dev, MSR); + byte |= MSR_LINK_ENEDCA; + write_nic_byte(dev, MSR, byte); + + fix_tx_fifo(dev); + +#ifdef DEBUG_TX + DMESG("txconf: %x %x",priv->TransmitConfig,read_nic_dword(dev,TCR)); +#endif + + cmd=read_nic_byte(dev,CMD); + write_nic_byte(dev,CMD,cmd | (1<<CMD_TX_ENABLE_SHIFT)); + + //write_nic_dword(dev,TX_CONF,txconf); + + +/* + rtl8180_set_mode(dev,EPROM_CMD_CONFIG); + write_nic_byte(dev, TX_DMA_POLLING, priv->dma_poll_mask); + rtl8180_set_mode(dev,EPROM_CMD_NORMAL); + */ +} + + +#endif |