| // SPDX-License-Identifier: GPL-2.0 |
| /* Copyright(c) 2007 - 2012 Realtek Corporation. */ |
| |
| #define _USB_OPS_LINUX_C_ |
| |
| #include "../include/drv_types.h" |
| #include "../include/usb_ops_linux.h" |
| #include "../include/rtl8188e_recv.h" |
| |
| unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) |
| { |
| unsigned int pipe = 0, ep_num = 0; |
| struct usb_device *pusbd = pdvobj->pusbdev; |
| |
| if (addr == RECV_BULK_IN_ADDR) { |
| pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]); |
| } else if (addr == RECV_INT_IN_ADDR) { |
| pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]); |
| } else if (addr < HW_QUEUE_ENTRY) { |
| ep_num = pdvobj->Queue2Pipe[addr]; |
| pipe = usb_sndbulkpipe(pusbd, ep_num); |
| } |
| |
| return pipe; |
| } |
| |
| struct zero_bulkout_context { |
| void *pbuf; |
| void *purb; |
| void *pirp; |
| void *padapter; |
| }; |
| |
| void rtw_read_port_cancel(struct adapter *padapter) |
| { |
| int i; |
| struct recv_buf *precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; |
| |
| DBG_88E("%s\n", __func__); |
| |
| padapter->bReadPortCancel = true; |
| |
| for (i = 0; i < NR_RECVBUFF; i++) { |
| precvbuf->reuse = true; |
| if (precvbuf->purb) |
| usb_kill_urb(precvbuf->purb); |
| precvbuf++; |
| } |
| } |
| |
| static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) |
| { |
| struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; |
| struct adapter *padapter = pxmitbuf->padapter; |
| struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
| |
| switch (pxmitbuf->flags) { |
| case VO_QUEUE_INX: |
| pxmitpriv->voq_cnt--; |
| break; |
| case VI_QUEUE_INX: |
| pxmitpriv->viq_cnt--; |
| break; |
| case BE_QUEUE_INX: |
| pxmitpriv->beq_cnt--; |
| break; |
| case BK_QUEUE_INX: |
| pxmitpriv->bkq_cnt--; |
| break; |
| case HIGH_QUEUE_INX: |
| rtw_chk_hi_queue_cmd(padapter); |
| break; |
| default: |
| break; |
| } |
| |
| if (padapter->bSurpriseRemoved || padapter->bDriverStopped || |
| padapter->bWritePortCancel) { |
| DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n", |
| __func__, padapter->bDriverStopped, |
| padapter->bSurpriseRemoved, padapter->bReadPortCancel, |
| pxmitbuf->ext_tag); |
| |
| goto check_completion; |
| } |
| |
| if (purb->status) { |
| DBG_88E("###=> urb_write_port_complete status(%d)\n", purb->status); |
| if (purb->status == -EINPROGRESS) { |
| goto check_completion; |
| } else if (purb->status == -ENOENT) { |
| DBG_88E("%s: -ENOENT\n", __func__); |
| goto check_completion; |
| } else if (purb->status == -ECONNRESET) { |
| DBG_88E("%s: -ECONNRESET\n", __func__); |
| goto check_completion; |
| } else if (purb->status == -ESHUTDOWN) { |
| padapter->bDriverStopped = true; |
| goto check_completion; |
| } else if ((purb->status != -EPIPE) && (purb->status != -EPROTO)) { |
| padapter->bSurpriseRemoved = true; |
| DBG_88E("bSurpriseRemoved = true\n"); |
| |
| goto check_completion; |
| } |
| } |
| |
| check_completion: |
| 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) || |
| (padapter->pwrctrlpriv.pnp_bstop_trx)) { |
| rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); |
| goto exit; |
| } |
| |
| spin_lock_irqsave(&pxmitpriv->lock, irqL); |
| |
| switch (addr) { |
| case VO_QUEUE_INX: |
| pxmitpriv->voq_cnt++; |
| pxmitbuf->flags = VO_QUEUE_INX; |
| break; |
| case VI_QUEUE_INX: |
| pxmitpriv->viq_cnt++; |
| pxmitbuf->flags = VI_QUEUE_INX; |
| break; |
| case BE_QUEUE_INX: |
| pxmitpriv->beq_cnt++; |
| pxmitbuf->flags = BE_QUEUE_INX; |
| break; |
| case BK_QUEUE_INX: |
| pxmitpriv->bkq_cnt++; |
| pxmitbuf->flags = BK_QUEUE_INX; |
| break; |
| case HIGH_QUEUE_INX: |
| pxmitbuf->flags = HIGH_QUEUE_INX; |
| break; |
| default: |
| pxmitbuf->flags = MGT_QUEUE_INX; |
| break; |
| } |
| |
| spin_unlock_irqrestore(&pxmitpriv->lock, irqL); |
| |
| purb = pxmitbuf->pxmit_urb[0]; |
| |
| /* 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); |
| DBG_88E("usb_write_port, status =%d\n", status); |
| |
| switch (status) { |
| case -ENODEV: |
| padapter->bDriverStopped = true; |
| break; |
| default: |
| break; |
| } |
| 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, j; |
| struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf; |
| |
| DBG_88E("%s\n", __func__); |
| |
| padapter->bWritePortCancel = true; |
| |
| for (i = 0; i < NR_XMITBUFF; i++) { |
| for (j = 0; j < 8; j++) { |
| if (pxmitbuf->pxmit_urb[j]) |
| usb_kill_urb(pxmitbuf->pxmit_urb[j]); |
| } |
| pxmitbuf++; |
| } |
| |
| pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf; |
| for (i = 0; i < NR_XMIT_EXTBUFF; i++) { |
| for (j = 0; j < 8; j++) { |
| if (pxmitbuf->pxmit_urb[j]) |
| usb_kill_urb(pxmitbuf->pxmit_urb[j]); |
| } |
| pxmitbuf++; |
| } |
| } |