Path: blob/master/ALFA-W1F1/RTL8814AU/hal/hal_hci/hal_usb.c
1307 views
/******************************************************************************1*2* Copyright(c) 2007 - 2017 Realtek Corporation.3*4* This program is free software; you can redistribute it and/or modify it5* under the terms of version 2 of the GNU General Public License as6* published by the Free Software Foundation.7*8* This program is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for11* more details.12*13*****************************************************************************/14#define _HAL_USB_C_1516#include <drv_types.h>17#include <hal_data.h>1819int usb_init_recv_priv(_adapter *padapter, u16 ini_in_buf_sz)20{21struct recv_priv *precvpriv = &padapter->recvpriv;22int i, res = _SUCCESS;23struct recv_buf *precvbuf;2425#ifdef PLATFORM_LINUX26tasklet_init(&precvpriv->recv_tasklet,27(void(*))usb_recv_tasklet,28(unsigned long)padapter);29#endif /* PLATFORM_LINUX */3031#ifdef PLATFORM_FREEBSD32#ifdef CONFIG_RX_INDICATE_QUEUE33TASK_INIT(&precvpriv->rx_indicate_tasklet, 0, rtw_rx_indicate_tasklet, padapter);34#endif /* CONFIG_RX_INDICATE_QUEUE */35#endif /* PLATFORM_FREEBSD */3637#ifdef CONFIG_USB_INTERRUPT_IN_PIPE38#ifdef PLATFORM_LINUX39precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);40if (precvpriv->int_in_urb == NULL) {41res = _FAIL;42RTW_INFO("alloc_urb for interrupt in endpoint fail !!!!\n");43goto exit;44}45#endif /* PLATFORM_LINUX */46precvpriv->int_in_buf = rtw_zmalloc(ini_in_buf_sz);47if (precvpriv->int_in_buf == NULL) {48res = _FAIL;49RTW_INFO("alloc_mem for interrupt in endpoint fail !!!!\n");50goto exit;51}52#endif /* CONFIG_USB_INTERRUPT_IN_PIPE */5354/* init recv_buf */55_rtw_init_queue(&precvpriv->free_recv_buf_queue);56_rtw_init_queue(&precvpriv->recv_buf_pending_queue);57#ifndef CONFIG_USE_USB_BUFFER_ALLOC_RX58/* this is used only when RX_IOBUF is sk_buff */59skb_queue_head_init(&precvpriv->free_recv_skb_queue);60#endif6162RTW_INFO("NR_RECVBUFF: %d\n", NR_RECVBUFF);63RTW_INFO("MAX_RECVBUF_SZ: %d\n", MAX_RECVBUF_SZ);64precvpriv->pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4);65if (precvpriv->pallocated_recv_buf == NULL) {66res = _FAIL;67goto exit;68}6970precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);7172precvbuf = (struct recv_buf *)precvpriv->precv_buf;7374for (i = 0; i < NR_RECVBUFF ; i++) {75_rtw_init_listhead(&precvbuf->list);7677_rtw_spinlock_init(&precvbuf->recvbuf_lock);7879precvbuf->alloc_sz = MAX_RECVBUF_SZ;8081res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);82if (res == _FAIL)83break;8485precvbuf->ref_cnt = 0;86precvbuf->adapter = padapter;8788/* rtw_list_insert_tail(&precvbuf->list, &(precvpriv->free_recv_buf_queue.queue)); */8990precvbuf++;91}9293precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;9495#if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD)9697skb_queue_head_init(&precvpriv->rx_skb_queue);9899#ifdef CONFIG_RX_INDICATE_QUEUE100memset(&precvpriv->rx_indicate_queue, 0, sizeof(struct ifqueue));101mtx_init(&precvpriv->rx_indicate_queue.ifq_mtx, "rx_indicate_queue", NULL, MTX_DEF);102#endif /* CONFIG_RX_INDICATE_QUEUE */103104#ifdef CONFIG_PREALLOC_RECV_SKB105{106int i;107SIZE_PTR tmpaddr = 0;108SIZE_PTR alignment = 0;109struct sk_buff *pskb = NULL;110111RTW_INFO("NR_PREALLOC_RECV_SKB: %d\n", NR_PREALLOC_RECV_SKB);112#ifdef CONFIG_FIX_NR_BULKIN_BUFFER113RTW_INFO("Enable CONFIG_FIX_NR_BULKIN_BUFFER\n");114#endif115116for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {117#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER118pskb = rtw_alloc_skb_premem(MAX_RECVBUF_SZ);119#else120pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);121#endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */122123if (pskb) {124#ifdef PLATFORM_FREEBSD125pskb->dev = padapter->pifp;126#else127pskb->dev = padapter->pnetdev;128#endif /* PLATFORM_FREEBSD */129130#ifndef CONFIG_PREALLOC_RX_SKB_BUFFER131tmpaddr = (SIZE_PTR)pskb->data;132alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);133skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));134#endif135skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);136}137}138}139#endif /* CONFIG_PREALLOC_RECV_SKB */140141#endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) */142143exit:144145return res;146}147148void usb_free_recv_priv(_adapter *padapter, u16 ini_in_buf_sz)149{150int i;151struct recv_buf *precvbuf;152struct recv_priv *precvpriv = &padapter->recvpriv;153154precvbuf = (struct recv_buf *)precvpriv->precv_buf;155156for (i = 0; i < NR_RECVBUFF ; i++) {157rtw_os_recvbuf_resource_free(padapter, precvbuf);158precvbuf++;159}160161if (precvpriv->pallocated_recv_buf)162rtw_mfree(precvpriv->pallocated_recv_buf, NR_RECVBUFF * sizeof(struct recv_buf) + 4);163164#ifdef CONFIG_USB_INTERRUPT_IN_PIPE165#ifdef PLATFORM_LINUX166if (precvpriv->int_in_urb)167usb_free_urb(precvpriv->int_in_urb);168#endif169if (precvpriv->int_in_buf)170rtw_mfree(precvpriv->int_in_buf, ini_in_buf_sz);171#endif /* CONFIG_USB_INTERRUPT_IN_PIPE */172173#ifdef PLATFORM_LINUX174175if (skb_queue_len(&precvpriv->rx_skb_queue))176RTW_WARN("rx_skb_queue not empty\n");177178rtw_skb_queue_purge(&precvpriv->rx_skb_queue);179180if (skb_queue_len(&precvpriv->free_recv_skb_queue))181RTW_WARN("free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue));182183#if !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX)184#if defined(CONFIG_PREALLOC_RECV_SKB) && defined(CONFIG_PREALLOC_RX_SKB_BUFFER)185{186struct sk_buff *skb;187188while ((skb = skb_dequeue(&precvpriv->free_recv_skb_queue)) != NULL) {189if (rtw_free_skb_premem(skb) != 0)190rtw_skb_free(skb);191}192}193#else194rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue);195#endif /* defined(CONFIG_PREALLOC_RX_SKB_BUFFER) && defined(CONFIG_PREALLOC_RECV_SKB) */196#endif /* !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX) */197198#endif /* PLATFORM_LINUX */199200#ifdef PLATFORM_FREEBSD201struct sk_buff *pskb;202while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue)))203rtw_skb_free(pskb);204205#if !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX)206rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue);207#endif208209#ifdef CONFIG_RX_INDICATE_QUEUE210struct mbuf *m;211for (;;) {212IF_DEQUEUE(&precvpriv->rx_indicate_queue, m);213if (m == NULL)214break;215rtw_os_pkt_free(m);216}217mtx_destroy(&precvpriv->rx_indicate_queue.ifq_mtx);218#endif /* CONFIG_RX_INDICATE_QUEUE */219220#endif /* PLATFORM_FREEBSD */221}222223#ifdef CONFIG_FW_C2H_REG224void usb_c2h_hisr_hdl(_adapter *adapter, u8 *buf)225{226u8 *c2h_evt = buf;227u8 id, seq, plen;228u8 *payload;229230if (rtw_hal_c2h_reg_hdr_parse(adapter, buf, &id, &seq, &plen, &payload) != _SUCCESS)231return;232233if (0)234RTW_PRINT("%s C2H == %d\n", __func__, id);235236if (rtw_hal_c2h_id_handle_directly(adapter, id, seq, plen, payload)) {237/* Handle directly */238rtw_hal_c2h_handler(adapter, id, seq, plen, payload);239240/* Replace with special pointer to trigger c2h_evt_clear only */241if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)&adapter->evtpriv) != _SUCCESS)242RTW_ERR("%s rtw_cbuf_push fail\n", __func__);243} else {244c2h_evt = rtw_malloc(C2H_REG_LEN);245if (c2h_evt != NULL) {246_rtw_memcpy(c2h_evt, buf, C2H_REG_LEN);247if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)c2h_evt) != _SUCCESS)248RTW_ERR("%s rtw_cbuf_push fail\n", __func__);249} else {250/* Error handling for malloc fail */251if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)NULL) != _SUCCESS)252RTW_ERR("%s rtw_cbuf_push fail\n", __func__);253}254}255_set_workitem(&adapter->evtpriv.c2h_wk);256}257#endif258259#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ260int usb_write_async(struct usb_device *udev, u32 addr, void *pdata, u16 len)261{262u8 request;263u8 requesttype;264u16 wvalue;265u16 index;266int ret;267268requesttype = VENDOR_WRITE;/* write_out */269request = REALTEK_USB_VENQT_CMD_REQ;270index = REALTEK_USB_VENQT_CMD_IDX;/* n/a */271272wvalue = (u16)(addr & 0x0000ffff);273274ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, index, pdata, len, requesttype);275276return ret;277}278279int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)280{281u8 data;282int ret;283struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;284struct usb_device *udev = pdvobjpriv->pusbdev;285286data = val;287ret = usb_write_async(udev, addr, &data, 1);288289return ret;290}291292int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)293{294u16 data;295int ret;296struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;297struct usb_device *udev = pdvobjpriv->pusbdev;298299data = val;300ret = usb_write_async(udev, addr, &data, 2);301302return ret;303}304305int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)306{307u32 data;308int ret;309struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;310struct usb_device *udev = pdvobjpriv->pusbdev;311312data = val;313ret = usb_write_async(udev, addr, &data, 4);314315return ret;316}317#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */318319u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)320{321u8 request;322u8 requesttype;323u16 wvalue;324u16 index;325u16 len;326u8 data = 0;327328329request = 0x05;330requesttype = 0x01;/* read_in */331index = 0;/* n/a */332333wvalue = (u16)(addr & 0x0000ffff);334len = 1;335336/* WLANON PAGE0_REG needs to add an offset 0x8000 */337#if defined(CONFIG_RTL8710B)338if(wvalue >= 0x0000 && wvalue < 0x0100)339wvalue |= 0x8000;340#endif341342usbctrl_vendorreq(pintfhdl, request, wvalue, index,343&data, len, requesttype);344345346return data;347}348349u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)350{351u8 request;352u8 requesttype;353u16 wvalue;354u16 index;355u16 len;356u16 data = 0;357358359request = 0x05;360requesttype = 0x01;/* read_in */361index = 0;/* n/a */362363wvalue = (u16)(addr & 0x0000ffff);364len = 2;365366/* WLANON PAGE0_REG needs to add an offset 0x8000 */367#if defined(CONFIG_RTL8710B)368if(wvalue >= 0x0000 && wvalue < 0x0100)369wvalue |= 0x8000;370#endif371372usbctrl_vendorreq(pintfhdl, request, wvalue, index,373&data, len, requesttype);374375376return data;377378}379380u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)381{382u8 request;383u8 requesttype;384u16 wvalue;385u16 index;386u16 len;387u32 data = 0;388389390request = 0x05;391requesttype = 0x01;/* read_in */392index = 0;/* n/a */393394wvalue = (u16)(addr & 0x0000ffff);395len = 4;396397/* WLANON PAGE0_REG needs to add an offset 0x8000 */398#if defined(CONFIG_RTL8710B)399if(wvalue >= 0x0000 && wvalue < 0x0100)400wvalue |= 0x8000;401#endif402403usbctrl_vendorreq(pintfhdl, request, wvalue, index,404&data, len, requesttype);405406407return data;408}409410int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)411{412u8 request;413u8 requesttype;414u16 wvalue;415u16 index;416u16 len;417u8 data;418int ret;419420421request = 0x05;422requesttype = 0x00;/* write_out */423index = 0;/* n/a */424425wvalue = (u16)(addr & 0x0000ffff);426len = 1;427data = val;428429/* WLANON PAGE0_REG needs to add an offset 0x8000 */430#if defined(CONFIG_RTL8710B)431if(wvalue >= 0x0000 && wvalue < 0x0100)432wvalue |= 0x8000;433#endif434435ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,436&data, len, requesttype);437438439return ret;440}441442int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)443{444u8 request;445u8 requesttype;446u16 wvalue;447u16 index;448u16 len;449u16 data;450int ret;451452453request = 0x05;454requesttype = 0x00;/* write_out */455index = 0;/* n/a */456457wvalue = (u16)(addr & 0x0000ffff);458len = 2;459data = val;460461/* WLANON PAGE0_REG needs to add an offset 0x8000 */462#if defined(CONFIG_RTL8710B)463if(wvalue >= 0x0000 && wvalue < 0x0100)464wvalue |= 0x8000;465#endif466467ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,468&data, len, requesttype);469470471return ret;472473}474475int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)476{477u8 request;478u8 requesttype;479u16 wvalue;480u16 index;481u16 len;482u32 data;483int ret;484485486request = 0x05;487requesttype = 0x00;/* write_out */488index = 0;/* n/a */489490wvalue = (u16)(addr & 0x0000ffff);491len = 4;492data = val;493494/* WLANON PAGE0_REG needs to add an offset 0x8000 */495#if defined(CONFIG_RTL8710B)496if(wvalue >= 0x0000 && wvalue < 0x0100)497wvalue |= 0x8000;498#endif499500ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,501&data, len, requesttype);502503504return ret;505506}507508int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata)509{510u8 request;511u8 requesttype;512u16 wvalue;513u16 index;514u16 len;515u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};516int ret;517518519request = 0x05;520requesttype = 0x00;/* write_out */521index = 0;/* n/a */522523wvalue = (u16)(addr & 0x0000ffff);524len = length;525_rtw_memcpy(buf, pdata, len);526ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,527buf, len, requesttype);528529530return ret;531}532533void usb_set_intf_ops(_adapter *padapter, struct _io_ops *pops)534{535_rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops));536537pops->_read8 = &usb_read8;538pops->_read16 = &usb_read16;539pops->_read32 = &usb_read32;540pops->_read_mem = &usb_read_mem;541pops->_read_port = &usb_read_port;542543pops->_write8 = &usb_write8;544pops->_write16 = &usb_write16;545pops->_write32 = &usb_write32;546pops->_writeN = &usb_writeN;547548#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ549pops->_write8_async = &usb_async_write8;550pops->_write16_async = &usb_async_write16;551pops->_write32_async = &usb_async_write32;552#endif553pops->_write_mem = &usb_write_mem;554pops->_write_port = &usb_write_port;555556pops->_read_port_cancel = &usb_read_port_cancel;557pops->_write_port_cancel = &usb_write_port_cancel;558559#ifdef CONFIG_USB_INTERRUPT_IN_PIPE560pops->_read_interrupt = &usb_read_interrupt;561#endif562563}564565566