962 lines
28 KiB
C
962 lines
28 KiB
C
|
/*
|
||
|
* ETF interfaces for XRadio drivers
|
||
|
*
|
||
|
* Copyright (c) 2013
|
||
|
* Xradio Technology Co., Ltd. <www.xradiotech.com>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 as
|
||
|
* published by the Free Software Foundation.
|
||
|
*/
|
||
|
|
||
|
#ifndef XRADIO_ETF_C
|
||
|
#define XRADIO_ETF_C
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/init.h>
|
||
|
#include <linux/vmalloc.h>
|
||
|
#include <linux/netlink.h>
|
||
|
#include <net/sock.h>
|
||
|
#include <linux/kthread.h>
|
||
|
#include <linux/wait.h>
|
||
|
#include <linux/firmware.h>
|
||
|
|
||
|
#include "etf.h"
|
||
|
#include "xradio.h"
|
||
|
#include "sbus.h"
|
||
|
#include "debug.h"
|
||
|
|
||
|
/********************* interfaces of adapter layer **********************/
|
||
|
static struct xradio_adapter adapter_priv;
|
||
|
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
static void adapter_rec_handler(struct sk_buff *__skb)
|
||
|
{
|
||
|
int i = 0;
|
||
|
struct adapter_item *item;
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
|
||
|
do {
|
||
|
spin_lock_bh(&adapter_priv.recv_lock);
|
||
|
if (likely(!list_empty(&adapter_priv.rx_pool))) {
|
||
|
item = list_first_entry(&adapter_priv.rx_pool, struct adapter_item, head);
|
||
|
item->skb = (void *)skb_get(__skb);
|
||
|
list_move_tail(&item->head, &adapter_priv.rx_queue);
|
||
|
spin_unlock_bh(&adapter_priv.recv_lock);
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s recv msg to rx_queue!\n", __func__);
|
||
|
break;
|
||
|
} else if (++i > ETF_QUEUE_TIMEOUT) { /* about 2s.*/
|
||
|
spin_unlock_bh(&adapter_priv.recv_lock);
|
||
|
etf_printk(XRADIO_DBG_ERROR,
|
||
|
"%s driver is process timeout, drop msg!\n", __func__);
|
||
|
return;
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_NIY,
|
||
|
"%s rx_pool is empty, wait %d!ms\n", __func__, i);
|
||
|
}
|
||
|
spin_unlock_bh(&adapter_priv.recv_lock);
|
||
|
msleep(i);
|
||
|
} while (1);
|
||
|
|
||
|
if (atomic_add_return(1, &adapter_priv.rx_cnt) == 1)
|
||
|
up(&adapter_priv.proc_sem);
|
||
|
return;
|
||
|
}
|
||
|
#else
|
||
|
static void adapter_rec_handler(struct sk_buff *skb)
|
||
|
{
|
||
|
struct nlmsghdr *nlhdr = (struct nlmsghdr *)skb->data;
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
|
||
|
if (nlhdr->nlmsg_len < sizeof(struct nlmsghdr)) {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "Corrupt netlink msg!\n");
|
||
|
} else {
|
||
|
int len = nlhdr->nlmsg_len - NLMSG_LENGTH(0);
|
||
|
adapter_priv.send_pid = nlhdr->nlmsg_pid;
|
||
|
adapter_priv.msg_len = min(ADAPTER_RX_BUF_LEN, len);
|
||
|
memcpy(adapter_priv.msg_buf, NLMSG_DATA(nlhdr), adapter_priv.msg_len);
|
||
|
if (len != adapter_priv.msg_len)
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s recv len(%d), proc len=%d!\n",
|
||
|
__func__, len, adapter_priv.msg_len);
|
||
|
else
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s recv msg len(%d)!\n",
|
||
|
__func__, adapter_priv.msg_len);
|
||
|
if (adapter_priv.handler)
|
||
|
adapter_priv.handler(adapter_priv.msg_buf, adapter_priv.msg_len);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static int adapter_init_msgbuf(void)
|
||
|
{
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
int i = 0;
|
||
|
#endif
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s\n", __func__);
|
||
|
if (adapter_priv.msg_buf) {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s msgbuf already init!\n", __func__);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
atomic_set(&adapter_priv.rx_cnt, 0);
|
||
|
INIT_LIST_HEAD(&adapter_priv.rx_queue);
|
||
|
INIT_LIST_HEAD(&adapter_priv.rx_pool);
|
||
|
for (i = 0; i < ADAPTER_ITEM_MAX; i++)
|
||
|
list_add_tail(&adapter_priv.rx_items[i].head, &adapter_priv.rx_pool);
|
||
|
#endif
|
||
|
|
||
|
adapter_priv.msg_buf = xr_kzalloc(ADAPTER_RX_BUF_LEN, false);
|
||
|
if (!adapter_priv.msg_buf)
|
||
|
return -ENOMEM;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void adapter_deinit_msgbuf(void)
|
||
|
{
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
struct adapter_item *item;
|
||
|
#endif
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s\n", __func__);
|
||
|
if (adapter_priv.msg_buf) {
|
||
|
kfree(adapter_priv.msg_buf);
|
||
|
adapter_priv.msg_buf = NULL;
|
||
|
}
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
spin_lock_bh(&adapter_priv.recv_lock);
|
||
|
list_for_each_entry(item, &adapter_priv.rx_queue, head) {
|
||
|
if (item->skb) {
|
||
|
dev_kfree_skb((struct sk_buff *)item->skb);
|
||
|
item->skb = NULL;
|
||
|
}
|
||
|
}
|
||
|
spin_unlock_bh(&adapter_priv.recv_lock);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
static int adapter_handle_rx_queue(void)
|
||
|
{
|
||
|
int len = 0;
|
||
|
struct nlmsghdr *nlhdr = NULL;
|
||
|
struct adapter_item *item;
|
||
|
bool bHandler = false;
|
||
|
while (1) {
|
||
|
spin_lock_bh(&adapter_priv.recv_lock);
|
||
|
if (!list_empty(&adapter_priv.rx_queue)) {
|
||
|
item = list_first_entry(&adapter_priv.rx_queue, struct adapter_item, head);
|
||
|
if (item->skb) {
|
||
|
struct sk_buff *skb = (struct sk_buff *)(item->skb);
|
||
|
nlhdr = (struct nlmsghdr *)skb->data;
|
||
|
if (nlhdr->nlmsg_len < sizeof(struct nlmsghdr)) {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "Corrupt netlink msg!\n");
|
||
|
} else {
|
||
|
len = nlhdr->nlmsg_len - NLMSG_LENGTH(0);
|
||
|
adapter_priv.send_pid = nlhdr->nlmsg_pid;
|
||
|
adapter_priv.msg_len = min(ADAPTER_RX_BUF_LEN, len);
|
||
|
memcpy(adapter_priv.msg_buf, NLMSG_DATA(nlhdr), len);
|
||
|
bHandler = true;
|
||
|
if (len != adapter_priv.msg_len)
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s recv len(%d), proc len=%d!\n",
|
||
|
__func__, len, adapter_priv.msg_len);
|
||
|
else
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s recv msg len(%d)!\n",
|
||
|
__func__, adapter_priv.msg_len);
|
||
|
}
|
||
|
dev_kfree_skb(skb);
|
||
|
item->skb = NULL;
|
||
|
list_move_tail(&item->head, &adapter_priv.rx_pool);
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s skb is NULL!\n", __func__);
|
||
|
}
|
||
|
} else {
|
||
|
spin_unlock_bh(&adapter_priv.recv_lock);
|
||
|
break;
|
||
|
}
|
||
|
spin_unlock_bh(&adapter_priv.recv_lock);
|
||
|
if (bHandler && adapter_priv.handler) {
|
||
|
adapter_priv.handler(adapter_priv.msg_buf, adapter_priv.msg_len);
|
||
|
bHandler = false;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int adapter_proc(void *param)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
int term = 0;
|
||
|
int recv = 0;
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s\n", __func__);
|
||
|
for (;;) {
|
||
|
ret = down_interruptible(&adapter_priv.proc_sem);
|
||
|
recv = atomic_xchg(&adapter_priv.rx_cnt, 0);
|
||
|
term = kthread_should_stop();
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s term=%d!\n", __func__, term);
|
||
|
if (term || adapter_priv.exit || ret < 0) {
|
||
|
break;
|
||
|
}
|
||
|
if (recv) {
|
||
|
adapter_handle_rx_queue();
|
||
|
}
|
||
|
}
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s: exit!\n", __func__);
|
||
|
return 0;
|
||
|
}
|
||
|
static int adapter_start_thread(void)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct sched_param param = {.sched_priority = 100 };
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s\n", __func__);
|
||
|
adapter_priv.thread_tsk = NULL;
|
||
|
adapter_priv.exit = 0;
|
||
|
adapter_priv.thread_tsk = kthread_create(&adapter_proc, NULL, XRADIO_ADAPTER);
|
||
|
if (IS_ERR(adapter_priv.thread_tsk)) {
|
||
|
ret = PTR_ERR(adapter_priv.thread_tsk);
|
||
|
adapter_priv.thread_tsk = NULL;
|
||
|
} else {
|
||
|
sched_setscheduler(adapter_priv.thread_tsk, SCHED_NORMAL, ¶m);
|
||
|
wake_up_process(adapter_priv.thread_tsk);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
static void adapter_stop_thread(void)
|
||
|
{
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s\n", __func__);
|
||
|
if (adapter_priv.thread_tsk != NULL) {
|
||
|
adapter_priv.exit = 1;
|
||
|
up(&adapter_priv.proc_sem);
|
||
|
kthread_stop(adapter_priv.thread_tsk);
|
||
|
adapter_priv.thread_tsk = NULL;
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s: thread_tsk is NULL!\n", __func__);
|
||
|
}
|
||
|
}
|
||
|
#endif /* ETF_QUEUEMODE */
|
||
|
|
||
|
static int xradio_adapter_send(void *data, int len)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct sk_buff *skb = NULL;
|
||
|
struct nlmsghdr *nlhdr = NULL;
|
||
|
u8 *payload = NULL;
|
||
|
if (0 == len || NULL == data)
|
||
|
return -EINVAL;
|
||
|
|
||
|
skb = xr_alloc_skb(NLMSG_SPACE(len + 1));
|
||
|
if (!skb) {
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s:xr_alloc_skb failed!\n", __func__);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
/* '\0' safe for strcpy, compat for old etf apk, may be removed in furture.*/
|
||
|
nlhdr = nlmsg_put(skb, 0, 0, 0, len + 1, 0); /* (len+1) is payload */
|
||
|
payload = (u8 *)NLMSG_DATA(nlhdr);
|
||
|
memcpy(payload, data, len);
|
||
|
payload[len] = '\0';
|
||
|
|
||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
|
||
|
NETLINK_CB(skb).pid = 0;
|
||
|
#else
|
||
|
NETLINK_CB(skb).portid = 0;
|
||
|
#endif
|
||
|
NETLINK_CB(skb).dst_group = 0;
|
||
|
|
||
|
down(&adapter_priv.send_lock);
|
||
|
ret = netlink_unicast(adapter_priv.sock, skb, adapter_priv.send_pid, 0);
|
||
|
if (ret < 0)
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s:netlink_unicast failed(%d),pid=%d!\n",
|
||
|
__func__, ret, adapter_priv.send_pid);
|
||
|
else
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s:netlink_unicast len(%d),pid=%d!\n",
|
||
|
__func__, ret, adapter_priv.send_pid);
|
||
|
up(&adapter_priv.send_lock);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int xradio_adapter_send_pkg(void *data1, int len1, void *data2, int len2)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct sk_buff *skb = NULL;
|
||
|
struct nlmsghdr *nlhdr = NULL;
|
||
|
u8 *payload = NULL;
|
||
|
int total_len = len1 + len2;
|
||
|
if (len1 <= 0 || len2 < 0 || NULL == data1)
|
||
|
return -EINVAL;
|
||
|
|
||
|
skb = xr_alloc_skb(NLMSG_SPACE(total_len + 1));
|
||
|
if (!skb) {
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s:xr_alloc_skb failed!\n", __func__);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
/* '\0' safe for strcpy, compat for old etf apk, may be removed in furture.*/
|
||
|
nlhdr = nlmsg_put(skb, 0, 0, 0, total_len + 1, 0);
|
||
|
payload = (u8 *)NLMSG_DATA(nlhdr);
|
||
|
memcpy(payload, data1, len1);
|
||
|
if (data2 && len2)
|
||
|
memcpy((payload + len1), data2, len2);
|
||
|
payload[total_len] = '\0';
|
||
|
|
||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
|
||
|
NETLINK_CB(skb).pid = 0;
|
||
|
#else
|
||
|
NETLINK_CB(skb).portid = 0;
|
||
|
#endif
|
||
|
NETLINK_CB(skb).dst_group = 0;
|
||
|
|
||
|
down(&adapter_priv.send_lock);
|
||
|
ret = netlink_unicast(adapter_priv.sock, skb, adapter_priv.send_pid, 0);
|
||
|
if (ret < 0)
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s:netlink_unicast failed(%d),pid=%d!\n",
|
||
|
__func__, ret, adapter_priv.send_pid);
|
||
|
else
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s:netlink_unicast len(%d),pid=%d!\n",
|
||
|
__func__, ret, adapter_priv.send_pid);
|
||
|
up(&adapter_priv.send_lock);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
struct xradio_adapter *xradio_adapter_init(msg_proc func)
|
||
|
{
|
||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
|
||
|
struct netlink_kernel_cfg cfg = {
|
||
|
.input = adapter_rec_handler,
|
||
|
};
|
||
|
#endif
|
||
|
if (func == NULL) {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s msg_proc is NULL\n", __func__);
|
||
|
return NULL;
|
||
|
}
|
||
|
adapter_priv.handler = func;
|
||
|
sema_init(&adapter_priv.send_lock, 1);
|
||
|
if (adapter_init_msgbuf()) {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s adapter_init_msgbuf failed\n", __func__);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
sema_init(&adapter_priv.proc_sem, 0);
|
||
|
if (adapter_start_thread()) {
|
||
|
adapter_deinit_msgbuf();
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s adapter_start_thread failed\n", __func__);
|
||
|
return NULL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
|
||
|
adapter_priv.sock = netlink_kernel_create(&init_net, NL_FOR_XRADIO, 0,
|
||
|
adapter_rec_handler, NULL, THIS_MODULE);
|
||
|
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
|
||
|
adapter_priv.sock = netlink_kernel_create(&init_net, NL_FOR_XRADIO,
|
||
|
THIS_MODULE, &cfg);
|
||
|
#else
|
||
|
adapter_priv.sock = netlink_kernel_create(&init_net, NL_FOR_XRADIO, &cfg);
|
||
|
#endif
|
||
|
|
||
|
if (adapter_priv.sock == NULL) {
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
adapter_stop_thread();
|
||
|
#endif
|
||
|
adapter_deinit_msgbuf();
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s netlink_kernel_create failed\n", __func__);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return &adapter_priv;
|
||
|
}
|
||
|
|
||
|
void xradio_adapter_deinit(void)
|
||
|
{
|
||
|
if (adapter_priv.sock != NULL) {
|
||
|
netlink_kernel_release(adapter_priv.sock);
|
||
|
adapter_priv.sock = NULL;
|
||
|
}
|
||
|
#if (ETF_QUEUEMODE)
|
||
|
adapter_stop_thread();
|
||
|
#endif
|
||
|
adapter_deinit_msgbuf();
|
||
|
}
|
||
|
|
||
|
|
||
|
/********************* interfaces of etf core **********************/
|
||
|
static struct xradio_etf etf_priv;
|
||
|
static struct etf_api_context context_save;
|
||
|
|
||
|
int wsm_etf_cmd(struct xradio_common *hw_priv, struct wsm_hdr *arg);
|
||
|
int xradio_bh_suspend(struct xradio_common *hw_priv);
|
||
|
int xradio_bh_resume(struct xradio_common *hw_priv);
|
||
|
|
||
|
bool etf_is_connect(void)
|
||
|
{
|
||
|
return (bool)(etf_priv.etf_state != ETF_STAT_NULL);
|
||
|
}
|
||
|
|
||
|
void etf_set_core(void *core_priv)
|
||
|
{
|
||
|
etf_priv.core_priv = core_priv;
|
||
|
}
|
||
|
|
||
|
const char *etf_get_fwpath(void)
|
||
|
{
|
||
|
return (const char *)etf_priv.fw_path;
|
||
|
}
|
||
|
|
||
|
const char *etf_get_sddpath(void)
|
||
|
{
|
||
|
return (const char *)etf_priv.sdd_path;
|
||
|
}
|
||
|
|
||
|
static int etf_get_sdd_param(u8 *sdd, int sdd_len, u8 ies, void **data)
|
||
|
{
|
||
|
int ie_len = 0;
|
||
|
int parsedLength = 0;
|
||
|
struct xradio_sdd *pElement = NULL;
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
|
||
|
/*parse SDD config.*/
|
||
|
pElement = (struct xradio_sdd *)sdd;
|
||
|
parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + \
|
||
|
pElement->length);
|
||
|
pElement = FIND_NEXT_ELT(pElement);
|
||
|
|
||
|
while (parsedLength < sdd_len) {
|
||
|
if (pElement->id == ies) {
|
||
|
*data = (void *)pElement->data;
|
||
|
ie_len = pElement->length;
|
||
|
}
|
||
|
parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + \
|
||
|
pElement->length);
|
||
|
pElement = FIND_NEXT_ELT(pElement);
|
||
|
}
|
||
|
|
||
|
xradio_dbg(XRADIO_DBG_MSG, "parse len=%d, ie_len=%d.\n",
|
||
|
parsedLength, ie_len);
|
||
|
return ie_len;
|
||
|
}
|
||
|
|
||
|
static int etf_driver_resp(int state, int result)
|
||
|
{
|
||
|
struct drv_resp drv_ret;
|
||
|
drv_ret.len = sizeof(drv_ret);
|
||
|
drv_ret.id = ETF_DRIVER_IND_ID;
|
||
|
drv_ret.state = state;
|
||
|
drv_ret.result = result;
|
||
|
return xradio_adapter_send(&drv_ret, drv_ret.len);
|
||
|
}
|
||
|
|
||
|
static int xradio_etf_connect(void)
|
||
|
{
|
||
|
int ret = BOOT_SUCCESS;
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
|
||
|
if (etf_priv.etf_state == ETF_STAT_NULL) {
|
||
|
etf_priv.etf_state = ETF_STAT_CONNECTING;
|
||
|
ret = xradio_core_init();
|
||
|
if (ret) {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s:xradio_core_init failed(%d).\n",
|
||
|
__func__, ret);
|
||
|
goto err;
|
||
|
}
|
||
|
etf_priv.etf_state = ETF_STAT_CONNECTED;
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s etf is already connect.\n", __func__);
|
||
|
return ETF_ERR_CONNECTED;
|
||
|
}
|
||
|
etf_printk(XRADIO_DBG_ALWY, "%s:ETF connect success.\n", __func__);
|
||
|
return 0;
|
||
|
|
||
|
err:
|
||
|
etf_priv.etf_state = ETF_STAT_NULL;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void xradio_etf_disconnect(void)
|
||
|
{
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
if (etf_priv.etf_state != ETF_STAT_NULL) {
|
||
|
xradio_core_deinit();
|
||
|
etf_priv.etf_state = ETF_STAT_NULL;
|
||
|
}
|
||
|
etf_printk(XRADIO_DBG_ALWY, "%s end.\n", __func__);
|
||
|
}
|
||
|
|
||
|
#if DGB_XRADIO_HWT
|
||
|
//HWT
|
||
|
extern u8 hwt_testing;
|
||
|
extern u8 hwt_tx_en;
|
||
|
extern u8 hwt_tx_cfm; /*confirm interval*/
|
||
|
extern u16 hwt_tx_len;
|
||
|
extern u16 hwt_tx_num;
|
||
|
|
||
|
extern u8 hwt_rx_en;
|
||
|
extern u16 hwt_rx_len;
|
||
|
extern u16 hwt_rx_num;
|
||
|
extern struct timeval hwt_start_time;
|
||
|
|
||
|
typedef struct HWT_PARAM_ENC_S {
|
||
|
u16 Msglen;
|
||
|
u16 MsgID;
|
||
|
u16 TestID;
|
||
|
u16 Params;
|
||
|
u16 Datalen;
|
||
|
u16 Data[2];
|
||
|
} HWT_PARAMENC;
|
||
|
|
||
|
int wsm_hwt_cmd(struct xradio_common *hw_priv, void *arg, size_t arg_size);
|
||
|
int HWT_Tx_handle(HWT_PARAMETERS *cmd)
|
||
|
{
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s: MsgID=0x%04X, MsgLen=%d, TestID=%d, params=%d, datalen=%d\n", __func__,
|
||
|
cmd->MsgID, cmd->Msglen, cmd->TestID, cmd->Params, cmd->Data);
|
||
|
if (hwt_testing) {
|
||
|
xradio_dbg(XRADIO_DBG_ALWY, "cmd refuse, hwt is testing!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
if (cmd->TestID == 0x1) {
|
||
|
hwt_tx_len = cmd->Data;
|
||
|
hwt_tx_num = cmd->Params;
|
||
|
hwt_tx_cfm = 1;//16; Be sure about the firmware has been using 16 buf when this value is set to 16
|
||
|
hwt_tx_en = 1;
|
||
|
hwt_testing = 1;
|
||
|
|
||
|
xradio_dbg(XRADIO_DBG_ALWY,
|
||
|
"hwt_tx_en=%d, hwt_tx_len=%d, hwt_tx_num=%d, hwt_tx_cfm=%d\n",
|
||
|
hwt_tx_en, hwt_tx_len, hwt_tx_num, hwt_tx_cfm);
|
||
|
|
||
|
if (!((struct xradio_common *)etf_priv.core_priv)->bh_error &&
|
||
|
atomic_add_return(1, &((struct xradio_common *)etf_priv.core_priv)->bh_tx) == 1)
|
||
|
wake_up(&((struct xradio_common *)etf_priv.core_priv)->bh_wq);
|
||
|
} else if (cmd->TestID == 0x2) {
|
||
|
hwt_rx_len = cmd->Data;
|
||
|
hwt_rx_num = cmd->Params;
|
||
|
hwt_rx_en = 1;
|
||
|
hwt_testing = 1;
|
||
|
|
||
|
xradio_dbg(XRADIO_DBG_ALWY,
|
||
|
"hwt_rx_en=%d, hwt_rx_len=%d, hwt_rx_num=%d\n", hwt_rx_en,
|
||
|
hwt_rx_len, hwt_rx_num);
|
||
|
|
||
|
wsm_hwt_cmd((struct xradio_common *)etf_priv.core_priv, (void *)&cmd->TestID, sizeof(HWT_PARAMETERS));
|
||
|
do_gettimeofday(&hwt_start_time);
|
||
|
|
||
|
} else if (cmd->TestID == 0x3) {
|
||
|
xradio_dbg(XRADIO_DBG_ALWY, "pkt_num=%d, pkt_len=%d, enc_data=0x%04X\n",
|
||
|
cmd->Params, ((HWT_PARAMENC *)cmd)->Data[0], ((HWT_PARAMENC *)cmd)->Data[1]);
|
||
|
hwt_testing = 1;
|
||
|
wsm_hwt_cmd((struct xradio_common *)etf_priv.core_priv, (void *)&cmd->TestID, sizeof(HWT_PARAMETERS)+2);
|
||
|
} else if (cmd->TestID == 0x4) {
|
||
|
hwt_testing = 1;
|
||
|
wsm_hwt_cmd((struct xradio_common *)etf_priv.core_priv, (void *)&cmd->TestID, sizeof(HWT_PARAMETERS));
|
||
|
} else {
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
static int xradio_etf_proc(void *data, int len)
|
||
|
{
|
||
|
int ret = BOOT_SUCCESS;
|
||
|
struct wsm_hdr *hdr_rev = (struct wsm_hdr *)data;
|
||
|
struct drv_download *download;
|
||
|
int datalen;
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
|
||
|
down(&etf_priv.etf_lock);
|
||
|
/* Don't process ETF cmd in wlan mode */
|
||
|
if (etf_priv.is_wlan) {
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s is in wlan mode.\n", __func__);
|
||
|
ret = ETF_ERR_WLAN_MODE;
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
/* Process msg from ETF API */
|
||
|
switch (MSG_ID(hdr_rev->id)) {
|
||
|
case ETF_SOFT_RESET_REQ_ID:
|
||
|
etf_printk(XRADIO_DBG_ALWY, "SOFT_RESET\n");
|
||
|
xradio_etf_disconnect();
|
||
|
etf_priv.fw_path = XR829_ETF_FIRMWARE;
|
||
|
etf_priv.sdd_path = XR829_SDD_FILE;
|
||
|
etf_priv.seq_send = 0;
|
||
|
etf_priv.seq_recv = 0;
|
||
|
memset(&context_save, 0, sizeof(context_save));
|
||
|
etf_driver_resp(BOOT_STATE_NULL, BOOT_SUCCESS);
|
||
|
break;
|
||
|
case ETF_GET_API_CONTEXT_ID: /* for ETF tools which cannot save context*/
|
||
|
{
|
||
|
struct etf_api_context_result *ctxt_ret = NULL;
|
||
|
struct xradio_common *hw_priv = etf_priv.core_priv;
|
||
|
ctxt_ret = (struct etf_api_context_result *)hdr_rev;
|
||
|
if (hw_priv) {
|
||
|
ctxt_ret->is_etf_fw_run = hw_priv->wsm_caps.firmwareReady;
|
||
|
memcpy(ctxt_ret->fw_label, hw_priv->wsm_caps.fw_label,
|
||
|
min(HI_SW_LABEL_MAX, WSM_FW_LABEL));
|
||
|
ctxt_ret->fw_api_ver = hw_priv->wsm_caps.firmwareApiVer;
|
||
|
ctxt_ret->mib_baseaddr = context_save.config[1];
|
||
|
} else {
|
||
|
ctxt_ret->is_etf_fw_run = 0;
|
||
|
memset(ctxt_ret->fw_label, 0, HI_SW_LABEL_MAX);
|
||
|
}
|
||
|
ctxt_ret->len = sizeof(*ctxt_ret);
|
||
|
ctxt_ret->id |= ETF_CNF_BASE;
|
||
|
ctxt_ret->result = 0;
|
||
|
xradio_adapter_send(ctxt_ret, sizeof(*ctxt_ret));
|
||
|
}
|
||
|
break;
|
||
|
case ETF_DOWNLOAD_ID:
|
||
|
etf_printk(XRADIO_DBG_NIY, "DOWNLOAD_FW, size=%d\n", hdr_rev->len);
|
||
|
download = (struct drv_download *)(hdr_rev + 1);
|
||
|
datalen = hdr_rev->len - sizeof(*download) - sizeof(*hdr_rev);
|
||
|
if (datalen <= 0) {
|
||
|
/*it means old version APK, TODO:remove it in future */
|
||
|
if (hdr_rev->len <= sizeof(*hdr_rev)) {
|
||
|
etf_driver_resp(BOOT_COMPLETE, BOOT_SUCCESS);
|
||
|
ret = xradio_etf_connect();
|
||
|
if (ret)
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
if (download->flags & DOWNLOAD_F_PATH_ONLY) {
|
||
|
etf_printk(XRADIO_DBG_WARN, "fw path=%s\n", (char *)(download+1));
|
||
|
/*TODO: set etf_priv.fw_path*/
|
||
|
|
||
|
} else if (download->flags & DOWNLOAD_F_START) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "fw first block\n");
|
||
|
/*TODO: open a tmp file to save firmware */
|
||
|
}
|
||
|
|
||
|
/*TODO: put data into a tmp file */
|
||
|
|
||
|
/*TODO: put data into a tmp file */
|
||
|
if ((download->flags & DOWNLOAD_F_END)) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "fw last block\n");
|
||
|
etf_driver_resp(BOOT_COMPLETE, BOOT_SUCCESS);
|
||
|
/*TODO: save data tmp file and update etf_priv.fw_path*/
|
||
|
ret = xradio_etf_connect();
|
||
|
if (ret)
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
}
|
||
|
break;
|
||
|
case ETF_DOWNLOAD_SDD_ID:
|
||
|
etf_printk(XRADIO_DBG_NIY, "DOWNLOAD_SDD, size=%d\n", hdr_rev->len);
|
||
|
download = (struct drv_download *)(hdr_rev + 1);
|
||
|
datalen = hdr_rev->len - sizeof(*download) - sizeof(*hdr_rev);
|
||
|
if (datalen <= 0) {
|
||
|
/*it means old version APK, TODO:remove it in future */
|
||
|
if (hdr_rev->len <= sizeof(*hdr_rev)) {
|
||
|
etf_driver_resp(BOOT_SDD_COMPLETE, BOOT_SUCCESS);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (download->flags & DOWNLOAD_F_PATH_ONLY) {
|
||
|
etf_printk(XRADIO_DBG_WARN, "sdd path=%s\n", (char *)(download+1));
|
||
|
/*TODO: set etf_priv.fw_path*/
|
||
|
|
||
|
} else if ((download->flags & DOWNLOAD_F_START)) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "sdd first block\n");
|
||
|
/*TODO: open a tmp file to save firmware */
|
||
|
}
|
||
|
|
||
|
/*TODO: put data into a tmp file */
|
||
|
|
||
|
if ((download->flags & DOWNLOAD_F_END)) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "sdd last block\n");
|
||
|
etf_driver_resp(BOOT_SDD_COMPLETE, BOOT_SUCCESS);
|
||
|
/*TODO: save data tmp file and update etf_priv.sdd_path*/
|
||
|
}
|
||
|
break;
|
||
|
case ETF_CONNECT_ID:
|
||
|
etf_printk(XRADIO_DBG_ALWY, "ETF_CONNECT_ID!\n");
|
||
|
etf_driver_resp(BOOT_COMPLETE, BOOT_SUCCESS);
|
||
|
ret = xradio_etf_connect();
|
||
|
if (ret)
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
break;
|
||
|
case ETF_DISCONNECT_ID:
|
||
|
etf_printk(XRADIO_DBG_ALWY, "ETF_DISCONNECT_ID!\n");
|
||
|
xradio_etf_disconnect();
|
||
|
etf_driver_resp(BOOT_STATE_NULL, BOOT_SUCCESS);
|
||
|
break;
|
||
|
case ETF_RECONNECT_ID:
|
||
|
etf_printk(XRADIO_DBG_ALWY, "ETF_RECONNECT_ID!\n");
|
||
|
if (1/*TODO: is update files*/) {
|
||
|
xradio_etf_disconnect();
|
||
|
etf_driver_resp(BOOT_COMPLETE, BOOT_SUCCESS);
|
||
|
ret = xradio_etf_connect();
|
||
|
if (ret)
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
} else {
|
||
|
ret = BOOT_ERR_BAD_OP;
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
etf_printk(XRADIO_DBG_ERROR, "No download files before!\n");
|
||
|
}
|
||
|
break;
|
||
|
case ETF_GET_SDD_POWER_DEFT: /* get default tx power */
|
||
|
{
|
||
|
#ifdef USE_VFS_FIRMWARE
|
||
|
const struct xr_file *sdd = NULL;
|
||
|
#else
|
||
|
const struct firmware *sdd = NULL;
|
||
|
#endif
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s ETF_GET_SDD_POWER_DEFT!\n", __func__);
|
||
|
|
||
|
#ifdef USE_VFS_FIRMWARE
|
||
|
sdd = xr_request_file(etf_get_sddpath());
|
||
|
#else
|
||
|
ret = request_firmware(&sdd, etf_get_sddpath(), NULL);
|
||
|
#endif
|
||
|
/* get sdd data */
|
||
|
if (likely(sdd) && likely(sdd->data)) {
|
||
|
int i;
|
||
|
u16 *outpower = (u16 *)(hdr_rev + 1);
|
||
|
void *ie_data = NULL;
|
||
|
int ie_len = etf_get_sdd_param((u8 *)sdd->data, sdd->size,
|
||
|
SDD_MAX_OUTPUT_POWER_2G4_ELT_ID, &ie_data);
|
||
|
if (ie_len > 0 && ie_data &&
|
||
|
ie_len < (ADAPTER_RX_BUF_LEN - sizeof(*hdr_rev))) {
|
||
|
memcpy(outpower, ie_data, ie_len);
|
||
|
for (i = 0; i < (ie_len>>1); i++)
|
||
|
outpower[i] -= 48; /*default pwr = max power - 48*/
|
||
|
}
|
||
|
hdr_rev->len = sizeof(*hdr_rev) + ie_len;
|
||
|
xradio_adapter_send(hdr_rev, hdr_rev->len);
|
||
|
#ifdef USE_VFS_FIRMWARE
|
||
|
xr_fileclose(sdd);
|
||
|
#else
|
||
|
release_firmware(sdd);
|
||
|
#endif
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s: can't load sdd file %s.\n",
|
||
|
__func__, etf_get_sddpath());
|
||
|
ret = -ENOENT;
|
||
|
hdr_rev->len = sizeof(*hdr_rev);
|
||
|
xradio_adapter_send(hdr_rev, sizeof(*hdr_rev));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ETF_GET_SDD_PARAM_ID:
|
||
|
{
|
||
|
struct xradio_common *hw_priv = etf_priv.core_priv;
|
||
|
struct get_sdd_param_req *sddreq = (struct get_sdd_param_req *)hdr_rev;
|
||
|
struct get_sdd_result *sddret = (struct get_sdd_result *)sddreq;
|
||
|
void *ie_data = NULL;
|
||
|
int ie_len = 0;
|
||
|
#ifdef USE_VFS_FIRMWARE
|
||
|
const struct xr_file *sdd = NULL;
|
||
|
#else
|
||
|
const struct firmware *sdd = NULL;
|
||
|
#endif
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s ETF_GET_SDD_PARAM_ID!\n", __func__);
|
||
|
|
||
|
if (hw_priv && hw_priv->sdd) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s use xradio_common sdd!\n", __func__);
|
||
|
sdd = hw_priv->sdd;
|
||
|
} else {
|
||
|
#ifdef USE_VFS_FIRMWARE
|
||
|
sdd = xr_request_file(etf_get_sddpath());
|
||
|
#else
|
||
|
ret = request_firmware(&sdd, etf_get_sddpath(), NULL);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
hdr_rev->id = hdr_rev->id + ETF_CNF_BASE;
|
||
|
if (likely(sdd) && likely(sdd->data)) {
|
||
|
if (sddreq->flags & FLAG_GET_SDD_ALL) {
|
||
|
sddret->result = 0;
|
||
|
sddret->length = sdd->size;
|
||
|
xradio_adapter_send_pkg(sddret, sizeof(*sddret), (u8 *)sdd->data,
|
||
|
sddret->length);
|
||
|
} else {
|
||
|
ie_len = etf_get_sdd_param((u8 *)sdd->data, sdd->size,
|
||
|
sddreq->ies, &ie_data);
|
||
|
if (ie_data && ie_len > 0) {
|
||
|
sddret->result = 0;
|
||
|
sddret->length = ie_len;
|
||
|
hdr_rev->len = sizeof(*sddret) + sddret->length;
|
||
|
xradio_adapter_send_pkg(sddret, sizeof(*sddret), ie_data,
|
||
|
sddret->length);
|
||
|
} else {
|
||
|
sddret->result = -ENOMSG;
|
||
|
sddret->length = 0;
|
||
|
hdr_rev->len = sizeof(*sddret) + sddret->length;
|
||
|
xradio_adapter_send(sddret, sizeof(*sddret));
|
||
|
}
|
||
|
}
|
||
|
if (hw_priv && hw_priv->sdd) {
|
||
|
sdd = NULL;
|
||
|
} else {
|
||
|
#ifdef USE_VFS_FIRMWARE
|
||
|
xr_fileclose(sdd);
|
||
|
#else
|
||
|
release_firmware(sdd);
|
||
|
#endif
|
||
|
}
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s: can't load sdd file %s.\n",
|
||
|
__func__, etf_get_sddpath());
|
||
|
sddret->result = -ENOENT;
|
||
|
sddret->length = 0;
|
||
|
hdr_rev->len = sizeof(*sddret) + sddret->length;
|
||
|
xradio_adapter_send(sddret, sizeof(*sddret));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s: passed cmd=0x%04x, len=%d",
|
||
|
__func__, MSG_ID(hdr_rev->id), hdr_rev->len);
|
||
|
if (etf_priv.etf_state != ETF_STAT_CONNECTED) {
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s etf Not connect.\n", __func__);
|
||
|
ret = ETF_ERR_NOT_CONNECT;
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
goto out;
|
||
|
}
|
||
|
if (SEQ_MASK(etf_priv.seq_send) != MSG_SEQ(hdr_rev->id)) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s:seq err, drv_seq=%d, seq=%d\n",
|
||
|
__func__, etf_priv.seq_send, MSG_SEQ(hdr_rev->id));
|
||
|
etf_priv.seq_send = MSG_SEQ(hdr_rev->id);
|
||
|
}
|
||
|
etf_priv.seq_send++;
|
||
|
if (ETF_HWT_REQ == MSG_ID(hdr_rev->id)) {
|
||
|
/*TODO: HW test*/
|
||
|
#if DGB_XRADIO_HWT
|
||
|
HWT_Tx_handle((HWT_PARAMETERS *)data);
|
||
|
#else
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s HW test unsupport\n", __func__);
|
||
|
#endif
|
||
|
} else if (etf_priv.core_priv) {
|
||
|
if (ETF_DOWNLOAD_SDD == MSG_ID(hdr_rev->id) &&
|
||
|
hdr_rev->len <= sizeof(struct etf_sdd_req)) {
|
||
|
struct xradio_common *hw_priv = etf_priv.core_priv;
|
||
|
struct etf_sdd_req *sdd_req = (struct etf_sdd_req *)hdr_rev;
|
||
|
u32 sdd_cmd = sdd_req->sdd_cmd;
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s add sdd data, cmd=0x%08x!\n",
|
||
|
__func__, sdd_cmd);
|
||
|
if (hw_priv->sdd) {
|
||
|
u8 *sdd_data = (u8 *)(hdr_rev + 1);
|
||
|
int sdd_len = hw_priv->sdd->size;
|
||
|
if (sdd_len + sizeof(*hdr_rev) + 4 < ADAPTER_RX_BUF_LEN) {
|
||
|
memcpy(sdd_data, hw_priv->sdd->data, sdd_len);
|
||
|
memcpy(sdd_data + sdd_len, &sdd_cmd, 4);
|
||
|
hdr_rev->len += sdd_len;
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_ERROR,
|
||
|
"ADAPTER_RX_BUF_LEN=%d, sdd_len=%d\n",
|
||
|
ADAPTER_RX_BUF_LEN, sdd_len);
|
||
|
}
|
||
|
} else
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s core_priv sdd is NULL\n",
|
||
|
__func__);
|
||
|
}
|
||
|
/* send to device*/
|
||
|
ret = wsm_etf_cmd(etf_priv.core_priv, (struct wsm_hdr *)data);
|
||
|
if (ret < 0) {
|
||
|
etf_driver_resp(BOOT_STATE_NULL, ret);
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s wsm_etf_cmd failed(%d)\n",
|
||
|
__func__, ret);
|
||
|
}
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s core_priv is NULL\n",
|
||
|
__func__);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
up(&etf_priv.etf_lock);
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s success\n", __func__);
|
||
|
return 0;
|
||
|
|
||
|
out:
|
||
|
up(&etf_priv.etf_lock);
|
||
|
if (ret)
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s proc failed(%d)\n", __func__, ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int xradio_etf_from_device(struct sk_buff **skb)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct wsm_hdr *wsm = (struct wsm_hdr *)((*skb)->data);
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s MsgId=0x%04x, len=%d\n", __func__,
|
||
|
wsm->id, wsm->len);
|
||
|
ret = xradio_adapter_send((void *)wsm, wsm->len);
|
||
|
if (ret < 0) {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s xradio_adapter_send failed(%d).\n",
|
||
|
__func__, ret);
|
||
|
} else {
|
||
|
etf_priv.seq_recv++;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void xradio_etf_save_context(void *buf, int len)
|
||
|
{
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
if (len == sizeof(context_save)) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s, len=%d\n", __func__, len);
|
||
|
memcpy(&context_save, buf, sizeof(context_save));
|
||
|
} else if (len > sizeof(context_save)) {
|
||
|
etf_printk(XRADIO_DBG_WARN, "%s, len=%d\n", __func__, len);
|
||
|
memcpy(&context_save, buf, sizeof(context_save));
|
||
|
} else {
|
||
|
etf_printk(XRADIO_DBG_ERROR, "%s,len too short=%d\n", __func__, len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void xradio_etf_to_wlan(u32 change)
|
||
|
{
|
||
|
down(&etf_priv.etf_lock);
|
||
|
etf_priv.is_wlan = change;
|
||
|
if (change && etf_is_connect()) {
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s change to wlan.\n", __func__);
|
||
|
xradio_etf_disconnect();
|
||
|
}
|
||
|
up(&etf_priv.etf_lock);
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(xradio_etf_to_wlan);
|
||
|
|
||
|
int xradio_etf_suspend(void)
|
||
|
{
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s\n", __func__);
|
||
|
if (down_trylock(&etf_priv.etf_lock)) {
|
||
|
etf_printk(XRADIO_DBG_WARN,
|
||
|
"%s etf_lock is locked\n", __func__);
|
||
|
return -EBUSY; /*etf is locked.*/
|
||
|
}
|
||
|
if (etf_is_connect()) {
|
||
|
etf_printk(XRADIO_DBG_WARN,
|
||
|
"%s etf is running, don't suspend!\n", __func__);
|
||
|
up(&etf_priv.etf_lock);
|
||
|
return -EBUSY; /*etf is running*/
|
||
|
}
|
||
|
up(&etf_priv.etf_lock);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int xradio_etf_resume(void)
|
||
|
{
|
||
|
etf_printk(XRADIO_DBG_NIY, "%s\n", __func__);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int xradio_etf_init(void)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
sema_init(&etf_priv.etf_lock, 1);
|
||
|
etf_priv.etf_state = ETF_STAT_NULL;
|
||
|
etf_priv.fw_path = XR829_ETF_FIRMWARE;
|
||
|
etf_priv.sdd_path = XR829_SDD_FILE;
|
||
|
etf_priv.adapter = xradio_adapter_init(&xradio_etf_proc);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void xradio_etf_deinit(void)
|
||
|
{
|
||
|
etf_printk(XRADIO_DBG_TRC, "%s\n", __func__);
|
||
|
/*ensure in disconnect state when etf deinit*/
|
||
|
xradio_etf_to_wlan(1);
|
||
|
xradio_adapter_deinit();
|
||
|
memset(&etf_priv, 0, sizeof(etf_priv));
|
||
|
}
|
||
|
|
||
|
#endif /*XRADIO_ETF_C*/
|