static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) { struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__, reason_code); if (!ath6kl_cfg80211_ready(ar)) return -EIO; if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { ath6kl_err("busy, destroy in progress\n"); return -EBUSY; } if (down_interruptible(&ar->sem)) { ath6kl_err("busy, couldn't get access\n"); return -ERESTARTSYS; } ar->reconnect_flag = 0; ath6kl_disconnect(ar); memset(ar->ssid, 0, sizeof(ar->ssid)); ar->ssid_len = 0; if (!test_bit(SKIP_SCAN, &ar->flag)) memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); up(&ar->sem); ar->sme_state = SME_DISCONNECTED; return 0; }
int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr) { u32 cid = BMI_SET_APP_START; int ret; u32 offset; u16 size; if (ar->bmi.done_sent) { ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); return -EACCES; } size = sizeof(cid) + sizeof(addr); if (size > ar->bmi.max_cmd_size) { WARN_ON(1); return -EINVAL; } memset(ar->bmi.cmd_buf, 0, size); ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr); offset = 0; memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); offset += sizeof(cid); memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); offset += sizeof(addr); ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); if (ret) { ath6kl_err("Unable to write to the device: %d\n", ret); return ret; } return 0; }
static int ath6kl_vreg_enable(struct ath6kl_power_vreg_data *vreg) { int rc = 0; ath6kl_dbg(ATH6KL_DBG_BOOT, "vreg_en for : %s\n", vreg->name); if (!vreg->is_enabled) { if (vreg->set_voltage_sup) { rc = regulator_set_voltage(vreg->reg, vreg->low_vol_level, vreg->high_vol_level); if (rc) { ath6kl_err("vreg_set_vol(%s) failed rc=%d\n", vreg->name, rc); goto out; } } rc = regulator_enable(vreg->reg); if (rc) { ath6kl_err("regulator_enable(%s) failed. rc=%d\n", vreg->name, rc); goto out; } vreg->is_enabled = true; } out: return rc; }
int rttm_init(void* ar) { S_RTTM_CONTEXT *prttm=NULL; ath6kl_dbg(ATH6KL_DBG_RTT,"rttm init "); prttm=kmalloc(sizeof(S_RTTM_CONTEXT),GFP_KERNEL); if(NULL==prttm) return -ENOMEM; memset(prttm,0,sizeof(S_RTTM_CONTEXT)); if(NULL==prttm->cirbuf) { ath6kl_err("RTT Init Failed to AllocMem for rttm context \n"); return -ENOMEM; } prttm->pvreadptr = prttm->cirbuf; prttm->pvbufptr = prttm->cirbuf; prttm->ar =ar; DEV_SETRTT_HDL(prttm); //Initialize NL For RTT if(0!=ath_netlink_init()) { ath6kl_err("RTT Init Failed to Initialize NetLink Interface \n"); return -ENODEV; } return 0; }
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar) { unsigned long timeout; u32 rx_word = 0; int ret = 0; timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); while (time_before(jiffies, timeout) && !rx_word) { ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS, (u8 *)&rx_word, sizeof(rx_word), HIF_RD_SYNC_BYTE_INC); if (ret) { ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n"); return ret; } /* all we really want is one bit */ rx_word &= (1 << ENDPOINT1); } if (!rx_word) { ath6kl_err("bmi_recv_buf FIFO empty\n"); return -EINVAL; } return ret; }
static int ath6kl_vreg_disable(struct ath6kl_power_vreg_data *vreg) { int rc = 0; if (!vreg) return rc; ath6kl_dbg(ATH6KL_DBG_BOOT, "vreg_disable for : %s\n", vreg->name); if (vreg->is_enabled) { rc = regulator_disable(vreg->reg); if (rc) { ath6kl_err("regulator_disable(%s) failed. rc=%d\n", vreg->name, rc); goto out; } vreg->is_enabled = false; if (vreg->set_voltage_sup) { /* Set the min voltage to 0 */ rc = regulator_set_voltage(vreg->reg, 0, vreg->high_vol_level); if (rc) { ath6kl_err("vreg_set_vol(%s) failed rc=%d\n", vreg->name, rc); goto out; } } } out: return rc; }
void ath_netlink_send(char *event_data, u32 event_datalen) { struct sk_buff *skb = NULL; struct nlmsghdr *nlh; skb = nlmsg_new(NLMSG_SPACE(event_datalen), GFP_ATOMIC); if (!skb) { ath6kl_err("%s: No memory,\n", __func__); return; } nlh = nlmsg_put(skb, gpid, 0, 0 , NLMSG_SPACE(event_datalen), 0); if (!nlh) { ath6kl_err("%s: nlmsg_put() failed\n", __func__); return; } memcpy(NLMSG_DATA(nlh), event_data, event_datalen); #ifdef ATH6KL_SUPPORT_NETLINK_KERNEL3_7 NETLINK_CB(skb).portid = 0; /* from kernel */ #else NETLINK_CB(skb).pid = 0; /* from kernel */ #endif NETLINK_CB(skb).dst_group = 0; /* unicast */ netlink_unicast(ath_nl_sock, skb, gpid, MSG_DONTWAIT); }
static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); if (!ath6kl_cfg80211_ready(ar)) return -EIO; if (test_bit(CONNECTED, &ar->flag)) { ar->tx_pwr = 0; if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) { ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n"); return -EIO; } wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0, 5 * HZ); if (signal_pending(current)) { ath6kl_err("target did not respond\n"); return -EINTR; } } *dbm = ar->tx_pwr; return 0; }
void ath6kl_mangle_mac_address(struct ath6kl *ar, u8 locally_administered_bit) { u8 *ptr_mac; int i, ret; u8 *macbuf; switch (ar->target_type) { case TARGET_TYPE_AR6003: ptr_mac = ar->fw_board + AR6003_MAC_ADDRESS_OFFSET; break; case TARGET_TYPE_AR6004: ptr_mac = ar->fw_board + AR6004_MAC_ADDRESS_OFFSET; break; default: ath6kl_err("Invalid Target Type\n"); return; } /* #if 0 mac address issue - It sometimes changed macaddress */ ath6kl_dbg(ATH6KL_DBG_BOOT, "MAC from EEPROM %02X:%02X:%02X:%02X:%02X:%02X\n", ptr_mac[0], ptr_mac[1], ptr_mac[2], ptr_mac[3], ptr_mac[4], ptr_mac[5]); /* #endif */ ret = ath6kl_fetch_nvmac_info(ar); if (ret) { ath6kl_err("MAC address nvmac file not found\n"); return; } macbuf = kmalloc(ath6kl_softmac_len + 1, GFP_ATOMIC); if (macbuf) { unsigned int softmac[6]; memcpy(macbuf, ath6kl_softmac, ath6kl_softmac_len); macbuf[ath6kl_softmac_len] = '\0'; if (sscanf(macbuf, "%02x:%02x:%02x:%02x:%02x:%02x", &softmac[0], &softmac[1], &softmac[2], &softmac[3], &softmac[4], &softmac[5]) == 6) { for (i = 0; i < 6; ++i) ptr_mac[i] = softmac[i] & 0xff; } ath6kl_dbg(ATH6KL_DBG_BOOT, "MAC from SoftMAC %02X_%02X:%02X\n", ptr_mac[0], ptr_mac[4], ptr_mac[5]); } vfree(ath6kl_softmac); if (locally_administered_bit) ptr_mac[0] |= 0x02; ath6kl_calculate_crc(ar->target_type, ar->fw_board, ar->fw_board_len); }
struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) { int ret = 0; struct wireless_dev *wdev; struct ath6kl *ar; wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!wdev) { ath6kl_err("couldn't allocate wireless device\n"); return NULL; } /* create a new wiphy for use with cfg80211 */ wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); if (!wdev->wiphy) { ath6kl_err("couldn't allocate wiphy device\n"); kfree(wdev); return NULL; } ar = wiphy_priv(wdev->wiphy); ar->p2p = !!ath6kl_p2p; wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes; wdev->wiphy->max_remain_on_channel_duration = 5000; /* set device pointer for wiphy */ set_wiphy_dev(wdev->wiphy, dev); wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); if (ar->p2p) { wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT); } /* max num of ssids that can be probed during scanning */ wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->cipher_suites = cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); ret = wiphy_register(wdev->wiphy); if (ret < 0) { ath6kl_err("couldn't register wiphy device\n"); wiphy_free(wdev->wiphy); kfree(wdev); return NULL; } return wdev; }
int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) { u32 cid = BMI_READ_MEMORY; int ret; u32 offset; u32 len_remain, rx_len; u16 size; if (ar->bmi.done_sent) { ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); return -EACCES; } size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len); if (size > ar->bmi.max_cmd_size) { WARN_ON(1); return -EINVAL; } memset(ar->bmi.cmd_buf, 0, size); ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read memory: device: addr: 0x%x, len: %d\n", addr, len); len_remain = len; while (len_remain) { rx_len = (len_remain < ar->bmi.max_data_size) ? len_remain : ar->bmi.max_data_size; offset = 0; memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); offset += sizeof(cid); memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); offset += sizeof(addr); memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len)); offset += sizeof(len); ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); if (ret) { ath6kl_err("Unable to write to the device: %d\n", ret); return ret; } ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len); if (ret) { ath6kl_err("Unable to read from the device: %d\n", ret); return ret; } memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len); len_remain -= rx_len; addr += rx_len; } return 0; }
/* mailbox recv message polling */ int ath6kl_hif_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd, int timeout) { struct ath6kl_irq_proc_registers *rg; int status = 0, i; u8 htc_mbox = 1 << HTC_MAILBOX; for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) { /* this is the standard HIF way, load the reg table */ status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, (u8 *) &dev->irq_proc_reg, sizeof(dev->irq_proc_reg), HIF_RD_SYNC_BYTE_INC); if (status) { ath6kl_err("failed to read reg table\n"); return status; } /* check for MBOX data and valid lookahead */ if (dev->irq_proc_reg.host_int_status & htc_mbox) { if (dev->irq_proc_reg.rx_lkahd_valid & htc_mbox) { /* * Mailbox has a message and the look ahead * is valid. */ rg = &dev->irq_proc_reg; *lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); break; } } /* delay a little */ mdelay(ATH6KL_TIME_QUANTUM); ath6kl_dbg(ATH6KL_DBG_HIF, "hif retry mbox poll try %d\n", i); } if (i == 0) { ath6kl_err("timeout waiting for recv message\n"); status = -ETIME; /* check if the target asserted */ if (dev->irq_proc_reg.counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK) /* * Target failure handler will be called in case of * an assert. */ ath6kl_hif_proc_dbg_intr(dev); } return status; }
int ath_netlink_init() { #ifdef ATH6KL_SUPPORT_NETLINK_KERNEL3_7 struct netlink_kernel_cfg netlink_cfg; if (ath_nl_sock == NULL) { netlink_cfg.groups = 1; netlink_cfg.input = ath_netlink_receive; netlink_cfg.cb_mutex = NULL; netlink_cfg.bind = NULL; netlink_cfg.flags = 0; ath_nl_sock = (struct sock *)netlink_kernel_create( &init_net, NETLINK_ATH_EVENT, &netlink_cfg); if (ath_nl_sock == NULL) { ath6kl_err("%s NetLink Create Failed\n", __func__); return -ENODEV; } } #elif defined(ATH6KL_SUPPORT_NETLINK_KERNEL3_6) struct netlink_kernel_cfg netlink_cfg; if (ath_nl_sock == NULL) { netlink_cfg.groups = 1; netlink_cfg.input = ath_netlink_receive; netlink_cfg.cb_mutex = NULL; netlink_cfg.bind = NULL; ath_nl_sock = (struct sock *)netlink_kernel_create( &init_net, NETLINK_ATH_EVENT, THIS_MODULE, &netlink_cfg); if (ath_nl_sock == NULL) { ath6kl_err("%s NetLink Create Failed\n", __func__); return -ENODEV; } } #else if (ath_nl_sock == NULL) { ath_nl_sock = (struct sock *)netlink_kernel_create( &init_net, NETLINK_ATH_EVENT, 1, &ath_netlink_receive, NULL, THIS_MODULE); if (ath_nl_sock == NULL) { ath6kl_err("%s NetLink Create Failed\n", __func__); return -ENODEV; } } #endif return 0; }
static int ath6kl_sdio_probe(struct platform_device *pdev) { struct ath6kl_platform_data *pdata = NULL; struct device *dev = &pdev->dev; int ret = 0; int length; char buf[3]; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { ath6kl_err("%s: Could not allocate memory for platform data\n", __func__); up(&wifi_control_sem); return -ENOMEM; } if (ath6kl_dt_parse_vreg_info(dev, &pdata->wifi_chip_pwd, "qca,wifi-chip-pwd") != 0) { ath6kl_err("%s: parse vreg info error\n", __func__); goto err; } pdata->pdev = pdev; platform_set_drvdata(pdev, pdata); gpdata = pdata; if (pdata->wifi_chip_pwd != NULL) { ret = ath6kl_platform_power(pdata, 1); if (ret == 0) { mdelay(50); length = snprintf(buf, sizeof(buf), "%d\n", 1 ? 1 : 0); android_readwrite_file( "/sys/devices/msm_sdcc.3/polling", NULL, buf, length); length = snprintf(buf, sizeof(buf), "%d\n", 0 ? 1 : 0); android_readwrite_file( "/sys/devices/msm_sdcc.3/polling", NULL, buf, length); mdelay(500); } } up(&wifi_control_sem); return ret; err: if (pdata != NULL) devm_kfree(dev, pdata); up(&wifi_control_sem); return -EINVAL; }
struct ath6kl *ath6kl_core_alloc(struct device *sdev) { struct net_device *dev; struct ath6kl *ar; struct wireless_dev *wdev; wdev = ath6kl_cfg80211_init(sdev); if (!wdev) { ath6kl_err("ath6kl_cfg80211_init failed\n"); return NULL; } ar = wdev_priv(wdev); ar->dev = sdev; ar->wdev = wdev; wdev->iftype = NL80211_IFTYPE_STATION; dev = alloc_netdev(0, "wlan%d", ether_setup); if (!dev) { ath6kl_err("no memory for network device instance\n"); ath6kl_cfg80211_deinit(ar); return NULL; } dev->ieee80211_ptr = wdev; SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); wdev->netdev = dev; ar->sme_state = SME_DISCONNECTED; ar->auto_auth_stage = AUTH_IDLE; init_netdev(dev); ar->net_dev = dev; set_bit(WLAN_ENABLED, &ar->flag); ar->wlan_pwr_state = WLAN_POWER_STATE_ON; spin_lock_init(&ar->lock); ath6kl_init_control_info(ar); init_waitqueue_head(&ar->event_wq); sema_init(&ar->sem, 1); clear_bit(DESTROY_IN_PROGRESS, &ar->flag); INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); setup_timer(&ar->disconnect_timer, disconnect_timer_handler, (unsigned long) dev); return ar; }
int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) { u32 cid = BMI_LZ_DATA; int ret; u32 offset; u32 len_remain, tx_len; const u32 header = sizeof(cid) + sizeof(len); u16 size; if (ar->bmi.done_sent) { ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); return -EACCES; } size = ar->bmi.max_data_size + header; if (size > ar->bmi.max_cmd_size) { WARN_ON(1); return -EINVAL; } memset(ar->bmi.cmd_buf, 0, size); ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n", len); len_remain = len; while (len_remain) { tx_len = (len_remain < (ar->bmi.max_data_size - header)) ? len_remain : (ar->bmi.max_data_size - header); offset = 0; memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); offset += sizeof(cid); memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); offset += sizeof(tx_len); memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], tx_len); offset += tx_len; ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); if (ret) { ath6kl_err("Unable to write to the device: %d\n", ret); return ret; } len_remain -= tx_len; } return 0; }
static bool ath6kl_cfg80211_ready(struct ath6kl *ar) { if (!test_bit(WMI_READY, &ar->flag)) { ath6kl_err("wmi is not ready\n"); return false; } if (!test_bit(WLAN_ENABLED, &ar->flag)) { ath6kl_err("wlan disabled\n"); return false; } return true; }
static void ap_keepalive_start(unsigned long arg) { struct ap_keepalive_info *ap_keepalive = (struct ap_keepalive_info *) arg; struct ath6kl_vif *vif = ap_keepalive->vif; int ret; BUG_ON(!vif); ath6kl_dbg(ATH6KL_DBG_KEEPALIVE, "ap_keepalive timer (vif idx %d) sta_list_index %x %s\n", vif->fw_vif_idx, vif->sta_list_index, (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_PRELOAD_STAT) ? "preload" : "update check"); if ((vif->nw_type == AP_NETWORK) && test_bit(CONNECTED, &vif->flags)) { if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_PRELOAD_STAT) { /* FIXME : get last_txrx_time pre N sec. and to check it in next run. */ ret = ap_keepalive_preload_txrx_time(vif); if (ret) { ath6kl_err("preload last_txrx_time fail, ret %d\n", ret); } } else { /* Update and check last TXRX time each stations. */ ret = ap_keepalive_update_check_txrx_time(vif); if (ret) { ath6kl_err("update and check last_txrx_time fail, ret %d\n", ret); } } if ((ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_START) && (ap_keepalive->ap_ka_interval)) { if (ap_keepalive->flags & ATH6KL_AP_KA_FLAGS_PRELOAD_STAT) { mod_timer(&ap_keepalive->ap_ka_timer, jiffies + msecs_to_jiffies(ATH6KL_AP_KA_PRELOAD_STAT_TIME)); ap_keepalive->flags &= ~ATH6KL_AP_KA_FLAGS_PRELOAD_STAT; } else { mod_timer(&ap_keepalive->ap_ka_timer, jiffies + msecs_to_jiffies(ap_keepalive->ap_ka_interval) - msecs_to_jiffies(ATH6KL_AP_KA_PRELOAD_STAT_TIME)); ap_keepalive->flags |= ATH6KL_AP_KA_FLAGS_PRELOAD_STAT; } } } return; }
int ath6kl_hif_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd, int timeout) { struct ath6kl_irq_proc_registers *rg; int status = 0, i; u8 htc_mbox = 1 << HTC_MAILBOX; for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) { status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, (u8 *) &dev->irq_proc_reg, sizeof(dev->irq_proc_reg), HIF_RD_SYNC_BYTE_INC); if (status) { ath6kl_err("failed to read reg table\n"); return status; } if (dev->irq_proc_reg.host_int_status & htc_mbox) { if (dev->irq_proc_reg.rx_lkahd_valid & htc_mbox) { rg = &dev->irq_proc_reg; *lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); break; } } mdelay(ATH6KL_TIME_QUANTUM); ath6kl_dbg(ATH6KL_DBG_HIF, "hif retry mbox poll try %d\n", i); } if (i == 0) { ath6kl_err("timeout waiting for recv message\n"); status = -ETIME; if (dev->irq_proc_reg.counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK) ath6kl_hif_proc_dbg_intr(dev); } return status; }
static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool pmgmt, int timeout) { struct ath6kl *ar = ath6kl_priv(dev); struct wmi_power_mode_cmd mode; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n", __func__, pmgmt, timeout); if (!ath6kl_cfg80211_ready(ar)) return -EIO; if (pmgmt) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); mode.pwr_mode = REC_POWER; } else { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); mode.pwr_mode = MAX_PERF_POWER; } if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) { ath6kl_err("wmi_powermode_cmd failed\n"); return -EIO; } return 0; }
void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, bool wait_fot_compltn, bool cold_reset) { int status = 0; u32 address; __le32 data; if (target_type != TARGET_TYPE_AR6003 && target_type != TARGET_TYPE_AR6004) return; data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : cpu_to_le32(RESET_CONTROL_MBOX_RST); switch (target_type) { case TARGET_TYPE_AR6003: address = AR6003_RESET_CONTROL_ADDRESS; break; case TARGET_TYPE_AR6004: address = AR6004_RESET_CONTROL_ADDRESS; break; default: address = AR6003_RESET_CONTROL_ADDRESS; break; } status = ath6kl_diag_write32(ar, address, data); if (status) ath6kl_err("failed to reset target\n"); }
static int ath6kl_set_auth_type(struct ath6kl *ar, enum nl80211_auth_type auth_type) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type); switch (auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: ar->dot11_auth_mode = OPEN_AUTH; break; case NL80211_AUTHTYPE_SHARED_KEY: ar->dot11_auth_mode = SHARED_AUTH; break; case NL80211_AUTHTYPE_NETWORK_EAP: ar->dot11_auth_mode = LEAP_AUTH; break; case NL80211_AUTHTYPE_AUTOMATIC: ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH; break; default: ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type); return -ENOTSUPP; } return 0; }
/* * We need to differentiate between the surprise and planned removal of the * device because of the following consideration: * * - In case of surprise removal, the hcd already frees up the pending * for the device and hence there is no need to unregister the function * driver inorder to get these requests. For planned removal, the function * driver has to explicitly unregister itself to have the hcd return all the * pending requests before the data structures for the devices are freed up. * Note that as per the current implementation, the function driver will * end up releasing all the devices since there is no API to selectively * release a particular device. * * - Certain commands issued to the target can be skipped for surprise * removal since they will anyway not go through. */ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) { struct ath6kl *ar; if (!dev || !ath6kl_priv(dev)) { ath6kl_err("failed to get device structure\n"); return; } ar = ath6kl_priv(dev); destroy_workqueue(ar->ath6kl_wq); if (ar->htc_target) htc_cleanup(ar->htc_target); aggr_module_destroy(ar->aggr_cntxt); ath6kl_cookie_cleanup(ar); ath6kl_cleanup_amsdu_rxbufs(ar); ath6kl_bmi_cleanup(ar); if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { unregister_netdev(dev); clear_bit(NETDEV_REGISTERED, &ar->flag); } free_netdev(dev); ath6kl_cfg80211_deinit(ar); }
static void ath6kl_calculate_crc(u32 target_type, u8 *data, size_t len) { u16 *crc, *data_idx; u16 checksum; int i; if (target_type == TARGET_TYPE_AR6003) { crc = (u16 *)(data + 0x04); } else if (target_type == TARGET_TYPE_AR6004) { len = 1024; crc = (u16 *)(data + 0x04); } else { ath6kl_err("Invalid target type\n"); return; } ath6kl_dbg(ATH6KL_DBG_BOOT, "Old Checksum: %u\n", *crc); *crc = 0; checksum = 0; data_idx = (u16 *)data; for (i = 0; i < len; i += 2) { checksum = checksum ^ (*data_idx); data_idx++; } *crc = cpu_to_le16(checksum); ath6kl_dbg(ATH6KL_DBG_BOOT, "New Checksum: %u\n", checksum); }
void ath6kl_target_failure(struct ath6kl *ar) { ath6kl_err("target asserted\n"); /* try dumping target assertion information (if any) */ ath6kl_dump_target_assert_info(ar); }
static void ath6kl_dump_target_assert_info(struct ath6kl *ar) { u32 address; u32 regdump_loc = 0; int status; u32 regdump_val[REGISTER_DUMP_LEN_MAX]; u32 i; if (ar->target_type != TARGET_TYPE_AR6003) return; /* the reg dump pointer is copied to the host interest area */ address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); address = TARG_VTOP(address); /* read RAM location through diagnostic window */ status = ath6kl_read_reg_diag(ar, &address, ®dump_loc); if (status || !regdump_loc) { ath6kl_err("failed to get ptr to register dump area\n"); return; } ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", regdump_loc); regdump_loc = TARG_VTOP(regdump_loc); /* fetch register dump data */ status = ath6kl_access_datadiag(ar, regdump_loc, (u8 *)®dump_val[0], REG_DUMP_COUNT_AR6003 * (sizeof(u32)), true); if (status) { ath6kl_err("failed to get register dump\n"); return; } ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n"); for (i = 0; i < REG_DUMP_COUNT_AR6003; i++) ath6kl_dbg(ATH6KL_DBG_TRC, " %d : 0x%8.8X\n", i, regdump_val[i]); }
int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param) { u32 cid = BMI_EXECUTE; int ret; u32 offset; u16 size; if (ar->bmi.done_sent) { ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); return -EACCES; } size = sizeof(cid) + sizeof(addr) + sizeof(param); if (size > ar->bmi.max_cmd_size) { WARN_ON(1); return -EINVAL; } memset(ar->bmi.cmd_buf, 0, size); ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n", addr, *param); offset = 0; memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); offset += sizeof(cid); memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); offset += sizeof(addr); memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param)); offset += sizeof(*param); ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); if (ret) { ath6kl_err("Unable to write to the device: %d\n", ret); return ret; } ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param)); if (ret) { ath6kl_err("Unable to read from the device: %d\n", ret); return ret; } memcpy(param, ar->bmi.cmd_buf, sizeof(*param)); return 0; }
static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev) { int status; u8 error_int_status; u8 reg_buf[4]; ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n"); error_int_status = dev->irq_proc_reg.error_int_status & 0x0F; if (!error_int_status) { WARN_ON(1); return -EIO; } ath6kl_dbg(ATH6KL_DBG_IRQ, "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n", error_int_status); if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status)) ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n"); if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status)) ath6kl_err("rx underflow\n"); if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status)) ath6kl_err("tx overflow\n"); /* Clear the interrupt */ dev->irq_proc_reg.error_int_status &= ~error_int_status; /* set W1C value to clear the interrupt, this hits the register first */ reg_buf[0] = error_int_status; reg_buf[1] = 0; reg_buf[2] = 0; reg_buf[3] = 0; status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS, reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); if (status) WARN_ON(1); return status; }
static int ath6kl_upload_otp(struct ath6kl *ar) { const char *filename; u32 address, param; int ret; switch (ar->version.target_ver) { case AR6003_REV2_VERSION: filename = AR6003_REV2_OTP_FILE; break; default: filename = AR6003_REV3_OTP_FILE; break; } if (ar->fw_otp == NULL) { ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, &ar->fw_otp_len); if (ret) { ath6kl_err("Failed to get OTP file %s: %d\n", filename, ret); return ret; } } address = ath6kl_get_load_address(ar->version.target_ver, APP_LOAD_ADDR); ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, ar->fw_otp_len); if (ret) { ath6kl_err("Failed to upload OTP file: %d\n", ret); return ret; } /* execute the OTP code */ param = 0; address = ath6kl_get_load_address(ar->version.target_ver, APP_START_OVERRIDE_ADDR); ath6kl_bmi_execute(ar, address, ¶m); return ret; }
static int ath6kl_upload_patch(struct ath6kl *ar) { const char *filename; u32 address, param; int ret; switch (ar->version.target_ver) { case AR6003_REV2_VERSION: filename = AR6003_REV2_PATCH_FILE; break; default: filename = AR6003_REV3_PATCH_FILE; break; } if (ar->fw_patch == NULL) { ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, &ar->fw_patch_len); if (ret) { ath6kl_err("Failed to get patch file %s: %d\n", filename, ret); return ret; } } address = ath6kl_get_load_address(ar->version.target_ver, DATASET_PATCH_ADDR); ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); if (ret) { ath6kl_err("Failed to write patch file: %d\n", ret); return ret; } param = address; ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_dset_list_head)), (unsigned char *) ¶m, 4); return 0; }