/******************************************************************************
* rtl871x_cmd.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
* Contact information:
* WLAN FAE <wlanfae@realtek.com>
* Larry Finger <Larry.Finger@lwfinger.net>
*
******************************************************************************/
#define _RTL871X_CMD_C_
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/circ_buf.h>
#include <linux/uaccess.h>
#include <asm/byteorder.h>
#include <linux/atomic.h>
#include <linux/semaphore.h>
#include <linux/rtnetlink.h>
#include "osdep_service.h"
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
/*
Caller and the r8712_cmd_thread can protect cmd_q by spin_lock.
No irqsave is necessary.
*/
static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
{
init_completion(&pcmdpriv->cmd_queue_comp);
init_completion(&pcmdpriv->terminate_cmdthread_comp);
_init_queue(&(pcmdpriv->cmd_queue));
/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
pcmdpriv->cmd_seq = 1;
pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
GFP_ATOMIC);
if (pcmdpriv->cmd_allocated_buf == NULL)
return _FAIL;
pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ -
((addr_t)(pcmdpriv->cmd_allocated_buf) &
(CMDBUFF_ALIGN_SZ - 1));
pcmdpriv->rsp_allocated_buf = kmalloc(MAX_RSPSZ + 4, GFP_ATOMIC);
if (pcmdpriv->rsp_allocated_buf == NULL)
return _FAIL;
pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 -
((addr_t)(pcmdpriv->rsp_allocated_buf) & 3);
pcmdpriv->cmd_issued_cnt = 0;
pcmdpriv->cmd_done_cnt = 0;
pcmdpriv->rsp_cnt = 0;
return _SUCCESS;
}
static sint _init_evt_priv(struct evt_priv *pevtpriv)
{
/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
pevtpriv->event_seq = 0;
pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC);
if (pevtpriv->evt_allocated_buf == NULL)
return _FAIL;
pevtpriv->evt_buf = pevtpriv->evt_allocated_buf + 4 -
((addr_t)(pevtpriv->evt_allocated_buf) & 3);
pevtpriv->evt_done_cnt = 0;
return _SUCCESS;
}
static void _free_evt_priv(struct evt_priv *pevtpriv)
{
kfree(pevtpriv->evt_allocated_buf);
}
static void _free_cmd_priv(struct cmd_priv *pcmdpriv)
{
if (pcmdpriv) {
kfree(pcmdpriv->cmd_allocated_buf);
kfree(pcmdpriv->rsp_allocated_buf);
}
}
/*
Calling Context:
_enqueue_cmd can only be called between kernel thread,
since only spin_lock is used.
ISR/Call-Back functions can't call this sub-function.
*/
static sint _enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
{
unsigned long irqL;
if (obj == NULL)
return _SUCCESS;
spin_lock_irqsave(&queue->lock, irqL);
list_add_tail(&obj->list, &queue->queue);
spin_unlock_irqrestore(&queue->lock, irqL);
return _SUCCESS;
}
static struct cmd_obj *_dequeue_cmd(struct __queue *queue)
{
unsigned long irqL;
struct cmd_obj *obj;
spin_lock_irqsave(&queue->lock, irqL);
obj = list_first_entry_or_null(&queue->queue,
struct cmd_obj, list);
if (obj)
list_del_init(&obj->list);
spin_unlock_irqrestore(&queue->lock, irqL);
return obj;
}
u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
{
return _init_cmd_priv(pcmdpriv);
}
u32 r8712_init_evt_priv(struct evt_priv *pevtpriv)
{
return _init_evt_priv(pevtpriv);
}
void r8712_free_evt_priv(struct evt_priv *pevtpriv)
{
_free_evt_priv(pevtpriv);
}
void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
{
_free_cmd_priv(pcmdpriv);
}
u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
{
int res;
if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
return _FAIL;
res = _enqueue_cmd(&pcmdpriv->cmd_queue, obj);