diff options
Diffstat (limited to 'drivers')
59 files changed, 38287 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 48e2e064a65..53404a4018f 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -81,5 +81,7 @@ source "drivers/staging/panel/Kconfig" source "drivers/staging/altpciechdma/Kconfig" +source "drivers/staging/rtl8187se/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index b301be8af94..170789f3c4c 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_ASUS_OLED) += asus_oled/ obj-$(CONFIG_PANEL) += panel/ obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/ +obj-$(CONFIG_RTL8187SE) += rtl8187se/ diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig new file mode 100644 index 00000000000..79c225acd1a --- /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 00000000000..cc1c2407402 --- /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 00000000000..49f53fe52af --- /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 00000000000..bf06abeeaeb --- /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 00000000000..b5b78dcd209 --- /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 00000000000..0c176e29a79 --- /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 00000000000..c627d029528 --- /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 00000000000..654f0e90af8 --- /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 00000000000..c97756f3b2e --- /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 00000000000..1968acfe32b --- /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 00000000000..c2df80e2ed9 --- /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 00000000000..1a95f2d3783 --- /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 00000000000..5d8b752fc0f --- /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 00000000000..64bcf15bd21 --- /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 00000000000..bf06abeeaeb --- /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 00000000000..af64cfbe16d --- /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 00000000000..b58a3bcc0dc --- /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 00000000000..7d890c328b0 --- /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 00000000000..e560b1e1102 --- /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 00000000000..f973daeeeb0 --- /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 00000000000..0c9fef0b4e3 --- /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 00000000000..79ec64959cf --- /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 00000000000..fcffee516d5 --- /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 00000000000..43b8aecee9d --- /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 00000000000..33a0687252a --- /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 00000000000..c7d9f4fda41 --- /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 00000000000..ddc22350d00 --- /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 00000000000..de67bb01b5f --- /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 00000000000..df256e487c2 --- /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 00000000000..4f3f9ed7751 --- /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 00000000000..9ed0ca42085 --- /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 00000000000..49f401fbce8 --- /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 00000000000..b1644651901 --- /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 00000000000..b58a3bcc0dc --- /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 00000000000..12215fc61dd --- /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 00000000000..7e4711fb930 --- /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 00000000000..a028a51b23f --- /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 00000000000..38455983728 --- /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 00000000000..742dc11fcac --- /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 00000000000..3de92f040f9 --- /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 00000000000..86cb427a7a4 --- /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 00000000000..fe965ca6430 --- /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 00000000000..bf38934bc09 --- /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 00000000000..cea08463d5e --- /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 00000000000..5d4fb550484 --- /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 00000000000..3851b936835 --- /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 00000000000..7958b3a734d --- /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 00000000000..96ed029ed64 --- /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 00000000000..458de6629ad --- /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 00000000000..90a574d46da --- /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 00000000000..1a62444dcc5 --- /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 00000000000..be44ca6eb1d --- /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 00000000000..d6495601715 --- /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 00000000000..683a69b96af --- /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 00000000000..c77abe502b7 --- /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 00000000000..b20a67d3341 --- /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 00000000000..4b885a2319e --- /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 |