/*! * @file wilc_wfi_netdevice.c * @brief File Operations OS wrapper functionality * @author mdaftedar * @sa wilc_wfi_netdevice.h * @date 01 MAR 2012 * @version 1.0 */ #ifdef SIMULATION #include "wilc_wfi_cfgoperations.h" #include "host_interface.h" MODULE_AUTHOR("Mai Daftedar"); MODULE_LICENSE("Dual BSD/GPL"); struct net_device *WILC_WFI_devs[2]; /* * Transmitter lockup simulation, normally disabled. */ static int lockup; module_param(lockup, int, 0); static int timeout = WILC_WFI_TIMEOUT; module_param(timeout, int, 0); /* * Do we run in NAPI mode? */ static int use_napi ; module_param(use_napi, int, 0); /* * A structure representing an in-flight packet. */ struct WILC_WFI_packet { struct WILC_WFI_packet *next; struct net_device *dev; int datalen; u8 data[ETH_DATA_LEN]; }; int pool_size = 8; module_param(pool_size, int, 0); static void WILC_WFI_TxTimeout(struct net_device *dev); static void (*WILC_WFI_Interrupt)(int, void *, struct pt_regs *); /** * @brief WILC_WFI_SetupPool * @details Set up a device's packet pool. * @param[in] struct net_device *dev : Network Device Pointer * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_SetupPool(struct net_device *dev) { struct WILC_WFI_priv *priv = netdev_priv(dev); int i; struct WILC_WFI_packet *pkt; priv->ppool = NULL; for (i = 0; i < pool_size; i++) { pkt = kmalloc (sizeof (struct WILC_WFI_packet), GFP_KERNEL); if (pkt == NULL) { PRINT_D(RX_DBG, "Ran out of memory allocating packet pool\n"); return; } pkt->dev = dev; pkt->next = priv->ppool; priv->ppool = pkt; } } /** * @brief WILC_WFI_TearDownPool * @details Internal cleanup function that's called after the network device * driver is unregistered * @param[in] struct net_device *dev : Network Device Driver * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_TearDownPool(struct net_device *dev) { struct WILC_WFI_priv *priv = netdev_priv(dev); struct WILC_WFI_packet *pkt; while ((pkt = priv->ppool)) { priv->ppool = pkt->next; kfree (pkt); /* FIXME - in-flight packets ? */ } } /** * @brief WILC_WFI_GetTxBuffer * @details Buffer/pool management * @param[in] net_device *dev : Network Device Driver Structure * @return struct WILC_WFI_packet * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ struct WILC_WFI_packet *WILC_WFI_GetTxBuffer(struct net_device *dev) { struct WILC_WFI_priv *priv = netdev_priv(dev); unsigned long flags; struct WILC_WFI_packet *pkt; spin_lock_irqsave(&priv->lock, flags); pkt = priv->ppool; priv->ppool = pkt->next; if (priv->ppool == NULL) { PRINT_INFO(RX_DBG, "Pool empty\n"); netif_stop_queue(dev); } spin_unlock_irqrestore(&priv->lock, flags); return pkt; } /** * @brief WILC_WFI_ReleaseBuffer * @details Buffer/pool management * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_ReleaseBuffer(struct WILC_WFI_packet *pkt) { unsigned long flags; struct WILC_WFI_priv *priv = netdev_priv(pkt->dev); spin_lock_irqsave(&priv->lock, flags); pkt->next = priv->ppool; priv->ppool = pkt; spin_unlock_irqrestore(&priv->lock, flags); if (netif_queue_stopped(pkt->dev) && pkt->next == NULL) netif_wake_queue(pkt->dev); } /** * @brief WILC_WFI_EnqueueBuf * @details Enqueuing packets in an RX buffer queue * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet * @param[in] net_device *dev : Network Device Driver Structure * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_EnqueueBuf(struct net_device *dev, struct WILC_WFI_packet *pkt) { unsigned long flags; struct WILC_WFI_priv *priv = netdev_priv(dev); spin_lock_irqsave(&priv->lock, flags); pkt->next = priv->rx_queue; /* FIXME - misorders packets */ priv->rx_queue = pkt; spin_unlock_irqrestore(&priv->lock, flags); } /** * @brief WILC_WFI_DequeueBuf * @details Dequeuing packets from the RX buffer queue * @param[in] net_device *dev : Network Device Driver Structure * @return WILC_WFI_packet *pkt : Structure holding in-flight pac * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ struct WILC_WFI_packet *WILC_WFI_DequeueBuf(struct net_device *dev) { struct WILC_WFI_priv *priv = netdev_priv(dev); struct WILC_WFI_packet *pkt; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); pkt = priv->rx_queue; if (pkt != NULL) priv->rx_queue = pkt->next; spin_unlock_irqrestore(&priv->lock, flags); return pkt; } /** * @brief WILC_WFI_RxInts * @details Enable and disable receive interrupts. * @param[in] net_device *dev : Network Device Driver Structure * @param[in] enable : Enable/Disable flag * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ static void WILC_WFI_RxInts(struct net_device *dev, int enable) { struct WILC_WFI_priv *priv = netdev_priv(dev); priv->rx_int_enabled = enable; } /** * @brief WILC_WFI_Open * @details Open Network Device Driver, called when the network * interface is opened. It starts the interface's transmit queue. * @param[in] net_device *dev : Network Device Driver Structure * @param[in] enable : Enable/Disable flag * @return int : Returns 0 upon success. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_Open(struct net_device *dev) { /* request_region(), request_irq(), .... (like fops->open) */ /* * Assign the hardware address of the board: use "\0SNULx", where * x is 0 or 1. The first byte is '\0' to avoid being a multicast * address (the first byte of multicast addrs is odd). */ memcpy(dev->dev_addr, "\0WLAN0", ETH_ALEN); if (dev == WILC_WFI_devs[1]) dev->dev_addr[ETH_ALEN - 1]++; /* \0SNUL1 */ WILC_WFI_InitHostInt(dev); netif_start_queue(dev); return 0; } /** * @brief WILC_WFI_Release * @details Release Network Device Driver, called when the network * interface is stopped or brought down. This function marks * the network driver as not being able to transmit * @param[in] net_device *dev : Network Device Driver Structure * @return int : Return 0 on Success. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_Release(struct net_device *dev) { /* release ports, irq and such -- like fops->close */ netif_stop_queue(dev); /* can't transmit any more */ return 0; } /** * @brief WILC_WFI_Config * @details Configuration changes (passed on by ifconfig) * @param[in] net_device *dev : Network Device Driver Structure * @param[in] struct ifmap *map : Contains the ioctl implementation for the * network driver. * @return int : Return 0 on Success. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_Config(struct net_device *dev, struct ifmap *map) { if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { PRINT_D(RX_DBG, KERN_WARNING "WILC_WFI: Can't change I/O address\n"); return -EOPNOTSUPP; } /* Allow changing the IRQ */ if (map->irq != dev->irq) { dev->irq = map->irq; /* request_irq() is delayed to open-time */ } /* ignore other fields */ return 0; } /** * @brief WILC_WFI_Rx * @details Receive a packet: retrieve, encapsulate and pass over to upper * levels * @param[in] net_device *dev : Network Device Driver Structure * @param[in] WILC_WFI_packet : * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_Rx(struct net_device *dev, struct WILC_WFI_packet *pkt) { int i; struct sk_buff *skb; struct WILC_WFI_priv *priv = netdev_priv(dev); s8 rssi; /* * The packet has been retrieved from the transmission * medium. Build an skb around it, so upper layers can handle it */ skb = dev_alloc_skb(pkt->datalen + 2); if (!skb) { if (printk_ratelimit()) PRINT_D(RX_DBG, "WILC_WFI rx: low on mem - packet dropped\n"); priv->stats.rx_dropped++; goto out; } skb_reserve(skb, 2); /* align IP on 16B boundary */ memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); if (priv->monitor_flag) { PRINT_INFO(RX_DBG, "In monitor device name %s\n", dev->name); priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); PRINT_D(RX_DBG, "VALUE PASSED IN OF HRWD %p\n", priv->hWILCWFIDrv); /* host_int_get_rssi(priv->hWILCWFIDrv, &(rssi)); */ if (INFO) { for (i = 14; i < skb->len; i++) PRINT_INFO(RX_DBG, "RXdata[%d] %02x\n", i, skb->data[i]); } WILC_WFI_monitor_rx(dev, skb); return; } out: return; } /** * @brief WILC_WFI_Poll * @details The poll implementation * @param[in] struct napi_struct *napi : * @param[in] int budget : * @return int : Return 0 on Success. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ static int WILC_WFI_Poll(struct napi_struct *napi, int budget) { int npackets = 0; struct sk_buff *skb; struct WILC_WFI_priv *priv = container_of(napi, struct WILC_WFI_priv, napi); struct net_device *dev = priv->dev; struct WILC_WFI_packet *pkt; while (npackets < budget && priv->rx_queue) { pkt = WILC_WFI_DequeueBuf(dev); skb = dev_alloc_skb(pkt->datalen + 2); if (!skb) { if (printk_ratelimit()) PRINT_D(RX_DBG, "WILC_WFI: packet dropped\n"); priv->stats.rx_dropped++; WILC_WFI_ReleaseBuffer(pkt); continue; } skb_reserve(skb, 2); /* align IP on 16B boundary */ memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ netif_receive_skb(skb); /* Maintain stats */ npackets++; WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, pkt->datalen, WILC_WFI_RX_PKT); WILC_WFI_ReleaseBuffer(pkt); } /* If we processed all packets, we're done; tell the kernel and re-enable ints */ if (npackets < budget) { napi_complete(napi); WILC_WFI_RxInts(dev, 1); } return npackets; } /** * @brief WILC_WFI_Poll * @details The typical interrupt entry point * @param[in] struct napi_struct *napi : * @param[in] int budget : * @return int : Return 0 on Success. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ static void WILC_WFI_RegularInterrupt(int irq, void *dev_id, struct pt_regs *regs) { int statusword; struct WILC_WFI_priv *priv; struct WILC_WFI_packet *pkt = NULL; /* * As usual, check the "device" pointer to be sure it is * really interrupting. * Then assign "struct device *dev" */ struct net_device *dev = (struct net_device *)dev_id; /* ... and check with hw if it's really ours */ /* paranoid */ if (!dev) return; /* Lock the device */ priv = netdev_priv(dev); spin_lock(&priv->lock); /* retrieve statusword: real netdevices use I/O instructions */ statusword = priv->status; priv->status = 0; if (statusword & WILC_WFI_RX_INTR) { /* send it to WILC_WFI_rx for handling */ pkt = priv->rx_queue; if (pkt) { priv->rx_queue = pkt->next; WILC_WFI_Rx(dev, pkt); } } if (statusword & WILC_WFI_TX_INTR) { /* a transmission is over: free the skb */ WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); dev_kfree_skb(priv->skb); } /* Unlock the device and we are done */ spin_unlock(&priv->lock); if (pkt) WILC_WFI_ReleaseBuffer(pkt); /* Do this outside the lock! */ return; } /** * @brief WILC_WFI_NapiInterrupt * @details A NAPI interrupt handler * @param[in] irq: * @param[in] dev_id: * @param[in] pt_regs: * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ static void WILC_WFI_NapiInterrupt(int irq, void *dev_id, struct pt_regs *regs) { int statusword; struct WILC_WFI_priv *priv; /* * As usual, check the "device" pointer for shared handlers. * Then assign "struct device *dev" */ struct net_device *dev = (struct net_device *)dev_id; /* ... and check with hw if it's really ours */ /* paranoid */ if (!dev) return; /* Lock the device */ priv = netdev_priv(dev); spin_lock(&priv->lock); /* retrieve statusword: real netdevices use I/O instructions */ statusword = priv->status; priv->status = 0; if (statusword & WILC_WFI_RX_INTR) { WILC_WFI_RxInts(dev, 0); /* Disable further interrupts */ napi_schedule(&priv->napi); } if (statusword & WILC_WFI_TX_INTR) { /* a transmission is over: free the skb */ WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); dev_kfree_skb(priv->skb); } /* Unlock the device and we are done */ spin_unlock(&priv->lock); return; } /** * @brief MI_WFI_HwTx * @details Transmit a packet (low level interface) * @param[in] buf: * @param[in] len: * @param[in] net_device *dev: * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) { /* * This function deals with hw details. This interface loops * back the packet to the other WILC_WFI interface (if any). * In other words, this function implements the WILC_WFI behaviour, * while all other procedures are rather device-independent */ struct iphdr *ih; struct net_device *dest; struct WILC_WFI_priv *priv; u32 *saddr, *daddr; struct WILC_WFI_packet *tx_buffer; /* I am paranoid. Ain't I? */ if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { PRINT_D(RX_DBG, "WILC_WFI: Hmm... packet too short (%i octets)\n", len); return; } if (0) { /* enable this conditional to look at the data */ int i; PRINT_D(RX_DBG, "len is %i", len); for (i = 14; i < len; i++) PRINT_D(RX_DBG, "TXdata[%d] %02x\n", i, buf[i] & 0xff); /* PRINT_D(RX_DBG, "\n"); */ } /* * Ethhdr is 14 bytes, but the kernel arranges for iphdr * to be aligned (i.e., ethhdr is unaligned) */ ih = (struct iphdr *)(buf + sizeof(struct ethhdr)); saddr = &ih->saddr; daddr = &ih->daddr; ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */ ((u8 *)daddr)[2] ^= 1; ih->check = 0; /* and rebuild the checksum (ip needs it) */ ih->check = ip_fast_csum((unsigned char *)ih, ih->ihl); if (dev == WILC_WFI_devs[0]) PRINT_D(RX_DBG, "%08x:%05i --> %08x:%05i\n", ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source), ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest)); else PRINT_D(RX_DBG, "%08x:%05i <-- %08x:%05i\n", ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest), ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source)); /* * Ok, now the packet is ready for transmission: first simulate a * receive interrupt on the twin device, then a * transmission-done on the transmitting device */ dest = WILC_WFI_devs[dev == WILC_WFI_devs[0] ? 1 : 0]; priv = netdev_priv(dest); tx_buffer = WILC_WFI_GetTxBuffer(dev); tx_buffer->datalen = len; memcpy(tx_buffer->data, buf, len); WILC_WFI_EnqueueBuf(dest, tx_buffer); if (priv->rx_int_enabled) { priv->status |= WILC_WFI_RX_INTR; WILC_WFI_Interrupt(0, dest, NULL); } priv = netdev_priv(dev); priv->tx_packetlen = len; priv->tx_packetdata = buf; priv->status |= WILC_WFI_TX_INTR; if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) { /* Simulate a dropped transmit interrupt */ netif_stop_queue(dev); PRINT_D(RX_DBG, "Simulate lockup at %ld, txp %ld\n", jiffies, (unsigned long) priv->stats.tx_packets); } else WILC_WFI_Interrupt(0, dev, NULL); } /** * @brief WILC_WFI_Tx * @details Transmit a packet (called by the kernel) * @param[in] sk_buff *skb: * @param[in] net_device *dev: * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev) { int len; char *data, shortpkt[ETH_ZLEN]; struct WILC_WFI_priv *priv = netdev_priv(dev); /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */ /* if(priv->monitor_flag) */ /* mac80211_hwsim_monitor_rx(skb); */ data = skb->data; len = skb->len; if (len < ETH_ZLEN) { memset(shortpkt, 0, ETH_ZLEN); memcpy(shortpkt, skb->data, skb->len); len = ETH_ZLEN; data = shortpkt; } dev->trans_start = jiffies; /* save the timestamp */ /* Remember the skb, so we can free it at interrupt time */ priv->skb = skb; /* actual deliver of data is device-specific, and not shown here */ WILC_WFI_HwTx(data, len, dev); return 0; /* Our simple device can not fail */ } /** * @brief WILC_WFI_TxTimeout * @details Deal with a transmit timeout. * @param[in] net_device *dev: * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_TxTimeout(struct net_device *dev) { struct WILC_WFI_priv *priv = netdev_priv(dev); PRINT_D(RX_DBG, "Transmit timeout at %ld, latency %ld\n", jiffies, jiffies - dev->trans_start); /* Simulate a transmission interrupt to get things moving */ priv->status = WILC_WFI_TX_INTR; WILC_WFI_Interrupt(0, dev, NULL); priv->stats.tx_errors++; netif_wake_queue(dev); return; } /** * @brief WILC_WFI_Ioctl * @details Ioctl commands * @param[in] net_device *dev: * @param[in] ifreq *rq * @param[in] cmd: * @return int : Return 0 on Success * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_Ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { PRINT_D(RX_DBG, "ioctl\n"); return 0; } /** * @brief WILC_WFI_Stat * @details Return statistics to the caller * @param[in] net_device *dev: * @return WILC_WFI_Stats : Return net_device_stats stucture with the * network device driver private data contents. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ struct net_device_stats *WILC_WFI_Stats(struct net_device *dev) { struct WILC_WFI_priv *priv = netdev_priv(dev); return &priv->stats; } /** * @brief WILC_WFI_RebuildHeader * @details This function is called to fill up an eth header, since arp is not * available on the interface * @param[in] sk_buff *skb: * @return int : Return 0 on Success * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_RebuildHeader(struct sk_buff *skb) { struct ethhdr *eth = (struct ethhdr *) skb->data; struct net_device *dev = skb->dev; memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ return 0; } /** * @brief WILC_WFI_RebuildHeader * @details This function is called to fill up an eth header, since arp is not * available on the interface * @param[in] sk_buff *skb: * @param[in] struct net_device *dev: * @param[in] unsigned short type: * @param[in] const void *saddr, * @param[in] const void *daddr: * @param[in] unsigned int len * @return int : Return 0 on Success * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_Header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned int len) { struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); eth->h_proto = htons(type); memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ return dev->hard_header_len; } /** * @brief WILC_WFI_ChangeMtu * @details The "change_mtu" method is usually not needed. * If you need it, it must be like this. * @param[in] net_device *dev : Network Device Driver Structure * @param[in] new_mtu : * @return int : Returns 0 on Success. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_ChangeMtu(struct net_device *dev, int new_mtu) { unsigned long flags; struct WILC_WFI_priv *priv = netdev_priv(dev); spinlock_t *lock = &priv->lock; /* check ranges */ if ((new_mtu < 68) || (new_mtu > 1500)) return -EINVAL; /* * Do anything you need, and the accept the value */ spin_lock_irqsave(lock, flags); dev->mtu = new_mtu; spin_unlock_irqrestore(lock, flags); return 0; /* success */ } static const struct header_ops WILC_WFI_header_ops = { .create = WILC_WFI_Header, .rebuild = WILC_WFI_RebuildHeader, .cache = NULL, /* disable caching */ }; static const struct net_device_ops WILC_WFI_netdev_ops = { .ndo_open = WILC_WFI_Open, .ndo_stop = WILC_WFI_Release, .ndo_set_config = WILC_WFI_Config, .ndo_start_xmit = WILC_WFI_Tx, .ndo_do_ioctl = WILC_WFI_Ioctl, .ndo_get_stats = WILC_WFI_Stats, .ndo_change_mtu = WILC_WFI_ChangeMtu, .ndo_tx_timeout = WILC_WFI_TxTimeout, }; /** * @brief WILC_WFI_Init * @details The init function (sometimes called probe). * It is invoked by register_netdev() * @param[in] net_device *dev: * @return NONE * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_Init(struct net_device *dev) { struct WILC_WFI_priv *priv; /* * Then, assign other fields in dev, using ether_setup() and some * hand assignments */ ether_setup(dev); /* assign some of the fields */ /* 1- Allocate space */ dev->netdev_ops = &WILC_WFI_netdev_ops; dev->header_ops = &WILC_WFI_header_ops; dev->watchdog_timeo = timeout; /* keep the default flags, just add NOARP */ dev->flags |= IFF_NOARP; dev->features |= NETIF_F_NO_CSUM; /* * Then, initialize the priv field. This encloses the statistics * and a few private fields. */ priv = netdev_priv(dev); memset(priv, 0, sizeof(struct WILC_WFI_priv)); priv->dev = dev; netif_napi_add(dev, &priv->napi, WILC_WFI_Poll, 2); /* The last parameter above is the NAPI "weight". */ spin_lock_init(&priv->lock); WILC_WFI_RxInts(dev, 1); /* enable receive interrupts */ WILC_WFI_SetupPool(dev); } /** * @brief WILC_WFI_Stat * @details Return statistics to the caller * @param[in] net_device *dev: * @return WILC_WFI_Stats : Return net_device_stats stucture with the * network device driver private data contents. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ void WILC_WFI_Cleanup(void) { int i; struct WILC_WFI_priv *priv[2]; /*if(hwsim_mon!=NULL) * { * PRINT_D(RX_DBG, "Freeing monitor interface\n"); * unregister_netdev(hwsim_mon); * free_netdev(hwsim_mon); * }*/ for (i = 0; i < 2; i++) { priv[i] = netdev_priv(WILC_WFI_devs[i]); if (WILC_WFI_devs[i]) { PRINT_D(RX_DBG, "Unregistering\n"); unregister_netdev(WILC_WFI_devs[i]); WILC_WFI_TearDownPool(WILC_WFI_devs[i]); free_netdev(WILC_WFI_devs[i]); PRINT_D(RX_DBG, "[NETDEV]Stopping interface\n"); WILC_WFI_DeInitHostInt(WILC_WFI_devs[i]); WILC_WFI_WiphyFree(WILC_WFI_devs[i]); } } /* unregister_netdev(hwsim_mon); */ WILC_WFI_deinit_mon_interface(); return; } void StartConfigSim(void); /** * @brief WILC_WFI_Stat * @details Return statistics to the caller * @param[in] net_device *dev: * @return WILC_WFI_Stats : Return net_device_stats stucture with the * network device driver private data contents. * @author mdaftedar * @date 01 MAR 2012 * @version 1.0 */ int WILC_WFI_InitModule(void) { int result, i, ret = -ENOMEM; struct WILC_WFI_priv *priv[2], *netpriv; struct wireless_dev *wdev; WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; char buf[IFNAMSIZ]; for (i = 0; i < 2; i++) { /* Allocate the net devices */ WILC_WFI_devs[i] = alloc_netdev(sizeof(struct WILC_WFI_priv), "wlan%d", WILC_WFI_Init); if (WILC_WFI_devs[i] == NULL) goto out; /* priv[i] = netdev_priv(WILC_WFI_devs[i]); */ wdev = WILC_WFI_WiphyRegister(WILC_WFI_devs[i]); WILC_WFI_devs[i]->ieee80211_ptr = wdev; netpriv = netdev_priv(WILC_WFI_devs[i]); netpriv->dev->ieee80211_ptr = wdev; netpriv->dev->ml_priv = netpriv; wdev->netdev = netpriv->dev; /*Registering the net device*/ result = register_netdev(WILC_WFI_devs[i]); if (result) PRINT_D(RX_DBG, "WILC_WFI: error %i registering device \"%s\"\n", result, WILC_WFI_devs[i]->name); else ret = 0; } /*init atmel driver */ priv[0] = netdev_priv(WILC_WFI_devs[0]); priv[1] = netdev_priv(WILC_WFI_devs[1]); if (priv[1]->dev->ieee80211_ptr->wiphy->interface_modes && BIT(NL80211_IFTYPE_MONITOR)) { /* snprintf(buf, IFNAMSIZ, "mon.%s", priv[1]->dev->name); */ /* WILC_WFI_init_mon_interface(); */ /* priv[1]->monitor_flag = 1; */ } priv[0]->bCfgScanning = false; priv[0]->u32RcvdChCount = 0; WILC_memset(priv[0]->au8AssociatedBss, 0xFF, ETH_ALEN); /* ret = host_int_init(&priv[0]->hWILCWFIDrv); */ /*copy handle to the other driver*/ /* priv[1]->hWILCWFIDrv = priv[0]->hWILCWFIDrv; */ if (ret) { PRINT_ER("Error Init Driver\n"); } out: if (ret) WILC_WFI_Cleanup(); return ret; } module_init(WILC_WFI_InitModule); module_exit(WILC_WFI_Cleanup); #endif