/****************************************************************************** * * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. * * 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 * *******************************************************************************/ #define _USB_OPS_LINUX_C_ #include #include #include 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; }; static void usb_bulkout_zero_complete(struct urb *purb, struct pt_regs *regs) { struct zero_bulkout_context *pcontext = (struct zero_bulkout_context *)purb->context; //DBG_88E("+usb_bulkout_zero_complete\n"); if (pcontext) { if (pcontext->pbuf) { rtw_mfree(pcontext->pbuf, sizeof(int)); } if (pcontext->purb && (pcontext->purb==purb)) { usb_free_urb(pcontext->purb); } rtw_mfree((u8*)pcontext, sizeof(struct zero_bulkout_context)); } } static u32 usb_bulkout_zero(struct intf_hdl *pintfhdl, u32 addr) { int pipe, status, len; u32 ret; unsigned char *pbuf; struct zero_bulkout_context *pcontext; PURB purb = NULL; _adapter *padapter = (_adapter *)pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); struct usb_device *pusbd = pdvobj->pusbdev; //DBG_88E("%s\n", __func__); if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(padapter->pwrctrlpriv.pnp_bstop_trx)) return _FAIL; pcontext = (struct zero_bulkout_context *)rtw_zmalloc(sizeof(struct zero_bulkout_context)); pbuf = (unsigned char *)rtw_zmalloc(sizeof(int)); purb = usb_alloc_urb(0, GFP_ATOMIC); len = 0; pcontext->pbuf = pbuf; pcontext->purb = purb; pcontext->pirp = NULL; pcontext->padapter = padapter; //translate DMA FIFO addr to pipehandle usb_fill_bulk_urb(purb, pusbd, pipe, pbuf, len, usb_bulkout_zero_complete, pcontext);//context is pcontext status = usb_submit_urb(purb, GFP_ATOMIC); if (!status) ret= _SUCCESS; else ret= _FAIL; return ret; } void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) { } void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) { } void usb_read_port_cancel(struct intf_hdl *pintfhdl) { int i; struct recv_buf *precvbuf; _adapter *padapter = pintfhdl->padapter; 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) { //DBG_88E("usb_read_port_cancel : usb_kill_urb\n"); usb_kill_urb(precvbuf->purb); } precvbuf++; } } static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) { _irqL irqL; int i; struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; _adapter *padapter = pxmitbuf->padapter; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; _func_enter_; 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: #ifdef CONFIG_AP_MODE rtw_chk_hi_queue_cmd(padapter); #endif break; default: break; } if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||padapter->bWritePortCancel) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); 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==0) { } else { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete : purb->status(%d) != 0\n", purb->status)); DBG_88E("###=> urb_write_port_complete status(%d)\n",purb->status); if ((purb->status==-EPIPE)||(purb->status==-EPROTO)) { sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); } else if (purb->status == -EINPROGRESS) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: EINPROGESS\n")); 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) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: ESHUTDOWN\n")); padapter->bDriverStopped=true; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped=true\n")); goto check_completion; } else { padapter->bSurpriseRemoved=true; DBG_88E("bSurpriseRemoved=true\n"); //rtl8192cu_trigger_gpio_0(padapter); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bSurpriseRemoved=true\n")); goto check_completion; } } { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time(); } 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); //if (rtw_txframes_pending(padapter)) { tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); } _func_exit_; } u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) { _irqL irqL; unsigned int pipe; int status; u32 ret = _FAIL, bwritezero = false; PURB purb = NULL; _adapter *padapter = (_adapter *)pintfhdl->padapter; 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; struct pkt_attrib *pattrib = &pxmitframe->attrib; _func_enter_; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("+usb_write_port\n")); if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(padapter->pwrctrlpriv.pnp_bstop_trx)) { #ifdef DBG_TX DBG_88E(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d, pnp_bstop_trx:%d\n",__func__, __LINE__ ,padapter->bDriverStopped, padapter->bSurpriseRemoved, padapter->pwrctrlpriv.pnp_bstop_trx ); #endif RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); goto exit; } _enter_critical(&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; } _exit_critical(&pxmitpriv->lock, &irqL); purb = pxmitbuf->pxmit_urb[0]; //translate DMA FIFO addr to pipehandle pipe = ffaddr2pipehdl(pdvobj, addr); #ifdef CONFIG_REDUCE_USB_TX_INT if ( (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0) || (pxmitbuf->ext_tag == true) ) { purb->transfer_flags &= (~URB_NO_INTERRUPT); } else { purb->transfer_flags |= URB_NO_INTERRUPT; } #endif 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) { { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_time = rtw_get_current_time(); } } else { rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); DBG_88E("usb_write_port, status=%d\n", status); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port(): usb_submit_urb, status=%x\n", status)); switch (status) { case -ENODEV: padapter->bDriverStopped=true; break; default: break; } goto exit; } ret= _SUCCESS; // Commented by Albert 2009/10/13 // We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. /* if (bwritezero == true) { usb_bulkout_zero(pintfhdl, addr); } */ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n")); exit: if (ret != _SUCCESS) rtw_free_xmitbuf(pxmitpriv, pxmitbuf); _func_exit_; return ret; } void usb_write_port_cancel(struct intf_hdl *pintfhdl) { int i, j; _adapter *padapter = pintfhdl->padapter; struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf; DBG_88E("%s\n", __func__); padapter->bWritePortCancel = true; for (i=0; ipxmit_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++; } }