summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/eswin/usb/ecrnx_usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/eswin/usb/ecrnx_usb.c')
-rw-r--r--drivers/net/wireless/eswin/usb/ecrnx_usb.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/drivers/net/wireless/eswin/usb/ecrnx_usb.c b/drivers/net/wireless/eswin/usb/ecrnx_usb.c
new file mode 100644
index 000000000000..4bfe655e5505
--- /dev/null
+++ b/drivers/net/wireless/eswin/usb/ecrnx_usb.c
@@ -0,0 +1,447 @@
+/**
+ ******************************************************************************
+ *
+ * @file ecrnx_usb.c
+ *
+ * @brief ECRNX usb init and management function
+ *
+ * Copyright (C) ESWIN 2015-2020
+ *
+ ******************************************************************************
+ */
+
+#include <linux/module.h>
+#include <linux/kthread.h>
+
+#include "core.h"
+//#include "debug.h"
+#include "ecrnx_utils.h"
+#include "ecrnx_cmds.h"
+#include "ecrnx_defs.h"
+#include "ecrnx_msg_rx.h"
+#include "ipc_host.h"
+#include "ipc_shared.h"
+#include "ecrnx_events.h"
+#include "ecrnx_usb.h"
+#ifdef CONFIG_TEST_ESWIN_USB
+#include "debug.h"
+#endif
+#ifdef CONFIG_ECRNX_WIFO_CAIL
+#include "ecrnx_amt.h"
+#endif
+
+
+#define USB_ADDR_DATA (unsigned int)(0x200)
+
+#ifdef CONFIG_ECRNX_SOFTMAC
+#define FW_STR "lmac"
+#elif defined CONFIG_ECRNX_FULLMAC
+#define FW_STR "fmac"
+#endif
+
+#if defined(CONFIG_ECRNX_DEBUGFS_CUSTOM)
+#include "ecrnx_debugfs_func.h"
+#endif
+
+extern const int nx_txdesc_cnt_msk[];
+
+struct vendor_radiotap_hdr {
+ u8 oui[3];
+ u8 subns;
+ u16 len;
+ u8 data[];
+};
+
+#ifdef CONFIG_WEXT_PRIV
+extern void priv_copy_data_wakeup(struct ecrnx_hw *ecrnx_hw, struct sk_buff *skb);
+#endif
+
+/**
+ * @brief: ipc_host_rxdesc_handler: Handle the reception of a Rx Descriptor
+ * Called from general IRQ handler when status %IPC_IRQ_E2A_RXDESC is set
+ * @param {env} pointer to the usb Host environment
+ * @param {skb} received skb data
+ * @return: none
+ */
+static int usb_host_rxdesc_handler(struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ u8 ret = 0;
+ // LMAC has triggered an IT saying that a reception has occurred.
+ // Then we first need to check the validity of the current hostbuf, and the validity
+ // of the next hostbufs too, because it is likely that several hostbufs have been
+ // filled within the time needed for this irq handling
+#ifdef CONFIG_ECRNX_FULLMAC
+ // call the external function to indicate that a RX descriptor is received
+ ret = env->cb.recv_data_ind(env->pthis, skb);
+#else
+ // call the external function to indicate that a RX packet is received
+ ret = env->cb.recv_data_ind(env->pthis, skb);
+#endif //(CONFIG_ECRNX_FULLMAC)
+ //ECRNX_DBG("%s exit!!", __func__);
+ return ret;
+}
+
+/**
+ * @brief: usb_host_radar_handler Handle the reception of radar events
+ * @param {env} pointer to the usb Host environment
+ * @param {skb} received skb data
+ * @return: none
+ */
+static int usb_host_radar_handler(struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ int ret = 0;
+
+#ifdef CONFIG_ECRNX_RADAR
+ // LMAC has triggered an IT saying that a radar event has been sent to upper layer.
+ // Then we first need to check the validity of the current msg buf, and the validity
+ // of the next buffers too, because it is likely that several buffers have been
+ // filled within the time needed for this irq handling
+ // call the external function to indicate that a RX packet is received
+ spin_lock(&((struct ecrnx_hw *)env->pthis)->radar.lock);
+ ret = env->cb.recv_radar_ind(env->pthis, skb);
+ spin_unlock(&((struct ecrnx_hw *)env->pthis)->radar.lock);
+#endif /* CONFIG_ECRNX_RADAR */
+ return ret;
+}
+
+/**
+ * @brief: usb_host_unsup_rx_vec_handler Handle the reception of unsupported rx vector
+ * @param {env} pointer to the usb Host environment
+ * @param {skb} received skb data
+ * @return: none
+ */
+static int usb_host_unsup_rx_vec_handler(struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ return env->cb.recv_unsup_rx_vec_ind(env->pthis, skb);
+}
+
+/**
+ * @brief: usb_host_msg_handler Handler for firmware message
+ * @param {env} pointer to the usb Host environment
+ * @param {skb} received skb data
+ * @return: none
+ */
+static int usb_host_msg_handler(struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ // LMAC has triggered an IT saying that a message has been sent to upper layer.
+ // Then we first need to check the validity of the current msg buf, and the validity
+ // of the next buffers too, because it is likely that several buffers have been
+ // filled within the time needed for this irq handling
+ // call the external function to indicate that a RX packet is received
+ return env->cb.recv_msg_ind(env->pthis, skb->data);
+}
+
+/**
+ * @brief: usb_host_msgack_handler Handle the reception of message acknowledgement
+ * @param {env} pointer to the usb Host environment
+ * @param {skb} received skb data
+ * @return: none
+ */
+static int usb_host_msgack_handler(struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ ptr_addr hostid = *(ptr_addr *)skb->data;
+
+ ASSERT_ERR(hostid);
+
+ env->msga2e_hostid = NULL;
+ env->cb.recv_msgack_ind(env->pthis, (void*)hostid);
+
+ return 0;
+}
+
+/**
+ * @brief: usb_host_dbg_handler Handle the reception of Debug event
+ * @param {env} pointer to the usb Host environment
+ * @param {skb} received skb data
+ * @return: none
+ */
+static int usb_host_dbg_handler(struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ // LMAC has triggered an IT saying that a DBG message has been sent to upper layer.
+ // Then we first need to check the validity of the current buffer, and the validity
+ // of the next buffers too, because it is likely that several buffers have been
+ // filled within the time needed for this irq handling
+ // call the external function to indicate that a RX packet is received
+ return env->cb.recv_dbg_ind(env->pthis, skb);
+}
+
+/**
+ * @brief: usb_host_tx_cfm_handler Handle the reception of TX confirmation
+ * @param {env} pointer to the usb Host environment
+ * @param {queue_idx} index of the hardware on which the confirmation has been received
+ * @param {user_pos} index of the user position
+ * @return: none
+ */
+static int usb_host_tx_cfm_handler(struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ ptr_addr host_id;
+ struct sk_buff *skb_cfm;
+ struct ecrnx_txhdr *txhdr;
+
+#ifdef CONFIG_ECRNX_FULLMAC
+ struct tx_cfm_tag *cfm;
+
+ cfm = (struct tx_cfm_tag *)skb->data;
+ //host_id = cfm->hostid;
+ memcpy((uint8_t *)&host_id, (uint8_t *)cfm->hostid, sizeof(ptr_addr));
+ if (host_id == 0) {
+ return 0;
+ }
+
+ ECRNX_DBG("%s:hostid(tx_skb):0x%08x, rx_skb: 0x%x \n", __func__, host_id, skb);
+ skb_cfm = (struct sk_buff *)host_id;
+ txhdr = (struct ecrnx_txhdr *)(*((ptr_addr*)skb_cfm->data - 1));
+ memcpy(&txhdr->hw_hdr.cfm, cfm, sizeof(*cfm));
+#elif defined CONFIG_ECRNX_SOFTMAC
+ //TODO:
+#endif
+
+ return env->cb.send_data_cfm(env->pthis, (void*)txhdr);
+}
+
+#ifdef CONFIG_ECRNX_WIFO_CAIL
+/**
+ * @brief: usb_host_amt_rx_handler Handle the reception of rx frame
+ * @param {frm_type} received frame type
+ * @param {skb} received skb data
+ * @return: none
+ */
+void usb_host_amt_rx_handler(uint32_t frm_type, struct sk_buff *skb)
+{
+ int need_free = 0;
+
+ ECRNX_DBG("%s enter, frame type: %d!!", __func__, frm_type);
+ if(!skb)
+ {
+ ECRNX_ERR("usb_host_amt_rx_handler input param error!! \n!");
+ return;
+ }
+
+ if (frm_type != USB_FRM_TYPE_RXDESC)
+ {
+ skb_pull(skb, SKB_DATA_COM_HD_OFFSET); //delete the frame common header
+ }
+
+ ECRNX_DBG("skb:0x%08x, skb_len:%d, frame type: %d!!", skb->data,skb->len, frm_type);
+
+ switch (frm_type)
+ {
+ case USB_FRM_TYPE_IWPRIV:
+ {
+ /*printk("vif_start:%d, vif_monitor:%d \n", ecrnx_hw->vif_started, ecrnx_hw->monitor_vif);
+ print_hex_dump(KERN_INFO, "iwpriv-cfm:", DUMP_PREFIX_ADDRESS, 32, 1,
+ skb->data, skb->len, false);*/
+ amt_vif.rxlen = skb->len;
+ memset(amt_vif.rxdata, 0, ECRNX_RXSIZE);
+ memcpy(amt_vif.rxdata, skb->data, skb->len);
+ amt_vif.rxdatas = 1;
+ wake_up(&amt_vif.rxdataq);
+ need_free = 1;
+ break;
+ }
+ default:
+ need_free = 1;
+ break;
+ }
+
+ if (need_free && skb) { // free the skb
+ ECRNX_DBG("skb free: 0x%x !! \n", skb);
+ dev_kfree_skb(skb);
+ }
+ ECRNX_DBG("%s exit!!", __func__);
+ return;
+}
+#endif
+
+
+/**
+ * @brief: usb_host_rx_handler Handle the reception of rx frame
+ * @param {frm_type} received frame type
+ * @param {env} pointer to the usb Host environment
+ * @param {skb} received skb data
+ * @return: none
+ */
+void usb_host_rx_handler(uint32_t frm_type, struct ipc_host_env_tag *env, struct sk_buff *skb)
+{
+ int ret = 1;
+
+ //ECRNX_DBG("%s enter, frame type: %d!!", __func__, frm_type);
+ if(!env || !skb)
+ {
+ ECRNX_ERR("usb_host_rx_handler input param error!! \n!");
+ return;
+ }
+
+ ((struct ecrnx_hw *)env->pthis)->usb_rx++;
+
+ if (frm_type != USB_FRM_TYPE_RXDESC)
+ {
+ skb_pull(skb, SKB_DATA_COM_HD_OFFSET); //delete the frame common header
+ }
+
+ //ECRNX_DBG("skb:0x%08x, skb_len:%d, frame type: %d!!", skb->data,skb->len, frm_type);
+
+ switch (frm_type)
+ {
+ case USB_FRM_TYPE_RXDESC:
+ {
+ // handle the RX descriptor reception
+ usb_host_rxdesc_handler(env, skb); //just for current only one endpoint test
+ break;
+ }
+
+ case USB_FRM_TYPE_MSG_ACK:
+ {
+ if(1 == skb->len)
+ {
+ ECRNX_PRINT("MSG_ACK len: 1");
+ break;
+ }
+ ret = usb_host_msgack_handler(env, skb);
+ break;
+ }
+
+ case USB_FRM_TYPE_MSG:
+ {
+ ret = usb_host_msg_handler(env, skb);
+ break;
+ }
+
+ case USB_FRM_TYPE_TXCFM:
+ {
+ if(!env->pthis)
+ {
+ ECRNX_ERR("env->pthis ptr error!! \n!");
+ break;
+ }
+
+ /* add the spinlock which was missed during porting.
+ when skb->len more than 24 and skb contans more than one data cfm.
+ data cfm structure length is 24 byte.
+ */
+ spin_lock_bh(&((struct ecrnx_hw *)env->pthis)->tx_lock);
+ while(skb->len > sizeof(struct tx_cfm_tag))
+ {
+ ret = usb_host_tx_cfm_handler(env, skb);
+ skb_pull(skb, sizeof(struct tx_cfm_tag));
+ }
+ ret = usb_host_tx_cfm_handler(env, skb);
+ spin_unlock_bh(&((struct ecrnx_hw *)env->pthis)->tx_lock);
+ break;
+ }
+
+ case USB_FRM_TYPE_UNSUP_RX_VEC:
+ {
+ // handle the unsupported rx vector reception
+ ret = usb_host_unsup_rx_vec_handler(env, skb);
+ break;
+ }
+
+ case USB_FRM_TYPE_RADAR:
+ {
+ // handle the radar event reception
+ ret = usb_host_radar_handler(env, skb);
+ break;
+ }
+
+ case USB_FRM_TYPE_TBTT_SEC:
+ {
+ env->cb.sec_tbtt_ind(env->pthis);
+ break;
+ }
+
+ case USB_FRM_TYPE_TBTT_PRIM:
+ {
+ env->cb.prim_tbtt_ind(env->pthis);
+ break;
+ }
+
+ case USB_FRM_TYPE_DBG:
+ {
+ ECRNX_DBG("--%s:USB_FRM_TYPE_DBG, len:%d, slave:%s \n", __func__, skb->len, skb->data);
+ ret = usb_host_dbg_handler(env, skb);
+ break;
+ }
+ case USB_FRM_TYPE_IWPRIV:
+ {
+#ifdef CONFIG_WEXT_PRIV
+#if 0
+ struct ecrnx_hw *ecrnx_hw = (struct ecrnx_hw *)env->pthis;
+ struct ecrnx_vif* ecrnx_vif = ecrnx_hw->vif_table[0];
+
+ printk("vif_start:%d, vif_monitor:%d \n", ecrnx_hw->vif_started, ecrnx_hw->monitor_vif);
+ print_hex_dump(KERN_INFO, "iwpriv-cfm:", DUMP_PREFIX_ADDRESS, 32, 1,
+ skb->data, skb->len, false);
+ ecrnx_vif->rxlen = skb->len;
+ memcpy(ecrnx_vif->rxdata, skb->data, skb->len);
+ ecrnx_vif->rxdatas = 1;
+ wake_up(&ecrnx_vif->rxdataq);
+#else
+ priv_copy_data_wakeup((struct ecrnx_hw *)env->pthis, skb);
+#endif
+
+#endif
+ ret = 0;
+ break;
+ }
+
+#if defined(CONFIG_ECRNX_DEBUGFS_CUSTOM)
+ case USB_FRM_DEBUG_FS:
+ {
+ uint32_t debugfs_type = ((uint32_t*)skb->data)[0];
+ debugfs_resp.debugfs_type = debugfs_type;
+
+
+ if((debugfs_type != SLAVE_LOG_LEVEL) && \
+ (debugfs_type < SLAVE_DEBUGFS_MAX)){
+
+ debugfs_resp.rxlen = skb->len-4;
+ memcpy(debugfs_resp.rxdata, skb->data+4, debugfs_resp.rxlen);
+
+ ECRNX_DBG("%s - wake_up()\n", __func__);
+ debugfs_resp.rxdatas = 1;
+ wake_up(&debugfs_resp.rxdataq);
+ }
+
+ break;
+ }
+#endif
+ default:
+ ret = 0;
+ break;
+ }
+
+ if (!ret && skb) { // free the skb
+ ECRNX_DBG("skb free: 0x%x, ret: %d!! \n", skb, ret);
+ dev_kfree_skb(skb);
+ }
+ //ECRNX_DBG("%s exit!!", __func__);
+ return;
+}
+
+/**
+ * @brief: ecrnx_usb_init Initialize usb interface.
+ * @param {ecrnx_hw} Main driver data
+ * @return: u8
+ */
+u8 ecrnx_usb_init(struct ecrnx_hw *ecrnx_hw)
+{
+ ECRNX_DBG("%s entry!!", __func__);
+ // Save the pointer to the register base
+ ecrnx_hw->ipc_env->pthis = (void*)ecrnx_hw;
+
+ ECRNX_DBG("%s exit!!", __func__);
+ return 0;
+}
+
+/**
+ * @brief: ecrnx_usb_deinit DeInitialize usb interface.
+ * @param {ecrnx_hw} Main driver data
+ * @return: none
+ */
+void ecrnx_usb_deinit(struct ecrnx_hw *ecrnx_hw)
+{
+ ECRNX_DBG(ECRNX_FN_ENTRY_STR);
+
+ memset(ecrnx_hw, 0, sizeof(struct ecrnx_hw));
+}