static void wl1251_sdio_interrupt(struct sdio_func *func) { struct wl1251 *wl = sdio_get_drvdata(func); wl1251_debug(DEBUG_IRQ, "IRQ"); /* FIXME should be synchronous for sdio */ ieee80211_queue_work(wl->hw, &wl->irq_work); }
static void wl1251_op_stop(struct ieee80211_hw *hw) { struct wl1251 *wl = hw->priv; wl1251_info("down"); wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); mutex_lock(&wl->mutex); WARN_ON(wl->state != WL1251_STATE_ON); if (wl->scanning) { ieee80211_scan_completed(wl->hw, true); wl->scanning = false; } wl->state = WL1251_STATE_OFF; wl1251_disable_interrupts(wl); mutex_unlock(&wl->mutex); cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->elp_work); mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ wl1251_tx_flush(wl); wl1251_power_off(wl); eth_zero_addr(wl->bssid); wl->listen_int = 1; wl->bss_type = MAX_BSS_TYPE; wl->data_in_count = 0; wl->rx_counter = 0; wl->rx_handled = 0; wl->rx_current_buffer = 0; wl->rx_last_id = 0; wl->next_tx_complete = 0; wl->elp = false; wl->station_mode = STATION_ACTIVE_MODE; wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->rssi_thold = 0; wl->channel = WL1251_DEFAULT_CHANNEL; wl->monitor_present = false; wl->joined = false; wl1251_debugfs_reset(wl); mutex_unlock(&wl->mutex); }
static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) { int ret = 0; wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", mbox->scheduled_scan_status, mbox->scheduled_scan_channels); if (wl->scanning) { ieee80211_scan_completed(wl->hw, false); wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; if (wl->hw->conf.flags & IEEE80211_CONF_IDLE) ret = wl1251_ps_set_mode(wl, STATION_IDLE); } return ret; }
static void wl1251_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wl1251 *wl = hw->priv; mutex_lock(&wl->mutex); wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); wl->vif = NULL; mutex_unlock(&wl->mutex); }
/* Routines to toggle sleep mode while in ELP */ void wl1251_ps_elp_sleep(struct wl1251 *wl) { if (wl->elp || !wl->psm) return; wl1251_debug(DEBUG_PSM, "chip to elp"); wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); wl->elp = true; }
static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) { int ret = 0; struct sdio_func *func = wl_to_func(wl); wl1251_enter(); if (enable) { if (wl->set_power) wl->set_power(true); ret = mmc_power_restore_host(func->card->host); if (ret) { wl1251_error("failed to restore host power"); goto out; } wl1251_debug(DEBUG_PSM, "sdio_claim_host"); sdio_claim_host(func); wl1251_debug(DEBUG_PSM, "sdio_enable_func"); sdio_enable_func(func); wl1251_debug(DEBUG_PSM, "sdio_release_host"); sdio_release_host(func); wl1251_debug(DEBUG_PSM, "sdio_done"); } else { wl1251_debug(DEBUG_PSM, "sdio_claim_host"); sdio_claim_host(func); wl1251_debug(DEBUG_PSM, "sdio_disable_func"); sdio_disable_func(func); wl1251_debug(DEBUG_PSM, "sdio_release_host"); sdio_release_host(func); wl1251_debug(DEBUG_PSM, "power_save_host"); ret = mmc_power_save_host(func->card->host); if (ret) { wl1251_error("failed to disable host power"); goto out; } wl1251_debug(DEBUG_PSM, "power_save done"); if (wl->set_power) wl->set_power(false); } out: wl1251_leave(); return ret; }
static void wl1251_rx_body(struct wl1251 *wl, struct wl1251_rx_descriptor *desc) { struct sk_buff *skb; struct ieee80211_rx_status status; u8 *rx_buffer, beacon = 0; u16 length, *fc; u32 curr_id, last_id_inc, rx_packet_ring_addr; length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); if (last_id_inc != curr_id) { wl1251_warning("curr ID:%d, last ID inc:%d", curr_id, last_id_inc); wl->rx_last_id = curr_id; } else { wl->rx_last_id = last_id_inc; } rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + sizeof(struct wl1251_rx_descriptor) + 20; if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; skb = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1251_error("Couldn't allocate RX frame"); return; } rx_buffer = skb_put(skb, length); wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); /* The actual length doesn't include the target's alignment */ skb_trim(skb, desc->length - PLCP_HEADER_LENGTH); fc = (u16 *)skb->data; if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) beacon = 1; wl1251_rx_status(wl, desc, &status, beacon); wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, beacon ? "beacon" : ""); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); ieee80211_rx_ni(wl->hw, skb); wl1251_update_rate(wl, length); }
int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, u16 beacon_interval, u8 dtim_interval) { struct cmd_join *join; int ret, i; u8 *bssid; join = kzalloc(sizeof(*join), GFP_KERNEL); if (!join) { ret = -ENOMEM; goto out; } wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", bss_type == BSS_TYPE_IBSS ? " ibss" : "", channel, beacon_interval, dtim_interval); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; for (i = 0; i < ETH_ALEN; i++) bssid[i] = wl->bssid[ETH_ALEN - i - 1]; join->rx_config_options = wl->rx_config; join->rx_filter_options = wl->rx_filter; /* * FIXME: disable temporarily all filters because after commit * 9cef8737 "mac80211: fix managed mode BSSID handling" broke * association. The filter logic needs to be implemented properly * and once that is done, this hack can be removed. */ join->rx_config_options = 0; join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; join->beacon_interval = beacon_interval; join->dtim_interval = dtim_interval; join->bss_type = bss_type; join->channel = channel; join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); if (ret < 0) { wl1251_error("failed to initiate cmd join"); goto out; } out: kfree(join); return ret; }
static irqreturn_t wl1251_irq(int irq, void *cookie) { struct wl1251 *wl; wl1251_debug(DEBUG_IRQ, "IRQ"); wl = cookie; ieee80211_queue_work(wl->hw, &wl->irq_work); return IRQ_HANDLED; }
int wl1251_acx_sg_cfg(struct wl1251 *wl) { struct acx_bt_wlan_coex_param *param; int ret; wl1251_debug(DEBUG_ACX, "acx sg cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) { ret = -ENOMEM; goto out; } /* BT-WLAN coext parameters */ param->min_rate = RATE_INDEX_24MBPS; param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; param->antenna_type = PTA_ANTENNA_TYPE_DEF; param->signal_type = PTA_SIGNALING_TYPE_DEF; param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; param->max_cts = PTA_MAX_NUM_CTS_DEF; param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; param->wlan_elp_hp = PTA_ELP_HP_DEF; param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); if (ret < 0) { wl1251_warning("failed to set sg config: %d", ret); goto out; } out: kfree(param); return ret; }
int wl1251_ps_elp_wakeup(struct wl1251 *wl) { unsigned long timeout, start; u32 elp_reg; if (delayed_work_pending(&wl->elp_work)) cancel_delayed_work(&wl->elp_work); if (!wl->elp) return 0; wl1251_debug(DEBUG_PSM, "waking up chip from elp"); start = jiffies; timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); /* * FIXME: we should wait for irq from chip but, as a temporary * solution to simplify locking, let's poll instead */ while (!(elp_reg & ELPCTRL_WLAN_READY)) { if (time_after(jiffies, timeout)) { wl1251_error("elp wakeup timeout"); return -ETIMEDOUT; } msleep(1); elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); } wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies - start)); wl->elp = false; return 0; }
static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) { if (wl->scanning) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw); mutex_lock(&wl->mutex); wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; } return 0; }
int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) { struct cmd_enabledisable_path *cmd; int ret; u16 cmd_rx, cmd_tx; wl1251_debug(DEBUG_CMD, "cmd data path"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->channel = channel; if (enable) { cmd_rx = CMD_ENABLE_RX; cmd_tx = CMD_ENABLE_TX; } else { cmd_rx = CMD_DISABLE_RX; cmd_tx = CMD_DISABLE_TX; } ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); if (ret < 0) { wl1251_error("rx %s cmd for channel %d failed", enable ? "start" : "stop", channel); goto out; } wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); if (ret < 0) { wl1251_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); <<<<<<< HEAD
int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, size_t len) { int ret; wl1251_debug(DEBUG_ACX, "acx mem map"); ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); if (ret < 0) return ret; return 0; }
void wl1251_elp_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1251 *wl; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1251, elp_work); wl1251_debug(DEBUG_PSM, "elp work"); mutex_lock(&wl->mutex); if (wl->elp || !wl->psm) goto out; wl1251_debug(DEBUG_PSM, "chip to elp"); wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); wl->elp = true; out: mutex_unlock(&wl->mutex); }
static struct net_device *ifname_to_netdev(struct net *net, struct genl_info *info) { char *ifname; if (!info->attrs[WL1251_NL_ATTR_IFNAME]) return NULL; ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]); wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname); return dev_get_by_name(net, ifname); }
static int wl1251_op_start(struct ieee80211_hw *hw) { struct wl1251 *wl = hw->priv; struct wiphy *wiphy = hw->wiphy; int ret = 0; wl1251_debug(DEBUG_MAC80211, "mac80211 start"); mutex_lock(&wl->mutex); if (wl->state != WL1251_STATE_OFF) { wl1251_error("cannot start because not in off state: %d", wl->state); ret = -EBUSY; goto out; } ret = wl1251_chip_wakeup(wl); if (ret < 0) goto out; ret = wl1251_boot(wl); if (ret < 0) goto out; ret = wl1251_hw_init(wl); if (ret < 0) goto out; ret = wl1251_acx_station_id(wl); if (ret < 0) goto out; wl->state = WL1251_STATE_ON; wl1251_info("firmware booted (%s)", wl->fw_ver); /* update hw/fw version info in wiphy struct */ wiphy->hw_version = wl->chip_id; strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version)); out: if (ret < 0) wl1251_power_off(wl); mutex_unlock(&wl->mutex); return ret; }
int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) { int ret; wl1251_debug(DEBUG_ACX, "acx statistics"); ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, sizeof(*stats)); if (ret < 0) { wl1251_warning("acx statistics failed: %d", ret); return -ENOMEM; } return 0; }
int wl1251_acx_data_path_params(struct wl1251 *wl, struct acx_data_path_params_resp *resp) { struct acx_data_path_params *params; int ret; wl1251_debug(DEBUG_ACX, "acx data path params"); params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { ret = -ENOMEM; goto out; } params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; params->tx_complete_threshold = 1; params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, params, sizeof(*params)); if (ret < 0) goto out; /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, resp, sizeof(*resp)); if (ret < 0) { wl1251_warning("failed to read data path parameters: %d", ret); goto out; } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { wl1251_warning("data path parameter acx status failed"); ret = -EIO; goto out; } out: kfree(params); return ret; }
static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) { struct wl1251 *wl; int ret = 0; if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER]) return -EINVAL; if (!info->attrs[WL1251_NL_ATTR_NVS_LEN]) return -EINVAL; wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { wl1251_error("wl1251 not found"); return -EINVAL; } mutex_lock(&wl->mutex); wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]); if (wl->nvs_len % 4) { wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len); ret = -EILSEQ; goto out; } /* If we already have an NVS, we should free it */ kfree(wl->nvs); wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); if (wl->nvs == NULL) { wl1251_error("Can't allocate NVS"); ret = -ENOMEM; goto out; } memcpy(wl->nvs, nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]), wl->nvs_len); wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", wl->nvs_len); out: mutex_unlock(&wl->mutex); return ret; }
int wl1251_acx_mem_cfg(struct wl1251 *wl) { struct wl1251_acx_config_memory *mem_conf; int ret, i; wl1251_debug(DEBUG_ACX, "acx mem cfg"); mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); if (!mem_conf) { ret = -ENOMEM; goto out; } /* memory config */ mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); mem_conf->mem_config.rx_mem_block_num = 35; mem_conf->mem_config.tx_min_mem_block_num = 64; mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; mem_conf->mem_config.num_ssid_profiles = 1; mem_conf->mem_config.debug_buffer_size = cpu_to_le16(TRACE_BUFFER_MAX_SIZE); /* RX queue config */ mem_conf->rx_queue_config.dma_address = 0; mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; /* TX queue config */ for (i = 0; i < MAX_TX_QUEUES; i++) { mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; mem_conf->tx_queue_config[i].attributes = i; } ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); if (ret < 0) { wl1251_warning("wl1251 mem config failed: %d", ret); goto out; } out: kfree(mem_conf); return ret; }
static int wl1251_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wl1251 *wl = hw->priv; int ret = 0; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_UAPSD | IEEE80211_VIF_SUPPORTS_CQM_RSSI; wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", vif->type, vif->addr); mutex_lock(&wl->mutex); if (wl->vif) { ret = -EBUSY; goto out; } wl->vif = vif; switch (vif->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; break; case NL80211_IFTYPE_ADHOC: wl->bss_type = BSS_TYPE_IBSS; break; default: ret = -EOPNOTSUPP; goto out; } if (!ether_addr_equal_unaligned(wl->mac_addr, vif->addr)) { memcpy(wl->mac_addr, vif->addr, ETH_ALEN); SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); ret = wl1251_acx_station_id(wl); if (ret < 0) goto out; } out: mutex_unlock(&wl->mutex); return ret; }
int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) { struct acx_sleep_auth *auth; int ret; wl1251_debug(DEBUG_ACX, "acx sleep auth"); auth = kzalloc(sizeof(*auth), GFP_KERNEL); if (!auth) return -ENOMEM; auth->sleep_auth = sleep_auth; ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); kfree(auth); return ret; }
int wl1251_acx_station_id(struct wl1251 *wl) { struct acx_dot11_station_id *mac; int ret, i; wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); mac = kzalloc(sizeof(*mac), GFP_KERNEL); if (!mac) return -ENOMEM; for (i = 0; i < ETH_ALEN; i++) mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); kfree(mac); return ret; }
/** * write acx value to firmware * * @wl: wl struct * @id: acx id * @buf: buffer containing acx, including all headers, must work with dma * @len: length of buf */ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) { struct acx_header *acx = buf; int ret; wl1251_debug(DEBUG_CMD, "cmd configure"); acx->id = id; /* payload length, does not include any headers */ acx->len = len - sizeof(*acx); ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); if (ret < 0) { wl1251_warning("CONFIGURE command NOK"); return ret; } return 0; }
int wl1251_acx_cca_threshold(struct wl1251 *wl) { struct acx_energy_detection *detection; int ret; wl1251_debug(DEBUG_ACX, "acx cca threshold"); detection = kzalloc(sizeof(*detection), GFP_KERNEL); if (!detection) return -ENOMEM; detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; detection->tx_energy_detection = 0; ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, detection, sizeof(*detection)); if (ret < 0) wl1251_warning("failed to set cca threshold: %d", ret); kfree(detection); return ret; }
int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len) { struct cmd_read_write_memory *cmd; int ret = 0; wl1251_debug(DEBUG_CMD, "cmd read memory"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } WARN_ON(len > MAX_READ_SIZE); len = min_t(size_t, len, MAX_READ_SIZE); cmd->addr = addr; cmd->size = len; ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); if (ret < 0) { wl1251_error("read memory command failed: %d", ret); goto out; } /* the read command got in, we can now read the answer */ wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); if (cmd->header.status != CMD_STATUS_SUCCESS) wl1251_error("error in read command result: %d", cmd->header.status); memcpy(answer, cmd->value, len); out: kfree(cmd); return ret; }
int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) { struct acx_preamble *acx; int ret; wl1251_debug(DEBUG_ACX, "acx_set_preamble"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; acx->preamble = preamble; ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); if (ret < 0) { wl1251_warning("Setting of preamble failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl1251_acx_aid(struct wl1251 *wl, u16 aid) { struct acx_aid *acx_aid; int ret; wl1251_debug(DEBUG_ACX, "acx aid"); acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); if (!acx_aid) return -ENOMEM; acx_aid->aid = aid; ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); if (ret < 0) { wl1251_warning("failed to set aid: %d", ret); goto out; } out: kfree(acx_aid); return ret; }
int wl1251_acx_sg_enable(struct wl1251 *wl) { struct acx_bt_wlan_coex *pta; int ret; wl1251_debug(DEBUG_ACX, "acx sg enable"); pta = kzalloc(sizeof(*pta), GFP_KERNEL); if (!pta) return -ENOMEM; pta->enable = SG_ENABLE; ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); if (ret < 0) { wl1251_warning("failed to set softgemini enable: %d", ret); goto out; } out: kfree(pta); return ret; }