blob: ca09f7ed7e4dd338e9bdf1c04bb847bdb47bc7e6 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2007 - 2012 Realtek Corporation. */
#define _USB_OPS_LINUX_C_
#include "../include/drv_types.h"
#include "../include/rtl8188e_recv.h"
static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
{
unsigned int pipe = 0, ep_num = 0;
struct usb_device *pusbd = pdvobj->pusbdev;
if (addr < HW_QUEUE_ENTRY) {
ep_num = pdvobj->Queue2Pipe[addr];
pipe = usb_sndbulkpipe(pusbd, ep_num);
}
return pipe;
}
void rtw_read_port_cancel(struct adapter *padapter)
{
int i;
struct recv_buf *precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
padapter->bReadPortCancel = true;
for (i = 0; i < NR_RECVBUFF; i++) {
precvbuf->reuse = true;
usb_kill_urb(precvbuf->purb);
precvbuf++;
}
}
static void usb_write_port_complete(struct urb *purb)
{
struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
struct adapter *padapter = pxmitbuf->padapter;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
if (pxmitbuf->high_queue)
rtw_chk_hi_queue_cmd(padapter);
switch (purb->status) {
case 0:
case -EINPROGRESS:
case -ENOENT:
case -ECONNRESET:
case -EPIPE:
case -EPROTO:
break;
case -ESHUTDOWN:
padapter->bDriverStopped = true;
break;
default:
padapter->bSurpriseRemoved = true;
break;
}
rtw_sctx_done_err(&pxmitbuf->sctx,
purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS);
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
}
u32 rtw_write_port(struct adapter *padapter, u32 addr, u32 cnt, u8 *wmem)
{
unsigned long irqL;
unsigned int pipe;
int status;
u32 ret = _FAIL;
struct urb *purb = NULL;
struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
struct usb_device *pusbd = pdvobj->pusbdev;
if (padapter->bDriverStopped || padapter->bSurpriseRemoved) {
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
goto exit;
}
spin_lock_irqsave(&pxmitpriv->lock, irqL);
pxmitbuf->high_queue = (addr == HIGH_QUEUE_INX);
spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
purb = pxmitbuf->pxmit_urb;
/* translate DMA FIFO addr to pipehandle */
pipe = ffaddr2pipehdl(pdvobj, addr);
usb_fill_bulk_urb(purb, pusbd, pipe,
pxmitframe->buf_addr, /* pxmitbuf->pbuf */
cnt,
usb_write_port_complete,
pxmitbuf);/* context is pxmitbuf */
status = usb_submit_urb(purb, GFP_ATOMIC);
if (status) {
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
if (status == -ENODEV)
padapter->bDriverStopped = true;
goto exit;
}
ret = _SUCCESS;
/* We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */
exit:
if (ret != _SUCCESS)
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
return ret;
}
void rtw_write_port_cancel(struct adapter *padapter)
{
int i;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
padapter->bWritePortCancel = true;
for (i = 0; i < NR_XMITBUFF; i++) {
usb_kill_urb(pxmitbuf->pxmit_urb);
pxmitbuf++;
}
pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf;
for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
usb_kill_urb(pxmitbuf->pxmit_urb);
pxmitbuf++;
}
}