#include <linux/types.h>
#include <linux/unistd.h>
#include <linux/ctype.h>
-#include <linux/bitops.h>
+#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops ethtool_ops_203;
-static struct ethtool_ops ethtool_ops;
/*
** Private functions
printk(" is in I/O only mode");
}
- lp = netdev_priv(dev);
+ lp = (struct ewrk3_private *) dev->priv;
lp->shmem_base = mem_start;
lp->shmem_length = shmem_length;
lp->lemac = lemac;
dev->get_stats = ewrk3_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->do_ioctl = ewrk3_ioctl;
- if (lp->adapter_name[4] == '3')
- SET_ETHTOOL_OPS(dev, ðtool_ops_203);
- else
- SET_ETHTOOL_OPS(dev, ðtool_ops);
dev->tx_timeout = ewrk3_timeout;
dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
static int ewrk3_open(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_long iobase = dev->base_addr;
int i, status = 0;
u_char icr, csr;
*/
static void ewrk3_init(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_char csr, page;
u_long iobase = dev->base_addr;
int i;
static void ewrk3_timeout(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_char icr, csr;
u_long iobase = dev->base_addr;
*/
static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_long iobase = dev->base_addr;
u_long buf = 0;
u_char icr;
u_long iobase;
u_char icr, cr, csr;
- lp = netdev_priv(dev);
+ lp = (struct ewrk3_private *) dev->priv;
iobase = dev->base_addr;
/* get the interrupt information */
/* Called with lp->hw_lock held */
static int ewrk3_rx(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_long iobase = dev->base_addr;
int i, status = 0;
u_char page;
*/
static int ewrk3_tx(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_long iobase = dev->base_addr;
u_char tx_status;
static int ewrk3_close(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_long iobase = dev->base_addr;
u_char icr, csr;
static struct net_device_stats *ewrk3_get_stats(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
/* Null body since there is no framing error counter */
return &lp->stats;
*/
static void set_multicast_list(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
u_long iobase = dev->base_addr;
u_char csr;
*/
static void SetMulticastFilter(struct net_device *dev)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
struct dev_mc_list *dmi = dev->mc_list;
u_long iobase = dev->base_addr;
int i;
return status; /* return the device name string */
}
-static void ewrk3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+static int ewrk3_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
{
- int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+ u_long iobase = dev->base_addr;
+ u32 ethcmd;
+
+ if (get_user(ethcmd, (u32 __user *)useraddr))
+ return -EFAULT;
+
+ switch (ethcmd) {
+
+ /* Get driver info */
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
+
+ strcpy(info.driver, DRV_NAME);
+ strcpy(info.version, DRV_VERSION);
+ sprintf(info.fw_version, "%d", fwrev);
+ strcpy(info.bus_info, "N/A");
+ info.eedump_len = EEPROM_MAX;
+ if (copy_to_user(useraddr, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->fw_version, "%d", fwrev);
- strcpy(info->bus_info, "N/A");
- info->eedump_len = EEPROM_MAX;
-}
+ /* Get settings */
+ case ETHTOOL_GSET: {
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ u_char cr = inb(EWRK3_CR);
-static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- unsigned long iobase = dev->base_addr;
- u8 cr = inb(EWRK3_CR);
-
- switch (lp->adapter_name[4]) {
- case '3': /* DE203 */
- ecmd->supported = SUPPORTED_BNC;
- ecmd->port = PORT_BNC;
- break;
+ switch (lp->adapter_name[4]) {
+ case '3': /* DE203 */
+ ecmd.supported = SUPPORTED_BNC;
+ ecmd.port = PORT_BNC;
+ break;
- case '4': /* DE204 */
- ecmd->supported = SUPPORTED_TP;
- ecmd->port = PORT_TP;
- break;
+ case '4': /* DE204 */
+ ecmd.supported = SUPPORTED_TP;
+ ecmd.port = PORT_TP;
+ break;
- case '5': /* DE205 */
- ecmd->supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
- ecmd->autoneg = !(cr & CR_APD);
- /*
- ** Port is only valid if autoneg is disabled
- ** and even then we don't know if AUI is jumpered.
- */
- if (!ecmd->autoneg)
- ecmd->port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
- break;
+ case '5': /* DE205 */
+ ecmd.supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
+ ecmd.autoneg = !(cr & CR_APD);
+ /*
+ ** Port is only valid if autoneg is disabled
+ ** and even then we don't know if AUI is jumpered.
+ */
+ if (!ecmd.autoneg)
+ ecmd.port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
+ break;
+ }
+
+ ecmd.supported |= SUPPORTED_10baseT_Half;
+ ecmd.speed = SPEED_10;
+ ecmd.duplex = DUPLEX_HALF;
+
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
}
- ecmd->supported |= SUPPORTED_10baseT_Half;
- ecmd->speed = SPEED_10;
- ecmd->duplex = DUPLEX_HALF;
- return 0;
-}
+ /* Set settings */
+ case ETHTOOL_SSET: {
+ struct ethtool_cmd ecmd;
+ u_char cr;
+ u_long flags;
+
+ /* DE205 is the only card with anything to set */
+ if (lp->adapter_name[4] != '5')
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+
+ /* Sanity-check parameters */
+ if (ecmd.speed != SPEED_10)
+ return -EINVAL;
+ if (ecmd.port != PORT_TP && ecmd.port != PORT_BNC)
+ return -EINVAL; /* AUI is not software-selectable */
+ if (ecmd.transceiver != XCVR_INTERNAL)
+ return -EINVAL;
+ if (ecmd.duplex != DUPLEX_HALF)
+ return -EINVAL;
+ if (ecmd.phy_address != 0)
+ return -EINVAL;
-static int ewrk3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- unsigned long iobase = dev->base_addr;
- unsigned long flags;
- u8 cr;
+ spin_lock_irqsave(&lp->hw_lock, flags);
+ cr = inb(EWRK3_CR);
- /* DE205 is the only card with anything to set */
- if (lp->adapter_name[4] != '5')
- return -EOPNOTSUPP;
+ /* If Autoneg is set, change to Auto Port mode */
+ /* Otherwise, disable Auto Port and set port explicitly */
+ if (ecmd.autoneg) {
+ cr &= ~CR_APD;
+ } else {
+ cr |= CR_APD;
+ if (ecmd.port == PORT_TP)
+ cr &= ~CR_PSEL; /* Force TP */
+ else
+ cr |= CR_PSEL; /* Force BNC */
+ }
- /* Sanity-check parameters */
- if (ecmd->speed != SPEED_10)
- return -EINVAL;
- if (ecmd->port != PORT_TP && ecmd->port != PORT_BNC)
- return -EINVAL; /* AUI is not software-selectable */
- if (ecmd->transceiver != XCVR_INTERNAL)
- return -EINVAL;
- if (ecmd->duplex != DUPLEX_HALF)
- return -EINVAL;
- if (ecmd->phy_address != 0)
- return -EINVAL;
+ /* Commit the changes */
+ outb(cr, EWRK3_CR);
- spin_lock_irqsave(&lp->hw_lock, flags);
- cr = inb(EWRK3_CR);
+ spin_unlock_irqrestore(&lp->hw_lock, flags);
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+ }
- /* If Autoneg is set, change to Auto Port mode */
- /* Otherwise, disable Auto Port and set port explicitly */
- if (ecmd->autoneg) {
- cr &= ~CR_APD;
- } else {
- cr |= CR_APD;
- if (ecmd->port == PORT_TP)
- cr &= ~CR_PSEL; /* Force TP */
- else
- cr |= CR_PSEL; /* Force BNC */
+ /* Get link status */
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = { ETHTOOL_GLINK };
+ u_char cmr = inb(EWRK3_CMR);
+
+ /* DE203 has BNC only and link status does not apply */
+ if (lp->adapter_name[4] == '3')
+ return -EOPNOTSUPP;
+
+ /* On DE204 this is always valid since TP is the only port. */
+ /* On DE205 this reflects TP status even if BNC or AUI is selected. */
+ edata.data = !(cmr & CMR_LINK);
+
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
}
- /* Commit the changes */
- outb(cr, EWRK3_CR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- return 0;
-}
+ /* Blink LED for identification */
+ case ETHTOOL_PHYS_ID: {
+ struct ethtool_value edata;
+ u_long flags;
+ u_char cr;
+ int count;
-static u32 ewrk3_get_link(struct net_device *dev)
-{
- unsigned long iobase = dev->base_addr;
- u8 cmr = inb(EWRK3_CMR);
- /* DE203 has BNC only and link status does not apply */
- /* On DE204 this is always valid since TP is the only port. */
- /* On DE205 this reflects TP status even if BNC or AUI is selected. */
- return !(cmr & CMR_LINK);
-}
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
-static int ewrk3_phys_id(struct net_device *dev, u32 data)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- unsigned long iobase = dev->base_addr;
- unsigned long flags;
- u8 cr;
- int count;
+ /* Toggle LED 4x per second */
+ count = edata.data << 2;
- /* Toggle LED 4x per second */
- count = data << 2;
+ spin_lock_irqsave(&lp->hw_lock, flags);
- spin_lock_irqsave(&lp->hw_lock, flags);
+ /* Bail if a PHYS_ID is already in progress */
+ if (lp->led_mask == 0) {
+ spin_unlock_irqrestore(&lp->hw_lock, flags);
+ return -EBUSY;
+ }
- /* Bail if a PHYS_ID is already in progress */
- if (lp->led_mask == 0) {
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- return -EBUSY;
- }
+ /* Prevent ISR from twiddling the LED */
+ lp->led_mask = 0;
- /* Prevent ISR from twiddling the LED */
- lp->led_mask = 0;
+ while (count--) {
+ /* Toggle the LED */
+ cr = inb(EWRK3_CR);
+ outb(cr ^ CR_LED, EWRK3_CR);
- while (count--) {
- /* Toggle the LED */
- cr = inb(EWRK3_CR);
- outb(cr ^ CR_LED, EWRK3_CR);
+ /* Wait a little while */
+ spin_unlock_irqrestore(&lp->hw_lock, flags);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ>>2);
+ spin_lock_irqsave(&lp->hw_lock, flags);
+
+ /* Exit if we got a signal */
+ if (signal_pending(current))
+ break;
+ }
- /* Wait a little while */
+ lp->led_mask = CR_LED;
+ cr = inb(EWRK3_CR);
+ outb(cr & ~CR_LED, EWRK3_CR);
spin_unlock_irqrestore(&lp->hw_lock, flags);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ>>2);
- spin_lock_irqsave(&lp->hw_lock, flags);
+ return signal_pending(current) ? -ERESTARTSYS : 0;
+ }
- /* Exit if we got a signal */
- if (signal_pending(current))
- break;
}
- lp->led_mask = CR_LED;
- cr = inb(EWRK3_CR);
- outb(cr & ~CR_LED, EWRK3_CR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- return signal_pending(current) ? -ERESTARTSYS : 0;
+ return -EOPNOTSUPP;
}
-static struct ethtool_ops ethtool_ops_203 = {
- .get_drvinfo = ewrk3_get_drvinfo,
- .get_settings = ewrk3_get_settings,
- .set_settings = ewrk3_set_settings,
- .phys_id = ewrk3_phys_id,
-};
-
-static struct ethtool_ops ethtool_ops = {
- .get_drvinfo = ewrk3_get_drvinfo,
- .get_settings = ewrk3_get_settings,
- .set_settings = ewrk3_set_settings,
- .get_link = ewrk3_get_link,
- .phys_id = ewrk3_phys_id,
-};
-
/*
** Perform IOCTL call functions here. Some are privileged operations and the
** effective uid is checked in those cases.
*/
static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct ewrk3_private *lp = netdev_priv(dev);
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_ifru;
u_long iobase = dev->base_addr;
int i, j, status = 0;
union ewrk3_addr *tmp;
- /* All we handle are private IOCTLs */
+ /* ethtool IOCTLs are handled elsewhere */
+ if (cmd == SIOCETHTOOL)
+ return ewrk3_ethtool_ioctl(dev, rq->ifr_data);
+
+ /* Other than ethtool, all we handle are private IOCTLs */
if (cmd != EWRK3IOCTL)
return -EOPNOTSUPP;