|
@@ -475,6 +475,8 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
|
|
|
(void *)rtl_swlps_rfon_wq_callback);
|
|
|
INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq,
|
|
|
(void *)rtl_fwevt_wq_callback);
|
|
|
+ INIT_DELAYED_WORK(&rtlpriv->works.c2hcmd_wq,
|
|
|
+ (void *)rtl_c2hcmd_wq_callback);
|
|
|
|
|
|
}
|
|
|
|
|
@@ -489,6 +491,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
|
|
|
cancel_delayed_work(&rtlpriv->works.ps_work);
|
|
|
cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
|
|
|
cancel_delayed_work(&rtlpriv->works.fwevt_wq);
|
|
|
+ cancel_delayed_work(&rtlpriv->works.c2hcmd_wq);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
|
|
|
|
|
@@ -556,6 +559,7 @@ int rtl_init_core(struct ieee80211_hw *hw)
|
|
|
spin_lock_init(&rtlpriv->locks.rf_lock);
|
|
|
spin_lock_init(&rtlpriv->locks.waitq_lock);
|
|
|
spin_lock_init(&rtlpriv->locks.entry_list_lock);
|
|
|
+ spin_lock_init(&rtlpriv->locks.c2hcmd_lock);
|
|
|
spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
|
|
|
spin_lock_init(&rtlpriv->locks.check_sendpkt_lock);
|
|
|
spin_lock_init(&rtlpriv->locks.fw_ps_lock);
|
|
@@ -563,6 +567,7 @@ int rtl_init_core(struct ieee80211_hw *hw)
|
|
|
spin_lock_init(&rtlpriv->locks.iqk_lock);
|
|
|
/* <5> init list */
|
|
|
INIT_LIST_HEAD(&rtlpriv->entry_list);
|
|
|
+ INIT_LIST_HEAD(&rtlpriv->c2hcmd_list);
|
|
|
|
|
|
rtlmac->link_state = MAC80211_NOLINK;
|
|
|
|
|
@@ -575,6 +580,7 @@ EXPORT_SYMBOL_GPL(rtl_init_core);
|
|
|
|
|
|
void rtl_deinit_core(struct ieee80211_hw *hw)
|
|
|
{
|
|
|
+ rtl_c2hcmd_launcher(hw, 0);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(rtl_deinit_core);
|
|
|
|
|
@@ -1729,6 +1735,93 @@ void rtl_fwevt_wq_callback(void *data)
|
|
|
|
|
|
rtlpriv->cfg->ops->c2h_command_handle(hw);
|
|
|
}
|
|
|
+
|
|
|
+void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val)
|
|
|
+{
|
|
|
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
+ unsigned long flags;
|
|
|
+ struct rtl_c2hcmd *c2hcmd;
|
|
|
+
|
|
|
+ c2hcmd = kmalloc(sizeof(*c2hcmd), GFP_KERNEL);
|
|
|
+
|
|
|
+ if (!c2hcmd)
|
|
|
+ goto label_err;
|
|
|
+
|
|
|
+ c2hcmd->val = kmalloc(len, GFP_KERNEL);
|
|
|
+
|
|
|
+ if (!c2hcmd->val)
|
|
|
+ goto label_err2;
|
|
|
+
|
|
|
+ /* fill data */
|
|
|
+ c2hcmd->tag = tag;
|
|
|
+ c2hcmd->len = len;
|
|
|
+ memcpy(c2hcmd->val, val, len);
|
|
|
+
|
|
|
+ /* enqueue */
|
|
|
+ spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags);
|
|
|
+
|
|
|
+ list_add_tail(&c2hcmd->list, &rtlpriv->c2hcmd_list);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags);
|
|
|
+
|
|
|
+ /* wake up wq */
|
|
|
+ queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.c2hcmd_wq, 0);
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+label_err2:
|
|
|
+ kfree(c2hcmd);
|
|
|
+
|
|
|
+label_err:
|
|
|
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_WARNING,
|
|
|
+ "C2H cmd enqueue fail.\n");
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(rtl_c2hcmd_enqueue);
|
|
|
+
|
|
|
+void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec)
|
|
|
+{
|
|
|
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
+ unsigned long flags;
|
|
|
+ struct rtl_c2hcmd *c2hcmd;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < 200; i++) {
|
|
|
+ /* dequeue a task */
|
|
|
+ spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags);
|
|
|
+
|
|
|
+ c2hcmd = list_first_entry_or_null(&rtlpriv->c2hcmd_list,
|
|
|
+ struct rtl_c2hcmd, list);
|
|
|
+
|
|
|
+ if (c2hcmd)
|
|
|
+ list_del(&c2hcmd->list);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags);
|
|
|
+
|
|
|
+ /* do it */
|
|
|
+ if (!c2hcmd)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (rtlpriv->cfg->ops->c2h_content_parsing && exec)
|
|
|
+ rtlpriv->cfg->ops->c2h_content_parsing(hw,
|
|
|
+ c2hcmd->tag, c2hcmd->len, c2hcmd->val);
|
|
|
+
|
|
|
+ /* free */
|
|
|
+ kfree(c2hcmd->val);
|
|
|
+
|
|
|
+ kfree(c2hcmd);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void rtl_c2hcmd_wq_callback(void *data)
|
|
|
+{
|
|
|
+ struct rtl_works *rtlworks = container_of_dwork_rtl(data,
|
|
|
+ struct rtl_works,
|
|
|
+ c2hcmd_wq);
|
|
|
+ struct ieee80211_hw *hw = rtlworks->hw;
|
|
|
+
|
|
|
+ rtl_c2hcmd_launcher(hw, 1);
|
|
|
+}
|
|
|
+
|
|
|
void rtl_easy_concurrent_retrytimer_callback(unsigned long data)
|
|
|
{
|
|
|
struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
|