1 /*
2 * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
3 * Copyright (c) 2015 iComm Corporation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <ssv6200.h>
18 #include "dev.h"
19 #include "sar.h"
20 #ifdef CONFIG_SSV_SUPPORT_ANDROID
21 #ifdef CONFIG_HAS_WAKELOCK
22 #include <linux/wakelock.h>
23 #endif
24 #ifdef CONFIG_HAS_EARLYSUSPEND
25 #include <linux/earlysuspend.h>
26 #elif LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0)
27 #include <linux/notifier.h>
28 #include <linux/fb.h>
29 #endif
30 struct ssv_softc *ssv_notify_sc = NULL;
31 EXPORT_SYMBOL(ssv_notify_sc);
32 #if defined(CONFIG_HAS_EARLYSUSPEND) || (LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0))
33 #ifdef CONFIG_HAS_EARLYSUSPEND
ssv6xxx_early_suspend(struct early_suspend * h)34 void ssv6xxx_early_suspend(struct early_suspend *h)
35 #else
36 void ssv6xxx_early_suspend(void)
37 #endif
38 {
39 #ifdef CONFIG_HAS_EARLYSUSPEND
40 struct ssv_softc *sc = container_of(h, struct ssv_softc, early_suspend);
41 #else
42 struct ssv_softc *sc = ssv_notify_sc;
43 #endif
44 sc->ps_status = PWRSV_PREPARE;
45 if (sc->is_sar_enabled) {
46 cancel_delayed_work(&sc->thermal_monitor_work);
47 flush_workqueue(sc->thermal_wq);
48 }
49 printk(KERN_INFO "ssv6xxx_early_suspend\n");
50 ssv6xxx_watchdog_controller(sc->sh ,(u8)SSV6XXX_HOST_CMD_WATCHDOG_STOP);
51 sc->watchdog_flag = WD_SLEEP;
52 }
53 #define DEAUTH_DISASSOC_LEN (24 + 2 )
ssv6xxx_send_deauth_toself(struct ssv_softc * sc,const u8 * bssid,const u8 * self_addr)54 void ssv6xxx_send_deauth_toself(struct ssv_softc *sc,const u8 *bssid,const u8 *self_addr)
55 {
56 struct sk_buff *deauth_skb ;
57 u8 frame_buf[DEAUTH_DISASSOC_LEN];
58 struct ieee80211_mgmt *mgmt = (void *)frame_buf;
59 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH);
60 mgmt->duration = 0;
61 mgmt->seq_ctrl = 0;
62 memcpy(mgmt->da, self_addr, ETH_ALEN);
63 memcpy(mgmt->sa, bssid, ETH_ALEN);
64 memcpy(mgmt->bssid, bssid, ETH_ALEN);
65 mgmt->u.deauth.reason_code = cpu_to_le16(2);
66 {
67 deauth_skb = dev_alloc_skb(DEAUTH_DISASSOC_LEN);
68 if (!deauth_skb)
69 return;
70 memcpy(skb_put(deauth_skb, DEAUTH_DISASSOC_LEN),
71 mgmt, DEAUTH_DISASSOC_LEN);
72 #if defined(USE_THREAD_RX) && !defined(IRQ_PROC_RX_DATA)
73 local_bh_disable();
74 ieee80211_rx(sc->hw, deauth_skb);
75 local_bh_enable();
76 #else
77 ieee80211_rx_irqsafe(sc->hw, deauth_skb);
78 #endif
79 return;
80 }
81 }
82 #ifdef CONFIG_HAS_EARLYSUSPEND
ssv6xxx_late_resume(struct early_suspend * h)83 void ssv6xxx_late_resume(struct early_suspend *h)
84 #else
85 void ssv6xxx_late_resume(void)
86 #endif
87 {
88 #ifdef CONFIG_HAS_EARLYSUSPEND
89 struct ssv_softc *sc = container_of(h, struct ssv_softc, early_suspend);
90 #else
91 struct ssv_softc *sc = ssv_notify_sc;
92 #endif
93 if (!sc)
94 return;
95 if(sc->ps_status == PWRSV_ENABLE)
96 {
97 if(sc->vif_info[0].vif)
98 {
99 if(sc->vif_info[0].vif->bss_conf.assoc)
100 {
101 printk("sc->vif_info[0].vif->bss_conf.assoc\n");
102 if ((sc->vif_info[0].vif->type == NL80211_IFTYPE_STATION) || (sc->vif_info[0].vif->p2p))
103 {
104 printk("sc->vif_info[0].vif->bss_conf.assoc ssv6xxx_send_deauth_toself\n");
105 ssv6xxx_send_deauth_toself(sc, sc->vif_info[0].vif->bss_conf.bssid, sc->vif_info[0].vif->addr);
106 }
107 }
108 }
109 if(sc->vif_info[1].vif)
110 {
111 if(sc->vif_info[1].vif->bss_conf.assoc)
112 {
113 printk("sc->vif_info[1].vif->bss_conf.assoc\n");
114 if ((sc->vif_info[1].vif->type == NL80211_IFTYPE_STATION) || (sc->vif_info[1].vif->p2p))
115 {
116 printk("sc->vif_info[1].vif->bss_conf.assoc ssv6xxx_send_deauth_toself\n");
117 ssv6xxx_send_deauth_toself(sc, sc->vif_info[1].vif->bss_conf.bssid, sc->vif_info[1].vif->addr);
118 }
119 }
120 }
121 }
122 if(sc)
123 ssv6xxx_disable_ps(sc);
124 else
125 printk(KERN_INFO "ssv6xxx_late_resume,sc=NULL\n");
126 if (sc->is_sar_enabled) {
127 queue_delayed_work(sc->thermal_wq, &sc->thermal_monitor_work, THERMAL_MONITOR_TIME);
128 }
129 ssv6xxx_watchdog_controller(sc->sh ,(u8)SSV6XXX_HOST_CMD_WATCHDOG_START);
130 sc->watchdog_flag = WD_KICKED;
131 printk(KERN_INFO "ssv6xxx_late_resume\n");
132 }
133 #ifndef CONFIG_HAS_EARLYSUSPEND
ssv_wlan_fb_event_notify(struct notifier_block * self,unsigned long action,void * data)134 static int ssv_wlan_fb_event_notify(struct notifier_block *self,
135 unsigned long action, void *data)
136 {
137 struct fb_event *event = data;
138 int blank_mode = *((int *)event->data);
139 if (action == FB_EARLY_EVENT_BLANK) {
140 switch (blank_mode) {
141 case FB_BLANK_UNBLANK:
142 break;
143 default:
144 ssv6xxx_early_suspend();
145 break;
146 }
147 }
148 else if (action == FB_EVENT_BLANK) {
149 switch (blank_mode) {
150 case FB_BLANK_UNBLANK:
151 ssv6xxx_late_resume();
152 break;
153 default:
154 break;
155 }
156 }
157 return NOTIFY_OK;
158 }
159 struct notifier_block ssv_wlan_fb_notifier = {
160 .notifier_call = ssv_wlan_fb_event_notify,
161 };
162 #endif
163 #endif
ssv_wakelock_init(struct ssv_softc * sc)164 void ssv_wakelock_init(struct ssv_softc *sc)
165 {
166 #ifdef CONFIG_HAS_WAKELOCK
167 wake_lock_init(&sc->ssv_wake_lock_, WAKE_LOCK_SUSPEND, "ssv6051");
168 #endif
169 #ifndef CONFIG_HAS_EARLYSUSPEND
170 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
171 fb_register_client(&ssv_wlan_fb_notifier);
172 #endif
173 #endif
174 }
ssv_wakelock_destroy(struct ssv_softc * sc)175 void ssv_wakelock_destroy(struct ssv_softc *sc)
176 {
177 #ifdef CONFIG_HAS_WAKELOCK
178 wake_lock_destroy(&sc->ssv_wake_lock_);
179 #endif
180 #ifndef CONFIG_HAS_EARLYSUSPEND
181 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
182 fb_unregister_client(&ssv_wlan_fb_notifier);
183 #endif
184 #endif
185 }
ssv_wake_lock(struct ssv_softc * sc)186 void ssv_wake_lock(struct ssv_softc *sc)
187 {
188 #ifdef CONFIG_HAS_WAKELOCK
189 wake_lock(&sc->ssv_wake_lock_);
190 #endif
191 }
ssv_wake_timeout(struct ssv_softc * sc,int secs)192 void ssv_wake_timeout(struct ssv_softc *sc, int secs)
193 {
194 #ifdef CONFIG_HAS_WAKELOCK
195 wake_lock_timeout(&sc->ssv_wake_lock_,secs*HZ);
196 #endif
197 }
ssv_wake_unlock(struct ssv_softc * sc)198 void ssv_wake_unlock(struct ssv_softc *sc)
199 {
200 #ifdef CONFIG_HAS_WAKELOCK
201 wake_unlock(&sc->ssv_wake_lock_);
202 #endif
203 }
204 #endif
205