diff options
Diffstat (limited to 'drivers/net/wireless/eswin/ecrnx_iwpriv.c')
-rw-r--r-- | drivers/net/wireless/eswin/ecrnx_iwpriv.c | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/drivers/net/wireless/eswin/ecrnx_iwpriv.c b/drivers/net/wireless/eswin/ecrnx_iwpriv.c new file mode 100644 index 000000000000..037fe56246a3 --- /dev/null +++ b/drivers/net/wireless/eswin/ecrnx_iwpriv.c @@ -0,0 +1,396 @@ +/** + ****************************************************************************** + * + * @file ecrnx_iwpriv.c + * + * @brief iwpriv function definitions + * + * Copyright (C) ESWIN 2015-2020 + * + ****************************************************************************** + */ + +/** + * INCLUDE FILES + ****************************************************************************** + */ +#include <net/cfg80211.h> +#include <net/iw_handler.h> +#include "ecrnx_defs.h" +#include "eswin_utils.h" + +#ifdef CONFIG_ECRNX_WIFO_CAIL +#include "ecrnx_amt.h" +#include "core.h" +#endif + +#ifdef CONFIG_WIRELESS_EXT +/** + * FUNCTION DEFINITIONS + ****************************************************************************** + */ +#define IN +#define OUT + +#ifdef CONFIG_WEXT_PRIV + /* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably + * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root + * only and don't return the modified struct ifreq to the application which + * is usually a problem. - Jean II */ +#ifdef CONFIG_ECRNX_WIFO_CAIL +#define IOCTL_IWPRIV_AMT (SIOCIWFIRSTPRIV + 1) +#endif +#define IOCTL_IWPRIV_WD (SIOCIWFIRSTPRIV + 3) + +#if 0 +static int priv_set_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + int *flag = (int*)pcExtra; + ECRNX_PRINT("cmd=%x, flags=%x\n", + prIwReqInfo->cmd, prIwReqInfo->flags); + ECRNX_PRINT("mode=%x, flags=%x\n", + prIwReqData->mode, prIwReqData->data.flags); + *flag = 0x1234; + prIwReqData->param.value = 0x1230; + + return 1; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl get int handler. +* +* \param[in] pDev Net device requested. +* \param[out] pIwReq Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. +* \param[out] pcExtra The buffer with put the return value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +static int priv_get_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + int status = 0; + prIwReqData->mode = 0xabcd; + return status; +} /* __priv_get_int */ + +static int priv_set_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + ECRNX_PRINT("cmd=%x, flags=%x\n", + prIwReqInfo->cmd, prIwReqInfo->flags); + ECRNX_PRINT("mode=%x, flags=%x\n", + prIwReqData->mode, prIwReqData->data.flags); + + return 0; + //return compat_priv(prNetDev, prIwReqInfo, + // prIwReqData, pcExtra, __priv_set_struct); +} + +static int priv_get_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + ECRNX_PRINT("cmd=%x, flags=%x\n", + prIwReqInfo->cmd, prIwReqInfo->flags); + ECRNX_PRINT("mode=%x, flags=%x\n", + prIwReqData->mode, prIwReqData->data.flags); + + prIwReqData->data.length = 6; + memcpy(pcExtra, "ecrnx", 6); + return 0; + +} + +static int priv_get_mac(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + struct sockaddr *dst = (struct sockaddr *) pcExtra; + struct ecrnx_vif *vif; + dbg_req_t req; + + req.dbg_level = DBG_TYPE_D; + req.direct = 0; + + vif = netdev_priv(prNetDev); + //send cmd to slave + ECRNX_PRINT("priv_get_mac: send cmd to slave \n"); + host_send(&req, sizeof(dbg_req_t), TX_FLAG_IWPRIV_IE); + //wait for slave confirm + vif->rxdatas = 0; + wait_event_interruptible_timeout(vif->rxdataq, vif->rxdatas, 2*HZ); + + ECRNX_PRINT("priv_get_mac: rx_len:%d \n", vif->rxlen); + if (!vif->rxlen) + return -1; + + prIwReqData->data.length = vif->rxlen; + memcpy(dst->sa_data, vif->rxdata, vif->rxlen); + dst->sa_family = 1; + prIwReqData->data.length = 1; + + return 0; +} + +static int priv_get_vers(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + ECRNX_PRINT("get vers cmd=%x, flags=%x\n", prIwReqInfo->cmd, prIwReqInfo->flags); + ECRNX_PRINT("mode=%x, flags=%x\n", prIwReqData->mode, prIwReqData->data.flags); + + memcpy(pcExtra, "1.0.1", 6); + prIwReqData->data.length = 6; + + return 0; +} + + +static int priv_set_debug_level(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + ECRNX_PRINT("priv_set_debug_level cmd=%x, flags=%x\n", + prIwReqInfo->cmd, prIwReqInfo->flags); + ECRNX_PRINT("mode=%x, flags=%x\n", + prIwReqData->mode, prIwReqData->data.flags); + + ECRNX_PRINT("param_value:%d \n", prIwReqData->param.value); + + ecrnx_dbg_level = prIwReqData->param.value; + return 0; +} +#endif + +#ifdef CONFIG_ECRNX_WIFO_CAIL +static int priv_amt(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + struct sockaddr *dst = (struct sockaddr *) pcExtra; + + if (amt_mode == false) { + ECRNX_ERR(" The current mode does not support the AMT commands!!\n"); + return -1; + } +// printk("buff:%s, len:%d\n", prIwReqData->data.pointer, prIwReqData->data.length); + //send cmd to slave + char *reqdata = kzalloc(prIwReqData->data.length, GFP_KERNEL); + if (!reqdata){ + return 0; + } + if (copy_from_user(reqdata, prIwReqData->data.pointer, prIwReqData->data.length)) { + return 0; + } + host_send(reqdata, prIwReqData->data.length, TX_FLAG_AMT_IWPRIV_IE); + kfree(reqdata); + + //wait for slave confirm + amt_vif.rxdatas = 0; + amt_vif.rxlen = 0; + + wait_event_interruptible_timeout(amt_vif.rxdataq, amt_vif.rxdatas, 2*HZ); + + ECRNX_PRINT("rxdatas: rx_len:%d, rxdata:[%s]\n", amt_vif.rxlen,amt_vif.rxdata); + if (!amt_vif.rxdatas){ + return -1; + } + + prIwReqData->data.length = amt_vif.rxlen; + memcpy(dst->sa_data, amt_vif.rxdata, amt_vif.rxlen); + dst->sa_family = 1; + memcpy(pcExtra, amt_vif.rxdata, amt_vif.rxlen); + + return 0; +} +#endif + +static struct ecrnx_vif *get_priv_vif(struct ecrnx_hw *ecrnx_hw) +{ + return ecrnx_hw->vif_table[0]; +} + +void priv_copy_data_wakeup(struct ecrnx_hw *ecrnx_hw, struct sk_buff *skb) +{ + struct ecrnx_vif* ecrnx_vif = get_priv_vif(ecrnx_hw); + + ECRNX_PRINT("iw_cfm vif_start:%d, vif_monitor:%d \n", ecrnx_hw->vif_started, ecrnx_hw->monitor_vif); + //print_hex_dump(KERN_INFO, DBG_PREFIX_IW_CFM, DUMP_PREFIX_ADDRESS, 32, 1, skb->data, skb->len, false); + if (ECRNX_RXSIZE > skb->len) { + ecrnx_vif->rxlen = skb->len; + } else { + ecrnx_vif->rxlen = ECRNX_RXSIZE; + } + + memcpy(ecrnx_vif->rxdata, skb->data, ecrnx_vif->rxlen); + ecrnx_vif->rxdatas = 1; + wake_up(&ecrnx_vif->rxdataq); +} + +static int priv_wd(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + struct sockaddr *dst = (struct sockaddr *) pcExtra; + struct ecrnx_vif *vif; + + //printk("priv_wd:%s, len:%d\n", prIwReqData->data.pointer, prIwReqData->data.length); + //send cmd to slave + char *reqdata = kzalloc(prIwReqData->data.length, GFP_KERNEL); + if (!reqdata){ + return 0; + } + + if (copy_from_user(reqdata, prIwReqData->data.pointer, prIwReqData->data.length)) { + return 0; + } + host_send(reqdata, prIwReqData->data.length, TX_FLAG_IWPRIV_IE); + kfree(reqdata); + + //wait for slave confirm + vif = netdev_priv(prNetDev); + vif = get_priv_vif(vif->ecrnx_hw); + vif->rxdatas = 0; + wait_event_interruptible_timeout(vif->rxdataq, vif->rxdatas, 2*HZ); + + if (!vif->rxdatas) + return -1; + + ECRNX_PRINT("priv_wd: rx_len:%d rxdata:[%s]\n", vif->rxlen, vif->rxdata); + prIwReqData->data.length = vif->rxlen; + memcpy(dst->sa_data, vif->rxdata, vif->rxlen); + dst->sa_family = 1; + memcpy(pcExtra, vif->rxdata, vif->rxlen); + + return 0; +} + +/* + * Structures to export the Wireless Handlers + */ +static const struct iw_priv_args ecrnx_wext_private_args[] = { +#ifdef CONFIG_ECRNX_WIFO_CAIL + {IOCTL_IWPRIV_AMT, IW_PRIV_TYPE_CHAR | 2000, IW_PRIV_TYPE_CHAR | 2000, "amt"}, +#endif + {IOCTL_IWPRIV_WD, IW_PRIV_TYPE_CHAR | 2000, IW_PRIV_TYPE_CHAR | 2000, "wd"}, +}; + +const iw_handler ecrnx_wext_private_handler[] = { +#ifdef CONFIG_ECRNX_WIFO_CAIL + [IOCTL_IWPRIV_AMT - SIOCIWFIRSTPRIV] = priv_amt, +#endif + [IOCTL_IWPRIV_WD - SIOCIWFIRSTPRIV] = priv_wd, +}; + +#endif + +/*------------------------------------------------------------------*/ +/* +* Commit handler : called after a bunch of SET operations +*/ +static int ecrnx_wext_config_commit(struct net_device *dev, + struct iw_request_info *info, /* NULL */ + void *zwrq, /* NULL */ + char *extra) /* NULL */ +{ + return 1; +} + +static int ecrnx_wext_get_name(struct net_device *dev, + struct iw_request_info *info, + char *cwrq, + char *extra) +{ + strcpy(cwrq, "IEEE 802.11"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set frequency + */ +static int ecrnx_wext_set_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + int rc = -EINPROGRESS; /* Call commit handler */ + ECRNX_PRINT("fwrq->e:%d, fwrq->m:%d \n", fwrq->e, fwrq->m); + return rc; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get frequency + */ +static int ecrnx_wext_get_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + fwrq->m = 100000 * + 2.412; + fwrq->e = 1; + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set Mode of Operation + */ +static int ecrnx_wext_set_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + ECRNX_PRINT("*uwrq:%d \n", *uwrq); + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get Mode of Operation + */ +static int ecrnx_wext_get_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + *uwrq = 0xFFEE; + return 0; +} + +static const iw_handler ecrnx_wext_handler[] = +{ + (iw_handler) ecrnx_wext_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) ecrnx_wext_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) ecrnx_wext_set_freq, /* SIOCSIWFREQ */ + (iw_handler) ecrnx_wext_get_freq, /* SIOCGIWFREQ */ + (iw_handler) ecrnx_wext_set_mode, /* SIOCSIWMODE */ + (iw_handler) ecrnx_wext_get_mode, /* SIOCGIWMODE */ +}; + +const struct iw_handler_def ecrnx_wext_handler_def = +{ + .num_standard = ARRAY_SIZE(ecrnx_wext_handler), + .standard = ecrnx_wext_handler, +#ifdef CONFIG_WEXT_PRIV + .num_private = ARRAY_SIZE(ecrnx_wext_private_handler), + .num_private_args = ARRAY_SIZE(ecrnx_wext_private_args), + .private = ecrnx_wext_private_handler, + .private_args = ecrnx_wext_private_args, +#endif +}; +#endif |