diff --git a/OrangePiRDA/external/common/rootfs/100-fs-warning b/OrangePiRDA/external/common/rootfs/100-fs-warning new file mode 100755 index 0000000..2e85d93 --- /dev/null +++ b/OrangePiRDA/external/common/rootfs/100-fs-warning @@ -0,0 +1,9 @@ +#!/bin/sh + +BOARD=`hostname` +echo "\033[31m\033[1m***********************************************" +echo "Welcome to ${BOARD}:" +echo "At first! please configure your ${BOARD}:" +echo "sudo orangepi-config" +echo "Have good trip on ${BOARD}!" +echo "***********************************************\033[22m\033[37m" diff --git a/OrangePiRDA/external/common/rootfs/cpu.sh b/OrangePiRDA/external/common/rootfs/cpu.sh new file mode 100755 index 0000000..1699704 --- /dev/null +++ b/OrangePiRDA/external/common/rootfs/cpu.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +Usage(){ + printf "\033[32mUsage: " + printf "\t$0 [-h] [-f]... [-s ]\n +Arguments: + -h Print Help (this message) + -f CPU0~3 supported frequencies + -s Set the maximum frequency of CPU0~3 + e.g: -s 1008000 1 (Set the maximum frequency of cpu1 to 1008000) + -c View the current frequency of cpu0~3 + -t View the current CPU temperature + -l List CPU ID + -i Viewing cpu statistics +\033[0m" +} + +while getopts ":hfFs:ctli" varname +do + case $varname in + h) + Usage + exit + ;; + + f) + echo "CPU0~3 supported frequencies: " + echo " " + echo "CPU[0]: " + cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies + echo "CPU[1]: " + cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_available_frequencies + echo "CPU[2]: " + cat /sys/devices/system/cpu/cpu2/cpufreq/scaling_available_frequencies + echo "CPU[3]: " + cat /sys/devices/system/cpu/cpu3/cpufreq/scaling_available_frequencies + exit + ;; + + s) + echo "Set the maximum frequency of CPU$3: $OPTARG" + echo $OPTARG > /sys/devices/system/cpu/cpu$3/cpufreq/scaling_max_freq + exit + ;; + + c) + echo "The current frequency of cpu0~3: " + cat /sys/devices/system/cpu/cpu[0123]/cpufreq/cpuinfo_cur_freq + exit + ;; + + t) + echo "The current CPU temperature: " + cat /sys/class/thermal/thermal_zone0/temp + exit + ;; + + l) + echo "List CPU ID: " + cat /sys/class/sunxi_info/sys_info | grep "sunxi_chipid" + exit + ;; + + i) + echo "Viewing cpu statistics: " + lscpu + exit + ;; + + *) + echo "\033[31mUnknow Option, Please use 'cpu_sh -h' for more commands.\033[0m" + exit 1 + ;; + esac +done + +Usage diff --git a/OrangePiRDA/external/common/rootfs/profile_for_root b/OrangePiRDA/external/common/rootfs/profile_for_root new file mode 100644 index 0000000..1f2dffd --- /dev/null +++ b/OrangePiRDA/external/common/rootfs/profile_for_root @@ -0,0 +1,9 @@ +# ~/.profile: executed by Bourne-compatible login shells. + +if [ "$BASH" ]; then + if [ -f ~/.bashrc ]; then + . ~/.bashrc + fi +fi + +tty -s && mesg n || true diff --git a/OrangePiRDA/external/common/rootfs/sshd_config b/OrangePiRDA/external/common/rootfs/sshd_config new file mode 100644 index 0000000..30bcbb3 --- /dev/null +++ b/OrangePiRDA/external/common/rootfs/sshd_config @@ -0,0 +1,80 @@ +# Package generated configuration file +# See the sshd_config(5) manpage for details + +# What ports, IPs and protocols we listen for +Port 22 +# Use these options to restrict which interfaces/protocols sshd will bind to +#ListenAddress :: +#ListenAddress 0.0.0.0 +Protocol 2 +# HostKeys for protocol version 2 +HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_dsa_key +HostKey /etc/ssh/ssh_host_ecdsa_key +HostKey /etc/ssh/ssh_host_ed25519_key + +# Logging +SyslogFacility AUTH +LogLevel INFO + +# Authentication: +LoginGraceTime 120 +PermitRootLogin yes +StrictModes yes + +PubkeyAuthentication yes +# AuthorizedKeysFile %h/.ssh/authorized_keys + +# Don't read the user's ~/.rhosts and ~/.shosts files +IgnoreRhosts yes +# For this to work you will also need host keys in /etc/ssh_known_hosts +# similar for protocol version 2 +HostbasedAuthentication no +# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication +#IgnoreUserKnownHosts yes + +# To enable empty passwords, change to yes (NOT RECOMMENDED) +PermitEmptyPasswords no + +# Change to yes to enable challenge-response passwords (beware issues with +# some PAM modules and threads) +ChallengeResponseAuthentication no + +# Change to no to disable tunnelled clear text passwords +PasswordAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosGetAFSToken no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +X11Forwarding yes +X11DisplayOffset 10 +PrintMotd no +PrintLastLog yes +TCPKeepAlive yes +#UseLogin no + +#MaxStartups 10:30:60 +#Banner /etc/issue.net + +# Allow client to pass locale environment variables +AcceptEnv LANG LC_* + +Subsystem sftp /usr/lib/openssh/sftp-server + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +UsePAM yes diff --git a/OrangePiRDA/kernel/arch/arm/configs/i96_linux_defconfig b/OrangePiRDA/kernel/arch/arm/configs/i96_linux_defconfig index e1d3ed3..ba83f06 100644 --- a/OrangePiRDA/kernel/arch/arm/configs/i96_linux_defconfig +++ b/OrangePiRDA/kernel/arch/arm/configs/i96_linux_defconfig @@ -28,7 +28,7 @@ CONFIG_BUILDTIME_EXTABLE_SORT=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_CROSS_COMPILE="" -CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION="-legendary-v1.25" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y @@ -94,7 +94,7 @@ CONFIG_IKCONFIG=m CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_CGROUPS=y -# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_DEVICE=y CONFIG_CPUSETS=y @@ -888,7 +888,7 @@ CONFIG_WEXT_CORE=y CONFIG_WEXT_PROC=y CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set -# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +CONFIG_CFG80211_DEVELOPER_WARNINGS=y CONFIG_CFG80211_REG_DEBUG=y # CONFIG_CFG80211_CERTIFICATION_ONUS is not set # CONFIG_CFG80211_DEFAULT_PS is not set @@ -907,8 +907,8 @@ CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" # CONFIG_MAC80211_MESH is not set # CONFIG_MAC80211_LEDS is not set CONFIG_MAC80211_DEBUGFS=y -# CONFIG_MAC80211_MESSAGE_TRACING is not set -# CONFIG_MAC80211_DEBUG_MENU is not set +CONFIG_MAC80211_MESSAGE_TRACING=y +CONFIG_MAC80211_DEBUG_MENU=y # CONFIG_WIMAX is not set CONFIG_RFKILL=y CONFIG_RFKILL_PM=y @@ -1308,7 +1308,7 @@ CONFIG_RDACBDEV=y CONFIG_RDAWFMAC=m CONFIG_RDAWFMAC_SDIO=y # CONFIG_RDAWFMAC_USB is not set -# CONFIG_RDAWDBG is not set +CONFIG_RDAWDBG=y # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -2470,9 +2470,9 @@ CONFIG_USB_PHY=y # CONFIG_USB_ULPI is not set CONFIG_USB_RDA_PHY=y CONFIG_USB_GADGET=y -# CONFIG_USB_GADGET_DEBUG is not set +CONFIG_USB_GADGET_DEBUG=y # CONFIG_USB_GADGET_DEBUG_FILES is not set -# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=2 CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 @@ -2837,7 +2837,7 @@ CONFIG_PROC_SYSCTL=y CONFIG_PROC_PAGE_MONITOR=y CONFIG_SYSFS=y CONFIG_TMPFS=y -# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_POSIX_ACL=y # CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_CONFIGFS_FS=y @@ -2982,7 +2982,7 @@ CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_PROVE_RCU_DELAY is not set # CONFIG_SPARSE_RCU_POINTER is not set # CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_RCU_TRACE is not set +CONFIG_RCU_TRACE=y # CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set # CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set @@ -2997,7 +2997,7 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_HAVE_C_RECORDMCOUNT=y CONFIG_TRACING_SUPPORT=y -# CONFIG_FTRACE is not set +CONFIG_FTRACE=y # CONFIG_RBTREE_TEST is not set # CONFIG_INTERVAL_TREE_TEST is not set # CONFIG_DYNAMIC_DEBUG is not set diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_cfg80211.c b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_cfg80211.c index 9ce120c..54c278b 100755 --- a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_cfg80211.c +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_cfg80211.c @@ -160,25 +160,23 @@ static const struct ieee80211_regdomain wland_regdom = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { - /* - * IEEE 802.11b/g, channels 1..11 - */ - REG_RULE(2412 - 10, 2472 + 10, 40, 6, 20, 0), - /* - * If any - */ - /* - * IEEE 802.11 channel 14 - Only JP enables this and for 802.11b only - */ - REG_RULE(2484 - 10, 2484 + 10, 20, 6, 20, 0), - /* - * IEEE 802.11a, channel 36..64 - */ - REG_RULE(5150 - 10, 5350 + 10, 40, 6, 20, 0), - /* - * IEEE 802.11a, channel 100..165 - */ - REG_RULE(5470 - 10, 5850 + 10, 40, 6, 20, 0),} + /* + * IEEE 802.11b/g, channels 1..11 + */ + REG_RULE(2412 - 10, 2472 + 10, 40, 6, 20, 0), + /* + * IEEE 802.11 channel 14 - Only JP enables this and for 802.11b only + */ + REG_RULE(2484 - 10, 2484 + 10, 20, 6, 20, 0), + /* + * IEEE 802.11a, channel 36..64 + */ + REG_RULE(5150 - 10, 5350 + 10, 40, 6, 20, 0), + /* + * IEEE 802.11a, channel 100..165 + */ + REG_RULE(5470 - 10, 5850 + 10, 40, 6, 20, 0), + } }; static const u32 __wl_cipher_suites[] = { @@ -1663,7 +1661,7 @@ static s32 cfg80211_set_tx_power(struct wiphy *wiphy, err = wland_fil_iovar_data_set(ifp, "qtxpower", &dbm, sizeof(dbm)); done: - WLAND_DBG(CFG80211, TRACE, "Done(qtxpower:%d)\n", err); + WLAND_DBG(CFG80211, INFO, "Done(qtxpower:%d, mbm:%d)\n", err, mbm); return err; } @@ -5224,7 +5222,6 @@ static const struct ieee80211_txrx_stypes } }; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) void cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { @@ -5246,58 +5243,12 @@ void cfg80211_reg_notifier(struct wiphy *wiphy, /* * We support only REGDOM_SET_BY_USER as of now */ - //if (request->initiator != NL80211_REGDOM_SET_BY_USER) { - // WLAND_ERR("reg_notifier for intiator:%d not supported \n", - // request->initiator); - // return; - //} - - if (request->alpha2[0] == '0' && request->alpha2[1] == '0') { - /* - * world domain - */ - WLAND_ERR("World domain. Setting XY/4 \n"); - strncpy(cspec.country_abbrev, "XY", strlen("XY")); - cspec.rev = 4; - } else { - memcpy(cspec.country_abbrev, request->alpha2, 2); - cspec.country_abbrev[3] = '\0'; - cspec.rev = -1; /* Unspecified */ - } - - WLAND_DBG(CFG80211, TRACE, "set country '%s/%d' done\n", - cspec.country_abbrev, cspec.rev); - return; -} -#else -int cfg80211_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct wland_cfg80211_info *cfg = - (struct wland_cfg80211_info *) wiphy_priv(wiphy); - struct wland_country cspec = { { - 0}, 0, { - 0} - }; - int err = 0; - - if (!request || !cfg) { - WLAND_ERR("Invalid arg\n"); - return err; + if (request->initiator != NL80211_REGDOM_SET_BY_USER) { + WLAND_ERR("reg_notifier for intiator:%d not supported \n", + request->initiator); + return; } - WLAND_DBG(CFG80211, TRACE, "ccode: %c%c Initiator: %d\n", - request->alpha2[0], request->alpha2[1], request->initiator); - - /* - * We support only REGDOM_SET_BY_USER as of now - */ - //if (request->initiator != NL80211_REGDOM_SET_BY_USER) { - // WLAND_ERR("reg_notifier for intiator:%d not supported \n", - // request->initiator); - // return err; - //} - if (request->alpha2[0] == '0' && request->alpha2[1] == '0') { /* * world domain @@ -5311,23 +5262,10 @@ int cfg80211_reg_notifier(struct wiphy *wiphy, cspec.rev = -1; /* Unspecified */ } -#if 0 - if ((ret = wldev_iovar_setbuf(cfg->wdev->netdev, "country", - (char *) &cspec, sizeof(cspec), cfg->ioctl_buf, - WLC_IOCTL_SMLEN, NULL)) < 0) { - WLAND_ERR("set country Failed :%d\n", ret); - goto exit; - } - - if ((ret = wland_update_wiphybands(cfg, false)) < 0) - WLAND_ERR("wland_update_wiphybands failed\n"); -exit: -#endif WLAND_DBG(CFG80211, TRACE, "set country '%s/%d' done\n", cspec.country_abbrev, cspec.rev); - return err; + return; } -#endif static struct wiphy *wland_setup_wiphy(struct device *phydev) { @@ -5461,9 +5399,9 @@ static struct wiphy *wland_setup_wiphy(struct device *phydev) //has its own custom regulatory domain and cannot identify the //ISO /IEC 3166 alpha2 it belongs to. When this is enabled //we will disregard the first regulatory hint (when the initiator is %REGDOM_SET_BY_CORE). - //wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; - //WLAND_DBG(CFG80211, TRACE, "Registering custom regulatory.\n"); + WLAND_DBG(CFG80211, INFO, "Registering custom regulatory.\n"); /* *the driver's regulatory notification callback, @@ -5472,7 +5410,7 @@ static struct wiphy *wland_setup_wiphy(struct device *phydev) */ wiphy->reg_notifier = cfg80211_reg_notifier; - //wiphy_apply_custom_regulatory(wiphy, &wland_regdom); + wiphy_apply_custom_regulatory(wiphy, &wland_regdom); err = wiphy_register(wiphy); if (unlikely(err < 0)) { diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_cfg80211.h b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_cfg80211.h new file mode 100755 index 0000000..1d7f802 --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_cfg80211.h @@ -0,0 +1,554 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAND_CFG80211_H_ +#define _WLAND_CFG80211_H_ + +/* for wland_d11inf */ +#include "wland_d11.h" +#include "wland_defs.h" + +/* pmkid */ +#define MAXPMKID 16 + +/* roam relations variables */ +#define ROAM_TRIGGER_LEVEL -75 +#define ROAM_DELTA 20 + +/* scan parameters */ +#define SCAN_IE_LEN_MAX 2048 +#define SCAN_NUM_MAX 10 + +#define ESCAN_AP_NUM_MAX 70 + +/* avoid access the wrong store cache eare */ +#define SCAN_VERSION_NUM 0x5995 + +#define SCAN_TIMER_INTERVAL_MS (2000) /* E-Scan timeout */ +#define SCAN_TIMER_INTERVAL_MS_91F (2000) /* E-Scan timeout */ +#define SCAN_TIMER2_INTERVAL_MS (25*1000) + +/* scan action state */ +#define SCAN_ACTION_START 1 +#define SCAN_ACTION_CONTINUE 2 +#define SCAN_ACTION_ABORT 3 + +#define CONNECT_TIMER_INTERVAL_MS 2000 /* connect timeout */ +#define CONNECT_RETRY_TIMES_MAX 5 /* CONNECT_TIMER_INTERVAL_MS*CONNECT_RETRY_TIMES_MAX should be no more than 10s */ +#define CONNECT_RESTOREWORK_TIMER_MS 6*1000 + +#define IE_MAX_LEN 512 + +/* IE TLV processing */ +#define TLV_LEN_OFF 1 /* length offset */ +#define TLV_HDR_LEN 2 /* header length */ +#define TLV_BODY_OFF 2 /* body offset */ +#define TLV_OUI_LEN 3 /* oui id length */ + +#define WLAND_TLV_INFO_MAX 1024 +#define WLAND_BSS_INFO_MAX 1024 +#define WLAND_ASSOC_INFO_MAX 512 /* assoc related fil max buf */ +#define WLAND_EXTRA_BUF_MAX 1024 +#define WLAND_BEACON_TIMEOUT 3 + +/* 802.11 Mgmt Packet flags */ +#define WLAND_VNDR_IE_BEACON_FLAG 0x01 +#define WLAND_VNDR_IE_PRBRSP_FLAG 0x02 +#define WLAND_VNDR_IE_ASSOCRSP_FLAG 0x04 +#define WLAND_VNDR_IE_AUTHRSP_FLAG 0x08 +#define WLAND_VNDR_IE_PRBREQ_FLAG 0x10 +#define WLAND_VNDR_IE_ASSOCREQ_FLAG 0x20 + +/* vendor IE in IW advertisement protocol ID field */ +#define WLAND_VNDR_IE_IWAPID_FLAG 0x40 + +/* allow custom IE id */ +#define WLAND_VNDR_IE_CUSTOM_FLAG 0x100 + +/* P2P Action Frames flags (spec ordered) */ +#define WLAND_VNDR_IE_GONREQ_FLAG 0x001000 +#define WLAND_VNDR_IE_GONRSP_FLAG 0x002000 +#define WLAND_VNDR_IE_GONCFM_FLAG 0x004000 +#define WLAND_VNDR_IE_INVREQ_FLAG 0x008000 +#define WLAND_VNDR_IE_INVRSP_FLAG 0x010000 +#define WLAND_VNDR_IE_DISREQ_FLAG 0x020000 +#define WLAND_VNDR_IE_DISRSP_FLAG 0x040000 +#define WLAND_VNDR_IE_PRDREQ_FLAG 0x080000 +#define WLAND_VNDR_IE_PRDRSP_FLAG 0x100000 + +#define WLAND_VNDR_IE_P2PAF_SHIFT 12 + +#define WLAND_PNO_VERSION 2 +#define WLAND_PNO_TIME 30 +#define WLAND_PNO_REPEAT 4 +#define WLAND_PNO_FREQ_EXPO_MAX 3 +#define WLAND_PNO_MAX_PFN_COUNT 16 +#define WLAND_PNO_ENABLE_ADAPTSCAN_BIT 6 +#define WLAND_PNO_HIDDEN_BIT 2 +#define WLAND_PNO_WPA_AUTH_ANY 0xFFFFFFFF +#define WLAND_PNO_SCAN_COMPLETE 1 +#define WLAND_PNO_SCAN_INCOMPLETE 0 + +#define WLAND_IFACE_MAX_CNT 3 + +#define VS_IE_FIXED_HDR_LEN 6 +#define WPA_IE_VERSION_LEN 2 +#define WPA_IE_MIN_OUI_LEN 4 + +#define VNDR_IE_CMD_LEN 4 /* length of the set command string :"add", "del" (+ NUL) */ +#define VNDR_IE_COUNT_OFFSET 4 +#define VNDR_IE_PKTFLAG_OFFSET 8 +#define VNDR_IE_VSIE_OFFSET 12 +#define VNDR_IE_HDR_SIZE 12 +#define VNDR_IE_PARSE_LIMIT 5 + +/* + * enum wland_scan_status - scan engine status + * + * @SCAN_STATUS_BUSY : scanning in progress on dongle. + * @SCAN_STATUS_ABORT : scan being aborted on dongle. + * @SCAN_STATUS_SUPPRESS: scanning is suppressed in driver. + */ +enum wland_scan_status { + SCAN_STATUS_BUSY, + SCAN_STATUS_ABORT, + SCAN_STATUS_SUPPRESS, +}; + +/* + * enum wland_vif_status - bit indices for vif status. + * + * @VIF_STATUS_READY : ready for operation. + * @VIF_STATUS_CONNECTING : connect/join in progress. + * @VIF_STATUS_CONNECTED : connected/joined succesfully. + * @VIF_STATUS_DISCONNECTING: disconnect/disable in progress. + * @VIF_STATUS_AP_CREATING : interface configured for AP operation. + * @VIF_STATUS_AP_CREATED : AP operation started. + * @VIF_STATUS_TESTING : chip enter test mode. + */ +enum wland_vif_status { + VIF_STATUS_READY, + VIF_STATUS_CONNECTING, + VIF_STATUS_CONNECTED, + VIF_STATUS_DISCONNECTING, + VIF_STATUS_AP_CREATING, + VIF_STATUS_AP_CREATED, + VIF_STATUS_TESTING, +}; + +/* + * enum wland_mode - driver mode of virtual interface. + * + * @WL_MODE_BSS : connects to BSS. + * @WL_MODE_IBSS: operate as ad-hoc. + * @WL_MODE_AP : operate as access-point. + */ +enum wland_mode { + WL_MODE_BSS, + WL_MODE_IBSS, + WL_MODE_AP +}; + +/* dongle configuration */ +struct wland_cfg80211_conf { + u32 frag_threshold; + u32 rts_threshold; + u32 retry_short; + u32 retry_long; + s32 tx_power; + struct ieee80211_channel channel; +}; + +struct pmkid { + u8 BSSID[ETH_ALEN]; + u8 PMKID[WLAN_PMKID_LEN]; +}; + +struct pmkid_list { + __le32 npmkid; + struct pmkid pmkid[1]; +}; + +/* basic structure of scan request */ +struct wland_cfg80211_scan_req { + struct wland_ssid_le ssid_le; +}; + +/* + * struct vif_saved_ie - holds saved IEs for a virtual interface. + * + * @probe_req_ie : IE info for probe request. + * @probe_res_ie : IE info for probe response. + * @beacon_ie : IE info for beacon frame. + * @probe_req_ie_len: IE info length for probe request. + * @probe_res_ie_len: IE info length for probe response. + * @beacon_ie_len : IE info length for beacon frame. + */ +struct vif_saved_ie { + u8 probe_req_ie[IE_MAX_LEN]; + u8 probe_res_ie[IE_MAX_LEN]; + u8 beacon_ie[IE_MAX_LEN]; + u8 assoc_req_ie[IE_MAX_LEN]; + u32 probe_req_ie_len; + u32 probe_res_ie_len; + u32 beacon_ie_len; + u32 assoc_req_ie_len; +}; + +/* + * struct wland_cfg80211_vif - virtual interface specific information. + * + * @ifp : lower layer interface pointer + * @wdev : wireless device. + * @profile : profile information. + * @mode : operating mode. + * @roam_off : roaming state. + * @sme_state : SME state using enum wland_vif_status bits. + * @pm_block : power-management blocked. + * @list : linked list. + * @mgmt_rx_reg : registered rx mgmt frame types. + */ +struct wland_cfg80211_vif { + struct wland_if *ifp; + struct wireless_dev wdev; + struct wland_cfg80211_profile profile; + s32 mode; + s32 roam_off; + ulong sme_state; + bool pm_block; + struct vif_saved_ie saved_ie; + struct list_head list; + u16 mgmt_rx_reg; +}; + +/* association inform */ +struct wland_cfg80211_connect_info { + u8 *req_ie; + s32 req_ie_len; + u8 *resp_ie; + s32 resp_ie_len; + + //connect control context + struct net_device *ndev; + struct timer_list timer; + struct timer_list connect_restorework_timeout; + u8 retry_times; + bool timer_on; + struct work_struct work; + struct workqueue_struct *connect_wq; + struct work_struct connect_restorework_timeout_work; + + void *data; +}; + +/* wpa2 pmk list */ +struct wland_cfg80211_pmk_list { + struct pmkid_list pmkids; + struct pmkid foo[MAXPMKID - 1]; +}; + +/* dongle scan state */ +enum wland_scan_state { + SCAN_STATE_IDLE, + SCAN_STATE_SCANNING +}; + +/* dongle escan controller */ +struct escan_info { + u32 escan_state; + struct wiphy *wiphy; + struct wland_if *ifp; + s32(*run) (struct wland_cfg80211_info * cfg, struct wland_if * ifp, + struct cfg80211_scan_request * request, u16 action); +}; + +/* + * struct wland_pno_param_le - PNO scan configuration parameters + * + * @version : PNO parameters version. + * @scan_freq : scan frequency. + * @lost_network_timeout: #sec. to declare discovered network as lost. + * @flags : Bit field to control features of PFN such as sort criteria auto enable switch and background scan. + * @rssi_margin : Margin to avoid jitter for choosing a PFN based on RSSI sort criteria. + * @bestn : number of best networks in each scan. + * @mscan : number of scans recorded. + * @repeat : minimum number of scan intervals before scan frequency changes in adaptive scan. + * @exp : exponent of 2 for maximum scan interval. + * @slow_freq : slow scan period. + */ +struct wland_pno_param_le { + __le32 version; + __le32 scan_freq; + __le32 lost_network_timeout; + __le16 flags; + __le16 rssi_margin; + u8 bestn; + u8 mscan; + u8 repeat; + u8 exp; + __le32 slow_freq; +}; + +/* + * struct wland_pno_net_param_le - scan parameters per preferred network. + * + * @ssid : ssid name and its length. + * @flags : bit2: hidden. + * @infra : BSS vs IBSS. + * @auth : Open vs Closed. + * @wpa_auth: WPA type. + * @wsec : wsec value. + */ +struct wland_pno_net_param_le { + struct wland_ssid_le ssid; + __le32 flags; + __le32 infra; + __le32 auth; + __le32 wpa_auth; + __le32 wsec; +}; + +/* + * struct wland_pno_net_info_le - information per found network. + * + * @bssid : BSS network identifier. + * @channel : channel number only. + * @SSID_len : length of ssid. + * @SSID : ssid characters. + * @RSSI : receive signal strength (in dBm). + * @timestamp : age in seconds. + */ +struct wland_pno_net_info_le { + u8 bssid[ETH_ALEN]; + u8 channel; + u8 SSID_len; + u8 SSID[32]; + __le16 RSSI; + __le16 timestamp; +}; + +/* + * struct wland_pno_scanresults_le - result returned in PNO NET FOUND event. + * + * @version : PNO version identifier. + * @status : indicates completion status of PNO scan. + * @count : amount of wland_pno_net_info_le entries appended. + */ +struct wland_pno_scanresults_le { + __le32 version; + __le32 status; + __le32 count; +}; + +/* + * struct wland_cfg80211_vif_event - virtual interface event information. + * + * @vif_wq : waitqueue awaiting interface event from firmware. + * @vif_event_lock : protects other members in this structure. + * @vif_complete : completion for net attach. + * @action : either add, change, or delete. + * @vif : virtual interface object related to the event. + */ +struct wland_cfg80211_vif_event { + wait_queue_head_t vif_wq; + struct mutex vif_event_lock; + u8 action; + struct wland_cfg80211_vif *vif; +}; + +/* + * struct wland_cfg80211_info - dongle private data of cfg80211 interface + * + * @wiphy : wiphy object for cfg80211 interface. + * @conf : dongle configuration. + * @p2p : peer-to-peer specific information. + * @btcoex : Bluetooth coexistence information. + * @scan_request: cfg80211 scan request object. + * @usr_sync : mainly for dongle up/down synchronization. + * @bss_list : bss_list holding scanned ap information. + * @scan_req_int: internal scan request object. + * @ie : information element object for internal purpose. + * @conn_info : association info. + * @pmk_list : wpa2 pmk list. + * @scan_status : scan activity on the dongle. + * @pub : common driver information. + * @channel : current channel. + * @active_scan : current scan mode. + * @sched_escan : e-scan for scheduled scan support running. + * @ibss_starter: indicates this sta is ibss starter. + * @pwr_save : indicate whether dongle to support power save mode. + * @dongle_up : indicate whether dongle up or not. + * @roam_on : on/off switch for dongle self-roaming. + * @scan_tried : indicates if first scan attempted. + * @extra_buf : mainly to grab assoc information. + * @scan_buf : scan information for escan or iscan. + * @scan_info : escan information. + * @scan_timeout : Timer for catch scan timeout. + * @scan_report_work : scan report worker. + * @vif_list : linked list of vif instances. + * @vif_cnt : number of vif instances. + * @vif_event : vif event signalling. + */ +struct wland_cfg80211_info { + struct wiphy *wiphy; + struct wland_cfg80211_conf *conf; + struct wland_cfg80211_pmk_list *pmk_list; + struct wland_private *pub; +#ifdef WLAND_BTCOEX_SUPPORT + struct wland_btcoex_info *btcoex; +#endif /* WLAND_BTCOEX_SUPPORT */ + struct cfg80211_scan_request *scan_request; + struct wland_cfg80211_connect_info conn_info; + struct wland_cfg80211_scan_req scan_req_int; +#ifdef WLAND_P2P_SUPPORT + struct wland_p2p_info p2p; +#endif /* WLAND_P2P_SUPPORT */ + ulong scan_status; + u32 channel; + bool active_scan; + bool sched_escan; + bool ibss_starter; + bool pwr_save; + bool dongle_up; + bool roam_on; + bool scan_tried; + u8 *extra_buf; + struct escan_info scan_info; + struct timer_list scan_timeout; + struct work_struct scan_report_work; + struct list_head vif_list; + u8 vif_cnt; + struct wland_cfg80211_vif_event vif_event; + struct completion vif_disabled; + struct mutex usr_sync; + struct wland_d11inf d11inf; + bool in_disconnecting; + bool in_waiting; + struct completion disconnecting_wait; +#ifdef WLAND_INIT_SCAN_SUPPORT + atomic_t init_scan; +#endif + struct wland_scan_results scan_results; + struct mutex scan_result_lock; + struct list_head scan_result_list; +}; + +/* + * struct wland_tlv - tag_ID/length/value_buffer tuple. + * + * @id : tag identifier. + * @len : number of bytes in value buffer. + * @data: value buffer. + */ +struct wland_tlv { + u8 id; + u8 len; + u8 data[1]; +}; + +static inline struct wiphy *cfg_to_wiphy(struct wland_cfg80211_info *cfg) +{ + return cfg->wiphy; +} + +static inline struct wland_cfg80211_info *wiphy_to_cfg(struct wiphy *w) +{ + return (struct wland_cfg80211_info *) (wiphy_priv(w)); +} + +static inline struct wland_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd) +{ + return (struct wland_cfg80211_info *) (wdev_priv(wd)); +} + +static inline struct net_device *cfg_to_ndev(struct wland_cfg80211_info *cfg) +{ + struct wland_cfg80211_vif *vif = + list_first_entry(&cfg->vif_list, struct wland_cfg80211_vif, + list); + + return vif->wdev.netdev; +} + +static inline struct wland_cfg80211_info *ndev_to_cfg(struct net_device *ndev) +{ + return wdev_to_cfg(ndev->ieee80211_ptr); +} + +static inline struct wland_cfg80211_profile *ndev_to_prof(struct net_device *nd) +{ + struct wland_if *ifp = netdev_priv(nd); + + return &ifp->vif->profile; +} + +static inline struct wland_cfg80211_vif *ndev_to_vif(struct net_device *ndev) +{ + struct wland_if *ifp = netdev_priv(ndev); + + return ifp->vif; +} + +static inline struct wland_cfg80211_connect_info *cfg_to_conn(struct + wland_cfg80211_info *cfg) +{ + return &cfg->conn_info; +} + +/* cfg802.11 attach/detach interface function */ +extern struct wland_cfg80211_info *cfg80211_attach(struct wland_private *drvr, + struct device *busdev); +extern void cfg80211_detach(struct wland_cfg80211_info *cfg); + +/* process cfg802.11 up/down */ +extern s32 wland_cfg80211_up(struct net_device *ndev); +extern s32 wland_cfg80211_down(struct net_device *ndev); + +/* cfg802.11 vif manager interface function */ +extern struct wland_cfg80211_vif *wland_alloc_vif(struct wland_cfg80211_info + *cfg, enum nl80211_iftype type, bool pm_block); +extern void wland_free_vif(struct wland_cfg80211_info *cfg, + struct wland_cfg80211_vif *vif); + +extern struct wland_tlv *wland_parse_tlvs(void *buf, int buflen, uint key); +extern u16 channel_to_chanspec(struct wland_d11inf *d11inf, + struct ieee80211_channel *ch); + +extern void wland_cfg80211_arm_vif_event(struct wland_cfg80211_info *cfg, + struct wland_cfg80211_vif *vif); +extern bool wland_cfg80211_vif_event_armed(struct wland_cfg80211_info *cfg); +extern int wland_cfg80211_wait_vif_event_timeout(struct wland_cfg80211_info + *cfg, u8 action, ulong timeout); +extern s32 wland_notify_escan_complete(struct wland_cfg80211_info *cfg, + struct wland_if *ifp, bool aborted, bool fw_abort); +extern void wland_abort_scanning(struct wland_cfg80211_info *cfg); + +extern bool wland_vif_get_state_all(struct wland_cfg80211_info *cfg, + ulong state); +extern s32 wland_vif_clear_mgmt_ies(struct wland_cfg80211_vif *vif); +extern s32 wland_vif_set_mgmt_ie(struct wland_cfg80211_vif *vif, s32 pktflag, + const u8 * vndr_ie_buf, u32 vndr_ie_len); + +#ifdef WLAND_MONITOR_SUPPORT + +/* Monitor interface */ +extern int wland_monitor_init(void *pub); +extern int wland_monitor_deinit(void); +extern int wland_add_monitor(char *name, struct net_device **new_ndev); +extern int wland_del_monitor(struct net_device *ndev); +#endif /*WLAND_MONITOR_SUPPORT */ +#endif /* _WLAND_CFG80211_H_ */ diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_dbg.c b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_dbg.c new file mode 100755 index 0000000..2b5cd21 --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_dbg.c @@ -0,0 +1,354 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Error Debug Area Bit Map */ +int wland_dbg_area = WLAND_DATA_VAL | + WLAND_TRAP_VAL | + WLAND_DCMD_VAL | + WLAND_EVENT_VAL | + WLAND_BUS_VAL | + WLAND_WEXT_VAL | + WLAND_DEFAULT_VAL | WLAND_SDIO_VAL | WLAND_CFG80211_VAL; + +int wland_dbg_level = WLAND_INFO_LEVEL; +int wland_dump_area = + //WLAND_TX_CTRL_AREA | + //WLAND_TX_MSDU_AREA | + //WLAND_RX_WIDRSP_AREA | + //WLAND_RX_MACSTAT_AREA | + //WLAND_RX_NETINFO_AREA | + //WLAND_RX_MSDU_AREA | + //WLAND_RX_NETEVENT_AREA | + WLAND_NONE_AREA; + +/* Set Default Debug Dir */ +static struct dentry *root_folder = NULL; + +static ssize_t wland_debugfs_sdio_counter_read(struct file *f, + char __user * data, size_t count, loff_t * ppos) +{ + struct wland_sdio_count *sdcnt = f->private_data; + int buf_size = 750; + int res; + int ret; + char *buf; + + /* + * only allow read from start + */ + if (*ppos > 0) + return 0; + + buf = kmalloc(buf_size, GFP_KERNEL); + if (buf == NULL) { + WLAND_ERR("kmalloc buf failed\n"); + return -ENOMEM; + } + + + res = scnprintf(buf, buf_size, + "intrcount: %u\nlastintrs: %u\n" + "pollcnt: %u\nregfails: %u\n" + "tx_sderrs: %u\nfcqueued: %u\n" + "rxrtx: %u\nrx_toolong: %u\n" + "rxc_errors: %u\nrx_hdrfail: %u\n" + "rx_badhdr: %u\nrx_badseq: %u\n" + "fc_rcvd: %u\nfc_xoff: %u\n" + "fc_xon: %u\n " + "f2rxhdrs: %u\nf2rxdata: %u\n" + "f2txdata: %u\nf1regdata: %u\n" + "tickcnt: %u\ntx_ctlerrs: %lu\n" + "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n" + "rx_ctlpkts: %lu\nrx_readahead: %lu\n", + sdcnt->intrcount, sdcnt->lastintrs, + sdcnt->pollcnt, sdcnt->regfails, + sdcnt->tx_sderrs, sdcnt->fcqueued, + sdcnt->rxrtx, sdcnt->rx_toolong, + sdcnt->rxc_errors, sdcnt->rx_hdrfail, + sdcnt->rx_badhdr, sdcnt->rx_badseq, + sdcnt->fc_rcvd, sdcnt->fc_xoff, + sdcnt->fc_xon, + sdcnt->f2rxhdrs, sdcnt->f2rxdata, + sdcnt->f2txdata, sdcnt->f1regdata, + sdcnt->tickcnt, sdcnt->tx_ctlerrs, + sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs, + sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt); + + ret = simple_read_from_buffer(data, count, ppos, buf, res); + kfree(buf); + return ret; +} + +static const struct file_operations wland_debugfs_sdio_counter_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = wland_debugfs_sdio_counter_read +}; + +static ssize_t wland_debugarea_read(struct file *file, char __user * userbuf, + size_t count, loff_t * ppos) +{ + size_t pos = 0; + u32 addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + ssize_t res; + + WLAND_DBG(DEFAULT, TRACE, "get debug_area:0x%x\n", wland_dbg_area); + + pos += snprintf(buf + pos, PAGE_SIZE - pos, "%x\n", wland_dbg_area); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + + free_page(addr); + return res; +} + +static ssize_t wland_debugarea_write(struct file *file, + const char __user * user_buf, size_t count, loff_t * ppos) +{ + ssize_t ret; + int debug_area; + u32 addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + if (copy_from_user(buf, user_buf, count)) { + ret = -EFAULT; + goto out_unlock; + } + + ret = sscanf(buf, "%x", &debug_area); + if (ret != 1) { + ret = -EINVAL; + goto out_unlock; + } + + wland_dbg_area = debug_area; + + WLAND_DBG(DEFAULT, TRACE, "set debug_area = 0x%x\n", wland_dbg_area); + + ret = count; +out_unlock: + free_page(addr); + return ret; +} + +static const struct file_operations wland_dbgarea_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = wland_debugarea_read, + .write = wland_debugarea_write +}; + +static ssize_t wland_debuglevel_read(struct file *file, char __user * userbuf, + size_t count, loff_t * ppos) +{ + size_t pos = 0; + u32 addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + ssize_t res; + + WLAND_DBG(DEFAULT, TRACE, "get debug_level:%d\n", wland_dbg_level); + + pos += snprintf(buf + pos, PAGE_SIZE - pos, "%d\n", wland_dbg_level); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + + free_page(addr); + return res; +} + +static ssize_t wland_debuglevel_write(struct file *file, + const char __user * user_buf, size_t count, loff_t * ppos) +{ + ssize_t ret; + int debug_level; + u32 addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + if (copy_from_user(buf, user_buf, count)) { + ret = -EFAULT; + goto out_unlock; + } + + ret = sscanf(buf, "%d", &debug_level); + if (ret != 1) { + ret = -EINVAL; + goto out_unlock; + } + + wland_dbg_level = debug_level; + + WLAND_DBG(DEFAULT, TRACE, "set debug_level = %d\n", wland_dbg_level); + + ret = count; +out_unlock: + free_page(addr); + return ret; +} + +static const struct file_operations wland_dbglevel_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = wland_debuglevel_read, + .write = wland_debuglevel_write +}; + +#ifdef DEBUG +static ssize_t wland_sdio_forensic_read(struct file *f, char __user * data, + size_t count, loff_t * ppos) +{ + //wland_private *drvr = f->private_data; + int res = 0; + + //res = brcmf_sdio_trap_info(bus, &sh, data, count); + + if (res > 0) + *ppos += res; + return (ssize_t) res; +} + +static const struct file_operations sdio_forensic_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = wland_sdio_forensic_read +}; +#endif /* DEBUG */ + +void wland_sdio_debugfs_create(struct wland_private *drvr) +{ +#ifdef DEBUG + struct dentry *dentry = drvr->dbgfs_dir;; + + if (IS_ERR_OR_NULL(dentry)) + return; + + debugfs_create_file("forensics", S_IRUGO, dentry, drvr, + &sdio_forensic_ops); + + debugfs_create_file("counters", S_IRUGO, dentry, drvr, + &wland_debugfs_sdio_counter_ops); + + debugfs_create_file("dbglevel", S_IRUGO, dentry, drvr, + &wland_dbglevel_ops); + + debugfs_create_file("dbgarea", S_IRUGO, dentry, drvr, + &wland_dbgarea_ops); +#endif /* DEBUG */ +} + +char *wland_dbgarea(int dbg_flags) +{ + switch (dbg_flags) { + case WLAND_TRAP_VAL: + return "[RDAWLAN_TRAP]"; + case WLAND_EVENT_VAL: + return "[RDAWLAN_EVENT]"; + case WLAND_DCMD_VAL: + return "[RDAWLAN_DCMD]"; + case WLAND_WEXT_VAL: + return "[RDAWLAN_WEXT]"; + case WLAND_DEFAULT_VAL: + return "[RDAWLAN_DEFAULT]"; + case WLAND_SDIO_VAL: + return "[RDAWLAN_SDIO]"; + case WLAND_USB_VAL: + return "[RDAWLAN_USB]"; + case WLAND_CFG80211_VAL: + return "[RDAWLAN_CFG80211]"; + case WLAND_BUS_VAL: + return "[RDAWLAN_BUS]"; + case WLAND_DATA_VAL: + return "[RDAWLAN_DATA]"; + default: + return "[RDAWLAN_UNKNOW]"; + } +} + +/* dbg attach */ +int wland_debugfs_attach(struct wland_private *drvr) +{ + struct device *dev = drvr->bus_if->dev; + + WLAND_DBG(DEFAULT, TRACE, "Enter.\n"); + + if (!root_folder) + return -ENODEV; + + drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); + + if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) + return -ENODEV; + + WLAND_DBG(DEFAULT, TRACE, "Done.\n"); + + return 0; +} + +/* dbg dettach */ +void wland_debugfs_detach(struct wland_private *drvr) +{ + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) + debugfs_remove_recursive(drvr->dbgfs_dir); + + WLAND_DBG(DEFAULT, TRACE, "Done\n"); +} + +/* dbg dir init */ +void wland_debugfs_init(void) +{ + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(root_folder)) + root_folder = NULL; + WLAND_DBG(DEFAULT, TRACE, "Done\n"); +} + +/* dbg dir exit */ +void wland_debugfs_exit(void) +{ + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + if (!root_folder) + return; + + debugfs_remove_recursive(root_folder); + + root_folder = NULL; + WLAND_DBG(DEFAULT, TRACE, "Done\n"); +} diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_dbg.h b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_dbg.h new file mode 100755 index 0000000..cf75f57 --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_dbg.h @@ -0,0 +1,171 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAND_DBG_H_ +#define _WLAND_DBG_H_ + +enum { + WLAND_ERROR_LEVEL = 0, + WLAND_WARNING_LEVEL = 1, + WLAND_NOTICE_LEVEL = 2, + WLAND_INFO_LEVEL = 3, + WLAND_DEBUG_LEVEL = 4, + WLAND_TRACE_LEVEL = 5, +}; + +#define WLAND_TRAP_VAL BIT0 +#define WLAND_EVENT_VAL BIT1 +#define WLAND_DCMD_VAL BIT2 +#define WLAND_WEXT_VAL BIT3 +#define WLAND_DEFAULT_VAL BIT4 +#define WLAND_SDIO_VAL BIT5 +#define WLAND_USB_VAL BIT6 +#define WLAND_CFG80211_VAL BIT7 +#define WLAND_BUS_VAL BIT8 +#define WLAND_DATA_VAL BIT9 +#define WLAND_UNMASK_VAL ((int)(0xFFFF)) + +#define WLAND_TX_CTRL_AREA BIT0 +#define WLAND_TX_MSDU_AREA BIT1 +#define WLAND_RX_WIDRSP_AREA BIT2 +#define WLAND_RX_MACSTAT_AREA BIT3 +#define WLAND_RX_NETINFO_AREA BIT4 +#define WLAND_RX_MSDU_AREA BIT5 +#define WLAND_RX_NETEVENT_AREA BIT6 +#define WLAND_ALL_AREA (0xFFFFFFFF) +#define WLAND_NONE_AREA (0) + +#define TX_CTRL (wland_dump_area & WLAND_TX_CTRL_AREA) +#define TX_MSDU (wland_dump_area & WLAND_TX_MSDU_AREA) +#define RX_WIDRSP (wland_dump_area & WLAND_RX_WIDRSP_AREA) +#define RX_MACSTAT (wland_dump_area & WLAND_RX_MACSTAT_AREA) +#define RX_NETINFO (wland_dump_area & WLAND_RX_NETINFO_AREA) +#define RX_NETEVENT (wland_dump_area & WLAND_RX_NETEVENT_AREA) +#define RX_MSDU (wland_dump_area & WLAND_RX_MSDU_AREA) + +#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] + +/* Macro for error messages. net_ratelimit() is used when driver + * debugging is not selected. When debugging the driver error + * messages are as important as other tracing or even more so. + */ +#ifdef DEBUG +#define WLAND_ERR(fmt, ...) pr_err("[RDAWLAN_ERR]:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#else /* defined(DEBUG) */ +#define WLAND_ERR(fmt, ...) do {\ + if (net_ratelimit()){\ + pr_err("[RDAWLAN_ERR]:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__);\ + } \ + } while (0) +#endif /* defined(DEBUG) */ + +#ifdef DEBUG +#define WLAND_DBG(area, level, fmt, ...) do {\ + int dgb_area = WLAND_##area##_VAL & wland_dbg_area;\ + int dbg_level = WLAND_##level##_LEVEL;\ + if(dgb_area && (dbg_level <= wland_dbg_level)){\ + pr_err("%s:<%s,%d> " fmt, wland_dbgarea(dgb_area), __func__, __LINE__, ##__VA_ARGS__);\ + } \ + } while (0) +#else /* defined(DEBUG) */ +#define WLAND_DBG(area, level, fmt, ...) no_printk(fmt, ##__VA_ARGS__) +#endif /* defined(DEBUG) */ + +#define WLAND_DUMP(area, data, len, fmt, ...)\ + do {\ + if (area){\ + pr_err("[RDAWLAN_DUMP]:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__);\ + wland_dbg_hex_dump(area, data, len, fmt, ##__VA_ARGS__);\ + }\ + } while (0) + +/* hold counter variables used in wlanfmac sdio driver. */ +struct wland_sdio_count { + uint intrcount; /* Count of device interrupt callbacks */ + uint lastintrs; /* Count as of last watchdog timer */ + uint pollcnt; /* Count of active polls */ + uint regfails; /* Count of R_REG failures */ + uint tx_sderrs; /* Count of tx attempts with sd errors */ + uint fcqueued; /* Tx packets that got queued */ + uint rxrtx; /* Count of rtx requests (NAK to dongle) */ + uint rx_toolong; /* Receive frames too long to receive */ + uint rxc_errors; /* SDIO errors when reading control frames */ + uint rx_hdrfail; /* SDIO errors on header reads */ + uint rx_badhdr; /* Bad received headers (roosync?) */ + uint rx_badseq; /* Mismatched rx sequence number */ + uint fc_rcvd; /* Number of flow-control events received */ + uint fc_xoff; /* Number which turned on flow-control */ + uint fc_xon; /* Number which turned off flow-control */ + uint f2rxhdrs; /* Number of header reads */ + uint f2rxdata; /* Number of frame data reads */ + uint f2txdata; /* Number of f2 frame writes */ + uint f1regdata; /* Number of f1 register accesses */ + uint tickcnt; /* Number of watchdog been schedule */ + ulong tx_ctlerrs; /* Err of sending ctrl frames */ + ulong tx_ctlpkts; /* Ctrl frames sent to dongle */ + ulong rx_ctlerrs; /* Err of processing rx ctrl frames */ + ulong rx_ctlpkts; /* Ctrl frames processed from dongle */ + ulong rx_readahead_cnt; /* packets where header read-ahead was used */ +}; + +struct wland_fws_stats { + u32 tlv_parse_failed; + u32 tlv_invalid_type; + u32 header_only_pkt; + u32 header_pulls; + u32 pkt2bus; + u32 send_pkts[5]; + u32 requested_sent[5]; + u32 generic_error; + u32 mac_update_failed; + u32 mac_ps_update_failed; + u32 if_update_failed; + u32 packet_request_failed; + u32 credit_request_failed; + u32 rollback_success; + u32 rollback_failed; + u32 delayq_full_error; + u32 supprq_full_error; + u32 txs_indicate; + u32 txs_discard; + u32 txs_supp_core; + u32 txs_supp_ps; + u32 txs_tossed; + u32 txs_host_tossed; + u32 bus_flow_block; + u32 fws_flow_block; +}; + +struct wland_sdio; +struct wland_private; + +extern int wland_dbg_area; +extern int wland_dbg_level; +extern int wland_dump_area; + +extern char *wland_dbgarea(int dbg_flags); + +/* setup bug info dir */ +extern void wland_debugfs_init(void); +extern void wland_debugfs_exit(void); + +extern void wland_sdio_debugfs_create(struct wland_private *drvr); +extern int wland_debugfs_attach(struct wland_private *drvr); +extern void wland_debugfs_detach(struct wland_private *drvr); + +#endif /* _WLAND_DBG_H_ */ diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_defs.h b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_defs.h index cd6da05..5fbe33c 100755 --- a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_defs.h +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_defs.h @@ -25,7 +25,7 @@ ****************************************************************************/ /* init_scan support */ -#define WLAND_INIT_SCAN_SUPPORT +//#define WLAND_INIT_SCAN_SUPPORT /* Driver Version Sync With Source Server */ #define WLAND_VER_MAJ 5 @@ -195,6 +195,7 @@ enum WLAND_CHIP_VERSION { /* define support cfg80211 or wext mode */ #define WLAND_CFG80211_SUPPORT +//#define WLAND_WEXT_SUPPORT /* define support wapi sec mode */ //#define WLAND_WAPI_SUPPORT diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_iw.c b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_iw.c new file mode 100755 index 0000000..03a09fd --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_iw.c @@ -0,0 +1,1824 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef WLAND_WEXT_SUPPORT + +#include +#include +#include +#include + +#include + +/** + * 802.11b/g supported bitrates (in 500Kb/s units) + */ +static const u8 wlan_bg_rates[MAX_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6c, 0x00, 0x00 +}; + +static const u16 wlan_nr_chan = 11; + +static int iwext_get_name(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *cwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + /* + * We could add support for 802.11n here as needed. Jean II + */ + snprintf(cwrq, IFNAMSIZ, "IEEE 802.11bgn"); + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +static int iwext_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + fwrq->m = (long) 2437 *100000; + + fwrq->e = 1; + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +static int iwext_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + if (priv->connect_status == MAC_CONNECTED) { + memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN); + } else { + memset(awrq->sa_data, 0, ETH_ALEN); + } + awrq->sa_family = ARPHRD_ETHER; + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +static int iwext_set_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_get_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 600; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + vwrq->value = val; + vwrq->disabled = val > WLAN_RTS_MAX_VALUE; /* min rts value is 0 */ + vwrq->fixed = 1; + + return ret; +} + +static int iwext_set_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_get_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 1460; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + vwrq->value = val; + vwrq->disabled = ((val < WLAN_FRAG_MIN_VALUE) + || (val > WLAN_FRAG_MAX_VALUE)); + vwrq->fixed = 1; + + return ret; +} + +static int iwext_get_mode(struct net_device *dev, struct iw_request_info *info, + u32 * uwrq, char *extra) +{ + *uwrq = IW_MODE_INFRA; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_get_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + vwrq->value = 20; // in dbm + vwrq->fixed = 1; + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_set_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_get_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 0; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + vwrq->disabled = 0; + + if (vwrq->flags & IW_RETRY_LONG) { + val = 7; + + /* + * Subtract 1 to convert try count to retry count + */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + } else { + val = 6; + + /* + * Subtract 1 to convert try count to retry count + */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; + } + + return ret; +} + +/** + * @brief Get Range Info + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int iwext_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + int i; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->min_nwid = 0; + range->max_nwid = 0; + + range->num_bitrates = sizeof(wlan_bg_rates); + for (i = 0; i < range->num_bitrates; i++) + range->bitrate[i] = wlan_bg_rates[i] * 500000; + range->num_bitrates = i; + + range->num_frequency = 0; + + range->scan_capa = IW_SCAN_CAPA_ESSID; + + for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (i < wlan_nr_chan); i++) { + range->freq[range->num_frequency].i = (long) (i + 1); + range->freq[range->num_frequency].m = + (long) ((2412 + 5 * i) * 100000); + range->freq[range->num_frequency].e = 1; + range->num_frequency++; + } + + range->num_channels = range->num_frequency; + + /* + * Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface + */ + range->throughput = 5000 * 1000; + + range->min_rts = WLAN_RTS_MIN_VALUE; + range->max_rts = WLAN_RTS_MAX_VALUE; + range->min_frag = WLAN_FRAG_MIN_VALUE; + range->max_frag = WLAN_FRAG_MAX_VALUE; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + /* + * Right now we support only "iwconfig ethX power on|off" + */ + range->pm_capa = IW_POWER_ON; + + /* + * Minimum version we recommend + */ + range->we_version_source = 15; + + /* + * Version we are compiled with + */ + range->we_version_compiled = WIRELESS_EXT; //it should be canlced + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + + range->min_retry = 0; + range->max_retry = 14; + + /* + * Set the qual, level and noise range values + */ + range->max_qual.qual = 100; + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->avg_qual.qual = 70; + /* + * TODO: Find real 'good' to 'bad' threshold value for RSSI + */ + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + range->sensitivity = 0; + + /* + * Setup the supported power level ranges + */ + memset(range->txpower, 0, sizeof(range->txpower)); + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + range->txpower[0] = 0; + range->txpower[1] = 20; + range->num_txpower = 2; + + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + range->enc_capa = IW_ENC_CAPA_WPA + | IW_ENC_CAPA_WPA2 + | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +static int iwext_set_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_get_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + vwrq->value = 0; + vwrq->flags = 0; + vwrq->disabled = 0; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int wlan_update_bss_stats(wlan_private * priv) +{ + int ret = 0; + + memcpy(priv->curbssparams.ssid, priv->assoc_ssid, + sizeof(priv->curbssparams.ssid)); + + if (priv->scan_running == WLAN_SCAN_RUNNING) + return ret; + + ret = wland_fil_get_cmd_data(priv, WID_RSSI, &priv->curbssparams.rssi, + sizeof(u8)); + if (ret < 0) + WLAND_ERR("get_rssi, ret = %d\n", ret); + + WLAND_DBG(WEXT, TRACE, "<<< ch = %d rssi = %d\n", + priv->curbssparams.channel, priv->curbssparams.rssi); + + return ret; +} + +struct iw_statistics *wland_get_wireless_stats(struct net_device *dev) +{ + struct wlan_private *priv = (struct wlan_private *) netdev_priv(dev); + int stats_valid = 0; + u8 snr; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + if (priv->connect_status != MAC_CONNECTED) + goto out; + + wlan_update_bss_stats(priv); + + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.level = + priv->curbssparams.rssi > + 127 ? priv->curbssparams.rssi - 271 : priv->curbssparams.rssi - + 15; + + snr = priv->wstats.qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + priv->wstats.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - + snr))) / (RSSI_DIFF * RSSI_DIFF); + + if (priv->wstats.qual.qual > 100) + priv->wstats.qual.qual = 100; + + priv->wstats.qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + stats_valid = 1; + +out: + if (!stats_valid) { + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; + priv->wstats.qual.updated |= + IW_QUAL_NOISE_INVALID | IW_QUAL_QUAL_INVALID | + IW_QUAL_LEVEL_INVALID; + } + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return &priv->wstats; +} + +static int iwext_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_set_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_get_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + vwrq->fixed = 0; + vwrq->value = 108 * 500000; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_set_mode(struct net_device *dev, struct iw_request_info *info, + u32 * uwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +/* + * @brief Get Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int iwext_get_encode(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, u8 * extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +/* + * @brief Set Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int iwext_set_encode(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +/* + * @brief Set Encryption key (internal) + * + * @param priv A pointer to private card structure + * @param key_material A pointer to key material + * @param key_length length of key material + * @param index key index to set + * @param set_tx_key Force set TX key (1 = yes, 0 = no) + * @return 0 --success, otherwise fail + */ +static int copy_wep_key(wlan_private * priv, const char *key_material, + u16 key_length, u16 index, int set_tx_key) +{ + int ret = 0; + struct enc_key *pkey; + + /* + * Paranoid validation of key index + */ + if (index > 3) { + ret = -EINVAL; + goto out; + } + + /* + * validate max key length + */ + if (key_length > KEY_LEN_WEP_104) { + ret = -EINVAL; + goto out; + } + + if (key_length == KEY_LEN_WEP_40) { + WLAND_DBG(WEXT, TRACE, "WEP40 : %02x%02x%02x%02x%02x\n", + key_material[0], key_material[1], key_material[2], + key_material[3], key_material[4]); + } else if (key_length == KEY_LEN_WEP_104) { + WLAND_DBG(WEXT, TRACE, "WEP104 : %02x%02x%02x%02x%02x" + " %02x%02x%02x%02x%02x" + " %02x%02x%02x\n", + key_material[0], key_material[1], key_material[2], + key_material[3], key_material[4], key_material[5], + key_material[6], key_material[7], key_material[8], + key_material[9], key_material[10], key_material[11], + key_material[12]); + } else { + WLAND_ERR("Error in WEP Key length %d\n", key_length); + } + + pkey = &priv->wep_keys[index]; + + if (key_length > 0) { + memset(pkey, 0, sizeof(struct enc_key)); + pkey->type = KEY_TYPE_ID_WEP; + + /* + * Standardize the key length + */ + pkey->len = + (key_length > + KEY_LEN_WEP_40) ? KEY_LEN_WEP_104 : KEY_LEN_WEP_40; + memcpy(pkey->key, key_material, key_length); + } + + if (set_tx_key) { + /* + * Ensure the chosen key is valid + */ + if (!pkey->len) { + WLAND_ERR("key not set, so cannot enable it\n"); + ret = -EINVAL; + goto out; + } + priv->wep_tx_keyidx = index; + } + + priv->secinfo.wep_enabled = 1; + +out: + return ret; +} + +static int validate_key_index(u16 def_index, u16 raw_index, u16 * out_index, + u16 * is_default) +{ + if (!out_index || !is_default) + return -EINVAL; + + /* + * Verify index if present, otherwise use default TX key index + */ + if (raw_index > 0) { + if (raw_index > 4) + return -EINVAL; + *out_index = raw_index - 1; + } else { + *out_index = def_index; + *is_default = 1; + } + return 0; +} + +void disable_wep(wlan_private * priv) +{ + int i; + + /* + * Set Open System auth mode + */ + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + /* + * Clear WEP keys and mark WEP as disabled + */ + priv->secinfo.wep_enabled = 0; + + for (i = 0; i < 4; i++) + priv->wep_keys[i].len = 0; +} + +void disable_wpa(wlan_private * priv) +{ + memset(&priv->wpa_mcast_key, 0, sizeof(struct enc_key)); + priv->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST; + + memset(&priv->wpa_unicast_key, 0, sizeof(struct enc_key)); + priv->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST; + + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + priv->secinfo.cipther_type = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; +} + +/** + * @brief Get Extended Encryption key (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 on success, otherwise failure + */ +static int iwext_get_encodeext(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = -EINVAL; + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + int index, max_key_len; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + max_key_len = dwrq->length - sizeof(*ext); + if (max_key_len < 0) + goto out; + + index = dwrq->flags & IW_ENCODE_INDEX; + if (index) { + if (index < 1 || index > 4) + goto out; + index--; + } else { + index = priv->wep_tx_keyidx; + } + + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + && ext->alg != IW_ENCODE_ALG_WEP) { + if (index != 0) + goto out; + } + + dwrq->flags = index + 1; + memset(ext, 0, sizeof(*ext)); + + if (!priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled && !priv->secinfo.WPA2enabled) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + dwrq->flags |= IW_ENCODE_DISABLED; + } else { + u8 *key = NULL; + + if (priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { + /* + * WEP + */ + ext->alg = IW_ENCODE_ALG_WEP; + ext->key_len = priv->wep_keys[index].len; + key = &priv->wep_keys[index].key[0]; + } else if (!priv->secinfo.wep_enabled + && (priv->secinfo.WPAenabled + || priv->secinfo.WPA2enabled)) { + /* + * WPA + */ + struct enc_key *pkey = NULL; + + if (priv->wpa_mcast_key.len + && (priv->wpa_mcast_key.flags & + KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_mcast_key; + else if (priv->wpa_unicast_key.len + && (priv->wpa_unicast_key.flags & + KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_unicast_key; + + if (pkey) { + if (pkey->type == KEY_TYPE_ID_AES) { + ext->alg = IW_ENCODE_ALG_CCMP; + } else { + ext->alg = IW_ENCODE_ALG_TKIP; + } + ext->key_len = pkey->len; + key = &pkey->key[0]; + } else { + ext->alg = IW_ENCODE_ALG_TKIP; + ext->key_len = 0; + } + } else { + goto out; + } + + if (ext->key_len > max_key_len) { + ret = -E2BIG; + goto out; + } + + if (ext->key_len) + memcpy(ext->key, key, ext->key_len); + else + dwrq->flags |= IW_ENCODE_NOKEY; + dwrq->flags |= IW_ENCODE_ENABLED; + } + ret = 0; + +out: + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +/** + * @brief Set Encryption key Extended (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int iwext_set_encodeext(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + int alg = ext->alg; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { + WLAND_DBG(WEXT, TRACE, "NO SEC\n"); + + if (priv->imode != 3 && priv->imode != 5) + disable_wep(priv); + disable_wpa(priv); + } else if (alg == IW_ENCODE_ALG_WEP) { + u16 is_default = 0, index, set_tx_key = 0; + + WLAND_DBG(WEXT, TRACE, "WEP, flags = 0x%04x\n", dwrq->flags); + + ret = validate_key_index(priv->wep_tx_keyidx, + (dwrq->flags & IW_ENCODE_INDEX), &index, &is_default); + if (ret) + goto out; + + /* + * If WEP isn't enabled, or if there is no key data but a valid + * * index, or if the set-TX-key flag was passed, set the TX key. + */ + if (!priv->secinfo.wep_enabled + || (dwrq->length == 0 && !is_default) + || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) + set_tx_key = 1; + + /* + * Copy key to driver + */ + ret = copy_wep_key(priv, ext->key, ext->key_len, index, + set_tx_key); + if (ret) + goto out; + + if (dwrq->flags & IW_ENCODE_RESTRICTED) { + priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; + } else if (dwrq->flags & IW_ENCODE_OPEN) { + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { + struct enc_key *pkey; + + WLAND_DBG(WEXT, TRACE, + "TKIP or CCMP, flags = 0x%04x, alg = %d\n", dwrq->flags, + alg); + + /* + * validate key length + */ + if (((alg == IW_ENCODE_ALG_TKIP) + && (ext->key_len != KEY_LEN_WPA_TKIP)) + || ((alg == IW_ENCODE_ALG_CCMP) + && (ext->key_len != KEY_LEN_WPA_AES))) { + WLAND_ERR("invalid size %d for key of alg, type %d\n", + ext->key_len, alg); + ret = -EINVAL; + goto out; + } + + /* + * Copy key to driver + */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + pkey = &priv->wpa_mcast_key; + } else { + pkey = &priv->wpa_unicast_key; + } + + memset(pkey, 0, sizeof(struct enc_key)); + memcpy(pkey->key, ext->key, ext->key_len); + pkey->len = ext->key_len; + if (pkey->len) + pkey->flags |= KEY_INFO_WPA_ENABLED; + + /* + * Do this after zeroing key structure + */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + pkey->flags |= KEY_INFO_WPA_MCAST; + } else { + pkey->flags |= KEY_INFO_WPA_UNICAST; + } + + if (alg == IW_ENCODE_ALG_TKIP) { + pkey->type = KEY_TYPE_ID_TKIP; + + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + && !(priv->imode & (BIT6))) { + WLAND_ERR + ("imode [0x%x] not match with cipher alg TKIP\n", + priv->imode); + } + } else if (alg == IW_ENCODE_ALG_CCMP) { + pkey->type = KEY_TYPE_ID_AES; + + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + && !(priv->imode & (BIT5))) { + WLAND_ERR + ("imode [0x%x] not match with cipher alg CCMP\n", + priv->imode); + } + } + + /* + * If WPA isn't enabled yet, do that now + */ + if (priv->secinfo.WPAenabled == 0 + && priv->secinfo.WPA2enabled == 0) { + priv->secinfo.WPAenabled = 1; + priv->secinfo.WPA2enabled = 1; + } + + /* + * Set Keys to MAC + */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* + * Set GTK + */ + ret = wland_set_gtk(priv, + (dwrq->flags & IW_ENCODE_INDEX) - 1, + ext->tx_seq, IW_ENCODE_SEQ_MAX_SIZE, pkey->key, + pkey->len); + if (ret) + goto out; + } else { + pkey->flags |= KEY_INFO_WPA_UNICAST; + /* + * Set PTK + */ + ret = wland_set_ptk(priv, pkey->key, pkey->len); + if (ret) + goto out; + } + + /* + * Only disable wep if necessary: can't waste time here. + */ + disable_wep(priv); + } else if (alg == IW_ENCODE_ALG_SM4) { //wapi + if (ext->key_len != 32) + goto out; + + priv->is_wapi = 1; + + /* + * Set Keys to MAC + */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + u8 tmp[8]; + + /* + * Set GTK + */ + ret = wland_set_gtk(priv, + (dwrq->flags & IW_ENCODE_INDEX) - 1, tmp, + IW_ENCODE_SEQ_MAX_SIZE, ext->key, ext->key_len); + if (ret) + goto out; + } else { + /* + * Set PTK + */ + ret = wland_set_ptk(priv, ext->key, ext->key_len); + if (ret) + goto out; + } + } + +out: + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +/* + * @brief PMKSA cache operation (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 on success, otherwise failure + */ +static int iwext_set_pmksa(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_set_genie(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + if (extra[0] == 0x44) { //wapi ie + u8 ie_len = extra[1] + 2; + wland_fil_set_cmd_data(priv, WID_WAPI_ASSOC_IE, extra, ie_len); + goto out; + } + + if (dwrq->length > MAX_WPA_IE_LEN || (dwrq->length && extra == NULL)) { + ret = -EINVAL; + goto out; + } + + if (dwrq->length) { + memcpy(&priv->wpa_ie[0], extra, dwrq->length); + priv->wpa_ie_len = dwrq->length; + } else { + memset(&priv->wpa_ie[0], 0, sizeof(priv->wpa_ie)); + priv->wpa_ie_len = 0; + } +out: + WLAND_DBG(WEXT, TRACE, "Done\n"); + return ret; +} + +static int iwext_get_genie(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + if (priv->wpa_ie_len == 0) { + dwrq->length = 0; + goto out; + } + + if (dwrq->length < priv->wpa_ie_len) { + ret = -E2BIG; + goto out; + } + + dwrq->length = priv->wpa_ie_len; + + memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len); +out: + WLAND_DBG(WEXT, TRACE, "Done\n"); + return ret; +} + +static int iwext_set_auth(struct net_device *dev, struct iw_request_info *info, + struct iw_param *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAND_DBG(WEXT, TRACE, "flags = 0x%04x, value = 0x%x\n", dwrq->flags, + dwrq->value); + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + if (dwrq->value & (IW_AUTH_CIPHER_WEP104 | + IW_AUTH_CIPHER_WEP40)) { + WLAND_DBG(WEXT, TRACE, "WEP Selected \n"); + priv->secinfo.wep_enabled = 1; + if (dwrq->value & IW_AUTH_CIPHER_WEP104) + priv->secinfo.cipther_type |= + IW_AUTH_CIPHER_WEP104; + else if (dwrq->value & IW_AUTH_CIPHER_WEP40) + priv->secinfo.cipther_type |= + IW_AUTH_CIPHER_WEP40; + } + if (dwrq->value & IW_AUTH_CIPHER_TKIP) { + WLAND_DBG(WEXT, TRACE, "IW_AUTH_CIPHER_TKIP \n"); + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_TKIP; + } + if (dwrq->value & IW_AUTH_CIPHER_CCMP) { + WLAND_DBG(WEXT, TRACE, "IW_AUTH_CIPHER_CCMP \n"); + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_CCMP; + } + if (dwrq->value & IW_AUTH_CIPHER_NONE) { + WLAND_DBG(WEXT, TRACE, "OPEN System \n"); + priv->secinfo.cipther_type = IW_AUTH_CIPHER_NONE; + } + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_DROP_UNENCRYPTED: + /* + * wlan does not use these parameters + */ + WLAND_DBG(WEXT, TRACE, "DO NOT USE\n"); + break; + + case IW_AUTH_KEY_MGMT: + WLAND_DBG(WEXT, TRACE, "KEY_MGMT, val = %d\n", dwrq->value); + priv->secinfo.key_mgmt = dwrq->value; + break; + + case IW_AUTH_WPA_VERSION: + if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { + WLAND_DBG(WEXT, TRACE, "WPA_VERSION, DISABLED\n"); + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + disable_wpa(priv); + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { + WLAND_DBG(WEXT, TRACE, "WPA_VERSION, WPA\n"); + priv->secinfo.WPAenabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { + WLAND_DBG(WEXT, TRACE, "WPA_VERSION, WPA2\n"); + priv->secinfo.WPA2enabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + if (dwrq->value & IW_AUTH_ALG_SHARED_KEY + || dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { + if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { + WLAND_DBG(WEXT, TRACE, + "80211_AUTH_ALG, SHARED_KEY\n"); + priv->secinfo.auth_mode |= + IW_AUTH_ALG_SHARED_KEY; + } + if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { + WLAND_DBG(WEXT, TRACE, + "80211_AUTH_ALG, OPEN\n"); + priv->secinfo.auth_mode |= + IW_AUTH_ALG_OPEN_SYSTEM; + } + } else if (dwrq->value & IW_AUTH_ALG_LEAP) { + WLAND_DBG(WEXT, TRACE, "80211_AUTH_ALG, LEAP\n"); + priv->secinfo.auth_mode = IW_AUTH_ALG_LEAP; + } else if (dwrq->value & IW_AUTH_ALG_WAPI) { + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } else { + WLAND_DBG(WEXT, TRACE, "80211_AUTH_ALG, unknown\n"); + ret = -EINVAL; + } + break; + + case IW_AUTH_WPA_ENABLED: + if (dwrq->value) { + WLAND_DBG(WEXT, TRACE, "WPA_ENABLED, value = 0x%x\n", + dwrq->value); + if (!priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { + priv->secinfo.WPAenabled = 1; + priv->secinfo.WPA2enabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = + IW_AUTH_ALG_OPEN_SYSTEM; + } + } else { + WLAND_DBG(WEXT, TRACE, "WPA_ENABLED, value = ZERO\n"); + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + disable_wpa(priv); + } + break; + + case IW_AUTH_WAPI_ENABLED: + if (dwrq->value & BIT1) { + disable_wpa(priv); + disable_wep(priv); + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } else if (dwrq->value & BIT2) { + disable_wpa(priv); + disable_wep(priv); + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } + break; + + default: + WLAND_DBG(WEXT, TRACE, "NOT SUPPORT\n"); + ret = -EOPNOTSUPP; + break; + } + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return ret; +} + +static int iwext_get_auth(struct net_device *dev, struct iw_request_info *info, + struct iw_param *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + dwrq->value = priv->secinfo.key_mgmt; + break; + + case IW_AUTH_WPA_VERSION: + dwrq->value = 0; + if (priv->secinfo.WPAenabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA; + if (priv->secinfo.WPA2enabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; + if (!dwrq->value) + dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; + break; + + case IW_AUTH_80211_AUTH_ALG: + dwrq->value = priv->secinfo.auth_mode; + break; + + case IW_AUTH_WPA_ENABLED: + if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled) + dwrq->value = 1; + break; + + default: + ret = -EOPNOTSUPP; + } + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return ret; +} + +static int iwext_set_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +static int iwext_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + memcpy(extra, priv->curbssparams.ssid, strlen(priv->curbssparams.ssid)); + dwrq->length = strlen(priv->curbssparams.ssid); + extra[dwrq->length] = '\0'; + + /* + * If none, we may want to get the one that was set + */ + dwrq->flags = 1; /* active */ + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + return 0; +} + +struct bss_descriptor *get_bss_desc_from_scanlist(wlan_private * priv, + u8 * bssid) +{ + struct bss_descriptor *iter_bss; + struct bss_descriptor *ret_bss = NULL; + + spin_lock(&priv->ScanListLock); + /* + * report all bss to upper layer + */ + list_for_each_entry(iter_bss, &priv->network_list, list) { + if (memcmp(iter_bss->bssid, bssid, 6) == 0) { + ret_bss = iter_bss; + break; + } + } + spin_unlock(&priv->ScanListLock); + return ret_bss; +} + +struct bss_descriptor *get_bss_desc_from_scanlist_ssid(wlan_private * priv, + u8 * ssid) +{ + struct bss_descriptor *iter_bss; + struct bss_descriptor *ret_bss = NULL; + + spin_lock(&priv->ScanListLock); + /* + * report all bss to upper layer + */ + list_for_each_entry(iter_bss, &priv->network_list, list) { + if (memcmp(iter_bss->ssid, ssid, iter_bss->ssid_len) == 0) { + ret_bss = iter_bss; + break; + } + } + spin_unlock(&priv->ScanListLock); + return ret_bss; +} + +static int iwext_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + u8 ssid[IW_ESSID_MAX_SIZE + 1], ssid_len = 0; + int in_ssid_len = dwrq->length; + + /* + * Check the size of the string + */ + if (in_ssid_len > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + goto out; + } + + memset(&ssid, 0, sizeof(ssid)); + + if (!dwrq->flags || !in_ssid_len) { + /* + * "any" SSID requested; leave SSID blank + */ + } else { + /* + * Specific SSID requested + */ + memcpy(&ssid, extra, in_ssid_len); + ssid[in_ssid_len] = '\0'; + ssid_len = in_ssid_len; + } + + WLAND_DBG(WEXT, TRACE, "requested SSID len = %d ssid:%s\n", ssid_len, + ssid); + + if (ssid_len) { + memcpy(&priv->assoc_ssid[0], ssid, sizeof(ssid)); + priv->assoc_ssid_len = ssid_len; + } +out: + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +u8 is_zero_eth_addr(u8 * addr) +{ + return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); +} + +/* + * @brief Connect to the AP or Ad-hoc Network with specific bssid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int iwext_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + u8 *ap_addr = NULL; + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + ap_addr = awrq->sa_data; + + if (!is_zero_eth_addr(ap_addr)) { + if (memcmp(priv->assoc_bssid, ap_addr, 6)) { + memcpy(priv->assoc_bssid, ap_addr, 6); + priv->ToggalAssociation = false; + + if (!priv->ReAssociationTimeOut.timer_is_canceled) + wland_del_timer(&priv->ReAssociationTimeOut); + if (priv->StartAssociationTimeOut.timer_is_canceled) + wland_mod_timer(&priv->StartAssociationTimeOut, + 100); + } else { + if (priv->ReAssociationTimeOut.timer_is_canceled) + wland_mod_timer(&priv->StartAssociationTimeOut, + 100); + } + priv->assoc_ongoing = true; + } else { + memcpy(priv->assoc_bssid, ap_addr, 6); + + wland_del_timer(&priv->ReAssociationTimeOut); + wland_del_timer(&priv->StartAssociationTimeOut); + + disable_wep(priv); + disable_wpa(priv); + } + + WLAND_DBG(WEXT, TRACE, "connect mac: " MACDBG "\n", + MAC2STRDBG(ap_addr)); + + return 0; +} + +static char *translate_scan(wlan_private * priv, + struct iw_request_info *info, + char *start, char *stop, struct bss_descriptor *bss_desc) +{ + + struct iw_event iwe; /* Temporary buffer */ + u8 snr; + struct bss_descriptor *bss = bss_desc; + + WLAND_DBG(WEXT, TRACE, + "translate_scan, ssid = %s ssi=%d ssid_len=%d \n", bss->ssid, + bss->rssi, bss->ssid_len); + + /* + * First entry *MUST* be the BSSID + */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); + + /* + * SSID + */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = bss->ssid_len; + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); + + /* + * Mode + */ + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = bss->mode; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); + + /* + * Frequency + */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = (2412 + 5 * (bss->channel - 1)) * 100000; + iwe.u.freq.e = 1; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); + + /* + * Add quality statistics + */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; + iwe.u.qual.level = bss->rssi > 127 ? bss->rssi - 271 : bss->rssi - 15; + + snr = iwe.u.qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + iwe.u.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - snr))) / + (RSSI_DIFF * RSSI_DIFF); + if (iwe.u.qual.qual > 100) + iwe.u.qual.qual = 100; + iwe.u.qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); + + /* + * Add encryption capability + */ + iwe.cmd = SIOCGIWENCODE; + if (bss->capability & 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; + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); + + memset(&iwe, 0, sizeof(iwe)); + if (bss_desc->wpa_ie_len && !bss_desc->wapi_ie_len) { + char *buf = kmalloc(MAX_WPA_IE_LEN, GFP_ATOMIC); + if(buf == NULL) { + WLAND_ERR("kmalloc buf failed\n"); + return -ENOMEM; + } + WLAND_DBG(WEXT, TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->wpa_ie[0], bss_desc->wpa_ie[1], + bss_desc->wpa_ie[2], bss_desc->wpa_ie[3], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 4], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 3], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 2], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 1]); + + memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->wpa_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + kfree(buf); + } + + memset(&iwe, 0, sizeof(iwe)); + + if (bss_desc->rsn_ie_len) { + char *buf = kmalloc(MAX_WPA_IE_LEN, GFP_ATOMIC); + if(buf == NULL) { + WLAND_ERR("kmalloc buf failed\n"); + return -ENOMEM; + } + + WLAND_DBG(WEXT, TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->rsn_ie[0], bss_desc->rsn_ie[1], + bss_desc->rsn_ie[2], bss_desc->rsn_ie[3], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 4], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 3], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 2], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 1]); + + memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->rsn_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + kfree(buf); + } + + if (bss_desc->wapi_ie_len) { + char *buf = NULL; + u8 pos = 0; + buf = kmalloc(MAX_WPA_IE_LEN, GFP_ATOMIC); + if(buf == NULL) { + WLAND_ERR("kmalloc buf failed\n"); + return -ENOMEM; + } + + memset(&iwe, 0, sizeof(iwe)); + WLAND_DBG(WEXT, TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->wapi_ie[0], bss_desc->wapi_ie[1], + bss_desc->wapi_ie[2], bss_desc->wapi_ie[3], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 4], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 3], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 2], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 1]); + + memcpy(buf, "wapi_ie=", 8); + + while (pos < bss_desc->wapi_ie_len) { + //transfer hex to ascii string because wpa_supplicant need do so + num_2_str(bss_desc->wapi_ie[pos], + (unsigned char *) (buf + 8 + 2 * pos)); + pos++; + } + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = bss_desc->wapi_ie_len * 2 + 8; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + kfree(buf); + } + + return start; +} + +/** + * @brief Handle Scan Network ioctl + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int iwext_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAND_DBG(WEXT, TRACE, "scan:%d assoc:%d <<< \n", priv->scan_running, + priv->assoc_ongoing); + + if (priv->scan_running == WLAN_SCAN_RUNNING || priv->assoc_ongoing) + goto out; + + if (wrqu->data.length == sizeof(struct iw_scan_req) + && wrqu->data.flags & IW_SCAN_THIS_ESSID) { + struct iw_scan_req *req = (struct iw_scan_req *) extra; + + priv->scan_ssid_len = req->essid_len > 32 ? 32 : req->essid_len; + memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); + priv->scan_ssid[priv->scan_ssid_len] = '\0'; + } else { + priv->scan_ssid_len = 0; + memset(priv->scan_ssid, '\0', sizeof(priv->scan_ssid)); + } + + priv->scan_running = WLAN_SCAN_RUNNING; + ret = wland_start_scan_set(priv, 1); + if (!ret) { + wland_mod_timer(&priv->ScanResultsTimeout, 1500); + } else { + priv->scan_running = WLAN_SCAN_IDLE; + } +out: + + WLAND_DBG(WEXT, TRACE, "Done\n"); + return 0; +} + +/* + * @brief Handle Retrieve scan table ioctl + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int iwext_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ +#define SCAN_ITEM_SIZE 128 + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + struct bss_descriptor *iter_bss; + struct bss_descriptor *safe; + char *ev = extra; + char *stop = ev + dwrq->length; + u8 items = 0; + + WLAND_DBG(WEXT, TRACE, "Enter\n"); + + /* + * iwlist should wait until the current scan is finished + */ + if (priv->scan_running != WLAN_SCAN_COMPLET) { + WLAND_DBG(WEXT, TRACE, "Scan is Running, return AGAIN\n"); + return -EAGAIN; + } + + spin_lock(&priv->ScanListLock); + /* + * report all bss to upper layer + */ + list_for_each_entry_safe(iter_bss, safe, &priv->network_list, list) { + char *next_ev; + ulong stale_time; + + if (stop - ev < SCAN_ITEM_SIZE) { + ret = -E2BIG; + break; + } + + /* + * Prune old an old scan result + */ + stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; + if (time_after(jiffies, stale_time)) { + list_move_tail(&iter_bss->list, + &priv->network_free_list); + WLAND_DBG(WEXT, TRACE, "Prune Old Bss %s\n", + iter_bss->ssid); + + clear_bss_descriptor(iter_bss); + continue; + } +#ifdef WIFI_SELECT_CHANNEL + if (iter_bss->channel > channel_nums) { + clear_bss_descriptor(iter_bss); + continue; + } +#endif + /* + * Translate to WE format this entry + */ + next_ev = translate_scan(priv, info, ev, stop, iter_bss); + + WLAND_DBG(WEXT, TRACE, "Report BSS %s\n", iter_bss->ssid); + + if (next_ev == NULL) + continue; + ev = next_ev; + items++; + } + spin_unlock(&priv->ScanListLock); + dwrq->length = (ev - extra); + dwrq->flags = 0; + + if (priv->scan_running != WLAN_SCAN_RUNNING) + priv->scan_running = WLAN_SCAN_IDLE; + + WLAND_DBG(WEXT, TRACE, "Done,ap:%d\n", items); + return ret; +} + +int iwext_set_mlme(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_mlme *mlme = (struct iw_mlme *) extra; + wland_if *ifp = netdev_priv(dev); + int ret = 0; + + WLAND_DBG(WEXT, TRACE, "Enter.\n"); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + case IW_MLME_DISASSOC: + { + u8 ssid[6]; + + memset(ssid, 0, 6); + WLAND_DBG(WEXT, TRACE, "DISASSOC\n"); + + wland_del_timer(&priv->AssociationTimeOut); + wland_del_timer(&priv->ReAssociationTimeOut); + priv->assoc_ongoing = false; + + /* + * silently ignore + */ + ret = wland_fil_set_cmd_data(ifp, WID_SSID, ssid, + sizeof(ssid)); + break; + } + + default: + { + WLAND_DBG(WEXT, TRACE, "Not supported cmd %d\n", + mlme->cmd); + ret = -EOPNOTSUPP; + break; + } + } + + WLAND_DBG(WEXT, TRACE, "Done.\n"); + return ret; +} + +#define MAX_WX_STRING 80 + +static int wl_iw_get_macaddr(struct net_device *dev, + struct iw_request_info *info, union iwreq_data *wrqu, char *extra) +{ + char *p = extra; + char buf[ETH_ALEN] = { 0 }; + wlan_private *priv = netdev_priv(dev); + int error = wland_fil_get_cmd_data(priv, WID_MAC_ADDR, buf, ETH_ALEN); + + p += snprintf(p, MAX_WX_STRING, + "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5]); + + wrqu->data.length = p - extra + 1; + + return error; +} + +static int iwext_set_priv(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *ext) +{ + int ret = 0; + char *extra; + + if (!(extra = kmalloc(dwrq->length, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, dwrq->pointer, dwrq->length)) { + kfree(extra); + return -EFAULT; + } + + if (dwrq->length && extra) { + if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0) { + ret = wl_iw_get_macaddr(dev, info, + (union iwreq_data *) dwrq, extra); + } else if (strnicmp(extra, "CSCAN", strlen("CSCAN")) == 0) { + } + } + + if (extra) { + if (copy_to_user(dwrq->pointer, extra, dwrq->length)) + ret = -EFAULT; + kfree(extra); + } + + return ret; +} + +static int iwext_get_stats(struct net_device *dev, struct iw_request_info *info, + u32 * uwrq, char *extra) +{ + struct iw_statistics *wstats = (struct iw_statistics *) extra; + wlan_private *priv = netdev_priv(dev); + int ret = 0; + + int stats_valid = 0; + u8 snr; + + WLAND_DBG(WEXT, TRACE, "%s >>>\n", __func__); + + if (priv->connect_status != MAC_CONNECTED) + goto out; + + ret = wlan_update_bss_stats(priv); + if (ret) + goto out; + + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.level = + priv->curbssparams.rssi > + 127 ? priv->curbssparams.rssi - 271 : priv->curbssparams.rssi - + 15; + + snr = wstats->qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + + wstats->qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - + snr))) / (RSSI_DIFF * RSSI_DIFF); + + if (wstats->qual.qual > 100) + wstats->qual.qual = 100; + + wstats->qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + stats_valid = 1; + +out: + if (!stats_valid) { + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = IW_QUAL_ALL_UPDATED; + wstats->qual.updated |= + IW_QUAL_NOISE_INVALID | IW_QUAL_QUAL_INVALID | + IW_QUAL_LEVEL_INVALID; + } + return ret; +} + +/* + * iwconfig settable callbacks + */ +static const iw_handler iwext_handler[] = { + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) iwext_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) iwext_set_freq, /* SIOCSIWFREQ */ + (iw_handler) iwext_get_freq, /* SIOCGIWFREQ */ + (iw_handler) iwext_set_mode, /* SIOCSIWMODE */ + (iw_handler) iwext_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) iwext_get_range, /* SIOCGIWRANGE */ + (iw_handler) iwext_set_priv, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) iwext_get_stats, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) iwext_set_wap, /* SIOCSIWAP */ + (iw_handler) iwext_get_wap, /* SIOCGIWAP */ + (iw_handler) iwext_set_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ + (iw_handler) iwext_set_scan, /* SIOCSIWSCAN */ + (iw_handler) iwext_get_scan, /* SIOCGIWSCAN */ + (iw_handler) iwext_set_essid, /* SIOCSIWESSID */ + (iw_handler) iwext_get_essid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iwext_set_rate, /* SIOCSIWRATE */ + (iw_handler) iwext_get_rate, /* SIOCGIWRATE */ + (iw_handler) iwext_set_rts, /* SIOCSIWRTS */ + (iw_handler) iwext_get_rts, /* SIOCGIWRTS */ + (iw_handler) iwext_set_frag, /* SIOCSIWFRAG */ + (iw_handler) iwext_get_frag, /* SIOCGIWFRAG */ + (iw_handler) iwext_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) iwext_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) iwext_set_retry, /* SIOCSIWRETRY */ + (iw_handler) iwext_get_retry, /* SIOCGIWRETRY */ + (iw_handler) iwext_set_encode, /* SIOCSIWENCODE */ + (iw_handler) iwext_get_encode, /* SIOCGIWENCODE */ + (iw_handler) iwext_set_power, /* SIOCSIWPOWER */ + (iw_handler) iwext_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iwext_set_genie, /* SIOCSIWGENIE */ + (iw_handler) iwext_get_genie, /* SIOCGIWGENIE */ + (iw_handler) iwext_set_auth, /* SIOCSIWAUTH */ + (iw_handler) iwext_get_auth, /* SIOCGIWAUTH */ + (iw_handler) iwext_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) iwext_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) iwext_set_pmksa, /* SIOCSIWPMKSA */ +}; + +struct iw_handler_def wland_iw_handler_def = { + .num_standard = ARRAY_SIZE(iwext_handler), + .standard = (iw_handler *) iwext_handler, + .get_wireless_stats = wland_get_wireless_stats, +}; + +int iwext_attach(struct wland_private *drvr, struct device *busdev) +{ + return 0; +} + +int iwext_dettach(void) +{ + return 0; +} + +#endif /* defined(WL_WIRELESS_EXT) */ diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_iw.h b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_iw.h new file mode 100755 index 0000000..56dec84 --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_iw.h @@ -0,0 +1,132 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAND_IW_H_ +#define _WLAND_IW_H_ + +#include + +#include +#include + +#define GET_SSID "SSID=" +#define GET_CHANNEL "CH=" +#define GET_NPROBE "NPROBE=" +#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" +#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" +#define GET_HOME_DWELL "HOME=" +#define GET_SCAN_TYPE "TYPE=" +#define BAND_GET_CMD "GETBAND" +#define BAND_SET_CMD "SETBAND" +#define DTIM_SKIP_GET_CMD "DTIMSKIPGET" +#define DTIM_SKIP_SET_CMD "DTIMSKIPSET" +#define SETSUSPEND_CMD "SETSUSPENDOPT" +#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" + +/* Lin - Is the extra space needed? */ +#define PNOSETUP_SET_CMD "PNOSETUP " /* TLV command has extra end space */ +#define PNOENABLE_SET_CMD "PNOFORCE" +#define PNODEBUG_SET_CMD "PNODEBUG" +#define TXPOWER_SET_CMD "TXPOWER" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +/* Structure to keep global parameters */ +typedef struct wl_iw_extra_params { + int target_channel; /* target channel */ +} wl_iw_extra_params_t; + +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ + char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ + int32 custom_locale_rev; /* Custom local revisin default -1 */ +}; + +/* ============================================== */ + +/* Defines from wlc_pub.h */ +#define WL_IW_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */ +#define WL_IW_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */ +#define WL_IW_RSSI_VERY_LOW -80 /* Very low quality cutoffs */ +#define WL_IW_RSSI_LOW -70 /* Low quality cutoffs */ +#define WL_IW_RSSI_GOOD -68 /* Good quality cutoffs */ +#define WL_IW_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */ +#define WL_IW_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */ +#define WL_IW_RSSI_INVALID 0 /* invalid RSSI value */ +#define MAX_WX_STRING 80 +#define SSID_FMT_BUF_LEN ((4 * 32) + 1) + +#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) +#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) +#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5) +#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7) +#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9) +#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) +#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) + +struct wl_iw { + char nickname[IW_ESSID_MAX_SIZE]; + struct iw_statistics wstats; + int spy_num; + u32 pwsec; /* pairwise wsec setting */ + u32 gwsec; /* group wsec setting */ + bool privacy_invoked; /* IW_AUTH_PRIVACY_INVOKED setting */ + struct ether_addr spy_addr[IW_MAX_SPY]; + struct iw_quality spy_qual[IW_MAX_SPY]; + void *wlinfo; +}; + +struct wl_ctrl { + struct timer_list *timer; + struct net_device *dev; + long sysioc_pid; + struct semaphore sysioc_sem; + struct completion sysioc_exited; +}; + +#if WIRELESS_EXT > 12 +#include +extern const struct iw_handler_def wland_iw_handler_def; +#endif /* WIRELESS_EXT > 12 */ + +extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +extern void wl_iw_event(struct net_device *dev, wl_event_msg_t * e, void *data); +extern int wl_iw_get_wireless_stats(struct net_device *dev, + struct iw_statistics *wstats); +int iwext_attach(struct net_device *dev, void *dhdp); +int wl_iw_send_priv_event(struct net_device *dev, char *flag); + +void iwext_detach(void); + +#define CSCAN_COMMAND "CSCAN " +#define CSCAN_TLV_PREFIX 'S' +#define CSCAN_TLV_VERSION 1 +#define CSCAN_TLV_SUBVERSION 0 +#define CSCAN_TLV_TYPE_SSID_IE 'S' +#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' +#define CSCAN_TLV_TYPE_NPROBE_IE 'N' +#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' +#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' +#define CSCAN_TLV_TYPE_HOME_IE 'H' +#define CSCAN_TLV_TYPE_STYPE_IE 'T' + +#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) iwe_stream_add_event(info, stream, ends, iwe, extra) +#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) iwe_stream_add_value(info, event, value, ends, iwe, event_len) +#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) iwe_stream_add_point(info, stream, ends, iwe, extra) + +#endif /* _WLAND_IW_H_ */ diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_linux.c b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_linux.c new file mode 100755 index 0000000..b5b5886 --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_linux.c @@ -0,0 +1,1113 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Version string to report */ +#ifndef SRCBASE +#define SRCBASE "drivers/net/wireless/rdaw80211" +#endif + +static char wland_ver[] = + "Compiled in " SRCBASE " on " __DATE__ " at " __TIME__; + +#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */ + +char *wland_ifname(struct wland_private *drvr, int ifidx) +{ + if (ifidx < 0 || ifidx >= WLAND_MAX_IFS) { + WLAND_ERR("ifidx %d out of range\n", ifidx); + return ""; + } + + if (drvr->iflist[ifidx] == NULL) { + WLAND_ERR("null i/f %d\n", ifidx); + return ""; + } + + return ((drvr->iflist[ifidx]->ndev) ? drvr->iflist[ifidx]->ndev-> + name : ""); +} + +struct net_device *dhd_idx2net(void *pub, s32 ifidx) +{ + struct wland_private *priv = (struct wland_private *) pub; + + if (!pub || ifidx < 0 || ifidx >= WLAND_MAX_IFS) + return NULL; + + if (priv && priv->iflist[ifidx]) + return priv->iflist[ifidx]->ndev; + + return NULL; +} + +s32 dhd_net2idx(struct wland_private * driv, struct net_device * net) +{ + int i = 0; + + ASSERT(driv); + + while (i < WLAND_MAX_IFS) { + if (driv->iflist[i] && (driv->iflist[i]->ndev == net)) + return i; + i++; + } + + return ALL_INTERFACES; +} + +static void _wland_set_multicast_list(struct work_struct *work) +{ + struct wland_if *ifp = + container_of(work, struct wland_if, multicast_work); + struct net_device *ndev = ifp->ndev; + + struct netdev_hw_addr *ha; + u32 cmd_value, cnt, buflen; + __le32 cnt_le; + char *buf, *bufp; + s32 err; + + /* + * Determine initial value of allmulti flag + */ + cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false; + + /* + * Send down the multicast list first. + */ + netif_addr_lock_bh(ndev); + cnt = netdev_mc_count(ndev); + netif_addr_unlock_bh(ndev); + + buflen = sizeof(cnt) + (cnt * ETH_ALEN); + buf = kmalloc(buflen, GFP_ATOMIC); + + WLAND_DBG(DEFAULT, TRACE, "Enter(idx:%d,cmd_value:%d,cnt:%d)\n", + ifp->bssidx, cmd_value, cnt); + + if (!buf) + return; + + bufp = buf; + cnt_le = cpu_to_le32(cnt); + memcpy(bufp, &cnt_le, sizeof(cnt_le)); + bufp += sizeof(cnt_le); + + netif_addr_lock_bh(ndev); + netdev_for_each_mc_addr(ha, ndev) { + if (!cnt) + break; + memcpy(bufp, ha->addr, ETH_ALEN); + bufp += ETH_ALEN; + cnt--; + } + + netif_addr_unlock_bh(ndev); + + err = wland_fil_iovar_data_set(ifp, "mcast_list", buf, buflen); + if (err < 0) { + WLAND_ERR("Setting mcast_list failed, %d\n", err); + cmd_value = cnt ? true : cmd_value; + } + + kfree(buf); + + /* + * Now send the allmulti setting. This is based on the setting in the + * net_device flags, but might be modified above to be turned on if we + * were trying to set some addresses and dongle rejected it... + */ + err = wland_fil_iovar_data_set(ifp, "allmulti", &cmd_value, + sizeof(cmd_value)); + if (err < 0) + WLAND_ERR("Setting allmulti failed, %d\n", err); + + /* + * Finally, pick up the PROMISC flag + */ + cmd_value = (ndev->flags & IFF_PROMISC) ? true : false; + err = wland_fil_iovar_data_set(ifp, "promisc", &cmd_value, + sizeof(cmd_value)); + if (err < 0) + WLAND_ERR("Setting failed,err:%d\n", err); +} + +static void _wland_set_mac_address(struct work_struct *work) +{ + s32 err; + struct wland_if *ifp = + container_of(work, struct wland_if, setmacaddr_work); + + WLAND_DBG(DEFAULT, TRACE, "Enter, idx=%d\n", ifp->bssidx); + + err = wland_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, + ETH_ALEN); + if (err < 0) { + WLAND_ERR("Setting cur_etheraddr failed, %d\n", err); + } else { + WLAND_DBG(DEFAULT, TRACE, "MAC address updated to %pM\n", + ifp->mac_addr); + memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN); + } +} + +static int netdev_set_mac_address(struct net_device *ndev, void *addr) +{ + struct wland_if *ifp = netdev_priv(ndev); + struct sockaddr *sa = (struct sockaddr *) addr; + + memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN); + + WLAND_DBG(DEFAULT, TRACE, "Enter %pM\n", sa->sa_data); + + schedule_work(&ifp->setmacaddr_work); + return 0; +} + +static void netdev_set_multicast_list(struct net_device *ndev) +{ + struct wland_if *ifp = netdev_priv(ndev); + + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + schedule_work(&ifp->multicast_work); +} + +int netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int ret = NETDEV_TX_OK; + struct wland_if *ifp = netdev_priv(ndev); + struct wland_private *drvr = ifp->drvr; + struct ethhdr *eh; + struct wland_sdio_dev *sdiodev = drvr->bus_if->bus_priv.sdio; + struct wland_sdio *bus = sdiodev->bus; + + WLAND_DBG(DEFAULT, TRACE, "Enter, ifp->bssidx=%d, skb->len=%d\n", + ifp->bssidx, skb->len); + + /* + * Can the device send data? + */ + if ((drvr->bus_if->state != WLAND_BUS_DATA) || bus->hang_was_sent) { + WLAND_ERR("xmit rejected state=%d\n", drvr->bus_if->state); + netif_stop_queue(ndev); + dev_kfree_skb(skb); + ret = NETDEV_TX_BUSY; + goto done; + } + + if (!drvr->iflist[ifp->bssidx]) { + WLAND_ERR("bad ifidx %d\n", ifp->bssidx); + netif_stop_queue(ndev); + dev_kfree_skb(skb); + ret = NETDEV_TX_BUSY; + goto done; + } + if (check_test_mode()) { + WLAND_DBG(DEFAULT, INFO, "WIFI in test mode.\n"); + dev_kfree_skb(skb); + goto done; + } + + /* + * Make sure there's enough room for any header + */ + if (skb_headroom(skb) < drvr->hdrlen) { + struct sk_buff *skb2; + + WLAND_DBG(DEFAULT, INFO, + "%s: insufficient headroom and realloc skb.\n", + wland_ifname(drvr, ifp->bssidx)); + skb2 = skb_realloc_headroom(skb, drvr->hdrlen); + dev_kfree_skb(skb); + skb = skb2; + if (skb == NULL) { + WLAND_ERR("%s: skb_realloc_headroom failed\n", + wland_ifname(drvr, ifp->bssidx)); + ret = -ENOMEM; + goto done; + } + } + + /* + * validate length for ether packet + */ + if (skb->len < sizeof(*eh)) { + WLAND_ERR("validate length for ether packet!\n"); + ret = -EINVAL; + dev_kfree_skb(skb); + goto done; + } + + ret = wland_sendpkt(ifp, skb); + +done: + if (ret < 0) { + ifp->stats.tx_dropped++; + } else { + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += skb->len; + } + + /* + * Return ok: we always eat the packet + */ + return NETDEV_TX_OK; +} + +static struct net_device_stats *netdev_get_stats(struct net_device *ndev) +{ + struct wland_if *ifp = netdev_priv(ndev); + + if (ifp == NULL) { + WLAND_ERR("BAD_IF\n"); + return NULL; + } + + WLAND_DBG(DEFAULT, TRACE, "Done, idx:%d\n", ifp->bssidx); + + return &ifp->stats; +} + +static void ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct wland_if *ifp = netdev_priv(ndev); + struct wland_private *drvr = ifp->drvr; + + strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); + snprintf(info->version, sizeof(info->version), "%d", drvr->drv_version); + strlcpy(info->bus_info, dev_name(drvr->bus_if->dev), + sizeof(info->bus_info)); +} + +static const struct ethtool_ops wland_ethtool_ops = { + .get_drvinfo = ethtool_get_drvinfo, +}; + +static int wland_ethtool(struct wland_if *ifp, void __user * uaddr) +{ + struct wland_private *drvr = ifp->drvr; + struct ethtool_drvinfo info; + char drvname[sizeof(info.driver)]; + u32 cmd; + struct ethtool_value edata; + u32 toe_cmpnt, csum_dir; + int ret; + + WLAND_DBG(DEFAULT, TRACE, "Enter, idx=%d\n", ifp->bssidx); + + /* + * all ethtool calls start with a cmd word + */ + if (copy_from_user(&cmd, uaddr, sizeof(u32))) + return -EFAULT; + + switch (cmd) { + case ETHTOOL_GDRVINFO: + /* + * Copy out any request driver name + */ + if (copy_from_user(&info, uaddr, sizeof(info))) + return -EFAULT; + strncpy(drvname, info.driver, sizeof(info.driver)); + drvname[sizeof(info.driver) - 1] = '\0'; + + /* + * clear struct for return + */ + memset(&info, 0, sizeof(info)); + info.cmd = cmd; + + /* + * if requested, identify ourselves + */ + if (strcmp(drvname, "?dhd") == 0) { + sprintf(info.driver, "dhd"); + strcpy(info.version, WLAND_VERSION_STR); + } + /* + * report dongle driver type + */ + else { + sprintf(info.driver, "wl"); + } + + sprintf(info.version, "%d", drvr->drv_version); + + if (copy_to_user(uaddr, &info, sizeof(info))) + return -EFAULT; + WLAND_DBG(DEFAULT, TRACE, "given %*s, returning %s\n", + (int) sizeof(drvname), drvname, info.driver); + break; + + /* + * Get toe offload components from dongle + */ + case ETHTOOL_GRXCSUM: + case ETHTOOL_GTXCSUM: + ret = wland_fil_iovar_data_get(ifp, "toe_ol", &toe_cmpnt, + sizeof(toe_cmpnt)); + if (ret < 0) + return ret; + + csum_dir = (cmd == ETHTOOL_GTXCSUM) ? + TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; + + edata.cmd = cmd; + edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; + + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return -EFAULT; + break; + + /* + * Set toe offload components in dongle + */ + case ETHTOOL_SRXCSUM: + case ETHTOOL_STXCSUM: + if (copy_from_user(&edata, uaddr, sizeof(edata))) + return -EFAULT; + + /* + * Read the current settings, update and write back + */ + ret = wland_fil_iovar_data_get(ifp, "toe_ol", &toe_cmpnt, + sizeof(toe_cmpnt)); + if (ret < 0) + return ret; + + csum_dir = (cmd == ETHTOOL_STXCSUM) ? + TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; + + if (edata.data != 0) + toe_cmpnt |= csum_dir; + else + toe_cmpnt &= ~csum_dir; + + /* + * If setting TX checksum mode, tell Linux the new mode + */ + if (cmd == ETHTOOL_STXCSUM) { + if (edata.data) + ifp->ndev->features |= NETIF_F_IP_CSUM; + else + ifp->ndev->features &= ~NETIF_F_IP_CSUM; + } + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, + int cmd) +{ + struct wland_if *ifp = netdev_priv(ndev); + struct wland_private *drvr = ifp->drvr; + int ret = 0; + + /* + * bt wifi coexist + */ + static int bt_state = 0; + int state = 0, old_state = 0; + struct pta_param_s pta_param; + + /* + * bt wifi coexist + */ + + WLAND_DBG(DEFAULT, TRACE, "Enter, idx=%d, cmd=0x%x\n", ifp->bssidx, + cmd); + +#ifdef WLAND_WEXT_SUPPORT + /* + * linux wireless extensions + */ + if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { + /* + * may recurse, do NOT lock + */ + ret = wland_iw_ioctl(ndev, ifr, cmd); + return ret; + } +#endif /* WLAND_WEXT_SUPPORT */ + + if (cmd == SIOCETHTOOL) { + ret = wland_ethtool(ifp, ifr->ifr_data); + return ret; + } + + /* + * linux wireless extensions + */ + if (cmd == SIOCDEVPRIVATE + 1) { + ret = wland_android_priv_cmd(ndev, ifr, cmd); + //dhd_check_hang(net, &dhd->pub, ret); + return ret; + } +#if 0 + if (cmd != SIOCDEVPRIVATE) { + dhd_os_wake_unlock(bus); + return -EOPNOTSUPP; + } +#endif + + if ((drvr->bus_if->chip != WLAND_VER_91_E) && (drvr->bus_if->chip != WLAND_VER_91_G)) + goto out; + + if (cmd == BT_COEXIST) { + state = ifr->ifr_metric; + ret = 0; + + pta_param.prot_mode = PTA_NONE_PROTECT; + pta_param.mac_rate = 0x0; + pta_param.hw_retry = 0x7; + pta_param.sw_retry = 0x3; + pta_param.cca_bypass = TRUE; + pta_param.active_time = 500; /* Unit is 100us */ + pta_param.thresh_time = 20; /* Unit is 100us */ + pta_param.auto_prot_thresh_time = 200; /* Unit is 100us */ + pta_param.flags = BIT0 | BIT1 | BIT5; + pta_param.listen_interval = 0x06; + + if (state == BT_STATE_SCO_ONGOING) { + state = BT_STATE_SCO_ON; + } + + old_state = bt_state; + + if (state & (BT_STATE_SCO_ON | BT_STATE_SCO_ONGOING)) { + bt_state |= BT_STATE_SCO_ON; + } + if (state & BT_STATE_A2DP_PLAYING) { + bt_state |= BT_STATE_A2DP_PLAYING; + } + if (state & BT_STATE_CONNECTION_ON) + bt_state |= BT_STATE_CONNECTION_ON; + + if (state == BT_STATE_SCO_OFF) { + bt_state &= ~BT_STATE_SCO_ON; + } else if (state == BT_STATE_A2DP_NO_PLAYING) { + bt_state &= ~BT_STATE_A2DP_PLAYING; + } else if (state == BT_STATE_CONNECTION_OFF) + bt_state &= ~BT_STATE_CONNECTION_ON; + + if (old_state == bt_state) + goto out; + + if (bt_state) { + if (bt_state & BT_STATE_SCO_ON) { + if (old_state) //should clear pta proc before to set a new pta protec + ret = wland_fil_set_cmd_data(ifp, + WID_PTA_PARAMETER, &pta_param, + sizeof(struct pta_param_s)); + pta_param.prot_mode = PTA_PS_POLL_PROTECT; + pta_param.mac_rate = 0x4; + pta_param.hw_retry = 0x1; + pta_param.sw_retry = 0x1; + pta_param.active_time = 25; + pta_param.thresh_time = 5; + pta_param.auto_prot_thresh_time = 15; + pta_param.flags = BIT0 | BIT1 | BIT5; + pta_param.listen_interval = 0x14; + } else if (bt_state & BT_STATE_A2DP_PLAYING) { + if (old_state) + ret = wland_fil_set_cmd_data(ifp, + WID_PTA_PARAMETER, &pta_param, + sizeof(struct pta_param_s)); + pta_param.prot_mode = PTA_NULL_DATA_PROTECT; + pta_param.active_time = 800; + pta_param.thresh_time = 50; + pta_param.auto_prot_thresh_time = 100; + pta_param.sw_retry = 0x2; + } else if (bt_state & BT_STATE_CONNECTION_ON) { + if (old_state) + ret = wland_fil_set_cmd_data(ifp, + WID_PTA_PARAMETER, &pta_param, + sizeof(struct pta_param_s)); + if(drvr->bus_if->chip == WLAND_VER_91_E) + pta_param.prot_mode = PTA_SELF_CTS_PROTECT; + else if(drvr->bus_if->chip == WLAND_VER_91_G) + pta_param.prot_mode = PTA_SELF_CTS_PROTECT; + pta_param.active_time = 1000; + pta_param.thresh_time = 100; + pta_param.auto_prot_thresh_time = 200; + } + } else { + pta_param.prot_mode = PTA_NONE_PROTECT; + } + ret = wland_fil_set_cmd_data(ifp, WID_PTA_PARAMETER, &pta_param, + sizeof(struct pta_param_s)); + WLAND_DBG(DEFAULT, INFO, "***BT_COEXIST state:%x \n", bt_state); + + } + +out: + WLAND_DBG(DEFAULT, TRACE, "Done.\n"); + + return ret; +} + +static int netdev_stop(struct net_device *ndev) +{ + struct wland_if *ifp = netdev_priv(ndev); + + WLAND_DBG(DEFAULT, TRACE, "Enter, idx=%d\n", ifp->bssidx); + + /* + * Set state and stop OS transmissions + */ + if (!netif_queue_stopped(ndev)) { + netif_stop_queue(ndev); + WLAND_DBG(DEFAULT, TRACE, "netif_stop_queue(ndev)\n"); + } + if (netif_carrier_ok(ndev)) { + netif_carrier_off(ndev); + WLAND_DBG(DEFAULT, TRACE, "netif_carrier_off(ndev)\n"); + } + + wland_cfg80211_down(ndev); + + return 0; +} + +static int netdev_open(struct net_device *ndev) +{ + struct wland_if *ifp = netdev_priv(ndev); + struct wland_private *drvr = ifp->drvr; + struct wland_bus *bus_if = drvr->bus_if; + +#ifdef WLAND_TBD_SUPPORT + u32 toe_ol; +#endif /*WLAND_TBD_SUPPORT */ + s32 ret = 0; + + WLAND_DBG(DEFAULT, TRACE, "Enter, idx=%d\n", ifp->bssidx); + + /* + * If bus is not ready, can't continue + */ + if (bus_if->state != WLAND_BUS_DATA) { + WLAND_ERR("failed bus is not ready\n"); + return -EAGAIN; + } + + atomic_set(&ifp->pend_8021x_cnt, 0); + +#ifdef WLAND_TBD_SUPPORT + /* + * Get current TOE mode from dongle + */ + if (wland_fil_iovar_data_get(ifp, "toe_ol", &toe_ol, + sizeof(toe_ol)) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) + ndev->features |= NETIF_F_IP_CSUM; + else + ndev->features &= ~NETIF_F_IP_CSUM; +#endif /*WLAND_TBD_SUPPORT */ + + if (wland_cfg80211_up(ndev) < 0) { + WLAND_ERR("failed to bring up cfg80211\n"); + ret = -ENODEV; + } + + /* + * Allow transmit calls + */ + if (!ret) { + netif_carrier_on(ndev); + WLAND_DBG(DEFAULT, TRACE, "netif_carrier_on(ndev)\n"); + netif_start_queue(ndev); + WLAND_DBG(DEFAULT, TRACE, "netif_start_queue(ndev)\n"); + } + + return ret; +} + +static void netdev_tx_timeout(struct net_device *dev) +{ + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + dev->trans_start = jiffies; /* prevent tx timeout */ + netif_wake_queue(dev); + dev->stats.tx_errors++; + + WLAND_DBG(DEFAULT, TRACE, "Done\n"); +} + +static const struct net_device_ops wland_netdev_ops_pri = { + .ndo_open = netdev_open, + .ndo_stop = netdev_stop, + .ndo_get_stats = netdev_get_stats, + .ndo_do_ioctl = netdev_ioctl_entry, + .ndo_start_xmit = netdev_start_xmit, + .ndo_tx_timeout = netdev_tx_timeout, + .ndo_set_mac_address = netdev_set_mac_address, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + .ndo_set_rx_mode = netdev_set_multicast_list, +#else /*(LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) */ + .ndo_set_multicast_list = netdev_set_multicast_list, +#endif /*(LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) */ +}; + +int netdev_attach(struct wland_if *ifp) +{ + struct wland_private *drvr = ifp->drvr; + struct net_device *ndev = ifp->ndev; + s32 err = 0; + + /* + * set appropriate operations + */ + ndev->netdev_ops = &wland_netdev_ops_pri; + + ndev->hard_header_len += drvr->hdrlen; + ndev->flags |= IFF_BROADCAST | IFF_MULTICAST; + + ndev->ethtool_ops = &wland_ethtool_ops; + +#ifdef WLAND_WEXT_SUPPORT +#if WIRELESS_EXT < 19 + ndev->get_wireless_stats = wland_get_wireless_stats; +#endif /* WIRELESS_EXT < 19 */ +#if WIRELESS_EXT > 12 + ndev->wireless_handlers = + (struct iw_handler_def *) &wland_iw_handler_def; +#endif /* WIRELESS_EXT > 12 */ +#endif /* WLAND_WEXT_SUPPORT */ + + /* + * set the mac address + */ + memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); + + WLAND_DBG(DEFAULT, TRACE, "Enter,(%s:idx:%d,ifidx:0x%x)\n", ndev->name, + ifp->bssidx, ifp->ifidx); + + err = register_netdev(ndev); + if (err != 0) { + WLAND_ERR("couldn't register the net device\n"); + goto fail; + } + + WLAND_DBG(DEFAULT, TRACE, + "%s: Rdamicro Host Driver(mac:%pM,ndevmtu:0x%x)\n", ndev->name, + ndev->dev_addr, ndev->mtu); + + INIT_WORK(&ifp->setmacaddr_work, _wland_set_mac_address); + INIT_WORK(&ifp->multicast_work, _wland_set_multicast_list); + + ndev->destructor = free_netdev; + return 0; + +fail: + drvr->iflist[ifp->bssidx] = NULL; + ndev->netdev_ops = NULL; + free_netdev(ndev); + return -EBADE; +} + +#ifdef WLAND_P2P_SUPPORT +static int netdev_p2p_open(struct net_device *ndev) +{ + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + return wland_cfg80211_up(ndev); +} + +static int netdev_p2p_stop(struct net_device *ndev) +{ + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + return wland_cfg80211_down(ndev); +} + +static int netdev_p2p_do_ioctl(struct net_device *ndev, struct ifreq *ifr, + int cmd) +{ + int ret = 0; + + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + /* + * There is no ifidx corresponding to p2p0 in our firmware. So we should + * * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. + * * For Android PRIV CMD handling map it to primary I/F + */ + if (cmd == SIOCDEVPRIVATE + 1) { + ret = wland_android_priv_cmd(ndev, ifr, cmd); + } else { + WLAND_ERR("IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", cmd); + ret = -1; + } + + return ret; +} + +static netdev_tx_t netdev_p2p_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + if (skb) + dev_kfree_skb_any(skb); + + WLAND_DBG(DEFAULT, TRACE, + "(%s) is not used for data operations.Droping the packet.\n", + ndev->name); + + /* + * Return ok: we always eat the packet + */ + return NETDEV_TX_OK; +} + +static const struct net_device_ops wland_netdev_ops_p2p = { + .ndo_open = netdev_p2p_open, + .ndo_stop = netdev_p2p_stop, + .ndo_do_ioctl = netdev_p2p_do_ioctl, + .ndo_start_xmit = netdev_p2p_start_xmit +}; + +static void cfgp2p_ethtool_get_drvinfo(struct net_device *net, + struct ethtool_drvinfo *info) +{ + snprintf(info->driver, sizeof(info->driver), "p2p"); + snprintf(info->version, sizeof(info->version), "%lu", (ulong) (0)); +} + +struct ethtool_ops cfgp2p_ethtool_ops = { + .get_drvinfo = cfgp2p_ethtool_get_drvinfo +}; + +/* register "p2p0" interface */ +int netdev_p2p_attach(struct wland_if *ifp) +{ + struct net_device *ndev = ifp->ndev; + + if (!ndev) { + WLAND_ERR("p2p net device is empty\n"); + return -EBADE; + } + ndev->netdev_ops = &wland_netdev_ops_p2p; + ndev->ethtool_ops = &cfgp2p_ethtool_ops; + + /* + * set the mac address + */ + memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); + + WLAND_DBG(DEFAULT, TRACE, "Enter(idx:%d,mac:%pM)\n", ifp->bssidx, + ifp->mac_addr); + + if (register_netdev(ndev)) { + WLAND_ERR("couldn't register the p2p net device\n"); + goto fail; + } + WLAND_DBG(DEFAULT, TRACE, "Done(%s: Rdamicro Host Driver For P2P0)\n", + ndev->name); + + return 0; +fail: + ifp->drvr->iflist[ifp->bssidx] = NULL; + ndev->netdev_ops = NULL; + free_netdev(ndev); + return -EBADE; +} +#endif /* WLAND_P2P_SUPPORT */ + +struct wland_if *wland_add_if(struct wland_private *drvr, s32 bssidx, s32 ifidx, + char *name, u8 * mac_addr) +{ + struct net_device *ndev; + struct wland_if *ifp = drvr->iflist[bssidx]; + + WLAND_DBG(DEFAULT, TRACE, "Enter, idx:%d, ifidx:%d.\n", bssidx, ifidx); + + if (!(drvr && (bssidx < WLAND_MAX_IFS))) { + WLAND_ERR("private not setup!\n"); + return ERR_PTR(-EINVAL); + } + + /* + * Delete the existing interface before overwriting it in case we missed the WLAND_E_IF_DEL event. + */ + if (ifp) { + WLAND_ERR("netname:%s,netdev:%p,ifidx:%d,already exists\n", + ifp->ndev->name, ifp->ndev, ifidx); + + if (ifidx) { + if (ifp->ndev) { + netif_stop_queue(ifp->ndev); + unregister_netdev(ifp->ndev); + free_netdev(ifp->ndev); + drvr->iflist[bssidx] = NULL; + } + } else { + WLAND_ERR("ignore IF event\n"); + return ERR_PTR(-EINVAL); + } + } + + WLAND_DBG(DEFAULT, TRACE, "drvr->p2p_enable:%d,bssidx:%d\n", + drvr->p2p_enable, bssidx); + + if (!drvr->p2p_enable && bssidx == 1) { + /* + * this is P2P_DEVICE interface + */ + WLAND_DBG(DEFAULT, TRACE, "allocate non-netdev interface\n"); + ifp = kzalloc(sizeof(struct wland_if), GFP_KERNEL); + if (!ifp) + return ERR_PTR(-ENOMEM); + memset(ifp, '\0', sizeof(struct wland_if)); + } else { + WLAND_DBG(DEFAULT, TRACE, "allocate netdev interface\n"); + /* + * Allocate netdev, including space for private structure + */ + ndev = alloc_netdev(sizeof(struct wland_if), name, ether_setup); + if (!ndev) + return ERR_PTR(-ENOMEM); + + ndev->netdev_ops = NULL; + + ifp = netdev_priv(ndev); + ifp->ndev = ndev; + } + + ifp->drvr = drvr; + ifp->ifidx = ifidx; + ifp->bssidx = bssidx; + + drvr->iflist[bssidx] = ifp; + + init_waitqueue_head(&ifp->pend_8021x_wait); + + spin_lock_init(&ifp->netif_stop_lock); + + if (mac_addr) + memcpy(ifp->mac_addr, mac_addr, ETH_ALEN); + + WLAND_DBG(DEFAULT, TRACE, "Done, pid:%x, if:%s (%pM) created ===\n", + current->pid, ifp->ndev->name, ifp->mac_addr); + + return ifp; +} + +void wland_del_if(struct wland_private *drvr, s32 bssidx) +{ + struct wland_if *ifp = drvr->iflist[bssidx]; + + if (!ifp) { + WLAND_ERR("Null interface,idx:%d\n", bssidx); + return; + } + + WLAND_DBG(DEFAULT, TRACE, "Enter,idx:%d,ifidx:%d,ndev:%p.\n", bssidx, + ifp->ifidx, ifp->ndev); + + if (ifp->ndev) { + if (bssidx == 0) { + if (ifp->ndev->netdev_ops == &wland_netdev_ops_pri) { + WLAND_DBG(DEFAULT, TRACE, + "wlan0 interface ops.\n"); + + if (!rtnl_is_locked()) + rtnl_lock(); + netdev_stop(ifp->ndev); + if (rtnl_is_locked()) + rtnl_unlock(); + } + } else { + WLAND_DBG(DEFAULT, TRACE, "stop netdev:%p.\n", + ifp->ndev); + netif_stop_queue(ifp->ndev); + } + + if (ifp->ndev->netdev_ops == &wland_netdev_ops_pri) { + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); + } + + /* + * unregister will take care of freeing it + */ + WLAND_DBG(DEFAULT, TRACE, "detach netdev:%p.\n", ifp->ndev); + + unregister_netdev(ifp->ndev); + drvr->iflist[bssidx] = NULL; + if (bssidx == 0 && drvr->config && !IS_ERR(drvr->config)) + cfg80211_detach(drvr->config); + } else { + drvr->iflist[bssidx] = NULL; + kfree(ifp); + } +} + +int wland_netdev_wait_pend8021x(struct net_device *ndev) +{ + struct wland_if *ifp = netdev_priv(ndev); + int err = wait_event_timeout(ifp->pend_8021x_wait, + !atomic_read(&ifp->pend_8021x_cnt), + msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); + + WARN_ON(!err); + + return !err; +} + +/* Module Entery For Linux OS */ +static void wland_driver_init(struct work_struct *work) +{ +#ifdef WLAND_SDIO_SUPPORT + wland_sdio_register(); +#endif /* WLAND_SDIO_SUPPORT */ +#ifdef WLAND_USB_SUPPORT + wland_usb_register(); +#endif /* WLAND_USB_SUPPORT */ +} + +static DECLARE_WORK(wland_driver_work, wland_driver_init); + +struct semaphore registration_sem; +bool registration_check = false; + +/* msec : allowed time to finished dhd registration */ +#define REGISTRATION_TIMEOUT 9000 + +void wland_registration_sem_up(bool check_flag) +{ + registration_check = check_flag; + up(®istration_sem); +} + +#define INSMOD_TEST 1 + +static int wlanfmac_module_init(void) +{ + WLAND_DBG(DEFAULT, TRACE, "%s.\n", wland_ver); + WLAND_DBG(DEFAULT, TRACE, "Ver: %d.%d.%d.\n", WLAND_VER_MAJ, + WLAND_VER_MIN, WLAND_VER_BLD); + + sema_init(®istration_sem, 0); + +#ifdef INSMOD_TEST + rda_wifi_power_on(); +#endif /*INSMOD_TEST */ + + wland_debugfs_init(); + + if (!schedule_work(&wland_driver_work)) + return -EBUSY; + + /* + * Wait till MMC sdio_register_driver callback called and made driver attach. + * It's needed to make sync up exit from dhd insmod and Kernel MMC sdio device callback registration + */ + if ((down_timeout(®istration_sem, + msecs_to_jiffies(REGISTRATION_TIMEOUT)) != 0) + || (!registration_check )) { + WLAND_ERR("sdio_register_driver timeout or error\n"); + cancel_work_sync(&wland_driver_work); + +#ifdef WLAND_SDIO_SUPPORT + wland_sdio_exit(); +#endif /* WLAND_SDIO_SUPPORT */ + +#ifdef WLAND_USB_SUPPORT + wland_usb_exit(); +#endif /*WLAND_USB_SUPPORT */ + + wland_debugfs_exit(); + +#ifdef INSMOD_TEST + rda_wifi_power_off(); +#endif /* INSMOD_TEST */ + return -ENODEV; + } + return 0; +} + +static void __exit wlanfmac_module_exit(void) +{ + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + + cancel_work_sync(&wland_driver_work); + +#ifdef WLAND_SDIO_SUPPORT + wland_sdio_exit(); +#endif /* WLAND_SDIO_SUPPORT */ + +#ifdef WLAND_USB_SUPPORT + wland_usb_exit(); +#endif /*WLAND_USB_SUPPORT */ + + wland_debugfs_exit(); + +#ifdef INSMOD_TEST + rda_wifi_power_off(); +#endif /* INSMOD_TEST */ + WLAND_DBG(DEFAULT, TRACE, "Done\n"); +} + +void rda_wland_shutdown(struct device *dev) +{ + struct wland_bus *bus_if = dev_get_drvdata(dev); + struct wland_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + + WLAND_DBG(DEFAULT, TRACE, "Enter\n"); + cancel_work_sync(&wland_driver_work); + wland_sdio_release(sdiodev->bus); + wland_debugfs_exit(); + WLAND_DBG(DEFAULT, TRACE, "Done\n"); +} + +late_initcall(wlanfmac_module_init); +module_exit(wlanfmac_module_exit); + +MODULE_AUTHOR("RdaMicro Corporation,BoChen"); +MODULE_DESCRIPTION("RdaMicro 802.11 Wireless LAN FullMac Driver."); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_sdio.c b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_sdio.c index de72202..536bd20 100755 --- a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_sdio.c +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_sdio.c @@ -353,7 +353,7 @@ static int wland_sdio_txpkt(struct wland_sdio *bus, struct sk_buff *pkt) *(__le16 *) frame = cpu_to_le16(len); len = real_len; - WLAND_DBG(SDIO, DEBUG, "pkt->len=%x, frame:%x, addr(pkt->data)=%p\n", len, + WLAND_DBG(SDIO, TRACE, "pkt->len=%x, frame:%x, addr(pkt->data)=%p\n", len, *(__le16 *) frame, pkt->data); if (len & (ALIGNMENT - 1)) @@ -764,7 +764,7 @@ static int wland_sdio_process_rxframes(struct wland_sdio *bus) */ size = skb->len; rx_len = (u16) (buf[0] | ((buf[1] & 0x0F) << 8)); - WLAND_DBG(SDIO, DEBUG, "size=%d, rx_len=%d, addr:%x\n", size, rx_len, (unsigned int)buf); + WLAND_DBG(SDIO, TRACE, "size=%d, rx_len=%d, addr:%x\n", size, rx_len, (unsigned int)buf); if (rx_len > size) { WLAND_ERR("SDIO read payload_len invalid! \n"); wland_pkt_buf_free_skb(skb); @@ -1084,7 +1084,7 @@ static int wland_sdio_bus_txctl(struct device *dev, u8 * msg, uint msglen) dhd_os_wait_for_event(bus, &bus->ctrl_frame_stat); if (!bus->ctrl_frame_stat && bus->ctrl_frame_send_success) { - WLAND_DBG(SDIO, DEBUG, + WLAND_DBG(SDIO, TRACE, "ctrl_frame_stat == false, send success\n"); ret = 0; } else if(!bus->ctrl_frame_stat && !bus->ctrl_frame_send_success){ diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_sdmmc.c b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_sdmmc.c new file mode 100755 index 0000000..13c5805 --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_sdmmc.c @@ -0,0 +1,1033 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* devices we support, null terminated */ +static const struct sdio_device_id wland_sdmmc_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_RDAWLAN, SDIO_DEVICE_ID_RDA599X)}, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, wland_sdmmc_ids); + +bool wland_pm_resume_error(struct wland_sdio_dev *sdiodev) +{ + bool is_err = false; + +#if 0 +#ifdef CONFIG_PM_SLEEP + is_err = atomic_read(&sdiodev->suspend); +#endif /* CONFIG_PM_SLEEP */ +#endif + return is_err; +} + +void wland_pm_resume_wait(struct wland_sdio_dev *sdiodev, + wait_queue_head_t * wq) +{ +#if 0 +#ifdef CONFIG_PM_SLEEP + int retry = 0; + + while (atomic_read(&sdiodev->suspend) && retry++ != 30) + wait_event_timeout(*wq, false, HZ / 100); +#endif /* CONFIG_PM_SLEEP */ +#endif +} + +int sdioh_request_byte(struct wland_sdio_dev *sdiodev, uint rw, uint regaddr, + u8 * byte) +{ + int err_ret; + + WLAND_DBG(SDIO, TRACE, "rw=%d,addr=0x%05x\n", rw, regaddr); + + wland_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait); + + if (wland_pm_resume_error(sdiodev)) + return -EIO; + + //sdio_claim_host(sdiodev->func); + if (SDIOH_WRITE == rw) /* CMD52 Write */ + sdio_writeb(sdiodev->func, *byte, regaddr, &err_ret); + else + *byte = sdio_readb(sdiodev->func, regaddr, &err_ret); + //sdio_release_host(sdiodev->func); + + if (err_ret) + WLAND_ERR("Failed to %s :@0x%05x=%02x,Err: %d.\n", + rw ? "write" : "read", regaddr, *byte, err_ret); + + return err_ret; +} + +int sdioh_request_word(struct wland_sdio_dev *sdiodev, uint rw, uint addr, + u32 * word, uint nbytes) +{ + int err_ret = -EIO; + + WLAND_DBG(SDIO, TRACE, "rw=%d, addr=0x%05x, nbytes=%d\n", rw, addr, + nbytes); + + wland_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); + + if (wland_pm_resume_error(sdiodev)) + return -EIO; + + sdio_claim_host(sdiodev->func); + if (SDIOH_WRITE == rw) { /* CMD52 Write */ + if (nbytes == 4) + sdio_writel(sdiodev->func, *word, addr, &err_ret); + else if (nbytes == 2) + sdio_writew(sdiodev->func, (*word & 0xFFFF), addr, + &err_ret); + else + WLAND_ERR("Invalid nbytes: %d\n", nbytes); + } else { /* CMD52 Read */ + if (nbytes == 4) + *word = sdio_readl(sdiodev->func, addr, &err_ret); + else if (nbytes == 2) + *word = sdio_readw(sdiodev->func, addr, + &err_ret) & 0xFFFF; + else + WLAND_ERR("Invalid nbytes: %d\n", nbytes); + } + sdio_release_host(sdiodev->func); + + if (err_ret) + WLAND_ERR("Failed to %s word, Err: 0x%08x\n", + rw ? "write" : "read", err_ret); + + return err_ret; +} + +int sdioh_request_bytes(struct wland_sdio_dev *sdiodev, uint rw, uint addr, + u8 * byte, uint nbyte) +{ + int err_ret = 0; + int bytes_left = 0, offset = 0, batch = 0; + + WLAND_DBG(SDIO, TRACE, "%s: addr=0x%05x, lenght=%d\n", + rw ? "WRITE" : "READ", addr, nbyte); + + wland_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); + + if (wland_pm_resume_error(sdiodev)) + return -EIO; + + //sdio_claim_host(sdiodev->func); + if (SDIOH_WRITE == rw) { + bytes_left = nbyte; + while (bytes_left > 0 && err_ret == 0) { + batch = (bytes_left > + sdiodev->func->cur_blksize) ? sdiodev->func-> + cur_blksize : bytes_left; +#ifdef WLAND_RDAPLATFORM_SUPPORT + { + u8 *packet_to_send = NULL; + struct page *pg = NULL; + + packet_to_send = byte + offset; + if (((u32) packet_to_send >> PAGE_SHIFT) != + (((u32) packet_to_send + batch - 1) >> PAGE_SHIFT) || + (u32)packet_to_send & (ALIGNMENT -1)) { + + pg = alloc_page(GFP_KERNEL); + if (!pg) { + err_ret = -1; + break; + } + memcpy(page_address(pg), packet_to_send, batch); + packet_to_send = page_address(pg); + WLAND_DBG(SDIO, TRACE, "wlan data cross page boundary addr:%x size:%x \n", + (u32)(packet_to_send), batch); + err_ret = sdio_writesb(sdiodev->func, addr, packet_to_send, batch); + __free_page(pg); + } else + err_ret = sdio_writesb(sdiodev->func, addr, packet_to_send, batch); + } + +#else + err_ret = + sdio_writesb(sdiodev->func, addr, byte + offset, + batch); +#endif + offset += batch; + bytes_left -= batch; + } + } else { + err_ret = sdio_readsb(sdiodev->func, byte, addr, nbyte); + } + //sdio_release_host(sdiodev->func); + + if (err_ret) + WLAND_ERR("Failed to %s bytes, Err: 0x%08x\n", + (SDIOH_WRITE == rw) ? "write" : "read", err_ret); + + return err_ret; +} + +#ifdef WLAND_SDIO_FC_SUPPORT +static int wland_sdio_flow_ctrl_90(struct wland_sdio_dev *sdiodev) +{ + int ret = 0; + u8 status = 0; + s32 int_sleep_count = 0, check_num = FLOW_CTRL_RXCMPL_RETRY_COUNT_90; + + WLAND_DBG(SDIO, TRACE, "Enter\n"); + if (sdiodev->bus_if->chip != WLAND_VER_90_D + && sdiodev->bus_if->chip != WLAND_VER_90_E) { + ret = -1; + WLAND_ERR + ("WIFI chip version not match(sdiodev->bus_if->chip=%d)\n", + sdiodev->bus_if->chip); + goto out; + } + + while (true) { + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, SDIOH_READ, + URSDIO_FUNC1_INT_PENDING, &status); + sdio_release_host(sdiodev->func); + if (status & I_RXCMPL) + WLAND_DBG(SDIO, TRACE, + "URSDIO_FUNC1_INT_PENDING:int_sleep_count=%d, status=%x \n", + int_sleep_count, status); + + if (ret) { + WLAND_ERR("wland read URSDIO_FUNC1_INT_PENDING failed......ret = %d\n", ret); + return ret; + } + + if ((status & I_RXCMPL) == 0) { + if (int_sleep_count >= check_num) { + status = I_RXCMPL; + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_INT_PENDING, &status); + sdio_release_host(sdiodev->func); + msleep(100); + WLAND_ERR + ("flows ctrl RXCMPL failed, count:%d over, return back \n", + check_num); + break; + } else { + int_sleep_count++; + schedule(); + } + } else { + status = I_RXCMPL; + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_INT_PENDING, &status); + sdio_release_host(sdiodev->func); + WLAND_DBG(SDIO, TRACE, + "clear flowctrl flag, int_sleep_count=%d\n", + int_sleep_count); + if (!ret) + break; + } + } + +out: + WLAND_DBG(SDIO, TRACE, "Done(ret:%d)\n", ret); + return ret; +} + +static int wland_sdio_flow_ctrl_91(struct wland_sdio_dev *sdiodev) +{ + int ret = 0; + u8 status = 0; + s32 int_sleep_count = 0, check_num = FLOW_CTRL_INT_SLEEP_RETRY_COUNT_91; + + WLAND_DBG(SDIO, TRACE, "Enter\n"); + if (sdiodev->bus_if->chip != WLAND_VER_91) { + ret = -1; + WLAND_ERR("WIFI chip version not match(sdiodev->bus_if->chip=%d)\n", + sdiodev->bus_if->chip); + goto out; + } + + while (true) { + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, SDIOH_READ, + URSDIO_FUNC1_INT_PENDING, &status); + sdio_release_host(sdiodev->func); + if (status & I_RXCMPL) + WLAND_DBG(SDIO, TRACE, + "URSDIO_FUNC1_INT_PENDING:int_sleep_count=%d, status=%x \n", + int_sleep_count, status); + + if (ret) { + WLAND_ERR("wland read URSDIO_FUNC1_INT_PENDING failed......ret = %d\n", ret); + return ret; + } + + if ((status & I_RXCMPL) == 0) { + if (int_sleep_count >= check_num) { + break; + } else { + int_sleep_count++; + } + } else { + status = I_SLEEP; + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_INT_PENDING, &status); + sdio_release_host(sdiodev->func); + WLAND_DBG(SDIO, TRACE, + "clear flowctrl flag, int_sleep_count=%d\n", + int_sleep_count); + if (!ret) + break; + } + if (int_sleep_count < 20) + udelay(10); + else + msleep(1); + } + +out: + WLAND_DBG(SDIO, TRACE, "Done(ret:%d)\n", ret); + return ret; +} + +static int wland_sdio_flow_ctrl_91e(struct wland_sdio_dev *sdiodev) +{ + int ret = 0; + u8 status = 0; + s32 int_sleep_count = 0, check_num = FLOW_CTRL_RXCMPL_RETRY_COUNT_91; + + WLAND_DBG(SDIO, TRACE, "Enter\n"); + if (sdiodev->bus_if->chip != WLAND_VER_91_E + && sdiodev->bus_if->chip != WLAND_VER_91_F + && sdiodev->bus_if->chip != WLAND_VER_91_G) { + ret = -1; + WLAND_ERR + ("WIFI chip version not match(sdiodev->bus_if->chip=%d)\n", + sdiodev->bus_if->chip); + goto out; + } + + while (true) { + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, SDIOH_READ, + URSDIO_FUNC1_INT_PENDING, &status); + sdio_release_host(sdiodev->func); + if (status & I_RXCMPL) + WLAND_DBG(SDIO, TRACE, + "URSDIO_FUNC1_INT_PENDING:int_sleep_count=%d, status=%x \n", + int_sleep_count, status); + + if (!ret) { + if ((status & I_RXCMPL) == 0) { + if (int_sleep_count >= check_num) { + status = I_RXCMPL; + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, + SDIOH_WRITE, + URSDIO_FUNC1_INT_PENDING, + &status); + sdio_release_host(sdiodev->func); + WLAND_ERR + ("flows ctrl RXCMPL failed, count:%d over, return back \n", + check_num); + ret = -1; + break; + } else { + int_sleep_count++; + } + if (int_sleep_count < 20) { + udelay(2); + } else { + WLAND_DBG(SDIO, DEBUG,"msleep(1)\n"); + mdelay(1); + } + } else { + status = I_RXCMPL; + sdio_claim_host(sdiodev->func); + ret = sdioh_request_byte(sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_INT_PENDING, &status); + sdio_release_host(sdiodev->func); + WLAND_DBG(SDIO, TRACE, + "clear flowctrl flag, int_sleep_count=%d\n", + int_sleep_count); + if (!ret) + break; + } + + } else { + WLAND_ERR("wland read URSDIO_FUNC1_INT_PENDING failed......ret = %d\n", ret); + return ret; + } + } + +out: + WLAND_DBG(SDIO, TRACE, "Done(ret:%d)\n", ret); + return ret; +} + +static int wland_sdio_flow_ctrl(struct wland_sdio_dev *sdiodev) +{ + int ret = 0; + + WLAND_DBG(SDIO, TRACE, "Enter\n"); + + if (sdiodev->bus_if->chip == WLAND_VER_90_D + || sdiodev->bus_if->chip == WLAND_VER_90_E) { + if ((ret = wland_sdio_flow_ctrl_90(sdiodev))) { + WLAND_ERR("wland_sdio_flow_ctrl_90 failed! \n"); + goto out; + } + } else if (sdiodev->bus_if->chip == WLAND_VER_91) { + if ((ret = wland_sdio_flow_ctrl_91(sdiodev))) { + WLAND_ERR("wland_sdio_flow_ctrl_91 failed! \n"); + goto out; + } + } else if (sdiodev->bus_if->chip == WLAND_VER_91_E + || sdiodev->bus_if->chip == WLAND_VER_91_F + || sdiodev->bus_if->chip == WLAND_VER_91_G) { + if ((ret = wland_sdio_flow_ctrl_91e(sdiodev))) { + WLAND_ERR("wland_sdio_flow_ctrl_91e failed! \n"); + goto out; + } + } else { + ret = -1; + WLAND_ERR("wlan_sdio_flow_ctrl unkown version:%d\n", + sdiodev->bus_if->chip); + } + +out: + WLAND_DBG(SDIO, TRACE, "Done(ret:%d)\n", ret); + return ret; +} +#endif /*WLAND_SDIO_FC_SUPPORT */ + +int wland_sdio_send_pkt(struct wland_sdio *bus, struct sk_buff *pkt, uint count) +{ + int ret = 0; + u8 size_l = 0, size_h = 0; + u16 size = 0; + u8 *buf = pkt->data; + + WLAND_DBG(SDIO, TRACE, "blockSize=%d, count=%d, pkt->len=%d, pkt->data=%p\n", + bus->blocksize, count, pkt->len, pkt->data); + //WLAND_DUMP(SDIO, pkt->data, count, "TX Data, len:%Zu\n", count); + if (check_test_mode() && check_sdio_init()) { + WLAND_DBG(SDIO, INFO, "In Test Mode and do not send pkt!\n"); + return ret; + } +#ifdef WLAND_SDIO_FC_SUPPORT + if ((ret = wland_sdio_flow_ctrl(bus->sdiodev))) { + WLAND_ERR("wland_sdio_flow_ctrl failed!\n"); + goto out; + } +#endif /*WLAND_SDIO_FC_SUPPORT */ + + size = count / 4; + + size_l = size & 0xFF; + size_h = ((size >> 8) & 0x7F) | 0x80; //0x80 flags means lenght higer bytes + + sdio_claim_host(bus->sdiodev->func); + ret = sdioh_request_byte(bus->sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_SPKTLEN_LO, &size_l); + ret |= sdioh_request_byte(bus->sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_SPKTLEN_HI, &size_h); + if (ret) { + WLAND_ERR(" sdioh_request_byte failed!\n"); + sdio_release_host(bus->sdiodev->func); + goto out; + } + ret = sdioh_request_bytes(bus->sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_FIFO_WR, buf, count); + sdio_release_host(bus->sdiodev->func); + +out: + WLAND_DBG(SDIO, TRACE, "Done(ret:%d)\n", ret); + return ret; +} + +int wland_sdio_recv_pkt(struct wland_sdio *bus, struct sk_buff *skbbuf, + uint size) +{ + int ret; /* Return code from calls */ + + if ((!skbbuf) || (!size)) { + WLAND_ERR("skb empty!\n"); + return -EINVAL;; + } + + ret = sdioh_request_bytes(bus->sdiodev, SDIOH_READ, + URSDIO_FUNC1_FIFO_RD, skbbuf->data, size); + if (ret < 0) { + WLAND_ERR("SDIO read data failed! \n"); + return ret; + } + + //skbbuf->len = size; + + WLAND_DBG(SDIO, TRACE, "Done(ret:%d,RxData,len:%d)\n", ret, size); + return ret; +} + +static int wland_ops_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct wland_sdio_dev *sdiodev; + struct wland_bus *bus_if; + struct osl_info *osh; + int err = -ENODEV; + + WLAND_DBG(SDIO, TRACE, "Enter\n"); + WLAND_DBG(SDIO, INFO, "Class=%x\n", func->class); + WLAND_DBG(SDIO, INFO, "sdio vendor ID: 0x%04x\n", func->vendor); + WLAND_DBG(SDIO, INFO, "sdio device ID: 0x%04x\n", func->device); + WLAND_DBG(SDIO, INFO, "Function#: %d\n", func->num); + + if (id->vendor != SDIO_VENDOR_ID_RDAWLAN) { + WLAND_ERR("Unmatch Vendor ID: 0x%x.\n", id->vendor); + return -ENODEV; + } + + osh = osl_attach(func, SDIO_BUS, true); + if (!osh) + return -ENOMEM; + + bus_if = osl_malloc(osh, sizeof(struct wland_bus)); + if (!bus_if) { + osl_detach(osh); + return -ENOMEM; + } + memset(bus_if, '\0', sizeof(struct wland_bus)); + + sdiodev = osl_malloc(osh, sizeof(struct wland_sdio_dev)); + if (!sdiodev) { + osl_free(osh, bus_if, sizeof(struct wland_bus)); + osl_detach(osh); + return -ENOMEM; + } + memset(sdiodev, '\0', sizeof(struct wland_sdio_dev)); + + /* + * initial sdiodev func parameters + */ + sdiodev->func = func; + sdiodev->bus_if = bus_if; + + bus_if->bus_priv.sdio = sdiodev; + bus_if->osh = osh; + + dev_set_drvdata(&func->dev, bus_if); + + sdiodev->dev = &func->dev; + + atomic_set(&sdiodev->suspend, false); + sdiodev->card_sleep = true; + + init_waitqueue_head(&sdiodev->request_byte_wait); + init_waitqueue_head(&sdiodev->request_word_wait); + init_waitqueue_head(&sdiodev->request_buffer_wait); + + WLAND_DBG(SDIO, TRACE, "F1 found, calling real sdio probe...\n"); + + err = wland_sdioh_attach(sdiodev); + if (err < 0) + goto fail; + + /* + * try to attach to the target device + */ + sdiodev->bus = wland_sdio_probe(osh, sdiodev); + if (!sdiodev->bus) { + WLAND_ERR("device attach failed\n"); + goto fail; + } + WLAND_DBG(SDIO, TRACE, "Done,init completed success...\n"); + return 0; +fail: + wland_sdioh_detach(sdiodev); + dev_set_drvdata(&func->dev, NULL); + osl_free(osh, sdiodev, sizeof(struct wland_sdio_dev)); + osl_free(osh, bus_if, sizeof(struct wland_bus)); + osl_detach(osh); + return err; +} + +static void wland_ops_sdio_remove(struct sdio_func *func) +{ + struct wland_bus *bus_if = NULL; + struct wland_sdio_dev *sdiodev = NULL; + struct osl_info *osh = NULL; + + WLAND_DBG(SDIO, TRACE, "Enter\n"); + bus_if = dev_get_drvdata(&func->dev); + if (bus_if) { + sdiodev = bus_if->bus_priv.sdio; + osh = bus_if->osh; + } else { + WLAND_ERR("bus_if == NULL and go out.\n"); + goto out; + } + if (sdiodev == NULL || osh == NULL) { + WLAND_ERR("sdiodev == NULL || osh == NULL and go out.\n"); + goto out; + } + WLAND_DBG(SDIO, TRACE, "SDIO-VID:0x%04x,SDIO-DID:0x%04x,Function:%d\n", + func->vendor, func->device, func->num); + + sdiodev->bus_if->state = WLAND_BUS_DOWN; + + if (sdiodev->bus) { + wland_sdio_release(sdiodev->bus); + sdiodev->bus = NULL; + } + + wland_sdioh_detach(sdiodev); + + dev_set_drvdata(&sdiodev->func->dev, NULL); + + osl_free(osh, sdiodev, sizeof(struct wland_sdio_dev)); + osl_free(osh, bus_if, sizeof(struct wland_bus)); + osl_detach(osh); + +out: + WLAND_DBG(SDIO, TRACE, "Done\n"); +} + +#ifdef CONFIG_PM +static int wland_sdio_suspend(struct device *dev) +{ + int ret = 0; + struct wland_bus *bus_if = dev_get_drvdata(dev); + struct wland_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + mmc_pm_flag_t sdio_flags; + + WLAND_DBG(SDIO, TRACE, "Enter.\n"); + netif_device_detach(bus_if->drvr->iflist[0]->ndev); + + sdio_flags = sdio_get_host_pm_caps(sdiodev->func); + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + WLAND_ERR("Host can't keep power while suspended\n"); + return -EINVAL; + } + + ret = sdio_set_host_pm_flags(sdiodev->func, MMC_PM_KEEP_POWER); + if (ret) { + WLAND_ERR("Failed to set pm_flags\n"); + return ret; + } + + atomic_set(&sdiodev->suspend, true); + + /* + * Watchdog timer interface for pm ops + */ + while (sdiodev->card_sleep != true) { + if (down_interruptible(&sdiodev->bus->txclk_sem)) { + WLAND_ERR("Can not request bus->txclk_sem.wland_sdio_suspend\n"); + continue; + } + wland_sdio_clkctl(sdiodev->bus, CLK_NONE); + up(&sdiodev->bus->txclk_sem); + wland_sched_timeout(50); + } + + WLAND_DBG(SDIO, TRACE, "Done.\n"); + return 0; +} + +static int wland_sdio_resume(struct device *dev) +{ + + struct wland_bus *bus_if = dev_get_drvdata(dev); + struct wland_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + + WLAND_DBG(SDIO, TRACE, "Enter\n"); + netif_device_attach(bus_if->drvr->iflist[0]->ndev); + + atomic_set(&sdiodev->suspend, false); + + WLAND_DBG(SDIO, TRACE, "Done\n"); + return 0; +} + +static const struct dev_pm_ops wland_sdio_pm_ops = { + .suspend = wland_sdio_suspend, + .resume = wland_sdio_resume, +}; +#endif /* ifdef CONFIG_PM */ + +static struct sdio_driver wland_sdmmc_driver = { + .probe = wland_ops_sdio_probe, + .remove = wland_ops_sdio_remove, + .name = WLAND_SDIO_NAME, + .id_table = wland_sdmmc_ids, + .drv = { +#ifdef CONFIG_PM + .pm = &wland_sdio_pm_ops, +#endif + .shutdown = &rda_wland_shutdown, + }, +}; + +/* Public entry points & extern's */ +int wland_sdioh_attach(struct wland_sdio_dev *sdiodev) +{ + int err_ret = 0; + + WLAND_DBG(SDIO, TRACE, "Enter.\n"); + sdio_claim_host(sdiodev->func); + err_ret = sdio_set_block_size(sdiodev->func, SDIO_FUNC1_BLOCKSIZE); + if (err_ret < 0) { + WLAND_ERR("Failed to set F1 blocksize.\n"); + goto out; + } + /* + * Enable Function 1 + */ + err_ret = sdio_enable_func(sdiodev->func); + if (err_ret < 0) + WLAND_ERR("Failed to enable F1 Err: 0x%08x.\n", err_ret); +out: + sdio_release_host(sdiodev->func); + WLAND_DBG(SDIO, TRACE, "Done.\n"); + return err_ret; +} + +void wland_sdioh_detach(struct wland_sdio_dev *sdiodev) +{ + WLAND_DBG(SDIO, TRACE, "Enter\n"); + + /* + * Disable Function 1 + */ + sdio_claim_host(sdiodev->func); + sdio_disable_func(sdiodev->func); + sdio_release_host(sdiodev->func); + + WLAND_DBG(SDIO, TRACE, "Done\n"); +} + +void wland_sdio_register(void) +{ + WLAND_DBG(SDIO, TRACE, "Enter\n"); + + if (sdio_register_driver(&wland_sdmmc_driver)) { + WLAND_ERR("sdio_register_driver failed\n"); + wland_registration_sem_up(false); + } else { + /* + * disable sdio interrupt + */ + rda_mmc_set_sdio_irq(1, false); + + /* + * trigger sdio bus scan device + */ + rda_mmc_bus_scan(1); + } + + WLAND_DBG(SDIO, TRACE, "Done\n"); +} + +void wland_sdio_exit(void) +{ + WLAND_DBG(SDIO, TRACE, "Enter\n"); + sdio_unregister_driver(&wland_sdmmc_driver); + WLAND_DBG(SDIO, TRACE, "Done\n"); +} + +////////////////////////////////////////////////////////////////////////////////// +// // +// Linux OSI Relations Area // +// // +////////////////////////////////////////////////////////////////////////////////// + +void dhd_os_sdlock(struct wland_sdio *bus) +{ + if (bus->threads_only) + down(&bus->sdsem); +} + +void dhd_os_sdunlock(struct wland_sdio *bus) +{ + if (bus->threads_only) + up(&bus->sdsem); +} + +void dhd_os_sdlock_txq(struct wland_sdio *bus, unsigned long *flags) +{ + if (bus) + spin_lock_irqsave(&bus->txqlock, *flags); +} + +void dhd_os_sdunlock_txq(struct wland_sdio *bus, unsigned long *flags) +{ + if (bus) + spin_unlock_irqrestore(&bus->txqlock, *flags); +} + +void dhd_os_sdlock_rxq(struct wland_sdio *bus, unsigned long *flags) +{ + if (bus) + spin_lock_irqsave(&bus->rxqlock, *flags); +} + +void dhd_os_sdunlock_rxq(struct wland_sdio *bus, unsigned long *flags) +{ + if (bus) + spin_unlock_irqrestore(&bus->rxqlock, *flags); +} + +int dhd_os_ioctl_resp_wait(struct wland_sdio *bus, uint * condition, + bool * pending) +{ + DECLARE_WAITQUEUE(wait, current); + + /* + * Convert timeout in millsecond to jiffies + */ + int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); + + /* + * Wait until control frame is available + */ + add_wait_queue(&bus->dcmd_resp_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (!(*condition) && (!signal_pending(current) && timeout)) + timeout = schedule_timeout(timeout); + + if (signal_pending(current)) + *pending = true; + + set_current_state(TASK_RUNNING); + remove_wait_queue(&bus->dcmd_resp_wait, &wait); + + return timeout; +} + +void dhd_os_ioctl_resp_wake(struct wland_sdio *bus) +{ + if (waitqueue_active(&bus->dcmd_resp_wait)) + wake_up(&bus->dcmd_resp_wait); +} + +void dhd_os_wait_for_event(struct wland_sdio *bus, bool * lockvar) +{ + int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); + wait_event_interruptible_timeout(bus->ctrl_wait, !(*lockvar), + timeout); +} + +void dhd_os_wait_event_wakeup(struct wland_sdio *bus) +{ + if (waitqueue_active(&bus->ctrl_wait)) + wake_up(&bus->ctrl_wait); +} + +int dhd_os_wake_lock(struct wland_sdio *bus) +{ + ulong flags; + int ret = 0; + + if (bus) { + spin_lock_irqsave(&bus->wakelock_spinlock, flags); +#ifdef CONFIG_HAS_WAKELOCK + if (!bus->wakelock_counter) { + //wake_lock(&bus->wl_wifi); + WLAND_DBG(SDIO, TRACE, "wl_wifi locked.\n"); + } +#endif /*CONFIG_HAS_WAKELOCK */ + bus->wakelock_counter++; + ret = bus->wakelock_counter; + spin_unlock_irqrestore(&bus->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_wake_lock_timeout(struct wland_sdio *bus) +{ + ulong flags; + int ret = 0; + + if (bus) { + spin_lock_irqsave(&bus->wakelock_spinlock, flags); + ret = bus->wakelock_rx_timeout_enable > + bus->wakelock_ctrl_timeout_enable ? + bus->wakelock_rx_timeout_enable : + bus->wakelock_ctrl_timeout_enable; +#ifdef CONFIG_HAS_WAKELOCK + if (bus->wakelock_rx_timeout_enable) + wake_lock_timeout(&bus->wl_rxwake, + msecs_to_jiffies + (bus->wakelock_rx_timeout_enable)); + if (bus->wakelock_ctrl_timeout_enable) + wake_lock_timeout(&bus->wl_ctrlwake, + msecs_to_jiffies + (bus->wakelock_ctrl_timeout_enable)); +#endif /*CONFIG_HAS_WAKELOCK */ + bus->wakelock_rx_timeout_enable = 0; + bus->wakelock_ctrl_timeout_enable = 0; + spin_unlock_irqrestore(&bus->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_wake_unlock(struct wland_sdio *bus) +{ + ulong flags; + int ret = 0; + + dhd_os_wake_lock_timeout(bus); + if (bus) { + spin_lock_irqsave(&bus->wakelock_spinlock, flags); + if (bus->wakelock_counter) { + bus->wakelock_counter--; +#ifdef CONFIG_HAS_WAKELOCK + if (!bus->wakelock_counter) { + //wake_unlock(&bus->wl_wifi); + WLAND_DBG(SDIO, TRACE, "wl_wifi unlock.\n"); + } +#endif /*CONFIG_HAS_WAKELOCK */ + ret = bus->wakelock_counter; + } + spin_unlock_irqrestore(&bus->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_check_wakelock(struct wland_sdio *bus) +{ +#ifdef CONFIG_HAS_WAKELOCK + if (!bus) + return 0; + + /* + * Indicate to the SD Host to avoid going to suspend if internal locks are up + */ + if (wake_lock_active(&bus->wl_wifi) + || wake_lock_active(&bus->wl_wdwake)) + return 1; +#endif /*CONFIG_HAS_WAKELOCK */ + return 0; +} + +int dhd_os_wd_wake_lock(struct wland_sdio *bus) +{ + ulong flags; + int ret = 0; + + if (bus) { + spin_lock_irqsave(&bus->wakelock_spinlock, flags); +#ifdef CONFIG_HAS_WAKELOCK + /* + * if wakelock_wd_counter was never used : lock it at once + */ + if (!bus->wakelock_wd_counter) { + wake_lock(&bus->wl_wdwake); + WLAND_DBG(SDIO, TRACE, "wl_wdwake lock.\n"); + } +#endif /*CONFIG_HAS_WAKELOCK */ + bus->wakelock_wd_counter++; + ret = bus->wakelock_wd_counter; + spin_unlock_irqrestore(&bus->wakelock_spinlock, flags); + } + return ret; +} + +int dhd_os_wd_wake_unlock(struct wland_sdio *bus) +{ + ulong flags; + int ret = 0; + + if (bus) { + spin_lock_irqsave(&bus->wakelock_spinlock, flags); + if (bus->wakelock_wd_counter) { + bus->wakelock_wd_counter = 0; +#ifdef CONFIG_HAS_WAKELOCK + wake_unlock(&bus->wl_wdwake); + WLAND_DBG(SDIO, TRACE, "wl_wdwake unlock.\n"); +#endif /*CONFIG_HAS_WAKELOCK */ + } + spin_unlock_irqrestore(&bus->wakelock_spinlock, flags); + } + return ret; +} + +ulong dhd_os_spin_lock(struct wland_sdio * bus) +{ + ulong flags = 0; + + if (bus) + spin_lock_irqsave(&bus->wakelock_spinlock, flags); + + return flags; +} + +void dhd_os_spin_unlock(struct wland_sdio *bus, ulong flags) +{ + if (bus) + spin_unlock_irqrestore(&bus->wakelock_spinlock, flags); +} + +////////////////////////////////////////////////////////////////////////////////// diff --git a/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_wid.c b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_wid.c new file mode 100755 index 0000000..49e55a2 --- /dev/null +++ b/OrangePiRDA/kernel/drivers/net/wireless/rdaw80211/rdawlan/wland_wid.c @@ -0,0 +1,508 @@ + +/* + * Copyright (c) 2014 Rdamicro Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int wland_proto_hdrpush(struct wland_private *drvr, s32 ifidx, + struct sk_buff *pktbuf) +{ + WLAND_DBG(DCMD, TRACE, "ifidx:%d,Enter\n", ifidx); + +#if 0 + struct bdc_header *h; + + /* + * Push BDC header used to convey priority for buses that don't + */ + PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); + + h = (struct bdc_header *) PKTDATA(dhd->osh, pktbuf); + + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (PKTSUMNEEDED(pktbuf)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->dataOffset = 0; + + BDC_SET_IF_IDX(h, ifidx); +#endif /* BDC */ + + return 0; +} + +int wland_proto_hdrpull(struct wland_private *drvr, s32 * ifidx, + struct sk_buff *pktbuf) +{ + WLAND_DBG(EVENT, TRACE, "Enter(pktbuf->len:%d)\n", pktbuf->len); + + /* + * Pop BDC header used to convey priority for buses that don't + */ + if (PKTLEN(drvr->bus_if->osh, pktbuf) <= FMW_HEADER_LEN) { + WLAND_ERR("rx data too short (%d <= %d)\n", pktbuf->len, + FMW_HEADER_LEN); + return -EBADE; + } + + if (ifidx) + *ifidx = 0; +#if 0 + *ifidx = pktbuf->data[3]; + if (*ifidx >= WLAND_MAX_IFS) { + WLAND_ERR("rx data ifnum out of range (%d)\n", *ifidx); + return -EBADE; + } + /* + * The ifidx is the idx to map to matching netdev/ifp. When receiving + * * events this is easy because it contains the bssidx which maps + * * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. + * * bssidx 1 is used for p2p0 and no data can be received or + * * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 + */ + if (*ifidx) + (*ifidx)++; + + ////////////////////////////////////////////// + struct bdc_header *h; + u8 data_offset = 0; + + h = (struct bdc_header *) PKTDATA(dhd->osh, pktbuf); + + if (!ifidx) { + /* + * for tx packet, skip the analysis + */ + data_offset = h->dataOffset; + PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); + goto exit; + } + + if ((*ifidx = BDC_GET_IF_IDX(h)) >= WLAND_MAX_IFS) { + DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", + __FUNCTION__, *ifidx)); + return BCME_ERROR; + } + + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != + BDC_PROTO_VER) { + DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", + wland_ifname(dhd, *ifidx), h->flags)); + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == + BDC_PROTO_VER_1) + h->dataOffset = 0; + else + return BCME_ERROR; + } + + if (h->flags & BDC_FLAG_SUM_GOOD) { + DHD_ERROR( + ("%s: BDC packet received with good rx-csum, flags 0x%x\n", + wland_ifname(dhd, *ifidx), h->flags)); + PKTSETSUMGOOD(pktbuf, true); + } + + PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); + data_offset = h->dataOffset; + PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); + + if (PKTLEN(dhd->osh, pktbuf) < (u32) (data_offset << 2)) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(dhd->osh, pktbuf), (data_offset * 4))); + return BCME_ERROR; + } +#endif /* BDC */ + + if (pktbuf->len == 0) + return -ENODATA; + + return 0; +} + +int wland_sendpkt(struct wland_if *ifp, struct sk_buff *pktbuf) +{ + struct wland_private *drvr = ifp->drvr; + struct ethhdr *eh = (struct ethhdr *) (pktbuf->data); + bool multicast = is_multicast_ether_addr(eh->h_dest); + bool pae = eh->h_proto == htons(ETH_P_PAE); + + WLAND_DBG(DCMD, TRACE, + "Enter(tx_proto:0x%X, is_multicast:%d, pae:%d)\n", + ntohs(eh->h_proto), multicast, pae); + + /* + * Update multicast statistic + */ + drvr->tx_multicast += ! !multicast; + if (pae) + atomic_inc(&ifp->pend_8021x_cnt); + + /* + * If the protocol uses a data header, apply it + */ + wland_proto_hdrpush(drvr, ifp->bssidx, pktbuf); + + /* + * Update multicast statistic + */ + if (pktbuf->len >= ETH_ALEN) { + struct ethhdr *eh = (struct ethhdr *) (pktbuf->data); + + WLAND_DBG(DCMD, TRACE, "dest: %pM\n", eh->h_dest); + WLAND_DBG(DCMD, TRACE, "source: %pM\n", eh->h_source); + if (is_multicast_ether_addr(eh->h_dest)) { + WLAND_DBG(DCMD, TRACE, "%pM is multicast ether addr\n", + eh->h_dest); + } + if (ntohs(eh->h_proto) == ETH_P_PAE) { + WLAND_DBG(DCMD, TRACE, "eh->h_proto == ETH_P_PAE\n"); + } + } + + /* + * Use bus module to send data frame + */ + return wland_bus_txdata(drvr->bus_if, pktbuf); +} + +/* setup chip */ +int wland_preinit_cmds(struct wland_if *ifp) +{ + int err = 0; + u32 u32Val = 0; + u8 u8Val = 0; + + /* + * add for qos + */ + struct wland_private *drvr = ifp->drvr; + struct wland_bus *bus_if = drvr->bus_if; + +#ifdef WLAND_POWER_MANAGER + struct wland_sdio_dev *sdiodev = drvr->bus_if->bus_priv.sdio; +#endif + + if (!ifp) { + WLAND_ERR("ifp Empty!\n"); + return -ENODEV; + } + + WLAND_DBG(DCMD, DEBUG, "Enter\n"); + + if (check_test_mode()) { + WLAND_DBG(DCMD, INFO, "In test mode and do nothing.\n"); + goto done; + } + err = wland_fil_get_cmd_data(ifp, WID_SYS_FW_VER, &u32Val, + sizeof(u32Val)); + if (err < 0) { + WLAND_ERR("Retreiving version information failed!\n"); + return -EINVAL; + } + WLAND_DBG(DCMD, DEBUG, "FirmWareVer:0x%x \n", u32Val); + + err = wland_fil_set_cmd_data(ifp, WID_MAC_ADDR, ifp->mac_addr, + ETH_ALEN); + if (err < 0) { + WLAND_ERR("set cur_etheraddr failed\n"); + goto done; + } + + WLAND_DBG(DCMD, DEBUG, "#########Set MAC Address(" MACDBG ")\n", + MAC2STRDBG(ifp->mac_addr)); + + err = wland_fil_get_cmd_data(ifp, WID_MAC_ADDR, ifp->mac_addr, + ETH_ALEN); + if (err < 0) { + WLAND_ERR("Retreiving cur_etheraddr failed, %d\n", err); + goto done; + } + + WLAND_DBG(DCMD, DEBUG, "#########Get MAC Address(" MACDBG ")\n", + MAC2STRDBG(ifp->mac_addr)); + + memcpy(ifp->drvr->mac, ifp->mac_addr, ETH_ALEN); + + u8Val = G_AUTO_PREAMBLE; + err = wland_fil_set_cmd_data(ifp, WID_PREAMBLE, &u8Val, sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set preamble failed, %d\n", err); + goto done; + } +#if 0 + u8Val = 0; + err = wland_fil_set_cmd_data(ifp, WID_PTA_MODE, &u8Val, sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set pta mode failed, %d\n", err); + goto done; + } + + err = wland_fil_set_cmd_data(ifp, WID_PTA_BLOCK_BT, &u8Val, + sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set pta block bt failed, %d\n", err); + goto done; + } +#endif + + err = wland_set_scan_timeout(ifp); + if (err < 0) { + WLAND_ERR("set_scan_timeout failed, %d\n", err); + goto done; + } + + u8Val = WIFI_LISTEN_INTERVAL; + err = wland_fil_set_cmd_data(ifp, WID_LISTEN_INTERVAL, &u8Val, + sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set_listen_interval failed, %d\n", err); + goto done; + } + + if (bus_if->chip == WLAND_VER_90_D || bus_if->chip == WLAND_VER_90_E) { + u8Val = WIFI_LINK_LOSS_THRESHOLD_90; + err = wland_fil_set_cmd_data(ifp, WID_LINK_LOSS_THRESHOLD, + &u8Val, sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set_link_loss_threshold failed, %d\n", err); + goto done; + } + } else if (bus_if->chip == WLAND_VER_91) { + u8Val = WIFI_LINK_LOSS_THRESHOLD_91; + err = wland_fil_set_cmd_data(ifp, WID_LINK_LOSS_THRESHOLD, + &u8Val, sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set_link_loss_threshold failed, %d\n", err); + goto done; + } + u8Val = 0x30; + err = wland_fil_set_cmd_data(ifp, WID_POWER_SAVE, &u8Val, + sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("Set WID_POWER_SAVE failed, %d\n", err); + goto done; + } + + } else if (bus_if->chip == WLAND_VER_91_E) { + u8Val = WIFI_LINK_LOSS_THRESHOLD_91; + err = wland_fil_set_cmd_data(ifp, WID_LINK_LOSS_THRESHOLD, + &u8Val, sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set_link_loss_threshold failed, %d\n", err); + goto done; + } + u8Val = 0x30; + err = wland_fil_set_cmd_data(ifp, WID_POWER_SAVE, &u8Val, + sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("Set WID_POWER_SAVE failed, %d\n", err); + goto done; + } + } else if (bus_if->chip == WLAND_VER_91_F) { + u8Val = WIFI_LINK_LOSS_THRESHOLD_91; + err = wland_fil_set_cmd_data(ifp, WID_LINK_LOSS_THRESHOLD, + &u8Val, sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set_link_loss_threshold failed, %d\n", err); + goto done; + } + u8Val = 0x30; + err = wland_fil_set_cmd_data(ifp, WID_POWER_SAVE, &u8Val, + sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("Set WID_POWER_SAVE failed, %d\n", err); + goto done; + } + u8Val = 0; + err = wland_fil_set_cmd_data(ifp, WID_QOS_ENABLE, &u8Val, + sizeof(u8Val)); + if (err) { + WLAND_ERR("Set WID_QOS_ENABLE failed! \n"); + goto done; + } + } else if (bus_if->chip == WLAND_VER_91_G) { + u8Val = WIFI_LINK_LOSS_THRESHOLD_91; + err = wland_fil_set_cmd_data(ifp, WID_LINK_LOSS_THRESHOLD, + &u8Val, sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("set_link_loss_threshold failed, %d\n", err); + goto done; + } + u8Val = 0x30; + err = wland_fil_set_cmd_data(ifp, WID_POWER_SAVE, &u8Val, + sizeof(u8Val)); + if (err < 0) { + WLAND_ERR("Set WID_POWER_SAVE failed, %d\n", err); + goto done; + } + u8Val = 0; + err = wland_fil_set_cmd_data(ifp, WID_QOS_ENABLE, &u8Val, + sizeof(u8Val)); + if (err) { + WLAND_ERR("wland_set_qos_enable failed! \n"); + goto done; + } + } +#ifdef WLAND_POWER_MANAGER + if (ifp->drvr->sleep_flags & WLAND_SLEEP_ENABLE) { + u8Val = MAX_FAST_PS; + err = wland_fil_set_cmd_data(ifp, WID_POWER_MANAGEMENT, &u8Val, + sizeof(u8Val)); + if (err < 0) + goto done; + } + if (ifp->drvr->sleep_flags & WLAND_SLEEP_PREASSO) { + u32Val = WIFI_PREASSO_SLEEP; + err = wland_fil_set_cmd_data(ifp, WID_PREASSO_SLEEP, &u32Val, + sizeof(u32Val)); + if (err < 0) + goto done; + } + u8Val = 1; + sdio_claim_host(sdiodev->func); + err = sdioh_request_byte(sdiodev, SDIOH_WRITE, + URSDIO_FUNC1_INT_TO_DEVICE, &u8Val); + sdio_release_host(sdiodev->func); + if (err) { + WLAND_ERR("Write URSDIO_FUNC1_INT_TO_DEVICE failed!\n"); + } +#endif /* WLAND_POWER_MANAGER */ +done: + WLAND_DBG(DCMD, DEBUG, "Done(err:%d)\n", err); + return err; +} + +int wland_start_chip(struct wland_if *ifp, u8 device_role) +{ + struct wland_private *drvr = ifp->drvr; + struct wland_sdio_dev *sdiodev = drvr->bus_if->bus_priv.sdio; + struct wland_sdio *bus = sdiodev->bus; + int err = -ENODEV; + + WLAND_DBG(DCMD, DEBUG, "Enter\n"); + if (!ifp) { + WLAND_ERR("ifp Empty!\n"); + goto fail; + } + + err = wland_bus_active(sdiodev->dev); + if (err < 0) { + WLAND_ERR("active bus failed!\n"); + goto fail; + } + + /* + * sta mode + */ + if ((device_role == 0) || (device_role == 0xA0)) { + drvr->dev_mode = false; + /* + * set up + */ + if (device_role & 0xA0) + drvr->p2p_enable = true; + else + drvr->p2p_enable = false; + } else { /* softap mode */ + + u8 val = MAC_ROLE_AP; + + drvr->dev_mode = true; + /* + * set up + */ + if (device_role & 0xA0) + drvr->p2p_enable = true; + else + drvr->p2p_enable = false; + + err = wland_fil_set_cmd_data(ifp, WID_MAC_ROLE, &val, + sizeof(u8)); + if (err < 0) { + WLAND_ERR("set preamble failed, %d\n", err); + goto fail; + } + } + + /* + * soft ap mac different with sta mac address + */ + if (drvr->dev_mode) { + /* + * revert six bit of the byte + */ + ifp->mac_addr[5] ^= (1 << (5)); + memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN); + } + + WLAND_DBG(DCMD, DEBUG, "Enter(device_role:0x%x)\n", device_role); + +#ifdef WLAND_FPGA_SUPPORT + WLAND_DBG(DCMD, TRACE, "FPGA Mode Enter\n"); +#else /*WLAND_FPGA_SUPPORT */ + WLAND_DBG(DCMD, DEBUG, "%s PATCH Enter\n", + check_test_mode()? "Test_mode" : "Nomal_mode"); + err = wland_sdio_trap_attach(drvr); + if (err < 0) { + WLAND_ERR("sdio_trap_attach failed!\n"); + goto fail; + } +#endif /* WLAND_FPGA_SUPPORT */ + + if (!check_test_mode()) { + bus->intr = true; + bus->poll = false; +#ifdef WLAND_SDIO_SUPPORT + rda_mmc_set_sdio_irq(1, true); +#endif /*WLAND_SDIO_SUPPORT */ + } + + err = wland_preinit_cmds(ifp); + if (err < 0) + WLAND_ERR("preinit cmds failed!\n"); + +fail: + WLAND_DBG(DCMD, TRACE, "Done(err:%d)\n", err); + + return err; +} diff --git a/OrangePiRDA/kernel/include/rda/tgt_ap_board_config.h b/OrangePiRDA/kernel/include/rda/tgt_ap_board_config.h index 80f5da4..9e1183e 100755 --- a/OrangePiRDA/kernel/include/rda/tgt_ap_board_config.h +++ b/OrangePiRDA/kernel/include/rda/tgt_ap_board_config.h @@ -34,10 +34,10 @@ #define _TGT_AP_SDMMC1_MAX_FREQ (50000000)/*5*/ #define _TGT_AP_SDMMC1_MCLK_INV (1) #define _TGT_AP_SDMMC1_MCLK_ADJ (1) -#define _TGT_AP_SDMMC2_MAX_FREQ (20000000)/*2*/ +#define _TGT_AP_SDMMC2_MAX_FREQ (50000000)/*5*/ #define _TGT_AP_SDMMC2_MCLK_INV (1) #define _TGT_AP_SDMMC2_MCLK_ADJ (3) -#define _TGT_AP_SDMMC3_MAX_FREQ (30000000)/*3*/ +#define _TGT_AP_SDMMC3_MAX_FREQ (50000000)/*5*/ #define _TGT_AP_SDMMC3_MCLK_ADJ (0) /* I2C clocks */ diff --git a/OrangePiRDA/kernel/sound/soc/rda/rda_dsp_aud.c b/OrangePiRDA/kernel/sound/soc/rda/rda_dsp_aud.c index 38ed42c..2b3b510 100755 --- a/OrangePiRDA/kernel/sound/soc/rda/rda_dsp_aud.c +++ b/OrangePiRDA/kernel/sound/soc/rda/rda_dsp_aud.c @@ -286,7 +286,7 @@ static int rda_gpioc_platform_probe(struct platform_device *pdev) led_trigger_register_simple(LED_CAM_FLASH, &rda_sensor_led); mdelay(5); led_trigger_event(rda_sensor_led, LED_HALF); - printk(" rda_gpioc_platform_probe22222222222222 \r\n "); + printk(KERN_INFO "rda_gpioc_platform_probe 2\n"); #endif return ret; diff --git a/OrangePiRDA/scripts/lib/build_image.sh b/OrangePiRDA/scripts/lib/build_image.sh index cd310d2..1bbfcae 100755 --- a/OrangePiRDA/scripts/lib/build_image.sh +++ b/OrangePiRDA/scripts/lib/build_image.sh @@ -5,7 +5,7 @@ build_rk_image() { } build_rda_image() { - VER="v1.24" + VER="v1.25" IMAGENAME="Legendary_OrangePi_${BOARD}_${OS}_${DISTRO}_${IMAGETYPE}_${VER}" IMAGE="${BUILD}/images/$IMAGENAME.img" diff --git a/OrangePiRDA/scripts/lib/distributions.sh b/OrangePiRDA/scripts/lib/distributions.sh index a75b7b6..fe0abd2 100755 --- a/OrangePiRDA/scripts/lib/distributions.sh +++ b/OrangePiRDA/scripts/lib/distributions.sh @@ -235,6 +235,20 @@ EOF #do_chroot /usr/bin/ssh-keygen -A } +set_locale() { + cat >"$DEST/type-phase" <"$DEST/lib/systemd/system/rc-local.service" <

Version History

    +
  1. September 26th 2022 - V1.25 - Removed deprecated default ssh options, more WiFi driver cleanup
  2. September 25th 2022 - V1.24 - Disable some WiFi crda / regulatory overrides hardcoded in drivers (there is now some regulatory activity in dmesg!). There's more work to do on it but it's definitely better than it was
  3. September 25th 2022 - V1.23 - Fixed many dmesg errors related to WiFi, rda-mmc, and others
  4. September 25th 2022 - V1.22 - Ported wireless fixes to source instead of binary driver, more distributions.sh organization into functions, add packages wireless-tools/lshw/haveged/libnl-3-dev/libnl-genl-3-dev, use rootfs caching more efficiently for rebuilding