Commit fa147b26 authored by Shrirang Bagul's avatar Shrirang Bagul Committed by Luis Henriques

UBUNTU: SAUCE: Support Redpine RS9113 WLAN/BT

BugLink: http://bugs.launchpad.net/bugs/1657682

This patch adds support for RS9113 WLAN-BT cards found on Dell Caracalla
IoT gateways.
Vendor release: RS9113.NB0.NL.GNU.LNX.0.9.3 on 12/01/2016
Signed-off-by: default avatarShrirang Bagul <shrirang.bagul@canonical.com>
Acked-by: default avatarTim Gardner <tim.gardner@canonical.com>
Acked-by: default avatarBrad Figg <brad.figg@canonical.com>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 44f542ad
......@@ -22,6 +22,7 @@ source "ubuntu/hio/Kconfig"
##
##
##
source "ubuntu/rsi/Kconfig"
##
##
##
......
......@@ -36,6 +36,9 @@ endif
##
##
##
obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/
##
##
##
##
##
......
config WLAN_VENDOR_RSI
bool "Redpine Signals Inc devices"
depends on X86 || X86_64
default y
---help---
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_RSI
config RSI_91X
tristate "Redpine Signals Inc 91x WLAN driver support"
depends on MAC80211
---help---
This option enabes support for RSI 1x1 devices.
Select M (recommended), if you have a RSI 1x1 wireless module.
config RSI_DEBUGFS
bool "Redpine Signals Inc debug support"
depends on RSI_91X
default y
---help---
Say Y, if you would like to enable debug support. This option
creates debugfs entries
config RSI_SDIO
tristate "Redpine Signals SDIO bus support"
depends on MMC && RSI_91X
default m
---help---
This option enables the SDIO bus support in rsi drivers.
Select M (recommended), if you have a RSI 1x1 wireless module.
config RSI_USB
tristate "Redpine Signals USB bus support"
depends on USB && RSI_91X
default m
---help---
This option enables the USB bus support in rsi drivers.
Select M (recommended), if you have a RSI 1x1 wireless module.
config RSI_HCI
tristate "Redpine Signals HCI support"
depends on RSI_91X
default m
---help---
This option enables the HCI support in rsi drivers for BT apps.
Select M (recommended), if you have a RSI 1x1 wireless module.
endif # WLAN_VENDOR_RSI
rsi_91x-y += rsi_91x_main.o
rsi_91x-y += rsi_91x_core.o
rsi_91x-y += rsi_91x_mac80211.o
rsi_91x-y += rsi_91x_mgmt.o
rsi_91x-y += rsi_91x_hal.o
rsi_91x-y += rsi_91x_ps.o
rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o
rsi_91x-$(CONFIG_RSI_HCI) += rsi_91x_hci.o
rsi_91x-$(CONFIG_RSI_COEX) += rsi_91x_coex.o
rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o
rsi_sdio-y += rsi_91x_sdio.o rsi_91x_sdio_ops.o
obj-$(CONFIG_RSI_91X) += rsi_91x.o
obj-$(CONFIG_RSI_SDIO) += rsi_sdio.o
obj-$(CONFIG_RSI_USB) += rsi_usb.o
/**
* Copyright (c) 2014 Redpine Signals Inc.
*
* Developer:
* Prameela Rani Ganrepudi <prameela.garnepudi@redpinesignals.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//#include "rsi_common.h"
#include "rsi_main.h"
#include "rsi_coex.h"
#include"rsi_hal.h"
static u8 rsi_coex_determine_coex_q(struct rsi_coex_ctrl_block *coex_cb)
{
u8 q_num = INVALID_QUEUE;
if (skb_queue_len(&coex_cb->coex_tx_qs[VIP_Q]) > 0)
q_num = VIP_Q;
if (skb_queue_len(&coex_cb->coex_tx_qs[COEX_Q]) > 0)
q_num = COEX_Q;
if (skb_queue_len(&coex_cb->coex_tx_qs[BT_Q]) > 0)
q_num = BT_Q;
if (skb_queue_len(&coex_cb->coex_tx_qs[ZIGB_Q]) > 0)
q_num = ZIGB_Q;
if (skb_queue_len(&coex_cb->coex_tx_qs[WLAN_Q]) > 0)
q_num = WLAN_Q;
return q_num;
}
static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
{
u8 coex_q;
struct sk_buff *skb;
while (1) {
coex_q = rsi_coex_determine_coex_q(coex_cb);
rsi_dbg(INFO_ZONE, "queue = %d\n", coex_q);
if (coex_q == INVALID_QUEUE) {
rsi_dbg(DATA_TX_ZONE, "No more pkt\n");
break;
}
mutex_lock(&coex_cb->coex_tx_lock);
if (coex_q == BT_Q) {
skb = skb_dequeue(&coex_cb->coex_tx_qs[BT_Q]);
rsi_send_bt_pkt(coex_cb->priv, skb);
}
mutex_unlock(&coex_cb->coex_tx_lock);
}
}
/**
* rsi_coex_scheduler_thread() - This function is a kernel thread to schedule
* the coex packets to device
* @common: Pointer to the driver private structure.
*
* Return: None.
*/
static void rsi_coex_scheduler_thread(struct rsi_coex_ctrl_block *coex_cb)
{
struct rsi_common *common = (struct rsi_common *)coex_cb->priv;
u32 timeout = EVENT_WAIT_FOREVER;
do {
rsi_wait_event(&coex_cb->coex_tx_thread.event, timeout);
rsi_reset_event(&coex_cb->coex_tx_thread.event);
rsi_coex_sched_tx_pkts(coex_cb);
} while (atomic_read(&coex_cb->coex_tx_thread.thread_done) == 0);
complete_and_exit(&coex_cb->coex_tx_thread.completion, 0);
}
int rsi_coex_recv_pkt(struct rsi_common *common, struct sk_buff *skb)
{
return 0;
}
int rsi_coex_send_pkt(struct rsi_common *common,
struct sk_buff *skb,
u8 hal_queue)
{
struct rsi_coex_ctrl_block *coex_cb = common->coex_cb;
int status = 0;
/* Add pkt to queue if not WLAN packet */
if (hal_queue != RSI_WLAN_Q) {
skb_queue_tail(&coex_cb->coex_tx_qs[hal_queue], skb);
rsi_set_event(&coex_cb->coex_tx_thread.event);
return status;
}
mutex_lock(&coex_cb->coex_tx_lock);
/* Send packet to hal */
status = rsi_send_data_pkt(common, skb);
mutex_unlock(&coex_cb->coex_tx_lock);
return 0;
}
int rsi_coex_init(struct rsi_common *common)
{
struct rsi_coex_ctrl_block *coex_cb = NULL;
int cnt;
coex_cb = kzalloc(sizeof(*coex_cb), GFP_KERNEL);
if (!coex_cb) {
rsi_dbg(ERR_ZONE,
"%s: Failed allocate coex control block\n",
__func__);
return -ENOMEM;
}
common->coex_cb = (void *)coex_cb;
/* Initialize co-ex queues */
for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
skb_queue_head_init(&coex_cb->coex_tx_qs[cnt]);
mutex_init(&coex_cb->coex_tx_lock);
/* Initialize co-ex thread */
if (rsi_create_kthread(common,
&coex_cb->coex_tx_thread,
rsi_coex_scheduler_thread,
"Coex-Tx-Thread")) {
rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
goto err;
}
return 0;
err:
return -1;
}
void rsi_coex_deinit(struct rsi_common *common)
{
int cnt;
struct rsi_coex_ctrl_block *coex_cb =
(struct rsi_coex_ctrl_block *)common->coex_cb;
/* Stop the coex tx thread */
rsi_kill_thread(&coex_cb->coex_tx_thread);
/* Empty the coex queue */
for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
skb_queue_purge(&coex_cb->coex_tx_qs[cnt]);
/* Free the coex control block */
kfree(coex_cb);
return;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/**
* Copyright (c) 2014 Redpine Signals Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/firmware.h>
#include "rsi_mgmt.h"
#include "rsi_common.h"
#include "rsi_hal.h"
#ifdef CONFIG_RSI_HCI
#include "rsi_hci.h"
#endif
#ifdef CONFIG_RSI_COEX
#include "rsi_coex.h"
#endif
u32 rsi_zone_enabled = //INFO_ZONE |
INIT_ZONE |
//MGMT_TX_ZONE |
//MGMT_RX_ZONE |
//DATA_TX_ZONE |
//DATA_RX_ZONE |
//FSM_ZONE |
//ISR_ZONE |
ERR_ZONE |
0;
EXPORT_SYMBOL_GPL(rsi_zone_enabled);
/**
* rsi_dbg() - This function outputs informational messages.
* @zone: Zone of interest for output message.
* @fmt: printf-style format for output message.
*
* Return: none
*/
void rsi_dbg(u32 zone, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (zone & rsi_zone_enabled)
pr_info("%pV", &vaf);
va_end(args);
}
EXPORT_SYMBOL_GPL(rsi_dbg);
/**
* rsi_hex_dump() - This function prints the packet (/msg) in hex bytes.
* @zone: Zone of interest for output message.
* @msg_str: Message to be printed with packet
* @msg: Packet to be printed
* @len: Length of the packet
*
* Return: none
*/
void rsi_hex_dump(u32 zone, char *msg_str, const u8 *msg, u32 len)
{
int ii;
if (!(zone & rsi_zone_enabled))
return;
printk("%s: (length = %d)\n", msg_str, len);
for (ii = 0; ii < len; ii++) {
if (!(ii % 16))
printk("\n");
printk("%02x ", msg[ii]);
}
printk("\n");
}
EXPORT_SYMBOL_GPL(rsi_hex_dump);
/**
* rsi_prepare_skb() - This function prepares the skb.
* @common: Pointer to the driver private structure.
* @buffer: Pointer to the packet data.
* @pkt_len: Length of the packet.
* @extended_desc: Extended descriptor.
*
* Return: Successfully skb.
*/
static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
u8 *buffer,
u32 pkt_len,
u8 extended_desc)
{
struct ieee80211_tx_info *info;
struct skb_info *rx_params;
struct sk_buff *skb = NULL;
u8 payload_offset;
if (WARN(!pkt_len, "%s: Dummy pkt received", __func__))
return NULL;
if (pkt_len > (RSI_RCV_BUFFER_LEN * 4)) {
rsi_dbg(ERR_ZONE, "%s: Pkt size > max rx buf size %d\n",
__func__, pkt_len);
pkt_len = RSI_RCV_BUFFER_LEN * 4;
}
pkt_len -= extended_desc;
skb = dev_alloc_skb(pkt_len + FRAME_DESC_SZ);
if (!skb)
return NULL;
payload_offset = (extended_desc + FRAME_DESC_SZ);
skb_put(skb, pkt_len);
memcpy((skb->data), (buffer + payload_offset), skb->len);
info = IEEE80211_SKB_CB(skb);
rx_params = (struct skb_info *)info->driver_data;
rx_params->rssi = rsi_get_rssi(buffer);
rx_params->channel = rsi_get_connected_channel(common->priv);
return skb;
}
/**
* rsi_read_pkt() - This function reads frames from the card.
* @common: Pointer to the driver private structure.
* @rcv_pkt_len: Received pkt length. In case of USB it is 0.
*
* Return: 0 on success, -1 on failure.
*/
int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
{
u8 *frame_desc = NULL, extended_desc = 0;
u32 index = 0, length = 0, queueno = 0;
u16 actual_length = 0, offset;
struct sk_buff *skb = NULL;
do {
frame_desc = &rx_pkt[index];
actual_length = *(u16 *)&frame_desc[0];
offset = *(u16 *)&frame_desc[2];
if ((actual_length < (4 + FRAME_DESC_SZ)) || (offset < 4)) {
rsi_dbg(ERR_ZONE,
"%s: actual_length (%d) is less than 20 or"
" offset(%d) is less than 4\n",
__func__, actual_length, offset);
break;
}
queueno = rsi_get_queueno(frame_desc, offset);
length = rsi_get_length(frame_desc, offset);
if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q)
extended_desc = rsi_get_extended_desc(frame_desc,
offset);
switch (queueno) {
case RSI_COEX_Q:
rsi_hex_dump(MGMT_RX_ZONE,
"RX Command packet",
frame_desc + offset,
FRAME_DESC_SZ + length);
rsi_mgmt_pkt_recv(common, (frame_desc + offset));
break;
case RSI_WIFI_DATA_Q:
rsi_hex_dump(DATA_RX_ZONE,
"RX Data pkt",
frame_desc + offset,
FRAME_DESC_SZ + length);
skb = rsi_prepare_skb(common,
(frame_desc + offset),
length,
extended_desc);
if (!skb)
goto fail;
rsi_indicate_pkt_to_os(common, skb);
break;
case RSI_WIFI_MGMT_Q:
rsi_mgmt_pkt_recv(common, (frame_desc + offset));
break;
#ifdef CONFIG_RSI_HCI
case RSI_BT_MGMT_Q:
case RSI_BT_DATA_Q:
rsi_hex_dump(DATA_RX_ZONE,
"RX BT Pkt",
frame_desc + offset,
FRAME_DESC_SZ + length);
rsi_hci_recv_pkt(common, frame_desc + offset);
break;
#endif
default:
rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
__func__, queueno);
goto fail;
}
index += actual_length;
rcv_pkt_len -= actual_length;
} while (rcv_pkt_len > 0);
return 0;
fail:
return -EINVAL;
}
EXPORT_SYMBOL_GPL(rsi_read_pkt);
/**
* rsi_tx_scheduler_thread() - This function is a kernel thread to send the
* packets to the device.
* @common: Pointer to the driver private structure.
*
* Return: None.
*/
static void rsi_tx_scheduler_thread(struct rsi_common *common)
{
struct rsi_hw *adapter = common->priv;
u32 timeout = EVENT_WAIT_FOREVER;
do {
if (adapter->determine_event_timeout)
timeout = adapter->determine_event_timeout(adapter);
rsi_wait_event(&common->tx_thread.event, timeout);
rsi_reset_event(&common->tx_thread.event);
if (common->init_done)
rsi_core_qos_processor(common);
} while (atomic_read(&common->tx_thread.thread_done) == 0);
complete_and_exit(&common->tx_thread.completion, 0);
}
/**
* rsi_91x_init() - This function initializes os interface operations.
* @void: Void.
*
* Return: Pointer to the adapter structure on success, NULL on failure .
*/
struct rsi_hw *rsi_91x_init(void)
{
struct rsi_hw *adapter = NULL;
struct rsi_common *common = NULL;
u8 ii = 0;
adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
if (!adapter)
return NULL;
adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
if (!adapter->priv) {
rsi_dbg(ERR_ZONE, "%s: Failed in allocation of priv\n",
__func__);
kfree(adapter);
return NULL;
}
common = adapter->priv;
common->priv = adapter;
for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
skb_queue_head_init(&common->tx_queue[ii]);
rsi_init_event(&common->tx_thread.event);
mutex_init(&common->mutex);
mutex_init(&common->tx_lock);
mutex_init(&common->rx_lock);
if (rsi_create_kthread(common,
&common->tx_thread,
rsi_tx_scheduler_thread,
"Tx-Thread")) {
rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
goto err;
}
rsi_default_ps_params(adapter);
spin_lock_init(&adapter->ps_lock);
common->uapsd_bitmap = 0;
init_bgscan_params(common);
common->init_done = true;
return adapter;
err:
kfree(common);
kfree(adapter);
return NULL;
}
EXPORT_SYMBOL_GPL(rsi_91x_init);
/**
* rsi_91x_deinit() - This function de-intializes os intf operations.
* @adapter: Pointer to the adapter structure.
*
* Return: None.
*/
void rsi_91x_deinit(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;
u8 ii;
rsi_dbg(INFO_ZONE, "%s: Deinit core module...\n", __func__);
rsi_kill_thread(&common->tx_thread);
for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
skb_queue_purge(&common->tx_queue[ii]);
common->init_done = false;
kfree(common);
kfree(adapter->rsi_dev);
kfree(adapter);
}
EXPORT_SYMBOL_GPL(rsi_91x_deinit);
/**
* rsi_91x_hal_module_init() - This function is invoked when the module is
* loaded into the kernel.
* It registers the client driver.
* @void: Void.
*
* Return: 0 on success, -1 on failure.
*/
static int rsi_91x_hal_module_init(void)
{
rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
return 0;
}
/**
* rsi_91x_hal_module_exit() - This function is called at the time of
* removing/unloading the module.
* It unregisters the client driver.
* @void: Void.
*
* Return: None.
*/
static void rsi_91x_hal_module_exit(void)
{
rsi_dbg(INIT_ZONE, "%s: Module exit called\n", __func__);
}
module_init(rsi_91x_hal_module_init);
module_exit(rsi_91x_hal_module_exit);
MODULE_AUTHOR("Redpine Signals Inc");
MODULE_DESCRIPTION("Station driver for RSI 91x devices");
MODULE_SUPPORTED_DEVICE("RSI-91x");
MODULE_VERSION("0.1");
MODULE_LICENSE("Dual BSD/GPL");
This diff is collapsed.
/**
* Copyright (c) 2014 Redpine Signals Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/etherdevice.h>
#include <linux/if.h>
#include <linux/version.h>
#include "rsi_debugfs.h"
#include "rsi_mgmt.h"
#include "rsi_common.h"
#include "rsi_ps.h"
/**
* str_psstate() - return the ps state in string format.
*
* @state - PS state.
*
* return: PS state in string format.
*/
char *str_psstate(enum ps_state state)
{
switch (state) {
case PS_NONE:
return "PS_NONE";
case PS_DISABLE_REQ_SENT:
return "PS_DISABLE_REQ_SENT";
case PS_ENABLE_REQ_SENT:
return "PS_ENABLE_REQ_SENT";
case PS_ENABLED:
return "PS_ENABLED";
default:
return "INVALID_STATE";
}
return "INVALID_STATE";
}
/**
* rsi_modify_ps_state() - Modify PS state to a new state.
*
* @adapter: pointer to rsi_hw structure.
* @nstate: new PS state.
*
* return: new state.
*/
static inline void rsi_modify_ps_state(struct rsi_hw *adapter,
enum ps_state nstate)
{
rsi_dbg(INFO_ZONE, "PS state changed %s => %s\n",
str_psstate(adapter->ps_state),
str_psstate(nstate));
adapter->ps_state = nstate;
}
/**
* rsi_default_ps_params() - Initalization of default powersave parameters.
*
* @adapter: pointer to rsi_hw structure.
*
* return: void.
*/
void rsi_default_ps_params(struct rsi_hw *adapter)
{
struct rsi_ps_info *ps_info = &adapter->ps_info;
ps_info->enabled = true;
ps_info->sleep_type = 1; /* LP */
ps_info->tx_threshold = 0;
ps_info->rx_threshold = 0;
ps_info->tx_hysterisis = 0;
ps_info->rx_hysterisis = 0;
ps_info->monitor_interval = 0;
ps_info->listen_interval = 2 * 100;
ps_info->num_bcns_per_lis_int = 0;
ps_info->dtim_interval_duration = 0;
ps_info->num_dtims_per_sleep = 0;
ps_info->deep_sleep_wakeup_period = 100;
}
EXPORT_SYMBOL_GPL(rsi_default_ps_params);
/**
* rsi_enable_ps() - enable power save
*
* @adapter: Pointer to rsi_hw structure.
*
* return: void.
*/
void rsi_enable_ps(struct rsi_hw *adapter)
{
if (adapter->ps_state != PS_NONE) {
rsi_dbg(ERR_ZONE,
"%s: Cannot accept enable PS in %s state\n",
__func__, str_psstate(adapter->ps_state));
return;
}
if (rsi_send_ps_request(adapter, true)) {
rsi_dbg(ERR_ZONE,
"%s: Failed to send PS request to device\n",
__func__);
return;
}
rsi_modify_ps_state(adapter, PS_ENABLE_REQ_SENT);
}
/**
* rsi_disable_ps() - disable power save
*
* @adapter: Pointer to rsi_hw structure.
*
* return: void.
*/
void rsi_disable_ps(struct rsi_hw *adapter)
{
if (adapter->ps_state != PS_ENABLED) {
rsi_dbg(ERR_ZONE,
"%s: Cannot accept disable PS in %s state\n",
__func__, str_psstate(adapter->ps_state));
return;
}
if (rsi_send_ps_request(adapter, false)) {
rsi_dbg(ERR_ZONE,
"%s: Failed to send PS request to device\n",
__func__);
return;
}
rsi_modify_ps_state(adapter, PS_DISABLE_REQ_SENT);
}
/**
* rsi_conf_uapsd() - configures UAPSD powersave.
*
* @adapter - Pointer to rsi_hw structure.
*
* return: void.
*/
void rsi_conf_uapsd(struct rsi_hw *adapter)
{
if (adapter->ps_state != PS_ENABLED)
return;
if (rsi_send_ps_request(adapter, false)) {
rsi_dbg(ERR_ZONE,
"%s: Failed to send PS request to device\n",
__func__);
return;
}
if (rsi_send_ps_request(adapter, true)) {
rsi_dbg(ERR_ZONE,
"%s: Failed to send PS request to device\n",
__func__);
}
}
/**
* rsi_handle_ps_confirm() - Processes powersave confirmation.
*
* @adapter - Pointer to rsi_hw structure.
* @msg - Recevied buffer.
*
* return: 0 on success.
*/
int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg)
{
u16 cfm_type = 0;
cfm_type = *(u16 *)&msg[PS_CONFIRM_INDEX];
switch (cfm_type) {
case SLEEP_REQUEST:
if (adapter->ps_state == PS_ENABLE_REQ_SENT)
rsi_modify_ps_state(adapter, PS_ENABLED);
break;
case WAKEUP_REQUEST:
if (adapter->ps_state == PS_DISABLE_REQ_SENT)
rsi_modify_ps_state(adapter, PS_NONE);
break;
default:
rsi_dbg(ERR_ZONE,
"Invalid PS confirm type %x in state %s\n",
cfm_type, str_psstate(adapter->ps_state));
return -1;
}
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment