mirror of
https://github.com/RinCat/RTL88x2BU-Linux-Driver.git
synced 2024-12-27 18:41:34 +00:00
321 lines
8.0 KiB
C
321 lines
8.0 KiB
C
|
/******************************************************************************
|
||
|
*
|
||
|
* 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;
|
||
|
}
|