Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices
0004  *
0005  * based on usbnet.c, asix.c and the vendor provided mcs7830 driver
0006  *
0007  * Copyright (C) 2010 Andreas Mohr <andi@lisas.de>
0008  * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
0009  * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
0010  * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
0011  * Copyright (c) 2002-2003 TiVo Inc.
0012  *
0013  * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!).
0014  *
0015  * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"),
0016  *             per active notification by manufacturer
0017  *
0018  * TODO:
0019  * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?)
0020  * - implement ethtool_ops get_pauseparam/set_pauseparam
0021  *   via HIF_REG_PAUSE_THRESHOLD (>= revision C only!)
0022  * - implement get_eeprom/[set_eeprom]
0023  * - switch PHY on/off on ifup/ifdown (perhaps in usbnet.c, via MII)
0024  * - mcs7830_get_regs() handling is weird: for rev 2 we return 32 regs,
0025  *   can access only ~ 24, remaining user buffer is uninitialized garbage
0026  * - anything else?
0027  */
0028 
0029 #include <linux/crc32.h>
0030 #include <linux/etherdevice.h>
0031 #include <linux/ethtool.h>
0032 #include <linux/mii.h>
0033 #include <linux/module.h>
0034 #include <linux/netdevice.h>
0035 #include <linux/slab.h>
0036 #include <linux/usb.h>
0037 #include <linux/usb/usbnet.h>
0038 
0039 /* requests */
0040 #define MCS7830_RD_BMREQ    (USB_DIR_IN  | USB_TYPE_VENDOR | \
0041                  USB_RECIP_DEVICE)
0042 #define MCS7830_WR_BMREQ    (USB_DIR_OUT | USB_TYPE_VENDOR | \
0043                  USB_RECIP_DEVICE)
0044 #define MCS7830_RD_BREQ     0x0E
0045 #define MCS7830_WR_BREQ     0x0D
0046 
0047 #define MCS7830_CTRL_TIMEOUT    1000
0048 #define MCS7830_MAX_MCAST   64
0049 
0050 #define MCS7830_VENDOR_ID   0x9710
0051 #define MCS7832_PRODUCT_ID  0x7832
0052 #define MCS7830_PRODUCT_ID  0x7830
0053 #define MCS7730_PRODUCT_ID  0x7730
0054 
0055 #define SITECOM_VENDOR_ID   0x0DF6
0056 #define LN_030_PRODUCT_ID   0x0021
0057 
0058 #define MCS7830_MII_ADVERTISE   (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
0059                  ADVERTISE_100HALF | ADVERTISE_10FULL | \
0060                  ADVERTISE_10HALF | ADVERTISE_CSMA)
0061 
0062 /* HIF_REG_XX corresponding index value */
0063 enum {
0064     HIF_REG_MULTICAST_HASH          = 0x00,
0065     HIF_REG_PACKET_GAP1         = 0x08,
0066     HIF_REG_PACKET_GAP2         = 0x09,
0067     HIF_REG_PHY_DATA            = 0x0a,
0068     HIF_REG_PHY_CMD1            = 0x0c,
0069        HIF_REG_PHY_CMD1_READ        = 0x40,
0070        HIF_REG_PHY_CMD1_WRITE       = 0x20,
0071        HIF_REG_PHY_CMD1_PHYADDR     = 0x01,
0072     HIF_REG_PHY_CMD2            = 0x0d,
0073        HIF_REG_PHY_CMD2_PEND_FLAG_BIT   = 0x80,
0074        HIF_REG_PHY_CMD2_READY_FLAG_BIT  = 0x40,
0075     HIF_REG_CONFIG              = 0x0e,
0076     /* hmm, spec sez: "R/W", "Except bit 3" (likely TXENABLE). */
0077        HIF_REG_CONFIG_CFG           = 0x80,
0078        HIF_REG_CONFIG_SPEED100      = 0x40,
0079        HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20,
0080        HIF_REG_CONFIG_RXENABLE      = 0x10,
0081        HIF_REG_CONFIG_TXENABLE      = 0x08,
0082        HIF_REG_CONFIG_SLEEPMODE     = 0x04,
0083        HIF_REG_CONFIG_ALLMULTICAST      = 0x02,
0084        HIF_REG_CONFIG_PROMISCUOUS       = 0x01,
0085     HIF_REG_ETHERNET_ADDR           = 0x0f,
0086     HIF_REG_FRAME_DROP_COUNTER      = 0x15, /* 0..ff; reset: 0 */
0087     HIF_REG_PAUSE_THRESHOLD         = 0x16,
0088        HIF_REG_PAUSE_THRESHOLD_DEFAULT  = 0,
0089 };
0090 
0091 /* Trailing status byte in Ethernet Rx frame */
0092 enum {
0093     MCS7830_RX_SHORT_FRAME      = 0x01, /* < 64 bytes */
0094     MCS7830_RX_LENGTH_ERROR     = 0x02, /* framelen != Ethernet length field */
0095     MCS7830_RX_ALIGNMENT_ERROR  = 0x04, /* non-even number of nibbles */
0096     MCS7830_RX_CRC_ERROR        = 0x08,
0097     MCS7830_RX_LARGE_FRAME      = 0x10, /* > 1518 bytes */
0098     MCS7830_RX_FRAME_CORRECT    = 0x20, /* frame is correct */
0099     /* [7:6] reserved */
0100 };
0101 
0102 struct mcs7830_data {
0103     u8 multi_filter[8];
0104     u8 config;
0105 };
0106 
0107 static const char driver_name[] = "MOSCHIP usb-ethernet driver";
0108 
0109 static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
0110 {
0111     int ret;
0112 
0113     ret = usbnet_read_cmd(dev, MCS7830_RD_BREQ, MCS7830_RD_BMREQ,
0114                   0x0000, index, data, size);
0115     if (ret < 0)
0116         return ret;
0117     else if (ret < size)
0118         return -ENODATA;
0119 
0120     return ret;
0121 }
0122 
0123 static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data)
0124 {
0125     return usbnet_write_cmd(dev, MCS7830_WR_BREQ, MCS7830_WR_BMREQ,
0126                 0x0000, index, data, size);
0127 }
0128 
0129 static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
0130 {
0131     usbnet_write_cmd_async(dev, MCS7830_WR_BREQ, MCS7830_WR_BMREQ,
0132                 0x0000, index, data, size);
0133 }
0134 
0135 static int mcs7830_hif_get_mac_address(struct usbnet *dev, unsigned char *addr)
0136 {
0137     int ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
0138     if (ret < 0)
0139         return ret;
0140     return 0;
0141 }
0142 
0143 static int mcs7830_hif_set_mac_address(struct usbnet *dev,
0144                        const unsigned char *addr)
0145 {
0146     int ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
0147 
0148     if (ret < 0)
0149         return ret;
0150     return 0;
0151 }
0152 
0153 static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
0154 {
0155     int ret;
0156     struct usbnet *dev = netdev_priv(netdev);
0157     struct sockaddr *addr = p;
0158 
0159     if (netif_running(netdev))
0160         return -EBUSY;
0161 
0162     if (!is_valid_ether_addr(addr->sa_data))
0163         return -EADDRNOTAVAIL;
0164 
0165     ret = mcs7830_hif_set_mac_address(dev, addr->sa_data);
0166 
0167     if (ret < 0)
0168         return ret;
0169 
0170     /* it worked --> adopt it on netdev side */
0171     eth_hw_addr_set(netdev, addr->sa_data);
0172 
0173     return 0;
0174 }
0175 
0176 static int mcs7830_read_phy(struct usbnet *dev, u8 index)
0177 {
0178     int ret;
0179     int i;
0180     __le16 val;
0181 
0182     u8 cmd[2] = {
0183         HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
0184         HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
0185     };
0186 
0187     mutex_lock(&dev->phy_mutex);
0188     /* write the MII command */
0189     ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
0190     if (ret < 0)
0191         goto out;
0192 
0193     /* wait for the data to become valid, should be within < 1ms */
0194     for (i = 0; i < 10; i++) {
0195         ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
0196         if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
0197             break;
0198         ret = -EIO;
0199         msleep(1);
0200     }
0201     if (ret < 0)
0202         goto out;
0203 
0204     /* read actual register contents */
0205     ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
0206     if (ret < 0)
0207         goto out;
0208     ret = le16_to_cpu(val);
0209     dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
0210         index, val, i);
0211 out:
0212     mutex_unlock(&dev->phy_mutex);
0213     return ret;
0214 }
0215 
0216 static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
0217 {
0218     int ret;
0219     int i;
0220     __le16 le_val;
0221 
0222     u8 cmd[2] = {
0223         HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
0224         HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
0225     };
0226 
0227     mutex_lock(&dev->phy_mutex);
0228 
0229     /* write the new register contents */
0230     le_val = cpu_to_le16(val);
0231     ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
0232     if (ret < 0)
0233         goto out;
0234 
0235     /* write the MII command */
0236     ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
0237     if (ret < 0)
0238         goto out;
0239 
0240     /* wait for the command to be accepted by the PHY */
0241     for (i = 0; i < 10; i++) {
0242         ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
0243         if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
0244             break;
0245         ret = -EIO;
0246         msleep(1);
0247     }
0248     if (ret < 0)
0249         goto out;
0250 
0251     ret = 0;
0252     dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
0253         index, val, i);
0254 out:
0255     mutex_unlock(&dev->phy_mutex);
0256     return ret;
0257 }
0258 
0259 /*
0260  * This algorithm comes from the original mcs7830 version 1.4 driver,
0261  * not sure if it is needed.
0262  */
0263 static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
0264 {
0265     int ret;
0266     /* Enable all media types */
0267     ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
0268 
0269     /* First reset BMCR */
0270     if (!ret)
0271         ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
0272     /* Enable Auto Neg */
0273     if (!ret)
0274         ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
0275     /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
0276     if (!ret)
0277         ret = mcs7830_write_phy(dev, MII_BMCR,
0278                 BMCR_ANENABLE | BMCR_ANRESTART  );
0279     return ret;
0280 }
0281 
0282 
0283 /*
0284  * if we can read register 22, the chip revision is C or higher
0285  */
0286 static int mcs7830_get_rev(struct usbnet *dev)
0287 {
0288     u8 dummy[2];
0289     int ret;
0290     ret = mcs7830_get_reg(dev, HIF_REG_FRAME_DROP_COUNTER, 2, dummy);
0291     if (ret > 0)
0292         return 2; /* Rev C or later */
0293     return 1; /* earlier revision */
0294 }
0295 
0296 /*
0297  * On rev. C we need to set the pause threshold
0298  */
0299 static void mcs7830_rev_C_fixup(struct usbnet *dev)
0300 {
0301     u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
0302     int retry;
0303 
0304     for (retry = 0; retry < 2; retry++) {
0305         if (mcs7830_get_rev(dev) == 2) {
0306             dev_info(&dev->udev->dev, "applying rev.C fixup\n");
0307             mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
0308                     1, &pause_threshold);
0309         }
0310         msleep(1);
0311     }
0312 }
0313 
0314 static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
0315                  int location)
0316 {
0317     struct usbnet *dev = netdev_priv(netdev);
0318     return mcs7830_read_phy(dev, location);
0319 }
0320 
0321 static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
0322                 int location, int val)
0323 {
0324     struct usbnet *dev = netdev_priv(netdev);
0325     mcs7830_write_phy(dev, location, val);
0326 }
0327 
0328 static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
0329 {
0330     struct usbnet *dev = netdev_priv(net);
0331     return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
0332 }
0333 
0334 static inline struct mcs7830_data *mcs7830_get_data(struct usbnet *dev)
0335 {
0336     return (struct mcs7830_data *)&dev->data;
0337 }
0338 
0339 static void mcs7830_hif_update_multicast_hash(struct usbnet *dev)
0340 {
0341     struct mcs7830_data *data = mcs7830_get_data(dev);
0342     mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
0343                 sizeof data->multi_filter,
0344                 data->multi_filter);
0345 }
0346 
0347 static void mcs7830_hif_update_config(struct usbnet *dev)
0348 {
0349     /* implementation specific to data->config
0350            (argument needs to be heap-based anyway - USB DMA!) */
0351     struct mcs7830_data *data = mcs7830_get_data(dev);
0352     mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
0353 }
0354 
0355 static void mcs7830_data_set_multicast(struct net_device *net)
0356 {
0357     struct usbnet *dev = netdev_priv(net);
0358     struct mcs7830_data *data = mcs7830_get_data(dev);
0359 
0360     memset(data->multi_filter, 0, sizeof data->multi_filter);
0361 
0362     data->config = HIF_REG_CONFIG_TXENABLE;
0363 
0364     /* this should not be needed, but it doesn't work otherwise */
0365     data->config |= HIF_REG_CONFIG_ALLMULTICAST;
0366 
0367     if (net->flags & IFF_PROMISC) {
0368         data->config |= HIF_REG_CONFIG_PROMISCUOUS;
0369     } else if (net->flags & IFF_ALLMULTI ||
0370            netdev_mc_count(net) > MCS7830_MAX_MCAST) {
0371         data->config |= HIF_REG_CONFIG_ALLMULTICAST;
0372     } else if (netdev_mc_empty(net)) {
0373         /* just broadcast and directed */
0374     } else {
0375         /* We use the 20 byte dev->data
0376          * for our 8 byte filter buffer
0377          * to avoid allocating memory that
0378          * is tricky to free later */
0379         struct netdev_hw_addr *ha;
0380         u32 crc_bits;
0381 
0382         /* Build the multicast hash filter. */
0383         netdev_for_each_mc_addr(ha, net) {
0384             crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
0385             data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
0386         }
0387     }
0388 }
0389 
0390 static int mcs7830_apply_base_config(struct usbnet *dev)
0391 {
0392     int ret;
0393 
0394     /* re-configure known MAC (suspend case etc.) */
0395     ret = mcs7830_hif_set_mac_address(dev, dev->net->dev_addr);
0396     if (ret) {
0397         dev_info(&dev->udev->dev, "Cannot set MAC address\n");
0398         goto out;
0399     }
0400 
0401     /* Set up PHY */
0402     ret = mcs7830_set_autoneg(dev, 0);
0403     if (ret) {
0404         dev_info(&dev->udev->dev, "Cannot set autoneg\n");
0405         goto out;
0406     }
0407 
0408     mcs7830_hif_update_multicast_hash(dev);
0409     mcs7830_hif_update_config(dev);
0410 
0411     mcs7830_rev_C_fixup(dev);
0412     ret = 0;
0413 out:
0414     return ret;
0415 }
0416 
0417 /* credits go to asix_set_multicast */
0418 static void mcs7830_set_multicast(struct net_device *net)
0419 {
0420     struct usbnet *dev = netdev_priv(net);
0421 
0422     mcs7830_data_set_multicast(net);
0423 
0424     mcs7830_hif_update_multicast_hash(dev);
0425     mcs7830_hif_update_config(dev);
0426 }
0427 
0428 static int mcs7830_get_regs_len(struct net_device *net)
0429 {
0430     struct usbnet *dev = netdev_priv(net);
0431 
0432     switch (mcs7830_get_rev(dev)) {
0433     case 1:
0434         return 21;
0435     case 2:
0436         return 32;
0437     }
0438     return 0;
0439 }
0440 
0441 static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
0442 {
0443     usbnet_get_drvinfo(net, drvinfo);
0444 }
0445 
0446 static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
0447 {
0448     struct usbnet *dev = netdev_priv(net);
0449 
0450     regs->version = mcs7830_get_rev(dev);
0451     mcs7830_get_reg(dev, 0, regs->len, data);
0452 }
0453 
0454 static const struct ethtool_ops mcs7830_ethtool_ops = {
0455     .get_drvinfo        = mcs7830_get_drvinfo,
0456     .get_regs_len       = mcs7830_get_regs_len,
0457     .get_regs       = mcs7830_get_regs,
0458 
0459     /* common usbnet calls */
0460     .get_link       = usbnet_get_link,
0461     .get_msglevel       = usbnet_get_msglevel,
0462     .set_msglevel       = usbnet_set_msglevel,
0463     .nway_reset     = usbnet_nway_reset,
0464     .get_link_ksettings = usbnet_get_link_ksettings_mii,
0465     .set_link_ksettings = usbnet_set_link_ksettings_mii,
0466 };
0467 
0468 static const struct net_device_ops mcs7830_netdev_ops = {
0469     .ndo_open       = usbnet_open,
0470     .ndo_stop       = usbnet_stop,
0471     .ndo_start_xmit     = usbnet_start_xmit,
0472     .ndo_tx_timeout     = usbnet_tx_timeout,
0473     .ndo_change_mtu     = usbnet_change_mtu,
0474     .ndo_get_stats64    = dev_get_tstats64,
0475     .ndo_validate_addr  = eth_validate_addr,
0476     .ndo_eth_ioctl      = mcs7830_ioctl,
0477     .ndo_set_rx_mode    = mcs7830_set_multicast,
0478     .ndo_set_mac_address    = mcs7830_set_mac_address,
0479 };
0480 
0481 static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
0482 {
0483     struct net_device *net = dev->net;
0484     u8 addr[ETH_ALEN];
0485     int ret;
0486     int retry;
0487 
0488     /* Initial startup: Gather MAC address setting from EEPROM */
0489     ret = -EINVAL;
0490     for (retry = 0; retry < 5 && ret; retry++)
0491         ret = mcs7830_hif_get_mac_address(dev, addr);
0492     if (ret) {
0493         dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
0494         goto out;
0495     }
0496     eth_hw_addr_set(net, addr);
0497 
0498     mcs7830_data_set_multicast(net);
0499 
0500     ret = mcs7830_apply_base_config(dev);
0501     if (ret)
0502         goto out;
0503 
0504     net->ethtool_ops = &mcs7830_ethtool_ops;
0505     net->netdev_ops = &mcs7830_netdev_ops;
0506 
0507     /* reserve space for the status byte on rx */
0508     dev->rx_urb_size = ETH_FRAME_LEN + 1;
0509 
0510     dev->mii.mdio_read = mcs7830_mdio_read;
0511     dev->mii.mdio_write = mcs7830_mdio_write;
0512     dev->mii.dev = net;
0513     dev->mii.phy_id_mask = 0x3f;
0514     dev->mii.reg_num_mask = 0x1f;
0515     dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
0516 
0517     ret = usbnet_get_endpoints(dev, udev);
0518 out:
0519     return ret;
0520 }
0521 
0522 /* The chip always appends a status byte that we need to strip */
0523 static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
0524 {
0525     u8 status;
0526 
0527     /* This check is no longer done by usbnet */
0528     if (skb->len < dev->net->hard_header_len) {
0529         dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
0530         return 0;
0531     }
0532 
0533     skb_trim(skb, skb->len - 1);
0534     status = skb->data[skb->len];
0535 
0536     if (status != MCS7830_RX_FRAME_CORRECT) {
0537         dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
0538 
0539         /* hmm, perhaps usbnet.c already sees a globally visible
0540            frame error and increments rx_errors on its own already? */
0541         dev->net->stats.rx_errors++;
0542 
0543         if (status &    (MCS7830_RX_SHORT_FRAME
0544                 |MCS7830_RX_LENGTH_ERROR
0545                 |MCS7830_RX_LARGE_FRAME))
0546             dev->net->stats.rx_length_errors++;
0547         if (status & MCS7830_RX_ALIGNMENT_ERROR)
0548             dev->net->stats.rx_frame_errors++;
0549         if (status & MCS7830_RX_CRC_ERROR)
0550             dev->net->stats.rx_crc_errors++;
0551     }
0552 
0553     return skb->len > 0;
0554 }
0555 
0556 static void mcs7830_status(struct usbnet *dev, struct urb *urb)
0557 {
0558     u8 *buf = urb->transfer_buffer;
0559     bool link, link_changed;
0560 
0561     if (urb->actual_length < 16)
0562         return;
0563 
0564     link = !(buf[1] == 0x20);
0565     link_changed = netif_carrier_ok(dev->net) != link;
0566     if (link_changed) {
0567         usbnet_link_change(dev, link, 0);
0568         netdev_dbg(dev->net, "Link Status is: %d\n", link);
0569     }
0570 }
0571 
0572 static const struct driver_info moschip_info = {
0573     .description    = "MOSCHIP 7830/7832/7730 usb-NET adapter",
0574     .bind       = mcs7830_bind,
0575     .rx_fixup   = mcs7830_rx_fixup,
0576     .flags      = FLAG_ETHER | FLAG_LINK_INTR,
0577     .status     = mcs7830_status,
0578     .in     = 1,
0579     .out        = 2,
0580 };
0581 
0582 static const struct driver_info sitecom_info = {
0583     .description    = "Sitecom LN-30 usb-NET adapter",
0584     .bind       = mcs7830_bind,
0585     .rx_fixup   = mcs7830_rx_fixup,
0586     .flags      = FLAG_ETHER | FLAG_LINK_INTR,
0587     .status     = mcs7830_status,
0588     .in     = 1,
0589     .out        = 2,
0590 };
0591 
0592 static const struct usb_device_id products[] = {
0593     {
0594         USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID),
0595         .driver_info = (unsigned long) &moschip_info,
0596     },
0597     {
0598         USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
0599         .driver_info = (unsigned long) &moschip_info,
0600     },
0601     {
0602         USB_DEVICE(MCS7830_VENDOR_ID, MCS7730_PRODUCT_ID),
0603         .driver_info = (unsigned long) &moschip_info,
0604     },
0605     {
0606         USB_DEVICE(SITECOM_VENDOR_ID, LN_030_PRODUCT_ID),
0607         .driver_info = (unsigned long) &sitecom_info,
0608     },
0609     {},
0610 };
0611 MODULE_DEVICE_TABLE(usb, products);
0612 
0613 static int mcs7830_reset_resume (struct usb_interface *intf)
0614 {
0615     /* YES, this function is successful enough that ethtool -d
0616            does show same output pre-/post-suspend */
0617 
0618     struct usbnet       *dev = usb_get_intfdata(intf);
0619 
0620     mcs7830_apply_base_config(dev);
0621 
0622     usbnet_resume(intf);
0623 
0624     return 0;
0625 }
0626 
0627 static struct usb_driver mcs7830_driver = {
0628     .name = driver_name,
0629     .id_table = products,
0630     .probe = usbnet_probe,
0631     .disconnect = usbnet_disconnect,
0632     .suspend = usbnet_suspend,
0633     .resume = usbnet_resume,
0634     .reset_resume = mcs7830_reset_resume,
0635     .disable_hub_initiated_lpm = 1,
0636 };
0637 
0638 module_usb_driver(mcs7830_driver);
0639 
0640 MODULE_DESCRIPTION("USB to network adapter MCS7830)");
0641 MODULE_LICENSE("GPL");