1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
--- linux-2.6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ linux-2.6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -265,7 +265,6 @@ int rtl92c_download_fw(struct ieee80211_
if (!rtlhal->pfirmware)
return 1;
- pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
pfwdata = (u8 *) rtlhal->pfirmware;
fwsize = rtlhal->fwsize;
--- linux-2.6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ linux-2.6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -186,6 +186,7 @@ int rtl92c_init_sw_vars(struct ieee80211
memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
rtlpriv->rtlhal.fwsize = firmware->size;
release_firmware(firmware);
+ pr_info("rtl8192ce: Loaded firmware file %s\n", rtlpriv->cfg->fw_name);
return 0;
}
--- linux-2.6/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ linux-2.6/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -43,6 +43,8 @@
#include "hw.h"
#include <linux/vmalloc.h>
#include <linux/module.h>
+#include <linux/atomic.h>
+#include <linux/types.h>
MODULE_AUTHOR("Georgia <georgia@realtek.com>");
MODULE_AUTHOR("Ziv Huang <ziv_huang@realtek.com>");
@@ -51,6 +53,10 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n USB wireless");
MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin");
+static char *rtl8192cu_firmware; /* pointer to firmware */
+static int firmware_size;
+static atomic_t usage_count;
+
static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -62,12 +68,21 @@ static int rtl92cu_init_sw_vars(struct i
rtlpriv->dm.disable_framebursting = false;
rtlpriv->dm.thermalvalue = 0;
rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
- rtlpriv->rtlhal.pfirmware = vmalloc(0x4000);
- if (!rtlpriv->rtlhal.pfirmware) {
+
+ if (rtl8192cu_firmware) {
+ /* firmware already loaded - true for suspend/resume
+ * and multiple instances of the device */
+ rtlpriv->rtlhal.pfirmware = rtl8192cu_firmware;
+ rtlpriv->rtlhal.fwsize = firmware_size;
+ return 0;
+ }
+ rtl8192cu_firmware = vzalloc(0x4000);
+ if (!rtl8192cu_firmware) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("Can't alloc buffer for fw.\n"));
return 1;
}
+
/* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
rtlpriv->io.dev);
@@ -82,9 +97,14 @@ static int rtl92cu_init_sw_vars(struct i
release_firmware(firmware);
return 1;
}
- memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
+ pr_info("rtl8192cu: Loaded firmware from file %s\n",
+ rtlpriv->cfg->fw_name);
+ memcpy(rtl8192cu_firmware, firmware->data, firmware->size);
+ firmware_size = firmware->size;
rtlpriv->rtlhal.fwsize = firmware->size;
+ rtlpriv->rtlhal.pfirmware = rtl8192cu_firmware;
release_firmware(firmware);
+ atomic_inc(&usage_count);
return 0;
}
@@ -93,12 +113,30 @@ static void rtl92cu_deinit_sw_vars(struc
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- if (rtlpriv->rtlhal.pfirmware) {
- vfree(rtlpriv->rtlhal.pfirmware);
+ atomic_dec(&usage_count);
+ if (!atomic_read(&usage_count) && rtlpriv->rtlhal.pfirmware) {
+ vfree(rtl8192cu_firmware);
+ rtl8192cu_firmware = NULL;
rtlpriv->rtlhal.pfirmware = NULL;
}
}
+#ifdef CONFIG_PM_SLEEP
+static int rtl8192cu_usb_suspend(struct usb_interface *pusb_intf,
+ pm_message_t message)
+{
+ /* Increase usage_count to Save loaded fw across suspend/resume */
+ atomic_inc(&usage_count);
+ return 0;
+}
+
+static int rtl8192cu_usb_resume(struct usb_interface *pusb_intf)
+{
+ atomic_dec(&usage_count); /* after resume, decrease usage count */
+ return 0;
+}
+#endif
+
static struct rtl_hal_ops rtl8192cu_hal_ops = {
.init_sw_vars = rtl92cu_init_sw_vars,
.deinit_sw_vars = rtl92cu_deinit_sw_vars,
@@ -374,11 +412,10 @@ static struct usb_driver rtl8192cu_drive
.disconnect = rtl_usb_disconnect,
.id_table = rtl8192c_usb_ids,
-#ifdef CONFIG_PM
- /* .suspend = rtl_usb_suspend, */
- /* .resume = rtl_usb_resume, */
- /* .reset_resume = rtl8192c_resume, */
-#endif /* CONFIG_PM */
+#ifdef CONFIG_PM_SLEEP
+ .suspend = rtl8192cu_usb_suspend,
+ .resume = rtl8192cu_usb_resume,
+#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_AUTOSUSPEND
.supports_autosuspend = 1,
#endif
|