rtl8192eu-linux-driver/os_dep/linux/rtw_android.c
Magnus Bergmark 6793baedf5
Fix strnicmp not defined in Kernel >= 4.0
This particular fix is all over the internet, as patches posted on
mailing lists, package maintainer's mirrors, etc.

I don't know the full origin of it, but it works. It also makes sense. I
found a quote regarding it here:

http://comments.gmane.org/gmane.linux.drivers.driver-project.devel/71438
> [...] patched so it will compile against kernels that no longer
> provide the old procfs API and with calls to strnicmp() replaced with
> strncasecmp().

Here's an example of the patch in the wild:
9cf1f08f9a/8192cu-dkms/RTL8192CU-kernel-4.0.patch

Note that the sources mentioned above all talk about the more common
8192cu driver, but the change is the same as both drivers share the
majority of the code with each other.
<speculation>
I guess this is part of the reason why the hardware makers don't publish
updated drivers; they've copy-pasted it everywhere and patching them all
is a pain for them.
</speculation>
2015-11-10 23:23:22 +01:00

1186 lines
30 KiB
C

/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*
******************************************************************************/
#ifdef CONFIG_GPIO_WAKEUP
#include <linux/gpio.h>
#endif
#include <drv_types.h>
#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
#include <linux/platform_device.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
#include <linux/wlan_plat.h>
#else
#include <linux/wifi_tiwlan.h>
#endif
#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
#ifdef CONFIG_GPIO_WAKEUP
#include <linux/interrupt.h>
#include <linux/irq.h>
#endif
extern void macstr2num(u8 *dst, u8 *src);
const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
"START",
"STOP",
"SCAN-ACTIVE",
"SCAN-PASSIVE",
"RSSI",
"LINKSPEED",
"RXFILTER-START",
"RXFILTER-STOP",
"RXFILTER-ADD",
"RXFILTER-REMOVE",
"BTCOEXSCAN-START",
"BTCOEXSCAN-STOP",
"BTCOEXMODE",
"SETSUSPENDOPT",
"P2P_DEV_ADDR",
"SETFWPATH",
"SETBAND",
"GETBAND",
"COUNTRY",
"P2P_SET_NOA",
"P2P_GET_NOA",
"P2P_SET_PS",
"SET_AP_WPS_P2P_IE",
#ifdef CONFIG_PNO_SUPPORT
"PNOSSIDCLR",
"PNOSETUP",
"PNOFORCE",
"PNODEBUG",
#endif
"MACADDR",
"BLOCK",
"WFD-ENABLE",
"WFD-DISABLE",
"WFD-SET-TCPPORT",
"WFD-SET-MAXTPUT",
"WFD-SET-DEVTYPE",
"SET_DTIM",
"HOSTAPD_SET_MACADDR_ACL",
"HOSTAPD_ACL_ADD_STA",
"HOSTAPD_ACL_REMOVE_STA",
#ifdef CONFIG_GTK_OL
"GTK_REKEY_OFFLOAD",
#endif //CONFIG_GTK_OL
/* Private command for P2P disable*/
"P2P_DISABLE"
};
#ifdef CONFIG_PNO_SUPPORT
#define PNO_TLV_PREFIX 'S'
#define PNO_TLV_VERSION '1'
#define PNO_TLV_SUBVERSION '2'
#define PNO_TLV_RESERVED '0'
#define PNO_TLV_TYPE_SSID_IE 'S'
#define PNO_TLV_TYPE_TIME 'T'
#define PNO_TLV_FREQ_REPEAT 'R'
#define PNO_TLV_FREQ_EXPO_MAX 'M'
typedef struct cmd_tlv {
char prefix;
char version;
char subver;
char reserved;
} cmd_tlv_t;
#ifdef CONFIG_PNO_SET_DEBUG
char pno_in_example[] = {
'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
'S', '1', '2', '0',
'S', //1
0x05,
'd', 'l', 'i', 'n', 'k',
'S', //2
0x06,
'B', 'U', 'F', 'B', 'U','F',
'S', //3
0x20,
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '!', '@', '#', '$', '%', '^',
'S', //4
0x0a,
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
'T',
'0', '5',
'R',
'2',
'M',
'2',
0x00
};
#endif /* CONFIG_PNO_SET_DEBUG */
#endif /* PNO_SUPPORT */
typedef struct android_wifi_priv_cmd {
#ifdef CONFIG_COMPAT
compat_uptr_t buf;
#else
char *buf;
#endif
int used_len;
int total_len;
} android_wifi_priv_cmd;
/**
* Local (static) functions and variables
*/
/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
* time (only) in dhd_open, subsequential wifi on will be handled by
* wl_android_wifi_on
*/
static int g_wifi_on = _TRUE;
unsigned int oob_irq;
#ifdef CONFIG_PNO_SUPPORT
/*
* rtw_android_pno_setup
* Description:
* This is used for private command.
*
* Parameter:
* net: net_device
* command: parameters from private command
* total_len: the length of the command.
*
* */
static int rtw_android_pno_setup(struct net_device *net, char *command, int total_len) {
pno_ssid_t pno_ssids_local[MAX_PNO_LIST_COUNT];
int res = -1;
int nssid = 0;
cmd_tlv_t *cmd_tlv_temp;
char *str_ptr;
int tlv_size_left;
int pno_time = 0;
int pno_repeat = 0;
int pno_freq_expo_max = 0;
int cmdlen = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_PNOSETUP_SET]) + 1;
#ifdef CONFIG_PNO_SET_DEBUG
int i;
char *p;
p = pno_in_example;
total_len = sizeof(pno_in_example);
str_ptr = p + cmdlen;
#else
str_ptr = command + cmdlen;
#endif
if (total_len < (cmdlen + sizeof(cmd_tlv_t))) {
DBG_871X("%s argument=%d less min size\n", __func__, total_len);
goto exit_proc;
}
tlv_size_left = total_len - cmdlen;
cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
memset(pno_ssids_local, 0, sizeof(pno_ssids_local));
if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
(cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
str_ptr += sizeof(cmd_tlv_t);
tlv_size_left -= sizeof(cmd_tlv_t);
if ((nssid = rtw_parse_ssid_list_tlv(&str_ptr, pno_ssids_local,
MAX_PNO_LIST_COUNT, &tlv_size_left)) <= 0) {
DBG_871X("SSID is not presented or corrupted ret=%d\n", nssid);
goto exit_proc;
} else {
if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
DBG_871X("%s scan duration corrupted field size %d\n",
__func__, tlv_size_left);
goto exit_proc;
}
str_ptr++;
pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
DBG_871X("%s: pno_time=%d\n", __func__, pno_time);
if (str_ptr[0] != 0) {
if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
DBG_871X("%s pno repeat : corrupted field\n",
__func__);
goto exit_proc;
}
str_ptr++;
pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
DBG_871X("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat);
if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
DBG_871X("%s FREQ_EXPO_MAX corrupted field size\n",
__func__);
goto exit_proc;
}
str_ptr++;
pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
DBG_871X("%s: pno_freq_expo_max=%d\n",
__func__, pno_freq_expo_max);
}
}
} else {
DBG_871X("%s get wrong TLV command\n", __FUNCTION__);
goto exit_proc;
}
res = rtw_dev_pno_set(net, pno_ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
#ifdef CONFIG_PNO_SET_DEBUG
rtw_dev_pno_debug(net);
#endif
exit_proc:
return res;
}
/*
* rtw_android_cfg80211_pno_setup
* Description:
* This is used for cfg80211 sched_scan.
*
* Parameter:
* net: net_device
* request: cfg80211_request
* */
int rtw_android_cfg80211_pno_setup(struct net_device *net,
struct cfg80211_ssid *ssids, int n_ssids, int interval) {
int res = -1;
int nssid = 0;
int pno_time = 0;
int pno_repeat = 0;
int pno_freq_expo_max = 0;
int index = 0;
pno_ssid_t pno_ssids_local[MAX_PNO_LIST_COUNT];
if (n_ssids > MAX_PNO_LIST_COUNT || n_ssids < 0) {
DBG_871X("%s: nssids(%d) is invalid.\n", __func__, n_ssids);
return -EINVAL;
}
memset(pno_ssids_local, 0, sizeof(pno_ssids_local));
nssid = n_ssids;
for (index = 0 ; index < nssid ; index++) {
pno_ssids_local[index].SSID_len = ssids[index].ssid_len;
memcpy(pno_ssids_local[index].SSID, ssids[index].ssid,
ssids[index].ssid_len);
}
pno_time = (interval / 1000);
DBG_871X("%s: nssids: %d, pno_time=%d\n", __func__, nssid, pno_time);
res = rtw_dev_pno_set(net, pno_ssids_local, nssid, pno_time,
pno_repeat, pno_freq_expo_max);
exit_proc:
return res;
}
int rtw_android_pno_enable(struct net_device *net, int pno_enable) {
_adapter *padapter = (_adapter *)rtw_netdev_priv(net);
struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
if (pwrctl) {
pwrctl->wowlan_pno_enable = pno_enable;
DBG_871X("%s: wowlan_pno_enable: %d\n", __func__, pwrctl->wowlan_pno_enable);
if (pwrctl->wowlan_pno_enable == 0) {
if (pwrctl->pnlo_info != NULL) {
rtw_mfree((u8 *)pwrctl->pnlo_info, sizeof(pno_nlo_info_t));
pwrctl->pnlo_info = NULL;
}
if (pwrctl->pno_ssid_list != NULL) {
rtw_mfree((u8 *)pwrctl->pno_ssid_list, sizeof(pno_ssid_list_t));
pwrctl->pno_ssid_list = NULL;
}
if (pwrctl->pscan_info != NULL) {
rtw_mfree((u8 *)pwrctl->pscan_info, sizeof(pno_scan_info_t));
pwrctl->pscan_info = NULL;
}
}
return 0;
} else {
return -1;
}
}
#endif //CONFIG_PNO_SUPPORT
int rtw_android_cmdstr_to_num(char *cmdstr)
{
int cmd_num;
for(cmd_num=0 ; cmd_num<ANDROID_WIFI_CMD_MAX; cmd_num++)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
if(!strncasecmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])) )
#else
if(0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])) )
#endif
break;
return cmd_num;
}
int rtw_android_get_rssi(struct net_device *net, char *command, int total_len)
{
_adapter *padapter = (_adapter *)rtw_netdev_priv(net);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct wlan_network *pcur_network = &pmlmepriv->cur_network;
int bytes_written = 0;
if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d",
pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi);
}
return bytes_written;
}
int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len)
{
_adapter *padapter = (_adapter *)rtw_netdev_priv(net);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct wlan_network *pcur_network = &pmlmepriv->cur_network;
int bytes_written = 0;
u16 link_speed = 0;
link_speed = rtw_get_cur_max_rate(padapter)/10;
bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
return bytes_written;
}
int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
int bytes_written = 0;
bytes_written = snprintf(command, total_len, "Macaddr = "MAC_FMT, MAC_ARG(net->dev_addr));
return bytes_written;
}
int rtw_android_set_country(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
int ret = _FAIL;
ret = rtw_set_country(adapter, country_code);
return (ret==_SUCCESS)?0:-1;
}
int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len)
{
int bytes_written = 0;
//We use the same address as our HW MAC address
_rtw_memcpy(command, net->dev_addr, ETH_ALEN);
bytes_written = ETH_ALEN;
return bytes_written;
}
int rtw_android_set_block(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK]) + 1;
#ifdef CONFIG_IOCTL_CFG80211
adapter_wdev_data(adapter)->block = (*block_value=='0')?_FALSE:_TRUE;
#endif
return 0;
}
int rtw_android_setband(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
char *arg = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SETBAND]) + 1;
u32 band = GHZ_MAX;
int ret = _FAIL;
sscanf(arg, "%u", &band);
ret = rtw_set_band(adapter, band);
return (ret==_SUCCESS)?0:-1;
}
int rtw_android_getband(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
int bytes_written = 0;
bytes_written = snprintf(command, total_len, "%u", adapter->setband);
return bytes_written;
}
int get_int_from_command( char* pcmd )
{
int i = 0;
for( i = 0; i < strlen( pcmd ); i++ )
{
if ( pcmd[ i ] == '=' )
{
// Skip the '=' and space characters.
i += 2;
break;
}
}
return ( rtw_atoi( pcmd + i ) );
}
#ifdef CONFIG_GTK_OL
int rtw_gtk_offload(struct net_device *net, u8 *cmd_ptr)
{
int i;
//u8 *cmd_ptr = priv_cmd.buf;
struct sta_info * psta;
_adapter *padapter = (_adapter *)rtw_netdev_priv(net);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
struct security_priv* psecuritypriv=&(padapter->securitypriv);
psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
if (psta == NULL)
{
DBG_8192C("%s, : Obtain Sta_info fail \n", __func__);
}
else
{
//string command length of "GTK_REKEY_OFFLOAD"
cmd_ptr += 18;
_rtw_memcpy(psta->kek, cmd_ptr, RTW_KEK_LEN);
cmd_ptr += RTW_KEK_LEN;
/*
printk("supplicant KEK: ");
for(i=0;i<RTW_KEK_LEN; i++)
printk(" %02x ", psta->kek[i]);
printk("\n supplicant KCK: ");
*/
_rtw_memcpy(psta->kck, cmd_ptr, RTW_KCK_LEN);
cmd_ptr += RTW_KCK_LEN;
/*
for(i=0;i<RTW_KEK_LEN; i++)
printk(" %02x ", psta->kck[i]);
*/
_rtw_memcpy(psta->replay_ctr, cmd_ptr, RTW_REPLAY_CTR_LEN);
psecuritypriv->binstallKCK_KEK = _TRUE;
//printk("\nREPLAY_CTR: ");
//for(i=0;i<RTW_REPLAY_CTR_LEN; i++)
//printk(" %02x ", psta->replay_ctr[i]);
}
return _SUCCESS;
}
#endif //CONFIG_GTK_OL
int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
{
int ret = 0;
char *command = NULL;
int cmd_num;
int bytes_written = 0;
#ifdef CONFIG_PNO_SUPPORT
uint cmdlen = 0;
uint pno_enable = 0;
#endif
android_wifi_priv_cmd priv_cmd;
_adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
#ifdef CONFIG_WFD
struct wifi_display_info *pwfd_info;
#endif
rtw_lock_suspend();
if (!ifr->ifr_data) {
ret = -EINVAL;
goto exit;
}
if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
ret = -EFAULT;
goto exit;
}
if ( padapter->registrypriv.mp_mode == 1) {
ret = -EFAULT;
goto exit;
}
//DBG_871X("%s priv_cmd.buf=%p priv_cmd.total_len=%d priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len);
command = rtw_zmalloc(priv_cmd.total_len);
if (!command)
{
DBG_871X("%s: failed to allocate memory\n", __FUNCTION__);
ret = -ENOMEM;
goto exit;
}
if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)){
DBG_871X("%s: failed to access memory\n", __FUNCTION__);
ret = -EFAULT;
goto exit;
}
#ifdef CONFIG_COMPAT
if (copy_from_user(command, compat_ptr(priv_cmd.buf), (unsigned long) priv_cmd.total_len)) {
#else
if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) {
#endif
ret = -EFAULT;
goto exit;
}
DBG_871X("%s: Android private cmd \"%s\" on %s\n"
, __FUNCTION__, command, ifr->ifr_name);
cmd_num = rtw_android_cmdstr_to_num(command);
switch(cmd_num) {
case ANDROID_WIFI_CMD_START:
//bytes_written = wl_android_wifi_on(net);
goto response;
case ANDROID_WIFI_CMD_SETFWPATH:
goto response;
}
if (!g_wifi_on) {
DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n"
,__FUNCTION__, command, ifr->ifr_name);
ret = 0;
goto exit;
}
switch(cmd_num) {
case ANDROID_WIFI_CMD_STOP:
//bytes_written = wl_android_wifi_off(net);
break;
case ANDROID_WIFI_CMD_SCAN_ACTIVE:
//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE);
#ifdef CONFIG_PLATFORM_MSTAR
#ifdef CONFIG_IOCTL_CFG80211
adapter_wdev_data((_adapter *)rtw_netdev_priv(net))->bandroid_scan = _TRUE;
#endif //CONFIG_IOCTL_CFG80211
#endif //CONFIG_PLATFORM_MSTAR
break;
case ANDROID_WIFI_CMD_SCAN_PASSIVE:
//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE);
break;
case ANDROID_WIFI_CMD_RSSI:
bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_LINKSPEED:
bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_MACADDR:
bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_BLOCK:
bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_RXFILTER_START:
//bytes_written = net_os_set_packet_filter(net, 1);
break;
case ANDROID_WIFI_CMD_RXFILTER_STOP:
//bytes_written = net_os_set_packet_filter(net, 0);
break;
case ANDROID_WIFI_CMD_RXFILTER_ADD:
//int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
//bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
break;
case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
//int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
//bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
break;
case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
/* TBD: BTCOEXSCAN-START */
break;
case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
/* TBD: BTCOEXSCAN-STOP */
break;
case ANDROID_WIFI_CMD_BTCOEXMODE:
#if 0
uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
if (mode == 1)
net_os_set_packet_filter(net, 0); /* DHCP starts */
else
net_os_set_packet_filter(net, 1); /* DHCP ends */
#ifdef WL_CFG80211
bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
#endif
#endif
break;
case ANDROID_WIFI_CMD_SETSUSPENDOPT:
//bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_SETBAND:
bytes_written = rtw_android_setband(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_GETBAND:
bytes_written = rtw_android_getband(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_COUNTRY:
bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
break;
#ifdef CONFIG_PNO_SUPPORT
case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
//bytes_written = dhd_dev_pno_reset(net);
break;
case ANDROID_WIFI_CMD_PNOSETUP_SET:
bytes_written = rtw_android_pno_setup(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_PNOENABLE_SET:
cmdlen = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_PNOENABLE_SET]);
pno_enable = *(command + cmdlen + 1) - '0';
bytes_written = rtw_android_pno_enable(net, pno_enable);
break;
#endif
case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_P2P_SET_NOA:
//int skip = strlen(CMD_P2P_SET_NOA) + 1;
//bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip);
break;
case ANDROID_WIFI_CMD_P2P_GET_NOA:
//bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_P2P_SET_PS:
//int skip = strlen(CMD_P2P_SET_PS) + 1;
//bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip);
break;
#ifdef CONFIG_IOCTL_CFG80211
case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE:
{
int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
break;
}
#endif //CONFIG_IOCTL_CFG80211
#ifdef CONFIG_WFD
case ANDROID_WIFI_CMD_WFD_ENABLE:
{
// Commented by Albert 2012/07/24
// We can enable the WFD function by using the following command:
// wpa_cli driver wfd-enable
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->wfd_enable = _TRUE;
break;
}
case ANDROID_WIFI_CMD_WFD_DISABLE:
{
// Commented by Albert 2012/07/24
// We can disable the WFD function by using the following command:
// wpa_cli driver wfd-disable
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->wfd_enable = _FALSE;
break;
}
case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
{
// Commented by Albert 2012/07/24
// We can set the tcp port number by using the following command:
// wpa_cli driver wfd-set-tcpport = 554
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
{
#ifdef CONFIG_COMPAT
pwfd_info->rtsp_ctrlport = ( u16 ) get_int_from_command( compat_ptr(priv_cmd.buf) );
#else
pwfd_info->rtsp_ctrlport = ( u16 ) get_int_from_command( priv_cmd.buf );
#endif
}
break;
}
case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
{
break;
}
case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
{
// Commented by Albert 2012/08/28
// Specify the WFD device type ( WFD source/primary sink )
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
{
#ifdef CONFIG_COMPAT
pwfd_info->wfd_device_type = ( u8 ) get_int_from_command( compat_ptr(priv_cmd.buf) );
#else
pwfd_info->wfd_device_type = ( u8 ) get_int_from_command( priv_cmd.buf );
#endif
pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
}
break;
}
#endif
case ANDROID_WIFI_CMD_CHANGE_DTIM:
{
#ifdef CONFIG_LPS
u8 dtim;
u8 *ptr = (u8 *) &priv_cmd.buf;
ptr += 9;//string command length of "SET_DTIM";
dtim = rtw_atoi(ptr);
DBG_871X("DTIM=%d\n", dtim);
rtw_lps_change_dtim_cmd(padapter, dtim);
#endif
}
break;
case ANDROID_WIFI_CMD_HOSTAPD_SET_MACADDR_ACL:
{
padapter->stapriv.acl_list.mode = ( u8 ) get_int_from_command(command);
DBG_871X("%s ANDROID_WIFI_CMD_HOSTAPD_SET_MACADDR_ACL mode:%d\n", __FUNCTION__, padapter->stapriv.acl_list.mode);
break;
}
case ANDROID_WIFI_CMD_HOSTAPD_ACL_ADD_STA:
{
u8 addr[ETH_ALEN] = {0x00};
macstr2num(addr, command+strlen("HOSTAPD_ACL_ADD_STA")+3); // 3 is space bar + "=" + space bar these 3 chars
rtw_acl_add_sta(padapter, addr);
break;
}
case ANDROID_WIFI_CMD_HOSTAPD_ACL_REMOVE_STA:
{
u8 addr[ETH_ALEN] = {0x00};
macstr2num(addr, command+strlen("HOSTAPD_ACL_REMOVE_STA")+3); // 3 is space bar + "=" + space bar these 3 chars
rtw_acl_remove_sta(padapter, addr);
break;
}
#ifdef CONFIG_GTK_OL
case ANDROID_WIFI_CMD_GTK_REKEY_OFFLOAD:
rtw_gtk_offload(net, priv_cmd.buf);
break;
#endif //CONFIG_GTK_OL
case ANDROID_WIFI_CMD_P2P_DISABLE:
{
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct wifidirect_info *pwdinfo= &(padapter->wdinfo);
u8 channel, ch_offset;
u16 bwmode;
rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
break;
}
default:
DBG_871X("Unknown PRIVATE command %s - ignored\n", command);
snprintf(command, 3, "OK");
bytes_written = strlen("OK");
}
response:
if (bytes_written >= 0) {
if ((bytes_written == 0) && (priv_cmd.total_len > 0))
command[0] = '\0';
if (bytes_written >= priv_cmd.total_len) {
DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
bytes_written = priv_cmd.total_len;
} else {
bytes_written++;
}
priv_cmd.used_len = bytes_written;
#ifdef CONFIG_COMPAT
if (copy_to_user(compat_ptr(priv_cmd.buf), command, bytes_written)) {
#else
if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) {
#endif
DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__);
ret = -EFAULT;
}
}
else {
ret = bytes_written;
}
exit:
rtw_unlock_suspend();
if (command) {
rtw_mfree(command, priv_cmd.total_len);
}
return ret;
}
/**
* Functions for Android WiFi card detection
*/
#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
static int g_wifidev_registered = 0;
static struct semaphore wifi_control_sem;
static struct wifi_platform_data *wifi_control_data = NULL;
static struct resource *wifi_irqres = NULL;
static int wifi_add_dev(void);
static void wifi_del_dev(void);
int rtw_android_wifictrl_func_add(void)
{
int ret = 0;
sema_init(&wifi_control_sem, 0);
ret = wifi_add_dev();
if (ret) {
DBG_871X("%s: platform_driver_register failed\n", __FUNCTION__);
return ret;
}
g_wifidev_registered = 1;
/* Waiting callback after platform_driver_register is done or exit with error */
if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) {
ret = -EINVAL;
DBG_871X("%s: platform_driver_register timeout\n", __FUNCTION__);
}
return ret;
}
void rtw_android_wifictrl_func_del(void)
{
if (g_wifidev_registered)
{
wifi_del_dev();
g_wifidev_registered = 0;
}
}
void *wl_android_prealloc(int section, unsigned long size)
{
void *alloc_ptr = NULL;
if (wifi_control_data && wifi_control_data->mem_prealloc) {
alloc_ptr = wifi_control_data->mem_prealloc(section, size);
if (alloc_ptr) {
DBG_871X("success alloc section %d\n", section);
if (size != 0L)
memset(alloc_ptr, 0, size);
return alloc_ptr;
}
}
DBG_871X("can't alloc section %d\n", section);
return NULL;
}
int wifi_get_irq_number(unsigned long *irq_flags_ptr)
{
if (wifi_irqres) {
*irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
return (int)wifi_irqres->start;
}
#ifdef CUSTOM_OOB_GPIO_NUM
return CUSTOM_OOB_GPIO_NUM;
#else
return -1;
#endif
}
int wifi_set_power(int on, unsigned long msec)
{
DBG_871X("%s = %d\n", __FUNCTION__, on);
if (wifi_control_data && wifi_control_data->set_power) {
wifi_control_data->set_power(on);
}
if (msec)
msleep(msec);
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
int wifi_get_mac_addr(unsigned char *buf)
{
DBG_871X("%s\n", __FUNCTION__);
if (!buf)
return -EINVAL;
if (wifi_control_data && wifi_control_data->get_mac_addr) {
return wifi_control_data->get_mac_addr(buf);
}
return -EOPNOTSUPP;
}
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) || defined(COMPAT_KERNEL_RELEASE)
void *wifi_get_country_code(char *ccode)
{
DBG_871X("%s\n", __FUNCTION__);
if (!ccode)
return NULL;
if (wifi_control_data && wifi_control_data->get_country_code) {
return wifi_control_data->get_country_code(ccode);
}
return NULL;
}
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
static int wifi_set_carddetect(int on)
{
DBG_871X("%s = %d\n", __FUNCTION__, on);
if (wifi_control_data && wifi_control_data->set_carddetect) {
wifi_control_data->set_carddetect(on);
}
return 0;
}
static int wifi_probe(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
(struct wifi_platform_data *)(pdev->dev.platform_data);
int wifi_wake_gpio = 0;
DBG_871X("## %s\n", __FUNCTION__);
wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
if (wifi_irqres == NULL)
wifi_irqres = platform_get_resource_byname(pdev,
IORESOURCE_IRQ, "bcm4329_wlan_irq");
else
wifi_wake_gpio = wifi_irqres->start;
#ifdef CONFIG_GPIO_WAKEUP
printk("%s: gpio:%d wifi_wake_gpio:%d\n", __func__,
wifi_irqres->start, wifi_wake_gpio);
if (wifi_wake_gpio > 0) {
gpio_request(wifi_wake_gpio, "oob_irq");
gpio_direction_input(wifi_wake_gpio);
oob_irq = gpio_to_irq(wifi_wake_gpio);
printk("%s oob_irq:%d\n", __func__, oob_irq);
}
else if(wifi_irqres)
{
oob_irq = wifi_irqres->start;
printk("%s oob_irq:%d\n", __func__, oob_irq);
}
#endif
wifi_control_data = wifi_ctrl;
wifi_set_power(1, 0); /* Power On */
wifi_set_carddetect(1); /* CardDetect (0->1) */
up(&wifi_control_sem);
return 0;
}
#ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
extern PADAPTER g_test_adapter;
static void shutdown_card(void)
{
u32 addr;
u8 tmp8, cnt=0;
if (NULL == g_test_adapter)
{
DBG_871X("%s: padapter==NULL\n", __FUNCTION__);
return;
}
#ifdef CONFIG_FWLPS_IN_IPS
LeaveAllPowerSaveMode(g_test_adapter);
#endif // CONFIG_FWLPS_IN_IPS
// Leave SDIO HCI Suspend
addr = 0x10250086;
rtw_write8(g_test_adapter, addr, 0);
do {
tmp8 = rtw_read8(g_test_adapter, addr);
cnt++;
DBG_871X(FUNC_ADPT_FMT ": polling SDIO_HSUS_CTRL(0x%x)=0x%x, cnt=%d\n",
FUNC_ADPT_ARG(g_test_adapter), addr, tmp8, cnt);
if (tmp8 & BIT(1))
break;
if (cnt >= 100)
{
DBG_871X(FUNC_ADPT_FMT ": polling 0x%x[1]==1 FAIL!!\n",
FUNC_ADPT_ARG(g_test_adapter), addr);
break;
}
rtw_mdelay_os(10);
} while (1);
// unlock register I/O
rtw_write8(g_test_adapter, 0x1C, 0);
// enable power down function
// 0x04[4] = 1
// 0x05[7] = 1
addr = 0x04;
tmp8 = rtw_read8(g_test_adapter, addr);
tmp8 |= BIT(4);
rtw_write8(g_test_adapter, addr, tmp8);
DBG_871X(FUNC_ADPT_FMT ": read after write 0x%x=0x%x\n",
FUNC_ADPT_ARG(g_test_adapter), addr, rtw_read8(g_test_adapter, addr));
addr = 0x05;
tmp8 = rtw_read8(g_test_adapter, addr);
tmp8 |= BIT(7);
rtw_write8(g_test_adapter, addr, tmp8);
DBG_871X(FUNC_ADPT_FMT ": read after write 0x%x=0x%x\n",
FUNC_ADPT_ARG(g_test_adapter), addr, rtw_read8(g_test_adapter, addr));
// lock register page0 0x0~0xB read/write
rtw_write8(g_test_adapter, 0x1C, 0x0E);
g_test_adapter->bSurpriseRemoved = _TRUE;
DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved=%d\n",
FUNC_ADPT_ARG(g_test_adapter), g_test_adapter->bSurpriseRemoved);
#ifdef CONFIG_CONCURRENT_MODE
if (g_test_adapter->pbuddy_adapter)
{
PADAPTER pbuddy;
pbuddy = g_test_adapter->pbuddy_adapter;
pbuddy->bSurpriseRemoved = _TRUE;
DBG_871X(FUNC_ADPT_FMT ": buddy(" ADPT_FMT ") bSurpriseRemoved=%d\n",
FUNC_ADPT_ARG(g_test_adapter), ADPT_ARG(pbuddy), pbuddy->bSurpriseRemoved);
}
#endif // CONFIG_CONCURRENT_MODE
}
#endif // RTW_SUPPORT_PLATFORM_SHUTDOWN
static int wifi_remove(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
(struct wifi_platform_data *)(pdev->dev.platform_data);
DBG_871X("## %s\n", __FUNCTION__);
wifi_control_data = wifi_ctrl;
wifi_set_power(0, 0); /* Power Off */
wifi_set_carddetect(0); /* CardDetect (1->0) */
up(&wifi_control_sem);
return 0;
}
#ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
static void wifi_shutdown(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
(struct wifi_platform_data *)(pdev->dev.platform_data);
DBG_871X("## %s\n", __FUNCTION__);
wifi_control_data = wifi_ctrl;
shutdown_card();
wifi_set_power(0, 0); /* Power Off */
wifi_set_carddetect(0); /* CardDetect (1->0) */
}
#endif // RTW_SUPPORT_PLATFORM_SHUTDOWN
static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
{
DBG_871X("##> %s\n", __FUNCTION__);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
bcmsdh_oob_intr_set(0);
#endif
return 0;
}
static int wifi_resume(struct platform_device *pdev)
{
DBG_871X("##> %s\n", __FUNCTION__);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
bcmsdh_oob_intr_set(1);
#endif
return 0;
}
/* temporarily use these two */
static struct platform_driver wifi_device = {
.probe = wifi_probe,
.remove = wifi_remove,
.suspend = wifi_suspend,
.resume = wifi_resume,
#ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
.shutdown = wifi_shutdown,
#endif // RTW_SUPPORT_PLATFORM_SHUTDOWN
.driver = {
.name = "bcmdhd_wlan",
}
};
static struct platform_driver wifi_device_legacy = {
.probe = wifi_probe,
.remove = wifi_remove,
.suspend = wifi_suspend,
.resume = wifi_resume,
.driver = {
.name = "bcm4329_wlan",
}
};
static int wifi_add_dev(void)
{
DBG_871X("## Calling platform_driver_register\n");
platform_driver_register(&wifi_device);
platform_driver_register(&wifi_device_legacy);
return 0;
}
static void wifi_del_dev(void)
{
DBG_871X("## Unregister platform_driver_register\n");
platform_driver_unregister(&wifi_device);
platform_driver_unregister(&wifi_device_legacy);
}
#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */