diff options
Diffstat (limited to 'drivers/net/wireless/rtl8192ce/os_dep/linux/usb_ops_linux.c')
-rwxr-xr-x | drivers/net/wireless/rtl8192ce/os_dep/linux/usb_ops_linux.c | 715 |
1 files changed, 715 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtl8192ce/os_dep/linux/usb_ops_linux.c b/drivers/net/wireless/rtl8192ce/os_dep/linux/usb_ops_linux.c new file mode 100755 index 000000000000..9878727f40dd --- /dev/null +++ b/drivers/net/wireless/rtl8192ce/os_dep/linux/usb_ops_linux.c @@ -0,0 +1,715 @@ +/****************************************************************************** + * + * 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 <drv_types.h> +#include <usb_ops_linux.h> +#include <rtw_sreset.h> + +#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ +static void _usbctrl_vendorreq_async_callback(struct urb *urb, struct pt_regs *regs) +{ + if (urb) { + if (urb->context) { + kfree(urb->context); + } + usb_free_urb(urb); + } +} + +static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, + u16 value, u16 index, void *pdata, u16 len, u8 requesttype) +{ + int rc; + unsigned int pipe; + u8 reqtype; + struct usb_ctrlrequest *dr; + struct urb *urb; + struct rtl819x_async_write_data { + u8 data[VENDOR_CMD_MAX_DATA_LEN]; + struct usb_ctrlrequest dr; + } *buf; + + + if (requesttype == VENDOR_READ) { + pipe = usb_rcvctrlpipe(udev, 0);//read_in + reqtype = REALTEK_USB_VENQT_READ; + } + else { + pipe = usb_sndctrlpipe(udev, 0);//write_out + reqtype = REALTEK_USB_VENQT_WRITE; + } + + buf = (struct rtl819x_async_write_data *)rtw_zmalloc(sizeof(*buf)); + if (!buf) { + rc = -ENOMEM; + goto exit; + } + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + rtw_mfree((u8*)buf, sizeof(*buf)); + rc = -ENOMEM; + goto exit; + } + + dr = &buf->dr; + + dr->bRequestType = reqtype; + dr->bRequest = request; + dr->wValue = cpu_to_le16(value); + dr->wIndex = cpu_to_le16(index); + dr->wLength = cpu_to_le16(len); + + _rtw_memcpy(buf, pdata, len); + + usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, buf, len, + _usbctrl_vendorreq_async_callback, buf); + + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc < 0) { + rtw_mfree((u8*)buf, sizeof(*buf)); + usb_free_urb(urb); + } + +exit: + return rc; +} + +int usb_write_async(struct usb_device *udev, u32 addr, void *pdata, u16 len) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + + int ret; + + requesttype = VENDOR_WRITE;//write_out + request = REALTEK_USB_VENQT_CMD_REQ; + index = REALTEK_USB_VENQT_CMD_IDX;//n/a + + wvalue = (u16)(addr&0x0000ffff); + + ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, index, pdata, len, requesttype); + + return ret; +} + +int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) +{ + u8 data; + int ret; + struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; + struct usb_device *udev=pdvobjpriv->pusbdev; + + _func_enter_; + data = val; + ret = usb_write_async(udev, addr, &data, 1); + _func_exit_; + + return ret; +} + +int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) +{ + u16 data; + int ret; + struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; + struct usb_device *udev=pdvobjpriv->pusbdev; + + _func_enter_; + data = val; + ret = usb_write_async(udev, addr, &data, 2); + _func_exit_; + + return ret; +} + +int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) +{ + u32 data; + int ret; + struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; + struct usb_device *udev=pdvobjpriv->pusbdev; + + _func_enter_; + data = val; + ret = usb_write_async(udev, addr, &data, 4); + _func_exit_; + + return ret; +} +#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */ + +unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) +{ + unsigned int pipe=0; + int ep_num=0; + _adapter *padapter = pdvobj->padapter; + struct usb_device *pusbd = pdvobj->pusbdev; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + if (addr == RECV_BULK_IN_ADDR) { + pipe=usb_rcvbulkpipe(pusbd, pHalData->RtBulkInPipe); + + } else if (addr == RECV_INT_IN_ADDR) { + pipe=usb_rcvbulkpipe(pusbd, pHalData->RtIntInPipe); + + } else if (addr < HW_QUEUE_ENTRY) { + ep_num = pHalData->Queue2EPNum[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_8192C("+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 = (struct dvobj_priv *)&padapter->dvobjpriv; + struct usb_device *pusbd = pdvobj->pusbdev; + + //DBG_871X("%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 + //pipe = ffaddr2pipehdl(pdvobj, addr); + + 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 _SUCCESS; + +} + +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_871X("%s\n", __func__); + + padapter->bReadPortCancel = _TRUE; + + for (i=0; i < NR_RECVBUFF ; i++) { + + precvbuf->reuse = _TRUE; + if (precvbuf->purb) { + //DBG_8192C("usb_read_port_cancel : usb_kill_urb \n"); + usb_kill_urb(precvbuf->purb); + } + precvbuf++; + } + +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE + usb_kill_urb(padapter->recvpriv.int_in_urb); +#endif +} + +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; + //struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; + //_adapter *padapter = pxmitframe->padapter; + _adapter *padapter = pxmitbuf->padapter; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + //struct pkt_attrib *pattrib = &pxmitframe->attrib; + +_func_enter_; + + switch(pxmitbuf->flags) + { + case XMIT_VO_QUEUE: + pxmitpriv->voq_cnt--; + break; + case XMIT_VI_QUEUE: + pxmitpriv->viq_cnt--; + break; + case XMIT_BE_QUEUE: + pxmitpriv->beq_cnt--; + break; + case XMIT_BK_QUEUE: + pxmitpriv->bkq_cnt--; + break; + case HIGH_QUEUE_INX: +#ifdef CONFIG_AP_MODE + rtw_chk_hi_queue_cmd(padapter); +#endif + break; + default: + break; + } + + +/* + _enter_critical(&pxmitpriv->lock, &irqL); + + pxmitpriv->txirp_cnt--; + + switch(pattrib->priority) + { + case 1: + case 2: + pxmitpriv->bkq_cnt--; + //DBG_8192C("pxmitpriv->bkq_cnt=%d\n", pxmitpriv->bkq_cnt); + break; + case 4: + case 5: + pxmitpriv->viq_cnt--; + //DBG_8192C("pxmitpriv->viq_cnt=%d\n", pxmitpriv->viq_cnt); + break; + case 6: + case 7: + pxmitpriv->voq_cnt--; + //DBG_8192C("pxmitpriv->voq_cnt=%d\n", pxmitpriv->voq_cnt); + break; + case 0: + case 3: + default: + pxmitpriv->beq_cnt--; + //DBG_8192C("pxmitpriv->beq_cnt=%d\n", pxmitpriv->beq_cnt); + break; + + } + + _exit_critical(&pxmitpriv->lock, &irqL); + + + if(pxmitpriv->txirp_cnt==0) + { + RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: txirp_cnt== 0, set allrxreturnevt!\n")); + _rtw_up_sema(&(pxmitpriv->tx_retevt)); + } +*/ + //rtw_free_xmitframe_ex(pxmitpriv, pxmitframe); + + 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_8192C("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x) \n", + __FUNCTION__,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_871X("###=> urb_write_port_complete status(%d)\n",purb->status); + if((purb->status==-EPIPE)||(purb->status==-EPROTO)) + { + //usb_clear_halt(pusbdev, purb->pipe); + //msleep(10); + 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_871X("%s: -ENOENT\n", __func__); + goto check_completion; + + } else if (purb->status == -ECONNRESET) { + DBG_871X("%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_8192C("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; + } + } + + #ifdef DBG_CONFIG_ERROR_DETECT + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time(); + } + #endif + +check_completion: + if (pxmitbuf->isSync) { + pxmitbuf->status = purb->status; + complete(&pxmitbuf->done); + } else { + rtw_free_xmitbuf(pxmitpriv, pxmitbuf); + } + + //if(rtw_txframes_pending(padapter)) + { + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); + } + +_func_exit_; + +} + +static u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem, int timeout_ms) +{ + _irqL irqL; + unsigned int pipe; + int status; + u32 ret, bwritezero = _FALSE; + PURB purb = NULL; + _adapter *padapter = (_adapter *)pintfhdl->padapter; + struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; + 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_871X(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d, pnp_bstop_trx:%d\n",__FUNCTION__, __LINE__ + ,padapter->bDriverStopped, padapter->bSurpriseRemoved, padapter->pwrctrlpriv.pnp_bstop_trx ); + #endif + + rtw_free_xmitbuf(pxmitpriv, pxmitbuf); + + RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); + return _FAIL; + } + + _enter_critical(&pxmitpriv->lock, &irqL); + + switch(addr) + { + case VO_QUEUE_INX: + pxmitpriv->voq_cnt++; + pxmitbuf->flags = XMIT_VO_QUEUE; + break; + case VI_QUEUE_INX: + pxmitpriv->viq_cnt++; + pxmitbuf->flags = XMIT_VI_QUEUE; + break; + case BE_QUEUE_INX: + pxmitpriv->beq_cnt++; + pxmitbuf->flags = XMIT_BE_QUEUE; + break; + case BK_QUEUE_INX: + pxmitpriv->bkq_cnt++; + pxmitbuf->flags = XMIT_BK_QUEUE; + break; + case HIGH_QUEUE_INX: + pxmitbuf->flags = HIGH_QUEUE_INX; + break; + default: + pxmitbuf->flags = XMIT_VO_QUEUE; + break; + } + + _exit_critical(&pxmitpriv->lock, &irqL); + +/* + _enter_critical(&pxmitpriv->lock, &irqL); + + //total irp + pxmitpriv->txirp_cnt++; + + //per ac irp + switch(pattrib->priority) + { + case 1: + case 2: + pxmitpriv->bkq_cnt++; + break; + case 4: + case 5: + pxmitpriv->viq_cnt++; + break; + case 6: + case 7: + pxmitpriv->voq_cnt++; + break; + case 0: + case 3: + default: + pxmitpriv->beq_cnt++; + break; + } + + + _exit_critical(&pxmitpriv->lock, &irqL); +*/ + + purb = pxmitbuf->pxmit_urb[0]; + +#if 0 + if(pdvobj->ishighspeed) + { + if(cnt> 0 && cnt%512 == 0) + { + //DBG_8192C("ishighspeed, cnt=%d\n", cnt); + bwritezero = _TRUE; + } + } + else + { + if(cnt > 0 && cnt%64 == 0) + { + //DBG_8192C("cnt=%d\n", cnt); + bwritezero = _TRUE; + } + } +#endif + + //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; + //DBG_8192C("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 + +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX + purb->transfer_dma = pxmitbuf->dma_transfer_addr; + purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + purb->transfer_flags |= URB_ZERO_PACKET; +#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX + +#if 0 + if (bwritezero) + { + purb->transfer_flags |= URB_ZERO_PACKET; + } +#endif + + if (timeout_ms >= 0) { + init_completion(&pxmitbuf->done); + pxmitbuf->isSync = _TRUE; + } else { + pxmitbuf->isSync = _FALSE; + } + pxmitbuf->status = 0; + + status = usb_submit_urb(purb, GFP_ATOMIC); + if (!status) + { + ret= _SUCCESS; + #ifdef DBG_CONFIG_ERROR_DETECT + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + pHalData->srestpriv.last_tx_time = rtw_get_current_time(); + } + #endif + } + else + { + DBG_871X("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)); + rtw_free_xmitbuf(pxmitpriv, pxmitbuf); + ret= _FAIL; + } + +// 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); + } +*/ + + // synchronous write handling + if(pxmitbuf->isSync == _TRUE && ret == _SUCCESS) { + unsigned long expire = timeout_ms ? msecs_to_jiffies(timeout_ms) : MAX_SCHEDULE_TIMEOUT; + int status; + + if (!wait_for_completion_timeout(&pxmitbuf->done, expire)) { + usb_kill_urb(purb); + status = (pxmitbuf->status == -ENOENT ? -ETIMEDOUT : pxmitbuf->status); + } else { + status = pxmitbuf->status; + } + + if (!status) { + ret= _SUCCESS; + } else { + DBG_871X("usb_write_port sync, status=%d\n", status); + ret = _FAIL; + } + rtw_free_xmitbuf(pxmitpriv, pxmitbuf); + } + + RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n")); + +_func_exit_; + + return ret; + +} + +inline u32 usb_write_port_async(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) +{ + return usb_write_port(pintfhdl, addr, cnt, wmem, -1); +} + +inline int usb_write_port_sync(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) +{ + return usb_write_port(pintfhdl, addr, cnt, wmem, RTW_USB_BULKOUT_TIMEOUT); +} + +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_871X("%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++; + } +} + |