blob: b3584b6af470511c3b983c8fa858352fc577624b [file] [log] [blame]
/**
* @file mlan_cmdevt.c
*
* @brief This file contains the handling of CMD/EVENT in MLAN
*
*
* Copyright (C) 2009, Marvell International Ltd.
* All Rights Reserved
*
*/
/*************************************************************
Change Log:
05/12/2009: initial version
************************************************************/
#include "mlan.h"
#include "mlan_join.h"
#include "mlan_util.h"
#include "mlan_fw.h"
#include "mlan_main.h"
#include "mlan_wmm.h"
#include "mlan_11n.h"
#include "mlan_11h.h"
#include "mlan_sdio.h"
/********************************************************
Local Variables
********************************************************/
/*******************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
/**
* @brief This function initializes the command node.
*
* @param pmpriv A pointer to mlan_private structure
* @param pcmd_node A pointer to cmd_ctrl_node structure
* @param cmd_oid Cmd oid: treated as sub command
* @param pioctl_buf A pointer to MLAN IOCTl Request buffer
* @param pdata_buf A pointer to information buffer
*
* @return N/A
*/
void
wlan_init_cmd_node(IN pmlan_private pmpriv,
IN cmd_ctrl_node * pcmd_node,
IN t_u32 cmd_oid,
IN t_void * pioctl_buf, IN t_void * pdata_buf)
{
t_u8 *head_ptr = MNULL;
ENTER();
if (pcmd_node == MNULL) {
LEAVE();
return;
}
pcmd_node->priv = pmpriv;
pcmd_node->cmd_oid = cmd_oid;
pcmd_node->pioctl_buf = pioctl_buf;
pcmd_node->pdata_buf = pdata_buf;
pcmd_node->cmdbuf = pcmd_node->pmbuf;
/* Make sure head_ptr for cmd buf is Align */
head_ptr = (t_u8 *) ALIGN_ADDR(pcmd_node->cmdbuf->pbuf, HEADER_ALIGNMENT);
pcmd_node->cmdbuf->data_offset =
(t_u32) (head_ptr - pcmd_node->cmdbuf->pbuf);
memset(head_ptr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
/* Prepare mlan_buffer for command sending */
pcmd_node->cmdbuf->buf_type = MLAN_BUF_TYPE_CMD;
pcmd_node->cmdbuf->data_offset += INTF_HEADER_LEN;
LEAVE();
}
/**
* @brief This function gets a free command node if available in
* command free queue.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or MNULL
*/
cmd_ctrl_node *
wlan_get_cmd_node(mlan_adapter * pmadapter)
{
cmd_ctrl_node *pcmd_node;
ENTER();
if (pmadapter == MNULL) {
LEAVE();
return MNULL;
}
if (util_peek_list(&pmadapter->cmd_free_q,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock)) {
pcmd_node = (cmd_ctrl_node *) util_dequeue_list(&pmadapter->cmd_free_q,
pmadapter->callbacks.
moal_spin_lock,
pmadapter->callbacks.
moal_spin_unlock);
} else {
PRINTM(MERROR, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
pcmd_node = MNULL;
}
LEAVE();
return pcmd_node;
}
/**
* @brief This function cleans command node.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pcmd_node A pointer to cmd_ctrl_node structure
*
* @return N/A
*/
t_void
wlan_clean_cmd_node(pmlan_adapter pmadapter, cmd_ctrl_node * pcmd_node)
{
ENTER();
if (pcmd_node == MNULL) {
LEAVE();
return;
}
pcmd_node->cmd_oid = 0;
pcmd_node->cmd_flag = 0;
pcmd_node->pioctl_buf = MNULL;
pcmd_node->pdata_buf = MNULL;
if (pcmd_node->respbuf) {
pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
pcmd_node->respbuf, 0,
MLAN_STATUS_SUCCESS);
pcmd_node->respbuf = MNULL;
}
LEAVE();
return;
}
/**
* @brief This function will return the pointer to the first entry in
* pending cmd which matches the given pioctl_req
*
* @param pmadapter A pointer to mlan_adapter
* @param pioctl_req A pointer to mlan_ioctl_req buf
*
* @return A pointer to first entry match pioctl_req
*/
cmd_ctrl_node *
wlan_get_pending_ioctl_cmd(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
{
cmd_ctrl_node *pcmd_node = MNULL;
ENTER();
if (!
(pcmd_node =
(cmd_ctrl_node *) util_peek_list(&pmadapter->cmd_pending_q,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.
moal_spin_unlock))) {
LEAVE();
return MNULL;
}
while (pcmd_node != (cmd_ctrl_node *) & pmadapter->cmd_pending_q) {
if (pcmd_node->pioctl_buf == pioctl_req) {
LEAVE();
return pcmd_node;
}
pcmd_node = pcmd_node->pnext;
}
LEAVE();
return MNULL;
}
/**
* @brief This function handles the command response of host_cmd
*
* @param pmpriv A pointer to mlan_private structure
* @param resp A pointer to HostCmd_DS_COMMAND
* @param pioctl_buf A pointer to mlan_ioctl_req structure
*
* @return MLAN_STATUS_SUCCESS
*/
static mlan_status
wlan_ret_host_cmd(IN pmlan_private pmpriv,
IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
{
mlan_ds_misc_cfg *misc;
t_u16 size = wlan_le16_to_cpu(resp->size);
ENTER();
PRINTM(MINFO, "host command response size = %d\n", size);
size = MIN(size, MRVDRV_SIZE_OF_CMD_BUFFER);
if (pioctl_buf) {
misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
misc->param.hostcmd.len = size;
memcpy(misc->param.hostcmd.cmd, (void *) resp, size);
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function sends host command to firmware.
*
* @param pmpriv A pointer to mlan_private structure
* @param cmd A pointer to HostCmd_DS_COMMAND structure
* @param pdata_buf A pointer to data buffer
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
wlan_cmd_host_cmd(IN pmlan_private pmpriv,
IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
{
mlan_ds_misc_cmd *pcmd_ptr = (mlan_ds_misc_cmd *) pdata_buf;
ENTER();
/* Copy the HOST command to command buffer */
memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len);
PRINTM(MCMND, "Host command size = %d\n", pcmd_ptr->len);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function downloads a command to firmware.
*
* @param pmpriv A pointer to mlan_private structure
* @param pcmd_node A pointer to cmd_ctrl_node structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
{
mlan_adapter *pmadapter = pmpriv->adapter;
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
mlan_status ret = MLAN_STATUS_SUCCESS;
HostCmd_DS_COMMAND *pcmd;
mlan_ioctl_req *pioctl_buf = MNULL;
t_u16 cmd_code;
t_u16 cmd_size;
t_u32 sec, usec;
ENTER();
if (!pmadapter || !pcmd_node) {
ret = MLAN_STATUS_FAILURE;
goto done;
}
pcmd =
(HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
pcmd_node->cmdbuf->data_offset);
if (pcmd_node->pioctl_buf != MNULL)
pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
/* Sanity test */
if (pcmd == MNULL || pcmd->size == 0) {
PRINTM(MERROR, "DNLD_CMD: pcmd is null or command size is zero, "
"Not sending\n");
if (pioctl_buf != MNULL)
pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL,
wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Set command sequence number */
pmadapter->seq_num++;
pcmd->seq_num = wlan_cpu_to_le16(pmadapter->seq_num);
wlan_request_cmd_lock(pmadapter);
pmadapter->curr_cmd = pcmd_node;
wlan_release_cmd_lock(pmadapter);
cmd_code = wlan_le16_to_cpu(pcmd->command);
cmd_size = wlan_le16_to_cpu(pcmd->size);
/* Set BSS_NO_BITS to HostCmd */
cmd_code = HostCmd_SET_BSS_NO(cmd_code, pcmd_node->priv->bss_num);
pcmd->command = wlan_cpu_to_le16(cmd_code);
pcmd_node->cmdbuf->data_len = cmd_size;
pmadapter->callbacks.moal_get_system_time(&sec, &usec);
PRINTM(MCMND, "DNLD_CMD (%lu.%lu): 0x%x, act 0x%x, len %d, seqno %d\n",
sec, usec, cmd_code,
wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN)), cmd_size,
wlan_le16_to_cpu(pcmd->seq_num));
DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *) pcmd, cmd_size);
/* Send the command to lower layer */
pcmd_node->cmdbuf->data_offset -= INTF_HEADER_LEN;
pcmd_node->cmdbuf->data_len += INTF_HEADER_LEN;
/* Extra header for SDIO is added here */
ret =
wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD, pcmd_node->cmdbuf,
MNULL);
if (ret == MLAN_STATUS_FAILURE) {
PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n");
if (pioctl_buf != MNULL)
pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL,
wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
wlan_request_cmd_lock(pmadapter);
pmadapter->curr_cmd = MNULL;
wlan_release_cmd_lock(pmadapter);
pmadapter->dbg.num_cmd_host_to_card_failure++;
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Save the last command id and action to debug log */
pmadapter->dbg.last_cmd_index =
(pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code;
pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] =
wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN));
/* Clear BSS_NO_BITS from HostCmd */
cmd_code &= HostCmd_CMD_ID_MASK;
/* Setup the timer after transmit command */
pcb->moal_start_timer(pmadapter->pmlan_cmd_timer, MFALSE, MRVDRV_TIMER_10S);
pmadapter->cmd_timer_is_set = MTRUE;
ret = MLAN_STATUS_SUCCESS;
done:
LEAVE();
return ret;
}
/**
* @brief This function sends sleep confirm command to firmware.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
wlan_dnld_sleep_confirm_cmd(mlan_adapter * pmadapter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
static t_u32 i = 0;
t_u16 cmd_len = 0;
HostCmd_DS_802_11_PS_MODE_ENH *pps_mode = MNULL;
opt_sleep_confirm_buffer *sleep_cfm_buf =
(opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
pmadapter->psleep_cfm->data_offset);
ENTER();
cmd_len = sizeof(HostCmd_DS_COMMAND);
pps_mode = &sleep_cfm_buf->ps_cfm_sleep.params.psmode_enh;
sleep_cfm_buf->ps_cfm_sleep.seq_num =
wlan_cpu_to_le16(++pmadapter->seq_num);
pps_mode->params.sleep_cfm.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep, cmd_len);
/* Send sleep confirm command to firmware */
pmadapter->psleep_cfm->data_len = cmd_len + INTF_HEADER_LEN;
ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD,
pmadapter->psleep_cfm, MNULL);
if (ret == MLAN_STATUS_FAILURE) {
PRINTM(MERROR, "SLEEP_CFM: failed\n");
pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
goto done;
} else {
if ((wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY))->bss_type ==
MLAN_BSS_TYPE_STA) {
if (!pps_mode->params.sleep_cfm.resp_ctrl) {
/* Response is not needed for sleep confirm command */
pmadapter->ps_state = PS_STATE_SLEEP;
} else {
pmadapter->ps_state = PS_STATE_SLEEP_CFM;
}
if (pps_mode->params.sleep_cfm.resp_ctrl != RESP_NEEDED
&& (pmadapter->is_hs_configured &&
!pmadapter->sleep_period.period)) {
pmadapter->pm_wakeup_card_req = MTRUE;
wlan_host_sleep_activated_event(wlan_get_priv
(pmadapter, MLAN_BSS_TYPE_STA),
MTRUE);
}
}
#define NUM_SC_PER_LINE 16
if (++i % NUM_SC_PER_LINE == 0)
PRINTM(MEVENT, "+\n");
else
PRINTM(MEVENT, "+");
}
done:
LEAVE();
return ret;
}
/********************************************************
Global Functions
********************************************************/
/**
* @brief Event handler
*
* @param priv A pointer to mlan_private structure
* @param event_id Event ID
* @param pmevent Event buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
wlan_recv_event(pmlan_private priv, mlan_event_id event_id, t_void * pmevent)
{
pmlan_callbacks pcb = &priv->adapter->callbacks;
ENTER();
if (pmevent)
/* The caller has provided the event. */
pcb->moal_recv_event(priv->adapter->pmoal_handle,
(pmlan_event) pmevent);
else {
mlan_event mevent;
memset(&mevent, 0, sizeof(mlan_event));
mevent.bss_num = priv->bss_num;
mevent.event_id = event_id;
mevent.event_len = 0;
pcb->moal_recv_event(priv->adapter->pmoal_handle, &mevent);
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function allocates the command buffer and links
* it to command free queue.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
wlan_alloc_cmd_buffer(IN mlan_adapter * pmadapter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
cmd_ctrl_node *pcmd_array;
t_u32 buf_size;
t_u32 i;
ENTER();
/* Allocate and initialize cmd_ctrl_node */
buf_size = sizeof(cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
ret = pcb->moal_malloc(buf_size, (t_u8 **) & pcmd_array);
if (ret != MLAN_STATUS_SUCCESS || !pcmd_array) {
PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate pcmd_array\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
pmadapter->cmd_pool = pcmd_array;
memset(pmadapter->cmd_pool, 0, buf_size);
/* Allocate and initialize command buffers */
for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
if (!
(pcmd_array[i].pmbuf =
wlan_alloc_mlan_buffer(pcb,
(MRVDRV_SIZE_OF_CMD_BUFFER +
HEADER_ALIGNMENT)))) {
PRINTM(MERROR, "ALLOC_CMD_BUF: pcmd_buf: out of memory\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
}
for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
wlan_insert_cmd_to_free_q(pmadapter, &pcmd_array[i]);
}
ret = MLAN_STATUS_SUCCESS;
done:
LEAVE();
return ret;
}
/**
* @brief This function frees the command buffer.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
wlan_free_cmd_buffer(IN mlan_adapter * pmadapter)
{
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
cmd_ctrl_node *pcmd_array;
t_u32 i;
ENTER();
/* Need to check if cmd pool is allocated or not */
if (pmadapter->cmd_pool == MNULL) {
PRINTM(MINFO, "FREE_CMD_BUF: cmd_pool is Null\n");
goto done;
}
pcmd_array = pmadapter->cmd_pool;
/* Release shared memory buffers */
for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
if (pcmd_array[i].pmbuf) {
PRINTM(MCMND, "Free all the command buffer.\n");
wlan_free_mlan_buffer(pcb, pcmd_array[i].pmbuf);
pcmd_array[i].pmbuf = MNULL;
}
if (pcmd_array[i].respbuf) {
pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
pcmd_array[i].respbuf, 0,
MLAN_STATUS_SUCCESS);
pcmd_array[i].respbuf = MNULL;
}
}
/* Release cmd_ctrl_node */
if (pmadapter->cmd_pool) {
PRINTM(MCMND, "Free command pool.\n");
pcb->moal_mfree((t_u8 *) pmadapter->cmd_pool);
pmadapter->cmd_pool = MNULL;
}
done:
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function handles events generated by firmware
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
wlan_process_event(pmlan_adapter pmadapter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
t_u32 eventcause = pmadapter->event_cause;
t_u32 bss_num = 0;
t_u32 in_ts_sec;
t_u32 in_ts_usec;
ENTER();
/* Save the last event to debug log */
pmadapter->dbg.last_event_index =
(pmadapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
pmadapter->dbg.last_event[pmadapter->dbg.last_event_index] =
(t_u16) eventcause;
/* Get BSS number and corresponding priv */
bss_num = EVENT_GET_BSS_NUM((t_u16) eventcause);
priv = pmadapter->priv[bss_num];
if (!priv) {
bss_num = 0;
priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
}
/* Clear BSS_NO_BITS from event */
eventcause &= EVENT_ID_MASK;
if (pmbuf)
pmbuf->bss_num = bss_num;
if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) {
pmadapter->callbacks.moal_get_system_time(&in_ts_sec, &in_ts_usec);
PRINTM(MEVENT, "%lu.%lu : Event: 0x%x\n", in_ts_sec, in_ts_usec,
eventcause);
}
ret = priv->ops.process_event(priv);
pmadapter->event_cause = 0;
pmadapter->pmlan_buffer_event = MNULL;
if (pmbuf) {
pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
0, MLAN_STATUS_SUCCESS);
}
LEAVE();
return ret;
}
/**
* @brief This function requests a lock on command queue.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return N/A
*/
t_void
wlan_request_cmd_lock(IN mlan_adapter * pmadapter)
{
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
ENTER();
/* Call MOAL spin lock callback function */
pcb->moal_spin_lock(pmadapter->pmlan_cmd_lock);
LEAVE();
return;
}
/**
* @brief This function releases a lock on command queue.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return N/A
*/
t_void
wlan_release_cmd_lock(IN mlan_adapter * pmadapter)
{
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
ENTER();
/* Call MOAL spin unlock callback function */
pcb->moal_spin_unlock(pmadapter->pmlan_cmd_lock);
LEAVE();
return;
}
/**
* @brief This function prepare the command before sending to firmware.
*
* @param pmpriv A pointer to mlan_private structure
* @param cmd_no Command number
* @param cmd_action Command action: GET or SET
* @param cmd_oid Cmd oid: treated as sub command
* @param pioctl_buf A pointer to MLAN IOCTl Request buffer
* @param pdata_buf A pointer to information buffer
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
wlan_prepare_cmd(IN mlan_private * pmpriv,
IN t_u16 cmd_no,
IN t_u16 cmd_action,
IN t_u32 cmd_oid,
IN t_void * pioctl_buf, IN t_void * pdata_buf)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = pmpriv->adapter;
cmd_ctrl_node *pcmd_node = MNULL;
HostCmd_DS_COMMAND *cmd_ptr = MNULL;
ENTER();
/* Sanity test */
if (pmadapter == MNULL) {
PRINTM(MERROR, "PREP_CMD: pmadapter is MNULL\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (pmadapter->surprise_removed) {
PRINTM(MERROR, "PREP_CMD: Card is Removed\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (pmadapter->hw_status == WlanHardwareStatusReset) {
if (cmd_no != HostCmd_CMD_FUNC_INIT) {
PRINTM(MERROR, "PREP_CMD: FW is in reset state\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
}
/* Get a new command node */
pcmd_node = wlan_get_cmd_node(pmadapter);
if (pcmd_node == MNULL) {
PRINTM(MERROR, "PREP_CMD: No free cmd node\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Initialize the command node */
wlan_init_cmd_node(pmpriv, pcmd_node, cmd_oid, pioctl_buf, pdata_buf);
if (pcmd_node->cmdbuf == MNULL) {
PRINTM(MERROR, "PREP_CMD: No free cmd buf\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
cmd_ptr =
(HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
pcmd_node->cmdbuf->data_offset);
cmd_ptr->command = cmd_no;
cmd_ptr->result = 0;
/* Prepare command */
if (cmd_no)
ret =
pmpriv->ops.prepare_cmd(pmpriv, cmd_no, cmd_action, cmd_oid,
pioctl_buf, pdata_buf, cmd_ptr);
else {
ret = wlan_cmd_host_cmd(pmpriv, cmd_ptr, pdata_buf);
pcmd_node->cmd_flag |= CMD_F_HOSTCMD;
}
/* Return error, since the command preparation failed */
if (ret != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no);
wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Send command */
if (cmd_no == HostCmd_CMD_802_11_SCAN)
wlan_queue_scan_cmd(pmpriv, pcmd_node);
else
wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
done:
LEAVE();
return ret;
}
/**
* @brief This function inserts command node to cmd_free_q
* after cleaning it.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pcmd_node A pointer to cmd_ctrl_node structure
*
* @return N/A
*/
t_void
wlan_insert_cmd_to_free_q(IN mlan_adapter * pmadapter,
IN cmd_ctrl_node * pcmd_node)
{
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
mlan_ioctl_req *pioctl_req = MNULL;
ENTER();
if (pcmd_node == MNULL)
goto done;
if (pcmd_node->pioctl_buf) {
pioctl_req = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
if (pioctl_req->status_code != MLAN_ERROR_NO_ERROR)
pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
pioctl_req, MLAN_STATUS_FAILURE);
else
pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
pioctl_req, MLAN_STATUS_SUCCESS);
}
/* Clean the node */
wlan_clean_cmd_node(pmadapter, pcmd_node);
/* Insert node into cmd_free_q */
util_enqueue_list_tail(&pmadapter->cmd_free_q,
(pmlan_linked_list) pcmd_node,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
done:
LEAVE();
}
/**
* @brief This function queues the command to cmd list.
*
* @param pmadapter A pointer to mlan_adapter structure
* @param pcmd_node A pointer to cmd_ctrl_node structure
* @param add_tail Specify if the cmd needs to be queued in the header or tail
*
* @return N/A
*/
t_void
wlan_insert_cmd_to_pending_q(IN mlan_adapter * pmadapter,
IN cmd_ctrl_node * pcmd_node, IN t_u32 add_tail)
{
HostCmd_DS_COMMAND *pcmd = MNULL;
t_u16 command;
ENTER();
if (pcmd_node == MNULL) {
PRINTM(MERROR, "QUEUE_CMD: pcmd_node is MNULL\n");
goto done;
}
pcmd =
(HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
pcmd_node->cmdbuf->data_offset);
if (pcmd == MNULL) {
PRINTM(MERROR, "QUEUE_CMD: pcmd is MNULL\n");
goto done;
}
command = wlan_le16_to_cpu(pcmd->command);
/* Exit_PS command needs to be queued in the header always. */
if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
HostCmd_DS_802_11_PS_MODE_ENH *pm = &pcmd->params.psmode_enh;
if (wlan_le16_to_cpu(pm->action) == DIS_PS) {
if (pmadapter->ps_state != PS_STATE_AWAKE)
add_tail = MFALSE;
}
}
if (add_tail) {
util_enqueue_list_tail(&pmadapter->cmd_pending_q,
(pmlan_linked_list) pcmd_node,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
} else {
util_enqueue_list_head(&pmadapter->cmd_pending_q,
(pmlan_linked_list) pcmd_node,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
}
PRINTM(MCMND, "QUEUE_CMD: cmd=0x%x is queued\n", command);
done:
LEAVE();
return;
}
/**
* @brief This function executes next command in command
* pending queue. It will put firmware back to PS mode
* if applicable.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
wlan_exec_next_cmd(mlan_adapter * pmadapter)
{
mlan_private *priv = MNULL;
cmd_ctrl_node *pcmd_node = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
HostCmd_DS_COMMAND *pcmd;
ENTER();
/* Sanity test */
if (pmadapter == MNULL) {
PRINTM(MERROR, "EXEC_NEXT_CMD: pmadapter is MNULL\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Check if already in processing */
if (pmadapter->curr_cmd) {
PRINTM(MERROR, "EXEC_NEXT_CMD: there is command in processing!\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
wlan_request_cmd_lock(pmadapter);
/* Check if any command is pending */
pcmd_node = (cmd_ctrl_node *) util_peek_list(&pmadapter->cmd_pending_q,
pmadapter->callbacks.
moal_spin_lock,
pmadapter->callbacks.
moal_spin_unlock);
if (pcmd_node) {
pcmd =
(HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
pcmd_node->cmdbuf->data_offset);
priv = pcmd_node->priv;
if (pmadapter->ps_state != PS_STATE_AWAKE) {
PRINTM(MERROR,
"Cannot send command in sleep state, this should not happen\n");
wlan_release_cmd_lock(pmadapter);
goto done;
}
util_unlink_list(&pmadapter->cmd_pending_q,
(pmlan_linked_list) pcmd_node,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
wlan_release_cmd_lock(pmadapter);
ret = wlan_dnld_cmd_to_fw(priv, pcmd_node);
priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
/* Any command sent to the firmware when host is in sleep mode, should
de-configure host sleep */
/* We should skip the host sleep configuration command itself though */
if (priv &&
(pcmd->command !=
wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
if (pmadapter->hs_activated == MTRUE) {
pmadapter->is_hs_configured = MFALSE;
wlan_host_sleep_activated_event(priv, MFALSE);
}
}
goto done;
} else {
wlan_release_cmd_lock(pmadapter);
}
ret = MLAN_STATUS_SUCCESS;
done:
LEAVE();
return ret;
}
/**
* @brief This function handles the command response
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
wlan_process_cmdresp(mlan_adapter * pmadapter)
{
HostCmd_DS_COMMAND *resp = MNULL;
mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
mlan_status ret = MLAN_STATUS_SUCCESS;
t_u16 orig_cmdresp_no;
t_u16 cmdresp_no;
t_u16 cmdresp_result;
mlan_ioctl_req *pioctl_buf = MNULL;
mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
t_u32 sec, usec;
ENTER();
/* Now we got response from FW, cancel the command timer */
if (pmadapter->cmd_timer_is_set) {
/* Cancel command timeout timer */
pcb->moal_stop_timer(pmadapter->pmlan_cmd_timer);
/* Cancel command timeout timer */
pmadapter->cmd_timer_is_set = MFALSE;
}
if (!pmadapter->curr_cmd || !pmadapter->curr_cmd->respbuf) {
resp = (HostCmd_DS_COMMAND *) pmadapter->upld_buf;
resp->command = wlan_le16_to_cpu(resp->command);
PRINTM(MERROR, "CMD_RESP: MNULL curr_cmd, 0x%x\n", resp->command);
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (pmadapter->curr_cmd->pioctl_buf != MNULL) {
pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
}
pmadapter->num_cmd_timeout = 0;
DBG_HEXDUMP(MCMD_D, "CMD_RESP",
pmadapter->curr_cmd->respbuf->pbuf +
pmadapter->curr_cmd->respbuf->data_offset, pmadapter->upld_len);
resp =
(HostCmd_DS_COMMAND *) (pmadapter->curr_cmd->respbuf->pbuf +
pmadapter->curr_cmd->respbuf->data_offset);
if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
/* Copy original response back to response buffer */
wlan_ret_host_cmd(pmpriv, resp, pioctl_buf);
}
resp->command = wlan_le16_to_cpu(resp->command);
resp->size = wlan_le16_to_cpu(resp->size);
resp->seq_num = wlan_le16_to_cpu(resp->seq_num);
resp->result = wlan_le16_to_cpu(resp->result);
orig_cmdresp_no = resp->command;
cmdresp_result = resp->result;
/* Save the last command response to debug log */
pmadapter->dbg.last_cmd_resp_index =
(pmadapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] =
orig_cmdresp_no;
pmadapter->callbacks.moal_get_system_time(&sec, &usec);
PRINTM(MCMND, "CMD_RESP (%lu.%lu): 0x%x, result %d, len %d, seqno %d\n",
sec, usec, orig_cmdresp_no, cmdresp_result, resp->size,
resp->seq_num);
if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
PRINTM(MERROR, "CMD_RESP: Invalid response to command!");
if (pioctl_buf) {
pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
}
wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
wlan_request_cmd_lock(pmadapter);
pmadapter->curr_cmd = MNULL;
wlan_release_cmd_lock(pmadapter);
ret = MLAN_STATUS_FAILURE;
goto done;
}
/* Get BSS number and corresponding priv */
pmpriv = pmadapter->priv[HostCmd_GET_BSS_NO(resp->command)];
if (!pmpriv)
pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
/* Clear RET_BIT & BSS_NO_BITS from HostCmd */
resp->command &= HostCmd_CMD_ID_MASK;
cmdresp_no = resp->command;
if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
if ((cmdresp_result == HostCmd_RESULT_OK)
&& (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
} else {
/* handle response */
ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp, pioctl_buf);
}
if ((pmadapter->hw_status == WlanHardwareStatusInitializing) &&
(pmadapter->last_init_cmd == cmdresp_no)) {
if (cmdresp_result == HostCmd_RESULT_OK)
pmadapter->hw_status = WlanHardwareStatusInitdone;
else
wlan_init_fw_complete(pmadapter);
}
if (pmadapter->curr_cmd) {
pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
if (pioctl_buf && (ret == MLAN_STATUS_SUCCESS))
pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
/* Clean up and put current command back to cmd_free_q */
wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
wlan_request_cmd_lock(pmadapter);
pmadapter->curr_cmd = MNULL;
wlan_release_cmd_lock(pmadapter);
}
done:
LEAVE();
return ret;
}
/**
* @brief This function handles the timeout of command sending.
* It will re-send the same command again.
*
* @param function_context A pointer to function_context
* @return n/a
*/
t_void
wlan_cmd_timeout_func(t_void * function_context)
{
mlan_adapter *pmadapter = (mlan_adapter *) function_context;
cmd_ctrl_node *pcmd_node = MNULL;
mlan_ioctl_req *pioctl_buf = MNULL;
t_u32 sec, usec;
t_u8 i;
ENTER();
pmadapter->cmd_timer_is_set = MFALSE;
pmadapter->num_cmd_timeout++;
pmadapter->dbg.num_cmd_timeout++;
if (!pmadapter->curr_cmd) {
PRINTM(MWARN, "CurCmd Empty\n");
goto exit;
}
pcmd_node = pmadapter->curr_cmd;
if (pcmd_node->pioctl_buf != MNULL) {
pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
pioctl_buf->status_code = MLAN_ERROR_CMD_TIMEOUT;
}
if (pcmd_node) {
pmadapter->dbg.timeout_cmd_id =
pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index];
pmadapter->dbg.timeout_cmd_act =
pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index];
pmadapter->callbacks.moal_get_system_time(&sec, &usec);
PRINTM(MERROR, "Timeout cmd id (%lu.%lu) = 0x%x, act = 0x%x \n", sec,
usec, pmadapter->dbg.timeout_cmd_id,
pmadapter->dbg.timeout_cmd_act);
PRINTM(MERROR, "num_data_h2c_failure = %d\n",
pmadapter->dbg.num_tx_host_to_card_failure);
PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
pmadapter->dbg.num_cmd_host_to_card_failure);
PRINTM(MERROR, "num_cmd_timeout = %d\n",
pmadapter->dbg.num_cmd_timeout);
PRINTM(MERROR, "num_tx_timeout = %d\n", pmadapter->dbg.num_tx_timeout);
PRINTM(MERROR, "last_cmd_index = %d\n", pmadapter->dbg.last_cmd_index);
PRINTM(MERROR, "last_cmd_id = ");
for (i = 0; i < DBG_CMD_NUM; i++) {
PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_id[i]);
}
PRINTM(MMSG, "\n");
PRINTM(MERROR, "last_cmd_act = ");
for (i = 0; i < DBG_CMD_NUM; i++) {
PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_act[i]);
}
PRINTM(MMSG, "\n");
PRINTM(MERROR, "last_cmd_resp_index = %d\n",
pmadapter->dbg.last_cmd_resp_index);
PRINTM(MERROR, "last_cmd_resp_id = ");
for (i = 0; i < DBG_CMD_NUM; i++) {
PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_resp_id[i]);
}
PRINTM(MMSG, "\n");
PRINTM(MERROR, "last_event_index = %d\n",
pmadapter->dbg.last_event_index);
PRINTM(MERROR, "last_event = ");
for (i = 0; i < DBG_CMD_NUM; i++) {
PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_event[i]);
}
PRINTM(MMSG, "\n");
PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", pmadapter->data_sent,
pmadapter->cmd_sent);
PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", pmadapter->ps_mode,
pmadapter->ps_state);
}
if (pmadapter->hw_status == WlanHardwareStatusInitializing)
wlan_init_fw_complete(pmadapter);
exit:
LEAVE();
return;
}
/**
* @brief Cancel all pending cmd.
*
* @param pmadapter A pointer to mlan_adapter
*
* @return N/A
*/
void
wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter)
{
cmd_ctrl_node *pcmd_node = MNULL;
pmlan_callbacks pcb = &pmadapter->callbacks;
mlan_ioctl_req *pioctl_buf = MNULL;
/* Cancel current cmd */
if ((pmadapter->curr_cmd) && (pmadapter->curr_cmd->pioctl_buf)) {
pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
wlan_request_cmd_lock(pmadapter);
pmadapter->curr_cmd->pioctl_buf = MNULL;
wlan_release_cmd_lock(pmadapter);
pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
MLAN_STATUS_FAILURE);
}
/* Cancel all pending command */
while ((pcmd_node =
(cmd_ctrl_node *) util_peek_list(&pmadapter->cmd_pending_q,
pcb->moal_spin_lock,
pcb->moal_spin_unlock))) {
util_unlink_list(&pmadapter->cmd_pending_q,
(pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
pcb->moal_spin_unlock);
if (pcmd_node->pioctl_buf) {
pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
MLAN_STATUS_FAILURE);
pcmd_node->pioctl_buf = MNULL;
}
wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
}
/* Cancel all pending scan command */
while ((pcmd_node =
(cmd_ctrl_node *) util_peek_list(&pmadapter->scan_pending_q,
pcb->moal_spin_lock,
pcb->moal_spin_unlock))) {
util_unlink_list(&pmadapter->scan_pending_q,
(pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
pcb->moal_spin_unlock);
pcmd_node->pioctl_buf = MNULL;
wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
}
wlan_request_cmd_lock(pmadapter);
pmadapter->scan_processing = MFALSE;
wlan_release_cmd_lock(pmadapter);
}
/**
* @brief Cancel pending ioctl cmd.
*
* @param pmadapter A pointer to mlan_adapter
* @param pioctl_req A pointer to mlan_ioctl_req buf
*
* @return N/A
*/
void
wlan_cancel_pending_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
{
pmlan_callbacks pcb = &pmadapter->callbacks;
cmd_ctrl_node *pcmd_node = MNULL;
ENTER();
PRINTM(MCMND, "MOAL Cancel IOCTL: 0x%x sub_id=0x%x action=%d\n",
pioctl_req->req_id, *((t_u32 *) pioctl_req->pbuf),
(int) pioctl_req->action);
if ((pmadapter->curr_cmd) &&
(pmadapter->curr_cmd->pioctl_buf == pioctl_req)) {
wlan_request_cmd_lock(pmadapter);
pcmd_node = pmadapter->curr_cmd;
pcmd_node->pioctl_buf = MNULL;
wlan_release_cmd_lock(pmadapter);
}
wlan_request_cmd_lock(pmadapter);
while ((pcmd_node =
wlan_get_pending_ioctl_cmd(pmadapter, pioctl_req)) != MNULL) {
util_unlink_list(&pmadapter->cmd_pending_q,
(pmlan_linked_list) pcmd_node,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
pcmd_node->pioctl_buf = MNULL;
wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
}
wlan_release_cmd_lock(pmadapter);
if (pioctl_req->req_id == MLAN_IOCTL_SCAN) {
/* Cancel all pending scan command */
while ((pcmd_node =
(cmd_ctrl_node *) util_peek_list(&pmadapter->scan_pending_q,
pcb->moal_spin_lock,
pcb->moal_spin_unlock))) {
util_unlink_list(&pmadapter->scan_pending_q,
(pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
pcb->moal_spin_unlock);
pcmd_node->pioctl_buf = MNULL;
wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
}
wlan_request_cmd_lock(pmadapter);
pmadapter->scan_processing = MFALSE;
wlan_release_cmd_lock(pmadapter);
}
pioctl_req->status_code = MLAN_ERROR_CMD_CANCEL;
pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req,
MLAN_STATUS_FAILURE);
LEAVE();
return;
}
/**
* @brief This function checks conditions and prepares to
* send sleep confirm command to firmware if OK.
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return N/A
*/
t_void
wlan_check_ps_cond(mlan_adapter * pmadapter)
{
ENTER();
if (!pmadapter->cmd_sent &&
!pmadapter->curr_cmd && !IS_CARD_RX_RCVD(pmadapter)) {
wlan_dnld_sleep_confirm_cmd(pmadapter);
} else {
PRINTM(MCMND, "Delay Sleep Confirm (%s%s%s)\n",
(pmadapter->cmd_sent) ? "D" : "",
(pmadapter->curr_cmd) ? "C" : "",
(IS_CARD_RX_RCVD(pmadapter)) ? "R" : "");
}
LEAVE();
}
/**
* @brief This function sends the HS_ACTIVATED event to the application
*
* @param priv A pointer to mlan_private structure
* @param activated MTRUE if activated, MFALSE if de-activated
*
* @return None
*/
t_void
wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated)
{
ENTER();
if (activated) {
if (priv->adapter->is_hs_configured) {
priv->adapter->hs_activated = MTRUE;
PRINTM(MEVENT, "hs_actived\n");
wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_ACTIVATED, MNULL);
} else
PRINTM(MWARN, "hs_activated: HS not configured !!!\n");
} else {
PRINTM(MEVENT, "hs_deactived\n");
priv->adapter->hs_activated = MFALSE;
wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_DEACTIVATED, MNULL);
}
LEAVE();
}
/**
* @brief This function sends the HS_WAKEUP event to the application
*
* @param priv A pointer to mlan_private structure
*
* @return None
*/
t_void
wlan_host_sleep_wakeup_event(pmlan_private priv)
{
ENTER();
if (priv->adapter->is_hs_configured) {
wlan_recv_event(priv, MLAN_EVENT_ID_FW_HS_WAKEUP, MNULL);
} else {
PRINTM(MWARN, "hs_wakeup: Host Sleep not configured !!!\n");
}
LEAVE();
}
/**
* @brief This function handles the command response of hs_cfg
*
* @param pmpriv A pointer to mlan_private structure
* @param resp A pointer to HostCmd_DS_COMMAND
* @param pioctl_buf A pointer to mlan_ioctl_req structure
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
wlan_ret_802_11_hs_cfg(IN pmlan_private pmpriv,
IN HostCmd_DS_COMMAND * resp,
IN mlan_ioctl_req * pioctl_buf)
{
pmlan_adapter pmadapter = pmpriv->adapter;
HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &resp->params.opt_hs_cfg;
ENTER();
if (phs_cfg->action == HS_ACTIVATE) {
wlan_host_sleep_activated_event(pmpriv, MTRUE);
goto done;
} else {
phs_cfg->params.hs_config.conditions =
wlan_le32_to_cpu(phs_cfg->params.hs_config.conditions);
PRINTM(MCMND,
"CMD_RESP: HS_CFG cmd reply result=%#x,"
" conditions=0x%x gpio=0x%x gap=0x%x\n", resp->result,
phs_cfg->params.hs_config.conditions,
phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
}
if (phs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL) {
pmadapter->is_hs_configured = MTRUE;
} else {
pmadapter->is_hs_configured = MFALSE;
if (pmadapter->hs_activated)
wlan_host_sleep_activated_event(pmpriv, MFALSE);
}
done:
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief Perform hs related activities on receving the power up interrupt
*
* @param pmadapter A pointer to the adapter structure
* @return N/A
*/
t_void
wlan_process_hs_config(pmlan_adapter pmadapter)
{
PRINTM(MINFO,
"Auto Cancelling host sleep since there is some interrupt from the firmware\n");
wlan_pm_wakeup_card(pmadapter);
pmadapter->hs_activated = MFALSE;
pmadapter->is_hs_configured = MFALSE;
wlan_host_sleep_activated_event(wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY),
MFALSE);
return;
}
/**
* @brief Check sleep confirm command response and set the state to ASLEEP
*
* @param pmadapter A pointer to the adapter structure
* @param pbuf A pointer to the command response buffer
* @param upld_len Command response buffer length
* @return N/A
*/
void
wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 * pbuf,
t_u32 upld_len)
{
HostCmd_DS_COMMAND *cmd;
pmlan_private pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
ENTER();
if (!upld_len) {
PRINTM(MERROR, "Command size is 0\n");
LEAVE();
return;
}
cmd = (HostCmd_DS_COMMAND *) pbuf;
cmd->result = wlan_le16_to_cpu(cmd->result);
cmd->command = wlan_le16_to_cpu(cmd->command);
/* Get BSS number and corresponding priv */
pmpriv = pmadapter->priv[HostCmd_GET_BSS_NO(cmd->command)];
if (!pmpriv)
pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
/* Clear RET_BIT & BSS_NO_BITS from HostCmd */
cmd->command &= HostCmd_CMD_ID_MASK;
if (cmd->command != HostCmd_CMD_802_11_PS_MODE_ENH) {
PRINTM(MERROR,
"Received unexpected response for command %x, result = %x\n",
cmd->command, cmd->result);
return;
}
PRINTM(MEVENT, "#\n");
if ((pmpriv->media_connected != MTRUE) || !pmadapter->sleep_period.period)
pmadapter->pm_wakeup_card_req = MTRUE;
if (cmd->result != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "Sleep confirm command failed\n");
LEAVE();
return;
}
if (pmadapter->is_hs_configured && !pmadapter->sleep_period.period) {
wlan_host_sleep_activated_event(wlan_get_priv
(pmadapter, MLAN_BSS_TYPE_ANY), MTRUE);
}
pmadapter->ps_state = PS_STATE_SLEEP;
LEAVE();
}