Commit | Line | Data |
---|---|---|
c5c77ba1 JK |
1 | /*! |
2 | * @file wilc_wfi_netdevice.c | |
3 | * @brief File Operations OS wrapper functionality | |
4 | * @author mdaftedar | |
5 | * @sa wilc_wfi_netdevice.h | |
6 | * @date 01 MAR 2012 | |
7 | * @version 1.0 | |
8 | */ | |
9 | ||
10 | #ifdef SIMULATION | |
11 | ||
12 | #include "wilc_wfi_cfgoperations.h" | |
13 | #include "host_interface.h" | |
14 | ||
15 | ||
16 | MODULE_AUTHOR("Mai Daftedar"); | |
17 | MODULE_LICENSE("Dual BSD/GPL"); | |
18 | ||
19 | ||
20 | struct net_device *WILC_WFI_devs[2]; | |
21 | ||
22 | /* | |
23 | * Transmitter lockup simulation, normally disabled. | |
24 | */ | |
25 | static int lockup; | |
26 | module_param(lockup, int, 0); | |
27 | ||
28 | static int timeout = WILC_WFI_TIMEOUT; | |
29 | module_param(timeout, int, 0); | |
30 | ||
31 | /* | |
32 | * Do we run in NAPI mode? | |
33 | */ | |
34 | static int use_napi ; | |
35 | module_param(use_napi, int, 0); | |
36 | ||
37 | ||
38 | /* | |
39 | * A structure representing an in-flight packet. | |
40 | */ | |
41 | struct WILC_WFI_packet { | |
42 | struct WILC_WFI_packet *next; | |
43 | struct net_device *dev; | |
44 | int datalen; | |
45 | u8 data[ETH_DATA_LEN]; | |
46 | }; | |
47 | ||
48 | ||
49 | ||
50 | int pool_size = 8; | |
51 | module_param(pool_size, int, 0); | |
52 | ||
53 | ||
54 | static void WILC_WFI_TxTimeout(struct net_device *dev); | |
55 | static void (*WILC_WFI_Interrupt)(int, void *, struct pt_regs *); | |
56 | ||
57 | /** | |
58 | * @brief WILC_WFI_SetupPool | |
59 | * @details Set up a device's packet pool. | |
60 | * @param[in] struct net_device *dev : Network Device Pointer | |
61 | * @return NONE | |
62 | * @author mdaftedar | |
63 | * @date 01 MAR 2012 | |
64 | * @version 1.0 | |
65 | */ | |
66 | void WILC_WFI_SetupPool(struct net_device *dev) | |
67 | { | |
68 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
69 | int i; | |
70 | struct WILC_WFI_packet *pkt; | |
71 | ||
72 | priv->ppool = NULL; | |
73 | for (i = 0; i < pool_size; i++) { | |
74 | pkt = kmalloc (sizeof (struct WILC_WFI_packet), GFP_KERNEL); | |
75 | if (pkt == NULL) { | |
76 | PRINT_D(RX_DBG, "Ran out of memory allocating packet pool\n"); | |
77 | return; | |
78 | } | |
79 | pkt->dev = dev; | |
80 | pkt->next = priv->ppool; | |
81 | priv->ppool = pkt; | |
82 | } | |
83 | } | |
84 | ||
85 | /** | |
86 | * @brief WILC_WFI_TearDownPool | |
87 | * @details Internal cleanup function that's called after the network device | |
88 | * driver is unregistered | |
89 | * @param[in] struct net_device *dev : Network Device Driver | |
90 | * @return NONE | |
91 | * @author mdaftedar | |
92 | * @date 01 MAR 2012 | |
93 | * @version 1.0 | |
94 | */ | |
95 | void WILC_WFI_TearDownPool(struct net_device *dev) | |
96 | { | |
97 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
98 | struct WILC_WFI_packet *pkt; | |
99 | ||
100 | while ((pkt = priv->ppool)) { | |
101 | priv->ppool = pkt->next; | |
102 | kfree (pkt); | |
103 | /* FIXME - in-flight packets ? */ | |
104 | } | |
105 | } | |
106 | ||
107 | /** | |
108 | * @brief WILC_WFI_GetTxBuffer | |
109 | * @details Buffer/pool management | |
110 | * @param[in] net_device *dev : Network Device Driver Structure | |
111 | * @return struct WILC_WFI_packet | |
112 | * @author mdaftedar | |
113 | * @date 01 MAR 2012 | |
114 | * @version 1.0 | |
115 | */ | |
116 | struct WILC_WFI_packet *WILC_WFI_GetTxBuffer(struct net_device *dev) | |
117 | { | |
118 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
119 | unsigned long flags; | |
120 | struct WILC_WFI_packet *pkt; | |
121 | ||
122 | spin_lock_irqsave(&priv->lock, flags); | |
123 | pkt = priv->ppool; | |
124 | priv->ppool = pkt->next; | |
125 | if (priv->ppool == NULL) { | |
126 | PRINT_INFO(RX_DBG, "Pool empty\n"); | |
127 | netif_stop_queue(dev); | |
128 | } | |
129 | spin_unlock_irqrestore(&priv->lock, flags); | |
130 | return pkt; | |
131 | } | |
132 | /** | |
133 | * @brief WILC_WFI_ReleaseBuffer | |
134 | * @details Buffer/pool management | |
135 | * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet | |
136 | * @return NONE | |
137 | * @author mdaftedar | |
138 | * @date 01 MAR 2012 | |
139 | * @version 1.0 | |
140 | */ | |
141 | void WILC_WFI_ReleaseBuffer(struct WILC_WFI_packet *pkt) | |
142 | { | |
143 | unsigned long flags; | |
144 | struct WILC_WFI_priv *priv = netdev_priv(pkt->dev); | |
145 | ||
146 | spin_lock_irqsave(&priv->lock, flags); | |
147 | pkt->next = priv->ppool; | |
148 | priv->ppool = pkt; | |
149 | spin_unlock_irqrestore(&priv->lock, flags); | |
150 | if (netif_queue_stopped(pkt->dev) && pkt->next == NULL) | |
151 | netif_wake_queue(pkt->dev); | |
152 | } | |
153 | ||
154 | /** | |
155 | * @brief WILC_WFI_EnqueueBuf | |
156 | * @details Enqueuing packets in an RX buffer queue | |
157 | * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet | |
158 | * @param[in] net_device *dev : Network Device Driver Structure | |
159 | * @return NONE | |
160 | * @author mdaftedar | |
161 | * @date 01 MAR 2012 | |
162 | * @version 1.0 | |
163 | */ | |
164 | void WILC_WFI_EnqueueBuf(struct net_device *dev, struct WILC_WFI_packet *pkt) | |
165 | { | |
166 | unsigned long flags; | |
167 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
168 | ||
169 | spin_lock_irqsave(&priv->lock, flags); | |
170 | pkt->next = priv->rx_queue; /* FIXME - misorders packets */ | |
171 | priv->rx_queue = pkt; | |
172 | spin_unlock_irqrestore(&priv->lock, flags); | |
173 | } | |
174 | ||
175 | /** | |
176 | * @brief WILC_WFI_DequeueBuf | |
177 | * @details Dequeuing packets from the RX buffer queue | |
178 | * @param[in] net_device *dev : Network Device Driver Structure | |
179 | * @return WILC_WFI_packet *pkt : Structure holding in-flight pac | |
180 | * @author mdaftedar | |
181 | * @date 01 MAR 2012 | |
182 | * @version 1.0 | |
183 | */ | |
184 | struct WILC_WFI_packet *WILC_WFI_DequeueBuf(struct net_device *dev) | |
185 | { | |
186 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
187 | struct WILC_WFI_packet *pkt; | |
188 | unsigned long flags; | |
189 | ||
190 | spin_lock_irqsave(&priv->lock, flags); | |
191 | pkt = priv->rx_queue; | |
192 | if (pkt != NULL) | |
193 | priv->rx_queue = pkt->next; | |
194 | spin_unlock_irqrestore(&priv->lock, flags); | |
195 | return pkt; | |
196 | } | |
197 | /** | |
198 | * @brief WILC_WFI_RxInts | |
199 | * @details Enable and disable receive interrupts. | |
200 | * @param[in] net_device *dev : Network Device Driver Structure | |
201 | * @param[in] enable : Enable/Disable flag | |
202 | * @return NONE | |
203 | * @author mdaftedar | |
204 | * @date 01 MAR 2012 | |
205 | * @version 1.0 | |
206 | */ | |
207 | static void WILC_WFI_RxInts(struct net_device *dev, int enable) | |
208 | { | |
209 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
210 | priv->rx_int_enabled = enable; | |
211 | } | |
212 | ||
213 | /** | |
214 | * @brief WILC_WFI_Open | |
215 | * @details Open Network Device Driver, called when the network | |
216 | * interface is opened. It starts the interface's transmit queue. | |
217 | * @param[in] net_device *dev : Network Device Driver Structure | |
218 | * @param[in] enable : Enable/Disable flag | |
219 | * @return int : Returns 0 upon success. | |
220 | * @author mdaftedar | |
221 | * @date 01 MAR 2012 | |
222 | * @version 1.0 | |
223 | */ | |
224 | int WILC_WFI_Open(struct net_device *dev) | |
225 | { | |
226 | /* request_region(), request_irq(), .... (like fops->open) */ | |
227 | /* | |
228 | * Assign the hardware address of the board: use "\0SNULx", where | |
229 | * x is 0 or 1. The first byte is '\0' to avoid being a multicast | |
230 | * address (the first byte of multicast addrs is odd). | |
231 | */ | |
232 | memcpy(dev->dev_addr, "\0WLAN0", ETH_ALEN); | |
233 | if (dev == WILC_WFI_devs[1]) | |
234 | dev->dev_addr[ETH_ALEN - 1]++; /* \0SNUL1 */ | |
235 | ||
236 | WILC_WFI_InitHostInt(dev); | |
237 | netif_start_queue(dev); | |
238 | return 0; | |
239 | } | |
240 | /** | |
241 | * @brief WILC_WFI_Release | |
242 | * @details Release Network Device Driver, called when the network | |
243 | * interface is stopped or brought down. This function marks | |
244 | * the network driver as not being able to transmit | |
245 | * @param[in] net_device *dev : Network Device Driver Structure | |
246 | * @return int : Return 0 on Success. | |
247 | * @author mdaftedar | |
248 | * @date 01 MAR 2012 | |
249 | * @version 1.0 | |
250 | */ | |
251 | int WILC_WFI_Release(struct net_device *dev) | |
252 | { | |
253 | /* release ports, irq and such -- like fops->close */ | |
254 | ||
255 | netif_stop_queue(dev); /* can't transmit any more */ | |
256 | ||
257 | return 0; | |
258 | } | |
259 | /** | |
260 | * @brief WILC_WFI_Config | |
261 | * @details Configuration changes (passed on by ifconfig) | |
262 | * @param[in] net_device *dev : Network Device Driver Structure | |
263 | * @param[in] struct ifmap *map : Contains the ioctl implementation for the | |
264 | * network driver. | |
265 | * @return int : Return 0 on Success. | |
266 | * @author mdaftedar | |
267 | * @date 01 MAR 2012 | |
268 | * @version 1.0 | |
269 | */ | |
270 | int WILC_WFI_Config(struct net_device *dev, struct ifmap *map) | |
271 | { | |
272 | if (dev->flags & IFF_UP) /* can't act on a running interface */ | |
273 | return -EBUSY; | |
274 | ||
275 | /* Don't allow changing the I/O address */ | |
276 | if (map->base_addr != dev->base_addr) { | |
277 | PRINT_D(RX_DBG, KERN_WARNING "WILC_WFI: Can't change I/O address\n"); | |
278 | return -EOPNOTSUPP; | |
279 | } | |
280 | ||
281 | /* Allow changing the IRQ */ | |
282 | if (map->irq != dev->irq) { | |
283 | dev->irq = map->irq; | |
284 | /* request_irq() is delayed to open-time */ | |
285 | } | |
286 | ||
287 | /* ignore other fields */ | |
288 | return 0; | |
289 | } | |
290 | /** | |
291 | * @brief WILC_WFI_Rx | |
292 | * @details Receive a packet: retrieve, encapsulate and pass over to upper | |
293 | * levels | |
294 | * @param[in] net_device *dev : Network Device Driver Structure | |
295 | * @param[in] WILC_WFI_packet : | |
296 | * @return NONE | |
297 | * @author mdaftedar | |
298 | * @date 01 MAR 2012 | |
299 | * @version 1.0 | |
300 | */ | |
301 | void WILC_WFI_Rx(struct net_device *dev, struct WILC_WFI_packet *pkt) | |
302 | { | |
303 | int i; | |
304 | struct sk_buff *skb; | |
305 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
306 | s8 rssi; | |
307 | /* | |
308 | * The packet has been retrieved from the transmission | |
309 | * medium. Build an skb around it, so upper layers can handle it | |
310 | */ | |
311 | ||
312 | ||
313 | skb = dev_alloc_skb(pkt->datalen + 2); | |
314 | if (!skb) { | |
315 | if (printk_ratelimit()) | |
316 | PRINT_D(RX_DBG, "WILC_WFI rx: low on mem - packet dropped\n"); | |
317 | priv->stats.rx_dropped++; | |
318 | goto out; | |
319 | } | |
320 | skb_reserve(skb, 2); /* align IP on 16B boundary */ | |
321 | memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); | |
322 | ||
323 | if (priv->monitor_flag) { | |
324 | PRINT_INFO(RX_DBG, "In monitor device name %s\n", dev->name); | |
325 | priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); | |
326 | PRINT_D(RX_DBG, "VALUE PASSED IN OF HRWD %p\n", priv->hWILCWFIDrv); | |
327 | /* host_int_get_rssi(priv->hWILCWFIDrv, &(rssi)); */ | |
328 | if (INFO) { | |
329 | for (i = 14; i < skb->len; i++) | |
330 | PRINT_INFO(RX_DBG, "RXdata[%d] %02x\n", i, skb->data[i]); | |
331 | } | |
332 | WILC_WFI_monitor_rx(dev, skb); | |
333 | return; | |
334 | } | |
c5c77ba1 JK |
335 | out: |
336 | return; | |
337 | } | |
338 | ||
339 | /** | |
340 | * @brief WILC_WFI_Poll | |
341 | * @details The poll implementation | |
342 | * @param[in] struct napi_struct *napi : | |
343 | * @param[in] int budget : | |
344 | * @return int : Return 0 on Success. | |
345 | * @author mdaftedar | |
346 | * @date 01 MAR 2012 | |
347 | * @version 1.0 | |
348 | */ | |
349 | static int WILC_WFI_Poll(struct napi_struct *napi, int budget) | |
350 | { | |
351 | int npackets = 0; | |
352 | struct sk_buff *skb; | |
353 | struct WILC_WFI_priv *priv = container_of(napi, struct WILC_WFI_priv, napi); | |
354 | struct net_device *dev = priv->dev; | |
355 | struct WILC_WFI_packet *pkt; | |
356 | ||
357 | while (npackets < budget && priv->rx_queue) { | |
358 | pkt = WILC_WFI_DequeueBuf(dev); | |
359 | skb = dev_alloc_skb(pkt->datalen + 2); | |
360 | if (!skb) { | |
361 | if (printk_ratelimit()) | |
362 | PRINT_D(RX_DBG, "WILC_WFI: packet dropped\n"); | |
363 | priv->stats.rx_dropped++; | |
364 | WILC_WFI_ReleaseBuffer(pkt); | |
365 | continue; | |
366 | } | |
367 | skb_reserve(skb, 2); /* align IP on 16B boundary */ | |
368 | memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); | |
369 | skb->dev = dev; | |
370 | skb->protocol = eth_type_trans(skb, dev); | |
371 | skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ | |
372 | netif_receive_skb(skb); | |
373 | /* Maintain stats */ | |
374 | npackets++; | |
375 | WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, pkt->datalen, WILC_WFI_RX_PKT); | |
376 | WILC_WFI_ReleaseBuffer(pkt); | |
377 | } | |
378 | /* If we processed all packets, we're done; tell the kernel and re-enable ints */ | |
379 | if (npackets < budget) { | |
380 | napi_complete(napi); | |
381 | WILC_WFI_RxInts(dev, 1); | |
382 | } | |
383 | return npackets; | |
384 | } | |
385 | ||
386 | /** | |
387 | * @brief WILC_WFI_Poll | |
388 | * @details The typical interrupt entry point | |
389 | * @param[in] struct napi_struct *napi : | |
390 | * @param[in] int budget : | |
391 | * @return int : Return 0 on Success. | |
392 | * @author mdaftedar | |
393 | * @date 01 MAR 2012 | |
394 | * @version 1.0 | |
395 | */ | |
396 | static void WILC_WFI_RegularInterrupt(int irq, void *dev_id, struct pt_regs *regs) | |
397 | { | |
398 | int statusword; | |
399 | struct WILC_WFI_priv *priv; | |
400 | struct WILC_WFI_packet *pkt = NULL; | |
401 | /* | |
402 | * As usual, check the "device" pointer to be sure it is | |
403 | * really interrupting. | |
404 | * Then assign "struct device *dev" | |
405 | */ | |
406 | struct net_device *dev = (struct net_device *)dev_id; | |
407 | /* ... and check with hw if it's really ours */ | |
408 | ||
409 | /* paranoid */ | |
410 | if (!dev) | |
411 | return; | |
412 | ||
413 | /* Lock the device */ | |
414 | priv = netdev_priv(dev); | |
415 | spin_lock(&priv->lock); | |
416 | ||
417 | /* retrieve statusword: real netdevices use I/O instructions */ | |
418 | statusword = priv->status; | |
419 | priv->status = 0; | |
420 | if (statusword & WILC_WFI_RX_INTR) { | |
421 | /* send it to WILC_WFI_rx for handling */ | |
422 | pkt = priv->rx_queue; | |
423 | if (pkt) { | |
424 | priv->rx_queue = pkt->next; | |
425 | WILC_WFI_Rx(dev, pkt); | |
426 | } | |
427 | } | |
428 | if (statusword & WILC_WFI_TX_INTR) { | |
429 | /* a transmission is over: free the skb */ | |
430 | WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); | |
431 | dev_kfree_skb(priv->skb); | |
432 | } | |
433 | ||
434 | /* Unlock the device and we are done */ | |
435 | spin_unlock(&priv->lock); | |
436 | if (pkt) | |
437 | WILC_WFI_ReleaseBuffer(pkt); /* Do this outside the lock! */ | |
438 | return; | |
439 | } | |
440 | /** | |
441 | * @brief WILC_WFI_NapiInterrupt | |
442 | * @details A NAPI interrupt handler | |
443 | * @param[in] irq: | |
444 | * @param[in] dev_id: | |
445 | * @param[in] pt_regs: | |
446 | * @return NONE | |
447 | * @author mdaftedar | |
448 | * @date 01 MAR 2012 | |
449 | * @version 1.0 | |
450 | */ | |
451 | static void WILC_WFI_NapiInterrupt(int irq, void *dev_id, struct pt_regs *regs) | |
452 | { | |
453 | int statusword; | |
454 | struct WILC_WFI_priv *priv; | |
455 | ||
456 | /* | |
457 | * As usual, check the "device" pointer for shared handlers. | |
458 | * Then assign "struct device *dev" | |
459 | */ | |
460 | struct net_device *dev = (struct net_device *)dev_id; | |
461 | /* ... and check with hw if it's really ours */ | |
462 | ||
463 | /* paranoid */ | |
464 | if (!dev) | |
465 | return; | |
466 | ||
467 | /* Lock the device */ | |
468 | priv = netdev_priv(dev); | |
469 | spin_lock(&priv->lock); | |
470 | ||
471 | /* retrieve statusword: real netdevices use I/O instructions */ | |
472 | statusword = priv->status; | |
473 | priv->status = 0; | |
474 | if (statusword & WILC_WFI_RX_INTR) { | |
475 | WILC_WFI_RxInts(dev, 0); /* Disable further interrupts */ | |
476 | napi_schedule(&priv->napi); | |
477 | } | |
478 | if (statusword & WILC_WFI_TX_INTR) { | |
479 | /* a transmission is over: free the skb */ | |
480 | ||
481 | WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); | |
482 | dev_kfree_skb(priv->skb); | |
483 | } | |
484 | ||
485 | /* Unlock the device and we are done */ | |
486 | spin_unlock(&priv->lock); | |
487 | return; | |
488 | } | |
489 | ||
490 | /** | |
491 | * @brief MI_WFI_HwTx | |
492 | * @details Transmit a packet (low level interface) | |
493 | * @param[in] buf: | |
494 | * @param[in] len: | |
495 | * @param[in] net_device *dev: | |
496 | * @return NONE | |
497 | * @author mdaftedar | |
498 | * @date 01 MAR 2012 | |
499 | * @version 1.0 | |
500 | */ | |
501 | void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) | |
502 | { | |
503 | /* | |
504 | * This function deals with hw details. This interface loops | |
505 | * back the packet to the other WILC_WFI interface (if any). | |
506 | * In other words, this function implements the WILC_WFI behaviour, | |
507 | * while all other procedures are rather device-independent | |
508 | */ | |
509 | struct iphdr *ih; | |
510 | struct net_device *dest; | |
511 | struct WILC_WFI_priv *priv; | |
512 | u32 *saddr, *daddr; | |
513 | struct WILC_WFI_packet *tx_buffer; | |
514 | ||
515 | ||
516 | /* I am paranoid. Ain't I? */ | |
517 | if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { | |
518 | PRINT_D(RX_DBG, "WILC_WFI: Hmm... packet too short (%i octets)\n", | |
519 | len); | |
520 | return; | |
521 | } | |
522 | ||
523 | if (0) { /* enable this conditional to look at the data */ | |
524 | int i; | |
525 | PRINT_D(RX_DBG, "len is %i", len); | |
526 | for (i = 14; i < len; i++) | |
527 | PRINT_D(RX_DBG, "TXdata[%d] %02x\n", i, buf[i] & 0xff); | |
528 | /* PRINT_D(RX_DBG, "\n"); */ | |
529 | } | |
530 | /* | |
531 | * Ethhdr is 14 bytes, but the kernel arranges for iphdr | |
532 | * to be aligned (i.e., ethhdr is unaligned) | |
533 | */ | |
534 | ih = (struct iphdr *)(buf + sizeof(struct ethhdr)); | |
535 | saddr = &ih->saddr; | |
536 | daddr = &ih->daddr; | |
537 | ||
538 | ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */ | |
539 | ((u8 *)daddr)[2] ^= 1; | |
540 | ||
541 | ih->check = 0; /* and rebuild the checksum (ip needs it) */ | |
542 | ih->check = ip_fast_csum((unsigned char *)ih, ih->ihl); | |
543 | ||
544 | ||
545 | if (dev == WILC_WFI_devs[0]) | |
546 | PRINT_D(RX_DBG, "%08x:%05i --> %08x:%05i\n", | |
547 | ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source), | |
548 | ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest)); | |
549 | else | |
550 | PRINT_D(RX_DBG, "%08x:%05i <-- %08x:%05i\n", | |
551 | ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest), | |
552 | ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source)); | |
553 | ||
554 | /* | |
555 | * Ok, now the packet is ready for transmission: first simulate a | |
556 | * receive interrupt on the twin device, then a | |
557 | * transmission-done on the transmitting device | |
558 | */ | |
559 | dest = WILC_WFI_devs[dev == WILC_WFI_devs[0] ? 1 : 0]; | |
560 | priv = netdev_priv(dest); | |
561 | ||
562 | tx_buffer = WILC_WFI_GetTxBuffer(dev); | |
563 | tx_buffer->datalen = len; | |
564 | memcpy(tx_buffer->data, buf, len); | |
565 | WILC_WFI_EnqueueBuf(dest, tx_buffer); | |
566 | if (priv->rx_int_enabled) { | |
567 | priv->status |= WILC_WFI_RX_INTR; | |
568 | WILC_WFI_Interrupt(0, dest, NULL); | |
569 | } | |
570 | ||
571 | priv = netdev_priv(dev); | |
572 | priv->tx_packetlen = len; | |
573 | priv->tx_packetdata = buf; | |
574 | priv->status |= WILC_WFI_TX_INTR; | |
575 | if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) { | |
576 | /* Simulate a dropped transmit interrupt */ | |
577 | netif_stop_queue(dev); | |
578 | PRINT_D(RX_DBG, "Simulate lockup at %ld, txp %ld\n", jiffies, | |
579 | (unsigned long) priv->stats.tx_packets); | |
580 | } else | |
581 | WILC_WFI_Interrupt(0, dev, NULL); | |
582 | ||
583 | } | |
584 | ||
585 | /** | |
586 | * @brief WILC_WFI_Tx | |
587 | * @details Transmit a packet (called by the kernel) | |
588 | * @param[in] sk_buff *skb: | |
589 | * @param[in] net_device *dev: | |
590 | * @return NONE | |
591 | * @author mdaftedar | |
592 | * @date 01 MAR 2012 | |
593 | * @version 1.0 | |
594 | */ | |
595 | int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev) | |
596 | { | |
597 | int len; | |
598 | char *data, shortpkt[ETH_ZLEN]; | |
599 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
600 | ||
601 | /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */ | |
602 | ||
603 | /* if(priv->monitor_flag) */ | |
604 | /* mac80211_hwsim_monitor_rx(skb); */ | |
605 | ||
606 | ||
607 | data = skb->data; | |
608 | len = skb->len; | |
609 | ||
610 | if (len < ETH_ZLEN) { | |
611 | memset(shortpkt, 0, ETH_ZLEN); | |
612 | memcpy(shortpkt, skb->data, skb->len); | |
613 | len = ETH_ZLEN; | |
614 | data = shortpkt; | |
615 | } | |
616 | dev->trans_start = jiffies; /* save the timestamp */ | |
617 | ||
618 | /* Remember the skb, so we can free it at interrupt time */ | |
619 | priv->skb = skb; | |
620 | ||
621 | /* actual deliver of data is device-specific, and not shown here */ | |
622 | WILC_WFI_HwTx(data, len, dev); | |
623 | ||
624 | return 0; /* Our simple device can not fail */ | |
625 | } | |
626 | ||
627 | /** | |
628 | * @brief WILC_WFI_TxTimeout | |
629 | * @details Deal with a transmit timeout. | |
630 | * @param[in] net_device *dev: | |
631 | * @return NONE | |
632 | * @author mdaftedar | |
633 | * @date 01 MAR 2012 | |
634 | * @version 1.0 | |
635 | */ | |
636 | void WILC_WFI_TxTimeout(struct net_device *dev) | |
637 | { | |
638 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
639 | ||
640 | PRINT_D(RX_DBG, "Transmit timeout at %ld, latency %ld\n", jiffies, | |
641 | jiffies - dev->trans_start); | |
642 | /* Simulate a transmission interrupt to get things moving */ | |
643 | priv->status = WILC_WFI_TX_INTR; | |
644 | WILC_WFI_Interrupt(0, dev, NULL); | |
645 | priv->stats.tx_errors++; | |
646 | netif_wake_queue(dev); | |
647 | return; | |
648 | } | |
649 | ||
650 | /** | |
651 | * @brief WILC_WFI_Ioctl | |
652 | * @details Ioctl commands | |
653 | * @param[in] net_device *dev: | |
654 | * @param[in] ifreq *rq | |
655 | * @param[in] cmd: | |
656 | * @return int : Return 0 on Success | |
657 | * @author mdaftedar | |
658 | * @date 01 MAR 2012 | |
659 | * @version 1.0 | |
660 | */ | |
661 | int WILC_WFI_Ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |
662 | { | |
663 | PRINT_D(RX_DBG, "ioctl\n"); | |
664 | return 0; | |
665 | } | |
666 | ||
667 | /** | |
668 | * @brief WILC_WFI_Stat | |
669 | * @details Return statistics to the caller | |
670 | * @param[in] net_device *dev: | |
671 | * @return WILC_WFI_Stats : Return net_device_stats stucture with the | |
672 | * network device driver private data contents. | |
673 | * @author mdaftedar | |
674 | * @date 01 MAR 2012 | |
675 | * @version 1.0 | |
676 | */ | |
677 | struct net_device_stats *WILC_WFI_Stats(struct net_device *dev) | |
678 | { | |
679 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
680 | return &priv->stats; | |
681 | } | |
682 | ||
683 | /** | |
684 | * @brief WILC_WFI_RebuildHeader | |
685 | * @details This function is called to fill up an eth header, since arp is not | |
686 | * available on the interface | |
687 | * @param[in] sk_buff *skb: | |
688 | * @return int : Return 0 on Success | |
689 | * @author mdaftedar | |
690 | * @date 01 MAR 2012 | |
691 | * @version 1.0 | |
692 | */ | |
693 | int WILC_WFI_RebuildHeader(struct sk_buff *skb) | |
694 | { | |
695 | struct ethhdr *eth = (struct ethhdr *) skb->data; | |
696 | struct net_device *dev = skb->dev; | |
697 | ||
698 | memcpy(eth->h_source, dev->dev_addr, dev->addr_len); | |
699 | memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); | |
700 | eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ | |
701 | return 0; | |
702 | } | |
703 | /** | |
704 | * @brief WILC_WFI_RebuildHeader | |
705 | * @details This function is called to fill up an eth header, since arp is not | |
706 | * available on the interface | |
707 | * @param[in] sk_buff *skb: | |
708 | * @param[in] struct net_device *dev: | |
709 | * @param[in] unsigned short type: | |
710 | * @param[in] const void *saddr, | |
711 | * @param[in] const void *daddr: | |
712 | * @param[in] unsigned int len | |
713 | * @return int : Return 0 on Success | |
714 | * @author mdaftedar | |
715 | * @date 01 MAR 2012 | |
716 | * @version 1.0 | |
717 | */ | |
718 | int WILC_WFI_Header(struct sk_buff *skb, struct net_device *dev, | |
719 | unsigned short type, const void *daddr, const void *saddr, | |
720 | unsigned int len) | |
721 | { | |
722 | struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); | |
723 | ||
724 | eth->h_proto = htons(type); | |
725 | memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len); | |
726 | memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len); | |
727 | eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ | |
728 | return dev->hard_header_len; | |
729 | } | |
730 | ||
731 | /** | |
732 | * @brief WILC_WFI_ChangeMtu | |
733 | * @details The "change_mtu" method is usually not needed. | |
734 | * If you need it, it must be like this. | |
735 | * @param[in] net_device *dev : Network Device Driver Structure | |
736 | * @param[in] new_mtu : | |
737 | * @return int : Returns 0 on Success. | |
738 | * @author mdaftedar | |
739 | * @date 01 MAR 2012 | |
740 | * @version 1.0 | |
741 | */ | |
742 | int WILC_WFI_ChangeMtu(struct net_device *dev, int new_mtu) | |
743 | { | |
744 | unsigned long flags; | |
745 | struct WILC_WFI_priv *priv = netdev_priv(dev); | |
746 | spinlock_t *lock = &priv->lock; | |
747 | ||
748 | /* check ranges */ | |
749 | if ((new_mtu < 68) || (new_mtu > 1500)) | |
750 | return -EINVAL; | |
751 | /* | |
752 | * Do anything you need, and the accept the value | |
753 | */ | |
754 | spin_lock_irqsave(lock, flags); | |
755 | dev->mtu = new_mtu; | |
756 | spin_unlock_irqrestore(lock, flags); | |
757 | return 0; /* success */ | |
758 | } | |
759 | ||
760 | static const struct header_ops WILC_WFI_header_ops = { | |
761 | .create = WILC_WFI_Header, | |
762 | .rebuild = WILC_WFI_RebuildHeader, | |
763 | .cache = NULL, /* disable caching */ | |
764 | }; | |
765 | ||
766 | ||
767 | static const struct net_device_ops WILC_WFI_netdev_ops = { | |
768 | .ndo_open = WILC_WFI_Open, | |
769 | .ndo_stop = WILC_WFI_Release, | |
770 | .ndo_set_config = WILC_WFI_Config, | |
771 | .ndo_start_xmit = WILC_WFI_Tx, | |
772 | .ndo_do_ioctl = WILC_WFI_Ioctl, | |
773 | .ndo_get_stats = WILC_WFI_Stats, | |
774 | .ndo_change_mtu = WILC_WFI_ChangeMtu, | |
775 | .ndo_tx_timeout = WILC_WFI_TxTimeout, | |
776 | }; | |
777 | ||
778 | /** | |
779 | * @brief WILC_WFI_Init | |
780 | * @details The init function (sometimes called probe). | |
781 | * It is invoked by register_netdev() | |
782 | * @param[in] net_device *dev: | |
783 | * @return NONE | |
784 | * @author mdaftedar | |
785 | * @date 01 MAR 2012 | |
786 | * @version 1.0 | |
787 | */ | |
788 | void WILC_WFI_Init(struct net_device *dev) | |
789 | { | |
790 | struct WILC_WFI_priv *priv; | |
791 | ||
792 | ||
793 | /* | |
794 | * Then, assign other fields in dev, using ether_setup() and some | |
795 | * hand assignments | |
796 | */ | |
797 | ether_setup(dev); /* assign some of the fields */ | |
798 | /* 1- Allocate space */ | |
799 | ||
800 | dev->netdev_ops = &WILC_WFI_netdev_ops; | |
801 | dev->header_ops = &WILC_WFI_header_ops; | |
802 | dev->watchdog_timeo = timeout; | |
803 | /* keep the default flags, just add NOARP */ | |
804 | dev->flags |= IFF_NOARP; | |
805 | dev->features |= NETIF_F_NO_CSUM; | |
806 | /* | |
807 | * Then, initialize the priv field. This encloses the statistics | |
808 | * and a few private fields. | |
809 | */ | |
810 | priv = netdev_priv(dev); | |
811 | memset(priv, 0, sizeof(struct WILC_WFI_priv)); | |
812 | priv->dev = dev; | |
813 | netif_napi_add(dev, &priv->napi, WILC_WFI_Poll, 2); | |
814 | /* The last parameter above is the NAPI "weight". */ | |
815 | spin_lock_init(&priv->lock); | |
816 | WILC_WFI_RxInts(dev, 1); /* enable receive interrupts */ | |
817 | WILC_WFI_SetupPool(dev); | |
818 | } | |
819 | ||
820 | /** | |
821 | * @brief WILC_WFI_Stat | |
822 | * @details Return statistics to the caller | |
823 | * @param[in] net_device *dev: | |
824 | * @return WILC_WFI_Stats : Return net_device_stats stucture with the | |
825 | * network device driver private data contents. | |
826 | * @author mdaftedar | |
827 | * @date 01 MAR 2012 | |
828 | * @version 1.0 | |
829 | */ | |
830 | ||
831 | void WILC_WFI_Cleanup(void) | |
832 | { | |
833 | int i; | |
834 | struct WILC_WFI_priv *priv[2]; | |
835 | ||
836 | /*if(hwsim_mon!=NULL) | |
837 | * { | |
838 | * PRINT_D(RX_DBG, "Freeing monitor interface\n"); | |
839 | * unregister_netdev(hwsim_mon); | |
840 | * free_netdev(hwsim_mon); | |
841 | * }*/ | |
842 | for (i = 0; i < 2; i++) { | |
843 | priv[i] = netdev_priv(WILC_WFI_devs[i]); | |
844 | ||
845 | if (WILC_WFI_devs[i]) { | |
846 | PRINT_D(RX_DBG, "Unregistering\n"); | |
847 | unregister_netdev(WILC_WFI_devs[i]); | |
848 | WILC_WFI_TearDownPool(WILC_WFI_devs[i]); | |
849 | free_netdev(WILC_WFI_devs[i]); | |
850 | PRINT_D(RX_DBG, "[NETDEV]Stopping interface\n"); | |
851 | WILC_WFI_DeInitHostInt(WILC_WFI_devs[i]); | |
852 | WILC_WFI_WiphyFree(WILC_WFI_devs[i]); | |
853 | } | |
854 | ||
855 | } | |
856 | /* unregister_netdev(hwsim_mon); */ | |
857 | WILC_WFI_deinit_mon_interface(); | |
858 | return; | |
859 | } | |
860 | ||
861 | ||
862 | void StartConfigSim(void); | |
863 | ||
864 | ||
865 | ||
866 | ||
867 | ||
868 | ||
869 | ||
870 | /** | |
871 | * @brief WILC_WFI_Stat | |
872 | * @details Return statistics to the caller | |
873 | * @param[in] net_device *dev: | |
874 | * @return WILC_WFI_Stats : Return net_device_stats stucture with the | |
875 | * network device driver private data contents. | |
876 | * @author mdaftedar | |
877 | * @date 01 MAR 2012 | |
878 | * @version 1.0 | |
879 | */ | |
880 | int WILC_WFI_InitModule(void) | |
881 | { | |
882 | ||
883 | int result, i, ret = -ENOMEM; | |
884 | struct WILC_WFI_priv *priv[2], *netpriv; | |
885 | struct wireless_dev *wdev; | |
886 | WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; | |
887 | char buf[IFNAMSIZ]; | |
888 | ||
889 | for (i = 0; i < 2; i++) { | |
890 | ||
891 | /* Allocate the net devices */ | |
892 | WILC_WFI_devs[i] = alloc_netdev(sizeof(struct WILC_WFI_priv), "wlan%d", | |
893 | WILC_WFI_Init); | |
894 | if (WILC_WFI_devs[i] == NULL) | |
895 | goto out; | |
896 | /* priv[i] = netdev_priv(WILC_WFI_devs[i]); */ | |
897 | ||
898 | wdev = WILC_WFI_WiphyRegister(WILC_WFI_devs[i]); | |
899 | WILC_WFI_devs[i]->ieee80211_ptr = wdev; | |
900 | netpriv = netdev_priv(WILC_WFI_devs[i]); | |
901 | netpriv->dev->ieee80211_ptr = wdev; | |
902 | netpriv->dev->ml_priv = netpriv; | |
903 | wdev->netdev = netpriv->dev; | |
904 | ||
905 | /*Registering the net device*/ | |
906 | result = register_netdev(WILC_WFI_devs[i]); | |
907 | if (result) | |
908 | PRINT_D(RX_DBG, "WILC_WFI: error %i registering device \"%s\"\n", | |
909 | result, WILC_WFI_devs[i]->name); | |
910 | else | |
911 | ret = 0; | |
912 | } | |
913 | ||
914 | ||
915 | /*init atmel driver */ | |
916 | priv[0] = netdev_priv(WILC_WFI_devs[0]); | |
917 | priv[1] = netdev_priv(WILC_WFI_devs[1]); | |
918 | ||
919 | if (priv[1]->dev->ieee80211_ptr->wiphy->interface_modes && BIT(NL80211_IFTYPE_MONITOR)) { | |
920 | /* snprintf(buf, IFNAMSIZ, "mon.%s", priv[1]->dev->name); */ | |
921 | /* WILC_WFI_init_mon_interface(); */ | |
922 | /* priv[1]->monitor_flag = 1; */ | |
923 | ||
924 | } | |
72ed4dc7 | 925 | priv[0]->bCfgScanning = false; |
c5c77ba1 JK |
926 | priv[0]->u32RcvdChCount = 0; |
927 | ||
928 | WILC_memset(priv[0]->au8AssociatedBss, 0xFF, ETH_ALEN); | |
929 | ||
930 | ||
931 | /* ret = host_int_init(&priv[0]->hWILCWFIDrv); */ | |
932 | /*copy handle to the other driver*/ | |
933 | /* priv[1]->hWILCWFIDrv = priv[0]->hWILCWFIDrv; */ | |
934 | if (ret) { | |
935 | PRINT_ER("Error Init Driver\n"); | |
936 | } | |
937 | ||
938 | ||
939 | out: | |
940 | if (ret) | |
941 | WILC_WFI_Cleanup(); | |
942 | return ret; | |
943 | ||
944 | ||
945 | } | |
946 | ||
947 | ||
948 | module_init(WILC_WFI_InitModule); | |
949 | module_exit(WILC_WFI_Cleanup); | |
950 | ||
951 | #endif |