linux/drivers/net/usb/mcs7830.c
<<
>>
Prefs
   1/*
   2 * MosChips MCS7830 based USB 2.0 Ethernet Devices
   3 *
   4 * based on usbnet.c, asix.c and the vendor provided mcs7830 driver
   5 *
   6 * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
   7 * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
   8 * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
   9 * Copyright (c) 2002-2003 TiVo Inc.
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  24 */
  25
  26#include <linux/crc32.h>
  27#include <linux/etherdevice.h>
  28#include <linux/ethtool.h>
  29#include <linux/init.h>
  30#include <linux/mii.h>
  31#include <linux/module.h>
  32#include <linux/netdevice.h>
  33#include <linux/usb.h>
  34#include <linux/usb/usbnet.h>
  35
  36/* requests */
  37#define MCS7830_RD_BMREQ        (USB_DIR_IN  | USB_TYPE_VENDOR | \
  38                                 USB_RECIP_DEVICE)
  39#define MCS7830_WR_BMREQ        (USB_DIR_OUT | USB_TYPE_VENDOR | \
  40                                 USB_RECIP_DEVICE)
  41#define MCS7830_RD_BREQ         0x0E
  42#define MCS7830_WR_BREQ         0x0D
  43
  44#define MCS7830_CTRL_TIMEOUT    1000
  45#define MCS7830_MAX_MCAST       64
  46
  47#define MCS7830_VENDOR_ID       0x9710
  48#define MCS7830_PRODUCT_ID      0x7830
  49#define MCS7730_PRODUCT_ID      0x7730
  50
  51#define SITECOM_VENDOR_ID       0x0DF6
  52#define LN_030_PRODUCT_ID       0x0021
  53
  54#define MCS7830_MII_ADVERTISE   (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
  55                                 ADVERTISE_100HALF | ADVERTISE_10FULL | \
  56                                 ADVERTISE_10HALF | ADVERTISE_CSMA)
  57
  58/* HIF_REG_XX coressponding index value */
  59enum {
  60        HIF_REG_MULTICAST_HASH                  = 0x00,
  61        HIF_REG_PACKET_GAP1                     = 0x08,
  62        HIF_REG_PACKET_GAP2                     = 0x09,
  63        HIF_REG_PHY_DATA                        = 0x0a,
  64        HIF_REG_PHY_CMD1                        = 0x0c,
  65           HIF_REG_PHY_CMD1_READ                = 0x40,
  66           HIF_REG_PHY_CMD1_WRITE               = 0x20,
  67           HIF_REG_PHY_CMD1_PHYADDR             = 0x01,
  68        HIF_REG_PHY_CMD2                        = 0x0d,
  69           HIF_REG_PHY_CMD2_PEND_FLAG_BIT       = 0x80,
  70           HIF_REG_PHY_CMD2_READY_FLAG_BIT      = 0x40,
  71        HIF_REG_CONFIG                          = 0x0e,
  72           HIF_REG_CONFIG_CFG                   = 0x80,
  73           HIF_REG_CONFIG_SPEED100              = 0x40,
  74           HIF_REG_CONFIG_FULLDUPLEX_ENABLE     = 0x20,
  75           HIF_REG_CONFIG_RXENABLE              = 0x10,
  76           HIF_REG_CONFIG_TXENABLE              = 0x08,
  77           HIF_REG_CONFIG_SLEEPMODE             = 0x04,
  78           HIF_REG_CONFIG_ALLMULTICAST          = 0x02,
  79           HIF_REG_CONFIG_PROMISCIOUS           = 0x01,
  80        HIF_REG_ETHERNET_ADDR                   = 0x0f,
  81        HIF_REG_22                              = 0x15,
  82        HIF_REG_PAUSE_THRESHOLD                 = 0x16,
  83           HIF_REG_PAUSE_THRESHOLD_DEFAULT      = 0,
  84};
  85
  86struct mcs7830_data {
  87        u8 multi_filter[8];
  88        u8 config;
  89};
  90
  91static const char driver_name[] = "MOSCHIP usb-ethernet driver";
  92
  93static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
  94{
  95        struct usb_device *xdev = dev->udev;
  96        int ret;
  97        void *buffer;
  98
  99        buffer = kmalloc(size, GFP_NOIO);
 100        if (buffer == NULL)
 101                return -ENOMEM;
 102
 103        ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
 104                              MCS7830_RD_BMREQ, 0x0000, index, buffer,
 105                              size, MCS7830_CTRL_TIMEOUT);
 106        memcpy(data, buffer, size);
 107        kfree(buffer);
 108
 109        return ret;
 110}
 111
 112static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
 113{
 114        struct usb_device *xdev = dev->udev;
 115        int ret;
 116        void *buffer;
 117
 118        buffer = kmalloc(size, GFP_NOIO);
 119        if (buffer == NULL)
 120                return -ENOMEM;
 121
 122        memcpy(buffer, data, size);
 123
 124        ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
 125                              MCS7830_WR_BMREQ, 0x0000, index, buffer,
 126                              size, MCS7830_CTRL_TIMEOUT);
 127        kfree(buffer);
 128        return ret;
 129}
 130
 131static void mcs7830_async_cmd_callback(struct urb *urb)
 132{
 133        struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
 134        int status = urb->status;
 135
 136        if (status < 0)
 137                printk(KERN_DEBUG "%s() failed with %d\n",
 138                       __func__, status);
 139
 140        kfree(req);
 141        usb_free_urb(urb);
 142}
 143
 144static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
 145{
 146        struct usb_ctrlrequest *req;
 147        int ret;
 148        struct urb *urb;
 149
 150        urb = usb_alloc_urb(0, GFP_ATOMIC);
 151        if (!urb) {
 152                dev_dbg(&dev->udev->dev,
 153                        "Error allocating URB in write_cmd_async!\n");
 154                return;
 155        }
 156
 157        req = kmalloc(sizeof *req, GFP_ATOMIC);
 158        if (!req) {
 159                dev_err(&dev->udev->dev,
 160                        "Failed to allocate memory for control request\n");
 161                goto out;
 162        }
 163        req->bRequestType = MCS7830_WR_BMREQ;
 164        req->bRequest = MCS7830_WR_BREQ;
 165        req->wValue = 0;
 166        req->wIndex = cpu_to_le16(index);
 167        req->wLength = cpu_to_le16(size);
 168
 169        usb_fill_control_urb(urb, dev->udev,
 170                             usb_sndctrlpipe(dev->udev, 0),
 171                             (void *)req, data, size,
 172                             mcs7830_async_cmd_callback, req);
 173
 174        ret = usb_submit_urb(urb, GFP_ATOMIC);
 175        if (ret < 0) {
 176                dev_err(&dev->udev->dev,
 177                        "Error submitting the control message: ret=%d\n", ret);
 178                goto out;
 179        }
 180        return;
 181out:
 182        kfree(req);
 183        usb_free_urb(urb);
 184}
 185
 186static int mcs7830_get_address(struct usbnet *dev)
 187{
 188        int ret;
 189        ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
 190                                   dev->net->dev_addr);
 191        if (ret < 0)
 192                return ret;
 193        return 0;
 194}
 195
 196static int mcs7830_read_phy(struct usbnet *dev, u8 index)
 197{
 198        int ret;
 199        int i;
 200        __le16 val;
 201
 202        u8 cmd[2] = {
 203                HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
 204                HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
 205        };
 206
 207        mutex_lock(&dev->phy_mutex);
 208        /* write the MII command */
 209        ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
 210        if (ret < 0)
 211                goto out;
 212
 213        /* wait for the data to become valid, should be within < 1ms */
 214        for (i = 0; i < 10; i++) {
 215                ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
 216                if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
 217                        break;
 218                ret = -EIO;
 219                msleep(1);
 220        }
 221        if (ret < 0)
 222                goto out;
 223
 224        /* read actual register contents */
 225        ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
 226        if (ret < 0)
 227                goto out;
 228        ret = le16_to_cpu(val);
 229        dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
 230                index, val, i);
 231out:
 232        mutex_unlock(&dev->phy_mutex);
 233        return ret;
 234}
 235
 236static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
 237{
 238        int ret;
 239        int i;
 240        __le16 le_val;
 241
 242        u8 cmd[2] = {
 243                HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
 244                HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
 245        };
 246
 247        mutex_lock(&dev->phy_mutex);
 248
 249        /* write the new register contents */
 250        le_val = cpu_to_le16(val);
 251        ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
 252        if (ret < 0)
 253                goto out;
 254
 255        /* write the MII command */
 256        ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
 257        if (ret < 0)
 258                goto out;
 259
 260        /* wait for the command to be accepted by the PHY */
 261        for (i = 0; i < 10; i++) {
 262                ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
 263                if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
 264                        break;
 265                ret = -EIO;
 266                msleep(1);
 267        }
 268        if (ret < 0)
 269                goto out;
 270
 271        ret = 0;
 272        dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
 273                index, val, i);
 274out:
 275        mutex_unlock(&dev->phy_mutex);
 276        return ret;
 277}
 278
 279/*
 280 * This algorithm comes from the original mcs7830 version 1.4 driver,
 281 * not sure if it is needed.
 282 */
 283static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
 284{
 285        int ret;
 286        /* Enable all media types */
 287        ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
 288
 289        /* First reset BMCR */
 290        if (!ret)
 291                ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
 292        /* Enable Auto Neg */
 293        if (!ret)
 294                ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
 295        /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
 296        if (!ret)
 297                ret = mcs7830_write_phy(dev, MII_BMCR,
 298                                BMCR_ANENABLE | BMCR_ANRESTART  );
 299        return ret < 0 ? : 0;
 300}
 301
 302
 303/*
 304 * if we can read register 22, the chip revision is C or higher
 305 */
 306static int mcs7830_get_rev(struct usbnet *dev)
 307{
 308        u8 dummy[2];
 309        int ret;
 310        ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
 311        if (ret > 0)
 312                return 2; /* Rev C or later */
 313        return 1; /* earlier revision */
 314}
 315
 316/*
 317 * On rev. C we need to set the pause threshold
 318 */
 319static void mcs7830_rev_C_fixup(struct usbnet *dev)
 320{
 321        u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
 322        int retry;
 323
 324        for (retry = 0; retry < 2; retry++) {
 325                if (mcs7830_get_rev(dev) == 2) {
 326                        dev_info(&dev->udev->dev, "applying rev.C fixup\n");
 327                        mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
 328                                        1, &pause_threshold);
 329                }
 330                msleep(1);
 331        }
 332}
 333
 334static int mcs7830_init_dev(struct usbnet *dev)
 335{
 336        int ret;
 337        int retry;
 338
 339        /* Read MAC address from EEPROM */
 340        ret = -EINVAL;
 341        for (retry = 0; retry < 5 && ret; retry++)
 342                ret = mcs7830_get_address(dev);
 343        if (ret) {
 344                dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
 345                goto out;
 346        }
 347
 348        /* Set up PHY */
 349        ret = mcs7830_set_autoneg(dev, 0);
 350        if (ret) {
 351                dev_info(&dev->udev->dev, "Cannot set autoneg\n");
 352                goto out;
 353        }
 354
 355        mcs7830_rev_C_fixup(dev);
 356        ret = 0;
 357out:
 358        return ret;
 359}
 360
 361static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
 362                             int location)
 363{
 364        struct usbnet *dev = netdev_priv(netdev);
 365        return mcs7830_read_phy(dev, location);
 366}
 367
 368static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
 369                                int location, int val)
 370{
 371        struct usbnet *dev = netdev_priv(netdev);
 372        mcs7830_write_phy(dev, location, val);
 373}
 374
 375static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 376{
 377        struct usbnet *dev = netdev_priv(net);
 378        return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
 379}
 380
 381/* credits go to asix_set_multicast */
 382static void mcs7830_set_multicast(struct net_device *net)
 383{
 384        struct usbnet *dev = netdev_priv(net);
 385        struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
 386
 387        data->config = HIF_REG_CONFIG_TXENABLE;
 388
 389        /* this should not be needed, but it doesn't work otherwise */
 390        data->config |= HIF_REG_CONFIG_ALLMULTICAST;
 391
 392        if (net->flags & IFF_PROMISC) {
 393                data->config |= HIF_REG_CONFIG_PROMISCIOUS;
 394        } else if (net->flags & IFF_ALLMULTI
 395                   || net->mc_count > MCS7830_MAX_MCAST) {
 396                data->config |= HIF_REG_CONFIG_ALLMULTICAST;
 397        } else if (net->mc_count == 0) {
 398                /* just broadcast and directed */
 399        } else {
 400                /* We use the 20 byte dev->data
 401                 * for our 8 byte filter buffer
 402                 * to avoid allocating memory that
 403                 * is tricky to free later */
 404                struct dev_mc_list *mc_list = net->mc_list;
 405                u32 crc_bits;
 406                int i;
 407
 408                memset(data->multi_filter, 0, sizeof data->multi_filter);
 409
 410                /* Build the multicast hash filter. */
 411                for (i = 0; i < net->mc_count; i++) {
 412                        crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
 413                        data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
 414                        mc_list = mc_list->next;
 415                }
 416
 417                mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
 418                                sizeof data->multi_filter,
 419                                data->multi_filter);
 420        }
 421
 422        mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
 423}
 424
 425static int mcs7830_get_regs_len(struct net_device *net)
 426{
 427        struct usbnet *dev = netdev_priv(net);
 428
 429        switch (mcs7830_get_rev(dev)) {
 430        case 1:
 431                return 21;
 432        case 2:
 433                return 32;
 434        }
 435        return 0;
 436}
 437
 438static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
 439{
 440        usbnet_get_drvinfo(net, drvinfo);
 441        drvinfo->regdump_len = mcs7830_get_regs_len(net);
 442}
 443
 444static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
 445{
 446        struct usbnet *dev = netdev_priv(net);
 447
 448        regs->version = mcs7830_get_rev(dev);
 449        mcs7830_get_reg(dev, 0, regs->len, data);
 450}
 451
 452static const struct ethtool_ops mcs7830_ethtool_ops = {
 453        .get_drvinfo            = mcs7830_get_drvinfo,
 454        .get_regs_len           = mcs7830_get_regs_len,
 455        .get_regs               = mcs7830_get_regs,
 456
 457        /* common usbnet calls */
 458        .get_link               = usbnet_get_link,
 459        .get_msglevel           = usbnet_get_msglevel,
 460        .set_msglevel           = usbnet_set_msglevel,
 461        .get_settings           = usbnet_get_settings,
 462        .set_settings           = usbnet_set_settings,
 463        .nway_reset             = usbnet_nway_reset,
 464};
 465
 466static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
 467{
 468        int ret;
 469        struct usbnet *dev = netdev_priv(netdev);
 470        struct sockaddr *addr = p;
 471
 472        if (netif_running(netdev))
 473                return -EBUSY;
 474
 475        if (!is_valid_ether_addr(addr->sa_data))
 476                return -EINVAL;
 477
 478        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 479
 480        ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
 481                        netdev->dev_addr);
 482
 483        if (ret < 0)
 484                return ret;
 485
 486        return 0;
 487}
 488
 489static const struct net_device_ops mcs7830_netdev_ops = {
 490        .ndo_open               = usbnet_open,
 491        .ndo_stop               = usbnet_stop,
 492        .ndo_start_xmit         = usbnet_start_xmit,
 493        .ndo_tx_timeout         = usbnet_tx_timeout,
 494        .ndo_change_mtu         = usbnet_change_mtu,
 495        .ndo_validate_addr      = eth_validate_addr,
 496        .ndo_do_ioctl           = mcs7830_ioctl,
 497        .ndo_set_multicast_list = mcs7830_set_multicast,
 498        .ndo_set_mac_address     = mcs7830_set_mac_address,
 499};
 500
 501static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
 502{
 503        struct net_device *net = dev->net;
 504        int ret;
 505
 506        ret = mcs7830_init_dev(dev);
 507        if (ret)
 508                goto out;
 509
 510        net->ethtool_ops = &mcs7830_ethtool_ops;
 511        net->netdev_ops = &mcs7830_netdev_ops;
 512        mcs7830_set_multicast(net);
 513
 514        /* reserve space for the status byte on rx */
 515        dev->rx_urb_size = ETH_FRAME_LEN + 1;
 516
 517        dev->mii.mdio_read = mcs7830_mdio_read;
 518        dev->mii.mdio_write = mcs7830_mdio_write;
 519        dev->mii.dev = net;
 520        dev->mii.phy_id_mask = 0x3f;
 521        dev->mii.reg_num_mask = 0x1f;
 522        dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
 523
 524        ret = usbnet_get_endpoints(dev, udev);
 525out:
 526        return ret;
 527}
 528
 529/* The chip always appends a status bytes that we need to strip */
 530static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 531{
 532        u8 status;
 533
 534        if (skb->len == 0) {
 535                dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
 536                return 0;
 537        }
 538
 539        skb_trim(skb, skb->len - 1);
 540        status = skb->data[skb->len];
 541
 542        if (status != 0x20)
 543                dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
 544
 545        return skb->len > 0;
 546}
 547
 548static const struct driver_info moschip_info = {
 549        .description    = "MOSCHIP 7830/7730 usb-NET adapter",
 550        .bind           = mcs7830_bind,
 551        .rx_fixup       = mcs7830_rx_fixup,
 552        .flags          = FLAG_ETHER,
 553        .in             = 1,
 554        .out            = 2,
 555};
 556
 557static const struct driver_info sitecom_info = {
 558        .description    = "Sitecom LN-30 usb-NET adapter",
 559        .bind           = mcs7830_bind,
 560        .rx_fixup       = mcs7830_rx_fixup,
 561        .flags          = FLAG_ETHER,
 562        .in             = 1,
 563        .out            = 2,
 564};
 565
 566static const struct usb_device_id products[] = {
 567        {
 568                USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
 569                .driver_info = (unsigned long) &moschip_info,
 570        },
 571        {
 572                USB_DEVICE(MCS7830_VENDOR_ID, MCS7730_PRODUCT_ID),
 573                .driver_info = (unsigned long) &moschip_info,
 574        },
 575        {
 576                USB_DEVICE(SITECOM_VENDOR_ID, LN_030_PRODUCT_ID),
 577                .driver_info = (unsigned long) &sitecom_info,
 578        },
 579        {},
 580};
 581MODULE_DEVICE_TABLE(usb, products);
 582
 583static struct usb_driver mcs7830_driver = {
 584        .name = driver_name,
 585        .id_table = products,
 586        .probe = usbnet_probe,
 587        .disconnect = usbnet_disconnect,
 588        .suspend = usbnet_suspend,
 589        .resume = usbnet_resume,
 590};
 591
 592static int __init mcs7830_init(void)
 593{
 594        return usb_register(&mcs7830_driver);
 595}
 596module_init(mcs7830_init);
 597
 598static void __exit mcs7830_exit(void)
 599{
 600        usb_deregister(&mcs7830_driver);
 601}
 602module_exit(mcs7830_exit);
 603
 604MODULE_DESCRIPTION("USB to network adapter MCS7830)");
 605MODULE_LICENSE("GPL");
 606