15b2fc499SJeff Garzik /*
2cabd0e3aSPeter Korsgaard * Davicom DM96xx USB 10/100Mbps ethernet devices
35b2fc499SJeff Garzik *
45b2fc499SJeff Garzik * Peter Korsgaard <jacmet@sunsite.dk>
55b2fc499SJeff Garzik *
65b2fc499SJeff Garzik * This file is licensed under the terms of the GNU General Public License
75b2fc499SJeff Garzik * version 2. This program is licensed "as is" without any warranty of any
85b2fc499SJeff Garzik * kind, whether express or implied.
95b2fc499SJeff Garzik */
105b2fc499SJeff Garzik
115b2fc499SJeff Garzik //#define DEBUG
125b2fc499SJeff Garzik
135b2fc499SJeff Garzik #include <linux/module.h>
145b2fc499SJeff Garzik #include <linux/sched.h>
155b2fc499SJeff Garzik #include <linux/stddef.h>
165b2fc499SJeff Garzik #include <linux/netdevice.h>
175b2fc499SJeff Garzik #include <linux/etherdevice.h>
185b2fc499SJeff Garzik #include <linux/ethtool.h>
195b2fc499SJeff Garzik #include <linux/mii.h>
205b2fc499SJeff Garzik #include <linux/usb.h>
215b2fc499SJeff Garzik #include <linux/crc32.h>
223692e94fSJussi Kivilinna #include <linux/usb/usbnet.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
245b2fc499SJeff Garzik
255b2fc499SJeff Garzik /* datasheet:
2698658bc9SWu Fengguang http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf
275b2fc499SJeff Garzik */
285b2fc499SJeff Garzik
295b2fc499SJeff Garzik /* control requests */
305b2fc499SJeff Garzik #define DM_READ_REGS 0x00
315b2fc499SJeff Garzik #define DM_WRITE_REGS 0x01
325b2fc499SJeff Garzik #define DM_READ_MEMS 0x02
335b2fc499SJeff Garzik #define DM_WRITE_REG 0x03
345b2fc499SJeff Garzik #define DM_WRITE_MEMS 0x05
355b2fc499SJeff Garzik #define DM_WRITE_MEM 0x07
365b2fc499SJeff Garzik
375b2fc499SJeff Garzik /* registers */
385b2fc499SJeff Garzik #define DM_NET_CTRL 0x00
395b2fc499SJeff Garzik #define DM_RX_CTRL 0x05
405b2fc499SJeff Garzik #define DM_SHARED_CTRL 0x0b
415b2fc499SJeff Garzik #define DM_SHARED_ADDR 0x0c
425b2fc499SJeff Garzik #define DM_SHARED_DATA 0x0d /* low + high */
435b2fc499SJeff Garzik #define DM_PHY_ADDR 0x10 /* 6 bytes */
445b2fc499SJeff Garzik #define DM_MCAST_ADDR 0x16 /* 8 bytes */
455b2fc499SJeff Garzik #define DM_GPR_CTRL 0x1e
465b2fc499SJeff Garzik #define DM_GPR_DATA 0x1f
476642f91cSPeter Korsgaard #define DM_CHIP_ID 0x2c
486642f91cSPeter Korsgaard #define DM_MODE_CTRL 0x91 /* only on dm9620 */
496642f91cSPeter Korsgaard
506642f91cSPeter Korsgaard /* chip id values */
516642f91cSPeter Korsgaard #define ID_DM9601 0
526642f91cSPeter Korsgaard #define ID_DM9620 1
535b2fc499SJeff Garzik
545b2fc499SJeff Garzik #define DM_MAX_MCAST 64
555b2fc499SJeff Garzik #define DM_MCAST_SIZE 8
565b2fc499SJeff Garzik #define DM_EEPROM_LEN 256
575b2fc499SJeff Garzik #define DM_TX_OVERHEAD 2 /* 2 byte header */
585b2fc499SJeff Garzik #define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */
595b2fc499SJeff Garzik #define DM_TIMEOUT 1000
605b2fc499SJeff Garzik
dm_read(struct usbnet * dev,u8 reg,u16 length,void * data)615b2fc499SJeff Garzik static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
625b2fc499SJeff Garzik {
6324b1042cSMing Lei int err;
6424b1042cSMing Lei err = usbnet_read_cmd(dev, DM_READ_REGS,
655b2fc499SJeff Garzik USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
6624b1042cSMing Lei 0, reg, data, length);
6724b1042cSMing Lei if(err != length && err >= 0)
6816d78bc2SPeter Korsgaard err = -EINVAL;
6916d78bc2SPeter Korsgaard return err;
705b2fc499SJeff Garzik }
715b2fc499SJeff Garzik
dm_read_reg(struct usbnet * dev,u8 reg,u8 * value)725b2fc499SJeff Garzik static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value)
735b2fc499SJeff Garzik {
745b2fc499SJeff Garzik return dm_read(dev, reg, 1, value);
755b2fc499SJeff Garzik }
765b2fc499SJeff Garzik
dm_write(struct usbnet * dev,u8 reg,u16 length,void * data)775b2fc499SJeff Garzik static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
785b2fc499SJeff Garzik {
7924b1042cSMing Lei int err;
8024b1042cSMing Lei err = usbnet_write_cmd(dev, DM_WRITE_REGS,
815b2fc499SJeff Garzik USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
8224b1042cSMing Lei 0, reg, data, length);
8324b1042cSMing Lei
8416d78bc2SPeter Korsgaard if (err >= 0 && err < length)
8516d78bc2SPeter Korsgaard err = -EINVAL;
8616d78bc2SPeter Korsgaard return err;
875b2fc499SJeff Garzik }
885b2fc499SJeff Garzik
dm_write_reg(struct usbnet * dev,u8 reg,u8 value)895b2fc499SJeff Garzik static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
905b2fc499SJeff Garzik {
911b9c3a1bSTushar Behera return usbnet_write_cmd(dev, DM_WRITE_REG,
925b2fc499SJeff Garzik USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
9324b1042cSMing Lei value, reg, NULL, 0);
945b2fc499SJeff Garzik }
955b2fc499SJeff Garzik
dm_write_async(struct usbnet * dev,u8 reg,u16 length,const void * data)9676660757SJakub Kicinski static void dm_write_async(struct usbnet *dev, u8 reg, u16 length,
9776660757SJakub Kicinski const void *data)
985b2fc499SJeff Garzik {
9924b1042cSMing Lei usbnet_write_cmd_async(dev, DM_WRITE_REGS,
10024b1042cSMing Lei USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1011b9c3a1bSTushar Behera 0, reg, data, length);
102ba734f34SPeter Korsgaard }
103ba734f34SPeter Korsgaard
dm_write_reg_async(struct usbnet * dev,u8 reg,u8 value)1045b2fc499SJeff Garzik static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
1055b2fc499SJeff Garzik {
1061b9c3a1bSTushar Behera usbnet_write_cmd_async(dev, DM_WRITE_REG,
1071b9c3a1bSTushar Behera USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1081b9c3a1bSTushar Behera value, reg, NULL, 0);
1095b2fc499SJeff Garzik }
1105b2fc499SJeff Garzik
dm_read_shared_word(struct usbnet * dev,int phy,u8 reg,__le16 * value)111eca1ad82SAl Viro static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
1125b2fc499SJeff Garzik {
1135b2fc499SJeff Garzik int ret, i;
1145b2fc499SJeff Garzik
1155b2fc499SJeff Garzik mutex_lock(&dev->phy_mutex);
1165b2fc499SJeff Garzik
1175b2fc499SJeff Garzik dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
1185b2fc499SJeff Garzik dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
1195b2fc499SJeff Garzik
1205b2fc499SJeff Garzik for (i = 0; i < DM_TIMEOUT; i++) {
12115c8bb12SSimon Que u8 tmp = 0;
1225b2fc499SJeff Garzik
1235b2fc499SJeff Garzik udelay(1);
1245b2fc499SJeff Garzik ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
1255b2fc499SJeff Garzik if (ret < 0)
1265b2fc499SJeff Garzik goto out;
1275b2fc499SJeff Garzik
1285b2fc499SJeff Garzik /* ready */
1295b2fc499SJeff Garzik if ((tmp & 1) == 0)
1305b2fc499SJeff Garzik break;
1315b2fc499SJeff Garzik }
1325b2fc499SJeff Garzik
1335b2fc499SJeff Garzik if (i == DM_TIMEOUT) {
13460b86755SJoe Perches netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
1355b2fc499SJeff Garzik ret = -EIO;
1365b2fc499SJeff Garzik goto out;
1375b2fc499SJeff Garzik }
1385b2fc499SJeff Garzik
1395b2fc499SJeff Garzik dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
1405b2fc499SJeff Garzik ret = dm_read(dev, DM_SHARED_DATA, 2, value);
1415b2fc499SJeff Garzik
14260b86755SJoe Perches netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
1435b2fc499SJeff Garzik phy, reg, *value, ret);
1445b2fc499SJeff Garzik
1455b2fc499SJeff Garzik out:
1465b2fc499SJeff Garzik mutex_unlock(&dev->phy_mutex);
1475b2fc499SJeff Garzik return ret;
1485b2fc499SJeff Garzik }
1495b2fc499SJeff Garzik
dm_write_shared_word(struct usbnet * dev,int phy,u8 reg,__le16 value)150eca1ad82SAl Viro static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
1515b2fc499SJeff Garzik {
1525b2fc499SJeff Garzik int ret, i;
1535b2fc499SJeff Garzik
1545b2fc499SJeff Garzik mutex_lock(&dev->phy_mutex);
1555b2fc499SJeff Garzik
1565b2fc499SJeff Garzik ret = dm_write(dev, DM_SHARED_DATA, 2, &value);
1575b2fc499SJeff Garzik if (ret < 0)
1585b2fc499SJeff Garzik goto out;
1595b2fc499SJeff Garzik
1605b2fc499SJeff Garzik dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
161e9162ab1SPeter Korsgaard dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);
1625b2fc499SJeff Garzik
1635b2fc499SJeff Garzik for (i = 0; i < DM_TIMEOUT; i++) {
16415c8bb12SSimon Que u8 tmp = 0;
1655b2fc499SJeff Garzik
1665b2fc499SJeff Garzik udelay(1);
1675b2fc499SJeff Garzik ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
1685b2fc499SJeff Garzik if (ret < 0)
1695b2fc499SJeff Garzik goto out;
1705b2fc499SJeff Garzik
1715b2fc499SJeff Garzik /* ready */
1725b2fc499SJeff Garzik if ((tmp & 1) == 0)
1735b2fc499SJeff Garzik break;
1745b2fc499SJeff Garzik }
1755b2fc499SJeff Garzik
1765b2fc499SJeff Garzik if (i == DM_TIMEOUT) {
17760b86755SJoe Perches netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
1785b2fc499SJeff Garzik ret = -EIO;
1795b2fc499SJeff Garzik goto out;
1805b2fc499SJeff Garzik }
1815b2fc499SJeff Garzik
1825b2fc499SJeff Garzik dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
1835b2fc499SJeff Garzik
1845b2fc499SJeff Garzik out:
1855b2fc499SJeff Garzik mutex_unlock(&dev->phy_mutex);
1865b2fc499SJeff Garzik return ret;
1875b2fc499SJeff Garzik }
1885b2fc499SJeff Garzik
dm_read_eeprom_word(struct usbnet * dev,u8 offset,void * value)1895b2fc499SJeff Garzik static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
1905b2fc499SJeff Garzik {
1915b2fc499SJeff Garzik return dm_read_shared_word(dev, 0, offset, value);
1925b2fc499SJeff Garzik }
1935b2fc499SJeff Garzik
1945b2fc499SJeff Garzik
1955b2fc499SJeff Garzik
dm9601_get_eeprom_len(struct net_device * dev)1965b2fc499SJeff Garzik static int dm9601_get_eeprom_len(struct net_device *dev)
1975b2fc499SJeff Garzik {
1985b2fc499SJeff Garzik return DM_EEPROM_LEN;
1995b2fc499SJeff Garzik }
2005b2fc499SJeff Garzik
dm9601_get_eeprom(struct net_device * net,struct ethtool_eeprom * eeprom,u8 * data)2015b2fc499SJeff Garzik static int dm9601_get_eeprom(struct net_device *net,
2025b2fc499SJeff Garzik struct ethtool_eeprom *eeprom, u8 * data)
2035b2fc499SJeff Garzik {
2045b2fc499SJeff Garzik struct usbnet *dev = netdev_priv(net);
205eca1ad82SAl Viro __le16 *ebuf = (__le16 *) data;
2065b2fc499SJeff Garzik int i;
2075b2fc499SJeff Garzik
2085b2fc499SJeff Garzik /* access is 16bit */
2095b2fc499SJeff Garzik if ((eeprom->offset % 2) || (eeprom->len % 2))
2105b2fc499SJeff Garzik return -EINVAL;
2115b2fc499SJeff Garzik
2125b2fc499SJeff Garzik for (i = 0; i < eeprom->len / 2; i++) {
2135b2fc499SJeff Garzik if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,
2145b2fc499SJeff Garzik &ebuf[i]) < 0)
2155b2fc499SJeff Garzik return -EINVAL;
2165b2fc499SJeff Garzik }
2175b2fc499SJeff Garzik return 0;
2185b2fc499SJeff Garzik }
2195b2fc499SJeff Garzik
dm9601_mdio_read(struct net_device * netdev,int phy_id,int loc)2205b2fc499SJeff Garzik static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
2215b2fc499SJeff Garzik {
2225b2fc499SJeff Garzik struct usbnet *dev = netdev_priv(netdev);
2235b2fc499SJeff Garzik
224eca1ad82SAl Viro __le16 res;
2258f8abb86SJavier Carrasco int err;
2265b2fc499SJeff Garzik
2275b2fc499SJeff Garzik if (phy_id) {
22860b86755SJoe Perches netdev_dbg(dev->net, "Only internal phy supported\n");
2295b2fc499SJeff Garzik return 0;
2305b2fc499SJeff Garzik }
2315b2fc499SJeff Garzik
2328f8abb86SJavier Carrasco err = dm_read_shared_word(dev, 1, loc, &res);
2338f8abb86SJavier Carrasco if (err < 0) {
2348f8abb86SJavier Carrasco netdev_err(dev->net, "MDIO read error: %d\n", err);
235*0ec3ea61SJavier Carrasco return 0;
2368f8abb86SJavier Carrasco }
2375b2fc499SJeff Garzik
23860b86755SJoe Perches netdev_dbg(dev->net,
23960b86755SJoe Perches "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
2405b2fc499SJeff Garzik phy_id, loc, le16_to_cpu(res));
2415b2fc499SJeff Garzik
2425b2fc499SJeff Garzik return le16_to_cpu(res);
2435b2fc499SJeff Garzik }
2445b2fc499SJeff Garzik
dm9601_mdio_write(struct net_device * netdev,int phy_id,int loc,int val)2455b2fc499SJeff Garzik static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
2465b2fc499SJeff Garzik int val)
2475b2fc499SJeff Garzik {
2485b2fc499SJeff Garzik struct usbnet *dev = netdev_priv(netdev);
249eca1ad82SAl Viro __le16 res = cpu_to_le16(val);
2505b2fc499SJeff Garzik
2515b2fc499SJeff Garzik if (phy_id) {
25260b86755SJoe Perches netdev_dbg(dev->net, "Only internal phy supported\n");
2535b2fc499SJeff Garzik return;
2545b2fc499SJeff Garzik }
2555b2fc499SJeff Garzik
25660b86755SJoe Perches netdev_dbg(dev->net, "dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
2575b2fc499SJeff Garzik phy_id, loc, val);
2585b2fc499SJeff Garzik
2595b2fc499SJeff Garzik dm_write_shared_word(dev, 1, loc, res);
2605b2fc499SJeff Garzik }
2615b2fc499SJeff Garzik
dm9601_get_drvinfo(struct net_device * net,struct ethtool_drvinfo * info)2625b2fc499SJeff Garzik static void dm9601_get_drvinfo(struct net_device *net,
2635b2fc499SJeff Garzik struct ethtool_drvinfo *info)
2645b2fc499SJeff Garzik {
2655b2fc499SJeff Garzik /* Inherit standard device info */
2665b2fc499SJeff Garzik usbnet_get_drvinfo(net, info);
2675b2fc499SJeff Garzik }
2685b2fc499SJeff Garzik
dm9601_get_link(struct net_device * net)2695b2fc499SJeff Garzik static u32 dm9601_get_link(struct net_device *net)
2705b2fc499SJeff Garzik {
2715b2fc499SJeff Garzik struct usbnet *dev = netdev_priv(net);
2725b2fc499SJeff Garzik
2735b2fc499SJeff Garzik return mii_link_ok(&dev->mii);
2745b2fc499SJeff Garzik }
2755b2fc499SJeff Garzik
dm9601_ioctl(struct net_device * net,struct ifreq * rq,int cmd)2765b2fc499SJeff Garzik static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
2775b2fc499SJeff Garzik {
2785b2fc499SJeff Garzik struct usbnet *dev = netdev_priv(net);
2795b2fc499SJeff Garzik
2805b2fc499SJeff Garzik return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
2815b2fc499SJeff Garzik }
2825b2fc499SJeff Garzik
2830fc0b732SStephen Hemminger static const struct ethtool_ops dm9601_ethtool_ops = {
2845b2fc499SJeff Garzik .get_drvinfo = dm9601_get_drvinfo,
2855b2fc499SJeff Garzik .get_link = dm9601_get_link,
2865b2fc499SJeff Garzik .get_msglevel = usbnet_get_msglevel,
2875b2fc499SJeff Garzik .set_msglevel = usbnet_set_msglevel,
2885b2fc499SJeff Garzik .get_eeprom_len = dm9601_get_eeprom_len,
2895b2fc499SJeff Garzik .get_eeprom = dm9601_get_eeprom,
2905b2fc499SJeff Garzik .nway_reset = usbnet_nway_reset,
29177651900SOliver Neukum .get_link_ksettings = usbnet_get_link_ksettings_mii,
29277651900SOliver Neukum .set_link_ksettings = usbnet_set_link_ksettings_mii,
2935b2fc499SJeff Garzik };
2945b2fc499SJeff Garzik
dm9601_set_multicast(struct net_device * net)2955b2fc499SJeff Garzik static void dm9601_set_multicast(struct net_device *net)
2965b2fc499SJeff Garzik {
2975b2fc499SJeff Garzik struct usbnet *dev = netdev_priv(net);
2985b2fc499SJeff Garzik /* We use the 20 byte dev->data for our 8 byte filter buffer
2995b2fc499SJeff Garzik * to avoid allocating memory that is tricky to free later */
3005b2fc499SJeff Garzik u8 *hashes = (u8 *) & dev->data;
30133eddedbSPeter Korsgaard u8 rx_ctl = 0x31;
3025b2fc499SJeff Garzik
3035b2fc499SJeff Garzik memset(hashes, 0x00, DM_MCAST_SIZE);
3045b2fc499SJeff Garzik hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */
3055b2fc499SJeff Garzik
3065b2fc499SJeff Garzik if (net->flags & IFF_PROMISC) {
3075b2fc499SJeff Garzik rx_ctl |= 0x02;
3082cc04d27SJiri Pirko } else if (net->flags & IFF_ALLMULTI ||
3092cc04d27SJiri Pirko netdev_mc_count(net) > DM_MAX_MCAST) {
310bf0ea638SPeter Korsgaard rx_ctl |= 0x08;
3112cc04d27SJiri Pirko } else if (!netdev_mc_empty(net)) {
31222bedad3SJiri Pirko struct netdev_hw_addr *ha;
3135b2fc499SJeff Garzik
31422bedad3SJiri Pirko netdev_for_each_mc_addr(ha, net) {
31522bedad3SJiri Pirko u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
3165b2fc499SJeff Garzik hashes[crc >> 3] |= 1 << (crc & 0x7);
3175b2fc499SJeff Garzik }
3185b2fc499SJeff Garzik }
3195b2fc499SJeff Garzik
3205b2fc499SJeff Garzik dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);
3215b2fc499SJeff Garzik dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
3225b2fc499SJeff Garzik }
3235b2fc499SJeff Garzik
__dm9601_set_mac_address(struct usbnet * dev)3244b9f8ec6SWu Fengguang static void __dm9601_set_mac_address(struct usbnet *dev)
3254b9f8ec6SWu Fengguang {
3264b9f8ec6SWu Fengguang dm_write_async(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
3274b9f8ec6SWu Fengguang }
3284b9f8ec6SWu Fengguang
dm9601_set_mac_address(struct net_device * net,void * p)329753dcfeeSPeter Korsgaard static int dm9601_set_mac_address(struct net_device *net, void *p)
330753dcfeeSPeter Korsgaard {
331753dcfeeSPeter Korsgaard struct sockaddr *addr = p;
332753dcfeeSPeter Korsgaard struct usbnet *dev = netdev_priv(net);
333753dcfeeSPeter Korsgaard
334f52deb0eSWu Fengguang if (!is_valid_ether_addr(addr->sa_data)) {
335f52deb0eSWu Fengguang dev_err(&net->dev, "not setting invalid mac address %pM\n",
336f52deb0eSWu Fengguang addr->sa_data);
337753dcfeeSPeter Korsgaard return -EINVAL;
338f52deb0eSWu Fengguang }
339753dcfeeSPeter Korsgaard
34049ed8ddeSJakub Kicinski eth_hw_addr_set(net, addr->sa_data);
3414b9f8ec6SWu Fengguang __dm9601_set_mac_address(dev);
342753dcfeeSPeter Korsgaard
343753dcfeeSPeter Korsgaard return 0;
344753dcfeeSPeter Korsgaard }
345753dcfeeSPeter Korsgaard
346fe85ff82SStephen Hemminger static const struct net_device_ops dm9601_netdev_ops = {
347fe85ff82SStephen Hemminger .ndo_open = usbnet_open,
348fe85ff82SStephen Hemminger .ndo_stop = usbnet_stop,
349fe85ff82SStephen Hemminger .ndo_start_xmit = usbnet_start_xmit,
350fe85ff82SStephen Hemminger .ndo_tx_timeout = usbnet_tx_timeout,
351fe85ff82SStephen Hemminger .ndo_change_mtu = usbnet_change_mtu,
352323955a0SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
353fe85ff82SStephen Hemminger .ndo_validate_addr = eth_validate_addr,
354a7605370SArnd Bergmann .ndo_eth_ioctl = dm9601_ioctl,
355afc4b13dSJiri Pirko .ndo_set_rx_mode = dm9601_set_multicast,
356fe85ff82SStephen Hemminger .ndo_set_mac_address = dm9601_set_mac_address,
357fe85ff82SStephen Hemminger };
358fe85ff82SStephen Hemminger
dm9601_bind(struct usbnet * dev,struct usb_interface * intf)3595b2fc499SJeff Garzik static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
3605b2fc499SJeff Garzik {
3615b2fc499SJeff Garzik int ret;
3626642f91cSPeter Korsgaard u8 mac[ETH_ALEN], id;
3635b2fc499SJeff Garzik
3645b2fc499SJeff Garzik ret = usbnet_get_endpoints(dev, intf);
3655b2fc499SJeff Garzik if (ret)
3665b2fc499SJeff Garzik goto out;
3675b2fc499SJeff Garzik
368fe85ff82SStephen Hemminger dev->net->netdev_ops = &dm9601_netdev_ops;
3695b2fc499SJeff Garzik dev->net->ethtool_ops = &dm9601_ethtool_ops;
3705b2fc499SJeff Garzik dev->net->hard_header_len += DM_TX_OVERHEAD;
3715b2fc499SJeff Garzik dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
372407900cfSPeter Korsgaard
373407900cfSPeter Korsgaard /* dm9620/21a require room for 4 byte padding, even in dm9601
374407900cfSPeter Korsgaard * mode, so we need +1 to be able to receive full size
375407900cfSPeter Korsgaard * ethernet frames.
376407900cfSPeter Korsgaard */
377407900cfSPeter Korsgaard dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1;
3785b2fc499SJeff Garzik
3795b2fc499SJeff Garzik dev->mii.dev = dev->net;
3805b2fc499SJeff Garzik dev->mii.mdio_read = dm9601_mdio_read;
3815b2fc499SJeff Garzik dev->mii.mdio_write = dm9601_mdio_write;
3825b2fc499SJeff Garzik dev->mii.phy_id_mask = 0x1f;
3835b2fc499SJeff Garzik dev->mii.reg_num_mask = 0x1f;
3845b2fc499SJeff Garzik
3855b2fc499SJeff Garzik /* reset */
386b8f59586SPeter Korsgaard dm_write_reg(dev, DM_NET_CTRL, 1);
3875b2fc499SJeff Garzik udelay(20);
3885b2fc499SJeff Garzik
3895b2fc499SJeff Garzik /* read MAC */
39020f10aa0SWu Fengguang if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, mac) < 0) {
3915b2fc499SJeff Garzik printk(KERN_ERR "Error reading MAC address\n");
3925b2fc499SJeff Garzik ret = -ENODEV;
3935b2fc499SJeff Garzik goto out;
3945b2fc499SJeff Garzik }
3955b2fc499SJeff Garzik
39620f10aa0SWu Fengguang /*
39720f10aa0SWu Fengguang * Overwrite the auto-generated address only with good ones.
39820f10aa0SWu Fengguang */
39920f10aa0SWu Fengguang if (is_valid_ether_addr(mac))
40016813717SJakub Kicinski eth_hw_addr_set(dev->net, mac);
401f52deb0eSWu Fengguang else {
402f52deb0eSWu Fengguang printk(KERN_WARNING
403f52deb0eSWu Fengguang "dm9601: No valid MAC address in EEPROM, using %pM\n",
404f52deb0eSWu Fengguang dev->net->dev_addr);
4054b9f8ec6SWu Fengguang __dm9601_set_mac_address(dev);
406f52deb0eSWu Fengguang }
40720f10aa0SWu Fengguang
4086642f91cSPeter Korsgaard if (dm_read_reg(dev, DM_CHIP_ID, &id) < 0) {
4096642f91cSPeter Korsgaard netdev_err(dev->net, "Error reading chip ID\n");
4106642f91cSPeter Korsgaard ret = -ENODEV;
4116642f91cSPeter Korsgaard goto out;
4126642f91cSPeter Korsgaard }
4136642f91cSPeter Korsgaard
4146642f91cSPeter Korsgaard /* put dm9620 devices in dm9601 mode */
4156642f91cSPeter Korsgaard if (id == ID_DM9620) {
4166642f91cSPeter Korsgaard u8 mode;
4176642f91cSPeter Korsgaard
4186642f91cSPeter Korsgaard if (dm_read_reg(dev, DM_MODE_CTRL, &mode) < 0) {
4196642f91cSPeter Korsgaard netdev_err(dev->net, "Error reading MODE_CTRL\n");
4206642f91cSPeter Korsgaard ret = -ENODEV;
4216642f91cSPeter Korsgaard goto out;
4226642f91cSPeter Korsgaard }
4236642f91cSPeter Korsgaard dm_write_reg(dev, DM_MODE_CTRL, mode & 0x7f);
4246642f91cSPeter Korsgaard }
4256642f91cSPeter Korsgaard
4265b2fc499SJeff Garzik /* power up phy */
4275b2fc499SJeff Garzik dm_write_reg(dev, DM_GPR_CTRL, 1);
4285b2fc499SJeff Garzik dm_write_reg(dev, DM_GPR_DATA, 0);
4295b2fc499SJeff Garzik
4305b2fc499SJeff Garzik /* receive broadcast packets */
4315b2fc499SJeff Garzik dm9601_set_multicast(dev->net);
4325b2fc499SJeff Garzik
4335b2fc499SJeff Garzik dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
4345b2fc499SJeff Garzik dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
4355b2fc499SJeff Garzik ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
4365b2fc499SJeff Garzik mii_nway_restart(&dev->mii);
4375b2fc499SJeff Garzik
4385b2fc499SJeff Garzik out:
4395b2fc499SJeff Garzik return ret;
4405b2fc499SJeff Garzik }
4415b2fc499SJeff Garzik
dm9601_rx_fixup(struct usbnet * dev,struct sk_buff * skb)4425b2fc499SJeff Garzik static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
4435b2fc499SJeff Garzik {
4445b2fc499SJeff Garzik u8 status;
4455b2fc499SJeff Garzik int len;
4465b2fc499SJeff Garzik
4475b2fc499SJeff Garzik /* format:
44861189c78SPeter Korsgaard b1: rx status
44961189c78SPeter Korsgaard b2: packet length (incl crc) low
45061189c78SPeter Korsgaard b3: packet length (incl crc) high
45161189c78SPeter Korsgaard b4..n-4: packet data
4525b2fc499SJeff Garzik bn-3..bn: ethernet crc
4535b2fc499SJeff Garzik */
4545b2fc499SJeff Garzik
4555b2fc499SJeff Garzik if (unlikely(skb->len < DM_RX_OVERHEAD)) {
4565b2fc499SJeff Garzik dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
4575b2fc499SJeff Garzik return 0;
4585b2fc499SJeff Garzik }
4595b2fc499SJeff Garzik
4605b2fc499SJeff Garzik status = skb->data[0];
4615b2fc499SJeff Garzik len = (skb->data[1] | (skb->data[2] << 8)) - 4;
4625b2fc499SJeff Garzik
4635b2fc499SJeff Garzik if (unlikely(status & 0xbf)) {
4649612101cSHerbert Xu if (status & 0x01) dev->net->stats.rx_fifo_errors++;
4659612101cSHerbert Xu if (status & 0x02) dev->net->stats.rx_crc_errors++;
4669612101cSHerbert Xu if (status & 0x04) dev->net->stats.rx_frame_errors++;
4679612101cSHerbert Xu if (status & 0x20) dev->net->stats.rx_missed_errors++;
4689612101cSHerbert Xu if (status & 0x90) dev->net->stats.rx_length_errors++;
4695b2fc499SJeff Garzik return 0;
4705b2fc499SJeff Garzik }
4715b2fc499SJeff Garzik
4725b2fc499SJeff Garzik skb_pull(skb, 3);
4735b2fc499SJeff Garzik skb_trim(skb, len);
4745b2fc499SJeff Garzik
4755b2fc499SJeff Garzik return 1;
4765b2fc499SJeff Garzik }
4775b2fc499SJeff Garzik
dm9601_tx_fixup(struct usbnet * dev,struct sk_buff * skb,gfp_t flags)4785b2fc499SJeff Garzik static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
4795b2fc499SJeff Garzik gfp_t flags)
4805b2fc499SJeff Garzik {
4814263c86dSPeter Korsgaard int len, pad;
4825b2fc499SJeff Garzik
4835b2fc499SJeff Garzik /* format:
48461189c78SPeter Korsgaard b1: packet length low
48561189c78SPeter Korsgaard b2: packet length high
4865b2fc499SJeff Garzik b3..n: packet data
4875b2fc499SJeff Garzik */
4885b2fc499SJeff Garzik
4894263c86dSPeter Korsgaard len = skb->len + DM_TX_OVERHEAD;
49023de559bSPeter Korsgaard
4914263c86dSPeter Korsgaard /* workaround for dm962x errata with tx fifo getting out of
4924263c86dSPeter Korsgaard * sync if a USB bulk transfer retry happens right after a
4934263c86dSPeter Korsgaard * packet with odd / maxpacket length by adding up to 3 bytes
4944263c86dSPeter Korsgaard * padding.
4954263c86dSPeter Korsgaard */
4964263c86dSPeter Korsgaard while ((len & 1) || !(len % dev->maxpacket))
4974263c86dSPeter Korsgaard len++;
4984263c86dSPeter Korsgaard
4994263c86dSPeter Korsgaard len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */
5004263c86dSPeter Korsgaard pad = len - skb->len;
5014263c86dSPeter Korsgaard
5024263c86dSPeter Korsgaard if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) {
5035b2fc499SJeff Garzik struct sk_buff *skb2;
5045b2fc499SJeff Garzik
5054263c86dSPeter Korsgaard skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags);
5065b2fc499SJeff Garzik dev_kfree_skb_any(skb);
5075b2fc499SJeff Garzik skb = skb2;
5085b2fc499SJeff Garzik if (!skb)
5095b2fc499SJeff Garzik return NULL;
5105b2fc499SJeff Garzik }
5115b2fc499SJeff Garzik
5125b2fc499SJeff Garzik __skb_push(skb, DM_TX_OVERHEAD);
5135b2fc499SJeff Garzik
5144263c86dSPeter Korsgaard if (pad) {
5154263c86dSPeter Korsgaard memset(skb->data + skb->len, 0, pad);
5164263c86dSPeter Korsgaard __skb_put(skb, pad);
5174263c86dSPeter Korsgaard }
5185b2fc499SJeff Garzik
5195b2fc499SJeff Garzik skb->data[0] = len;
5205b2fc499SJeff Garzik skb->data[1] = len >> 8;
5215b2fc499SJeff Garzik
5225b2fc499SJeff Garzik return skb;
5235b2fc499SJeff Garzik }
5245b2fc499SJeff Garzik
dm9601_status(struct usbnet * dev,struct urb * urb)5255b2fc499SJeff Garzik static void dm9601_status(struct usbnet *dev, struct urb *urb)
5265b2fc499SJeff Garzik {
5275b2fc499SJeff Garzik int link;
5285b2fc499SJeff Garzik u8 *buf;
5295b2fc499SJeff Garzik
5305b2fc499SJeff Garzik /* format:
5315b2fc499SJeff Garzik b0: net status
5325b2fc499SJeff Garzik b1: tx status 1
5335b2fc499SJeff Garzik b2: tx status 2
5345b2fc499SJeff Garzik b3: rx status
5355b2fc499SJeff Garzik b4: rx overflow
5365b2fc499SJeff Garzik b5: rx count
5375b2fc499SJeff Garzik b6: tx count
5385b2fc499SJeff Garzik b7: gpr
5395b2fc499SJeff Garzik */
5405b2fc499SJeff Garzik
5415b2fc499SJeff Garzik if (urb->actual_length < 8)
5425b2fc499SJeff Garzik return;
5435b2fc499SJeff Garzik
5445b2fc499SJeff Garzik buf = urb->transfer_buffer;
5455b2fc499SJeff Garzik
5465b2fc499SJeff Garzik link = !!(buf[0] & 0x40);
5475b2fc499SJeff Garzik if (netif_carrier_ok(dev->net) != link) {
548c10b1710SMing Lei usbnet_link_change(dev, link, 1);
54960b86755SJoe Perches netdev_dbg(dev->net, "Link Status is: %d\n", link);
5505b2fc499SJeff Garzik }
5515b2fc499SJeff Garzik }
5525b2fc499SJeff Garzik
dm9601_link_reset(struct usbnet * dev)5535b2fc499SJeff Garzik static int dm9601_link_reset(struct usbnet *dev)
5545b2fc499SJeff Garzik {
5558ae6dacaSDavid Decotigny struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
5565b2fc499SJeff Garzik
5575b2fc499SJeff Garzik mii_check_media(&dev->mii, 1, 1);
5585b2fc499SJeff Garzik mii_ethtool_gset(&dev->mii, &ecmd);
5595b2fc499SJeff Garzik
5608ae6dacaSDavid Decotigny netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
5618ae6dacaSDavid Decotigny ethtool_cmd_speed(&ecmd), ecmd.duplex);
5625b2fc499SJeff Garzik
5635b2fc499SJeff Garzik return 0;
5645b2fc499SJeff Garzik }
5655b2fc499SJeff Garzik
5665b2fc499SJeff Garzik static const struct driver_info dm9601_info = {
567cabd0e3aSPeter Korsgaard .description = "Davicom DM96xx USB 10/100 Ethernet",
56837e8273cSBen Hutchings .flags = FLAG_ETHER | FLAG_LINK_INTR,
5695b2fc499SJeff Garzik .bind = dm9601_bind,
5705b2fc499SJeff Garzik .rx_fixup = dm9601_rx_fixup,
5715b2fc499SJeff Garzik .tx_fixup = dm9601_tx_fixup,
5725b2fc499SJeff Garzik .status = dm9601_status,
5735b2fc499SJeff Garzik .link_reset = dm9601_link_reset,
5745b2fc499SJeff Garzik .reset = dm9601_link_reset,
5755b2fc499SJeff Garzik };
5765b2fc499SJeff Garzik
5775b2fc499SJeff Garzik static const struct usb_device_id products[] = {
5785b2fc499SJeff Garzik {
5795b2fc499SJeff Garzik USB_DEVICE(0x07aa, 0x9601), /* Corega FEther USB-TXC */
5805b2fc499SJeff Garzik .driver_info = (unsigned long)&dm9601_info,
5815b2fc499SJeff Garzik },
5825b2fc499SJeff Garzik {
5835b2fc499SJeff Garzik USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */
5845b2fc499SJeff Garzik .driver_info = (unsigned long)&dm9601_info,
5855b2fc499SJeff Garzik },
5865b2fc499SJeff Garzik {
5875b2fc499SJeff Garzik USB_DEVICE(0x0a46, 0x6688), /* ZT6688 USB NIC */
5885b2fc499SJeff Garzik .driver_info = (unsigned long)&dm9601_info,
5895b2fc499SJeff Garzik },
5905b2fc499SJeff Garzik {
5915b2fc499SJeff Garzik USB_DEVICE(0x0a46, 0x0268), /* ShanTou ST268 USB NIC */
5925b2fc499SJeff Garzik .driver_info = (unsigned long)&dm9601_info,
5935b2fc499SJeff Garzik },
594a06da754SPeter Korsgaard {
595a06da754SPeter Korsgaard USB_DEVICE(0x0a46, 0x8515), /* ADMtek ADM8515 USB NIC */
596a06da754SPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
597a06da754SPeter Korsgaard },
598b47b4b22SPeter Korsgaard {
599b47b4b22SPeter Korsgaard USB_DEVICE(0x0a47, 0x9601), /* Hirose USB-100 */
600b47b4b22SPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
601b47b4b22SPeter Korsgaard },
602a1a69c8dSPeter Korsgaard {
603a1a69c8dSPeter Korsgaard USB_DEVICE(0x0fe6, 0x8101), /* DM9601 USB to Fast Ethernet Adapter */
604a1a69c8dSPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
605a1a69c8dSPeter Korsgaard },
60606b71b65SJanusz Krzysztofik {
60767158cebSShahar Havivi USB_DEVICE(0x0fe6, 0x9700), /* DM9601 USB to Fast Ethernet Adapter */
60867158cebSShahar Havivi .driver_info = (unsigned long)&dm9601_info,
60967158cebSShahar Havivi },
61067158cebSShahar Havivi {
61106b71b65SJanusz Krzysztofik USB_DEVICE(0x0a46, 0x9000), /* DM9000E */
61206b71b65SJanusz Krzysztofik .driver_info = (unsigned long)&dm9601_info,
61306b71b65SJanusz Krzysztofik },
6146642f91cSPeter Korsgaard {
6156642f91cSPeter Korsgaard USB_DEVICE(0x0a46, 0x9620), /* DM9620 USB to Fast Ethernet Adapter */
6166642f91cSPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
6176642f91cSPeter Korsgaard },
6183b387892SPeter Korsgaard {
6193b387892SPeter Korsgaard USB_DEVICE(0x0a46, 0x9621), /* DM9621A USB to Fast Ethernet Adapter */
6203b387892SPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
6213b387892SPeter Korsgaard },
6227c4b5175SPeter Korsgaard {
6237c4b5175SPeter Korsgaard USB_DEVICE(0x0a46, 0x9622), /* DM9622 USB to Fast Ethernet Adapter */
6247c4b5175SPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
6257c4b5175SPeter Korsgaard },
6267c4b5175SPeter Korsgaard {
6277c4b5175SPeter Korsgaard USB_DEVICE(0x0a46, 0x0269), /* DM962OA USB to Fast Ethernet Adapter */
6287c4b5175SPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
6297c4b5175SPeter Korsgaard },
6307c4b5175SPeter Korsgaard {
6317c4b5175SPeter Korsgaard USB_DEVICE(0x0a46, 0x1269), /* DM9621A USB to Fast Ethernet Adapter */
6327c4b5175SPeter Korsgaard .driver_info = (unsigned long)&dm9601_info,
6337c4b5175SPeter Korsgaard },
634a609d025SKamil Lorenc {
635a609d025SKamil Lorenc USB_DEVICE(0x0586, 0x3427), /* ZyXEL Keenetic Plus DSL xDSL modem */
636a609d025SKamil Lorenc .driver_info = (unsigned long)&dm9601_info,
637a609d025SKamil Lorenc },
6385b2fc499SJeff Garzik {}, // END
6395b2fc499SJeff Garzik };
6405b2fc499SJeff Garzik
6415b2fc499SJeff Garzik MODULE_DEVICE_TABLE(usb, products);
6425b2fc499SJeff Garzik
6435b2fc499SJeff Garzik static struct usb_driver dm9601_driver = {
6445b2fc499SJeff Garzik .name = "dm9601",
6455b2fc499SJeff Garzik .id_table = products,
6465b2fc499SJeff Garzik .probe = usbnet_probe,
6475b2fc499SJeff Garzik .disconnect = usbnet_disconnect,
6485b2fc499SJeff Garzik .suspend = usbnet_suspend,
6495b2fc499SJeff Garzik .resume = usbnet_resume,
650e1f12eb6SSarah Sharp .disable_hub_initiated_lpm = 1,
6515b2fc499SJeff Garzik };
6525b2fc499SJeff Garzik
653d632eb1bSGreg Kroah-Hartman module_usb_driver(dm9601_driver);
6545b2fc499SJeff Garzik
6555b2fc499SJeff Garzik MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
656cabd0e3aSPeter Korsgaard MODULE_DESCRIPTION("Davicom DM96xx USB 10/100 ethernet devices");
6575b2fc499SJeff Garzik MODULE_LICENSE("GPL");
658