linux/drivers/net/usb/dm9601.c
<<
>>
Prefs
   1/*
   2 * Davicom DM96xx USB 10/100Mbps ethernet devices
   3 *
   4 * Peter Korsgaard <jacmet@sunsite.dk>
   5 *
   6 * This file is licensed under the terms of the GNU General Public License
   7 * version 2.  This program is licensed "as is" without any warranty of any
   8 * kind, whether express or implied.
   9 */
  10
  11//#define DEBUG
  12
  13#include <linux/module.h>
  14#include <linux/sched.h>
  15#include <linux/stddef.h>
  16#include <linux/netdevice.h>
  17#include <linux/etherdevice.h>
  18#include <linux/ethtool.h>
  19#include <linux/mii.h>
  20#include <linux/usb.h>
  21#include <linux/crc32.h>
  22#include <linux/usb/usbnet.h>
  23#include <linux/slab.h>
  24
  25/* datasheet:
  26 http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf
  27*/
  28
  29/* control requests */
  30#define DM_READ_REGS    0x00
  31#define DM_WRITE_REGS   0x01
  32#define DM_READ_MEMS    0x02
  33#define DM_WRITE_REG    0x03
  34#define DM_WRITE_MEMS   0x05
  35#define DM_WRITE_MEM    0x07
  36
  37/* registers */
  38#define DM_NET_CTRL     0x00
  39#define DM_RX_CTRL      0x05
  40#define DM_SHARED_CTRL  0x0b
  41#define DM_SHARED_ADDR  0x0c
  42#define DM_SHARED_DATA  0x0d    /* low + high */
  43#define DM_PHY_ADDR     0x10    /* 6 bytes */
  44#define DM_MCAST_ADDR   0x16    /* 8 bytes */
  45#define DM_GPR_CTRL     0x1e
  46#define DM_GPR_DATA     0x1f
  47#define DM_CHIP_ID      0x2c
  48#define DM_MODE_CTRL    0x91    /* only on dm9620 */
  49
  50/* chip id values */
  51#define ID_DM9601       0
  52#define ID_DM9620       1
  53
  54#define DM_MAX_MCAST    64
  55#define DM_MCAST_SIZE   8
  56#define DM_EEPROM_LEN   256
  57#define DM_TX_OVERHEAD  2       /* 2 byte header */
  58#define DM_RX_OVERHEAD  7       /* 3 byte header + 4 byte crc tail */
  59#define DM_TIMEOUT      1000
  60
  61static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
  62{
  63        int err;
  64        err = usbnet_read_cmd(dev, DM_READ_REGS,
  65                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  66                               0, reg, data, length);
  67        if(err != length && err >= 0)
  68                err = -EINVAL;
  69        return err;
  70}
  71
  72static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value)
  73{
  74        return dm_read(dev, reg, 1, value);
  75}
  76
  77static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
  78{
  79        int err;
  80        err = usbnet_write_cmd(dev, DM_WRITE_REGS,
  81                                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  82                                0, reg, data, length);
  83
  84        if (err >= 0 && err < length)
  85                err = -EINVAL;
  86        return err;
  87}
  88
  89static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
  90{
  91        return usbnet_write_cmd(dev, DM_WRITE_REG,
  92                                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  93                                value, reg, NULL, 0);
  94}
  95
  96static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
  97{
  98        usbnet_write_cmd_async(dev, DM_WRITE_REGS,
  99                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 100                               0, reg, data, length);
 101}
 102
 103static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
 104{
 105        usbnet_write_cmd_async(dev, DM_WRITE_REG,
 106                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 107                               value, reg, NULL, 0);
 108}
 109
 110static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
 111{
 112        int ret, i;
 113
 114        mutex_lock(&dev->phy_mutex);
 115
 116        dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
 117        dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
 118
 119        for (i = 0; i < DM_TIMEOUT; i++) {
 120                u8 tmp = 0;
 121
 122                udelay(1);
 123                ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
 124                if (ret < 0)
 125                        goto out;
 126
 127                /* ready */
 128                if ((tmp & 1) == 0)
 129                        break;
 130        }
 131
 132        if (i == DM_TIMEOUT) {
 133                netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
 134                ret = -EIO;
 135                goto out;
 136        }
 137
 138        dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
 139        ret = dm_read(dev, DM_SHARED_DATA, 2, value);
 140
 141        netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
 142                   phy, reg, *value, ret);
 143
 144 out:
 145        mutex_unlock(&dev->phy_mutex);
 146        return ret;
 147}
 148
 149static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
 150{
 151        int ret, i;
 152
 153        mutex_lock(&dev->phy_mutex);
 154
 155        ret = dm_write(dev, DM_SHARED_DATA, 2, &value);
 156        if (ret < 0)
 157                goto out;
 158
 159        dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
 160        dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);
 161
 162        for (i = 0; i < DM_TIMEOUT; i++) {
 163                u8 tmp = 0;
 164
 165                udelay(1);
 166                ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
 167                if (ret < 0)
 168                        goto out;
 169
 170                /* ready */
 171                if ((tmp & 1) == 0)
 172                        break;
 173        }
 174
 175        if (i == DM_TIMEOUT) {
 176                netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
 177                ret = -EIO;
 178                goto out;
 179        }
 180
 181        dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
 182
 183out:
 184        mutex_unlock(&dev->phy_mutex);
 185        return ret;
 186}
 187
 188static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
 189{
 190        return dm_read_shared_word(dev, 0, offset, value);
 191}
 192
 193
 194
 195static int dm9601_get_eeprom_len(struct net_device *dev)
 196{
 197        return DM_EEPROM_LEN;
 198}
 199
 200static int dm9601_get_eeprom(struct net_device *net,
 201                             struct ethtool_eeprom *eeprom, u8 * data)
 202{
 203        struct usbnet *dev = netdev_priv(net);
 204        __le16 *ebuf = (__le16 *) data;
 205        int i;
 206
 207        /* access is 16bit */
 208        if ((eeprom->offset % 2) || (eeprom->len % 2))
 209                return -EINVAL;
 210
 211        for (i = 0; i < eeprom->len / 2; i++) {
 212                if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,
 213                                        &ebuf[i]) < 0)
 214                        return -EINVAL;
 215        }
 216        return 0;
 217}
 218
 219static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
 220{
 221        struct usbnet *dev = netdev_priv(netdev);
 222
 223        __le16 res;
 224
 225        if (phy_id) {
 226                netdev_dbg(dev->net, "Only internal phy supported\n");
 227                return 0;
 228        }
 229
 230        dm_read_shared_word(dev, 1, loc, &res);
 231
 232        netdev_dbg(dev->net,
 233                   "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
 234                   phy_id, loc, le16_to_cpu(res));
 235
 236        return le16_to_cpu(res);
 237}
 238
 239static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
 240                              int val)
 241{
 242        struct usbnet *dev = netdev_priv(netdev);
 243        __le16 res = cpu_to_le16(val);
 244
 245        if (phy_id) {
 246                netdev_dbg(dev->net, "Only internal phy supported\n");
 247                return;
 248        }
 249
 250        netdev_dbg(dev->net, "dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
 251                   phy_id, loc, val);
 252
 253        dm_write_shared_word(dev, 1, loc, res);
 254}
 255
 256static void dm9601_get_drvinfo(struct net_device *net,
 257                               struct ethtool_drvinfo *info)
 258{
 259        /* Inherit standard device info */
 260        usbnet_get_drvinfo(net, info);
 261}
 262
 263static u32 dm9601_get_link(struct net_device *net)
 264{
 265        struct usbnet *dev = netdev_priv(net);
 266
 267        return mii_link_ok(&dev->mii);
 268}
 269
 270static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 271{
 272        struct usbnet *dev = netdev_priv(net);
 273
 274        return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
 275}
 276
 277static const struct ethtool_ops dm9601_ethtool_ops = {
 278        .get_drvinfo    = dm9601_get_drvinfo,
 279        .get_link       = dm9601_get_link,
 280        .get_msglevel   = usbnet_get_msglevel,
 281        .set_msglevel   = usbnet_set_msglevel,
 282        .get_eeprom_len = dm9601_get_eeprom_len,
 283        .get_eeprom     = dm9601_get_eeprom,
 284        .nway_reset     = usbnet_nway_reset,
 285        .get_link_ksettings     = usbnet_get_link_ksettings,
 286        .set_link_ksettings     = usbnet_set_link_ksettings,
 287};
 288
 289static void dm9601_set_multicast(struct net_device *net)
 290{
 291        struct usbnet *dev = netdev_priv(net);
 292        /* We use the 20 byte dev->data for our 8 byte filter buffer
 293         * to avoid allocating memory that is tricky to free later */
 294        u8 *hashes = (u8 *) & dev->data;
 295        u8 rx_ctl = 0x31;
 296
 297        memset(hashes, 0x00, DM_MCAST_SIZE);
 298        hashes[DM_MCAST_SIZE - 1] |= 0x80;      /* broadcast address */
 299
 300        if (net->flags & IFF_PROMISC) {
 301                rx_ctl |= 0x02;
 302        } else if (net->flags & IFF_ALLMULTI ||
 303                   netdev_mc_count(net) > DM_MAX_MCAST) {
 304                rx_ctl |= 0x08;
 305        } else if (!netdev_mc_empty(net)) {
 306                struct netdev_hw_addr *ha;
 307
 308                netdev_for_each_mc_addr(ha, net) {
 309                        u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
 310                        hashes[crc >> 3] |= 1 << (crc & 0x7);
 311                }
 312        }
 313
 314        dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);
 315        dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
 316}
 317
 318static void __dm9601_set_mac_address(struct usbnet *dev)
 319{
 320        dm_write_async(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
 321}
 322
 323static int dm9601_set_mac_address(struct net_device *net, void *p)
 324{
 325        struct sockaddr *addr = p;
 326        struct usbnet *dev = netdev_priv(net);
 327
 328        if (!is_valid_ether_addr(addr->sa_data)) {
 329                dev_err(&net->dev, "not setting invalid mac address %pM\n",
 330                                                                addr->sa_data);
 331                return -EINVAL;
 332        }
 333
 334        memcpy(net->dev_addr, addr->sa_data, net->addr_len);
 335        __dm9601_set_mac_address(dev);
 336
 337        return 0;
 338}
 339
 340static const struct net_device_ops dm9601_netdev_ops = {
 341        .ndo_open               = usbnet_open,
 342        .ndo_stop               = usbnet_stop,
 343        .ndo_start_xmit         = usbnet_start_xmit,
 344        .ndo_tx_timeout         = usbnet_tx_timeout,
 345        .ndo_change_mtu         = usbnet_change_mtu,
 346        .ndo_get_stats64        = usbnet_get_stats64,
 347        .ndo_validate_addr      = eth_validate_addr,
 348        .ndo_do_ioctl           = dm9601_ioctl,
 349        .ndo_set_rx_mode        = dm9601_set_multicast,
 350        .ndo_set_mac_address    = dm9601_set_mac_address,
 351};
 352
 353static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
 354{
 355        int ret;
 356        u8 mac[ETH_ALEN], id;
 357
 358        ret = usbnet_get_endpoints(dev, intf);
 359        if (ret)
 360                goto out;
 361
 362        dev->net->netdev_ops = &dm9601_netdev_ops;
 363        dev->net->ethtool_ops = &dm9601_ethtool_ops;
 364        dev->net->hard_header_len += DM_TX_OVERHEAD;
 365        dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
 366
 367        /* dm9620/21a require room for 4 byte padding, even in dm9601
 368         * mode, so we need +1 to be able to receive full size
 369         * ethernet frames.
 370         */
 371        dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1;
 372
 373        dev->mii.dev = dev->net;
 374        dev->mii.mdio_read = dm9601_mdio_read;
 375        dev->mii.mdio_write = dm9601_mdio_write;
 376        dev->mii.phy_id_mask = 0x1f;
 377        dev->mii.reg_num_mask = 0x1f;
 378
 379        /* reset */
 380        dm_write_reg(dev, DM_NET_CTRL, 1);
 381        udelay(20);
 382
 383        /* read MAC */
 384        if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, mac) < 0) {
 385                printk(KERN_ERR "Error reading MAC address\n");
 386                ret = -ENODEV;
 387                goto out;
 388        }
 389
 390        /*
 391         * Overwrite the auto-generated address only with good ones.
 392         */
 393        if (is_valid_ether_addr(mac))
 394                memcpy(dev->net->dev_addr, mac, ETH_ALEN);
 395        else {
 396                printk(KERN_WARNING
 397                        "dm9601: No valid MAC address in EEPROM, using %pM\n",
 398                        dev->net->dev_addr);
 399                __dm9601_set_mac_address(dev);
 400        }
 401
 402        if (dm_read_reg(dev, DM_CHIP_ID, &id) < 0) {
 403                netdev_err(dev->net, "Error reading chip ID\n");
 404                ret = -ENODEV;
 405                goto out;
 406        }
 407
 408        /* put dm9620 devices in dm9601 mode */
 409        if (id == ID_DM9620) {
 410                u8 mode;
 411
 412                if (dm_read_reg(dev, DM_MODE_CTRL, &mode) < 0) {
 413                        netdev_err(dev->net, "Error reading MODE_CTRL\n");
 414                        ret = -ENODEV;
 415                        goto out;
 416                }
 417                dm_write_reg(dev, DM_MODE_CTRL, mode & 0x7f);
 418        }
 419
 420        /* power up phy */
 421        dm_write_reg(dev, DM_GPR_CTRL, 1);
 422        dm_write_reg(dev, DM_GPR_DATA, 0);
 423
 424        /* receive broadcast packets */
 425        dm9601_set_multicast(dev->net);
 426
 427        dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
 428        dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
 429                          ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
 430        mii_nway_restart(&dev->mii);
 431
 432out:
 433        return ret;
 434}
 435
 436static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 437{
 438        u8 status;
 439        int len;
 440
 441        /* format:
 442           b1: rx status
 443           b2: packet length (incl crc) low
 444           b3: packet length (incl crc) high
 445           b4..n-4: packet data
 446           bn-3..bn: ethernet crc
 447         */
 448
 449        if (unlikely(skb->len < DM_RX_OVERHEAD)) {
 450                dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
 451                return 0;
 452        }
 453
 454        status = skb->data[0];
 455        len = (skb->data[1] | (skb->data[2] << 8)) - 4;
 456
 457        if (unlikely(status & 0xbf)) {
 458                if (status & 0x01) dev->net->stats.rx_fifo_errors++;
 459                if (status & 0x02) dev->net->stats.rx_crc_errors++;
 460                if (status & 0x04) dev->net->stats.rx_frame_errors++;
 461                if (status & 0x20) dev->net->stats.rx_missed_errors++;
 462                if (status & 0x90) dev->net->stats.rx_length_errors++;
 463                return 0;
 464        }
 465
 466        skb_pull(skb, 3);
 467        skb_trim(skb, len);
 468
 469        return 1;
 470}
 471
 472static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 473                                       gfp_t flags)
 474{
 475        int len, pad;
 476
 477        /* format:
 478           b1: packet length low
 479           b2: packet length high
 480           b3..n: packet data
 481        */
 482
 483        len = skb->len + DM_TX_OVERHEAD;
 484
 485        /* workaround for dm962x errata with tx fifo getting out of
 486         * sync if a USB bulk transfer retry happens right after a
 487         * packet with odd / maxpacket length by adding up to 3 bytes
 488         * padding.
 489         */
 490        while ((len & 1) || !(len % dev->maxpacket))
 491                len++;
 492
 493        len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */
 494        pad = len - skb->len;
 495
 496        if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) {
 497                struct sk_buff *skb2;
 498
 499                skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags);
 500                dev_kfree_skb_any(skb);
 501                skb = skb2;
 502                if (!skb)
 503                        return NULL;
 504        }
 505
 506        __skb_push(skb, DM_TX_OVERHEAD);
 507
 508        if (pad) {
 509                memset(skb->data + skb->len, 0, pad);
 510                __skb_put(skb, pad);
 511        }
 512
 513        skb->data[0] = len;
 514        skb->data[1] = len >> 8;
 515
 516        return skb;
 517}
 518
 519static void dm9601_status(struct usbnet *dev, struct urb *urb)
 520{
 521        int link;
 522        u8 *buf;
 523
 524        /* format:
 525           b0: net status
 526           b1: tx status 1
 527           b2: tx status 2
 528           b3: rx status
 529           b4: rx overflow
 530           b5: rx count
 531           b6: tx count
 532           b7: gpr
 533        */
 534
 535        if (urb->actual_length < 8)
 536                return;
 537
 538        buf = urb->transfer_buffer;
 539
 540        link = !!(buf[0] & 0x40);
 541        if (netif_carrier_ok(dev->net) != link) {
 542                usbnet_link_change(dev, link, 1);
 543                netdev_dbg(dev->net, "Link Status is: %d\n", link);
 544        }
 545}
 546
 547static int dm9601_link_reset(struct usbnet *dev)
 548{
 549        struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
 550
 551        mii_check_media(&dev->mii, 1, 1);
 552        mii_ethtool_gset(&dev->mii, &ecmd);
 553
 554        netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
 555                   ethtool_cmd_speed(&ecmd), ecmd.duplex);
 556
 557        return 0;
 558}
 559
 560static const struct driver_info dm9601_info = {
 561        .description    = "Davicom DM96xx USB 10/100 Ethernet",
 562        .flags          = FLAG_ETHER | FLAG_LINK_INTR,
 563        .bind           = dm9601_bind,
 564        .rx_fixup       = dm9601_rx_fixup,
 565        .tx_fixup       = dm9601_tx_fixup,
 566        .status         = dm9601_status,
 567        .link_reset     = dm9601_link_reset,
 568        .reset          = dm9601_link_reset,
 569};
 570
 571static const struct usb_device_id products[] = {
 572        {
 573         USB_DEVICE(0x07aa, 0x9601),    /* Corega FEther USB-TXC */
 574         .driver_info = (unsigned long)&dm9601_info,
 575         },
 576        {
 577         USB_DEVICE(0x0a46, 0x9601),    /* Davicom USB-100 */
 578         .driver_info = (unsigned long)&dm9601_info,
 579         },
 580        {
 581         USB_DEVICE(0x0a46, 0x6688),    /* ZT6688 USB NIC */
 582         .driver_info = (unsigned long)&dm9601_info,
 583         },
 584        {
 585         USB_DEVICE(0x0a46, 0x0268),    /* ShanTou ST268 USB NIC */
 586         .driver_info = (unsigned long)&dm9601_info,
 587         },
 588        {
 589         USB_DEVICE(0x0a46, 0x8515),    /* ADMtek ADM8515 USB NIC */
 590         .driver_info = (unsigned long)&dm9601_info,
 591         },
 592        {
 593        USB_DEVICE(0x0a47, 0x9601),     /* Hirose USB-100 */
 594        .driver_info = (unsigned long)&dm9601_info,
 595         },
 596        {
 597        USB_DEVICE(0x0fe6, 0x8101),     /* DM9601 USB to Fast Ethernet Adapter */
 598        .driver_info = (unsigned long)&dm9601_info,
 599         },
 600        {
 601         USB_DEVICE(0x0fe6, 0x9700),    /* DM9601 USB to Fast Ethernet Adapter */
 602         .driver_info = (unsigned long)&dm9601_info,
 603         },
 604        {
 605         USB_DEVICE(0x0a46, 0x9000),    /* DM9000E */
 606         .driver_info = (unsigned long)&dm9601_info,
 607         },
 608        {
 609         USB_DEVICE(0x0a46, 0x9620),    /* DM9620 USB to Fast Ethernet Adapter */
 610         .driver_info = (unsigned long)&dm9601_info,
 611         },
 612        {
 613         USB_DEVICE(0x0a46, 0x9621),    /* DM9621A USB to Fast Ethernet Adapter */
 614         .driver_info = (unsigned long)&dm9601_info,
 615        },
 616        {
 617         USB_DEVICE(0x0a46, 0x9622),    /* DM9622 USB to Fast Ethernet Adapter */
 618         .driver_info = (unsigned long)&dm9601_info,
 619        },
 620        {
 621         USB_DEVICE(0x0a46, 0x0269),    /* DM962OA USB to Fast Ethernet Adapter */
 622         .driver_info = (unsigned long)&dm9601_info,
 623        },
 624        {
 625         USB_DEVICE(0x0a46, 0x1269),    /* DM9621A USB to Fast Ethernet Adapter */
 626         .driver_info = (unsigned long)&dm9601_info,
 627        },
 628        {
 629         USB_DEVICE(0x0586, 0x3427),    /* ZyXEL Keenetic Plus DSL xDSL modem */
 630         .driver_info = (unsigned long)&dm9601_info,
 631        },
 632        {},                     // END
 633};
 634
 635MODULE_DEVICE_TABLE(usb, products);
 636
 637static struct usb_driver dm9601_driver = {
 638        .name = "dm9601",
 639        .id_table = products,
 640        .probe = usbnet_probe,
 641        .disconnect = usbnet_disconnect,
 642        .suspend = usbnet_suspend,
 643        .resume = usbnet_resume,
 644        .disable_hub_initiated_lpm = 1,
 645};
 646
 647module_usb_driver(dm9601_driver);
 648
 649MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
 650MODULE_DESCRIPTION("Davicom DM96xx USB 10/100 ethernet devices");
 651MODULE_LICENSE("GPL");
 652