/*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
**
-** Copyright (c) 1999-2001 Petko Manolov (pmanolov@lnxw.com)
+** Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
**
**
** ChangeLog:
** TODO: suppressing HCD warnings spewage on disconnect.
** v0.4.13 Ethernet address is now set at probe(), not at open()
** time as this seems to break dhcpd.
+** v0.5.0 branch to 2.5.x kernels
+** v0.5.1 ethtool support added
*/
/*
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <asm/byteorder.h>
+#include <asm/uaccess.h>
#include "pegasus.h"
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.4.23 (2002/02/01)"
-#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
+#define DRIVER_VERSION "v0.5.1 (2002/03/06)"
+#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
#define PEGASUS_USE_INTR
#define PEGASUS_WRITE_EEPROM
+#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
+ BMSR_100FULL | BMSR_ANEGCAPABLE)
static int loopback = 0;
static int mii_mode = 0;
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
__u16 auxmode;
- read_mii_word( pegasus, 0, 0x1b, &auxmode );
- write_mii_word( pegasus, 0, 0x1b, auxmode | 4 );
+ read_mii_word( pegasus, 0, MII_TPISTATUS, &auxmode );
+ write_mii_word( pegasus, 0, MII_TPISTATUS, auxmode | 4 );
}
return 0;
if ( !(bmsr & 0x20) && !loopback )
warn( "%s: link NOT established (0x%x) - check the cable.",
dev->name, bmsr );
- if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
+ if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
return 2;
if ( !(linkpart & 1) )
warn( "link partner stat %x", linkpart );
data[0] = 0xc9;
data[1] = 0;
- if ( linkpart & (ANLPA_100TX_FD | ANLPA_10T_FD) )
+ if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
data[1] |= 0x20; /* set full duplex */
- if ( linkpart & (ANLPA_100TX_FD | ANLPA_100TX_HD) )
+ if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
data[1] |= 0x10; /* set 100 Mbps */
if ( mii_mode )
data[1] = 0;
}
+static void set_carrier(struct net_device *net)
+{
+ pegasus_t *pegasus;
+ short tmp;
+
+ pegasus = net->priv;
+ read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+ if (tmp & BMSR_LSTATUS)
+ netif_carrier_on(net);
+ else
+ netif_carrier_off(net);
+
+}
+
+
static int pegasus_open(struct net_device *net)
{
pegasus_t *pegasus = (pegasus_t *)net->priv;
int res;
- if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
- err("can't enable_net_traffic() - %d", res);
- return -EIO;
- }
FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU,
#endif
netif_start_queue( net );
pegasus->flags |= PEGASUS_RUNNING;
+ if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
+ err("can't enable_net_traffic() - %d", res);
+ return -EIO;
+ }
+ set_carrier(net);
return 0;
}
}
+static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
+{
+ pegasus_t *pegasus;
+ int cmd;
+ char tmp[128];
+
+ pegasus = net->priv;
+ if (get_user(cmd, (int *)uaddr))
+ return -EFAULT;
+ switch (cmd) {
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+ strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+ strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+ sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
+ pegasus->usb->devnum);
+ strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+ if (copy_to_user(uaddr, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ case ETHTOOL_GSET: {
+ struct ethtool_cmd ecmd;
+ short lpa, bmcr;
+
+ if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+ return -EFAULT;
+ ecmd.supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP |
+ SUPPORTED_MII);
+ ecmd.port = PORT_TP;
+ ecmd.transceiver = XCVR_INTERNAL;
+ ecmd.phy_address = pegasus->phy;
+ read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
+ read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
+ if (bmcr & BMCR_ANENABLE) {
+ ecmd.autoneg = AUTONEG_ENABLE;
+ ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
+ SPEED_100 : SPEED_10;
+ if (ecmd.speed == SPEED_100)
+ ecmd.duplex = lpa & LPA_100FULL ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ else
+ ecmd.duplex = lpa & LPA_10FULL ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ ecmd.autoneg = AUTONEG_DISABLE;
+ ecmd.speed = bmcr & BMCR_SPEED100 ?
+ SPEED_100 : SPEED_10;
+ ecmd.duplex = bmcr & BMCR_FULLDPLX ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ }
+ if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case ETHTOOL_SSET: {
+ return -EOPNOTSUPP;
+ }
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = {ETHTOOL_GLINK};
+ edata.data = netif_carrier_ok(net);
+ if (copy_to_user(uaddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
{
__u16 *data = (__u16 *)&rq->ifr_data;
pegasus_t *pegasus = net->priv;
switch(cmd) {
- case SIOCDEVPRIVATE:
- data[0] = pegasus->phy;
- case SIOCDEVPRIVATE+1:
- read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
- return 0;
- case SIOCDEVPRIVATE+2:
- if ( !capable(CAP_NET_ADMIN) )
- return -EPERM;
- write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
- return 0;
- default:
- return -EOPNOTSUPP;
+ case SIOCETHTOOL:
+ return pegasus_ethtool_ioctl(net, rq->ifr_data);
+ case SIOCDEVPRIVATE:
+ data[0] = pegasus->phy;
+ case SIOCDEVPRIVATE+1:
+ read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+ return 0;
+ case SIOCDEVPRIVATE+2:
+ if ( !capable(CAP_NET_ADMIN) )
+ return -EPERM;
+ write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
}
}
/*
- * Copyright (c) 1999,2000 Petko Manolov - Petkan (pmanolov@lnxw.com)
+ * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define EPROM_WR_ENABLE 0x10
#define EPROM_LOAD 0x20
-#define MII_BMCR 0x00
-#define MII_BMSR 0x01
-#define BMSR_MEDIA 0x7808
-#define MII_ANLPA 0x05
-#define ANLPA_100TX_FD 0x0100
-#define ANLPA_100TX_HD 0x0080
-#define ANLPA_10T_FD 0x0040
-#define ANLPA_10T_HD 0x0020
#define PHY_DONE 0x80
#define PHY_READ 0x40
#define PHY_WRITE 0x20
PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
VENDOR_ADMTEK, 0x0986,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,