/*
- *
* Copyright (C) 2002 Intersil Americas Inc.
* Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
* Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
*
*/
-#include <linux/version.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/ethtool.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/if_arp.h>
#define ISL3877_IMAGE_FILE "isl3877"
#define ISL3886_IMAGE_FILE "isl3886"
#define ISL3890_IMAGE_FILE "isl3890"
+MODULE_FIRMWARE(ISL3877_IMAGE_FILE);
+MODULE_FIRMWARE(ISL3886_IMAGE_FILE);
+MODULE_FIRMWARE(ISL3890_IMAGE_FILE);
static int prism54_bring_down(islpci_private *);
static int islpci_alloc_memory(islpci_private *);
-static struct net_device_stats *islpci_statistics(struct net_device *);
/* Temporary dummy MAC address to use until firmware is loaded.
* The idea there is that some tools (such as nameif) may query
ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
- /* set the cards base address for writting the data */
+ /* set the card's base address for writing the data */
isl38xx_w32_flush(device_base, reg,
ISL38XX_DIR_MEM_BASE_REG);
wmb(); /* be paranoid */
******************************************************************************/
irqreturn_t
-islpci_interrupt(int irq, void *config, struct pt_regs *regs)
+islpci_interrupt(int irq, void *config)
{
u32 reg;
islpci_private *priv = config;
#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_FUNCTION_CALLS,
- "IRQ: Identification register 0x%p 0x%x \n", device, reg);
+ "IRQ: Identification register 0x%p 0x%x\n", device, reg);
#endif
/* check for each bit in the register separately */
if (reg & ISL38XX_INT_IDENT_UPDATE) {
#if VERBOSE > SHOW_ERROR_MESSAGES
/* Queue has been updated */
- DEBUG(SHOW_TRACING, "IRQ: Update flag \n");
+ DEBUG(SHOW_TRACING, "IRQ: Update flag\n");
DEBUG(SHOW_QUEUE_INDEXES,
"CB drv Qs: [%i][%i][%i][%i][%i][%i]\n",
ISL38XX_CB_RX_DATA_LQ) != 0) {
#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_TRACING,
- "Received frame in Data Low Queue \n");
+ "Received frame in Data Low Queue\n");
#endif
islpci_eth_receive(priv);
}
/* Device has been initialized */
#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_TRACING,
- "IRQ: Init flag, device initialized \n");
+ "IRQ: Init flag, device initialized\n");
#endif
wake_up(&priv->reset_done);
}
if (reg & ISL38XX_INT_IDENT_SLEEP) {
/* Device intends to move to powersave state */
#if VERBOSE > SHOW_ERROR_MESSAGES
- DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");
+ DEBUG(SHOW_TRACING, "IRQ: Sleep flag\n");
#endif
isl38xx_handle_sleep_request(priv->control_block,
&powerstate,
if (reg & ISL38XX_INT_IDENT_WAKEUP) {
/* Device has been woken up to active state */
#if VERBOSE > SHOW_ERROR_MESSAGES
- DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");
+ DEBUG(SHOW_TRACING, "IRQ: Wakeup flag\n");
#endif
isl38xx_handle_wakeup(priv->control_block,
}
netif_start_queue(ndev);
-/* netif_mark_up( ndev ); */
+
+ /* Turn off carrier if in STA or Ad-hoc mode. It will be turned on
+ * once the firmware receives a trap of being associated
+ * (GEN_OID_LINKSTATE). In other modes (AP or WDS or monitor) we
+ * should just leave the carrier on as its expected the firmware
+ * won't send us a trigger. */
+ if (priv->iw_mode == IW_MODE_INFRA || priv->iw_mode == IW_MODE_ADHOC)
+ netif_carrier_off(ndev);
+ else
+ netif_carrier_on(ndev);
return 0;
}
islpci_set_state(priv, PRV_STATE_PREBOOT);
/* disable all device interrupts in case they weren't */
- isl38xx_disable_interrupts(priv->device_base);
+ isl38xx_disable_interrupts(priv->device_base);
/* For safety reasons, we may want to ensure that no DMA transfer is
* currently in progress by emptying the TX and RX queues. */
DEFINE_WAIT(wait);
prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE);
-
+
/* now the last step is to reset the interface */
isl38xx_interface_reset(priv->device_base, priv->device_host_address);
islpci_set_state(priv, PRV_STATE_PREINIT);
for(count = 0; count < 2 && result; count++) {
/* The software reset acknowledge needs about 220 msec here.
* Be conservative and wait for up to one second. */
-
+
remaining = schedule_timeout_uninterruptible(HZ);
if(remaining > 0) {
break;
}
- /* If we're here it's because our IRQ hasn't yet gone through.
+ /* If we're here it's because our IRQ hasn't yet gone through.
* Retry a bit more...
*/
printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n",
/* Now that the device is 100% up, let's allow
* for the other interrupts --
- * NOTE: this is not *yet* true since we've only allowed the
+ * NOTE: this is not *yet* true since we've only allowed the
* INIT interrupt on the IRQ line. We can perhaps poll
* the IRQ line until we know for sure the reset went through */
isl38xx_enable_common_interrupts(priv->device_base);
return rc;
}
-static struct net_device_stats *
-islpci_statistics(struct net_device *ndev)
-{
- islpci_private *priv = netdev_priv(ndev);
-
-#if VERBOSE > SHOW_ERROR_MESSAGES
- DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n");
-#endif
-
- return &priv->statistics;
-}
-
/******************************************************************************
Network device configuration functions
******************************************************************************/
ioremap(pci_resource_start(priv->pdev, 0),
ISL38XX_PCI_MEM_SIZE))) {
/* error in remapping the PCI device memory address range */
- printk(KERN_ERR "PCI memory remapping failed \n");
+ printk(KERN_ERR "PCI memory remapping failed\n");
return -1;
}
}
prism54_acl_init(&priv->acl);
- prism54_wpa_ie_init(priv);
- if (mgt_init(priv))
+ prism54_wpa_bss_ie_init(priv);
+ if (mgt_init(priv))
goto out_free;
return 0;
pci_unmap_single(priv->pdev, buf->pci_addr,
buf->size, PCI_DMA_FROMDEVICE);
buf->pci_addr = 0;
- if (buf->mem)
- kfree(buf->mem);
+ kfree(buf->mem);
buf->size = 0;
buf->mem = NULL;
}
/* Free the acces control list and the WPA list */
prism54_acl_clean(&priv->acl);
- prism54_wpa_ie_clean(priv);
+ prism54_wpa_bss_ie_clean(priv);
mgt_clean(priv);
return 0;
}
#endif
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+}
+
+static const struct ethtool_ops islpci_ethtool_ops = {
+ .get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
+static const struct net_device_ops islpci_netdev_ops = {
+ .ndo_open = islpci_open,
+ .ndo_stop = islpci_close,
+ .ndo_do_ioctl = prism54_ioctl,
+ .ndo_start_xmit = islpci_eth_transmit,
+ .ndo_tx_timeout = islpci_eth_tx_timeout,
+ .ndo_set_mac_address = prism54_set_mac_address,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
struct net_device *
islpci_setup(struct pci_dev *pdev)
{
if (!ndev)
return ndev;
- SET_MODULE_OWNER(ndev);
pci_set_drvdata(pdev, ndev);
#if defined(SET_NETDEV_DEV)
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->irq = pdev->irq;
/* initialize the function pointers */
- ndev->open = &islpci_open;
- ndev->stop = &islpci_close;
- ndev->get_stats = &islpci_statistics;
- ndev->do_ioctl = &prism54_ioctl;
- ndev->wireless_handlers =
- (struct iw_handler_def *) &prism54_handler_def;
-
- ndev->hard_start_xmit = &islpci_eth_transmit;
+ ndev->netdev_ops = &islpci_netdev_ops;
+ ndev->wireless_handlers = &prism54_handler_def;
+ ndev->ethtool_ops = &islpci_ethtool_ops;
+
/* ndev->set_multicast_list = &islpci_set_multicast_list; */
ndev->addr_len = ETH_ALEN;
- ndev->set_mac_address = &prism54_set_mac_address;
/* Get a non-zero dummy MAC address for nameif. Jean II */
memcpy(ndev->dev_addr, dummy_mac, 6);
-#ifdef HAVE_TX_TIMEOUT
ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT;
- ndev->tx_timeout = &islpci_eth_tx_timeout;
-#endif
/* allocate a private device structure to the network device */
priv = netdev_priv(ndev);
init_waitqueue_head(&priv->reset_done);
/* init the queue read locks, process wait counter */
- sema_init(&priv->mgmt_sem, 1);
+ mutex_init(&priv->mgmt_lock);
priv->mgmt_received = NULL;
init_waitqueue_head(&priv->mgmt_wqueue);
- sema_init(&priv->stats_sem, 1);
+ mutex_init(&priv->stats_lock);
spin_lock_init(&priv->slock);
/* init state machine with off#1 state */
priv->state_off = 1;
/* initialize workqueue's */
- INIT_WORK(&priv->stats_work,
- (void (*)(void *)) prism54_update_stats, priv);
+ INIT_WORK(&priv->stats_work, prism54_update_stats);
priv->stats_timestamp = 0;
- INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv);
+ INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake);
priv->reset_task_pending = 0;
/* allocate various memory areas */
if (register_netdev(ndev)) {
DEBUG(SHOW_ERROR_MESSAGES,
- "ERROR: register_netdev() failed \n");
+ "ERROR: register_netdev() failed\n");
goto do_islpci_free_memory;
}
if (!priv->state_off)
priv->state = new_state;
break;
- };
+ }
#if 0
printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n",
priv->ndev->name, old_state, new_state, priv->state_off);