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