| //------------------------------------------------------------------------------ |
| // Copyright (c) 2004-2010 Atheros Communications Inc. |
| // All rights reserved. |
| // |
| // |
| // |
| // 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. |
| // |
| // |
| // |
| // Author(s): ="Atheros" |
| //------------------------------------------------------------------------------ |
| |
| #include "ar6000_drv.h" |
| #include "ieee80211_ioctl.h" |
| #include "ar6kap_common.h" |
| #include "targaddrs.h" |
| #include "a_hci.h" |
| #include "wlan_config.h" |
| |
| extern int enablerssicompensation; |
| u32 tcmdRxFreq; |
| extern unsigned int wmitimeout; |
| extern A_WAITQUEUE_HEAD arEvent; |
| extern int tspecCompliance; |
| extern int bmienable; |
| extern int loghci; |
| |
| static int |
| ar6000_ioctl_get_roam_tbl(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if(wmi_get_roam_tbl_cmd(ar->arWmi) != 0) { |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| ar6000_ioctl_get_roam_data(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| |
| /* currently assume only roam times are required */ |
| if(wmi_get_roam_data_cmd(ar->arWmi, ROAM_DATA_TIME) != 0) { |
| return -EIO; |
| } |
| |
| |
| return 0; |
| } |
| |
| static int |
| ar6000_ioctl_set_roam_ctrl(struct net_device *dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_ROAM_CTRL_CMD cmd; |
| u8 size = sizeof(cmd); |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| |
| if (copy_from_user(&cmd, userdata, size)) { |
| return -EFAULT; |
| } |
| |
| if (cmd.roamCtrlType == WMI_SET_HOST_BIAS) { |
| if (cmd.info.bssBiasInfo.numBss > 1) { |
| size += (cmd.info.bssBiasInfo.numBss - 1) * sizeof(WMI_BSS_BIAS); |
| } |
| } |
| |
| if (copy_from_user(&cmd, userdata, size)) { |
| return -EFAULT; |
| } |
| |
| if(wmi_set_roam_ctrl_cmd(ar->arWmi, &cmd, size) != 0) { |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| ar6000_ioctl_set_powersave_timers(struct net_device *dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_POWERSAVE_TIMERS_POLICY_CMD cmd; |
| u8 size = sizeof(cmd); |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, size)) { |
| return -EFAULT; |
| } |
| |
| if (copy_from_user(&cmd, userdata, size)) { |
| return -EFAULT; |
| } |
| |
| if(wmi_set_powersave_timers_cmd(ar->arWmi, &cmd, size) != 0) { |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| ar6000_ioctl_set_qos_supp(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_QOS_SUPP_CMD cmd; |
| int ret; |
| |
| if ((dev->flags & IFF_UP) != IFF_UP) { |
| return -EIO; |
| } |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, (char *)((unsigned int*)rq->ifr_data + 1), |
| sizeof(cmd))) |
| { |
| return -EFAULT; |
| } |
| |
| ret = wmi_set_qos_supp_cmd(ar->arWmi, cmd.status); |
| |
| switch (ret) { |
| case 0: |
| return 0; |
| case A_EBUSY : |
| return -EBUSY; |
| case A_NO_MEMORY: |
| return -ENOMEM; |
| case A_EINVAL: |
| default: |
| return -EFAULT; |
| } |
| } |
| |
| static int |
| ar6000_ioctl_set_wmm(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_WMM_CMD cmd; |
| int ret; |
| |
| if ((dev->flags & IFF_UP) != IFF_UP) { |
| return -EIO; |
| } |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, (char *)((unsigned int*)rq->ifr_data + 1), |
| sizeof(cmd))) |
| { |
| return -EFAULT; |
| } |
| |
| if (cmd.status == WMI_WMM_ENABLED) { |
| ar->arWmmEnabled = true; |
| } else { |
| ar->arWmmEnabled = false; |
| } |
| |
| ret = wmi_set_wmm_cmd(ar->arWmi, cmd.status); |
| |
| switch (ret) { |
| case 0: |
| return 0; |
| case A_EBUSY : |
| return -EBUSY; |
| case A_NO_MEMORY: |
| return -ENOMEM; |
| case A_EINVAL: |
| default: |
| return -EFAULT; |
| } |
| } |
| |
| static int |
| ar6000_ioctl_set_txop(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_WMM_TXOP_CMD cmd; |
| int ret; |
| |
| if ((dev->flags & IFF_UP) != IFF_UP) { |
| return -EIO; |
| } |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, (char *)((unsigned int*)rq->ifr_data + 1), |
| sizeof(cmd))) |
| { |
| return -EFAULT; |
| } |
| |
| ret = wmi_set_wmm_txop(ar->arWmi, cmd.txopEnable); |
| |
| switch (ret) { |
| case 0: |
| return 0; |
| case A_EBUSY : |
| return -EBUSY; |
| case A_NO_MEMORY: |
| return -ENOMEM; |
| case A_EINVAL: |
| default: |
| return -EFAULT; |
| } |
| } |
| |
| static int |
| ar6000_ioctl_get_rd(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| int ret = 0; |
| |
| if ((dev->flags & IFF_UP) != IFF_UP || ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if(copy_to_user((char *)((unsigned int*)rq->ifr_data + 1), |
| &ar->arRegCode, sizeof(ar->arRegCode))) |
| ret = -EFAULT; |
| |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_set_country(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_AP_SET_COUNTRY_CMD cmd; |
| int ret; |
| |
| if ((dev->flags & IFF_UP) != IFF_UP) { |
| return -EIO; |
| } |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, (char *)((unsigned int*)rq->ifr_data + 1), |
| sizeof(cmd))) |
| { |
| return -EFAULT; |
| } |
| |
| ar->ap_profile_flag = 1; /* There is a change in profile */ |
| |
| ret = wmi_set_country(ar->arWmi, cmd.countryCode); |
| memcpy(ar->ap_country_code, cmd.countryCode, 3); |
| |
| switch (ret) { |
| case 0: |
| return 0; |
| case A_EBUSY : |
| return -EBUSY; |
| case A_NO_MEMORY: |
| return -ENOMEM; |
| case A_EINVAL: |
| default: |
| return -EFAULT; |
| } |
| } |
| |
| |
| /* Get power mode command */ |
| static int |
| ar6000_ioctl_get_power_mode(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_POWER_MODE_CMD power_mode; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| power_mode.powerMode = wmi_get_power_mode_cmd(ar->arWmi); |
| if (copy_to_user(rq->ifr_data, &power_mode, sizeof(WMI_POWER_MODE_CMD))) { |
| ret = -EFAULT; |
| } |
| |
| return ret; |
| } |
| |
| |
| static int |
| ar6000_ioctl_set_channelParams(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_CHANNEL_PARAMS_CMD cmd, *cmdp; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if( (ar->arNextMode == AP_NETWORK) && (cmd.numChannels || cmd.scanParam) ) { |
| A_PRINTF("ERROR: Only wmode is allowed in AP mode\n"); |
| return -EIO; |
| } |
| |
| if (cmd.numChannels > 1) { |
| cmdp = A_MALLOC(130); |
| if (copy_from_user(cmdp, rq->ifr_data, |
| sizeof (*cmdp) + |
| ((cmd.numChannels - 1) * sizeof(u16)))) |
| { |
| kfree(cmdp); |
| return -EFAULT; |
| } |
| } else { |
| cmdp = &cmd; |
| } |
| |
| if ((ar->arPhyCapability == WMI_11G_CAPABILITY) && |
| ((cmdp->phyMode == WMI_11A_MODE) || (cmdp->phyMode == WMI_11AG_MODE))) |
| { |
| ret = -EINVAL; |
| } |
| |
| if (!ret && |
| (wmi_set_channelParams_cmd(ar->arWmi, cmdp->scanParam, cmdp->phyMode, |
| cmdp->numChannels, cmdp->channelList) |
| != 0)) |
| { |
| ret = -EIO; |
| } |
| |
| if (cmd.numChannels > 1) { |
| kfree(cmdp); |
| } |
| |
| ar->ap_wmode = cmdp->phyMode; |
| /* Set the profile change flag to allow a commit cmd */ |
| ar->ap_profile_flag = 1; |
| |
| return ret; |
| } |
| |
| |
| static int |
| ar6000_ioctl_set_snr_threshold(struct net_device *dev, struct ifreq *rq) |
| { |
| |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SNR_THRESHOLD_PARAMS_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if( wmi_set_snr_threshold_params(ar->arWmi, &cmd) != 0 ) { |
| ret = -EIO; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_set_rssi_threshold(struct net_device *dev, struct ifreq *rq) |
| { |
| #define SWAP_THOLD(thold1, thold2) do { \ |
| USER_RSSI_THOLD tmpThold; \ |
| tmpThold.tag = thold1.tag; \ |
| tmpThold.rssi = thold1.rssi; \ |
| thold1.tag = thold2.tag; \ |
| thold1.rssi = thold2.rssi; \ |
| thold2.tag = tmpThold.tag; \ |
| thold2.rssi = tmpThold.rssi; \ |
| } while (0) |
| |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_RSSI_THRESHOLD_PARAMS_CMD cmd; |
| USER_RSSI_PARAMS rssiParams; |
| s32 i, j; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user((char *)&rssiParams, (char *)((unsigned int *)rq->ifr_data + 1), sizeof(USER_RSSI_PARAMS))) { |
| return -EFAULT; |
| } |
| cmd.weight = rssiParams.weight; |
| cmd.pollTime = rssiParams.pollTime; |
| |
| memcpy(ar->rssi_map, &rssiParams.tholds, sizeof(ar->rssi_map)); |
| /* |
| * only 6 elements, so use bubble sorting, in ascending order |
| */ |
| for (i = 5; i > 0; i--) { |
| for (j = 0; j < i; j++) { /* above tholds */ |
| if (ar->rssi_map[j+1].rssi < ar->rssi_map[j].rssi) { |
| SWAP_THOLD(ar->rssi_map[j+1], ar->rssi_map[j]); |
| } else if (ar->rssi_map[j+1].rssi == ar->rssi_map[j].rssi) { |
| return -EFAULT; |
| } |
| } |
| } |
| for (i = 11; i > 6; i--) { |
| for (j = 6; j < i; j++) { /* below tholds */ |
| if (ar->rssi_map[j+1].rssi < ar->rssi_map[j].rssi) { |
| SWAP_THOLD(ar->rssi_map[j+1], ar->rssi_map[j]); |
| } else if (ar->rssi_map[j+1].rssi == ar->rssi_map[j].rssi) { |
| return -EFAULT; |
| } |
| } |
| } |
| |
| #ifdef DEBUG |
| for (i = 0; i < 12; i++) { |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("thold[%d].tag: %d, thold[%d].rssi: %d \n", |
| i, ar->rssi_map[i].tag, i, ar->rssi_map[i].rssi)); |
| } |
| #endif |
| |
| if (enablerssicompensation) { |
| for (i = 0; i < 6; i++) |
| ar->rssi_map[i].rssi = rssi_compensation_reverse_calc(ar, ar->rssi_map[i].rssi, true); |
| for (i = 6; i < 12; i++) |
| ar->rssi_map[i].rssi = rssi_compensation_reverse_calc(ar, ar->rssi_map[i].rssi, false); |
| } |
| |
| cmd.thresholdAbove1_Val = ar->rssi_map[0].rssi; |
| cmd.thresholdAbove2_Val = ar->rssi_map[1].rssi; |
| cmd.thresholdAbove3_Val = ar->rssi_map[2].rssi; |
| cmd.thresholdAbove4_Val = ar->rssi_map[3].rssi; |
| cmd.thresholdAbove5_Val = ar->rssi_map[4].rssi; |
| cmd.thresholdAbove6_Val = ar->rssi_map[5].rssi; |
| cmd.thresholdBelow1_Val = ar->rssi_map[6].rssi; |
| cmd.thresholdBelow2_Val = ar->rssi_map[7].rssi; |
| cmd.thresholdBelow3_Val = ar->rssi_map[8].rssi; |
| cmd.thresholdBelow4_Val = ar->rssi_map[9].rssi; |
| cmd.thresholdBelow5_Val = ar->rssi_map[10].rssi; |
| cmd.thresholdBelow6_Val = ar->rssi_map[11].rssi; |
| |
| if( wmi_set_rssi_threshold_params(ar->arWmi, &cmd) != 0 ) { |
| ret = -EIO; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_set_lq_threshold(struct net_device *dev, struct ifreq *rq) |
| { |
| |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_LQ_THRESHOLD_PARAMS_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, (char *)((unsigned int *)rq->ifr_data + 1), sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if( wmi_set_lq_threshold_params(ar->arWmi, &cmd) != 0 ) { |
| ret = -EIO; |
| } |
| |
| return ret; |
| } |
| |
| |
| static int |
| ar6000_ioctl_set_probedSsid(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_PROBED_SSID_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_probedSsid_cmd(ar->arWmi, cmd.entryIndex, cmd.flag, cmd.ssidLength, |
| cmd.ssid) != 0) |
| { |
| ret = -EIO; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_set_badAp(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_ADD_BAD_AP_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (cmd.badApIndex > WMI_MAX_BAD_AP_INDEX) { |
| return -EIO; |
| } |
| |
| if (memcmp(cmd.bssid, null_mac, AR6000_ETH_ADDR_LEN) == 0) { |
| /* |
| * This is a delete badAP. |
| */ |
| if (wmi_deleteBadAp_cmd(ar->arWmi, cmd.badApIndex) != 0) { |
| ret = -EIO; |
| } |
| } else { |
| if (wmi_addBadAp_cmd(ar->arWmi, cmd.badApIndex, cmd.bssid) != 0) { |
| ret = -EIO; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_create_qos(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_CREATE_PSTREAM_CMD cmd; |
| int ret; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| ret = wmi_verify_tspec_params(&cmd, tspecCompliance); |
| if (ret == 0) |
| ret = wmi_create_pstream_cmd(ar->arWmi, &cmd); |
| |
| switch (ret) { |
| case 0: |
| return 0; |
| case A_EBUSY : |
| return -EBUSY; |
| case A_NO_MEMORY: |
| return -ENOMEM; |
| case A_EINVAL: |
| default: |
| return -EFAULT; |
| } |
| } |
| |
| static int |
| ar6000_ioctl_delete_qos(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_DELETE_PSTREAM_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| ret = wmi_delete_pstream_cmd(ar->arWmi, cmd.trafficClass, cmd.tsid); |
| |
| switch (ret) { |
| case 0: |
| return 0; |
| case A_EBUSY : |
| return -EBUSY; |
| case A_NO_MEMORY: |
| return -ENOMEM; |
| case A_EINVAL: |
| default: |
| return -EFAULT; |
| } |
| } |
| |
| static int |
| ar6000_ioctl_get_qos_queue(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| struct ar6000_queuereq qreq; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if( copy_from_user(&qreq, rq->ifr_data, |
| sizeof(struct ar6000_queuereq))) |
| return -EFAULT; |
| |
| qreq.activeTsids = wmi_get_mapped_qos_queue(ar->arWmi, qreq.trafficClass); |
| |
| if (copy_to_user(rq->ifr_data, &qreq, |
| sizeof(struct ar6000_queuereq))) |
| { |
| ret = -EFAULT; |
| } |
| |
| return ret; |
| } |
| |
| #ifdef CONFIG_HOST_TCMD_SUPPORT |
| static int |
| ar6000_ioctl_tcmd_get_rx_report(struct net_device *dev, |
| struct ifreq *rq, u8 *data, u32 len) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| u32 buf[4+TCMD_MAX_RATES]; |
| int ret = 0; |
| |
| if (ar->bIsDestroyProgress) { |
| return -EBUSY; |
| } |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (down_interruptible(&ar->arSem)) { |
| return -ERESTARTSYS; |
| } |
| |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| return -EBUSY; |
| } |
| |
| ar->tcmdRxReport = 0; |
| if (wmi_test_cmd(ar->arWmi, data, len) != 0) { |
| up(&ar->arSem); |
| return -EIO; |
| } |
| |
| wait_event_interruptible_timeout(arEvent, ar->tcmdRxReport != 0, wmitimeout * HZ); |
| |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| |
| buf[0] = ar->tcmdRxTotalPkt; |
| buf[1] = ar->tcmdRxRssi; |
| buf[2] = ar->tcmdRxcrcErrPkt; |
| buf[3] = ar->tcmdRxsecErrPkt; |
| memcpy(((u8 *)buf)+(4*sizeof(u32)), ar->tcmdRateCnt, sizeof(ar->tcmdRateCnt)); |
| memcpy(((u8 *)buf)+(4*sizeof(u32))+(TCMD_MAX_RATES *sizeof(u16)), ar->tcmdRateCntShortGuard, sizeof(ar->tcmdRateCntShortGuard)); |
| |
| if (!ret && copy_to_user(rq->ifr_data, buf, sizeof(buf))) { |
| ret = -EFAULT; |
| } |
| |
| up(&ar->arSem); |
| |
| return ret; |
| } |
| |
| void |
| ar6000_tcmd_rx_report_event(void *devt, u8 *results, int len) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)devt; |
| TCMD_CONT_RX * rx_rep = (TCMD_CONT_RX *)results; |
| |
| if (enablerssicompensation) { |
| rx_rep->u.report.rssiInDBm = rssi_compensation_calc_tcmd(tcmdRxFreq, rx_rep->u.report.rssiInDBm,rx_rep->u.report.totalPkt); |
| } |
| |
| |
| ar->tcmdRxTotalPkt = rx_rep->u.report.totalPkt; |
| ar->tcmdRxRssi = rx_rep->u.report.rssiInDBm; |
| ar->tcmdRxcrcErrPkt = rx_rep->u.report.crcErrPkt; |
| ar->tcmdRxsecErrPkt = rx_rep->u.report.secErrPkt; |
| ar->tcmdRxReport = 1; |
| A_MEMZERO(ar->tcmdRateCnt, sizeof(ar->tcmdRateCnt)); |
| A_MEMZERO(ar->tcmdRateCntShortGuard, sizeof(ar->tcmdRateCntShortGuard)); |
| memcpy(ar->tcmdRateCnt, rx_rep->u.report.rateCnt, sizeof(ar->tcmdRateCnt)); |
| memcpy(ar->tcmdRateCntShortGuard, rx_rep->u.report.rateCntShortGuard, sizeof(ar->tcmdRateCntShortGuard)); |
| |
| wake_up(&arEvent); |
| } |
| #endif /* CONFIG_HOST_TCMD_SUPPORT*/ |
| |
| static int |
| ar6000_ioctl_set_error_report_bitmask(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_TARGET_ERROR_REPORT_BITMASK cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| ret = wmi_set_error_report_bitmask(ar->arWmi, cmd.bitmask); |
| |
| return (ret==0 ? ret : -EINVAL); |
| } |
| |
| static int |
| ar6000_clear_target_stats(struct net_device *dev) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| TARGET_STATS *pStats = &ar->arTargetStats; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| AR6000_SPIN_LOCK(&ar->arLock, 0); |
| A_MEMZERO(pStats, sizeof(TARGET_STATS)); |
| AR6000_SPIN_UNLOCK(&ar->arLock, 0); |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_get_target_stats(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| TARGET_STATS_CMD cmd; |
| TARGET_STATS *pStats = &ar->arTargetStats; |
| int ret = 0; |
| |
| if (ar->bIsDestroyProgress) { |
| return -EBUSY; |
| } |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| return -ERESTARTSYS; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| return -EBUSY; |
| } |
| |
| ar->statsUpdatePending = true; |
| |
| if(wmi_get_stats_cmd(ar->arWmi) != 0) { |
| up(&ar->arSem); |
| return -EIO; |
| } |
| |
| wait_event_interruptible_timeout(arEvent, ar->statsUpdatePending == false, wmitimeout * HZ); |
| |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| |
| if (!ret && copy_to_user(rq->ifr_data, pStats, sizeof(*pStats))) { |
| ret = -EFAULT; |
| } |
| |
| if (cmd.clearStats == 1) { |
| ret = ar6000_clear_target_stats(dev); |
| } |
| |
| up(&ar->arSem); |
| |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_get_ap_stats(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| u32 action; /* Allocating only the desired space on the frame. Declaring is as a WMI_AP_MODE_STAT variable results in exceeding the compiler imposed limit on the maximum frame size */ |
| WMI_AP_MODE_STAT *pStats = &ar->arAPStats; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| if (copy_from_user(&action, (char *)((unsigned int*)rq->ifr_data + 1), |
| sizeof(u32))) |
| { |
| return -EFAULT; |
| } |
| if (action == AP_CLEAR_STATS) { |
| u8 i; |
| AR6000_SPIN_LOCK(&ar->arLock, 0); |
| for(i = 0; i < AP_MAX_NUM_STA; i++) { |
| pStats->sta[i].tx_bytes = 0; |
| pStats->sta[i].tx_pkts = 0; |
| pStats->sta[i].tx_error = 0; |
| pStats->sta[i].tx_discard = 0; |
| pStats->sta[i].rx_bytes = 0; |
| pStats->sta[i].rx_pkts = 0; |
| pStats->sta[i].rx_error = 0; |
| pStats->sta[i].rx_discard = 0; |
| } |
| AR6000_SPIN_UNLOCK(&ar->arLock, 0); |
| return ret; |
| } |
| |
| if (down_interruptible(&ar->arSem)) { |
| return -ERESTARTSYS; |
| } |
| |
| ar->statsUpdatePending = true; |
| |
| if(wmi_get_stats_cmd(ar->arWmi) != 0) { |
| up(&ar->arSem); |
| return -EIO; |
| } |
| |
| wait_event_interruptible_timeout(arEvent, ar->statsUpdatePending == false, wmitimeout * HZ); |
| |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| |
| if (!ret && copy_to_user(rq->ifr_data, pStats, sizeof(*pStats))) { |
| ret = -EFAULT; |
| } |
| |
| up(&ar->arSem); |
| |
| return ret; |
| } |
| |
| static int |
| ar6000_ioctl_set_access_params(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_ACCESS_PARAMS_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_access_params_cmd(ar->arWmi, cmd.ac, cmd.txop, cmd.eCWmin, cmd.eCWmax, |
| cmd.aifsn) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return (ret); |
| } |
| |
| static int |
| ar6000_ioctl_set_disconnect_timeout(struct net_device *dev, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_DISC_TIMEOUT_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_disctimeout_cmd(ar->arWmi, cmd.disconnectTimeout) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return (ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_voice_pkt_size(struct net_device *dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_VOICE_PKT_SIZE_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_voice_pkt_size_cmd(ar->arWmi, cmd.voicePktSize) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| |
| return (ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_max_sp_len(struct net_device *dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_MAX_SP_LEN_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_max_sp_len_cmd(ar->arWmi, cmd.maxSPLen) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return (ret); |
| } |
| |
| |
| static int |
| ar6000_xioctl_set_bt_status_cmd(struct net_device *dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BT_STATUS_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_bt_status_cmd(ar->arWmi, cmd.streamType, cmd.status) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return (ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_bt_params_cmd(struct net_device *dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BT_PARAMS_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_bt_params_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return (ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_btcoex_fe_ant_cmd(struct net_device * dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_FE_ANT_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_fe_ant_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_btcoex_colocated_bt_dev_cmd(struct net_device * dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_colocated_bt_dev_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_btcoex_btinquiry_page_config_cmd(struct net_device * dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_btinquiry_page_config_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_btcoex_sco_config_cmd(struct net_device * dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_SCO_CONFIG_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_sco_config_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_btcoex_a2dp_config_cmd(struct net_device * dev, |
| char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_A2DP_CONFIG_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_a2dp_config_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_btcoex_aclcoex_config_cmd(struct net_device * dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_aclcoex_config_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return(ret); |
| } |
| |
| static int |
| ar60000_xioctl_set_btcoex_debug_cmd(struct net_device * dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_DEBUG_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_debug_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_btcoex_bt_operating_status_cmd(struct net_device * dev, char *userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_btcoex_bt_operating_status_cmd(ar->arWmi, &cmd) == 0) |
| { |
| ret = 0; |
| } else { |
| ret = -EINVAL; |
| } |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_get_btcoex_config_cmd(struct net_device * dev, char *userdata, |
| struct ifreq *rq) |
| { |
| |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| AR6000_BTCOEX_CONFIG btcoexConfig; |
| WMI_BTCOEX_CONFIG_EVENT *pbtcoexConfigEv = &ar->arBtcoexConfig; |
| |
| int ret = 0; |
| |
| if (ar->bIsDestroyProgress) { |
| return -EBUSY; |
| } |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| if (copy_from_user(&btcoexConfig.configCmd, userdata, sizeof(AR6000_BTCOEX_CONFIG))) { |
| return -EFAULT; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| return -ERESTARTSYS; |
| } |
| |
| if (wmi_get_btcoex_config_cmd(ar->arWmi, (WMI_GET_BTCOEX_CONFIG_CMD *)&btcoexConfig.configCmd) != 0) |
| { |
| up(&ar->arSem); |
| return -EIO; |
| } |
| |
| ar->statsUpdatePending = true; |
| |
| wait_event_interruptible_timeout(arEvent, ar->statsUpdatePending == false, wmitimeout * HZ); |
| |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| |
| if (!ret && copy_to_user(btcoexConfig.configEvent, pbtcoexConfigEv, sizeof(WMI_BTCOEX_CONFIG_EVENT))) { |
| ret = -EFAULT; |
| } |
| up(&ar->arSem); |
| return ret; |
| } |
| |
| static int |
| ar6000_xioctl_get_btcoex_stats_cmd(struct net_device * dev, char *userdata, struct ifreq *rq) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| AR6000_BTCOEX_STATS btcoexStats; |
| WMI_BTCOEX_STATS_EVENT *pbtcoexStats = &ar->arBtcoexStats; |
| int ret = 0; |
| |
| if (ar->bIsDestroyProgress) { |
| return -EBUSY; |
| } |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (down_interruptible(&ar->arSem)) { |
| return -ERESTARTSYS; |
| } |
| |
| if (copy_from_user(&btcoexStats.statsEvent, userdata, sizeof(AR6000_BTCOEX_CONFIG))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_get_btcoex_stats_cmd(ar->arWmi) != 0) |
| { |
| up(&ar->arSem); |
| return -EIO; |
| } |
| |
| ar->statsUpdatePending = true; |
| |
| wait_event_interruptible_timeout(arEvent, ar->statsUpdatePending == false, wmitimeout * HZ); |
| |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| |
| if (!ret && copy_to_user(btcoexStats.statsEvent, pbtcoexStats, sizeof(WMI_BTCOEX_STATS_EVENT))) { |
| ret = -EFAULT; |
| } |
| |
| |
| up(&ar->arSem); |
| |
| return(ret); |
| } |
| |
| static int |
| ar6000_xioctl_set_excess_tx_retry_thres_cmd(struct net_device * dev, char * userdata) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_SET_EXCESS_TX_RETRY_THRES_CMD cmd; |
| int ret = 0; |
| |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| |
| if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| return -EFAULT; |
| } |
| |
| if (wmi_set_excess_tx_retry_thres_cmd(ar->arWmi, &cmd) != 0) |
| { |
| ret = -EINVAL; |
| } |
| return(ret); |
| } |
| |
| #ifdef CONFIG_HOST_GPIO_SUPPORT |
| struct ar6000_gpio_intr_wait_cmd_s gpio_intr_results; |
| /* gpio_reg_results and gpio_data_available are protected by arSem */ |
| static struct ar6000_gpio_register_cmd_s gpio_reg_results; |
| static bool gpio_data_available; /* Requested GPIO data available */ |
| static bool gpio_intr_available; /* GPIO interrupt info available */ |
| static bool gpio_ack_received; /* GPIO ack was received */ |
| |
| /* Host-side initialization for General Purpose I/O support */ |
| void ar6000_gpio_init(void) |
| { |
| gpio_intr_available = false; |
| gpio_data_available = false; |
| gpio_ack_received = false; |
| } |
| |
| /* |
| * Called when a GPIO interrupt is received from the Target. |
| * intr_values shows which GPIO pins have interrupted. |
| * input_values shows a recent value of GPIO pins. |
| */ |
| void |
| ar6000_gpio_intr_rx(u32 intr_mask, u32 input_values) |
| { |
| gpio_intr_results.intr_mask = intr_mask; |
| gpio_intr_results.input_values = input_values; |
| *((volatile bool *)&gpio_intr_available) = true; |
| wake_up(&arEvent); |
| } |
| |
| /* |
| * This is called when a response is received from the Target |
| * for a previous or ar6000_gpio_input_get or ar6000_gpio_register_get |
| * call. |
| */ |
| void |
| ar6000_gpio_data_rx(u32 reg_id, u32 value) |
| { |
| gpio_reg_results.gpioreg_id = reg_id; |
| gpio_reg_results.value = value; |
| *((volatile bool *)&gpio_data_available) = true; |
| wake_up(&arEvent); |
| } |
| |
| /* |
| * This is called when an acknowledgement is received from the Target |
| * for a previous or ar6000_gpio_output_set or ar6000_gpio_register_set |
| * call. |
| */ |
| void |
| ar6000_gpio_ack_rx(void) |
| { |
| gpio_ack_received = true; |
| wake_up(&arEvent); |
| } |
| |
| int |
| ar6000_gpio_output_set(struct net_device *dev, |
| u32 set_mask, |
| u32 clear_mask, |
| u32 enable_mask, |
| u32 disable_mask) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| gpio_ack_received = false; |
| return wmi_gpio_output_set(ar->arWmi, |
| set_mask, clear_mask, enable_mask, disable_mask); |
| } |
| |
| static int |
| ar6000_gpio_input_get(struct net_device *dev) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| *((volatile bool *)&gpio_data_available) = false; |
| return wmi_gpio_input_get(ar->arWmi); |
| } |
| |
| static int |
| ar6000_gpio_register_set(struct net_device *dev, |
| u32 gpioreg_id, |
| u32 value) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| gpio_ack_received = false; |
| return wmi_gpio_register_set(ar->arWmi, gpioreg_id, value); |
| } |
| |
| static int |
| ar6000_gpio_register_get(struct net_device *dev, |
| u32 gpioreg_id) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| *((volatile bool *)&gpio_data_available) = false; |
| return wmi_gpio_register_get(ar->arWmi, gpioreg_id); |
| } |
| |
| static int |
| ar6000_gpio_intr_ack(struct net_device *dev, |
| u32 ack_mask) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| gpio_intr_available = false; |
| return wmi_gpio_intr_ack(ar->arWmi, ack_mask); |
| } |
| #endif /* CONFIG_HOST_GPIO_SUPPORT */ |
| |
| #if defined(CONFIG_TARGET_PROFILE_SUPPORT) |
| static struct prof_count_s prof_count_results; |
| static bool prof_count_available; /* Requested GPIO data available */ |
| |
| static int |
| prof_count_get(struct net_device *dev) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| *((volatile bool *)&prof_count_available) = false; |
| return wmi_prof_count_get_cmd(ar->arWmi); |
| } |
| |
| /* |
| * This is called when a response is received from the Target |
| * for a previous prof_count_get call. |
| */ |
| void |
| prof_count_rx(u32 addr, u32 count) |
| { |
| prof_count_results.addr = addr; |
| prof_count_results.count = count; |
| *((volatile bool *)&prof_count_available) = true; |
| wake_up(&arEvent); |
| } |
| #endif /* CONFIG_TARGET_PROFILE_SUPPORT */ |
| |
| |
| static int |
| ar6000_create_acl_data_osbuf(struct net_device *dev, u8 *userdata, void **p_osbuf) |
| { |
| void *osbuf = NULL; |
| u8 tmp_space[8]; |
| HCI_ACL_DATA_PKT *acl; |
| u8 hdr_size, *datap=NULL; |
| int ret = 0; |
| |
| /* ACL is in data path. There is a need to create pool |
| * mechanism for allocating and freeing NETBUFs - ToDo later. |
| */ |
| |
| *p_osbuf = NULL; |
| acl = (HCI_ACL_DATA_PKT *)tmp_space; |
| hdr_size = sizeof(acl->hdl_and_flags) + sizeof(acl->data_len); |
| |
| do { |
| if (a_copy_from_user(acl, userdata, hdr_size)) { |
| ret = A_EFAULT; |
| break; |
| } |
| |
| osbuf = A_NETBUF_ALLOC(hdr_size + acl->data_len); |
| if (osbuf == NULL) { |
| ret = A_NO_MEMORY; |
| break; |
| } |
| A_NETBUF_PUT(osbuf, hdr_size + acl->data_len); |
| datap = (u8 *)A_NETBUF_DATA(osbuf); |
| |
| /* Real copy to osbuf */ |
| acl = (HCI_ACL_DATA_PKT *)(datap); |
| memcpy(acl, tmp_space, hdr_size); |
| if (a_copy_from_user(acl->data, userdata + hdr_size, acl->data_len)) { |
| ret = A_EFAULT; |
| break; |
| } |
| } while(false); |
| |
| if (ret == 0) { |
| *p_osbuf = osbuf; |
| } else { |
| A_NETBUF_FREE(osbuf); |
| } |
| return ret; |
| } |
| |
| |
| |
| int |
| ar6000_ioctl_ap_setparam(AR_SOFTC_T *ar, int param, int value) |
| { |
| int ret=0; |
| |
| switch(param) { |
| case IEEE80211_PARAM_WPA: |
| switch (value) { |
| case WPA_MODE_WPA1: |
| ar->arAuthMode = WPA_AUTH; |
| break; |
| case WPA_MODE_WPA2: |
| ar->arAuthMode = WPA2_AUTH; |
| break; |
| case WPA_MODE_AUTO: |
| ar->arAuthMode = WPA_AUTH | WPA2_AUTH; |
| break; |
| case WPA_MODE_NONE: |
| ar->arAuthMode = NONE_AUTH; |
| break; |
| } |
| break; |
| case IEEE80211_PARAM_AUTHMODE: |
| if(value == IEEE80211_AUTH_WPA_PSK) { |
| if (WPA_AUTH == ar->arAuthMode) { |
| ar->arAuthMode = WPA_PSK_AUTH; |
| } else if (WPA2_AUTH == ar->arAuthMode) { |
| ar->arAuthMode = WPA2_PSK_AUTH; |
| } else if ((WPA_AUTH | WPA2_AUTH) == ar->arAuthMode) { |
| ar->arAuthMode = WPA_PSK_AUTH | WPA2_PSK_AUTH; |
| } else { |
| AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Error - Setting PSK "\ |
| "mode when WPA param was set to %d\n", |
| ar->arAuthMode)); |
| ret = -EIO; |
| } |
| } |
| break; |
| case IEEE80211_PARAM_UCASTCIPHER: |
| ar->arPairwiseCrypto = 0; |
| if(value & (1<<IEEE80211_CIPHER_AES_CCM)) { |
| ar->arPairwiseCrypto |= AES_CRYPT; |
| } |
| if(value & (1<<IEEE80211_CIPHER_TKIP)) { |
| ar->arPairwiseCrypto |= TKIP_CRYPT; |
| } |
| if(!ar->arPairwiseCrypto) { |
| AR_DEBUG_PRINTF(ATH_DEBUG_ERR, |
| ("Error - Invalid cipher in WPA \n")); |
| ret = -EIO; |
| } |
| break; |
| case IEEE80211_PARAM_PRIVACY: |
| if(value == 0) { |
| ar->arDot11AuthMode = OPEN_AUTH; |
| ar->arAuthMode = NONE_AUTH; |
| ar->arPairwiseCrypto = NONE_CRYPT; |
| ar->arPairwiseCryptoLen = 0; |
| ar->arGroupCrypto = NONE_CRYPT; |
| ar->arGroupCryptoLen = 0; |
| } |
| break; |
| #ifdef WAPI_ENABLE |
| case IEEE80211_PARAM_WAPI: |
| A_PRINTF("WAPI Policy: %d\n", value); |
| ar->arDot11AuthMode = OPEN_AUTH; |
| ar->arAuthMode = NONE_AUTH; |
| if(value & 0x1) { |
| ar->arPairwiseCrypto = WAPI_CRYPT; |
| ar->arGroupCrypto = WAPI_CRYPT; |
| } else { |
| ar->arPairwiseCrypto = NONE_CRYPT; |
| ar->arGroupCrypto = NONE_CRYPT; |
| } |
| break; |
| #endif |
| } |
| return ret; |
| } |
| |
| int |
| ar6000_ioctl_setparam(AR_SOFTC_T *ar, int param, int value) |
| { |
| bool profChanged = false; |
| int ret=0; |
| |
| if(ar->arNextMode == AP_NETWORK) { |
| ar->ap_profile_flag = 1; /* There is a change in profile */ |
| switch (param) { |
| case IEEE80211_PARAM_WPA: |
| case IEEE80211_PARAM_AUTHMODE: |
| case IEEE80211_PARAM_UCASTCIPHER: |
| case IEEE80211_PARAM_PRIVACY: |
| case IEEE80211_PARAM_WAPI: |
| ret = ar6000_ioctl_ap_setparam(ar, param, value); |
| return ret; |
| } |
| } |
| |
| switch (param) { |
| case IEEE80211_PARAM_WPA: |
| switch (value) { |
| case WPA_MODE_WPA1: |
| ar->arAuthMode = WPA_AUTH; |
| profChanged = true; |
| break; |
| case WPA_MODE_WPA2: |
| ar->arAuthMode = WPA2_AUTH; |
| profChanged = true; |
| break; |
| case WPA_MODE_NONE: |
| ar->arAuthMode = NONE_AUTH; |
| profChanged = true; |
| break; |
| } |
| break; |
| case IEEE80211_PARAM_AUTHMODE: |
| switch(value) { |
| case IEEE80211_AUTH_WPA_PSK: |
| if (WPA_AUTH == ar->arAuthMode) { |
| ar->arAuthMode = WPA_PSK_AUTH; |
| profChanged = true; |
| } else if (WPA2_AUTH == ar->arAuthMode) { |
| ar->arAuthMode = WPA2_PSK_AUTH; |
| profChanged = true; |
| } else { |
| AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Error - Setting PSK "\ |
| "mode when WPA param was set to %d\n", |
| ar->arAuthMode)); |
| ret = -EIO; |
| } |
| break; |
| case IEEE80211_AUTH_WPA_CCKM: |
| if (WPA2_AUTH == ar->arAuthMode) { |
| ar->arAuthMode = WPA2_AUTH_CCKM; |
| } else { |
| ar->arAuthMode = WPA_AUTH_CCKM; |
| } |
| break; |
| default: |
| break; |
| } |
| break; |
| case IEEE80211_PARAM_UCASTCIPHER: |
| switch (value) { |
| case IEEE80211_CIPHER_AES_CCM: |
| ar->arPairwiseCrypto = AES_CRYPT; |
| profChanged = true; |
| break; |
| case IEEE80211_CIPHER_TKIP: |
| ar->arPairwiseCrypto = TKIP_CRYPT; |
| profChanged = true; |
| break; |
| case IEEE80211_CIPHER_WEP: |
| ar->arPairwiseCrypto = WEP_CRYPT; |
| profChanged = true; |
| break; |
| case IEEE80211_CIPHER_NONE: |
| ar->arPairwiseCrypto = NONE_CRYPT; |
| profChanged = true; |
| break; |
| } |
| break; |
| case IEEE80211_PARAM_UCASTKEYLEN: |
| if (!IEEE80211_IS_VALID_WEP_CIPHER_LEN(value)) { |
| ret = -EIO; |
| } else { |
| ar->arPairwiseCryptoLen = value; |
| } |
| break; |
| case IEEE80211_PARAM_MCASTCIPHER: |
| switch (value) { |
| case IEEE80211_CIPHER_AES_CCM: |
| ar->arGroupCrypto = AES_CRYPT; |
| profChanged = true; |
| break; |
| case IEEE80211_CIPHER_TKIP: |
| ar->arGroupCrypto = TKIP_CRYPT; |
| profChanged = true; |
| break; |
| case IEEE80211_CIPHER_WEP: |
| ar->arGroupCrypto = WEP_CRYPT; |
| profChanged = true; |
| break; |
| case IEEE80211_CIPHER_NONE: |
| ar->arGroupCrypto = NONE_CRYPT; |
| profChanged = true; |
| break; |
| } |
| break; |
| case IEEE80211_PARAM_MCASTKEYLEN: |
| if (!IEEE80211_IS_VALID_WEP_CIPHER_LEN(value)) { |
| ret = -EIO; |
| } else { |
| ar->arGroupCryptoLen = value; |
| } |
| break; |
| case IEEE80211_PARAM_COUNTERMEASURES: |
| if (ar->arWmiReady == false) { |
| return -EIO; |
| } |
| wmi_set_tkip_countermeasures_cmd(ar->arWmi, value); |
| break; |
| default: |
| break; |
| } |
| if ((ar->arNextMode != AP_NETWORK) && (profChanged == true)) { |
| /* |
| * profile has changed. Erase ssid to signal change |
| */ |
| A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); |
| } |
| |
| return ret; |
| } |
| |
| int |
| ar6000_ioctl_setkey(AR_SOFTC_T *ar, struct ieee80211req_key *ik) |
| { |
| KEY_USAGE keyUsage; |
| int status; |
| CRYPTO_TYPE keyType = NONE_CRYPT; |
| |
| #ifdef USER_KEYS |
| ar->user_saved_keys.keyOk = false; |
| #endif |
| if ( (0 == memcmp(ik->ik_macaddr, null_mac, IEEE80211_ADDR_LEN)) || |
| (0 == memcmp(ik->ik_macaddr, bcast_mac, IEEE80211_ADDR_LEN)) ) { |
| keyUsage = GROUP_USAGE; |
| if(ar->arNextMode == AP_NETWORK) { |
| memcpy(&ar->ap_mode_bkey, ik, |
| sizeof(struct ieee80211req_key)); |
| #ifdef WAPI_ENABLE |
| if(ar->arPairwiseCrypto == WAPI_CRYPT) { |
| return ap_set_wapi_key(ar, ik); |
| } |
| #endif |
| } |
| #ifdef USER_KEYS |
| memcpy(&ar->user_saved_keys.bcast_ik, ik, |
| sizeof(struct ieee80211req_key)); |
| #endif |
| } else { |
| keyUsage = PAIRWISE_USAGE; |
| #ifdef USER_KEYS |
| memcpy(&ar->user_saved_keys.ucast_ik, ik, |
| sizeof(struct ieee80211req_key)); |
| #endif |
| #ifdef WAPI_ENABLE |
| if(ar->arNextMode == AP_NETWORK) { |
| if(ar->arPairwiseCrypto == WAPI_CRYPT) { |
| return ap_set_wapi_key(ar, ik); |
| } |
| } |
| #endif |
| } |
| |
| switch (ik->ik_type) { |
| case IEEE80211_CIPHER_WEP: |
| keyType = WEP_CRYPT; |
| break; |
| case IEEE80211_CIPHER_TKIP: |
| keyType = TKIP_CRYPT; |
| break; |
| case IEEE80211_CIPHER_AES_CCM: |
| keyType = AES_CRYPT; |
| break; |
| default: |
| break; |
| } |
| #ifdef USER_KEYS |
| ar->user_saved_keys.keyType = keyType; |
| #endif |
| if (IEEE80211_CIPHER_CCKM_KRK != ik->ik_type) { |
| if (NONE_CRYPT == keyType) { |
| return -EIO; |
| } |
| |
| if ((WEP_CRYPT == keyType)&&(!ar->arConnected)) { |
| int index = ik->ik_keyix; |
| |
| if (!IEEE80211_IS_VALID_WEP_CIPHER_LEN(ik->ik_keylen)) { |
| return -EIO; |
| } |
| |
| A_MEMZERO(ar->arWepKeyList[index].arKey, |
| sizeof(ar->arWepKeyList[index].arKey)); |
| memcpy(ar->arWepKeyList[index].arKey, ik->ik_keydata, ik->ik_keylen); |
| ar->arWepKeyList[index].arKeyLen = ik->ik_keylen; |
| |
| if(ik->ik_flags & IEEE80211_KEY_DEFAULT){ |
| ar->arDefTxKeyIndex = index; |
| } |
| |
| return 0; |
| } |
| |
| if (((WPA_PSK_AUTH == ar->arAuthMode) || (WPA2_PSK_AUTH == ar->arAuthMode)) && |
| (GROUP_USAGE & keyUsage)) |
| { |
| A_UNTIMEOUT(&ar->disconnect_timer); |
| } |
| |
| status = wmi_addKey_cmd(ar->arWmi, ik->ik_keyix, keyType, keyUsage, |
| ik->ik_keylen, (u8 *)&ik->ik_keyrsc, |
| ik->ik_keydata, KEY_OP_INIT_VAL, ik->ik_macaddr, |
| SYNC_BOTH_WMIFLAG); |
| |
| if (status) { |
| return -EIO; |
| } |
| } else { |
| status = wmi_add_krk_cmd(ar->arWmi, ik->ik_keydata); |
| } |
| |
| #ifdef USER_KEYS |
| ar->user_saved_keys.keyOk = true; |
| #endif |
| |
| return 0; |
| } |
| |
| int ar6000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| HIF_DEVICE *hifDevice = ar->arHifDevice; |
| int ret = 0, param; |
| unsigned int address = 0; |
| unsigned int length = 0; |
| unsigned char *buffer; |
| char *userdata; |
| u32 connectCtrlFlags; |
| |
| |
| WMI_SET_AKMP_PARAMS_CMD akmpParams; |
| WMI_SET_PMKID_LIST_CMD pmkidInfo; |
| |
| WMI_SET_HT_CAP_CMD htCap; |
| WMI_SET_HT_OP_CMD htOp; |
| |
| /* |
| * ioctl operations may have to wait for the Target, so we cannot hold rtnl. |
| * Prevent the device from disappearing under us and release the lock during |
| * the ioctl operation. |
| */ |
| dev_hold(dev); |
| rtnl_unlock(); |
| |
| if (cmd == AR6000_IOCTL_EXTENDED) { |
| /* |
| * This allows for many more wireless ioctls than would otherwise |
| * be available. Applications embed the actual ioctl command in |
| * the first word of the parameter block, and use the command |
| * AR6000_IOCTL_EXTENDED_CMD on the ioctl call. |
| */ |
| if (get_user(cmd, (int *)rq->ifr_data)) { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| userdata = (char *)(((unsigned int *)rq->ifr_data)+1); |
| if(is_xioctl_allowed(ar->arNextMode, cmd) != 0) { |
| A_PRINTF("xioctl: cmd=%d not allowed in this mode\n",cmd); |
| ret = -EOPNOTSUPP; |
| goto ioctl_done; |
| } |
| } else { |
| int ret = is_iwioctl_allowed(ar->arNextMode, cmd); |
| if(ret == A_ENOTSUP) { |
| A_PRINTF("iwioctl: cmd=0x%x not allowed in this mode\n", cmd); |
| ret = -EOPNOTSUPP; |
| goto ioctl_done; |
| } else if (ret == A_ERROR) { |
| /* It is not our ioctl (out of range ioctl) */ |
| ret = -EOPNOTSUPP; |
| goto ioctl_done; |
| } |
| userdata = (char *)rq->ifr_data; |
| } |
| |
| if ((ar->arWlanState == WLAN_DISABLED) && |
| ((cmd != AR6000_XIOCTRL_WMI_SET_WLAN_STATE) && |
| (cmd != AR6000_XIOCTL_GET_WLAN_SLEEP_STATE) && |
| (cmd != AR6000_XIOCTL_DIAG_READ) && |
| (cmd != AR6000_XIOCTL_DIAG_WRITE) && |
| (cmd != AR6000_XIOCTL_SET_BT_HW_POWER_STATE) && |
| (cmd != AR6000_XIOCTL_GET_BT_HW_POWER_STATE) && |
| (cmd != AR6000_XIOCTL_ADD_AP_INTERFACE) && |
| (cmd != AR6000_XIOCTL_REMOVE_AP_INTERFACE) && |
| (cmd != AR6000_IOCTL_WMI_GETREV))) |
| { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| |
| ret = 0; |
| switch(cmd) |
| { |
| case IEEE80211_IOCTL_SETPARAM: |
| { |
| int param, value; |
| int *ptr = (int *)rq->ifr_ifru.ifru_newname; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else { |
| param = *ptr++; |
| value = *ptr; |
| ret = ar6000_ioctl_setparam(ar,param,value); |
| } |
| break; |
| } |
| case IEEE80211_IOCTL_SETKEY: |
| { |
| struct ieee80211req_key keydata; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&keydata, userdata, |
| sizeof(struct ieee80211req_key))) { |
| ret = -EFAULT; |
| } else { |
| ar6000_ioctl_setkey(ar, &keydata); |
| } |
| break; |
| } |
| case IEEE80211_IOCTL_DELKEY: |
| case IEEE80211_IOCTL_SETOPTIE: |
| { |
| //ret = -EIO; |
| break; |
| } |
| case IEEE80211_IOCTL_SETMLME: |
| { |
| struct ieee80211req_mlme mlme; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&mlme, userdata, |
| sizeof(struct ieee80211req_mlme))) { |
| ret = -EFAULT; |
| } else { |
| switch (mlme.im_op) { |
| case IEEE80211_MLME_AUTHORIZE: |
| A_PRINTF("setmlme AUTHORIZE %02X:%02X\n", |
| mlme.im_macaddr[4], mlme.im_macaddr[5]); |
| break; |
| case IEEE80211_MLME_UNAUTHORIZE: |
| A_PRINTF("setmlme UNAUTHORIZE %02X:%02X\n", |
| mlme.im_macaddr[4], mlme.im_macaddr[5]); |
| break; |
| case IEEE80211_MLME_DEAUTH: |
| A_PRINTF("setmlme DEAUTH %02X:%02X\n", |
| mlme.im_macaddr[4], mlme.im_macaddr[5]); |
| //remove_sta(ar, mlme.im_macaddr); |
| break; |
| case IEEE80211_MLME_DISASSOC: |
| A_PRINTF("setmlme DISASSOC %02X:%02X\n", |
| mlme.im_macaddr[4], mlme.im_macaddr[5]); |
| //remove_sta(ar, mlme.im_macaddr); |
| break; |
| default: |
| ret = 0; |
| goto ioctl_done; |
| } |
| |
| wmi_ap_set_mlme(ar->arWmi, mlme.im_op, mlme.im_macaddr, |
| mlme.im_reason); |
| } |
| break; |
| } |
| case IEEE80211_IOCTL_ADDPMKID: |
| { |
| struct ieee80211req_addpmkid req; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&req, userdata, sizeof(struct ieee80211req_addpmkid))) { |
| ret = -EFAULT; |
| } else { |
| int status; |
| |
| AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("Add pmkid for %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x en=%d\n", |
| req.pi_bssid[0], req.pi_bssid[1], req.pi_bssid[2], |
| req.pi_bssid[3], req.pi_bssid[4], req.pi_bssid[5], |
| req.pi_enable)); |
| |
| status = wmi_setPmkid_cmd(ar->arWmi, req.pi_bssid, req.pi_pmkid, |
| req.pi_enable); |
| |
| if (status) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| } |
| break; |
| } |
| #ifdef CONFIG_HOST_TCMD_SUPPORT |
| case AR6000_XIOCTL_TCMD_CONT_TX: |
| { |
| TCMD_CONT_TX txCmd; |
| |
| if ((ar->tcmdPm == TCMD_PM_SLEEP) || |
| (ar->tcmdPm == TCMD_PM_DEEPSLEEP)) |
| { |
| A_PRINTF("Can NOT send tx tcmd when target is asleep! \n"); |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| |
| if(copy_from_user(&txCmd, userdata, sizeof(TCMD_CONT_TX))) { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } else { |
| wmi_test_cmd(ar->arWmi,(u8 *)&txCmd, sizeof(TCMD_CONT_TX)); |
| } |
| } |
| break; |
| case AR6000_XIOCTL_TCMD_CONT_RX: |
| { |
| TCMD_CONT_RX rxCmd; |
| |
| if ((ar->tcmdPm == TCMD_PM_SLEEP) || |
| (ar->tcmdPm == TCMD_PM_DEEPSLEEP)) |
| { |
| A_PRINTF("Can NOT send rx tcmd when target is asleep! \n"); |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| if(copy_from_user(&rxCmd, userdata, sizeof(TCMD_CONT_RX))) { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| |
| switch(rxCmd.act) |
| { |
| case TCMD_CONT_RX_PROMIS: |
| case TCMD_CONT_RX_FILTER: |
| case TCMD_CONT_RX_SETMAC: |
| case TCMD_CONT_RX_SET_ANT_SWITCH_TABLE: |
| wmi_test_cmd(ar->arWmi,(u8 *)&rxCmd, |
| sizeof(TCMD_CONT_RX)); |
| tcmdRxFreq = rxCmd.u.para.freq; |
| break; |
| case TCMD_CONT_RX_REPORT: |
| ar6000_ioctl_tcmd_get_rx_report(dev, rq, |
| (u8 *)&rxCmd, sizeof(TCMD_CONT_RX)); |
| break; |
| default: |
| A_PRINTF("Unknown Cont Rx mode: %d\n",rxCmd.act); |
| ret = -EINVAL; |
| goto ioctl_done; |
| } |
| } |
| break; |
| case AR6000_XIOCTL_TCMD_PM: |
| { |
| TCMD_PM pmCmd; |
| |
| if(copy_from_user(&pmCmd, userdata, sizeof(TCMD_PM))) { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| ar->tcmdPm = pmCmd.mode; |
| wmi_test_cmd(ar->arWmi, (u8 *)&pmCmd, sizeof(TCMD_PM)); |
| } |
| break; |
| #endif /* CONFIG_HOST_TCMD_SUPPORT */ |
| |
| case AR6000_XIOCTL_BMI_DONE: |
| if(bmienable) |
| { |
| rtnl_lock(); /* ar6000_init expects to be called holding rtnl lock */ |
| ret = ar6000_init(dev); |
| rtnl_unlock(); |
| } |
| else |
| { |
| ret = BMIDone(hifDevice); |
| } |
| break; |
| |
| case AR6000_XIOCTL_BMI_READ_MEMORY: |
| if (get_user(address, (unsigned int *)userdata) || |
| get_user(length, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Read Memory (address: 0x%x, length: %d)\n", |
| address, length)); |
| if ((buffer = (unsigned char *)A_MALLOC(length)) != NULL) { |
| A_MEMZERO(buffer, length); |
| ret = BMIReadMemory(hifDevice, address, buffer, length); |
| if (copy_to_user(rq->ifr_data, buffer, length)) { |
| ret = -EFAULT; |
| } |
| A_FREE(buffer); |
| } else { |
| ret = -ENOMEM; |
| } |
| break; |
| |
| case AR6000_XIOCTL_BMI_WRITE_MEMORY: |
| if (get_user(address, (unsigned int *)userdata) || |
| get_user(length, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Write Memory (address: 0x%x, length: %d)\n", |
| address, length)); |
| if ((buffer = (unsigned char *)A_MALLOC(length)) != NULL) { |
| A_MEMZERO(buffer, length); |
| if (copy_from_user(buffer, &userdata[sizeof(address) + |
| sizeof(length)], length)) |
| { |
| ret = -EFAULT; |
| } else { |
| ret = BMIWriteMemory(hifDevice, address, buffer, length); |
| } |
| A_FREE(buffer); |
| } else { |
| ret = -ENOMEM; |
| } |
| break; |
| |
| case AR6000_XIOCTL_BMI_TEST: |
| AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("No longer supported\n")); |
| ret = -EOPNOTSUPP; |
| break; |
| |
| case AR6000_XIOCTL_BMI_EXECUTE: |
| if (get_user(address, (unsigned int *)userdata) || |
| get_user(param, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Execute (address: 0x%x, param: %d)\n", |
| address, param)); |
| ret = BMIExecute(hifDevice, address, (u32 *)¶m); |
| /* return value */ |
| if (put_user(param, (unsigned int *)rq->ifr_data)) { |
| ret = -EFAULT; |
| break; |
| } |
| break; |
| |
| case AR6000_XIOCTL_BMI_SET_APP_START: |
| if (get_user(address, (unsigned int *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Set App Start (address: 0x%x)\n", address)); |
| ret = BMISetAppStart(hifDevice, address); |
| break; |
| |
| case AR6000_XIOCTL_BMI_READ_SOC_REGISTER: |
| if (get_user(address, (unsigned int *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| ret = BMIReadSOCRegister(hifDevice, address, (u32 *)¶m); |
| /* return value */ |
| if (put_user(param, (unsigned int *)rq->ifr_data)) { |
| ret = -EFAULT; |
| break; |
| } |
| break; |
| |
| case AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER: |
| if (get_user(address, (unsigned int *)userdata) || |
| get_user(param, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| ret = BMIWriteSOCRegister(hifDevice, address, param); |
| break; |
| |
| #ifdef HTC_RAW_INTERFACE |
| case AR6000_XIOCTL_HTC_RAW_OPEN: |
| ret = 0; |
| if (!arRawIfEnabled(ar)) { |
| /* make sure block size is set in case the target was reset since last |
| * BMI phase (i.e. flashup downloads) */ |
| ret = ar6000_set_htc_params(ar->arHifDevice, |
| ar->arTargetType, |
| 0, /* use default yield */ |
| 0 /* use default number of HTC ctrl buffers */ |
| ); |
| if (ret) { |
| break; |
| } |
| /* Terminate the BMI phase */ |
| ret = BMIDone(hifDevice); |
| if (ret == 0) { |
| ret = ar6000_htc_raw_open(ar); |
| } |
| } |
| break; |
| |
| case AR6000_XIOCTL_HTC_RAW_CLOSE: |
| if (arRawIfEnabled(ar)) { |
| ret = ar6000_htc_raw_close(ar); |
| arRawIfEnabled(ar) = false; |
| } else { |
| ret = A_ERROR; |
| } |
| break; |
| |
| case AR6000_XIOCTL_HTC_RAW_READ: |
| if (arRawIfEnabled(ar)) { |
| unsigned int streamID; |
| if (get_user(streamID, (unsigned int *)userdata) || |
| get_user(length, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| buffer = (unsigned char*)rq->ifr_data + sizeof(length); |
| ret = ar6000_htc_raw_read(ar, (HTC_RAW_STREAM_ID)streamID, |
| (char*)buffer, length); |
| if (put_user(ret, (unsigned int *)rq->ifr_data)) { |
| ret = -EFAULT; |
| break; |
| } |
| } else { |
| ret = A_ERROR; |
| } |
| break; |
| |
| case AR6000_XIOCTL_HTC_RAW_WRITE: |
| if (arRawIfEnabled(ar)) { |
| unsigned int streamID; |
| if (get_user(streamID, (unsigned int *)userdata) || |
| get_user(length, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| buffer = (unsigned char*)userdata + sizeof(streamID) + sizeof(length); |
| ret = ar6000_htc_raw_write(ar, (HTC_RAW_STREAM_ID)streamID, |
| (char*)buffer, length); |
| if (put_user(ret, (unsigned int *)rq->ifr_data)) { |
| ret = -EFAULT; |
| break; |
| } |
| } else { |
| ret = A_ERROR; |
| } |
| break; |
| #endif /* HTC_RAW_INTERFACE */ |
| |
| case AR6000_XIOCTL_BMI_LZ_STREAM_START: |
| if (get_user(address, (unsigned int *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Start Compressed Stream (address: 0x%x)\n", address)); |
| ret = BMILZStreamStart(hifDevice, address); |
| break; |
| |
| case AR6000_XIOCTL_BMI_LZ_DATA: |
| if (get_user(length, (unsigned int *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Send Compressed Data (length: %d)\n", length)); |
| if ((buffer = (unsigned char *)A_MALLOC(length)) != NULL) { |
| A_MEMZERO(buffer, length); |
| if (copy_from_user(buffer, &userdata[sizeof(length)], length)) |
| { |
| ret = -EFAULT; |
| } else { |
| ret = BMILZData(hifDevice, buffer, length); |
| } |
| A_FREE(buffer); |
| } else { |
| ret = -ENOMEM; |
| } |
| break; |
| |
| #if defined(CONFIG_TARGET_PROFILE_SUPPORT) |
| /* |
| * Optional support for Target-side profiling. |
| * Not needed in production. |
| */ |
| |
| /* Configure Target-side profiling */ |
| case AR6000_XIOCTL_PROF_CFG: |
| { |
| u32 period; |
| u32 nbins; |
| if (get_user(period, (unsigned int *)userdata) || |
| get_user(nbins, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| if (wmi_prof_cfg_cmd(ar->arWmi, period, nbins) != 0) { |
| ret = -EIO; |
| } |
| |
| break; |
| } |
| |
| /* Start a profiling bucket/bin at the specified address */ |
| case AR6000_XIOCTL_PROF_ADDR_SET: |
| { |
| u32 addr; |
| if (get_user(addr, (unsigned int *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| if (wmi_prof_addr_set_cmd(ar->arWmi, addr) != 0) { |
| ret = -EIO; |
| } |
| |
| break; |
| } |
| |
| /* START Target-side profiling */ |
| case AR6000_XIOCTL_PROF_START: |
| wmi_prof_start_cmd(ar->arWmi); |
| break; |
| |
| /* STOP Target-side profiling */ |
| case AR6000_XIOCTL_PROF_STOP: |
| wmi_prof_stop_cmd(ar->arWmi); |
| break; |
| case AR6000_XIOCTL_PROF_COUNT_GET: |
| { |
| if (ar->bIsDestroyProgress) { |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| |
| prof_count_available = false; |
| ret = prof_count_get(dev); |
| if (ret != 0) { |
| up(&ar->arSem); |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| |
| /* Wait for Target to respond. */ |
| wait_event_interruptible(arEvent, prof_count_available); |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } else { |
| if (copy_to_user(userdata, &prof_count_results, |
| sizeof(prof_count_results))) |
| { |
| ret = -EFAULT; |
| } |
| } |
| up(&ar->arSem); |
| break; |
| } |
| #endif /* CONFIG_TARGET_PROFILE_SUPPORT */ |
| |
| case AR6000_IOCTL_WMI_GETREV: |
| { |
| if (copy_to_user(rq->ifr_data, &ar->arVersion, |
| sizeof(ar->arVersion))) |
| { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SETPWR: |
| { |
| WMI_POWER_MODE_CMD pwrModeCmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&pwrModeCmd, userdata, |
| sizeof(pwrModeCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_powermode_cmd(ar->arWmi, pwrModeCmd.powerMode) |
| != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_IBSS_PM_CAPS: |
| { |
| WMI_IBSS_PM_CAPS_CMD ibssPmCaps; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&ibssPmCaps, userdata, |
| sizeof(ibssPmCaps))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_ibsspmcaps_cmd(ar->arWmi, ibssPmCaps.power_saving, ibssPmCaps.ttl, |
| ibssPmCaps.atim_windows, ibssPmCaps.timeout_value) != 0) |
| { |
| ret = -EIO; |
| } |
| AR6000_SPIN_LOCK(&ar->arLock, 0); |
| ar->arIbssPsEnable = ibssPmCaps.power_saving; |
| AR6000_SPIN_UNLOCK(&ar->arLock, 0); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_AP_PS: |
| { |
| WMI_AP_PS_CMD apPsCmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&apPsCmd, userdata, |
| sizeof(apPsCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_apps_cmd(ar->arWmi, apPsCmd.psType, apPsCmd.idle_time, |
| apPsCmd.ps_period, apPsCmd.sleep_period) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_PMPARAMS: |
| { |
| WMI_POWER_PARAMS_CMD pmParams; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&pmParams, userdata, |
| sizeof(pmParams))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_pmparams_cmd(ar->arWmi, pmParams.idle_period, |
| pmParams.pspoll_number, |
| pmParams.dtim_policy, |
| pmParams.tx_wakeup_policy, |
| pmParams.num_tx_to_wakeup, |
| #if WLAN_CONFIG_IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN |
| IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN |
| #else |
| SEND_POWER_SAVE_FAIL_EVENT_ALWAYS |
| #endif |
| ) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SETSCAN: |
| { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&ar->scParams, userdata, |
| sizeof(ar->scParams))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (CAN_SCAN_IN_CONNECT(ar->scParams.scanCtrlFlags)) { |
| ar->arSkipScan = false; |
| } else { |
| ar->arSkipScan = true; |
| } |
| |
| if (wmi_scanparams_cmd(ar->arWmi, ar->scParams.fg_start_period, |
| ar->scParams.fg_end_period, |
| ar->scParams.bg_period, |
| ar->scParams.minact_chdwell_time, |
| ar->scParams.maxact_chdwell_time, |
| ar->scParams.pas_chdwell_time, |
| ar->scParams.shortScanRatio, |
| ar->scParams.scanCtrlFlags, |
| ar->scParams.max_dfsch_act_time, |
| ar->scParams.maxact_scan_per_ssid) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SETLISTENINT: |
| { |
| WMI_LISTEN_INT_CMD listenCmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&listenCmd, userdata, |
| sizeof(listenCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_listeninterval_cmd(ar->arWmi, listenCmd.listenInterval, listenCmd.numBeacons) != 0) { |
| ret = -EIO; |
| } else { |
| AR6000_SPIN_LOCK(&ar->arLock, 0); |
| ar->arListenIntervalT = listenCmd.listenInterval; |
| ar->arListenIntervalB = listenCmd.numBeacons; |
| AR6000_SPIN_UNLOCK(&ar->arLock, 0); |
| } |
| |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_BMISS_TIME: |
| { |
| WMI_BMISS_TIME_CMD bmissCmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&bmissCmd, userdata, |
| sizeof(bmissCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_bmisstime_cmd(ar->arWmi, bmissCmd.bmissTime, bmissCmd.numBeacons) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SETBSSFILTER: |
| { |
| WMI_BSS_FILTER_CMD filt; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&filt, userdata, |
| sizeof(filt))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_bssfilter_cmd(ar->arWmi, filt.bssFilter, filt.ieMask) |
| != 0) { |
| ret = -EIO; |
| } else { |
| ar->arUserBssFilter = filt.bssFilter; |
| } |
| } |
| break; |
| } |
| |
| case AR6000_IOCTL_WMI_SET_SNRTHRESHOLD: |
| { |
| ret = ar6000_ioctl_set_snr_threshold(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_RSSITHRESHOLD: |
| { |
| ret = ar6000_ioctl_set_rssi_threshold(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_CLR_RSSISNR: |
| { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } |
| ret = wmi_clr_rssi_snr(ar->arWmi); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_LQTHRESHOLD: |
| { |
| ret = ar6000_ioctl_set_lq_threshold(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_LPREAMBLE: |
| { |
| WMI_SET_LPREAMBLE_CMD setLpreambleCmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setLpreambleCmd, userdata, |
| sizeof(setLpreambleCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_lpreamble_cmd(ar->arWmi, setLpreambleCmd.status, |
| #if WLAN_CONFIG_DONOT_IGNORE_BARKER_IN_ERP |
| WMI_DONOT_IGNORE_BARKER_IN_ERP |
| #else |
| WMI_IGNORE_BARKER_IN_ERP |
| #endif |
| ) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_RTS: |
| { |
| WMI_SET_RTS_CMD rtsCmd; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&rtsCmd, userdata, |
| sizeof(rtsCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| ar->arRTS = rtsCmd.threshold; |
| if (wmi_set_rts_cmd(ar->arWmi, rtsCmd.threshold) |
| != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_WMM: |
| { |
| ret = ar6000_ioctl_set_wmm(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_QOS_SUPP: |
| { |
| ret = ar6000_ioctl_set_qos_supp(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_TXOP: |
| { |
| ret = ar6000_ioctl_set_txop(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_GET_RD: |
| { |
| ret = ar6000_ioctl_get_rd(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_CHANNELPARAMS: |
| { |
| ret = ar6000_ioctl_set_channelParams(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_PROBEDSSID: |
| { |
| ret = ar6000_ioctl_set_probedSsid(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_BADAP: |
| { |
| ret = ar6000_ioctl_set_badAp(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_CREATE_QOS: |
| { |
| ret = ar6000_ioctl_create_qos(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_DELETE_QOS: |
| { |
| ret = ar6000_ioctl_delete_qos(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_GET_QOS_QUEUE: |
| { |
| ret = ar6000_ioctl_get_qos_queue(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_GET_TARGET_STATS: |
| { |
| ret = ar6000_ioctl_get_target_stats(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_ERROR_REPORT_BITMASK: |
| { |
| ret = ar6000_ioctl_set_error_report_bitmask(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_ASSOC_INFO: |
| { |
| WMI_SET_ASSOC_INFO_CMD cmd; |
| u8 assocInfo[WMI_MAX_ASSOC_INFO_LEN]; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| break; |
| } |
| |
| if (get_user(cmd.ieType, userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| if (cmd.ieType >= WMI_MAX_ASSOC_INFO_TYPE) { |
| ret = -EIO; |
| break; |
| } |
| |
| if (get_user(cmd.bufferSize, userdata + 1) || |
| (cmd.bufferSize > WMI_MAX_ASSOC_INFO_LEN) || |
| copy_from_user(assocInfo, userdata + 2, cmd.bufferSize)) { |
| ret = -EFAULT; |
| break; |
| } |
| if (wmi_associnfo_cmd(ar->arWmi, cmd.ieType, |
| cmd.bufferSize, assocInfo) != 0) { |
| ret = -EIO; |
| break; |
| } |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_ACCESS_PARAMS: |
| { |
| ret = ar6000_ioctl_set_access_params(dev, rq); |
| break; |
| } |
| case AR6000_IOCTL_WMI_SET_DISC_TIMEOUT: |
| { |
| ret = ar6000_ioctl_set_disconnect_timeout(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_FORCE_TARGET_RESET: |
| { |
| if (ar->arHtcTarget) |
| { |
| // HTCForceReset(htcTarget); |
| } |
| else |
| { |
| AR_DEBUG_PRINTF(ATH_DEBUG_WARN,("ar6000_ioctl cannot attempt reset.\n")); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_TARGET_INFO: |
| case AR6000_XIOCTL_CHECK_TARGET_READY: /* backwards compatibility */ |
| { |
| /* If we made it to here, then the Target exists and is ready. */ |
| |
| if (cmd == AR6000_XIOCTL_TARGET_INFO) { |
| if (copy_to_user((u32 *)rq->ifr_data, &ar->arVersion.target_ver, |
| sizeof(ar->arVersion.target_ver))) |
| { |
| ret = -EFAULT; |
| } |
| if (copy_to_user(((u32 *)rq->ifr_data)+1, &ar->arTargetType, |
| sizeof(ar->arTargetType))) |
| { |
| ret = -EFAULT; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS: |
| { |
| WMI_SET_HB_CHALLENGE_RESP_PARAMS_CMD hbparam; |
| |
| if (copy_from_user(&hbparam, userdata, sizeof(hbparam))) |
| { |
| ret = -EFAULT; |
| } else { |
| AR6000_SPIN_LOCK(&ar->arLock, 0); |
| /* Start a cyclic timer with the parameters provided. */ |
| if (hbparam.frequency) { |
| ar->arHBChallengeResp.frequency = hbparam.frequency; |
| } |
| if (hbparam.threshold) { |
| ar->arHBChallengeResp.missThres = hbparam.threshold; |
| } |
| |
| /* Delete the pending timer and start a new one */ |
| if (timer_pending(&ar->arHBChallengeResp.timer)) { |
| A_UNTIMEOUT(&ar->arHBChallengeResp.timer); |
| } |
| A_TIMEOUT_MS(&ar->arHBChallengeResp.timer, ar->arHBChallengeResp.frequency * 1000, 0); |
| AR6000_SPIN_UNLOCK(&ar->arLock, 0); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP: |
| { |
| u32 cookie; |
| |
| if (copy_from_user(&cookie, userdata, sizeof(cookie))) { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| |
| /* Send the challenge on the control channel */ |
| if (wmi_get_challenge_resp_cmd(ar->arWmi, cookie, APP_HB_CHALLENGE) != 0) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| break; |
| } |
| #ifdef USER_KEYS |
| case AR6000_XIOCTL_USER_SETKEYS: |
| { |
| |
| ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_RUN; |
| |
| if (copy_from_user(&ar->user_key_ctrl, userdata, |
| sizeof(ar->user_key_ctrl))) |
| { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| |
| A_PRINTF("ar6000 USER set key %x\n", ar->user_key_ctrl); |
| break; |
| } |
| #endif /* USER_KEYS */ |
| |
| #ifdef CONFIG_HOST_GPIO_SUPPORT |
| case AR6000_XIOCTL_GPIO_OUTPUT_SET: |
| { |
| struct ar6000_gpio_output_set_cmd_s gpio_output_set_cmd; |
| |
| if (ar->bIsDestroyProgress) { |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| |
| if (copy_from_user(&gpio_output_set_cmd, userdata, |
| sizeof(gpio_output_set_cmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| ret = ar6000_gpio_output_set(dev, |
| gpio_output_set_cmd.set_mask, |
| gpio_output_set_cmd.clear_mask, |
| gpio_output_set_cmd.enable_mask, |
| gpio_output_set_cmd.disable_mask); |
| if (ret != 0) { |
| ret = -EIO; |
| } |
| } |
| up(&ar->arSem); |
| break; |
| } |
| case AR6000_XIOCTL_GPIO_INPUT_GET: |
| { |
| if (ar->bIsDestroyProgress) { |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| |
| ret = ar6000_gpio_input_get(dev); |
| if (ret != 0) { |
| up(&ar->arSem); |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| |
| /* Wait for Target to respond. */ |
| wait_event_interruptible(arEvent, gpio_data_available); |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } else { |
| A_ASSERT(gpio_reg_results.gpioreg_id == GPIO_ID_NONE); |
| |
| if (copy_to_user(userdata, &gpio_reg_results.value, |
| sizeof(gpio_reg_results.value))) |
| { |
| ret = -EFAULT; |
| } |
| } |
| up(&ar->arSem); |
| break; |
| } |
| case AR6000_XIOCTL_GPIO_REGISTER_SET: |
| { |
| struct ar6000_gpio_register_cmd_s gpio_register_cmd; |
| |
| if (ar->bIsDestroyProgress) { |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| |
| if (copy_from_user(&gpio_register_cmd, userdata, |
| sizeof(gpio_register_cmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| ret = ar6000_gpio_register_set(dev, |
| gpio_register_cmd.gpioreg_id, |
| gpio_register_cmd.value); |
| if (ret != 0) { |
| ret = -EIO; |
| } |
| |
| /* Wait for acknowledgement from Target */ |
| wait_event_interruptible(arEvent, gpio_ack_received); |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| } |
| up(&ar->arSem); |
| break; |
| } |
| case AR6000_XIOCTL_GPIO_REGISTER_GET: |
| { |
| struct ar6000_gpio_register_cmd_s gpio_register_cmd; |
| |
| if (ar->bIsDestroyProgress) { |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| |
| if (copy_from_user(&gpio_register_cmd, userdata, |
| sizeof(gpio_register_cmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| ret = ar6000_gpio_register_get(dev, gpio_register_cmd.gpioreg_id); |
| if (ret != 0) { |
| up(&ar->arSem); |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| |
| /* Wait for Target to respond. */ |
| wait_event_interruptible(arEvent, gpio_data_available); |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } else { |
| A_ASSERT(gpio_register_cmd.gpioreg_id == gpio_reg_results.gpioreg_id); |
| if (copy_to_user(userdata, &gpio_reg_results, |
| sizeof(gpio_reg_results))) |
| { |
| ret = -EFAULT; |
| } |
| } |
| } |
| up(&ar->arSem); |
| break; |
| } |
| case AR6000_XIOCTL_GPIO_INTR_ACK: |
| { |
| struct ar6000_gpio_intr_ack_cmd_s gpio_intr_ack_cmd; |
| |
| if (ar->bIsDestroyProgress) { |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| |
| if (copy_from_user(&gpio_intr_ack_cmd, userdata, |
| sizeof(gpio_intr_ack_cmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| ret = ar6000_gpio_intr_ack(dev, gpio_intr_ack_cmd.ack_mask); |
| if (ret != 0) { |
| ret = -EIO; |
| } |
| } |
| up(&ar->arSem); |
| break; |
| } |
| case AR6000_XIOCTL_GPIO_INTR_WAIT: |
| { |
| /* Wait for Target to report an interrupt. */ |
| wait_event_interruptible(arEvent, gpio_intr_available); |
| |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } else { |
| if (copy_to_user(userdata, &gpio_intr_results, |
| sizeof(gpio_intr_results))) |
| { |
| ret = -EFAULT; |
| } |
| } |
| break; |
| } |
| #endif /* CONFIG_HOST_GPIO_SUPPORT */ |
| |
| case AR6000_XIOCTL_DBGLOG_CFG_MODULE: |
| { |
| struct ar6000_dbglog_module_config_s config; |
| |
| if (copy_from_user(&config, userdata, sizeof(config))) { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| |
| /* Send the challenge on the control channel */ |
| if (wmi_config_debug_module_cmd(ar->arWmi, config.mmask, |
| config.tsr, config.rep, |
| config.size, config.valid) != 0) |
| { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_DBGLOG_GET_DEBUG_LOGS: |
| { |
| /* Send the challenge on the control channel */ |
| if (ar6000_dbglog_get_debug_logs(ar) != 0) |
| { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_SET_ADHOC_BSSID: |
| { |
| WMI_SET_ADHOC_BSSID_CMD adhocBssid; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&adhocBssid, userdata, |
| sizeof(adhocBssid))) |
| { |
| ret = -EFAULT; |
| } else if (memcmp(adhocBssid.bssid, bcast_mac, |
| AR6000_ETH_ADDR_LEN) == 0) |
| { |
| ret = -EFAULT; |
| } else { |
| |
| memcpy(ar->arReqBssid, adhocBssid.bssid, sizeof(ar->arReqBssid)); |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_SET_OPT_MODE: |
| { |
| WMI_SET_OPT_MODE_CMD optModeCmd; |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&optModeCmd, userdata, |
| sizeof(optModeCmd))) |
| { |
| ret = -EFAULT; |
| } else if (ar->arConnected && optModeCmd.optMode == SPECIAL_ON) { |
| ret = -EFAULT; |
| |
| } else if (wmi_set_opt_mode_cmd(ar->arWmi, optModeCmd.optMode) |
| != 0) |
| { |
| ret = -EIO; |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_OPT_SEND_FRAME: |
| { |
| WMI_OPT_TX_FRAME_CMD optTxFrmCmd; |
| u8 data[MAX_OPT_DATA_LEN]; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| break; |
| } |
| |
| if (copy_from_user(&optTxFrmCmd, userdata, sizeof(optTxFrmCmd))) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| if (optTxFrmCmd.optIEDataLen > MAX_OPT_DATA_LEN) { |
| ret = -EINVAL; |
| break; |
| } |
| |
| if (copy_from_user(data, userdata+sizeof(WMI_OPT_TX_FRAME_CMD) - 1, |
| optTxFrmCmd.optIEDataLen)) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| ret = wmi_opt_tx_frame_cmd(ar->arWmi, |
| optTxFrmCmd.frmType, |
| optTxFrmCmd.dstAddr, |
| optTxFrmCmd.bssid, |
| optTxFrmCmd.optIEDataLen, |
| data); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SETRETRYLIMITS: |
| { |
| WMI_SET_RETRY_LIMITS_CMD setRetryParams; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setRetryParams, userdata, |
| sizeof(setRetryParams))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_retry_limits_cmd(ar->arWmi, setRetryParams.frameType, |
| setRetryParams.trafficClass, |
| setRetryParams.maxRetries, |
| setRetryParams.enableNotify) != 0) |
| { |
| ret = -EIO; |
| } |
| AR6000_SPIN_LOCK(&ar->arLock, 0); |
| ar->arMaxRetries = setRetryParams.maxRetries; |
| AR6000_SPIN_UNLOCK(&ar->arLock, 0); |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_SET_BEACON_INTVAL: |
| { |
| WMI_BEACON_INT_CMD bIntvlCmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&bIntvlCmd, userdata, |
| sizeof(bIntvlCmd))) |
| { |
| ret = -EFAULT; |
| } else if (wmi_set_adhoc_bconIntvl_cmd(ar->arWmi, bIntvlCmd.beaconInterval) |
| != 0) |
| { |
| ret = -EIO; |
| } |
| if(ret == 0) { |
| ar->ap_beacon_interval = bIntvlCmd.beaconInterval; |
| ar->ap_profile_flag = 1; /* There is a change in profile */ |
| } |
| break; |
| } |
| case IEEE80211_IOCTL_SETAUTHALG: |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| struct ieee80211req_authalg req; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&req, userdata, |
| sizeof(struct ieee80211req_authalg))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (req.auth_alg & AUTH_ALG_OPEN_SYSTEM) { |
| ar->arDot11AuthMode |= OPEN_AUTH; |
| ar->arPairwiseCrypto = NONE_CRYPT; |
| ar->arGroupCrypto = NONE_CRYPT; |
| } |
| if (req.auth_alg & AUTH_ALG_SHARED_KEY) { |
| ar->arDot11AuthMode |= SHARED_AUTH; |
| ar->arPairwiseCrypto = WEP_CRYPT; |
| ar->arGroupCrypto = WEP_CRYPT; |
| ar->arAuthMode = NONE_AUTH; |
| } |
| if (req.auth_alg == AUTH_ALG_LEAP) { |
| ar->arDot11AuthMode = LEAP_AUTH; |
| } |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_SET_VOICE_PKT_SIZE: |
| ret = ar6000_xioctl_set_voice_pkt_size(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_SET_MAX_SP: |
| ret = ar6000_xioctl_set_max_sp_len(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_GET_ROAM_TBL: |
| ret = ar6000_ioctl_get_roam_tbl(dev, rq); |
| break; |
| case AR6000_XIOCTL_WMI_SET_ROAM_CTRL: |
| ret = ar6000_ioctl_set_roam_ctrl(dev, userdata); |
| break; |
| case AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS: |
| ret = ar6000_ioctl_set_powersave_timers(dev, userdata); |
| break; |
| case AR6000_XIOCTRL_WMI_GET_POWER_MODE: |
| ret = ar6000_ioctl_get_power_mode(dev, rq); |
| break; |
| case AR6000_XIOCTRL_WMI_SET_WLAN_STATE: |
| { |
| AR6000_WLAN_STATE state; |
| if (get_user(state, (unsigned int *)userdata)) |
| ret = -EFAULT; |
| else if (ar6000_set_wlan_state(ar, state) != 0) |
| ret = -EIO; |
| break; |
| } |
| case AR6000_XIOCTL_WMI_GET_ROAM_DATA: |
| ret = ar6000_ioctl_get_roam_data(dev, rq); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BT_STATUS: |
| ret = ar6000_xioctl_set_bt_status_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BT_PARAMS: |
| ret = ar6000_xioctl_set_bt_params_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BTCOEX_FE_ANT: |
| ret = ar6000_xioctl_set_btcoex_fe_ant_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BTCOEX_COLOCATED_BT_DEV: |
| ret = ar6000_xioctl_set_btcoex_colocated_bt_dev_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG: |
| ret = ar6000_xioctl_set_btcoex_btinquiry_page_config_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BTCOEX_SCO_CONFIG: |
| ret = ar6000_xioctl_set_btcoex_sco_config_cmd( dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BTCOEX_A2DP_CONFIG: |
| ret = ar6000_xioctl_set_btcoex_a2dp_config_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BTCOEX_ACLCOEX_CONFIG: |
| ret = ar6000_xioctl_set_btcoex_aclcoex_config_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BTCOEX_DEBUG: |
| ret = ar60000_xioctl_set_btcoex_debug_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_BT_OPERATING_STATUS: |
| ret = ar6000_xioctl_set_btcoex_bt_operating_status_cmd(dev, userdata); |
| break; |
| |
| case AR6000_XIOCTL_WMI_GET_BTCOEX_CONFIG: |
| ret = ar6000_xioctl_get_btcoex_config_cmd(dev, userdata, rq); |
| break; |
| |
| case AR6000_XIOCTL_WMI_GET_BTCOEX_STATS: |
| ret = ar6000_xioctl_get_btcoex_stats_cmd(dev, userdata, rq); |
| break; |
| |
| case AR6000_XIOCTL_WMI_STARTSCAN: |
| { |
| WMI_START_SCAN_CMD setStartScanCmd, *cmdp; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setStartScanCmd, userdata, |
| sizeof(setStartScanCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (setStartScanCmd.numChannels > 1) { |
| cmdp = A_MALLOC(130); |
| if (copy_from_user(cmdp, userdata, |
| sizeof (*cmdp) + |
| ((setStartScanCmd.numChannels - 1) * |
| sizeof(u16)))) |
| { |
| kfree(cmdp); |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| } else { |
| cmdp = &setStartScanCmd; |
| } |
| |
| if (wmi_startscan_cmd(ar->arWmi, cmdp->scanType, |
| cmdp->forceFgScan, |
| cmdp->isLegacy, |
| cmdp->homeDwellTime, |
| cmdp->forceScanInterval, |
| cmdp->numChannels, |
| cmdp->channelList) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SETFIXRATES: |
| { |
| WMI_FIX_RATES_CMD setFixRatesCmd; |
| int returnStatus; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setFixRatesCmd, userdata, |
| sizeof(setFixRatesCmd))) |
| { |
| ret = -EFAULT; |
| } else { |
| returnStatus = wmi_set_fixrates_cmd(ar->arWmi, setFixRatesCmd.fixRateMask); |
| if (returnStatus == A_EINVAL) { |
| ret = -EINVAL; |
| } else if(returnStatus != 0) { |
| ret = -EIO; |
| } else { |
| ar->ap_profile_flag = 1; /* There is a change in profile */ |
| } |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_WMI_GETFIXRATES: |
| { |
| WMI_FIX_RATES_CMD getFixRatesCmd; |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| int ret = 0; |
| |
| if (ar->bIsDestroyProgress) { |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| /* Used copy_from_user/copy_to_user to access user space data */ |
| if (copy_from_user(&getFixRatesCmd, userdata, sizeof(getFixRatesCmd))) { |
| ret = -EFAULT; |
| } else { |
| ar->arRateMask = 0xFFFFFFFF; |
| |
| if (wmi_get_ratemask_cmd(ar->arWmi) != 0) { |
| up(&ar->arSem); |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| |
| wait_event_interruptible_timeout(arEvent, ar->arRateMask != 0xFFFFFFFF, wmitimeout * HZ); |
| |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| |
| if (!ret) { |
| getFixRatesCmd.fixRateMask = ar->arRateMask; |
| } |
| |
| if(copy_to_user(userdata, &getFixRatesCmd, sizeof(getFixRatesCmd))) { |
| ret = -EFAULT; |
| } |
| |
| up(&ar->arSem); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_AUTHMODE: |
| { |
| WMI_SET_AUTH_MODE_CMD setAuthMode; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setAuthMode, userdata, |
| sizeof(setAuthMode))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_authmode_cmd(ar->arWmi, setAuthMode.mode) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_REASSOCMODE: |
| { |
| WMI_SET_REASSOC_MODE_CMD setReassocMode; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setReassocMode, userdata, |
| sizeof(setReassocMode))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_reassocmode_cmd(ar->arWmi, setReassocMode.mode) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_DIAG_READ: |
| { |
| u32 addr, data; |
| if (get_user(addr, (unsigned int *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| addr = TARG_VTOP(ar->arTargetType, addr); |
| if (ar6000_ReadRegDiag(ar->arHifDevice, &addr, &data) != 0) { |
| ret = -EIO; |
| } |
| if (put_user(data, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_DIAG_WRITE: |
| { |
| u32 addr, data; |
| if (get_user(addr, (unsigned int *)userdata) || |
| get_user(data, (unsigned int *)userdata + 1)) { |
| ret = -EFAULT; |
| break; |
| } |
| addr = TARG_VTOP(ar->arTargetType, addr); |
| if (ar6000_WriteRegDiag(ar->arHifDevice, &addr, &data) != 0) { |
| ret = -EIO; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_KEEPALIVE: |
| { |
| WMI_SET_KEEPALIVE_CMD setKeepAlive; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } else if (copy_from_user(&setKeepAlive, userdata, |
| sizeof(setKeepAlive))){ |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_keepalive_cmd(ar->arWmi, setKeepAlive.keepaliveInterval) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_PARAMS: |
| { |
| WMI_SET_PARAMS_CMD cmd; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } else if (copy_from_user(&cmd, userdata, |
| sizeof(cmd))){ |
| ret = -EFAULT; |
| } else if (copy_from_user(&cmd, userdata, |
| sizeof(cmd) + cmd.length)) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_params_cmd(ar->arWmi, cmd.opcode, cmd.length, cmd.buffer) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_MCAST_FILTER: |
| { |
| WMI_SET_MCAST_FILTER_CMD cmd; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } else if (copy_from_user(&cmd, userdata, |
| sizeof(cmd))){ |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_mcast_filter_cmd(ar->arWmi, cmd.multicast_mac[0], |
| cmd.multicast_mac[1], |
| cmd.multicast_mac[2], |
| cmd.multicast_mac[3]) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_DEL_MCAST_FILTER: |
| { |
| WMI_SET_MCAST_FILTER_CMD cmd; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } else if (copy_from_user(&cmd, userdata, |
| sizeof(cmd))){ |
| ret = -EFAULT; |
| } else { |
| if (wmi_del_mcast_filter_cmd(ar->arWmi, cmd.multicast_mac[0], |
| cmd.multicast_mac[1], |
| cmd.multicast_mac[2], |
| cmd.multicast_mac[3]) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_MCAST_FILTER: |
| { |
| WMI_MCAST_FILTER_CMD cmd; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } else if (copy_from_user(&cmd, userdata, |
| sizeof(cmd))){ |
| ret = -EFAULT; |
| } else { |
| if (wmi_mcast_filter_cmd(ar->arWmi, cmd.enable) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_GET_KEEPALIVE: |
| { |
| AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev); |
| WMI_GET_KEEPALIVE_CMD getKeepAlive; |
| int ret = 0; |
| if (ar->bIsDestroyProgress) { |
| ret =-EBUSY; |
| goto ioctl_done; |
| } |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (down_interruptible(&ar->arSem)) { |
| ret = -ERESTARTSYS; |
| goto ioctl_done; |
| } |
| if (ar->bIsDestroyProgress) { |
| up(&ar->arSem); |
| ret = -EBUSY; |
| goto ioctl_done; |
| } |
| if (copy_from_user(&getKeepAlive, userdata,sizeof(getKeepAlive))) { |
| ret = -EFAULT; |
| } else { |
| getKeepAlive.keepaliveInterval = wmi_get_keepalive_cmd(ar->arWmi); |
| ar->arKeepaliveConfigured = 0xFF; |
| if (wmi_get_keepalive_configured(ar->arWmi) != 0){ |
| up(&ar->arSem); |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| wait_event_interruptible_timeout(arEvent, ar->arKeepaliveConfigured != 0xFF, wmitimeout * HZ); |
| if (signal_pending(current)) { |
| ret = -EINTR; |
| } |
| |
| if (!ret) { |
| getKeepAlive.configured = ar->arKeepaliveConfigured; |
| } |
| if (copy_to_user(userdata, &getKeepAlive, sizeof(getKeepAlive))) { |
| ret = -EFAULT; |
| } |
| up(&ar->arSem); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_APPIE: |
| { |
| WMI_SET_APPIE_CMD appIEcmd; |
| u8 appIeInfo[IEEE80211_APPIE_FRAME_MAX_LEN]; |
| u32 fType,ieLen; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } |
| if (get_user(fType, (u32 *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| appIEcmd.mgmtFrmType = fType; |
| if (appIEcmd.mgmtFrmType >= IEEE80211_APPIE_NUM_OF_FRAME) { |
| ret = -EIO; |
| } else { |
| if (get_user(ieLen, (u32 *)(userdata + 4))) { |
| ret = -EFAULT; |
| break; |
| } |
| appIEcmd.ieLen = ieLen; |
| A_PRINTF("WPSIE: Type-%d, Len-%d\n",appIEcmd.mgmtFrmType, appIEcmd.ieLen); |
| if (appIEcmd.ieLen > IEEE80211_APPIE_FRAME_MAX_LEN) { |
| ret = -EIO; |
| break; |
| } |
| if (copy_from_user(appIeInfo, userdata + 8, appIEcmd.ieLen)) { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_appie_cmd(ar->arWmi, appIEcmd.mgmtFrmType, |
| appIEcmd.ieLen, appIeInfo) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_MGMT_FRM_RX_FILTER: |
| { |
| WMI_BSS_FILTER_CMD cmd; |
| u32 filterType; |
| |
| if (copy_from_user(&filterType, userdata, sizeof(u32))) |
| { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| if (filterType & (IEEE80211_FILTER_TYPE_BEACON | |
| IEEE80211_FILTER_TYPE_PROBE_RESP)) |
| { |
| cmd.bssFilter = ALL_BSS_FILTER; |
| } else { |
| cmd.bssFilter = NONE_BSS_FILTER; |
| } |
| if (wmi_bssfilter_cmd(ar->arWmi, cmd.bssFilter, 0) != 0) { |
| ret = -EIO; |
| } else { |
| ar->arUserBssFilter = cmd.bssFilter; |
| } |
| |
| AR6000_SPIN_LOCK(&ar->arLock, 0); |
| ar->arMgmtFilter = filterType; |
| AR6000_SPIN_UNLOCK(&ar->arLock, 0); |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_WSC_STATUS: |
| { |
| u32 wsc_status; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| goto ioctl_done; |
| } else if (copy_from_user(&wsc_status, userdata, sizeof(u32))) |
| { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| if (wmi_set_wsc_status_cmd(ar->arWmi, wsc_status) != 0) { |
| ret = -EIO; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_BMI_ROMPATCH_INSTALL: |
| { |
| u32 ROM_addr; |
| u32 RAM_addr; |
| u32 nbytes; |
| u32 do_activate; |
| u32 rompatch_id; |
| |
| if (get_user(ROM_addr, (u32 *)userdata) || |
| get_user(RAM_addr, (u32 *)userdata + 1) || |
| get_user(nbytes, (u32 *)userdata + 2) || |
| get_user(do_activate, (u32 *)userdata + 3)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Install rompatch from ROM: 0x%x to RAM: 0x%x length: %d\n", |
| ROM_addr, RAM_addr, nbytes)); |
| ret = BMIrompatchInstall(hifDevice, ROM_addr, RAM_addr, |
| nbytes, do_activate, &rompatch_id); |
| if (ret == 0) { |
| /* return value */ |
| if (put_user(rompatch_id, (unsigned int *)rq->ifr_data)) { |
| ret = -EFAULT; |
| break; |
| } |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL: |
| { |
| u32 rompatch_id; |
| |
| if (get_user(rompatch_id, (u32 *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("UNinstall rompatch_id %d\n", rompatch_id)); |
| ret = BMIrompatchUninstall(hifDevice, rompatch_id); |
| break; |
| } |
| |
| case AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE: |
| case AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE: |
| { |
| u32 rompatch_count; |
| |
| if (get_user(rompatch_count, (u32 *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Change rompatch activation count=%d\n", rompatch_count)); |
| length = sizeof(u32) * rompatch_count; |
| if ((buffer = (unsigned char *)A_MALLOC(length)) != NULL) { |
| A_MEMZERO(buffer, length); |
| if (copy_from_user(buffer, &userdata[sizeof(rompatch_count)], length)) |
| { |
| ret = -EFAULT; |
| } else { |
| if (cmd == AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE) { |
| ret = BMIrompatchActivate(hifDevice, rompatch_count, (u32 *)buffer); |
| } else { |
| ret = BMIrompatchDeactivate(hifDevice, rompatch_count, (u32 *)buffer); |
| } |
| } |
| A_FREE(buffer); |
| } else { |
| ret = -ENOMEM; |
| } |
| |
| break; |
| } |
| case AR6000_XIOCTL_SET_IP: |
| { |
| WMI_SET_IP_CMD setIP; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setIP, userdata, |
| sizeof(setIP))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_ip_cmd(ar->arWmi, |
| &setIP) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_WMI_SET_HOST_SLEEP_MODE: |
| { |
| WMI_SET_HOST_SLEEP_MODE_CMD setHostSleepMode; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setHostSleepMode, userdata, |
| sizeof(setHostSleepMode))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_host_sleep_mode_cmd(ar->arWmi, |
| &setHostSleepMode) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_SET_WOW_MODE: |
| { |
| WMI_SET_WOW_MODE_CMD setWowMode; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&setWowMode, userdata, |
| sizeof(setWowMode))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_wow_mode_cmd(ar->arWmi, |
| &setWowMode) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_GET_WOW_LIST: |
| { |
| WMI_GET_WOW_LIST_CMD getWowList; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&getWowList, userdata, |
| sizeof(getWowList))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_get_wow_list_cmd(ar->arWmi, |
| &getWowList) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_ADD_WOW_PATTERN: |
| { |
| #define WOW_PATTERN_SIZE 64 |
| #define WOW_MASK_SIZE 64 |
| |
| WMI_ADD_WOW_PATTERN_CMD cmd; |
| u8 mask_data[WOW_PATTERN_SIZE]={0}; |
| u8 pattern_data[WOW_PATTERN_SIZE]={0}; |
| |
| do { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| break; |
| } |
| if(copy_from_user(&cmd, userdata, |
| sizeof(WMI_ADD_WOW_PATTERN_CMD))) |
| { |
| ret = -EFAULT; |
| break; |
| } |
| if (copy_from_user(pattern_data, |
| userdata + 3, |
| cmd.filter_size)) |
| { |
| ret = -EFAULT; |
| break; |
| } |
| if (copy_from_user(mask_data, |
| (userdata + 3 + cmd.filter_size), |
| cmd.filter_size)) |
| { |
| ret = -EFAULT; |
| break; |
| } |
| if (wmi_add_wow_pattern_cmd(ar->arWmi, |
| &cmd, pattern_data, mask_data, cmd.filter_size) != 0) |
| { |
| ret = -EIO; |
| } |
| } while(false); |
| #undef WOW_PATTERN_SIZE |
| #undef WOW_MASK_SIZE |
| break; |
| } |
| case AR6000_XIOCTL_WMI_DEL_WOW_PATTERN: |
| { |
| WMI_DEL_WOW_PATTERN_CMD delWowPattern; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&delWowPattern, userdata, |
| sizeof(delWowPattern))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_del_wow_pattern_cmd(ar->arWmi, |
| &delWowPattern) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_DUMP_HTC_CREDIT_STATE: |
| if (ar->arHtcTarget != NULL) { |
| #ifdef ATH_DEBUG_MODULE |
| HTCDumpCreditStates(ar->arHtcTarget); |
| #endif /* ATH_DEBUG_MODULE */ |
| #ifdef HTC_EP_STAT_PROFILING |
| { |
| struct htc_endpoint_stats stats; |
| int i; |
| |
| for (i = 0; i < 5; i++) { |
| if (HTCGetEndpointStatistics(ar->arHtcTarget, |
| i, |
| HTC_EP_STAT_SAMPLE_AND_CLEAR, |
| &stats)) { |
| A_PRINTF(KERN_ALERT"------- Profiling Endpoint : %d \n", i); |
| A_PRINTF(KERN_ALERT"TxCreditLowIndications : %d \n", stats.TxCreditLowIndications); |
| A_PRINTF(KERN_ALERT"TxIssued : %d \n", stats.TxIssued); |
| A_PRINTF(KERN_ALERT"TxDropped: %d \n", stats.TxDropped); |
| A_PRINTF(KERN_ALERT"TxPacketsBundled : %d \n", stats.TxPacketsBundled); |
| A_PRINTF(KERN_ALERT"TxBundles : %d \n", stats.TxBundles); |
| A_PRINTF(KERN_ALERT"TxCreditRpts : %d \n", stats.TxCreditRpts); |
| A_PRINTF(KERN_ALERT"TxCreditsRptsFromRx : %d \n", stats.TxCreditRptsFromRx); |
| A_PRINTF(KERN_ALERT"TxCreditsRptsFromOther : %d \n", stats.TxCreditRptsFromOther); |
| A_PRINTF(KERN_ALERT"TxCreditsRptsFromEp0 : %d \n", stats.TxCreditRptsFromEp0); |
| A_PRINTF(KERN_ALERT"TxCreditsFromRx : %d \n", stats.TxCreditsFromRx); |
| A_PRINTF(KERN_ALERT"TxCreditsFromOther : %d \n", stats.TxCreditsFromOther); |
| A_PRINTF(KERN_ALERT"TxCreditsFromEp0 : %d \n", stats.TxCreditsFromEp0); |
| A_PRINTF(KERN_ALERT"TxCreditsConsummed : %d \n", stats.TxCreditsConsummed); |
| A_PRINTF(KERN_ALERT"TxCreditsReturned : %d \n", stats.TxCreditsReturned); |
| A_PRINTF(KERN_ALERT"RxReceived : %d \n", stats.RxReceived); |
| A_PRINTF(KERN_ALERT"RxPacketsBundled : %d \n", stats.RxPacketsBundled); |
| A_PRINTF(KERN_ALERT"RxLookAheads : %d \n", stats.RxLookAheads); |
| A_PRINTF(KERN_ALERT"RxBundleLookAheads : %d \n", stats.RxBundleLookAheads); |
| A_PRINTF(KERN_ALERT"RxBundleIndFromHdr : %d \n", stats.RxBundleIndFromHdr); |
| A_PRINTF(KERN_ALERT"RxAllocThreshHit : %d \n", stats.RxAllocThreshHit); |
| A_PRINTF(KERN_ALERT"RxAllocThreshBytes : %d \n", stats.RxAllocThreshBytes); |
| A_PRINTF(KERN_ALERT"---- \n"); |
| |
| } |
| } |
| } |
| #endif |
| } |
| break; |
| case AR6000_XIOCTL_TRAFFIC_ACTIVITY_CHANGE: |
| if (ar->arHtcTarget != NULL) { |
| struct ar6000_traffic_activity_change data; |
| |
| if (copy_from_user(&data, userdata, sizeof(data))) |
| { |
| ret = -EFAULT; |
| goto ioctl_done; |
| } |
| /* note, this is used for testing (mbox ping testing), indicate activity |
| * change using the stream ID as the traffic class */ |
| ar6000_indicate_tx_activity(ar, |
| (u8)data.StreamID, |
| data.Active ? true : false); |
| } |
| break; |
| case AR6000_XIOCTL_WMI_SET_CONNECT_CTRL_FLAGS: |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&connectCtrlFlags, userdata, |
| sizeof(connectCtrlFlags))) |
| { |
| ret = -EFAULT; |
| } else { |
| ar->arConnectCtrlFlags = connectCtrlFlags; |
| } |
| break; |
| case AR6000_XIOCTL_WMI_SET_AKMP_PARAMS: |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&akmpParams, userdata, |
| sizeof(WMI_SET_AKMP_PARAMS_CMD))) |
| { |
| ret = -EFAULT; |
| } else { |
| if (wmi_set_akmp_params_cmd(ar->arWmi, &akmpParams) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| case AR6000_XIOCTL_WMI_SET_PMKID_LIST: |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else { |
| if (copy_from_user(&pmkidInfo.numPMKID, userdata, |
| sizeof(pmkidInfo.numPMKID))) |
| { |
| ret = -EFAULT; |
| break; |
| } |
| if (copy_from_user(&pmkidInfo.pmkidList, |
| userdata + sizeof(pmkidInfo.numPMKID), |
| pmkidInfo.numPMKID * sizeof(WMI_PMKID))) |
| { |
| ret = -EFAULT; |
| break; |
| } |
| if (wmi_set_pmkid_list_cmd(ar->arWmi, &pmkidInfo) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| case AR6000_XIOCTL_WMI_GET_PMKID_LIST: |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else { |
| if (wmi_get_pmkid_list_cmd(ar->arWmi) != 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| case AR6000_XIOCTL_WMI_ABORT_SCAN: |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } |
| ret = wmi_abort_scan_cmd(ar->arWmi); |
| break; |
| case AR6000_XIOCTL_AP_HIDDEN_SSID: |
| { |
| u8 hidden_ssid; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&hidden_ssid, userdata, sizeof(hidden_ssid))) { |
| ret = -EFAULT; |
| } else { |
| wmi_ap_set_hidden_ssid(ar->arWmi, hidden_ssid); |
| ar->ap_hidden_ssid = hidden_ssid; |
| ar->ap_profile_flag = 1; /* There is a change in profile */ |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_STA_LIST: |
| { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else { |
| u8 i; |
| ap_get_sta_t temp; |
| A_MEMZERO(&temp, sizeof(temp)); |
| for(i=0;i<AP_MAX_NUM_STA;i++) { |
| memcpy(temp.sta[i].mac, ar->sta_list[i].mac, ATH_MAC_LEN); |
| temp.sta[i].aid = ar->sta_list[i].aid; |
| temp.sta[i].keymgmt = ar->sta_list[i].keymgmt; |
| temp.sta[i].ucipher = ar->sta_list[i].ucipher; |
| temp.sta[i].auth = ar->sta_list[i].auth; |
| } |
| if(copy_to_user((ap_get_sta_t *)rq->ifr_data, &temp, |
| sizeof(ar->sta_list))) { |
| ret = -EFAULT; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_SET_NUM_STA: |
| { |
| u8 num_sta; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&num_sta, userdata, sizeof(num_sta))) { |
| ret = -EFAULT; |
| } else if(num_sta > AP_MAX_NUM_STA) { |
| /* value out of range */ |
| ret = -EINVAL; |
| } else { |
| wmi_ap_set_num_sta(ar->arWmi, num_sta); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_SET_ACL_POLICY: |
| { |
| u8 policy; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&policy, userdata, sizeof(policy))) { |
| ret = -EFAULT; |
| } else if(policy == ar->g_acl.policy) { |
| /* No change in policy */ |
| } else { |
| if(!(policy & AP_ACL_RETAIN_LIST_MASK)) { |
| /* clear ACL list */ |
| memset(&ar->g_acl,0,sizeof(WMI_AP_ACL)); |
| } |
| ar->g_acl.policy = policy; |
| wmi_ap_set_acl_policy(ar->arWmi, policy); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_SET_ACL_MAC: |
| { |
| WMI_AP_ACL_MAC_CMD acl; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&acl, userdata, sizeof(acl))) { |
| ret = -EFAULT; |
| } else { |
| if(acl_add_del_mac(&ar->g_acl, &acl)) { |
| wmi_ap_acl_mac_list(ar->arWmi, &acl); |
| } else { |
| A_PRINTF("ACL list error\n"); |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_ACL_LIST: |
| { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if(copy_to_user((WMI_AP_ACL *)rq->ifr_data, &ar->g_acl, |
| sizeof(WMI_AP_ACL))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_COMMIT_CONFIG: |
| { |
| ret = ar6000_ap_mode_profile_commit(ar); |
| break; |
| } |
| case IEEE80211_IOCTL_GETWPAIE: |
| { |
| struct ieee80211req_wpaie wpaie; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&wpaie, userdata, sizeof(wpaie))) { |
| ret = -EFAULT; |
| } else if (ar6000_ap_mode_get_wpa_ie(ar, &wpaie)) { |
| ret = -EFAULT; |
| } else if(copy_to_user(userdata, &wpaie, sizeof(wpaie))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_CONN_INACT_TIME: |
| { |
| u32 period; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&period, userdata, sizeof(period))) { |
| ret = -EFAULT; |
| } else { |
| wmi_ap_conn_inact_time(ar->arWmi, period); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_PROT_SCAN_TIME: |
| { |
| WMI_AP_PROT_SCAN_TIME_CMD bgscan; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&bgscan, userdata, sizeof(bgscan))) { |
| ret = -EFAULT; |
| } else { |
| wmi_ap_bgscan_time(ar->arWmi, bgscan.period_min, bgscan.dwell_ms); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_SET_COUNTRY: |
| { |
| ret = ar6000_ioctl_set_country(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_AP_SET_DTIM: |
| { |
| WMI_AP_SET_DTIM_CMD d; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&d, userdata, sizeof(d))) { |
| ret = -EFAULT; |
| } else { |
| if(d.dtim > 0 && d.dtim < 11) { |
| ar->ap_dtim_period = d.dtim; |
| wmi_ap_set_dtim(ar->arWmi, d.dtim); |
| ar->ap_profile_flag = 1; /* There is a change in profile */ |
| } else { |
| A_PRINTF("DTIM out of range. Valid range is [1-10]\n"); |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WMI_TARGET_EVENT_REPORT: |
| { |
| WMI_SET_TARGET_EVENT_REPORT_CMD evtCfgCmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } |
| if (copy_from_user(&evtCfgCmd, userdata, |
| sizeof(evtCfgCmd))) { |
| ret = -EFAULT; |
| break; |
| } |
| ret = wmi_set_target_event_report_cmd(ar->arWmi, &evtCfgCmd); |
| break; |
| } |
| case AR6000_XIOCTL_AP_INTRA_BSS_COMM: |
| { |
| u8 intra=0; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&intra, userdata, sizeof(intra))) { |
| ret = -EFAULT; |
| } else { |
| ar->intra_bss = (intra?1:0); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_DUMP_MODULE_DEBUG_INFO: |
| { |
| struct drv_debug_module_s moduleinfo; |
| |
| if (copy_from_user(&moduleinfo, userdata, sizeof(moduleinfo))) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| a_dump_module_debug_info_by_name(moduleinfo.modulename); |
| ret = 0; |
| break; |
| } |
| case AR6000_XIOCTL_MODULE_DEBUG_SET_MASK: |
| { |
| struct drv_debug_module_s moduleinfo; |
| |
| if (copy_from_user(&moduleinfo, userdata, sizeof(moduleinfo))) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| if (a_set_module_mask(moduleinfo.modulename, moduleinfo.mask)) { |
| ret = -EFAULT; |
| } |
| |
| break; |
| } |
| case AR6000_XIOCTL_MODULE_DEBUG_GET_MASK: |
| { |
| struct drv_debug_module_s moduleinfo; |
| |
| if (copy_from_user(&moduleinfo, userdata, sizeof(moduleinfo))) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| if (a_get_module_mask(moduleinfo.modulename, &moduleinfo.mask)) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| if (copy_to_user(userdata, &moduleinfo, sizeof(moduleinfo))) { |
| ret = -EFAULT; |
| break; |
| } |
| |
| break; |
| } |
| #ifdef ATH_AR6K_11N_SUPPORT |
| case AR6000_XIOCTL_DUMP_RCV_AGGR_STATS: |
| { |
| PACKET_LOG *copy_of_pkt_log; |
| |
| aggr_dump_stats(ar->aggr_cntxt, ©_of_pkt_log); |
| if (copy_to_user(rq->ifr_data, copy_of_pkt_log, sizeof(PACKET_LOG))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_SETUP_AGGR: |
| { |
| WMI_ADDBA_REQ_CMD cmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| ret = -EFAULT; |
| } else { |
| wmi_setup_aggr_cmd(ar->arWmi, cmd.tid); |
| } |
| } |
| break; |
| |
| case AR6000_XIOCTL_DELE_AGGR: |
| { |
| WMI_DELBA_REQ_CMD cmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| ret = -EFAULT; |
| } else { |
| wmi_delete_aggr_cmd(ar->arWmi, cmd.tid, cmd.is_sender_initiator); |
| } |
| } |
| break; |
| |
| case AR6000_XIOCTL_ALLOW_AGGR: |
| { |
| WMI_ALLOW_AGGR_CMD cmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| ret = -EFAULT; |
| } else { |
| wmi_allow_aggr_cmd(ar->arWmi, cmd.tx_allow_aggr, cmd.rx_allow_aggr); |
| } |
| } |
| break; |
| |
| case AR6000_XIOCTL_SET_HT_CAP: |
| { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&htCap, userdata, |
| sizeof(htCap))) |
| { |
| ret = -EFAULT; |
| } else { |
| |
| if (wmi_set_ht_cap_cmd(ar->arWmi, &htCap) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_SET_HT_OP: |
| { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&htOp, userdata, |
| sizeof(htOp))) |
| { |
| ret = -EFAULT; |
| } else { |
| |
| if (wmi_set_ht_op_cmd(ar->arWmi, htOp.sta_chan_width) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| #endif |
| case AR6000_XIOCTL_ACL_DATA: |
| { |
| void *osbuf = NULL; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (ar6000_create_acl_data_osbuf(dev, (u8 *)userdata, &osbuf) != 0) { |
| ret = -EIO; |
| } else { |
| if (wmi_data_hdr_add(ar->arWmi, osbuf, DATA_MSGTYPE, 0, WMI_DATA_HDR_DATA_TYPE_ACL,0,NULL) != 0) { |
| AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("XIOCTL_ACL_DATA - wmi_data_hdr_add failed\n")); |
| } else { |
| /* Send data buffer over HTC */ |
| ar6000_acl_data_tx(osbuf, ar->arNetDev); |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_HCI_CMD: |
| { |
| char tmp_buf[512]; |
| s8 i; |
| WMI_HCI_CMD *cmd = (WMI_HCI_CMD *)tmp_buf; |
| u8 size; |
| |
| size = sizeof(cmd->cmd_buf_sz); |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(cmd, userdata, size)) { |
| ret = -EFAULT; |
| } else if(copy_from_user(cmd->buf, userdata + size, cmd->cmd_buf_sz)) { |
| ret = -EFAULT; |
| } else { |
| if (wmi_send_hci_cmd(ar->arWmi, cmd->buf, cmd->cmd_buf_sz) != 0) { |
| ret = -EIO; |
| }else if(loghci) { |
| A_PRINTF_LOG("HCI Command To PAL --> \n"); |
| for(i = 0; i < cmd->cmd_buf_sz; i++) { |
| A_PRINTF_LOG("0x%02x ",cmd->buf[i]); |
| if((i % 10) == 0) { |
| A_PRINTF_LOG("\n"); |
| } |
| } |
| A_PRINTF_LOG("\n"); |
| A_PRINTF_LOG("==================================\n"); |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_WLAN_CONN_PRECEDENCE: |
| { |
| WMI_SET_BT_WLAN_CONN_PRECEDENCE cmd; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&cmd, userdata, sizeof(cmd))) { |
| ret = -EFAULT; |
| } else { |
| if (cmd.precedence == BT_WLAN_CONN_PRECDENCE_WLAN || |
| cmd.precedence == BT_WLAN_CONN_PRECDENCE_PAL) { |
| if ( wmi_set_wlan_conn_precedence_cmd(ar->arWmi, cmd.precedence) != 0) { |
| ret = -EIO; |
| } |
| } else { |
| ret = -EINVAL; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_STAT: |
| { |
| ret = ar6000_ioctl_get_ap_stats(dev, rq); |
| break; |
| } |
| case AR6000_XIOCTL_SET_TX_SELECT_RATES: |
| { |
| WMI_SET_TX_SELECT_RATES_CMD masks; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&masks, userdata, |
| sizeof(masks))) |
| { |
| ret = -EFAULT; |
| } else { |
| |
| if (wmi_set_tx_select_rates_cmd(ar->arWmi, masks.rateMasks) != 0) |
| { |
| ret = -EIO; |
| } |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_HIDDEN_SSID: |
| { |
| WMI_AP_HIDDEN_SSID_CMD ssid; |
| ssid.hidden_ssid = ar->ap_hidden_ssid; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if(copy_to_user((WMI_AP_HIDDEN_SSID_CMD *)rq->ifr_data, |
| &ssid, sizeof(WMI_AP_HIDDEN_SSID_CMD))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_COUNTRY: |
| { |
| WMI_AP_SET_COUNTRY_CMD cty; |
| memcpy(cty.countryCode, ar->ap_country_code, 3); |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if(copy_to_user((WMI_AP_SET_COUNTRY_CMD *)rq->ifr_data, |
| &cty, sizeof(WMI_AP_SET_COUNTRY_CMD))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_WMODE: |
| { |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if(copy_to_user((u8 *)rq->ifr_data, |
| &ar->ap_wmode, sizeof(u8))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_DTIM: |
| { |
| WMI_AP_SET_DTIM_CMD dtim; |
| dtim.dtim = ar->ap_dtim_period; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if(copy_to_user((WMI_AP_SET_DTIM_CMD *)rq->ifr_data, |
| &dtim, sizeof(WMI_AP_SET_DTIM_CMD))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_BINTVL: |
| { |
| WMI_BEACON_INT_CMD bi; |
| bi.beaconInterval = ar->ap_beacon_interval; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if(copy_to_user((WMI_BEACON_INT_CMD *)rq->ifr_data, |
| &bi, sizeof(WMI_BEACON_INT_CMD))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_GET_RTS: |
| { |
| WMI_SET_RTS_CMD rts; |
| rts.threshold = ar->arRTS; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if(copy_to_user((WMI_SET_RTS_CMD *)rq->ifr_data, |
| &rts, sizeof(WMI_SET_RTS_CMD))) { |
| ret = -EFAULT; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_FETCH_TARGET_REGS: |
| { |
| u32 targregs[AR6003_FETCH_TARG_REGS_COUNT]; |
| |
| if (ar->arTargetType == TARGET_TYPE_AR6003) { |
| ar6k_FetchTargetRegs(hifDevice, targregs); |
| if (copy_to_user((u32 *)rq->ifr_data, &targregs, sizeof(targregs))) |
| { |
| ret = -EFAULT; |
| } |
| } else { |
| ret = -EOPNOTSUPP; |
| } |
| break; |
| } |
| case AR6000_XIOCTL_AP_SET_11BG_RATESET: |
| { |
| WMI_AP_SET_11BG_RATESET_CMD rate; |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&rate, userdata, sizeof(rate))) { |
| ret = -EFAULT; |
| } else { |
| wmi_ap_set_rateset(ar->arWmi, rate.rateset); |
| } |
| break; |
| } |
| case AR6000_XIOCTL_GET_WLAN_SLEEP_STATE: |
| { |
| WMI_REPORT_SLEEP_STATE_EVENT wmiSleepEvent ; |
| |
| if (ar->arWlanState == WLAN_ENABLED) { |
| wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_AWAKE; |
| } else { |
| wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP; |
| } |
| rq->ifr_ifru.ifru_ivalue = ar->arWlanState; /* return value */ |
| |
| ar6000_send_event_to_app(ar, WMI_REPORT_SLEEP_STATE_EVENTID, (u8 *)&wmiSleepEvent, |
| sizeof(WMI_REPORT_SLEEP_STATE_EVENTID)); |
| break; |
| } |
| #ifdef CONFIG_PM |
| case AR6000_XIOCTL_SET_BT_HW_POWER_STATE: |
| { |
| unsigned int state; |
| if (get_user(state, (unsigned int *)userdata)) { |
| ret = -EFAULT; |
| break; |
| } |
| if (ar6000_set_bt_hw_state(ar, state)!= 0) { |
| ret = -EIO; |
| } |
| } |
| break; |
| case AR6000_XIOCTL_GET_BT_HW_POWER_STATE: |
| rq->ifr_ifru.ifru_ivalue = !ar->arBTOff; /* return value */ |
| break; |
| #endif |
| |
| case AR6000_XIOCTL_WMI_SET_TX_SGI_PARAM: |
| { |
| WMI_SET_TX_SGI_PARAM_CMD SGICmd; |
| |
| if (ar->arWmiReady == false) { |
| ret = -EIO; |
| } else if (copy_from_user(&SGICmd, userdata, |
| sizeof(SGICmd))){ |
| ret = -EFAULT; |
| } else{ |
| if (wmi_SGI_cmd(ar->arWmi, SGICmd.sgiMask, SGICmd.sgiPERThreshold) != 0) { |
| ret = -EIO; |
| } |
| |
| } |
| break; |
| } |
| |
| case AR6000_XIOCTL_ADD_AP_INTERFACE: |
| #ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT |
| { |
| char ap_ifname[IFNAMSIZ] = {0,}; |
| if (copy_from_user(ap_ifname, userdata, IFNAMSIZ)) { |
| ret = -EFAULT; |
| } else { |
| if (ar6000_add_ap_interface(ar, ap_ifname) != 0) { |
| ret = -EIO; |
| } |
| } |
| } |
| #else |
| ret = -EOPNOTSUPP; |
| #endif |
| break; |
| case AR6000_XIOCTL_REMOVE_AP_INTERFACE: |
| #ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT |
| if (ar6000_remove_ap_interface(ar) != 0) { |
| ret = -EIO; |
| } |
| #else |
| ret = -EOPNOTSUPP; |
| #endif |
| break; |
| |
| case AR6000_XIOCTL_WMI_SET_EXCESS_TX_RETRY_THRES: |
| { |
| ret = ar6000_xioctl_set_excess_tx_retry_thres_cmd(dev, userdata); |
| break; |
| } |
| |
| default: |
| ret = -EOPNOTSUPP; |
| } |
| |
| ioctl_done: |
| rtnl_lock(); /* restore rtnl state */ |
| dev_put(dev); |
| |
| return ret; |
| } |
| |
| u8 mac_cmp_wild(u8 *mac, u8 *new_mac, u8 wild, u8 new_wild) |
| { |
| u8 i; |
| |
| for(i=0;i<ATH_MAC_LEN;i++) { |
| if((wild & 1<<i) && (new_wild & 1<<i)) continue; |
| if(mac[i] != new_mac[i]) return 1; |
| } |
| if((memcmp(new_mac, null_mac, 6)==0) && new_wild && |
| (wild != new_wild)) { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| u8 acl_add_del_mac(WMI_AP_ACL *a, WMI_AP_ACL_MAC_CMD *acl) |
| { |
| s8 already_avail=-1, free_slot=-1, i; |
| |
| /* To check whether this mac is already there in our list */ |
| for(i=AP_ACL_SIZE-1;i>=0;i--) |
| { |
| if(mac_cmp_wild(a->acl_mac[i], acl->mac, a->wildcard[i], |
| acl->wildcard)==0) |
| already_avail = i; |
| |
| if(!((1 << i) & a->index)) |
| free_slot = i; |
| } |
| |
| if(acl->action == ADD_MAC_ADDR) |
| { |
| /* Dont add mac if it is already available */ |
| if((already_avail >= 0) || (free_slot == -1)) |
| return 0; |
| |
| memcpy(a->acl_mac[free_slot], acl->mac, ATH_MAC_LEN); |
| a->index = a->index | (1 << free_slot); |
| acl->index = free_slot; |
| a->wildcard[free_slot] = acl->wildcard; |
| return 1; |
| } |
| else if(acl->action == DEL_MAC_ADDR) |
| { |
| if(acl->index > AP_ACL_SIZE) |
| return 0; |
| |
| if(!(a->index & (1 << acl->index))) |
| return 0; |
| |
| A_MEMZERO(a->acl_mac[acl->index],ATH_MAC_LEN); |
| a->index = a->index & ~(1 << acl->index); |
| a->wildcard[acl->index] = 0; |
| return 1; |
| } |
| |
| return 0; |
| } |