|
|
|
@ -1,909 +0,0 @@
|
|
|
|
|
/*!
|
|
|
|
|
* @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);
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
|
|
|
|
|
priv[0]->bCfgScanning = false;
|
|
|
|
|
priv[0]->u32RcvdChCount = 0;
|
|
|
|
|
|
|
|
|
|
WILC_memset(priv[0]->au8AssociatedBss, 0xFF, ETH_ALEN);
|
|
|
|
|
|
|
|
|
|
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
|