#ifdef __RTOS__ #include #include #include #include #include #else #include #include #include #include #include #include #include #endif #include "../hgic_def.h" #include "fwdl.h" #include "fwctrl.h" #include "utils.h" #define ARG_DUP(arg,len) if(ctrl->param.arg != (void *)arg){ \ if(ctrl->param.arg) kfree(ctrl->param.arg); \ ctrl->param.arg = hgic_strdup(arg,len);\ } #define ARG_FREE(arg) do{\ if(ctrl->param.arg) kfree(ctrl->param.arg);\ ctrl->param.arg = NULL;\ } while (0) #define STR_LEN(s) ((s)?strlen(s):0) static void *hgic_strdup(void *arg, u32 len) { int s = 0; u8 *ptr = NULL; if (arg) { s = (len > 0) ? (len) : (strlen((char *)arg) + 1); ptr = kzalloc(s, GFP_KERNEL); if (ptr) { if (len > 0) { memcpy(ptr, arg, len); } else { strcpy(ptr, (char *)arg); } } } return ptr; } u16 hgic_ctrl_cookie(struct hgic_fwctrl *ctrl) { unsigned long flags; uint16_t cookie = 0; spin_lock_irqsave(&ctrl->lock, flags); cookie = ctrl->cookie++; ctrl->cookie &= HGIC_TX_COOKIE_MASK; spin_unlock_irqrestore(&ctrl->lock, flags); return cookie; } static struct sk_buff *hgic_alloc_ctrl_skb(u32 size) { struct sk_buff *skb = dev_alloc_skb(sizeof(struct hgic_ctrl_hdr) + size + 4); if (!skb) { return skb; } memset(skb->data, 0, sizeof(struct hgic_ctrl_hdr) + size); skb_reserve(skb, sizeof(struct hgic_ctrl_hdr)); skb_put(skb, size); return skb; } static struct sk_buff *hgic_fwctrl_send_cmd(struct hgic_fwctrl *ctrl, u32 cmd_id, struct sk_buff *skb, bool sync) { struct hgic_ctrl_hdr *hdr = NULL; struct hgic_cmd_response resp; u16 id = cmd_id - HGIC_CMD_START; hdr = (struct hgic_ctrl_hdr *)skb_push(skb, sizeof(struct hgic_ctrl_hdr)); hdr->hdr.magic = HGIC_HDR_TX_MAGIC; hdr->hdr.length = skb->len; hdr->hdr.ifidx = 1; hdr->hdr.cookie = hgic_ctrl_cookie(ctrl); if (id > 255) { hdr->hdr.type = HGIC_HDR_TYPE_CMD2; hdr->cmd2.cmd_id = id; hdr->cmd2.status = 0; } else { hdr->hdr.type = HGIC_HDR_TYPE_CMD; hdr->cmd.cmd_id = id; hdr->cmd.status = 0; } memset(&resp, 0, sizeof(resp)); resp.cookie = hdr->hdr.cookie; return hgic_fwctrl_send_data(ctrl, skb, &resp, HGIC_CMD_TIMEOUT); } static int hgic_fwctrl_set_byte(struct hgic_fwctrl *ctrl, u32 cmd_id, u8 val) { int ret = -1; struct sk_buff *skb = NULL; struct sk_buff *resp = NULL; struct hgic_ctrl_hdr *hdr = NULL; skb = hgic_alloc_ctrl_skb(1); if (skb) { skb->data[0] = val; resp = hgic_fwctrl_send_cmd(ctrl, cmd_id, skb, true); if (resp) { hdr = (struct hgic_ctrl_hdr *)resp->data; ret = hdr->cmd.status; dev_kfree_skb_any(resp); } } if (ret) { hgic_dbg("cmd:%d, ret:%d (%s)\r\n", cmd_id, ret, resp ? "Responsed" : "No Response"); } return ret; } static int hgic_fwctrl_set_int_val(struct hgic_fwctrl *ctrl, u32 cmd_id, u32 val) { int ret = -1; struct sk_buff *skb = NULL; struct sk_buff *resp = NULL; struct hgic_ctrl_hdr *hdr = NULL; skb = hgic_alloc_ctrl_skb(4); if (skb) { put_unaligned_le32(val, skb->data); resp = hgic_fwctrl_send_cmd(ctrl, cmd_id, skb, true); if (resp) { hdr = (struct hgic_ctrl_hdr *)resp->data; ret = hdr->cmd.status; dev_kfree_skb_any(resp); } } if (ret) { hgic_dbg("cmd:%d, ret:%d (%s)\r\n", cmd_id, ret, resp ? "Responsed" : "No Response"); } return ret; } static short hgic_fwctrl_get_short_val(struct hgic_fwctrl *ctrl, u32 cmd_id) { short ret = -1; struct sk_buff *skb = NULL; struct sk_buff *resp = NULL; struct hgic_ctrl_hdr *hdr = NULL; skb = hgic_alloc_ctrl_skb(0); if (skb) { resp = hgic_fwctrl_send_cmd(ctrl, cmd_id, skb, true); if (resp) { hdr = (struct hgic_ctrl_hdr *)resp->data; ret = hdr->cmd.status; dev_kfree_skb_any(resp); } } return ret; } static int hgic_fwctrl_set_bytes(struct hgic_fwctrl *ctrl, u32 cmd_id, u8 *data, u32 len) { int ret = -1; struct sk_buff *skb = NULL; struct sk_buff *resp = NULL; struct hgic_ctrl_hdr *hdr = NULL; skb = hgic_alloc_ctrl_skb(len); if (skb) { if (data && len > 0) { memcpy(skb->data, data, len); skb->data[len] = 0; } resp = hgic_fwctrl_send_cmd(ctrl, cmd_id, skb, true); if (resp) { hdr = (struct hgic_ctrl_hdr *)resp->data; ret = hdr->cmd.status; dev_kfree_skb_any(resp); } if (ret) { hgic_dbg("cmd:%d, ret:%d (%s)\r\n", cmd_id, ret, resp ? "Responsed" : "No Response"); } } return ret; } static int hgic_fwctrl_get_bytes(struct hgic_fwctrl *ctrl, u32 cmd_id, u8 *buff, u32 len) { int ret = -1; struct sk_buff *skb = NULL; struct sk_buff *resp = NULL; struct hgic_ctrl_hdr *hdr = NULL; skb = hgic_alloc_ctrl_skb(0); if (skb) { resp = hgic_fwctrl_send_cmd(ctrl, cmd_id, skb, true); if (resp) { hdr = (struct hgic_ctrl_hdr *)resp->data; ret = hdr->cmd.status; if (ret > 0 && len > 0) { ret = ret > len ? len : ret; memcpy(buff, (char *)(hdr + 1), ret); } dev_kfree_skb_any(resp); } } if (ret < 0) { hgic_dbg("get string: cmd:%d, ret:%d (%s)\r\n", cmd_id, ret, resp ? "Responsed" : "No Response"); } return ret; } static int hgic_fwctrl_do_cmd(struct hgic_fwctrl *ctrl, u32 cmd_id, u8 *data, u32 len, u8 *buff, u32 size) { int ret = -1; struct sk_buff *skb = NULL; struct sk_buff *resp = NULL; struct hgic_ctrl_hdr *hdr = NULL; skb = hgic_alloc_ctrl_skb(len); if (skb) { if (data && len > 0) { memcpy(skb->data, data, len); skb->data[len] = 0; } resp = hgic_fwctrl_send_cmd(ctrl, cmd_id, skb, true); if (resp) { hdr = (struct hgic_ctrl_hdr *)resp->data; ret = hdr->cmd.status; if (ret > 0 && buff) { memcpy(buff, (char *)(hdr + 1), ret > size ? size : ret); } dev_kfree_skb_any(resp); } if (ret < 0) { hgic_dbg("cmd:%d, ret:%d (%s)\r\n", cmd_id, ret, resp ? "Responsed" : "No Response"); } } return ret; } static int hgic_fwctrl_rx_response(struct hgic_fwctrl *ctrl, struct sk_buff *skb) { int find = 0; unsigned long flags; struct hgic_cmd_response *resp = NULL; struct hgic_ctrl_hdr *cmd = (struct hgic_ctrl_hdr *)skb->data;; spin_lock_irqsave(&ctrl->lock, flags); list_for_each_entry(resp, &ctrl->pd_list, list) { if (resp->cookie == cmd->hdr.cookie) { resp->skb = skb; complete(&resp->cmpl); find = 1; break; } } spin_unlock_irqrestore(&ctrl->lock, flags); if (!find) { dev_kfree_skb_any(skb); } return 0; } static void hgic_fwctrl_clear_pdlist(struct hgic_fwctrl *ctrl) { unsigned long flags; struct hgic_cmd_response *sync = NULL; spin_lock_irqsave(&ctrl->lock, flags); list_for_each_entry(sync, &ctrl->pd_list, list) { complete(&sync->cmpl); } spin_unlock_irqrestore(&ctrl->lock, flags); } static void hgic_fwctrl_work(struct work_struct *work) { struct hgic_fwctrl *ctrl = NULL; struct sk_buff *skb = NULL; struct hgic_ctrl_hdr *hdr = NULL; ctrl = container_of(work, struct hgic_fwctrl, work); while (!skb_queue_empty(&ctrl->rxq)) { skb = skb_dequeue(&ctrl->rxq); hdr = (struct hgic_ctrl_hdr *)skb->data; switch (hdr->hdr.type) { case HGIC_HDR_TYPE_CMD: case HGIC_HDR_TYPE_CMD2: case HGIC_HDR_TYPE_BOOTDL: case HGIC_HDR_TYPE_OTA: hgic_fwctrl_rx_response(ctrl, skb); break; case HGIC_HDR_TYPE_EVENT: case HGIC_HDR_TYPE_EVENT2: hgic_rx_fw_event(ctrl, skb); break; default: dev_kfree_skb(skb); break; } } } static void hgic_fwctrl_flush_work(struct work_struct *work) { struct hgic_fwctrl *ctrl = container_of(work, struct hgic_fwctrl, flush_work); hgic_fwctrl_flush_param(ctrl); } struct sk_buff *hgic_fwctrl_send_data(struct hgic_fwctrl *ctrl, struct sk_buff *skb, struct hgic_cmd_response *resp, u32 timeout) { unsigned long flags; init_completion(&resp->cmpl); spin_lock_irqsave(&ctrl->lock, flags); list_add(&resp->list, &ctrl->pd_list); spin_unlock_irqrestore(&ctrl->lock, flags); skb_queue_tail(&ctrl->txq, skb); hgic_schedule(ctrl); if (timeout) { wait_for_completion_timeout(&resp->cmpl, msecs_to_jiffies(timeout)); } spin_lock_irqsave(&ctrl->lock, flags); list_del(&resp->list); spin_unlock_irqrestore(&ctrl->lock, flags); #ifdef __RTOS__ deinit_completion(&resp->cmpl); #endif return resp->skb; } void hgic_fwctrl_rx(struct hgic_fwctrl *ctrl, struct sk_buff *skb) { skb_queue_tail(&ctrl->rxq, skb); if (ctrl->wq) { queue_work(ctrl->wq, &ctrl->work); } else { hgic_err("fwctrl workqueue is NULL\r\n"); } } void hgic_fwctrl_init(struct hgic_fwctrl *ctrl, void *dev) { memset(ctrl, 0, sizeof(struct hgic_fwctrl)); ctrl->dev = dev; ctrl->param.acs = 0x3; ctrl->param.tx_mcs = 0xff; ctrl->param.ps_mode = 0xff; ctrl->param.wkio_mode = 0xff; spin_lock_init(&ctrl->lock); INIT_LIST_HEAD(&ctrl->pd_list); skb_queue_head_init(&ctrl->rxq); skb_queue_head_init(&ctrl->txq); INIT_WORK(&ctrl->flush_work, hgic_fwctrl_flush_work); INIT_WORK(&ctrl->work, hgic_fwctrl_work); ctrl->wq = ALLOC_ORDERED_WORKQUEUE("fwctrl", 0); } void hgic_fwctrl_release(struct hgic_fwctrl *ctrl) { cancel_work_sync(&ctrl->work); cancel_work_sync(&ctrl->flush_work); hgic_fwctrl_clear_pdlist(ctrl); hgic_clear_queue(&ctrl->txq); hgic_clear_queue(&ctrl->rxq); #ifdef __RTOS__ skb_queue_head_deinit(&ctrl->rxq); skb_queue_head_deinit(&ctrl->txq); spin_lock_deinit(&ctrl->lock); #endif if (ctrl->wq) { flush_workqueue(ctrl->wq); destroy_workqueue(ctrl->wq); } ARG_FREE(country_code); ARG_FREE(ssid); ARG_FREE(bssid); ARG_FREE(bssid_filter); ARG_FREE(key_mgmt); ARG_FREE(wpa_psk); ARG_FREE(mode); ARG_FREE(mac_addr); ARG_FREE(chan_list); ARG_FREE(paired_stas); ARG_FREE(mcast_key); } void hgic_fwctrl_flush_param(struct hgic_fwctrl *ctrl) { //int retry = 0; if (ctrl->param.bss_bw) { hgic_fwctrl_set_bss_bw(ctrl, ctrl->param.bss_bw); } if (ctrl->param.chan_list) { hgic_fwctrl_set_chan_list(ctrl, (u16 *)ctrl->param.chan_list, ctrl->param.chan_cnt); } if (ctrl->param.freq_start) { hgic_fwctrl_set_freq_range(ctrl, ctrl->param.freq_start, ctrl->param.freq_end, ctrl->param.chan_bw); } if (ctrl->param.country_code) { hgic_fwctrl_set_countryregion(ctrl, ctrl->param.country_code); } if (ctrl->param.ssid) { hgic_fwctrl_set_ssid(ctrl, ctrl->param.ssid); } if (ctrl->param.bssid) { hgic_fwctrl_set_bssid(ctrl, ctrl->param.bssid); } if (ctrl->param.bssid_filter) { hgic_fwctrl_set_bssid_filter(ctrl, ctrl->param.bssid_filter); } if (ctrl->param.key_mgmt) { hgic_fwctrl_set_key_mgmt(ctrl, ctrl->param.key_mgmt); } if (ctrl->param.wpa_psk) { hgic_fwctrl_set_wpa_psk(ctrl, ctrl->param.wpa_psk); } if (ctrl->param.mcast_key) { hgic_fwctrl_set_mcast_key(ctrl, ctrl->param.mcast_key); } if (ctrl->param.mac_addr) { hgic_fwctrl_set_mac(ctrl, ctrl->param.mac_addr); } if (ctrl->param.channel) { hgic_fwctrl_set_channel(ctrl, ctrl->param.channel); } if (ctrl->param.rts_threshold) { hgic_fwctrl_set_rts_threshold(ctrl, ctrl->param.rts_threshold); } if (ctrl->param.frag_threshold) { hgic_fwctrl_set_frag_threshold(ctrl, ctrl->param.frag_threshold); } if (ctrl->param.listen_interval) { hgic_fwctrl_set_listen_interval(ctrl, ctrl->param.listen_interval); } if (ctrl->param.center_freq) { hgic_fwctrl_set_center_freq(ctrl, ctrl->param.center_freq); } if (ctrl->param.beacon_int) { hgic_fwctrl_set_beacon_int(ctrl, ctrl->param.beacon_int); } if (ctrl->param.ethertype) { hgic_fwctrl_set_ethertype(ctrl, ctrl->param.ethertype); } if (ctrl->param.txpower) { hgic_fwctrl_set_txpower(ctrl, ctrl->param.txpower); } if (ctrl->param.primary_chan) { hgic_fwctrl_set_primary_chan(ctrl, ctrl->param.primary_chan); } if (ctrl->param.mode) { hgic_fwctrl_set_mode(ctrl, ctrl->param.mode); } if (ctrl->param.acs != 0x3) { hgic_fwctrl_set_acs(ctrl, ctrl->param.acs, ctrl->param.acs_tmo); } if (ctrl->param.bss_max_idle) { hgic_fwctrl_set_bss_max_idle(ctrl, ctrl->param.bss_max_idle); } if (ctrl->param.dtim_period) { hgic_fwctrl_set_dtim_period(ctrl, ctrl->param.dtim_period); } if (ctrl->param.ps_connect) { hgic_fwctrl_set_ps_connect(ctrl, ctrl->param.ps_connect, ctrl->param.ps_connect_roundup); } if (ctrl->param.agg_cnt) { hgic_fwctrl_set_agg_cnt(ctrl, ctrl->param.agg_cnt); } if (ctrl->param.wkio_mode != 0xff) { hgic_fwctrl_set_wkio_mode(ctrl, ctrl->param.wkio_mode); } if (ctrl->param.ps_mode != 0xff) { hgic_fwctrl_set_ps_mode(ctrl, ctrl->param.ps_mode); } if (ctrl->param.aplost_time) { hgic_fwctrl_set_aplost_time(ctrl, ctrl->param.aplost_time); } if (ctrl->param.tx_mcs != 0xff) { hgic_fwctrl_set_tx_mcs(ctrl, ctrl->param.tx_mcs); } } /////////////////////////////////////////////////////////////////////////////////////////// int hgic_fwctrl_testmode_cmd(struct hgic_fwctrl *ctrl, u8 *cmd, u32 size) { int ret = 0; ret = hgic_fwctrl_do_cmd(ctrl, HGIC_CMD_TESTMODE_CMD, cmd, STR_LEN(cmd), cmd, size); if (ret < 0) { strcpy(cmd, "failed"); } else { cmd[ret] = 0; } return ret; } int hgic_fwctrl_get_status(struct hgic_fwctrl *ctrl, u8 *buff, u32 len) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_STATUS, buff, len); } int hgic_fwctrl_get_conn_state(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_do_cmd(ctrl, HGIC_CMD_GET_CONN_STATE, NULL, 0, NULL, 0); } int hgic_fwctrl_get_fwinfo(struct hgic_fwctrl *ctrl, struct hgic_fw_info *info) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_FW_INFO, (u8 *)info, sizeof(struct hgic_fw_info)); } int hgic_fwctrl_set_countryregion(struct hgic_fwctrl *ctrl, u8 *country_code) { ARG_DUP(country_code, 0); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_COUNTERY, country_code, STR_LEN(country_code)); } int hgic_fwctrl_set_ssid(struct hgic_fwctrl *ctrl, u8 *ssid) { ARG_DUP(ssid, 0); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_SSID, ssid, STR_LEN(ssid)); } int hgic_fwctrl_set_bssid(struct hgic_fwctrl *ctrl, u8 *bssid) { ARG_DUP(bssid, 6); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_BSSID, bssid, 6); } int hgic_fwctrl_set_channel(struct hgic_fwctrl *ctrl, u32 channel) { ctrl->param.acs = 0; ctrl->param.channel = channel; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_CHANNEL, channel); } int hgic_fwctrl_set_bssid_filter(struct hgic_fwctrl *ctrl, u8 *bssid_filter) { ARG_DUP(bssid_filter, 0); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_BSSID_FILTER, bssid_filter, STR_LEN(bssid_filter)); } int hgic_fwctrl_set_rts_threshold(struct hgic_fwctrl *ctrl, u32 rts_threshold) { ctrl->param.rts_threshold = rts_threshold; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_RTS_THRESHOLD, rts_threshold); } int hgic_fwctrl_set_frag_threshold(struct hgic_fwctrl *ctrl, u32 frag_threshold) { ctrl->param.frag_threshold = frag_threshold; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_FRG_THRESHOLD, frag_threshold); } int hgic_fwctrl_set_key_mgmt(struct hgic_fwctrl *ctrl, u8 *key_mgmt) { ARG_DUP(key_mgmt, 0); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_KEY_MGMT, key_mgmt, STR_LEN(key_mgmt)); } int hgic_fwctrl_set_wpa_psk(struct hgic_fwctrl *ctrl, u8 *wpa_psk) { ARG_DUP(wpa_psk, 0); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_WPA_PSK, wpa_psk, STR_LEN(wpa_psk)); } int hgic_fwctrl_set_wbnat(struct hgic_fwctrl *ctrl, u32 enable) { return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_WBNAT, enable); } int hgic_fwctrl_set_freq_range(struct hgic_fwctrl *ctrl, u32 freq_start, u32 freq_end, u32 bss_bw) { u8 data[12]; put_unaligned_le32(freq_start, data); put_unaligned_le32(freq_end, data + 4); put_unaligned_le32(bss_bw, data + 8); ctrl->param.freq_start = freq_start; ctrl->param.freq_end = freq_end; ctrl->param.chan_bw = bss_bw; ARG_FREE(chan_list); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_FREQ_RANGE, data, 12); } int hgic_fwctrl_set_bss_bw(struct hgic_fwctrl *ctrl, u8 bss_bw) { ctrl->param.bss_bw = bss_bw; return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_BSS_BW, bss_bw); } int hgic_fwctrl_set_tx_bw(struct hgic_fwctrl *ctrl, u8 tx_bw) { ctrl->param.tx_bw = tx_bw; return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_TX_BW, tx_bw); } int hgic_fwctrl_set_tx_mcs(struct hgic_fwctrl *ctrl, u8 tx_mcs) { ctrl->param.tx_mcs = tx_mcs; return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_TX_MCS, tx_mcs); } int hgic_fwctrl_set_acs(struct hgic_fwctrl *ctrl, u8 acs, u8 acs_tmo) { u8 data[2] = {acs, acs_tmo}; ctrl->param.acs = acs; ctrl->param.acs_tmo = acs_tmo; if (acs) { ctrl->param.channel = 0; ctrl->param.center_freq = 0; } return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_ACS_ENABLE, data, 2); } int hgic_fwctrl_set_bgrssi(struct hgic_fwctrl *ctrl, u8 bgrssi) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_BG_RSSI, bgrssi); } int hgic_fwctrl_set_chan_list(struct hgic_fwctrl *ctrl, u16 *chan_list, u32 cnt) { int ret = -1; int i = 0; u8 *buf = kzalloc((1 + cnt) * sizeof(u16), GFP_KERNEL); ARG_DUP(chan_list, cnt * sizeof(u16)); ctrl->param.chan_cnt = cnt; ctrl->param.freq_start = 0; if (buf) { put_unaligned_le16(cnt, buf); for (i = 0; i < cnt; i++) { put_unaligned_le16(chan_list[i], buf + (i + 1) * sizeof(u16)); } ret = hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_CHAN_LIST, buf, (1 + cnt) * sizeof(u16)); kfree(buf); } return ret; } int hgic_fwctrl_set_mode(struct hgic_fwctrl *ctrl, u8 *mode) { ARG_DUP(mode, 0); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_WORK_MODE, mode, STR_LEN(mode)); } int hgic_fwctrl_set_paired_stas(struct hgic_fwctrl *ctrl, u8 *paired_stas, u32 len) { ARG_DUP(paired_stas, len); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_PAIRED_STATIONS, paired_stas, len); } int hgic_fwctrl_set_pairing(struct hgic_fwctrl *ctrl, u8 start) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_PAIRING, start); } int hgic_fwctrl_open_dev(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_do_cmd(ctrl, HGIC_CMD_DEV_OPEN, 0, 0, 0, 0); } int hgic_fwctrl_close_dev(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_do_cmd(ctrl, HGIC_CMD_DEV_CLOSE, 0, 0, 0, 0); } int hgic_fwctrl_set_txpower(struct hgic_fwctrl *ctrl, u32 tx_power) { ctrl->param.txpower = tx_power; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_TX_POWER, tx_power); } int hgic_fwctrl_get_txpower(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_TX_POWER); } int hgic_fwctrl_set_listen_interval(struct hgic_fwctrl *ctrl, u32 listen_interval) { ctrl->param.listen_interval = listen_interval; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_LISTEN_INTERVAL, listen_interval); } int hgic_fwctrl_set_center_freq(struct hgic_fwctrl *ctrl, u32 center_freq) { ctrl->param.acs = 0; ctrl->param.center_freq = center_freq; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_CENTER_FREQ, center_freq); } int hgic_fwctrl_set_tx_count(struct hgic_fwctrl *ctrl, u32 short_frm_tx_count, u32 long_frm_tx_count) { u8 data[8]; put_unaligned_le32(short_frm_tx_count, data); put_unaligned_le32(long_frm_tx_count, data + 4); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_TX_LCOUNT, data, 8); } int hgic_fwctrl_set_key(struct hgic_fwctrl *ctrl, u8 cmd, u16 aid, u8 *key, u8 len) { int ret = -ENOMEM; u8 *buff = kmalloc(len + 4, GFP_KERNEL); if (buff) { buff[0] = cmd; put_unaligned_le16(aid, buff + 1); buff[3] = len; memcpy(buff + 4, key, len); ret = hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_KEY, buff, len + 4); kfree(buff); } return ret; } int hgic_fwctrl_add_sta(struct hgic_fwctrl *ctrl, u16 aid, u8 *addr) { uint8_t sta_info[8]; put_unaligned_le16(aid, sta_info); memcpy(sta_info + 2, addr, 6); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_ADD_STA, sta_info, 8); } int hgic_fwctrl_del_sta(struct hgic_fwctrl *ctrl, u32 aid) { return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_REMOVE_STA, aid); } int hgic_fwctrl_set_primary_chan(struct hgic_fwctrl *ctrl, u8 primary_chan) { ctrl->param.primary_chan = primary_chan; return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_PRIMARY_CHAN, primary_chan); } int hgic_fwctrl_set_aid(struct hgic_fwctrl *ctrl, u32 aid) { return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_AID, aid); } int hgic_fwctrl_set_mac(struct hgic_fwctrl *ctrl, u8 *mac_addr) { ARG_DUP(mac_addr, 6); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_MAC, mac_addr, 6); } int hgic_fwctrl_get_scan_list(struct hgic_fwctrl *ctrl, u8 *buff, u32 size) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_SCAN_LIST, buff, size); } int hgic_fwctrl_scan(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SCAN, 1); } int hgic_fwctrl_set_txq_param(struct hgic_fwctrl *ctrl, u8 *txq, u32 size) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_TXQ_PARAM, txq, size); } int hgic_fwctrl_get_temperature(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_TEMPERATURE); } int hgic_fwctrl_enter_sleep(struct hgic_fwctrl *ctrl, u8 sleep) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_ENTER_SLEEP, sleep); } int hgic_fwctrl_get_sta_list(struct hgic_fwctrl *ctrl, struct hgic_sta_info *sta_list, u32 size) { int ret = hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_STA_LIST, (u8 *)sta_list, size * sizeof(struct hgic_sta_info)); return ret > 0 ? (ret / sizeof(struct hgic_sta_info)) : ret; } int hgic_fwctrl_set_beacon_int(struct hgic_fwctrl *ctrl, u32 beacon_int) { ctrl->param.beacon_int = beacon_int; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_BEACON_INT, beacon_int); } int hgic_fwctrl_get_ssid(struct hgic_fwctrl *ctrl, u8 *ssid, u32 size) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_SSID, ssid, size); } int hgic_fwctrl_get_bssid(struct hgic_fwctrl *ctrl, u8 *bssid) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_BSSID, bssid, 6); } int hgic_fwctrl_get_wpapsk(struct hgic_fwctrl *ctrl, u8 *psk, u32 size) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_WPA_PSK, psk, size); } int hgic_fwctrl_save_cfg(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_do_cmd(ctrl, HGIC_CMD_SAVE_CFG, 0, 0, 0, 0); } int hgic_fwctrl_join_group(struct hgic_fwctrl *ctrl, u8 *addr, u8 aid) { u8 val[7]; memcpy(val, addr, 6); val[6] = aid; return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_JOIN_GROUP, val, 7); } int hgic_fwctrl_set_ethertype(struct hgic_fwctrl *ctrl, u16 ethertype) { u8 vals[2]; ctrl->param.ethertype = ethertype; put_unaligned_le16(ethertype, vals); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_ETHER_TYPE, vals, 2); } int hgic_fwctrl_get_sta_count(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_do_cmd(ctrl, HGIC_CMD_GET_STA_COUNT, 0, 0, 0, 0); } int hgic_fwctrl_get_agg_cnt(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_AGG_CNT); } int hgic_fwctrl_set_agg_cnt(struct hgic_fwctrl *ctrl, u8 agg_cnt) { ctrl->param.agg_cnt = agg_cnt; return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_AGG_CNT, agg_cnt); } int hgic_fwctrl_get_bss_bw(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_BSS_BW); } int hgic_fwctrl_get_freq_range(struct hgic_fwctrl *ctrl, u32 *freq_start, u32 *freq_end, u32 *bss_bw) { int ret = 0; u32 vals[3]; ret = hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_FREQ_RANGE, (u8 *)&vals, sizeof(vals)); if (ret == 12) { *freq_start = vals[0]; *freq_end = vals[1]; *bss_bw = vals[2]; } return (ret == 12); } int hgic_fwctrl_get_chan_list(struct hgic_fwctrl *ctrl, u16 *chan_list, u16 count) { int ret = hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_CHAN_LIST, (u8 *)chan_list, count * sizeof(u16)); return ret > 0 ? ret / sizeof(u16) : 0; } int hgic_fwctrl_wakeup_sta(struct hgic_fwctrl *ctrl, u8 *addr) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_WAKEUP_STA, addr, 6); } int hgic_fwctrl_set_ps_heartbeat(struct hgic_fwctrl *ctrl, u32 ipaddr, u32 dport, u32 period, u32 hb_tmo) { u8 val[16]; put_unaligned_le32(ipaddr, val); put_unaligned_le32(dport, val + 4); put_unaligned_le32(period, val + 8); put_unaligned_le32(hb_tmo, val + 12); hgic_dbg("ip:%x, port:%d, period:%d, hb_tmo:%d\r\n", ipaddr, dport, period, hb_tmo); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_PS_HEARTBEAT, val, 16); } int hgic_fwctrl_set_ps_heartbeat_resp(struct hgic_fwctrl *ctrl, u8 *data, u32 size) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_PS_HEARTBEAT_RESP, data, size); } int hgic_fwctrl_set_ps_wakeup_data(struct hgic_fwctrl *ctrl, u8 *data, u32 size) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_PS_WAKEUP_DATA, data, size); } int hgic_fwctrl_set_ps_connect(struct hgic_fwctrl *ctrl, u8 period, u8 roundup) { u8 val[2] = {period, roundup}; ctrl->param.ps_connect = period; ctrl->param.ps_connect_roundup = roundup; return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_PS_CONNECT, val, 2); } int hgic_fwctrl_radio_onoff(struct hgic_fwctrl *ctrl, u8 onoff) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_RADIO_ONOFF, onoff); } int hgic_fwctrl_set_bss_max_idle(struct hgic_fwctrl *ctrl, u32 max_idle) { ctrl->param.bss_max_idle = max_idle; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_BSS_MAX_IDLE, max_idle); } int hgic_fwctrl_set_wkio_mode(struct hgic_fwctrl *ctrl, u8 mode) { ctrl->param.wkio_mode = mode; return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_WKIO_MODE, mode); } int hgic_fwctrl_set_dtim_period(struct hgic_fwctrl *ctrl, u32 period) { ctrl->param.dtim_period = period; return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_DTIM_PERIOD, period); } int hgic_fwctrl_set_ps_mode(struct hgic_fwctrl *ctrl, u8 mode) { ctrl->param.ps_mode = mode; return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_PS_MODE, mode); } int hgic_fwctrl_set_load_def(struct hgic_fwctrl *ctrl, u8 rst) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_LOAD_DEF, rst); } int hgic_fwctrl_disassoc_sta(struct hgic_fwctrl *ctrl, u8 *addr) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_DISASSOC_STA, addr, 6); } int hgic_fwctrl_set_aplost_time(struct hgic_fwctrl *ctrl, u32 aplost_time) { return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_APLOST_TIME, aplost_time); } int hgic_fwctrl_get_wkreason(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_do_cmd(ctrl, HGIC_CMD_GET_WAKEUP_REASON, 0, 0, 0, 0); } int hgic_fwctrl_unpair(struct hgic_fwctrl *ctrl, u8 *addr) { ARG_FREE(ssid); ARG_FREE(bssid); ARG_FREE(bssid_filter); ARG_FREE(key_mgmt); ARG_FREE(wpa_psk); ARG_FREE(paired_stas); ARG_FREE(mcast_key); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_UNPAIR, addr, 6); } int hgic_fwctrl_set_auto_chswitch(struct hgic_fwctrl *ctrl, u8 enable) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_AUTO_CHAN_SWITCH, enable); } int hgic_fwctrl_set_mcast_key(struct hgic_fwctrl *ctrl, u8 *mcast_key) { ARG_DUP(mcast_key, 0); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_MCAST_KEY, mcast_key, STR_LEN(mcast_key)); } int hgic_fwctrl_set_reassoc_wkhost(struct hgic_fwctrl *ctrl, u8 enable) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_REASSOC_WKHOST, enable); } int hgic_fwctrl_set_wakeup_io(struct hgic_fwctrl *ctrl, u8 io, u8 edge) { u8 val[2] = {io, edge}; return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_WAKEUP_IO, val, 2); } int hgic_fwctrl_set_dbginfo_output(struct hgic_fwctrl *ctrl, u8 enable) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_DBGINFO_OUTPUT, enable); } int hgic_fwctrl_set_sysdbg(struct hgic_fwctrl *ctrl, u8 *cmd) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_SYSDBG, cmd, STR_LEN(cmd)); } int hgic_fwctrl_set_autosleep_time(struct hgic_fwctrl *ctrl, u8 time) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_AUTO_SLEEP_TIME, time); } int hgic_fwctrl_get_key_mgmt(struct hgic_fwctrl *ctrl, u8 *ssid, u32 size) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_KEY_MGMT, ssid, size); } int hgic_fwctrl_set_supper_pwr(struct hgic_fwctrl *ctrl, u8 enable) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_SUPPER_PWR, enable); } int hgic_fwctrl_set_repeater_ssid(struct hgic_fwctrl *ctrl, u8 *ssid) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_REPEATER_SSID, ssid, STR_LEN(ssid)); } int hgic_fwctrl_set_repeater_psk(struct hgic_fwctrl *ctrl, u8 *wpa_psk) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_REPEATER_PSK, wpa_psk, STR_LEN(wpa_psk)); } int hgic_fwctrl_set_auto_save(struct hgic_fwctrl *ctrl, u8 enable) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_CFG_AUTO_SAVE, enable); } int hgic_fwctrl_set_pair_autostop(struct hgic_fwctrl *ctrl, u8 enable) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_PAIR_AUTOSTOP, enable); } int hgic_fwctrl_send_cust_mgmt(struct hgic_fwctrl *ctrl, u8 *data, u32 len) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SEND_CUST_MGMT, data, len); } int hgic_fwctrl_get_battery_level(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_BATTERY_LEVEL); } int hgic_fwctrl_set_dcdc13v(struct hgic_fwctrl *ctrl, u8 enable) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_DCDC13, enable); } int hgic_fwctrl_set_acktmo(struct hgic_fwctrl *ctrl, u32 tmo) { return hgic_fwctrl_set_int_val(ctrl, HGIC_CMD_SET_ACKTMO, tmo); } int hgic_fwctrl_get_module_type(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_MODULETYPE); } int hgic_fwctrl_set_pa_pwrctl_dis(struct hgic_fwctrl *ctrl, u8 dis) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_PA_PWRCTRL_DIS, dis); } int hgic_fwctrl_set_dhcpc(struct hgic_fwctrl *ctrl, u8 en) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_DHCPC, en); } int hgic_fwctrl_get_dhcpc_result(struct hgic_fwctrl *ctrl, u8 *buff, int len) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_DHCPC_RESULT, buff, len); } int hgic_fwctrl_set_wkdata_mask(struct hgic_fwctrl *ctrl, u16 offset, u8 *mask, u8 mask_len) { u8 data[128]; if(mask_len > 16) mask_len = 16; memset(data, 0, sizeof(data)); put_unaligned_le16(offset, data); memcpy(data + 2, mask, mask_len); return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_WKUPDATA_MASK, data, mask_len + 2); } int hgic_fwctrl_get_wkdata_buff(struct hgic_fwctrl *ctrl, u8 *buff, int len) { return hgic_fwctrl_get_bytes(ctrl, HGIC_CMD_GET_WKDATA_BUFF, buff, len); } int hgic_fwctrl_get_disassoc_reason(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_DISASSOC_REASON); } int hgic_fwctrl_set_wkdata_save(struct hgic_fwctrl *ctrl, u8 save) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_WKUPDATA_SAVEEN, save); } int hgic_fwctrl_set_cust_driver_data(struct hgic_fwctrl *ctrl, u8 *data, u32 len) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_CUST_DRIVER_DATA, data, len); } int hgic_fwctrl_set_mcast_txparam(struct hgic_fwctrl *ctrl, struct hgic_mcast_txparam *param) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_MCAST_TXPARAM, (u8 *)param, sizeof(struct hgic_mcast_txparam)); } int hgic_fwctrl_set_freqinfo(struct hgic_fwctrl *ctrl, u8 *data, u32 len) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_STA_FREQINFO, data, len); } int hgic_fwctrl_reset_sta(struct hgic_fwctrl *ctrl, u8 *addr) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_RESET_STA, addr, 6); } int hgic_fwctrl_set_ant_auto(struct hgic_fwctrl *ctrl, u8 en) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_ANT_AUTO, en); } int hgic_fwctrl_select_ant(struct hgic_fwctrl *ctrl, u8 ant) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_ANT_SEL, ant); } int hgic_fwctrl_get_ant_sel(struct hgic_fwctrl *ctrl) { return hgic_fwctrl_get_short_val(ctrl, HGIC_CMD_GET_ANT_SEL); } int hgic_fwctrl_set_wkhost_reasons(struct hgic_fwctrl *ctrl, u8 *reasons, u8 count) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_WKUP_HOST_REASON, reasons, count); } int hgic_fwctrl_set_mac_filter(struct hgic_fwctrl *ctrl, u8 en) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_MAC_FILTER_EN, en); } int hgic_fwctrl_set_atcmd(struct hgic_fwctrl *ctrl, char *atcmd) { return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_ATCMD, atcmd, strlen(atcmd)); } int hgic_fwctrl_set_roaming(struct hgic_fwctrl *ctrl, u8 en, u8 same_freq) { u8 vals[2] = {en, same_freq}; return hgic_fwctrl_set_bytes(ctrl, HGIC_CMD_SET_ROAMING, vals, 2); } int hgic_fwctrl_set_ap_hide(struct hgic_fwctrl *ctrl, u8 hide) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_AP_HIDE, hide); } int hgic_fwctrl_set_frm_tx_maxcnt(struct hgic_fwctrl *ctrl, u8 txcnt) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_MAX_TCNT, txcnt); } int hgic_fwctrl_set_assert_holdup(struct hgic_fwctrl *ctrl, u8 holdup) { return hgic_fwctrl_set_byte(ctrl, HGIC_CMD_SET_ASSERT_HOLDUP, holdup); }