RTL88x2BU-Linux-Driver/hal/rtl8822b/usb/rtl8822bu_halmac.c

321 lines
8.0 KiB
C
Raw Normal View History

/******************************************************************************
*
* Copyright(c) 2015 - 2017 Realtek Corporation.
*
* 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.
*
*****************************************************************************/
#define _RTL8822BU_HALMAC_C_
#include <drv_types.h> /* struct dvobj_priv and etc. */
#include "../../hal_halmac.h"
#include "../rtl8822b.h" /* rtl8822b_cal_txdesc_chksum() and etc. */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) || (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
#define usb_write_port_complete_not_xmitframe(purb, regs) usb_write_port_complete_not_xmitframe(purb)
#endif
static void usb_write_port_complete_not_xmitframe(struct urb *purb, struct pt_regs *regs)
{
if (purb->status == 0) {
;
} else {
RTW_INFO("###=> urb_write_port_complete status(%d)\n", purb->status);
if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
;
} else if (purb->status == -EINPROGRESS) {
goto check_completion;
} else if (purb->status == -ENOENT) {
RTW_INFO("%s: -ENOENT\n", __func__);
goto check_completion;
} else if (purb->status == -ECONNRESET) {
RTW_INFO("%s: -ECONNRESET\n", __func__);
goto check_completion;
} else if (purb->status == -ESHUTDOWN) {
RTW_INFO("%s: -ESHUTDOWN\n", __func__);
goto check_completion;
} else {
goto check_completion;
}
}
check_completion:
rtw_mfree(purb->transfer_buffer, purb->transfer_buffer_length);
usb_free_urb(purb);
}
static u32 usb_write_port_not_xmitframe(struct dvobj_priv *d, u8 addr, u32 cnt, u8 *wmem)
{
struct dvobj_priv *pobj = (struct dvobj_priv *)d;
PADAPTER padapter = dvobj_get_primary_adapter(pobj);
unsigned int pipe;
int status;
u32 ret = _FAIL, bwritezero = _FALSE;
PURB purb = NULL;
struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobj->pusbdev;
purb = usb_alloc_urb(0, GFP_KERNEL);
if (purb == NULL) {
RTW_ERR("purb == NULL\n");
return _FAIL;
}
/* translate DMA FIFO addr to pipehandle */
pipe = ffaddr2pipehdl(pdvobj, addr);
usb_fill_bulk_urb(purb, pusbd, pipe,
wmem,
cnt,
usb_write_port_complete_not_xmitframe,
padapter);
#ifdef USB_PACKET_OFFSET_SZ
#if (USB_PACKET_OFFSET_SZ == 0)
purb->transfer_flags |= URB_ZERO_PACKET;
#endif
#endif
#if 0
if (bwritezero)
purb->transfer_flags |= URB_ZERO_PACKET;
#endif
status = usb_submit_urb(purb, GFP_ATOMIC);
if (!status) {
#ifdef DBG_CONFIG_ERROR_DETECT
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
pHalData->srestpriv.last_tx_time = rtw_get_current_time();
}
#endif
} else {
RTW_INFO("usb_write_port, status=%d\n", status);
switch (status) {
case -ENODEV:
break;
default:
break;
}
goto exit;
}
ret = _SUCCESS;
exit:
if (ret != _SUCCESS)
usb_free_urb(purb);
return ret;
}
static u8 usb_write_data_not_xmitframe(void *d, u8 *pBuf, u32 size, u8 qsel)
{
struct dvobj_priv *pobj = (struct dvobj_priv *)d;
PADAPTER padapter = dvobj_get_primary_adapter(pobj);
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
u32 desclen, len;
u8 *buf;
u8 ret;
u8 addr;
u8 add_pkt_offset = 0;
desclen = rtl8822b_get_tx_desc_size(padapter);
len = desclen + size;
if (qsel == HALMAC_TXDESC_QSEL_BEACON) {
if (len % pHalData->UsbBulkOutSize == 0)
add_pkt_offset = 1;
if (add_pkt_offset == 1)
len = len + PACKET_OFFSET_SZ;
buf = rtw_zmalloc(len);
if (!buf)
return _FALSE;
if (add_pkt_offset == 1)
_rtw_memcpy(buf + desclen + PACKET_OFFSET_SZ , pBuf, size);
else
_rtw_memcpy(buf + desclen, pBuf, size);
SET_TX_DESC_TXPKTSIZE_8822B(buf, size);
if (add_pkt_offset == 1) {
SET_TX_DESC_OFFSET_8822B(buf, desclen + PACKET_OFFSET_SZ);
SET_TX_DESC_PKT_OFFSET_8822B(buf, 1);
} else
SET_TX_DESC_OFFSET_8822B(buf, desclen);
} else if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD){
buf = rtw_zmalloc(len);
if (!buf)
return _FALSE;
_rtw_memcpy(buf + desclen, pBuf, size);
SET_TX_DESC_TXPKTSIZE_8822B(buf, size);
} else {
RTW_ERR("%s: qsel may be error(%d)\n", __func__, qsel);
return _FALSE;
}
SET_TX_DESC_QSEL_8822B(buf, qsel);
rtl8822b_cal_txdesc_chksum(padapter, buf);
addr = rtw_halmac_usb_get_bulkout_id(d, buf, len);
ret = usb_write_port_not_xmitframe(d, addr, len , buf);
if (_SUCCESS == ret) {
ret = _TRUE;
} else {
RTW_ERR("%s , rtl8822bu_simple_write_port fail\n", __func__);
rtw_mfree(buf , len);
ret = _FALSE;
}
return ret;
}
static u8 usb_write_data_rsvd_page_normal(void *d, u8 *pBuf, u32 size)
{
struct dvobj_priv *pobj = (struct dvobj_priv *)d;
PADAPTER padapter = dvobj_get_primary_adapter(pobj);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_frame *pcmdframe = NULL;
struct pkt_attrib *pattrib = NULL;
u8 txdesoffset = 0;
u8 *buf = NULL;
if (size + TXDESC_OFFSET > MAX_CMDBUF_SZ) {
RTW_INFO("%s: total buffer size(%d) > MAX_CMDSZE(%d)\n"
, __func__, size + TXDESC_OFFSET, MAX_CMDSZ);
return _FALSE;
}
pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
if (pcmdframe == NULL) {
RTW_INFO("%s: alloc cmd frame fail!\n", __func__);
return _FALSE;
}
txdesoffset = TXDESC_OFFSET;
buf = pcmdframe->buf_addr;
_rtw_memcpy((buf + txdesoffset), pBuf, size); /* shift desclen */
/* update attribute */
pattrib = &pcmdframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
pattrib->qsel = HALMAC_TXDESC_QSEL_BEACON;
pattrib->pktlen = size;
pattrib->last_txcmdsz = size;
/* fill tx desc in dump_mgntframe */
dump_mgntframe(padapter, pcmdframe);
return _TRUE;
}
static u8 usb_write_data_h2c_normal(void *d, u8 *pBuf, u32 size)
{
struct dvobj_priv *pobj = (struct dvobj_priv *)d;
PADAPTER padapter = dvobj_get_primary_adapter(pobj);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_frame *pcmdframe = NULL;
struct pkt_attrib *pattrib = NULL;
u8 txdesoffset = 0;
u8 *buf = NULL;
if (size + TXDESC_OFFSET > MAX_XMIT_EXTBUF_SZ) {
RTW_INFO("%s: total buffer size(%d) > MAX_XMIT_EXTBUF_SZ(%d)\n"
, __func__, size + TXDESC_OFFSET, MAX_XMIT_EXTBUF_SZ);
return _FALSE;
}
pcmdframe = alloc_mgtxmitframe(pxmitpriv);
if (pcmdframe == NULL) {
RTW_INFO("%s: alloc cmd frame fail!\n", __func__);
return _FALSE;
}
txdesoffset = TXDESC_SIZE;
buf = pcmdframe->buf_addr;
_rtw_memcpy(buf + txdesoffset, pBuf, size); /* shift desclen */
/* update attribute */
pattrib = &pcmdframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
pattrib->qsel = HALMAC_TXDESC_QSEL_H2C_CMD;
pattrib->pktlen = size;
pattrib->last_txcmdsz = size;
/* fill tx desc in dump_mgntframe */
dump_mgntframe(padapter, pcmdframe);
return _TRUE;
}
static u8 usb_write_data_rsvd_page(void *d, u8 *pBuf, u32 size)
{
struct dvobj_priv *pobj = (struct dvobj_priv *)d;
PADAPTER padapter = dvobj_get_primary_adapter(pobj);
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
if (pHalData->not_xmitframe_fw_dl)
return usb_write_data_not_xmitframe(d , pBuf , size, HALMAC_TXDESC_QSEL_BEACON);
else
return usb_write_data_rsvd_page_normal(d , pBuf , size);
}
static u8 usb_write_data_h2c(void *d, u8 *pBuf, u32 size)
{
struct dvobj_priv *pobj = (struct dvobj_priv *)d;
PADAPTER padapter = dvobj_get_primary_adapter(pobj);
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
if (pHalData->not_xmitframe_fw_dl)
return usb_write_data_not_xmitframe(d , pBuf , size, HALMAC_TXDESC_QSEL_H2C_CMD);
else
return usb_write_data_h2c_normal(d , pBuf , size);
}
int rtl8822bu_halmac_init_adapter(PADAPTER padapter)
{
struct dvobj_priv *d;
struct halmac_platform_api *api;
int err;
d = adapter_to_dvobj(padapter);
api = &rtw_halmac_platform_api;
api->SEND_RSVD_PAGE = usb_write_data_rsvd_page;
api->SEND_H2C_PKT = usb_write_data_h2c;
err = rtw_halmac_init_adapter(d, api);
return err;
}