Commit | Line | Data |
---|---|---|
c5c77ba1 JK |
1 | #include "wilc_wfi_cfgoperations.h" |
2 | #include "linux_wlan_common.h" | |
3 | #include "wilc_wlan_if.h" | |
4 | #include "wilc_wlan.h" | |
c5c77ba1 JK |
5 | |
6 | #include <linux/slab.h> | |
7 | #include <linux/sched.h> | |
8 | #include <linux/delay.h> | |
9 | #include <linux/workqueue.h> | |
10 | #include <linux/interrupt.h> | |
11 | #include <linux/irq.h> | |
f1a99830 | 12 | #include <linux/gpio.h> |
c5c77ba1 JK |
13 | |
14 | #include <linux/kthread.h> | |
15 | #include <linux/firmware.h> | |
16 | #include <linux/delay.h> | |
17 | ||
18 | #include <linux/init.h> | |
19 | #include <linux/netdevice.h> | |
c5c77ba1 | 20 | #include <linux/inetdevice.h> |
c5c77ba1 JK |
21 | #include <linux/etherdevice.h> |
22 | #include <linux/module.h> | |
23 | #include <linux/kernel.h> | |
24 | #include <linux/skbuff.h> | |
25 | ||
c5c77ba1 JK |
26 | #include <linux/semaphore.h> |
27 | ||
c5c77ba1 JK |
28 | static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr); |
29 | ||
30 | static struct notifier_block g_dev_notifier = { | |
31 | .notifier_call = dev_state_ev_handler | |
32 | }; | |
c5c77ba1 | 33 | |
c5c77ba1 JK |
34 | #define IRQ_WAIT 1 |
35 | #define IRQ_NO_WAIT 0 | |
c5c77ba1 | 36 | static struct semaphore close_exit_sync; |
c5c77ba1 | 37 | |
7c67c053 | 38 | static int wlan_deinit_locks(struct net_device *dev); |
32dd51bc | 39 | static void wlan_deinitialize_threads(struct net_device *dev); |
c5c77ba1 | 40 | |
c5c77ba1 | 41 | static void linux_wlan_tx_complete(void *priv, int status); |
c5c77ba1 | 42 | static int mac_init_fn(struct net_device *ndev); |
c5c77ba1 JK |
43 | static struct net_device_stats *mac_stats(struct net_device *dev); |
44 | static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd); | |
45 | static void wilc_set_multicast_list(struct net_device *dev); | |
750ffe9b | 46 | |
0e1af73d | 47 | bool wilc_enable_ps = true; |
c5c77ba1 | 48 | |
c5c77ba1 JK |
49 | static const struct net_device_ops wilc_netdev_ops = { |
50 | .ndo_init = mac_init_fn, | |
0e1af73d AB |
51 | .ndo_open = wilc_mac_open, |
52 | .ndo_stop = wilc_mac_close, | |
53 | .ndo_start_xmit = wilc_mac_xmit, | |
c5c77ba1 JK |
54 | .ndo_do_ioctl = mac_ioctl, |
55 | .ndo_get_stats = mac_stats, | |
56 | .ndo_set_rx_mode = wilc_set_multicast_list, | |
57 | ||
58 | }; | |
c5c77ba1 | 59 | |
c5c77ba1 JK |
60 | static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr) |
61 | { | |
62 | struct in_ifaddr *dev_iface = (struct in_ifaddr *)ptr; | |
2726887c | 63 | struct wilc_priv *priv; |
f24374aa | 64 | struct host_if_drv *hif_drv; |
c5c77ba1 | 65 | struct net_device *dev; |
eac3e8f6 | 66 | u8 *ip_addr_buf; |
a4cac481 | 67 | struct wilc_vif *vif; |
63d03e47 | 68 | u8 null_ip[4] = {0}; |
c5c77ba1 JK |
69 | char wlan_dev_name[5] = "wlan0"; |
70 | ||
3a147c07 | 71 | if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev) { |
c5c77ba1 JK |
72 | PRINT_D(GENERIC_DBG, "dev_iface = NULL\n"); |
73 | return NOTIFY_DONE; | |
74 | } | |
75 | ||
582f8a27 LK |
76 | if (memcmp(dev_iface->ifa_label, "wlan0", 5) && |
77 | memcmp(dev_iface->ifa_label, "p2p0", 4)) { | |
c5c77ba1 JK |
78 | PRINT_D(GENERIC_DBG, "Interface is neither WLAN0 nor P2P0\n"); |
79 | return NOTIFY_DONE; | |
80 | } | |
81 | ||
82 | dev = (struct net_device *)dev_iface->ifa_dev->dev; | |
3a147c07 | 83 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) { |
c5c77ba1 JK |
84 | PRINT_D(GENERIC_DBG, "No Wireless registerd\n"); |
85 | return NOTIFY_DONE; | |
86 | } | |
87 | priv = wiphy_priv(dev->ieee80211_ptr->wiphy); | |
3a147c07 | 88 | if (!priv) { |
c5c77ba1 JK |
89 | PRINT_D(GENERIC_DBG, "No Wireless Priv\n"); |
90 | return NOTIFY_DONE; | |
91 | } | |
f24374aa | 92 | hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv; |
a4cac481 GL |
93 | vif = netdev_priv(dev); |
94 | if (!vif || !hif_drv) { | |
c5c77ba1 JK |
95 | PRINT_D(GENERIC_DBG, "No Wireless Priv\n"); |
96 | return NOTIFY_DONE; | |
97 | } | |
98 | ||
98b89847 | 99 | PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler +++\n"); |
c5c77ba1 JK |
100 | |
101 | switch (event) { | |
102 | case NETDEV_UP: | |
98b89847 | 103 | PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_UP %p\n", dev); |
c5c77ba1 JK |
104 | |
105 | PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Obtained ===============\n\n"); | |
106 | ||
a4cac481 | 107 | if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) { |
f24374aa | 108 | hif_drv->IFC_UP = 1; |
0e1af73d AB |
109 | wilc_optaining_ip = false; |
110 | del_timer(&wilc_during_ip_timer); | |
c5c77ba1 JK |
111 | PRINT_D(GENERIC_DBG, "IP obtained , enable scan\n"); |
112 | } | |
113 | ||
0e1af73d | 114 | if (wilc_enable_ps) |
fbf5379b | 115 | wilc_set_power_mgmt(vif, 1, 0); |
c5c77ba1 JK |
116 | |
117 | PRINT_D(GENERIC_DBG, "[%s] Up IP\n", dev_iface->ifa_label); | |
118 | ||
eac3e8f6 LK |
119 | ip_addr_buf = (char *)&dev_iface->ifa_address; |
120 | PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", | |
121 | ip_addr_buf[0], ip_addr_buf[1], | |
122 | ip_addr_buf[2], ip_addr_buf[3]); | |
fbf5379b | 123 | wilc_setup_ipaddress(vif, ip_addr_buf, vif->u8IfIdx); |
c5c77ba1 JK |
124 | |
125 | break; | |
126 | ||
127 | case NETDEV_DOWN: | |
98b89847 | 128 | PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_DOWN %p\n", dev); |
c5c77ba1 JK |
129 | |
130 | PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Released ===============\n\n"); | |
a4cac481 | 131 | if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) { |
f24374aa | 132 | hif_drv->IFC_UP = 0; |
0e1af73d | 133 | wilc_optaining_ip = false; |
c5c77ba1 JK |
134 | } |
135 | ||
136 | if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0) | |
fbf5379b | 137 | wilc_set_power_mgmt(vif, 0, 0); |
c5c77ba1 | 138 | |
fbf5379b | 139 | wilc_resolve_disconnect_aberration(vif); |
c5c77ba1 | 140 | |
c5c77ba1 JK |
141 | PRINT_D(GENERIC_DBG, "[%s] Down IP\n", dev_iface->ifa_label); |
142 | ||
eac3e8f6 LK |
143 | ip_addr_buf = null_ip; |
144 | PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", | |
145 | ip_addr_buf[0], ip_addr_buf[1], | |
146 | ip_addr_buf[2], ip_addr_buf[3]); | |
c5c77ba1 | 147 | |
fbf5379b | 148 | wilc_setup_ipaddress(vif, ip_addr_buf, vif->u8IfIdx); |
c5c77ba1 JK |
149 | |
150 | break; | |
151 | ||
152 | default: | |
98b89847 | 153 | PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler event=default\n"); |
c5c77ba1 JK |
154 | PRINT_INFO(GENERIC_DBG, "[%s] unknown dev event: %lu\n", dev_iface->ifa_label, event); |
155 | ||
156 | break; | |
157 | } | |
158 | ||
159 | return NOTIFY_DONE; | |
c5c77ba1 | 160 | } |
c5c77ba1 | 161 | |
c5c77ba1 JK |
162 | static irqreturn_t isr_uh_routine(int irq, void *user_data) |
163 | { | |
a4cac481 | 164 | struct wilc_vif *vif; |
3948362d GL |
165 | struct wilc *wilc; |
166 | struct net_device *dev = (struct net_device *)user_data; | |
167 | ||
a4cac481 GL |
168 | vif = netdev_priv(dev); |
169 | wilc = vif->wilc; | |
c5c77ba1 JK |
170 | PRINT_D(INT_DBG, "Interrupt received UH\n"); |
171 | ||
3948362d | 172 | if (wilc->close) { |
c5c77ba1 | 173 | PRINT_ER("Driver is CLOSING: Can't handle UH interrupt\n"); |
c5c77ba1 | 174 | return IRQ_HANDLED; |
c5c77ba1 | 175 | } |
c5c77ba1 | 176 | return IRQ_WAKE_THREAD; |
c5c77ba1 | 177 | } |
c5c77ba1 | 178 | |
1608c403 | 179 | static irqreturn_t isr_bh_routine(int irq, void *userdata) |
c5c77ba1 | 180 | { |
a4cac481 | 181 | struct wilc_vif *vif; |
2e7933d0 GL |
182 | struct wilc *wilc; |
183 | ||
a4cac481 GL |
184 | vif = netdev_priv(userdata); |
185 | wilc = vif->wilc; | |
2e7933d0 | 186 | |
2e7933d0 | 187 | if (wilc->close) { |
c5c77ba1 | 188 | PRINT_ER("Driver is CLOSING: Can't handle BH interrupt\n"); |
c5c77ba1 | 189 | return IRQ_HANDLED; |
c5c77ba1 JK |
190 | } |
191 | ||
c5c77ba1 | 192 | PRINT_D(INT_DBG, "Interrupt received BH\n"); |
50b929e0 | 193 | wilc_handle_isr(wilc); |
c5c77ba1 | 194 | |
c5c77ba1 | 195 | return IRQ_HANDLED; |
c5c77ba1 | 196 | } |
c5c77ba1 | 197 | |
2c1d05d1 | 198 | static int init_irq(struct net_device *dev) |
c5c77ba1 JK |
199 | { |
200 | int ret = 0; | |
a4cac481 | 201 | struct wilc_vif *vif; |
2c1d05d1 GL |
202 | struct wilc *wl; |
203 | ||
a4cac481 GL |
204 | vif = netdev_priv(dev); |
205 | wl = vif->wilc; | |
c5c77ba1 | 206 | |
c4d139cb AB |
207 | if ((gpio_request(wl->gpio, "WILC_INTR") == 0) && |
208 | (gpio_direction_input(wl->gpio) == 0)) { | |
209 | wl->dev_irq_num = gpio_to_irq(wl->gpio); | |
c5c77ba1 JK |
210 | } else { |
211 | ret = -1; | |
212 | PRINT_ER("could not obtain gpio for WILC_INTR\n"); | |
213 | } | |
214 | ||
83231b72 LK |
215 | if (ret != -1 && request_threaded_irq(wl->dev_irq_num, |
216 | isr_uh_routine, | |
217 | isr_bh_routine, | |
218 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | |
219 | "WILC_IRQ", dev) < 0) { | |
c4d139cb AB |
220 | PRINT_ER("Failed to request IRQ for GPIO: %d\n", wl->gpio); |
221 | gpio_free(wl->gpio); | |
c5c77ba1 JK |
222 | ret = -1; |
223 | } else { | |
c5c77ba1 | 224 | PRINT_D(INIT_DBG, "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n", |
c4d139cb | 225 | wl->dev_irq_num, wl->gpio); |
c5c77ba1 JK |
226 | } |
227 | ||
228 | return ret; | |
229 | } | |
c5c77ba1 | 230 | |
ec5cc750 | 231 | static void deinit_irq(struct net_device *dev) |
c5c77ba1 | 232 | { |
a4cac481 | 233 | struct wilc_vif *vif; |
ec5cc750 GL |
234 | struct wilc *wilc; |
235 | ||
a4cac481 GL |
236 | vif = netdev_priv(dev); |
237 | wilc = vif->wilc; | |
ec5cc750 | 238 | |
c4d139cb AB |
239 | /* Deintialize IRQ */ |
240 | if (wilc->dev_irq_num) { | |
ec5cc750 | 241 | free_irq(wilc->dev_irq_num, wilc); |
c4d139cb | 242 | gpio_free(wilc->gpio); |
c5c77ba1 | 243 | } |
c5c77ba1 JK |
244 | } |
245 | ||
d36ec22d | 246 | void wilc_dbg(u8 *buff) |
c5c77ba1 JK |
247 | { |
248 | PRINT_D(INIT_DBG, "%d\n", *buff); | |
249 | } | |
250 | ||
562ed3f1 | 251 | int wilc_lock_timeout(struct wilc *nic, void *vp, u32 timeout) |
c5c77ba1 | 252 | { |
562ed3f1 | 253 | /* FIXME: replace with mutex_lock or wait_for_completion */ |
c5c77ba1 | 254 | int error = -1; |
8dfaafd6 | 255 | |
c5c77ba1 | 256 | PRINT_D(LOCK_DBG, "Locking %p\n", vp); |
3a147c07 | 257 | if (vp) |
582f8a27 LK |
258 | error = down_timeout((struct semaphore *)vp, |
259 | msecs_to_jiffies(timeout)); | |
78174ada | 260 | else |
c5c77ba1 | 261 | PRINT_ER("Failed, mutex is NULL\n"); |
c5c77ba1 JK |
262 | return error; |
263 | } | |
264 | ||
562ed3f1 | 265 | void wilc_mac_indicate(struct wilc *wilc, int flag) |
c5c77ba1 | 266 | { |
c5c77ba1 JK |
267 | int status; |
268 | ||
269 | if (flag == WILC_MAC_INDICATE_STATUS) { | |
582f8a27 LK |
270 | wilc_wlan_cfg_get_val(WID_STATUS, |
271 | (unsigned char *)&status, 4); | |
64f2b71b GL |
272 | if (wilc->mac_status == WILC_MAC_STATUS_INIT) { |
273 | wilc->mac_status = status; | |
274 | up(&wilc->sync_event); | |
c5c77ba1 | 275 | } else { |
64f2b71b | 276 | wilc->mac_status = status; |
c5c77ba1 | 277 | } |
c5c77ba1 JK |
278 | } else if (flag == WILC_MAC_INDICATE_SCAN) { |
279 | PRINT_D(GENERIC_DBG, "Scanning ...\n"); | |
c5c77ba1 | 280 | } |
c5c77ba1 JK |
281 | } |
282 | ||
1608c403 | 283 | static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) |
c5c77ba1 | 284 | { |
660786ea | 285 | u8 *bssid, *bssid1; |
c5c77ba1 JK |
286 | int i = 0; |
287 | ||
d239222e | 288 | bssid = mac_header + 10; |
660786ea | 289 | bssid1 = mac_header + 4; |
c5c77ba1 | 290 | |
ba615f1e GL |
291 | for (i = 0; i < wilc->vif_num; i++) { |
292 | if (wilc->vif[i]->mode == STATION_MODE) | |
293 | if (!memcmp(bssid, wilc->vif[i]->bssid, ETH_ALEN)) | |
294 | return wilc->vif[i]->ndev; | |
295 | if (wilc->vif[i]->mode == AP_MODE) | |
296 | if (!memcmp(bssid1, wilc->vif[i]->bssid, ETH_ALEN)) | |
297 | return wilc->vif[i]->ndev; | |
298 | } | |
8259a53e | 299 | |
c5c77ba1 JK |
300 | return NULL; |
301 | } | |
302 | ||
ba615f1e | 303 | int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) |
c5c77ba1 JK |
304 | { |
305 | int i = 0; | |
306 | int ret = -1; | |
a4cac481 | 307 | struct wilc_vif *vif; |
472791a9 | 308 | struct wilc *wilc; |
c5c77ba1 | 309 | |
a4cac481 GL |
310 | vif = netdev_priv(wilc_netdev); |
311 | wilc = vif->wilc; | |
472791a9 GL |
312 | |
313 | for (i = 0; i < wilc->vif_num; i++) | |
1f435d2e GL |
314 | if (wilc->vif[i]->ndev == wilc_netdev) { |
315 | memcpy(wilc->vif[i]->bssid, bssid, 6); | |
ba615f1e | 316 | wilc->vif[i]->mode = mode; |
c5c77ba1 JK |
317 | ret = 0; |
318 | break; | |
319 | } | |
8259a53e | 320 | |
c5c77ba1 JK |
321 | return ret; |
322 | } | |
323 | ||
562ed3f1 | 324 | int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) |
c5c77ba1 | 325 | { |
51e825f7 CL |
326 | u8 i = 0; |
327 | u8 null_bssid[6] = {0}; | |
328 | u8 ret_val = 0; | |
c5c77ba1 | 329 | |
562ed3f1 | 330 | for (i = 0; i < wilc->vif_num; i++) |
1f435d2e | 331 | if (memcmp(wilc->vif[i]->bssid, null_bssid, 6)) |
c5c77ba1 | 332 | ret_val++; |
8259a53e | 333 | |
c5c77ba1 JK |
334 | return ret_val; |
335 | } | |
336 | ||
c5c77ba1 JK |
337 | #define USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS |
338 | ||
339 | static int linux_wlan_txq_task(void *vp) | |
340 | { | |
341 | int ret, txq_count; | |
a4cac481 | 342 | struct wilc_vif *vif; |
88687584 GL |
343 | struct wilc *wl; |
344 | struct net_device *dev = vp; | |
c5c77ba1 JK |
345 | #if defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS |
346 | #define TX_BACKOFF_WEIGHT_INCR_STEP (1) | |
347 | #define TX_BACKOFF_WEIGHT_DECR_STEP (1) | |
348 | #define TX_BACKOFF_WEIGHT_MAX (7) | |
349 | #define TX_BACKOFF_WEIGHT_MIN (0) | |
350 | #define TX_BACKOFF_WEIGHT_UNIT_MS (10) | |
351 | int backoff_weight = TX_BACKOFF_WEIGHT_MIN; | |
c5c77ba1 JK |
352 | #endif |
353 | ||
a4cac481 GL |
354 | vif = netdev_priv(dev); |
355 | wl = vif->wilc; | |
88687584 | 356 | |
88687584 | 357 | up(&wl->txq_thread_started); |
c5c77ba1 | 358 | while (1) { |
c5c77ba1 | 359 | PRINT_D(TX_DBG, "txq_task Taking a nap :)\n"); |
88687584 | 360 | down(&wl->txq_event); |
c5c77ba1 JK |
361 | PRINT_D(TX_DBG, "txq_task Who waked me up :$\n"); |
362 | ||
88687584 | 363 | if (wl->close) { |
88687584 | 364 | up(&wl->txq_thread_started); |
c5c77ba1 JK |
365 | |
366 | while (!kthread_should_stop()) | |
367 | schedule(); | |
368 | ||
369 | PRINT_D(TX_DBG, "TX thread stopped\n"); | |
370 | break; | |
371 | } | |
372 | PRINT_D(TX_DBG, "txq_task handle the sending packet and let me go to sleep.\n"); | |
373 | #if !defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS | |
a1332cad | 374 | ret = wilc_wlan_handle_txq(dev, &txq_count); |
c5c77ba1 JK |
375 | #else |
376 | do { | |
a1332cad | 377 | ret = wilc_wlan_handle_txq(dev, &txq_count); |
98b89847 | 378 | if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { |
c5c77ba1 | 379 | PRINT_D(TX_DBG, "Waking up queue\n"); |
98b89847 | 380 | |
1f435d2e GL |
381 | if (netif_queue_stopped(wl->vif[0]->ndev)) |
382 | netif_wake_queue(wl->vif[0]->ndev); | |
383 | if (netif_queue_stopped(wl->vif[1]->ndev)) | |
384 | netif_wake_queue(wl->vif[1]->ndev); | |
c5c77ba1 JK |
385 | } |
386 | ||
98b89847 | 387 | if (ret == WILC_TX_ERR_NO_BUF) { |
c5c77ba1 | 388 | backoff_weight += TX_BACKOFF_WEIGHT_INCR_STEP; |
fc4b95d6 | 389 | if (backoff_weight > TX_BACKOFF_WEIGHT_MAX) |
c5c77ba1 | 390 | backoff_weight = TX_BACKOFF_WEIGHT_MAX; |
c5c77ba1 JK |
391 | } else { |
392 | if (backoff_weight > TX_BACKOFF_WEIGHT_MIN) { | |
393 | backoff_weight -= TX_BACKOFF_WEIGHT_DECR_STEP; | |
fc4b95d6 | 394 | if (backoff_weight < TX_BACKOFF_WEIGHT_MIN) |
c5c77ba1 | 395 | backoff_weight = TX_BACKOFF_WEIGHT_MIN; |
c5c77ba1 JK |
396 | } |
397 | } | |
98b89847 | 398 | } while (ret == WILC_TX_ERR_NO_BUF && !wl->close); |
c5c77ba1 JK |
399 | #endif |
400 | } | |
401 | return 0; | |
402 | } | |
403 | ||
562ed3f1 | 404 | void wilc_rx_complete(struct wilc *nic) |
c5c77ba1 JK |
405 | { |
406 | PRINT_D(RX_DBG, "RX completed\n"); | |
407 | } | |
408 | ||
0e1af73d | 409 | int wilc_wlan_get_firmware(struct net_device *dev) |
c5c77ba1 | 410 | { |
a4cac481 | 411 | struct wilc_vif *vif; |
65c8adcf | 412 | struct wilc *wilc; |
14823bf2 | 413 | int chip_id, ret = 0; |
c5c77ba1 JK |
414 | const struct firmware *wilc_firmware; |
415 | char *firmware; | |
416 | ||
a4cac481 GL |
417 | vif = netdev_priv(dev); |
418 | wilc = vif->wilc; | |
65c8adcf | 419 | |
14823bf2 GL |
420 | chip_id = wilc_get_chipid(wilc, 0); |
421 | ||
422 | if (chip_id < 0x1003a0) | |
423 | firmware = FIRMWARE_1002; | |
424 | else | |
425 | firmware = FIRMWARE_1003; | |
426 | ||
427 | netdev_info(dev, "loading firmware %s\n", firmware); | |
c5c77ba1 | 428 | |
a4cac481 GL |
429 | if (!vif) { |
430 | PRINT_ER("vif is NULL\n"); | |
c5c77ba1 JK |
431 | goto _fail_; |
432 | } | |
433 | ||
1006b5c7 GL |
434 | if (!(&vif->ndev->dev)) { |
435 | PRINT_ER("&vif->ndev->dev is NULL\n"); | |
c5c77ba1 JK |
436 | goto _fail_; |
437 | } | |
438 | ||
b03314e2 | 439 | if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) { |
c5c77ba1 JK |
440 | PRINT_ER("%s - firmare not available\n", firmware); |
441 | ret = -1; | |
442 | goto _fail_; | |
443 | } | |
65c8adcf | 444 | wilc->firmware = wilc_firmware; |
c5c77ba1 JK |
445 | |
446 | _fail_: | |
447 | ||
448 | return ret; | |
c5c77ba1 JK |
449 | } |
450 | ||
9bf3d727 | 451 | static int linux_wlan_start_firmware(struct net_device *dev) |
c5c77ba1 | 452 | { |
a4cac481 | 453 | struct wilc_vif *vif; |
9bf3d727 | 454 | struct wilc *wilc; |
c5c77ba1 | 455 | int ret = 0; |
9bf3d727 | 456 | |
a4cac481 GL |
457 | vif = netdev_priv(dev); |
458 | wilc = vif->wilc; | |
9bf3d727 | 459 | |
c5c77ba1 | 460 | PRINT_D(INIT_DBG, "Starting Firmware ...\n"); |
562ed3f1 | 461 | ret = wilc_wlan_start(wilc); |
c5c77ba1 JK |
462 | if (ret < 0) { |
463 | PRINT_ER("Failed to start Firmware\n"); | |
0aeea1ad | 464 | return ret; |
c5c77ba1 JK |
465 | } |
466 | ||
c5c77ba1 | 467 | PRINT_D(INIT_DBG, "Waiting for Firmware to get ready ...\n"); |
562ed3f1 | 468 | ret = wilc_lock_timeout(wilc, &wilc->sync_event, 5000); |
c5c77ba1 | 469 | if (ret) { |
c5c77ba1 | 470 | PRINT_D(INIT_DBG, "Firmware start timed out"); |
0aeea1ad | 471 | return ret; |
c5c77ba1 | 472 | } |
c5c77ba1 JK |
473 | PRINT_D(INIT_DBG, "Firmware successfully started\n"); |
474 | ||
0aeea1ad | 475 | return 0; |
c5c77ba1 | 476 | } |
a40b22c5 | 477 | |
562ed3f1 | 478 | static int wilc1000_firmware_download(struct net_device *dev) |
c5c77ba1 | 479 | { |
a4cac481 | 480 | struct wilc_vif *vif; |
ed760b67 | 481 | struct wilc *wilc; |
c5c77ba1 JK |
482 | int ret = 0; |
483 | ||
a4cac481 GL |
484 | vif = netdev_priv(dev); |
485 | wilc = vif->wilc; | |
ed760b67 GL |
486 | |
487 | if (!wilc->firmware) { | |
c5c77ba1 | 488 | PRINT_ER("Firmware buffer is NULL\n"); |
14b1821d | 489 | return -ENOBUFS; |
c5c77ba1 | 490 | } |
c5c77ba1 | 491 | PRINT_D(INIT_DBG, "Downloading Firmware ...\n"); |
562ed3f1 | 492 | ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data, |
ed760b67 | 493 | wilc->firmware->size); |
fc4b95d6 | 494 | if (ret < 0) |
14b1821d | 495 | return ret; |
c5c77ba1 | 496 | |
c5c77ba1 JK |
497 | PRINT_D(INIT_DBG, "Freeing FW buffer ...\n"); |
498 | PRINT_D(INIT_DBG, "Releasing firmware\n"); | |
ed760b67 | 499 | release_firmware(wilc->firmware); |
6f72ed75 | 500 | wilc->firmware = NULL; |
c5c77ba1 | 501 | |
17aacd43 | 502 | PRINT_D(INIT_DBG, "Download Succeeded\n"); |
c5c77ba1 | 503 | |
14b1821d | 504 | return 0; |
c5c77ba1 JK |
505 | } |
506 | ||
00215dde | 507 | static int linux_wlan_init_test_config(struct net_device *dev, |
b8f6ca0b | 508 | struct wilc_vif *vif) |
c5c77ba1 | 509 | { |
c5c77ba1 | 510 | unsigned char c_val[64]; |
c5c77ba1 | 511 | unsigned char mac_add[] = {0x00, 0x80, 0xC2, 0x5E, 0xa2, 0xff}; |
b8f6ca0b | 512 | struct wilc *wilc = vif->wilc; |
2726887c | 513 | struct wilc_priv *priv; |
0fa66c71 | 514 | struct host_if_drv *hif_drv; |
c5c77ba1 JK |
515 | |
516 | PRINT_D(TX_DBG, "Start configuring Firmware\n"); | |
c5c77ba1 | 517 | priv = wiphy_priv(dev->ieee80211_ptr->wiphy); |
0fa66c71 LK |
518 | hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv; |
519 | PRINT_D(INIT_DBG, "Host = %p\n", hif_drv); | |
b8f6ca0b | 520 | wilc_get_mac_address(vif, mac_add); |
c5c77ba1 | 521 | |
582f8a27 LK |
522 | PRINT_D(INIT_DBG, "MAC address is : %02x-%02x-%02x-%02x-%02x-%02x\n", |
523 | mac_add[0], mac_add[1], mac_add[2], | |
524 | mac_add[3], mac_add[4], mac_add[5]); | |
00215dde | 525 | wilc_get_chipid(wilc, 0); |
c5c77ba1 | 526 | |
e5d57e91 | 527 | *(int *)c_val = 1; |
c5c77ba1 | 528 | |
89758e13 | 529 | if (!wilc_wlan_cfg_set(wilc, 1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0)) |
c5c77ba1 JK |
530 | goto _fail_; |
531 | ||
c5c77ba1 | 532 | c_val[0] = 0; |
89758e13 | 533 | if (!wilc_wlan_cfg_set(wilc, 0, WID_PC_TEST_MODE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
534 | goto _fail_; |
535 | ||
536 | c_val[0] = INFRASTRUCTURE; | |
89758e13 | 537 | if (!wilc_wlan_cfg_set(wilc, 0, WID_BSS_TYPE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
538 | goto _fail_; |
539 | ||
c5c77ba1 | 540 | c_val[0] = RATE_AUTO; |
89758e13 | 541 | if (!wilc_wlan_cfg_set(wilc, 0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
542 | goto _fail_; |
543 | ||
544 | c_val[0] = G_MIXED_11B_2_MODE; | |
89758e13 GL |
545 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11G_OPERATING_MODE, c_val, 1, 0, |
546 | 0)) | |
c5c77ba1 JK |
547 | goto _fail_; |
548 | ||
549 | c_val[0] = 1; | |
89758e13 | 550 | if (!wilc_wlan_cfg_set(wilc, 0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0)) |
c5c77ba1 JK |
551 | goto _fail_; |
552 | ||
553 | c_val[0] = G_SHORT_PREAMBLE; | |
89758e13 | 554 | if (!wilc_wlan_cfg_set(wilc, 0, WID_PREAMBLE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
555 | goto _fail_; |
556 | ||
557 | c_val[0] = AUTO_PROT; | |
89758e13 | 558 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_PROT_MECH, c_val, 1, 0, 0)) |
c5c77ba1 JK |
559 | goto _fail_; |
560 | ||
c5c77ba1 | 561 | c_val[0] = ACTIVE_SCAN; |
89758e13 | 562 | if (!wilc_wlan_cfg_set(wilc, 0, WID_SCAN_TYPE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
563 | goto _fail_; |
564 | ||
565 | c_val[0] = SITE_SURVEY_OFF; | |
89758e13 | 566 | if (!wilc_wlan_cfg_set(wilc, 0, WID_SITE_SURVEY, c_val, 1, 0, 0)) |
c5c77ba1 JK |
567 | goto _fail_; |
568 | ||
98b89847 | 569 | *((int *)c_val) = 0xffff; |
89758e13 | 570 | if (!wilc_wlan_cfg_set(wilc, 0, WID_RTS_THRESHOLD, c_val, 2, 0, 0)) |
c5c77ba1 JK |
571 | goto _fail_; |
572 | ||
573 | *((int *)c_val) = 2346; | |
89758e13 | 574 | if (!wilc_wlan_cfg_set(wilc, 0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0)) |
c5c77ba1 JK |
575 | goto _fail_; |
576 | ||
c5c77ba1 | 577 | c_val[0] = 0; |
89758e13 | 578 | if (!wilc_wlan_cfg_set(wilc, 0, WID_BCAST_SSID, c_val, 1, 0, 0)) |
c5c77ba1 JK |
579 | goto _fail_; |
580 | ||
581 | c_val[0] = 1; | |
89758e13 | 582 | if (!wilc_wlan_cfg_set(wilc, 0, WID_QOS_ENABLE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
583 | goto _fail_; |
584 | ||
585 | c_val[0] = NO_POWERSAVE; | |
89758e13 | 586 | if (!wilc_wlan_cfg_set(wilc, 0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0)) |
c5c77ba1 JK |
587 | goto _fail_; |
588 | ||
b4d04c15 | 589 | c_val[0] = NO_SECURITY; /* NO_ENCRYPT, 0x79 */ |
89758e13 | 590 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11I_MODE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
591 | goto _fail_; |
592 | ||
593 | c_val[0] = OPEN_SYSTEM; | |
89758e13 | 594 | if (!wilc_wlan_cfg_set(wilc, 0, WID_AUTH_TYPE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
595 | goto _fail_; |
596 | ||
c5c77ba1 | 597 | strcpy(c_val, "123456790abcdef1234567890"); |
89758e13 GL |
598 | if (!wilc_wlan_cfg_set(wilc, 0, WID_WEP_KEY_VALUE, c_val, |
599 | (strlen(c_val) + 1), 0, 0)) | |
c5c77ba1 JK |
600 | goto _fail_; |
601 | ||
c5c77ba1 | 602 | strcpy(c_val, "12345678"); |
89758e13 GL |
603 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11I_PSK, c_val, (strlen(c_val)), 0, |
604 | 0)) | |
c5c77ba1 JK |
605 | goto _fail_; |
606 | ||
c5c77ba1 | 607 | strcpy(c_val, "password"); |
89758e13 GL |
608 | if (!wilc_wlan_cfg_set(wilc, 0, WID_1X_KEY, c_val, (strlen(c_val) + 1), |
609 | 0, 0)) | |
c5c77ba1 JK |
610 | goto _fail_; |
611 | ||
c5c77ba1 JK |
612 | c_val[0] = 192; |
613 | c_val[1] = 168; | |
614 | c_val[2] = 1; | |
615 | c_val[3] = 112; | |
89758e13 | 616 | if (!wilc_wlan_cfg_set(wilc, 0, WID_1X_SERV_ADDR, c_val, 4, 0, 0)) |
c5c77ba1 JK |
617 | goto _fail_; |
618 | ||
619 | c_val[0] = 3; | |
89758e13 | 620 | if (!wilc_wlan_cfg_set(wilc, 0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0)) |
c5c77ba1 JK |
621 | goto _fail_; |
622 | ||
623 | c_val[0] = 3; | |
89758e13 | 624 | if (!wilc_wlan_cfg_set(wilc, 0, WID_DTIM_PERIOD, c_val, 1, 0, 0)) |
c5c77ba1 JK |
625 | goto _fail_; |
626 | ||
627 | c_val[0] = NORMAL_ACK; | |
89758e13 | 628 | if (!wilc_wlan_cfg_set(wilc, 0, WID_ACK_POLICY, c_val, 1, 0, 0)) |
c5c77ba1 JK |
629 | goto _fail_; |
630 | ||
631 | c_val[0] = 0; | |
89758e13 GL |
632 | if (!wilc_wlan_cfg_set(wilc, 0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1, |
633 | 0, 0)) | |
c5c77ba1 JK |
634 | goto _fail_; |
635 | ||
636 | c_val[0] = 48; | |
89758e13 GL |
637 | if (!wilc_wlan_cfg_set(wilc, 0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0, |
638 | 0)) | |
c5c77ba1 JK |
639 | goto _fail_; |
640 | ||
641 | c_val[0] = 28; | |
89758e13 GL |
642 | if (!wilc_wlan_cfg_set(wilc, 0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0, |
643 | 0)) | |
c5c77ba1 JK |
644 | goto _fail_; |
645 | ||
c5c77ba1 | 646 | *((int *)c_val) = 100; |
89758e13 | 647 | if (!wilc_wlan_cfg_set(wilc, 0, WID_BEACON_INTERVAL, c_val, 2, 0, 0)) |
c5c77ba1 JK |
648 | goto _fail_; |
649 | ||
650 | c_val[0] = REKEY_DISABLE; | |
89758e13 | 651 | if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_POLICY, c_val, 1, 0, 0)) |
c5c77ba1 JK |
652 | goto _fail_; |
653 | ||
c5c77ba1 | 654 | *((int *)c_val) = 84600; |
89758e13 | 655 | if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_PERIOD, c_val, 4, 0, 0)) |
c5c77ba1 JK |
656 | goto _fail_; |
657 | ||
c5c77ba1 | 658 | *((int *)c_val) = 500; |
89758e13 GL |
659 | if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_PACKET_COUNT, c_val, 4, 0, |
660 | 0)) | |
c5c77ba1 JK |
661 | goto _fail_; |
662 | ||
663 | c_val[0] = 1; | |
89758e13 GL |
664 | if (!wilc_wlan_cfg_set(wilc, 0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0, |
665 | 0)) | |
c5c77ba1 JK |
666 | goto _fail_; |
667 | ||
668 | c_val[0] = G_SELF_CTS_PROT; | |
89758e13 | 669 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
670 | goto _fail_; |
671 | ||
98b89847 | 672 | c_val[0] = 1; |
89758e13 | 673 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_ENABLE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
674 | goto _fail_; |
675 | ||
676 | c_val[0] = HT_MIXED_MODE; | |
89758e13 GL |
677 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_OPERATING_MODE, c_val, 1, 0, |
678 | 0)) | |
c5c77ba1 JK |
679 | goto _fail_; |
680 | ||
98b89847 | 681 | c_val[0] = 1; |
89758e13 GL |
682 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0, |
683 | 0)) | |
c5c77ba1 JK |
684 | goto _fail_; |
685 | ||
686 | memcpy(c_val, mac_add, 6); | |
687 | ||
89758e13 | 688 | if (!wilc_wlan_cfg_set(wilc, 0, WID_MAC_ADDR, c_val, 6, 0, 0)) |
c5c77ba1 JK |
689 | goto _fail_; |
690 | ||
c5c77ba1 | 691 | c_val[0] = DETECT_PROTECT_REPORT; |
89758e13 GL |
692 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1, |
693 | 0, 0)) | |
c5c77ba1 JK |
694 | goto _fail_; |
695 | ||
696 | c_val[0] = RTS_CTS_NONHT_PROT; | |
89758e13 | 697 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
698 | goto _fail_; |
699 | ||
700 | c_val[0] = 0; | |
89758e13 GL |
701 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0, |
702 | 0)) | |
c5c77ba1 JK |
703 | goto _fail_; |
704 | ||
705 | c_val[0] = MIMO_MODE; | |
89758e13 | 706 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_SMPS_MODE, c_val, 1, 0, 0)) |
c5c77ba1 JK |
707 | goto _fail_; |
708 | ||
709 | c_val[0] = 7; | |
89758e13 GL |
710 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0, |
711 | 0)) | |
c5c77ba1 JK |
712 | goto _fail_; |
713 | ||
98b89847 | 714 | c_val[0] = 1; |
89758e13 GL |
715 | if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1, |
716 | 1, 1)) | |
c5c77ba1 JK |
717 | goto _fail_; |
718 | ||
719 | return 0; | |
720 | ||
721 | _fail_: | |
722 | return -1; | |
723 | } | |
724 | ||
53dc0cfe | 725 | void wilc1000_wlan_deinit(struct net_device *dev) |
c5c77ba1 | 726 | { |
a4cac481 | 727 | struct wilc_vif *vif; |
53dc0cfe | 728 | struct wilc *wl; |
c5c77ba1 | 729 | |
a4cac481 GL |
730 | vif = netdev_priv(dev); |
731 | wl = vif->wilc; | |
53dc0cfe GL |
732 | |
733 | if (!wl) { | |
734 | netdev_err(dev, "wl is NULL\n"); | |
735 | return; | |
736 | } | |
737 | ||
738 | if (wl->initialized) { | |
739 | netdev_info(dev, "Deinitializing wilc1000...\n"); | |
c5c77ba1 | 740 | |
c5c77ba1 | 741 | PRINT_D(INIT_DBG, "Disabling IRQ\n"); |
5547c1f0 | 742 | if (!wl->dev_irq_num && |
af9ae09a | 743 | wl->hif_func->disable_interrupt) { |
c4d139cb | 744 | mutex_lock(&wl->hif_cs); |
af9ae09a | 745 | wl->hif_func->disable_interrupt(wl); |
c4d139cb AB |
746 | mutex_unlock(&wl->hif_cs); |
747 | } | |
3a147c07 | 748 | if (&wl->txq_event) |
53dc0cfe | 749 | up(&wl->txq_event); |
c5c77ba1 | 750 | |
c5c77ba1 | 751 | PRINT_D(INIT_DBG, "Deinitializing Threads\n"); |
32dd51bc | 752 | wlan_deinitialize_threads(dev); |
c5c77ba1 JK |
753 | |
754 | PRINT_D(INIT_DBG, "Deinitializing IRQ\n"); | |
ec5cc750 | 755 | deinit_irq(dev); |
c5c77ba1 | 756 | |
562ed3f1 | 757 | wilc_wlan_stop(wl); |
c5c77ba1 JK |
758 | |
759 | PRINT_D(INIT_DBG, "Deinitializing WILC Wlan\n"); | |
2de7cbec | 760 | wilc_wlan_cleanup(dev); |
c4d139cb | 761 | #if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31) |
5547c1f0 | 762 | if (!wl->dev_irq_num && |
af9ae09a | 763 | wl->hif_func->disable_interrupt) { |
5547c1f0 | 764 | |
c4d139cb AB |
765 | PRINT_D(INIT_DBG, "Disabling IRQ 2\n"); |
766 | ||
767 | mutex_lock(&wl->hif_cs); | |
af9ae09a | 768 | wl->hif_func->disable_interrupt(wl); |
c4d139cb AB |
769 | mutex_unlock(&wl->hif_cs); |
770 | } | |
c5c77ba1 JK |
771 | #endif |
772 | ||
c5c77ba1 | 773 | PRINT_D(INIT_DBG, "Deinitializing Locks\n"); |
7c67c053 | 774 | wlan_deinit_locks(dev); |
c5c77ba1 | 775 | |
53dc0cfe | 776 | wl->initialized = false; |
c5c77ba1 JK |
777 | |
778 | PRINT_D(INIT_DBG, "wilc1000 deinitialization Done\n"); | |
779 | ||
780 | } else { | |
781 | PRINT_D(INIT_DBG, "wilc1000 is not initialized\n"); | |
782 | } | |
c5c77ba1 JK |
783 | } |
784 | ||
1608c403 | 785 | static int wlan_init_locks(struct net_device *dev) |
c5c77ba1 | 786 | { |
a4cac481 | 787 | struct wilc_vif *vif; |
38afb390 GL |
788 | struct wilc *wl; |
789 | ||
a4cac481 GL |
790 | vif = netdev_priv(dev); |
791 | wl = vif->wilc; | |
c5c77ba1 JK |
792 | |
793 | PRINT_D(INIT_DBG, "Initializing Locks ...\n"); | |
794 | ||
38afb390 GL |
795 | mutex_init(&wl->hif_cs); |
796 | mutex_init(&wl->rxq_cs); | |
c5c77ba1 | 797 | |
38afb390 GL |
798 | spin_lock_init(&wl->txq_spinlock); |
799 | sema_init(&wl->txq_add_to_head_cs, 1); | |
c5c77ba1 | 800 | |
38afb390 | 801 | sema_init(&wl->txq_event, 0); |
c5c77ba1 | 802 | |
38afb390 GL |
803 | sema_init(&wl->cfg_event, 0); |
804 | sema_init(&wl->sync_event, 0); | |
c5c77ba1 | 805 | |
38afb390 | 806 | sema_init(&wl->txq_thread_started, 0); |
c5c77ba1 | 807 | |
c5c77ba1 JK |
808 | return 0; |
809 | } | |
810 | ||
7c67c053 | 811 | static int wlan_deinit_locks(struct net_device *dev) |
c5c77ba1 | 812 | { |
a4cac481 | 813 | struct wilc_vif *vif; |
7c67c053 GL |
814 | struct wilc *wilc; |
815 | ||
a4cac481 GL |
816 | vif = netdev_priv(dev); |
817 | wilc = vif->wilc; | |
7c67c053 | 818 | |
c5c77ba1 JK |
819 | PRINT_D(INIT_DBG, "De-Initializing Locks\n"); |
820 | ||
3a147c07 | 821 | if (&wilc->hif_cs) |
7c67c053 | 822 | mutex_destroy(&wilc->hif_cs); |
c5c77ba1 | 823 | |
3a147c07 | 824 | if (&wilc->rxq_cs) |
7c67c053 | 825 | mutex_destroy(&wilc->rxq_cs); |
c5c77ba1 | 826 | |
c5c77ba1 JK |
827 | return 0; |
828 | } | |
a40b22c5 | 829 | |
1608c403 | 830 | static int wlan_initialize_threads(struct net_device *dev) |
c5c77ba1 | 831 | { |
a4cac481 | 832 | struct wilc_vif *vif; |
75a94665 | 833 | struct wilc *wilc; |
8dfaafd6 | 834 | |
a4cac481 GL |
835 | vif = netdev_priv(dev); |
836 | wilc = vif->wilc; | |
75a94665 | 837 | |
c5c77ba1 | 838 | PRINT_D(INIT_DBG, "Initializing Threads ...\n"); |
c5c77ba1 | 839 | PRINT_D(INIT_DBG, "Creating kthread for transmission\n"); |
88687584 | 840 | wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev, |
75a94665 GL |
841 | "K_TXQ_TASK"); |
842 | if (!wilc->txq_thread) { | |
c5c77ba1 | 843 | PRINT_ER("couldn't create TXQ thread\n"); |
6bc72c5a LK |
844 | wilc->close = 0; |
845 | return -ENOBUFS; | |
c5c77ba1 | 846 | } |
75a94665 | 847 | down(&wilc->txq_thread_started); |
c5c77ba1 JK |
848 | |
849 | return 0; | |
c5c77ba1 JK |
850 | } |
851 | ||
32dd51bc | 852 | static void wlan_deinitialize_threads(struct net_device *dev) |
c5c77ba1 | 853 | { |
a4cac481 | 854 | struct wilc_vif *vif; |
32dd51bc | 855 | struct wilc *wl; |
a4cac481 GL |
856 | vif = netdev_priv(dev); |
857 | wl = vif->wilc; | |
c5c77ba1 | 858 | |
32dd51bc | 859 | wl->close = 1; |
c5c77ba1 | 860 | PRINT_D(INIT_DBG, "Deinitializing Threads\n"); |
c5c77ba1 | 861 | |
3a147c07 | 862 | if (&wl->txq_event) |
32dd51bc | 863 | up(&wl->txq_event); |
c5c77ba1 | 864 | |
3a147c07 | 865 | if (wl->txq_thread) { |
32dd51bc GL |
866 | kthread_stop(wl->txq_thread); |
867 | wl->txq_thread = NULL; | |
c5c77ba1 | 868 | } |
c5c77ba1 JK |
869 | } |
870 | ||
a4cac481 | 871 | int wilc1000_wlan_init(struct net_device *dev, struct wilc_vif *vif) |
c5c77ba1 | 872 | { |
c5c77ba1 | 873 | int ret = 0; |
a4cac481 | 874 | struct wilc *wl = vif->wilc; |
c5c77ba1 | 875 | |
0fa683b6 GL |
876 | if (!wl->initialized) { |
877 | wl->mac_status = WILC_MAC_STATUS_INIT; | |
878 | wl->close = 0; | |
c5c77ba1 | 879 | |
38afb390 | 880 | wlan_init_locks(dev); |
c5c77ba1 | 881 | |
4bd7baf0 | 882 | ret = wilc_wlan_init(dev); |
c5c77ba1 JK |
883 | if (ret < 0) { |
884 | PRINT_ER("Initializing WILC_Wlan FAILED\n"); | |
885 | ret = -EIO; | |
886 | goto _fail_locks_; | |
887 | } | |
c5c77ba1 | 888 | |
c4d139cb | 889 | if (wl->gpio >= 0 && init_irq(dev)) { |
c5c77ba1 JK |
890 | PRINT_ER("couldn't initialize IRQ\n"); |
891 | ret = -EIO; | |
b46d6882 | 892 | goto _fail_locks_; |
c5c77ba1 | 893 | } |
c5c77ba1 | 894 | |
75a94665 | 895 | ret = wlan_initialize_threads(dev); |
b46d6882 TC |
896 | if (ret < 0) { |
897 | PRINT_ER("Initializing Threads FAILED\n"); | |
898 | ret = -EIO; | |
899 | goto _fail_wilc_wlan_; | |
900 | } | |
901 | ||
5547c1f0 | 902 | if (!wl->dev_irq_num && |
af9ae09a GL |
903 | wl->hif_func->enable_interrupt && |
904 | wl->hif_func->enable_interrupt(wl)) { | |
c5c77ba1 JK |
905 | PRINT_ER("couldn't initialize IRQ\n"); |
906 | ret = -EIO; | |
907 | goto _fail_irq_init_; | |
908 | } | |
c5c77ba1 | 909 | |
0e1af73d | 910 | if (wilc_wlan_get_firmware(dev)) { |
17aacd43 | 911 | PRINT_ER("Can't get firmware\n"); |
c5c77ba1 JK |
912 | ret = -EIO; |
913 | goto _fail_irq_enable_; | |
914 | } | |
915 | ||
562ed3f1 | 916 | ret = wilc1000_firmware_download(dev); |
c5c77ba1 JK |
917 | if (ret < 0) { |
918 | PRINT_ER("Failed to download firmware\n"); | |
919 | ret = -EIO; | |
920 | goto _fail_irq_enable_; | |
921 | } | |
922 | ||
9bf3d727 | 923 | ret = linux_wlan_start_firmware(dev); |
c5c77ba1 JK |
924 | if (ret < 0) { |
925 | PRINT_ER("Failed to start firmware\n"); | |
926 | ret = -EIO; | |
927 | goto _fail_irq_enable_; | |
928 | } | |
929 | ||
d40c99c7 | 930 | if (wilc_wlan_cfg_get(wl, 1, WID_FIRMWARE_VERSION, 1, 0)) { |
c5c77ba1 JK |
931 | int size; |
932 | char Firmware_ver[20]; | |
8dfaafd6 | 933 | |
894de36b | 934 | size = wilc_wlan_cfg_get_val( |
c5c77ba1 JK |
935 | WID_FIRMWARE_VERSION, |
936 | Firmware_ver, sizeof(Firmware_ver)); | |
937 | Firmware_ver[size] = '\0'; | |
938 | PRINT_D(INIT_DBG, "***** Firmware Ver = %s *******\n", Firmware_ver); | |
939 | } | |
b8f6ca0b | 940 | ret = linux_wlan_init_test_config(dev, vif); |
c5c77ba1 JK |
941 | |
942 | if (ret < 0) { | |
943 | PRINT_ER("Failed to configure firmware\n"); | |
944 | ret = -EIO; | |
945 | goto _fail_fw_start_; | |
946 | } | |
947 | ||
0fa683b6 | 948 | wl->initialized = true; |
98b89847 | 949 | return 0; |
c5c77ba1 | 950 | |
c5c77ba1 | 951 | _fail_fw_start_: |
562ed3f1 | 952 | wilc_wlan_stop(wl); |
c5c77ba1 JK |
953 | |
954 | _fail_irq_enable_: | |
5547c1f0 | 955 | if (!wl->dev_irq_num && |
af9ae09a GL |
956 | wl->hif_func->disable_interrupt) |
957 | wl->hif_func->disable_interrupt(wl); | |
c5c77ba1 | 958 | _fail_irq_init_: |
c4d139cb AB |
959 | if (wl->dev_irq_num) |
960 | deinit_irq(dev); | |
c5c77ba1 | 961 | |
32dd51bc | 962 | wlan_deinitialize_threads(dev); |
c5c77ba1 | 963 | _fail_wilc_wlan_: |
2de7cbec | 964 | wilc_wlan_cleanup(dev); |
c5c77ba1 | 965 | _fail_locks_: |
7c67c053 | 966 | wlan_deinit_locks(dev); |
c5c77ba1 JK |
967 | PRINT_ER("WLAN Iinitialization FAILED\n"); |
968 | } else { | |
969 | PRINT_D(INIT_DBG, "wilc1000 already initialized\n"); | |
970 | } | |
971 | return ret; | |
972 | } | |
973 | ||
1608c403 | 974 | static int mac_init_fn(struct net_device *ndev) |
c5c77ba1 | 975 | { |
98b89847 LK |
976 | netif_start_queue(ndev); |
977 | netif_stop_queue(ndev); | |
c5c77ba1 JK |
978 | |
979 | return 0; | |
980 | } | |
c5c77ba1 | 981 | |
0e1af73d | 982 | int wilc_mac_open(struct net_device *ndev) |
c5c77ba1 | 983 | { |
a4cac481 | 984 | struct wilc_vif *vif; |
562ed3f1 | 985 | struct wilc *wilc; |
c5c77ba1 | 986 | |
c5c77ba1 | 987 | unsigned char mac_add[ETH_ALEN] = {0}; |
c5c77ba1 JK |
988 | int ret = 0; |
989 | int i = 0; | |
2726887c | 990 | struct wilc_priv *priv; |
f3c1366e GL |
991 | struct wilc *wl; |
992 | ||
a4cac481 GL |
993 | vif = netdev_priv(ndev); |
994 | wl = vif->wilc; | |
c5c77ba1 | 995 | |
b03314e2 | 996 | if (!wl|| !wl->dev) { |
7d05652c CG |
997 | netdev_err(ndev, "wilc1000: SPI device not ready\n"); |
998 | return -ENODEV; | |
999 | } | |
b03314e2 | 1000 | |
a4cac481 GL |
1001 | vif = netdev_priv(ndev); |
1002 | wilc = vif->wilc; | |
1006b5c7 | 1003 | priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy); |
c5c77ba1 JK |
1004 | PRINT_D(INIT_DBG, "MAC OPEN[%p]\n", ndev); |
1005 | ||
dd4b6a83 | 1006 | ret = wilc_init_host_int(ndev); |
c5c77ba1 JK |
1007 | if (ret < 0) { |
1008 | PRINT_ER("Failed to initialize host interface\n"); | |
1009 | ||
1010 | return ret; | |
1011 | } | |
c5c77ba1 | 1012 | |
c5c77ba1 | 1013 | PRINT_D(INIT_DBG, "*** re-init ***\n"); |
a4cac481 | 1014 | ret = wilc1000_wlan_init(ndev, vif); |
c5c77ba1 JK |
1015 | if (ret < 0) { |
1016 | PRINT_ER("Failed to initialize wilc1000\n"); | |
a9a16823 | 1017 | wilc_deinit_host_int(ndev); |
c5c77ba1 JK |
1018 | return ret; |
1019 | } | |
1020 | ||
fbf5379b | 1021 | wilc_get_mac_address(vif, mac_add); |
310a28fd | 1022 | PRINT_D(INIT_DBG, "Mac address: %pM\n", mac_add); |
c5c77ba1 | 1023 | |
f3c1366e | 1024 | for (i = 0; i < wl->vif_num; i++) { |
1f435d2e GL |
1025 | if (ndev == wl->vif[i]->ndev) { |
1026 | memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN); | |
e32737e9 | 1027 | wilc_set_operation_mode(vif, vif->iftype); |
c5c77ba1 JK |
1028 | break; |
1029 | } | |
1030 | } | |
1031 | ||
1f435d2e | 1032 | memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN); |
c5c77ba1 JK |
1033 | |
1034 | if (!is_valid_ether_addr(ndev->dev_addr)) { | |
1035 | PRINT_ER("Error: Wrong MAC address\n"); | |
339d244a LK |
1036 | wilc_deinit_host_int(ndev); |
1037 | wilc1000_wlan_deinit(ndev); | |
1038 | return -EINVAL; | |
c5c77ba1 JK |
1039 | } |
1040 | ||
1006b5c7 GL |
1041 | wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy, |
1042 | vif->ndev->ieee80211_ptr, | |
a4cac481 GL |
1043 | vif->g_struct_frame_reg[0].frame_type, |
1044 | vif->g_struct_frame_reg[0].reg); | |
1006b5c7 GL |
1045 | wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy, |
1046 | vif->ndev->ieee80211_ptr, | |
a4cac481 GL |
1047 | vif->g_struct_frame_reg[1].frame_type, |
1048 | vif->g_struct_frame_reg[1].reg); | |
c5c77ba1 | 1049 | netif_wake_queue(ndev); |
f3c1366e | 1050 | wl->open_ifcs++; |
a4cac481 | 1051 | vif->mac_opened = 1; |
c5c77ba1 | 1052 | return 0; |
c5c77ba1 | 1053 | } |
c5c77ba1 | 1054 | |
1608c403 | 1055 | static struct net_device_stats *mac_stats(struct net_device *dev) |
c5c77ba1 | 1056 | { |
a4cac481 | 1057 | struct wilc_vif *vif= netdev_priv(dev); |
c5c77ba1 | 1058 | |
a4cac481 | 1059 | return &vif->netstats; |
c5c77ba1 JK |
1060 | } |
1061 | ||
c5c77ba1 JK |
1062 | static void wilc_set_multicast_list(struct net_device *dev) |
1063 | { | |
c5c77ba1 | 1064 | struct netdev_hw_addr *ha; |
2726887c | 1065 | struct wilc_priv *priv; |
ef7606c5 | 1066 | struct host_if_drv *hif_drv; |
cf60106b | 1067 | struct wilc_vif *vif; |
c5c77ba1 | 1068 | int i = 0; |
8dfaafd6 | 1069 | |
c5c77ba1 | 1070 | priv = wiphy_priv(dev->ieee80211_ptr->wiphy); |
cf60106b | 1071 | vif = netdev_priv(dev); |
ef7606c5 | 1072 | hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv; |
c5c77ba1 | 1073 | |
c5c77ba1 JK |
1074 | if (!dev) |
1075 | return; | |
1076 | ||
582f8a27 LK |
1077 | PRINT_D(INIT_DBG, "Setting Multicast List with count = %d.\n", |
1078 | dev->mc.count); | |
c5c77ba1 JK |
1079 | |
1080 | if (dev->flags & IFF_PROMISC) { | |
17aacd43 | 1081 | PRINT_D(INIT_DBG, "Set promiscuous mode ON, retrive all packets\n"); |
c5c77ba1 JK |
1082 | return; |
1083 | } | |
1084 | ||
582f8a27 LK |
1085 | if ((dev->flags & IFF_ALLMULTI) || |
1086 | (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) { | |
c5c77ba1 | 1087 | PRINT_D(INIT_DBG, "Disable multicast filter, retrive all multicast packets\n"); |
fbf5379b | 1088 | wilc_setup_multicast_filter(vif, false, 0); |
c5c77ba1 JK |
1089 | return; |
1090 | } | |
1091 | ||
c5c77ba1 JK |
1092 | if ((dev->mc.count) == 0) { |
1093 | PRINT_D(INIT_DBG, "Enable multicast filter, retrive directed packets only.\n"); | |
fbf5379b | 1094 | wilc_setup_multicast_filter(vif, true, 0); |
c5c77ba1 JK |
1095 | return; |
1096 | } | |
1097 | ||
c8537e6d | 1098 | netdev_for_each_mc_addr(ha, dev) { |
0e1af73d | 1099 | memcpy(wilc_multicast_mac_addr_list[i], ha->addr, ETH_ALEN); |
c5c77ba1 | 1100 | PRINT_D(INIT_DBG, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i, |
0e1af73d AB |
1101 | wilc_multicast_mac_addr_list[i][0], |
1102 | wilc_multicast_mac_addr_list[i][1], | |
1103 | wilc_multicast_mac_addr_list[i][2], | |
1104 | wilc_multicast_mac_addr_list[i][3], | |
1105 | wilc_multicast_mac_addr_list[i][4], | |
1106 | wilc_multicast_mac_addr_list[i][5]); | |
c5c77ba1 JK |
1107 | i++; |
1108 | } | |
1109 | ||
fbf5379b | 1110 | wilc_setup_multicast_filter(vif, true, (dev->mc.count)); |
c5c77ba1 JK |
1111 | |
1112 | return; | |
c5c77ba1 JK |
1113 | } |
1114 | ||
c5c77ba1 JK |
1115 | static void linux_wlan_tx_complete(void *priv, int status) |
1116 | { | |
c5c77ba1 | 1117 | struct tx_complete_data *pv_data = (struct tx_complete_data *)priv; |
8dfaafd6 | 1118 | |
78174ada | 1119 | if (status == 1) |
c5c77ba1 | 1120 | PRINT_D(TX_DBG, "Packet sent successfully - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); |
78174ada | 1121 | else |
c5c77ba1 | 1122 | PRINT_D(TX_DBG, "Couldn't send packet - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); |
c5c77ba1 | 1123 | dev_kfree_skb(pv_data->skb); |
a18dd630 | 1124 | kfree(pv_data); |
c5c77ba1 JK |
1125 | } |
1126 | ||
0e1af73d | 1127 | int wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) |
c5c77ba1 | 1128 | { |
a4cac481 | 1129 | struct wilc_vif *vif; |
c5c77ba1 | 1130 | struct tx_complete_data *tx_data = NULL; |
44ec3b75 | 1131 | int queue_count; |
fd8f0367 | 1132 | char *udp_buf; |
c5c77ba1 JK |
1133 | struct iphdr *ih; |
1134 | struct ethhdr *eth_h; | |
b7495be5 | 1135 | struct wilc *wilc; |
8dfaafd6 | 1136 | |
a4cac481 GL |
1137 | vif = netdev_priv(ndev); |
1138 | wilc = vif->wilc; | |
c5c77ba1 | 1139 | |
c5c77ba1 JK |
1140 | PRINT_D(TX_DBG, "Sending packet just received from TCP/IP\n"); |
1141 | ||
c5c77ba1 JK |
1142 | if (skb->dev != ndev) { |
1143 | PRINT_ER("Packet not destined to this device\n"); | |
1144 | return 0; | |
1145 | } | |
1146 | ||
b38e9030 | 1147 | tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC); |
3a147c07 | 1148 | if (!tx_data) { |
c5c77ba1 JK |
1149 | PRINT_ER("Failed to allocate memory for tx_data structure\n"); |
1150 | dev_kfree_skb(skb); | |
1151 | netif_wake_queue(ndev); | |
1152 | return 0; | |
1153 | } | |
1154 | ||
1155 | tx_data->buff = skb->data; | |
1156 | tx_data->size = skb->len; | |
1157 | tx_data->skb = skb; | |
1158 | ||
1159 | eth_h = (struct ethhdr *)(skb->data); | |
fc4b95d6 | 1160 | if (eth_h->h_proto == 0x8e88) |
c5c77ba1 | 1161 | PRINT_D(INIT_DBG, "EAPOL transmitted\n"); |
c5c77ba1 | 1162 | |
c5c77ba1 JK |
1163 | ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); |
1164 | ||
fd8f0367 LK |
1165 | udp_buf = (char *)ih + sizeof(struct iphdr); |
1166 | if ((udp_buf[1] == 68 && udp_buf[3] == 67) || | |
1167 | (udp_buf[1] == 67 && udp_buf[3] == 68)) | |
1168 | PRINT_D(GENERIC_DBG, "DHCP Message transmitted, type:%x %x %x\n", | |
1169 | udp_buf[248], udp_buf[249], udp_buf[250]); | |
c5c77ba1 | 1170 | |
c5c77ba1 | 1171 | PRINT_D(TX_DBG, "Sending packet - Size = %d - Address = %p - SKB = %p\n", tx_data->size, tx_data->buff, tx_data->skb); |
c5c77ba1 | 1172 | PRINT_D(TX_DBG, "Adding tx packet to TX Queue\n"); |
a4cac481 GL |
1173 | vif->netstats.tx_packets++; |
1174 | vif->netstats.tx_bytes += tx_data->size; | |
1f435d2e | 1175 | tx_data->pBssid = wilc->vif[vif->u8IfIdx]->bssid; |
44ec3b75 LK |
1176 | queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data, |
1177 | tx_data->buff, tx_data->size, | |
1178 | linux_wlan_tx_complete); | |
c5c77ba1 | 1179 | |
44ec3b75 | 1180 | if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) { |
1f435d2e GL |
1181 | netif_stop_queue(wilc->vif[0]->ndev); |
1182 | netif_stop_queue(wilc->vif[1]->ndev); | |
c5c77ba1 JK |
1183 | } |
1184 | ||
1185 | return 0; | |
1186 | } | |
1187 | ||
0e1af73d | 1188 | int wilc_mac_close(struct net_device *ndev) |
c5c77ba1 | 1189 | { |
2726887c | 1190 | struct wilc_priv *priv; |
a4cac481 | 1191 | struct wilc_vif *vif; |
2db2c8a7 | 1192 | struct host_if_drv *hif_drv; |
ca64ad6e | 1193 | struct wilc *wl; |
c5c77ba1 | 1194 | |
a4cac481 | 1195 | vif = netdev_priv(ndev); |
c5c77ba1 | 1196 | |
1006b5c7 GL |
1197 | if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr || |
1198 | !vif->ndev->ieee80211_ptr->wiphy) { | |
a4cac481 | 1199 | PRINT_ER("vif = NULL\n"); |
c5c77ba1 JK |
1200 | return 0; |
1201 | } | |
1202 | ||
1006b5c7 | 1203 | priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy); |
a4cac481 | 1204 | wl = vif->wilc; |
c5c77ba1 | 1205 | |
3a147c07 | 1206 | if (!priv) { |
c5c77ba1 JK |
1207 | PRINT_ER("priv = NULL\n"); |
1208 | return 0; | |
1209 | } | |
1210 | ||
2db2c8a7 | 1211 | hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv; |
c5c77ba1 | 1212 | |
c5c77ba1 JK |
1213 | PRINT_D(GENERIC_DBG, "Mac close\n"); |
1214 | ||
ca64ad6e GL |
1215 | if (!wl) { |
1216 | PRINT_ER("wl = NULL\n"); | |
c5c77ba1 JK |
1217 | return 0; |
1218 | } | |
1219 | ||
2db2c8a7 LK |
1220 | if (!hif_drv) { |
1221 | PRINT_ER("hif_drv = NULL\n"); | |
c5c77ba1 JK |
1222 | return 0; |
1223 | } | |
1224 | ||
ca64ad6e GL |
1225 | if ((wl->open_ifcs) > 0) { |
1226 | wl->open_ifcs--; | |
c5c77ba1 JK |
1227 | } else { |
1228 | PRINT_ER("ERROR: MAC close called while number of opened interfaces is zero\n"); | |
1229 | return 0; | |
1230 | } | |
1231 | ||
1006b5c7 GL |
1232 | if (vif->ndev) { |
1233 | netif_stop_queue(vif->ndev); | |
c5c77ba1 | 1234 | |
1006b5c7 | 1235 | wilc_deinit_host_int(vif->ndev); |
c5c77ba1 JK |
1236 | } |
1237 | ||
ca64ad6e | 1238 | if (wl->open_ifcs == 0) { |
c5c77ba1 | 1239 | PRINT_D(GENERIC_DBG, "Deinitializing wilc1000\n"); |
ca64ad6e | 1240 | wl->close = 1; |
53dc0cfe | 1241 | wilc1000_wlan_deinit(ndev); |
c5c77ba1 | 1242 | WILC_WFI_deinit_mon_interface(); |
c5c77ba1 JK |
1243 | } |
1244 | ||
8990d856 | 1245 | up(&close_exit_sync); |
a4cac481 | 1246 | vif->mac_opened = 0; |
c5c77ba1 JK |
1247 | |
1248 | return 0; | |
1249 | } | |
1250 | ||
1608c403 | 1251 | static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) |
c5c77ba1 | 1252 | { |
63d03e47 | 1253 | u8 *buff = NULL; |
ca356ada | 1254 | s8 rssi; |
4e4467fd | 1255 | u32 size = 0, length = 0; |
a4cac481 | 1256 | struct wilc_vif *vif; |
2726887c | 1257 | struct wilc_priv *priv; |
9457b05e | 1258 | s32 ret = 0; |
07320b6b | 1259 | struct wilc *wilc; |
c5c77ba1 | 1260 | |
a4cac481 GL |
1261 | vif = netdev_priv(ndev); |
1262 | wilc = vif->wilc; | |
c5c77ba1 | 1263 | |
07320b6b | 1264 | if (!wilc->initialized) |
c5c77ba1 JK |
1265 | return 0; |
1266 | ||
c5c77ba1 | 1267 | switch (cmd) { |
c5c77ba1 JK |
1268 | case SIOCSIWPRIV: |
1269 | { | |
f05ab249 | 1270 | struct iwreq *wrq = (struct iwreq *)req; |
c5c77ba1 JK |
1271 | |
1272 | size = wrq->u.data.length; | |
1273 | ||
1274 | if (size && wrq->u.data.pointer) { | |
582f8a27 LK |
1275 | buff = memdup_user(wrq->u.data.pointer, |
1276 | wrq->u.data.length); | |
360e27a9 SM |
1277 | if (IS_ERR(buff)) |
1278 | return PTR_ERR(buff); | |
c5c77ba1 JK |
1279 | |
1280 | if (strncasecmp(buff, "RSSI", length) == 0) { | |
1006b5c7 | 1281 | priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy); |
fbf5379b | 1282 | ret = wilc_get_rssi(vif, &rssi); |
9457b05e | 1283 | if (ret) |
c5c77ba1 | 1284 | PRINT_ER("Failed to send get rssi param's message queue "); |
c5c77ba1 JK |
1285 | PRINT_INFO(GENERIC_DBG, "RSSI :%d\n", rssi); |
1286 | ||
c5c77ba1 JK |
1287 | rssi += 5; |
1288 | ||
1289 | snprintf(buff, size, "rssi %d", rssi); | |
1290 | ||
1291 | if (copy_to_user(wrq->u.data.pointer, buff, size)) { | |
60cb1e20 | 1292 | PRINT_ER("%s: failed to copy data to user buffer\n", __func__); |
9457b05e | 1293 | ret = -EFAULT; |
c5c77ba1 JK |
1294 | goto done; |
1295 | } | |
1296 | } | |
1297 | } | |
1298 | } | |
1299 | break; | |
1300 | ||
1301 | default: | |
1302 | { | |
1303 | PRINT_INFO(GENERIC_DBG, "Command - %d - has been received\n", cmd); | |
9457b05e | 1304 | ret = -EOPNOTSUPP; |
c5c77ba1 JK |
1305 | goto done; |
1306 | } | |
1307 | } | |
1308 | ||
1309 | done: | |
1310 | ||
642ac6c0 | 1311 | kfree(buff); |
c5c77ba1 | 1312 | |
9457b05e | 1313 | return ret; |
c5c77ba1 JK |
1314 | } |
1315 | ||
562ed3f1 | 1316 | void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset) |
c5c77ba1 | 1317 | { |
c5c77ba1 JK |
1318 | unsigned int frame_len = 0; |
1319 | int stats; | |
1320 | unsigned char *buff_to_send = NULL; | |
1321 | struct sk_buff *skb; | |
c5c77ba1 | 1322 | struct net_device *wilc_netdev; |
a4cac481 | 1323 | struct wilc_vif *vif; |
c5c77ba1 | 1324 | |
0953a2e3 LK |
1325 | if (!wilc) |
1326 | return; | |
1327 | ||
7e725b47 | 1328 | wilc_netdev = get_if_handler(wilc, buff); |
3a147c07 | 1329 | if (!wilc_netdev) |
c5c77ba1 JK |
1330 | return; |
1331 | ||
1332 | buff += pkt_offset; | |
a4cac481 | 1333 | vif = netdev_priv(wilc_netdev); |
c5c77ba1 JK |
1334 | |
1335 | if (size > 0) { | |
c5c77ba1 JK |
1336 | frame_len = size; |
1337 | buff_to_send = buff; | |
1338 | ||
c5c77ba1 | 1339 | skb = dev_alloc_skb(frame_len); |
3a147c07 | 1340 | if (!skb) { |
c5c77ba1 JK |
1341 | PRINT_ER("Low memory - packet droped\n"); |
1342 | return; | |
1343 | } | |
c5c77ba1 JK |
1344 | skb->dev = wilc_netdev; |
1345 | ||
c5c77ba1 JK |
1346 | memcpy(skb_put(skb, frame_len), buff_to_send, frame_len); |
1347 | ||
c5c77ba1 | 1348 | skb->protocol = eth_type_trans(skb, wilc_netdev); |
a4cac481 GL |
1349 | vif->netstats.rx_packets++; |
1350 | vif->netstats.rx_bytes += frame_len; | |
c5c77ba1 JK |
1351 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1352 | stats = netif_rx(skb); | |
1353 | PRINT_D(RX_DBG, "netif_rx ret value is: %d\n", stats); | |
1354 | } | |
c5c77ba1 JK |
1355 | } |
1356 | ||
11f4b2ee | 1357 | void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) |
c5c77ba1 JK |
1358 | { |
1359 | int i = 0; | |
a4cac481 | 1360 | struct wilc_vif *vif; |
c5c77ba1 | 1361 | |
11f4b2ee | 1362 | for (i = 0; i < wilc->vif_num; i++) { |
1f435d2e | 1363 | vif = netdev_priv(wilc->vif[i]->ndev); |
a4cac481 | 1364 | if (vif->monitor_flag) { |
c5c77ba1 JK |
1365 | WILC_WFI_monitor_rx(buff, size); |
1366 | return; | |
1367 | } | |
1368 | } | |
1369 | ||
1f435d2e | 1370 | vif = netdev_priv(wilc->vif[1]->ndev); |
a4cac481 GL |
1371 | if ((buff[0] == vif->g_struct_frame_reg[0].frame_type && vif->g_struct_frame_reg[0].reg) || |
1372 | (buff[0] == vif->g_struct_frame_reg[1].frame_type && vif->g_struct_frame_reg[1].reg)) | |
1f435d2e | 1373 | WILC_WFI_p2p_rx(wilc->vif[1]->ndev, buff, size); |
c5c77ba1 JK |
1374 | } |
1375 | ||
857c7b00 | 1376 | void wilc_netdev_cleanup(struct wilc *wilc) |
4875c499 TC |
1377 | { |
1378 | int i = 0; | |
a4cac481 | 1379 | struct wilc_vif *vif[NUM_CONCURRENT_IFC]; |
4875c499 | 1380 | |
1f435d2e | 1381 | if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) { |
4875c499 TC |
1382 | unregister_inetaddr_notifier(&g_dev_notifier); |
1383 | ||
1384 | for (i = 0; i < NUM_CONCURRENT_IFC; i++) | |
1f435d2e | 1385 | vif[i] = netdev_priv(wilc->vif[i]->ndev); |
4875c499 TC |
1386 | } |
1387 | ||
90b984c8 GL |
1388 | if (wilc && wilc->firmware) |
1389 | release_firmware(wilc->firmware); | |
4875c499 | 1390 | |
1f435d2e | 1391 | if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) { |
08037941 | 1392 | wilc_lock_timeout(wilc, &close_exit_sync, 5 * 1000); |
4875c499 TC |
1393 | |
1394 | for (i = 0; i < NUM_CONCURRENT_IFC; i++) | |
1f435d2e | 1395 | if (wilc->vif[i]->ndev) |
a4cac481 | 1396 | if (vif[i]->mac_opened) |
1f435d2e | 1397 | wilc_mac_close(wilc->vif[i]->ndev); |
4875c499 TC |
1398 | |
1399 | for (i = 0; i < NUM_CONCURRENT_IFC; i++) { | |
1f435d2e GL |
1400 | unregister_netdev(wilc->vif[i]->ndev); |
1401 | wilc_free_wiphy(wilc->vif[i]->ndev); | |
1402 | free_netdev(wilc->vif[i]->ndev); | |
4875c499 TC |
1403 | } |
1404 | } | |
1405 | ||
90b984c8 | 1406 | kfree(wilc); |
4875c499 | 1407 | } |
750ffe9b | 1408 | EXPORT_SYMBOL_GPL(wilc_netdev_cleanup); |
4875c499 | 1409 | |
7d37a4a1 AB |
1410 | int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type, |
1411 | int gpio, const struct wilc_hif_func *ops) | |
c5c77ba1 | 1412 | { |
c5c77ba1 | 1413 | int i; |
a4cac481 | 1414 | struct wilc_vif *vif; |
c5c77ba1 | 1415 | struct net_device *ndev; |
562ed3f1 | 1416 | struct wilc *wl; |
c5c77ba1 | 1417 | |
642768ee | 1418 | sema_init(&close_exit_sync, 0); |
c5c77ba1 | 1419 | |
825b966f | 1420 | wl = kzalloc(sizeof(*wl), GFP_KERNEL); |
562ed3f1 | 1421 | if (!wl) |
ac61ef86 | 1422 | return -ENOMEM; |
c5c77ba1 | 1423 | |
562ed3f1 AB |
1424 | *wilc = wl; |
1425 | wl->io_type = io_type; | |
1426 | wl->gpio = gpio; | |
af9ae09a | 1427 | wl->hif_func = ops; |
c4d139cb | 1428 | |
c5c77ba1 | 1429 | register_inetaddr_notifier(&g_dev_notifier); |
c5c77ba1 JK |
1430 | |
1431 | for (i = 0; i < NUM_CONCURRENT_IFC; i++) { | |
a4cac481 | 1432 | ndev = alloc_etherdev(sizeof(struct wilc_vif)); |
c5c77ba1 JK |
1433 | if (!ndev) { |
1434 | PRINT_ER("Failed to allocate ethernet dev\n"); | |
1435 | return -1; | |
1436 | } | |
1437 | ||
a4cac481 GL |
1438 | vif = netdev_priv(ndev); |
1439 | memset(vif, 0, sizeof(struct wilc_vif)); | |
c5c77ba1 | 1440 | |
84d3b87e | 1441 | if (i == 0) |
c5c77ba1 | 1442 | strcpy(ndev->name, "wlan%d"); |
84d3b87e | 1443 | else |
c5c77ba1 JK |
1444 | strcpy(ndev->name, "p2p%d"); |
1445 | ||
a4cac481 | 1446 | vif->u8IfIdx = wl->vif_num; |
a4cac481 | 1447 | vif->wilc = *wilc; |
1f435d2e GL |
1448 | wl->vif[i] = vif; |
1449 | wl->vif[wl->vif_num]->ndev = ndev; | |
562ed3f1 | 1450 | wl->vif_num++; |
e5af0561 | 1451 | ndev->netdev_ops = &wilc_netdev_ops; |
c5c77ba1 | 1452 | |
c5c77ba1 JK |
1453 | { |
1454 | struct wireless_dev *wdev; | |
2e7d5377 | 1455 | wdev = wilc_create_wiphy(ndev, dev); |
c5c77ba1 | 1456 | |
67039928 AB |
1457 | if (dev) |
1458 | SET_NETDEV_DEV(ndev, dev); | |
c5c77ba1 | 1459 | |
3a147c07 | 1460 | if (!wdev) { |
c5c77ba1 JK |
1461 | PRINT_ER("Can't register WILC Wiphy\n"); |
1462 | return -1; | |
1463 | } | |
1464 | ||
1006b5c7 GL |
1465 | vif->ndev->ieee80211_ptr = wdev; |
1466 | vif->ndev->ml_priv = vif; | |
1467 | wdev->netdev = vif->ndev; | |
a4cac481 GL |
1468 | vif->netstats.rx_packets = 0; |
1469 | vif->netstats.tx_packets = 0; | |
1470 | vif->netstats.rx_bytes = 0; | |
1471 | vif->netstats.tx_bytes = 0; | |
c5c77ba1 | 1472 | } |
c5c77ba1 | 1473 | |
c5c77ba1 | 1474 | if (register_netdev(ndev)) { |
582f8a27 LK |
1475 | PRINT_ER("Device couldn't be registered - %s\n", |
1476 | ndev->name); | |
98b89847 | 1477 | return -1; |
c5c77ba1 JK |
1478 | } |
1479 | ||
a4cac481 GL |
1480 | vif->iftype = STATION_MODE; |
1481 | vif->mac_opened = 0; | |
c5c77ba1 JK |
1482 | } |
1483 | ||
c5c77ba1 JK |
1484 | return 0; |
1485 | } | |
750ffe9b | 1486 | EXPORT_SYMBOL_GPL(wilc_netdev_init); |
c94f05ee AB |
1487 | |
1488 | MODULE_LICENSE("GPL"); |